From e95ca9ef89c79fbff8f0d1394311f5f18d653cdd Mon Sep 17 00:00:00 2001 From: hcong <1050828145@qq.com> Date: 星期五, 18 十月 2024 16:49:49 +0800 Subject: [PATCH] 动态表头 --- src/views/fysp/evaluation/EvalutationEdit.vue | 51 + src/components.d.ts | 8 src/views/fysp/evaluation/EvalutationRecordTest.vue | 519 ++++++++++++++++++++++++ src/constants/menu.js | 37 + src/router/index.js | 22 + src/views/fysp/evaluation/components/ChangeableColumnTable.vue | 585 +++++++++++++++++++++++++++ 6 files changed, 1,208 insertions(+), 14 deletions(-) diff --git a/src/components.d.ts b/src/components.d.ts index 124cacb..fa6c032 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -19,11 +19,14 @@ ElBreadcrumbItem: typeof import('element-plus/es')['ElBreadcrumbItem'] ElButton: typeof import('element-plus/es')['ElButton'] ElCard: typeof import('element-plus/es')['ElCard'] + ElCascader: typeof import('element-plus/es')['ElCascader'] + ElCheckbox: typeof import('element-plus/es')['ElCheckbox'] ElCol: typeof import('element-plus/es')['ElCol'] ElCollapse: typeof import('element-plus/es')['ElCollapse'] ElCollapseItem: typeof import('element-plus/es')['ElCollapseItem'] ElConfigProvider: typeof import('element-plus/es')['ElConfigProvider'] ElContainer: typeof import('element-plus/es')['ElContainer'] + ElDatePicker: typeof import('element-plus/es')['ElDatePicker'] ElDescriptions: typeof import('element-plus/es')['ElDescriptions'] ElDescriptionsItem: typeof import('element-plus/es')['ElDescriptionsItem'] ElDialog: typeof import('element-plus/es')['ElDialog'] @@ -41,7 +44,11 @@ ElMenuItem: typeof import('element-plus/es')['ElMenuItem'] ElMenuItemGroup: typeof import('element-plus/es')['ElMenuItemGroup'] ElOption: typeof import('element-plus/es')['ElOption'] + ElPageHeader: typeof import('element-plus/es')['ElPageHeader'] + ElPagination: typeof import('element-plus/es')['ElPagination'] ElPopover: typeof import('element-plus/es')['ElPopover'] + ElRadioButton: typeof import('element-plus/es')['ElRadioButton'] + ElRadioGroup: typeof import('element-plus/es')['ElRadioGroup'] ElRow: typeof import('element-plus/es')['ElRow'] ElScrollbar: typeof import('element-plus/es')['ElScrollbar'] ElSelect: typeof import('element-plus/es')['ElSelect'] @@ -55,6 +62,7 @@ ElTabs: typeof import('element-plus/es')['ElTabs'] ElTag: typeof import('element-plus/es')['ElTag'] ElText: typeof import('element-plus/es')['ElText'] + ElTooltip: typeof import('element-plus/es')['ElTooltip'] ElTree: typeof import('element-plus/es')['ElTree'] ElUpload: typeof import('element-plus/es')['ElUpload'] Footer: typeof import('./components/core/Footer.vue')['default'] diff --git a/src/constants/menu.js b/src/constants/menu.js index 9e744ee..afc82bb 100644 --- a/src/constants/menu.js +++ b/src/constants/menu.js @@ -72,6 +72,11 @@ // name: '鏁存敼瀹℃牳', // }, { + path: '/fysp/sceneInfo', + icon: 'Files', + name: '鍦烘櫙淇℃伅' + }, + { icon: 'DocumentChecked', name: '鑷姩璇勪及', children: [ @@ -84,6 +89,16 @@ path: '/fysp/evaluation/evalutationRecord', icon: 'Tickets', name: '璇勪及璁板綍', + }, + { + path: '/fysp/evaluation/evalutationRecordRank', + icon: 'Tickets', + name: '璇勪及鎺掑悕', + }, + { + path: '/fysp/evaluation/evalutationRecordEdit', + icon: 'Tickets', + name: '璇勫垎璋冩暣', }, ], }, @@ -114,6 +129,28 @@ icon: 'Files', name: '瀵瑰鏀寔' }, + + // { + // icon: 'Search', + // name: '涓氬姟鍒嗘瀽', + // children: [ + // { + // path: '/analysis/profollow', + // icon: 'Search', + // name: '闂鍔ㄦ�佽窡韪�', + // }, + // { + // path: '/analysis/proanalysis', + // icon: 'Search', + // name: '闂鏁存敼鍒嗘瀽', + // }, + // { + // path: '/analysis/standardjudge', + // icon: 'Search', + // name: '瑙勮寖鎬ц瘎浼�', + // }, + // ], + // }, // { // path: '/dailyreport', // icon: 'Search', diff --git a/src/router/index.js b/src/router/index.js index 41e3ccd..2cce391 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -122,11 +122,17 @@ component: () => import('@/views/fysp/config/EvalutationRule.vue') }, { + //璇勪及瀛愯鍒欎慨鏀归〉闈� + name: 'fyspEvalutationEdit', + path: '/fysp/config/evalutationRule/CompEvalutionSubRuleUpd/:subRuleId', + component: () => import('@/views/fysp/config/components/evalution/CompEvalutionSubRuleUpd.vue'), + }, + { //璇勪及鏁版嵁婧� name: 'fyspEvalutationTask', path: '/fysp/evaluation/evalutationTask', component: () => import('@/views/fysp/evaluation/EvalutationTask.vue'), - meta: { keepAlive: false } + meta: { keepAlive: true } }, { //璇勪及绠$悊 @@ -136,6 +142,20 @@ meta: { keepAlive: true } }, { + //璇勪及鎺掑悕 + name: 'fyspEvalutationRecordRank', + path: '/fysp/evaluation/evalutationRecordRank', + component: () => import('@/views/fysp/evaluation/EvalutationRecordTest.vue'), + meta: { keepAlive: true, readonly: true } + }, + { + //璇勫垎璋冩暣 + name: 'fyspEvalutationRecordEdit', + path: '/fysp/evaluation/evalutationRecordEdit', + component: () => import('@/views/fysp/evaluation/EvalutationRecordTest.vue'), + meta: { keepAlive: true, readonly: false } + }, + { //璇勪及缁撴灉璇︽儏 name: 'fyspEvalutationEdit', path: '/fysp/evaluation/evalutationEdit/:subTaskId', diff --git a/src/views/fysp/evaluation/EvalutationEdit.vue b/src/views/fysp/evaluation/EvalutationEdit.vue index f45dabf..6be8741 100644 --- a/src/views/fysp/evaluation/EvalutationEdit.vue +++ b/src/views/fysp/evaluation/EvalutationEdit.vue @@ -2,7 +2,10 @@ <FYPageHeader title="璇勪及缁撴灉璇︽儏"></FYPageHeader> <el-row v-for="item in evaluation" :key="item.id"> </el-row> <div class="btns"> - <el-button type="primary" @click="submit" :disabled="!isUpdated">鎻愪氦</el-button> + <!-- <el-button type="primary" @click="submit" :disabled="!isUpdated">鎻愪氦</el-button> --> + </div> + <div class="fixed-div"> + <span>鎬诲垎锛� {{ score }}</span> </div> <el-table class="table-style" @@ -26,6 +29,7 @@ <el-table-column prop="two_maxScore" label="鏈�澶у垎鍊�" width="90" /> <el-table-column v-slot="scope" prop="three_title" label="鍏蜂綋闂"> <el-checkbox + :disabled="disable" v-model="scope.row.three_select" @change="(checked) => threeSelectChange(checked, scope.row)" >{{ scope.row.three_title }}</el-checkbox @@ -46,6 +50,8 @@ }, data() { return { + disable: false, + score: '', tableData: [], evaluation: [], subTaskId: '', @@ -100,27 +106,33 @@ }, /** 鎻愪环 */ submit() { + this.disable = true; evaluateApi .updateScore({ subTaskId: this.subTaskId, itemList: this.checkedUpdatedList }) .then((res) => { - if (res.success) { - ElMessage({ - message: res.message, - type: 'success' - }); - }else { - ElMessage({ - message: res.message, - type: 'error' - }); - } + this.disable = false; + this.score = res.data.score; + // if (res.success) { + // ElMessage({ + // message: res.message, + // type: 'success' + // }); + // }else { + // ElMessage({ + // message: res.message, + // type: 'error' + // }); + // } + }) + .catch((e) => { + this.disable = false; }); setTimeout(() => { this.getList(); - }, 1000); + }, 200); }, /** 閫氳繃绗笁绾х殑id鑾峰彇涓婄骇浠ュ強椤剁骇 */ getSuperObjByThreeId(threeId, list, path = []) { @@ -146,6 +158,7 @@ /** 闂閫夋嫨妗� */ threeSelectChange(isSelect, row) { this.isUpdated = true; + this.submit(); }, /** 鍒楀悎骞� */ objectSpanMethod({ row, column, rowIndex, columnIndex }) { @@ -241,6 +254,7 @@ this.subTaskId = this.$route.params.subTaskId; evaluateApi.fetchItemEvaluation(this.subTaskId).then((res) => { this.isUpdated = false; + this.score = res.data.score; this.tableData = this.genTableData(res.data.details); }); }, @@ -276,4 +290,15 @@ .red-cell { background-color: red; } +/* 鍥哄畾瀹氫綅鐨� div */ +.fixed-div { + position: fixed; + top: 7%; /* 璺濈椤堕儴 20px */ + right: 20px; /* 璺濈鍙充晶 20px */ + width: 200px; /* div 鐨勫搴� */ + background-color: #f2f2f2; /* 鑳屾櫙棰滆壊 */ + padding: 20px; /* 鍐呰竟璺� */ + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); /* 闃村奖鏁堟灉 */ + z-index: 1000; /* 纭繚 div 鍦ㄩ〉闈㈠叾浠栧唴瀹逛箣涓� */ +} </style> diff --git a/src/views/fysp/evaluation/EvalutationRecordTest.vue b/src/views/fysp/evaluation/EvalutationRecordTest.vue new file mode 100644 index 0000000..9a5341e --- /dev/null +++ b/src/views/fysp/evaluation/EvalutationRecordTest.vue @@ -0,0 +1,519 @@ +<template> + <ChangeableColumnTable + @search="onSearch" + :pagination="false" + :cols="cols" + ref="tableRef" + @select-updated="selectUpdated" + @select-batch-updated="selectBatchUpdated" + > + <template #options> + <!-- 鍖哄幙 --> + <FYOptionLocation + :allOption="false" + :level="3" + :checkStrictly="false" + v-model:value="formSearch.locations" + ></FYOptionLocation> + <!-- 鍦烘櫙绫诲瀷 --> + <FYOptionScene + :allOption="false" + :type="2" + v-model:value="formSearch.scenetype" + ></FYOptionScene> + <!-- 鏃堕棿 --> + <FYOptionTime :initValue="false" type="month" v-model:value="formSearch.time"></FYOptionTime> + </template> + <template #buttons> + <!-- <el-button icon="Download" size="default" type="success" @click="download" + >瑙勮寖鎬ц瘎浼颁笌鍒嗘瀽鎶ュ憡</el-button + > --> + + <CompReport + :locations="formSearch.locations" + :scenetype="formSearch.scenetype" + :time="formSearch.time" + ></CompReport> + </template> + <template #options-expand> + <!-- <div class="flex-div flex-v-center"> + <el-form-item label="閮ㄥ垎鎵e垎"> + <el-select + style="width: 310px" + collapse-tags + collapse-tags-tooltip + v-model="partScoreHeads" + multiple + placeholder="閮ㄥ垎鎵e垎椤�" + clearable + filterable + @change="onSelectionChange" + > + <el-option + v-for="item in cols.filter((item) => 'children' in item)" + :key="item" + :label="item.label" + :value="item.name" + /> </el-select + ></el-form-item> + <el-tooltip placement="bottom-start" effect="light"> + <template #content> + <el-text size="b">閫変腑鐨勬潯鐩搴旂殑鎵e垎鎬诲拰灏嗕細鏄剧ず鍦ㄨ〃鏍间腑鐨勯儴鍒嗘墸鍒嗗垪涓�</el-text><br /> + </template> + <el-icon class="m-l-8 cursor-p" :size="16" color="var(--el-color-warning)" + ><QuestionFilled + /></el-icon> + </el-tooltip> + </div>--> + + <el-form :inline="true"> + <CompQuickSet @quick-set="setOptions"></CompQuickSet> + </el-form> + </template> + </ChangeableColumnTable> +</template> +<script> +import ChangeableColumnTable from './components/ChangeableColumnTable.vue'; +import CompReport from './components/CompReport.vue'; +import evaluateApi from '@/api/fysp/evaluateApi'; +import { useCloned } from '@vueuse/core'; +import dayjs from 'dayjs'; +import { ElMessage } from 'element-plus'; +import { useMessageBox, useMessageBoxTip } from '../../../composables/messageBox'; +export default { + components: { + ChangeableColumnTable, + CompReport, + }, + data() { + return { + partScoreHeads: [], + editRecordSwitch: false, + dataReady: false, + area: {}, + formSearch: { + locations: {}, + scenetype: {}, + time: dayjs().add(-1, 'M').date(1).toDate() + }, + refreshTable: true, + cols: [], + tableData: [] + }; + }, + methods: { + onSelectionChange() { + for (const tableItem of this.tableData) { + tableItem.partSum = 0; + for (const headItem of this.partScoreHeads) { + if (headItem in tableItem) { + tableItem.partSum += tableItem[headItem]; + } else { + tableItem.partSum = ''; + } + } + } + }, + // 鎸囧畾娣诲姞鐨勮〃澶撮『搴� + addHead(headObj, index) { + this.cols.splice(index, 0, headObj); + }, + async selectBatchUpdated(rows, name) { + var promises = []; + for (const row of rows) { + if (!row.subTaskId || row.subTaskId == null) { + for (var attr in row) { + if (attr.endsWith('ScoreSelect')) { + row[attr] = false; + } + } + continue; + } + var checkedUpdatedList = []; + for (const attr in row) { + if (attr.endsWith('ScoreSelect') && Boolean(row[attr])) { + var id = attr.split('ScoreSelect')[0]; + checkedUpdatedList.push(id); + } + } + promises.push( + evaluateApi + .updateScore({ + subTaskId: row.subTaskId, + itemList: checkedUpdatedList + }) + .then(() => { + evaluateApi.fetchItemEvaluation(row.subTaskId).then((res) => { + this.updateChangeableData(res.data.details, res.data.score, row.subTaskId); + }); + }) + ); + } + var reSend = true; + while (promises.length !== 0 && reSend) { + reSend = false; + await Promise.allSettled(promises).then((results) => { + results.forEach((result, index) => { + if (result.status === 'fulfilled') { + } else { + // 鎴愬姛浜嗗垹鎺夎繖涓猵romise + promises.splice(index, 1); + } + }); + }); + + ElMessage({ + message: '鍏ㄩ儴鎴愬姛', + type: 'success', + plain: true + }); + if (promises.length == 0) { + // ElMessage({ + // message: '鍏ㄩ儴鎴愬姛', + // type: 'success', + // plain: true + // }); + } else { + // useMessageBoxTip({ + // confirmMsg: '鏄惁閲嶈瘯', + // confirmTitle: '鎵归噺鏇存柊澶辫触', + // onConfirm: async () => { + // reSend = true; + // } + // }); + } + } + }, + // 閫変腑鏇存敼鐨勫洖璋� + selectUpdated(row) { + if (!row.subTaskId || row.subTaskId == null) { + for (var attr in row) { + if (attr.endsWith('ScoreSelect')) { + row[attr] = false; + } + } + return; + } + var checkedUpdatedList = []; + for (const attr in row) { + if (attr.endsWith('ScoreSelect') && Boolean(row[attr])) { + var id = attr.split('ScoreSelect')[0]; + checkedUpdatedList.push(id); + } + } + evaluateApi + .updateScore({ + subTaskId: row.subTaskId, + itemList: checkedUpdatedList + }) + .then(() => { + evaluateApi.fetchItemEvaluation(row.subTaskId).then((res) => { + this.updateChangeableData(res.data.details, res.data.score, row.subTaskId); + }); + }); + }, + _getParam() { + const { locations, scenetype, time } = this.formSearch; + return { + provincecode: locations.pCode, + provincename: locations.pName, + citycode: locations.cCode, + cityname: locations.cName, + districtcode: locations.dCode, + districtname: locations.dName, + starttime: dayjs(time).format('YYYY-MM-DD HH:mm:ss'), + scensetypeid: scenetype.value + }; + }, + // 鏇存柊涓�琛屾暟鎹� + updateChangeableData(data, score, subTaskId) { + for (let index = 0; index < this.tableData.length; index++) { + const element = this.tableData[index]; + if (element.subTaskId == subTaskId) { + element.resultscorebef = score; + this.genChangeableData(data, element); + // this.tableData[index] = element; + } + } + }, + // 鐢熸垚寰楀垎鏉$洰鐨勬暟鎹� + genChangeableData(data, tableItem) { + for (let index = 0; index < data.length; index++) { + const element = data[index]; + tableItem[`${element.id}Score`] = element.score; + if (element.select) { + tableItem[`${element.id}ScoreSelect`] = element.select; + } + var twoLevel = element.subList; + + if (!twoLevel) { + continue; + } + for (let index = 0; index < twoLevel.length; index++) { + const threeElement = twoLevel[index]; + tableItem[`${threeElement.id}Score`] = threeElement.score; + if (threeElement.select) { + tableItem[`${threeElement.id}ScoreSelect`] = threeElement.select; + } + var threeLevel = threeElement.subList; + if (!threeLevel) { + continue; + } + for (let index = 0; index < threeLevel.length; index++) { + const target = threeLevel[index]; + // 灞曠ず褰撳墠瀛愯鍒欑殑鍒嗗�� + // tableItem[`${target.id}Score`] = target.maxScore; + // 灞曠ず褰撳墠椤圭殑褰撳墠寰楀垎 + tableItem[`${target.id}Score`] = target.score; + if (target.select) { + tableItem[`${target.id}ScoreSelect`] = target.select; + } + } + } + } + }, + // 鐢熸垚寰楀垎鏉$洰鐨勮〃澶� + genChangeableHead(data) { + // 涓�绾ц〃澶� + for (let i = 0; i < data.length; i++) { + const element = data[i]; + const col = { + fixed: false + }; + this.cols.push(col); + col.label = element.title; + col.name = `${element.id}Score`; + + for (const attr in element) { + // 浜岀骇琛ㄥご + let children = []; + col.children = children; + if (attr === 'subList') { + for (let j = 0; j < element[attr].length; j++) { + const twoElement = element[attr][j]; + const child = { + fixed: false + }; + children.push(child); + child.label = twoElement.title; + child.name = `${twoElement.id}Score`; + + for (const attr2 in twoElement) { + // 涓夌骇鎸囨爣 + let children2 = []; + child.children = children2; + if (attr2 === 'subList') { + for (let k = 0; k < twoElement[attr2].length; k++) { + const threeElement = twoElement[attr2][k]; + const child2 = { + fixed: false + }; + children2.push(child2); + child2.label = threeElement.title; + child2.name = `${threeElement.id}Score`; + if (this.editRecordSwitch) { + child2.needSelect = true; + } + } + } + } + } + } + } + } + }, + // 鎺掑悕琛ㄥご + genRankHead() { + var head = { + name: 'rank', + label: '鎬诲垎鎺掑悕', + // fixed: 'left' + }; + this.addHead(head, 0); + }, + // 缂栧彿鏂规硶 + makeNumber(array, propName) { + if (!(array instanceof Array)) { + return; + } + // var copy = []; + // array.forEach((item) => { + // copy.push(item); + // }); + + array.sort((a, b) => b[propName] - a[propName]); + // var maxIndex = copy.length; + var minIndex = 1; + array.forEach((item) => { + item.rank = minIndex++; + }); + }, + // 鎺掑悕鏁版嵁 + genRankData() { + this.makeNumber(this.tableData, 'resultscorebef'); + }, + // 鍩烘湰淇℃伅琛ㄥご + genTableHeadBaseInfo(data) { + var cols = [ + { + name: 'sceneIndex', + label: '缂栧彿', + fixed: false, + noncloseable: true + }, + { + name: 'createdate', + label: '宸℃煡鏃ユ湡', + fixed: 'left', + }, + { + name: 'scensename', + label: '鍚嶇О', + fixed: 'left', + }, + { + name: 'resultscorebef', + label: '寰楀垎', + fixed: false + }, + { + name: 'districtname', + label: '鍖哄幙', + fixed: false + }, + { + name: 'townname', + label: '琛楅亾', + fixed: false + }, + { + name: 'scenseaddress', + label: '鍦板潃', + fixed: false + } + ]; + for (var col of cols) { + this.cols.push(col); + } + }, + // 鐢熸垚鍩烘湰鏁版嵁淇℃伅 + genTableDataBaseInfo(data, tableItem) { + try { + tableItem.sceneIndex = data.sceneIndex; + tableItem.scensename = data.sceneName; + tableItem.districtname = data.dname; + tableItem.townname = data.tname; + if (!data.evaluation) { + tableItem.createdate = ''; + tableItem.resultscorebef = ''; + tableItem.scenseaddress = ''; + return; + } + tableItem.createdate = data.evaluation.createdate + ? dayjs(data.evaluation.createdate).format('MM-DD') + : ''; + tableItem.resultscorebef = data.evaluation.resultscorebef || 0; + tableItem.scenseaddress = data.evaluation.scenseaddress || ''; + } catch (e) { + console.log(e.message, data); + } + }, + onSearch(page, func) { + this.dataReady = false; + this.tableData = []; + this.cols = []; + const area = this._getParam(); + var expandHeadOk = false; + var baseHeadOk = false; + var showExpand = true; + evaluateApi + .fetchAutoEvaluation(area) + .then((res) => { + for (const element of res.data) { + if (element.subTaskId == null) { + showExpand = false; + // continue; + // console.log('subTask涓虹┖'); + } else { + showExpand = true; + } + var tableItem = {}; + + if (!baseHeadOk) { + this.genTableHeadBaseInfo(element); + baseHeadOk = true; + } + if (showExpand) { + evaluateApi + .fetchItemEvaluation(element.subTaskId) + .then((res) => { + const data = res.data.details; + tableItem = { + subTaskId: element.subTaskId + }; + this.tableData.push(tableItem); + try { + if (!expandHeadOk) { + this.genChangeableHead(data); + expandHeadOk = true; + } + } catch (e) { + console.log('琛ㄥご鍑嗗澶辫触', e.message); + } + this.genTableDataBaseInfo(element, tableItem); + this.genChangeableData(data, tableItem); + }) + .catch((error) => { + console.error('Error fetching item evaluation:', error); + }) + .finally(() => {}); + } else { + this.genTableDataBaseInfo(element, tableItem); + this.tableData.push(tableItem); + } + } + }) + .finally(() => { + setTimeout(() => { + this.dataReady = true; + // 鐢熸垚鎺掑悕琛ㄥご + this.genRankHead(); + this.genRankData(); + func({ data: this.tableData }); + }, 1000); + }); + }, + // 鍒濆鍖栬皟鏁寸姸鎬� + initEditRecord() { + if (!Boolean(this.$route.meta.readonly)) { + this.editRecordSwitch = true; + } + }, + // 鍒濆鍖� + init() { + this.initEditRecord(); + }, + + setOptions(param) { + this.formSearch.locations = param.locations; + this.formSearch.scenetype = param.scenetype; + this.formSearch.sourceType = param.sourceType; + this.$refs.tableRef.onSearch(); + } + }, + created() { + this.init(); + }, + mounted() { + this.$refs.tableRef.onSearch(); + } +}; +</script> +<style scoped> +.flex-div { + display: flex; +} +.flex-v-center { + align-items: center; +} +</style> diff --git a/src/views/fysp/evaluation/components/ChangeableColumnTable.vue b/src/views/fysp/evaluation/components/ChangeableColumnTable.vue new file mode 100644 index 0000000..79ee4da --- /dev/null +++ b/src/views/fysp/evaluation/components/ChangeableColumnTable.vue @@ -0,0 +1,585 @@ +<template> + <!-- <el-button type="text" @click="reShow">娴嬭瘯閲嶆柊鍔犺浇鍔ㄦ�佽〃澶寸粍浠�</el-button> --> + <el-row ref="searchRef"> + <FYSearchBar @search="onSearch"> + <template #options> + <slot name="options"></slot> + </template> + <template #buttons> + <slot name="buttons"></slot> + </template> + </FYSearchBar> + </el-row> + <el-row ref="expandRef" justify="space-between"> + <el-col span="22"> + <slot name="options-expand"></slot> + </el-col> + <el-col span="2"> + <el-space :wrap="false"> + <el-text size="small">瀛椾綋</el-text> + <el-radio-group v-model="fontSize" size="small"> + <el-radio-button value="small">灏�</el-radio-button> + <el-radio-button value="default">涓�</el-radio-button> + <el-radio-button value="large">澶�</el-radio-button> + </el-radio-group> + <el-popover placement="bottom" :width="400" trigger="click"> + <template #reference> + <el-button type="primary" @click="genHeadTreeData">琛ㄥご淇敼</el-button> + </template> + <!-- 鍒楀嚭琛ㄥご鐨勬爲鐘剁粨鏋� --> + <el-tree + v-if="isOk" + :props="headTreeProps" + :data="headTreeData" + node-key="label" + show-checkbox + :default-checked-keys="showHeadLabels" + @check-change="handleHeadCheckChange" + /> + <div class="tree-btus"> + <el-button size="small" type="primary" @click="deleteSecondLevelNodes" + >绉婚櫎鎵�鏈変簩绾ц妭鐐�</el-button + > + <el-button size="small" type="primary" @click="deleteThirdLevelNodes" + >绉婚櫎鎵�鏈変笁绾ц妭鐐�</el-button + > + <!-- <el-button size="small" type="primary" @click="resetCols">澶嶅師</el-button> --> + </div> + </el-popover> + </el-space> + </el-col> + </el-row> + <div ref="expand2Ref"> + <slot name="options-expand2"></slot> + </div> + <el-table + :data="tableData" + v-loading="loading" + :row-class-name="tableRowClassName" + table-layout="auto" + :height="tableHeight" + :size="fontSize" + @header-contextmenu="headerContextmenu" + border + > + <el-table-column + v-for="(item, index) in tableCols" + :key="item.label" + :fixed="item.fixed" + :label="item.label" + :prop="item.name" + :ref="item.name" + :sortable="item.name ? true : false" + > + <template v-slot:header v-if="item.needSelect"> + <div> + {{ item.label }} + <el-button + @click="handleHeaderBacthSelectClick(item, true, $event)" + type="primary" + size="default" + circle + > + 閫変腑 + </el-button> + <el-button + @click="handleHeaderBacthSelectClick(item, false, $event)" + type="success" + size="default" + circle + > + 鍘婚櫎 + </el-button> + </div> + </template> + <template v-slot:default1="scope"> + <el-checkbox + v-if="item.needSelect" + v-model="scope.row[`${item.name}Select`]" + @change="(checked) => selectChange(checked, scope.row)" + >{{ scope.row[item.name] }}</el-checkbox + > + </template> + <el-table-column + v-if="item.children && item.children.length > 0" + v-for="(item2, index2) in item.children" + :label="item2.label" + :prop="item2.name" + :ref="item2.name" + :sortable="item2.name ? true : false" + > + <template v-slot:header v-if="item2.needSelect"> + <div> + {{ item2.label }} + <el-button + @click="handleHeaderBacthSelectClick(item2, true, $event)" + type="primary" + size="default" + circle + > + 閫変腑 + </el-button> + <el-button + @click="handleHeaderBacthSelectClick(item2, false, $event)" + type="success" + size="default" + circle + > + 鍘婚櫎 + </el-button> + </div> + </template> + + <template v-slot:default2="scope2"> + <el-checkbox + v-if="item2.needSelect" + v-model="scope2.row[`${item2.name}Select`]" + @change="(checked) => selectChange(checked, scope2.row)" + >{{ scope2.row[item2.name] }}</el-checkbox + > + </template> + <el-table-column + v-if="item2.children && item2.children.length > 0" + v-for="(item3, index3) in item2.children" + :label="item3.label" + :prop="item3.name" + :ref="item3.name" + :sortable="item3.name ? true : false" + > + <template v-slot:header v-if="item3.needSelect"> + <div> + {{ item3.label }} + <el-button + @click="handleHeaderBacthSelectClick(item3, true, $event)" + type="primary" + size="default" + circle + > + 閫変腑 + </el-button> + <el-button + @click="handleHeaderBacthSelectClick(item3, false, $event)" + type="success" + size="default" + circle + > + 鍘婚櫎 + </el-button> + </div> + </template> + <template v-slot="scope3"> + <div class="flex-div"> + <!-- <div v-if="scope3.row.loader" class="loader"></div> --> + <div v-if="item3.needSelect"> + <el-checkbox + v-model="scope3.row[`${item3.name}Select`]" + @change="(checked) => selectChange(checked, scope3.row)" + >{{ scope3.row[item3.name] }}</el-checkbox + > + </div> + <div v-else> + {{ scope3.row[item3.name] }} + </div> + </div> + </template> + </el-table-column> + </el-table-column> + </el-table-column> + </el-table> + + <el-pagination + v-if="pagination" + ref="paginationRef" + class="el-pagination" + v-model:current-page="currentPage" + v-model:page-size="pageSize" + :page-sizes="[10, 20, 50, 100]" + :background="true" + layout="total, sizes, prev, pager, next, jumper" + :total="total" + /> +</template> + +<script> +import { useCloned } from '@vueuse/core'; +export default { + props: { + cols: [], + rowClassName: undefined, + pagination: { + type: Boolean, + default: true + }, + // '' | 'small' | 'default' | 'large' + size: { + type: String, + default: 'default' + } + }, + data() { + return { + isOk: false, + reLoad: true, + i: 0, + headTreeData: [], + headTreeProps: { + children: 'children', + label: 'label', + disabled: 'noncloseable' + }, + tableHeight: '500', + tableData: [], + total: 0, + currentPage: 1, + pageSize: 20, + loading: false, + fontSize: 'default', + tableCols: [ + { + name: '', + label: '', + needSelect: false, + children: [] + } + ] + }; + }, + emits: ['search'], + watch: { + cols: { + handler(nValue, oValue) { + this.tableCols = nValue; + }, + immediate: true + }, + currentPage(nValue, oValue) { + if (nValue != oValue) { + this.onSearch(); + } + }, + pageSize(nValue, oValue) { + if (nValue != oValue) { + this.onSearch(); + } + }, + size: { + handler(nValue, oValue) { + if (nValue != oValue) { + this.fontSize = nValue; + } + }, + immediate: true + } + }, + computed: { + showHeadLabels() { + var result = this.collectLabels(this.cols); + + return result; + }, + cTableHeight() { + if (this.$refs.searchRef) { + const h1 = this.$refs.searchRef.$el.offsetHeight; + const h2 = this.$refs.paginationRef ? this.$refs.paginationRef.$el.offsetHeight : 0; + const h3 = this.$refs.expandRef.$el.offsetHeight; + const h4 = this.$refs.expand2Ref.offsetHeight; + + const h = h1 + h2 + h3 + h4; + // return `calc(100vh - ${h1}px - ${h2}px - var(--el-main-padding) * 2 - var(--el-header-height))`; + return `calc(100vh - ${h}px - 60px - var(--el-main-padding) * 2)`; + } else { + return '500'; + } + } + }, + methods: { + deleteLevelNodes(tree, level) { + // 閬嶅巻鏍戜腑鐨勬瘡涓妭鐐� + tree.forEach((node) => { + if (node.children && node.children.length > 0) { + // 濡傛灉褰撳墠鑺傜偣鐨勫瓙鑺傜偣鏁扮粍涓嶄负绌猴紝閫掑綊璋冪敤 + this.deleteLevelNodes(node.children, level - 1); + } + }); + + // 濡傛灉褰撳墠绾у埆杈惧埌鎸囧畾绾у埆锛屾竻绌哄瓙鑺傜偣鏁扮粍 + if (level === 1) { + tree.length = 0; + } + }, + + // 鍒犻櫎鎵�鏈変簩绾ц妭鐐� + deleteSecondLevelNodes() { + this.loading = true; + this.deleteLevelNodes(this.tableCols, 2); + + this.loading = false; + this.genHeadTreeData(); + }, + + // 鍒犻櫎鎵�鏈変笁绾ц妭鐐� + deleteThirdLevelNodes() { + this.loading = true; + this.deleteLevelNodes(this.tableCols, 3); + this.loading = false; + this.genHeadTreeData(); + }, + deepCopyCols() { + return this.deepCopy(this.cols); + }, + resetCols() { + + this.tableCols = this.deepCopyCols(); + }, + collectLabels(nodes) { + let labels = []; // 鐢ㄤ簬瀛樺偍 isShow 涓� true 鐨勮妭鐐圭殑 label + + function traverseNodes(nodes) { + nodes.forEach((node) => { + // 濡傛灉 isShow 涓� true锛屽皢 label 娣诲姞鍒版暟缁勪腑 + if (!(`isShow` in node) || node.isShow) { + // labels.push(node); + labels.push(node.label); + } + + // 濡傛灉褰撳墠鑺傜偣鏈夊瓙鑺傜偣锛岄�掑綊璋冪敤閬嶅巻鍑芥暟 + if (node.children && node.children.length > 0) { + traverseNodes(node.children); + } + }); + } + + traverseNodes(nodes); // 寮�濮嬮�掑綊閬嶅巻 + + return labels; // 杩斿洖鏀堕泦鍒扮殑 labels 鏁扮粍 + }, + // 鏇存柊isShow鐘舵�� + updateShowTableHead(labelValue, checked) { + function traverseNodes(nodes) { + for (let index = nodes.length - 1; index >= 0; index--) { + const node = nodes[index]; + if (node.label == labelValue) { + + // node.isShow = !node.isShow; + // setTimeout(()=>{ + // nodes.splice(index, 0, node); + // }, 1000) + nodes.splice(index, 1); + } + + // 濡傛灉褰撳墠鑺傜偣鏈夊瓙鑺傜偣锛岄�掑綊璋冪敤閬嶅巻鍑芥暟 + if (node.children && node.children.length > 0) { + traverseNodes(node.children); + } + } + } + + traverseNodes(this.tableCols); // 寮�濮嬮�掑綊閬嶅巻 + }, + // 鐢熸垚琛ㄥご鏁版嵁 + genHeadTreeData() { + this.headTreeData = this.tableCols; + }, + // 琛ㄥご鐘舵�佹敼鍙� + handleHeadCheckChange(data, checked, indeterminate) { + this.updateShowTableHead(data.label, checked); + }, + // 鐢熸垚閫変腑鐘舵�佸睘鎬у悕 + genSelectPropName(name) { + return `${name}Select`; + }, + // 杞腑鐘舵�佽浆鍙� 浼犲叆涓�琛屾暟鎹拰闇�瑕佽浆鎹㈤�変腑鐘舵�佺殑鍒楀悕 + setSelectStatus(row, name, status) { + if ((!name) in row) { + return false; + } + row[this.genSelectPropName(name)] = status; + return true; + }, + reShow() { + // setTimeout(() => { + // this.isOk = true; + // console.log("鏁版嵁", this.tableData); + // }, 1000); + }, + // 琛ㄥご琚彸閿� + headerContextmenu(column, event) { + event.preventDefault(); + for (let i = 0; i < this.tableCols.length; i++) { + var item = this.tableCols[i]; + if (item.label == column.label) { + this.tableCols.splice(i, 1); + break; + } + } + }, + handleHeaderBacthSelectClick(prop, isSelect, event) { + event.stopPropagation(); + this.tableData.forEach((element) => { + this.setSelectStatus(element, prop.name, isSelect); + }); + this.selectBatchChange(isSelect, this.tableData, this.genSelectPropName(prop.name)); + }, + initSelectStatus() { + for (let index = 0; index < this.tableData.length; index++) { + const element = this.tableData[index]; + } + }, + initTableData() { + this.initSelectStatus(); + }, + deepCopy(obj, hash = new WeakMap()) { + // 濡傛灉鏄痭ull锛岀洿鎺ヨ繑鍥瀗ull + if (obj === null) return null; + // 濡傛灉鏄熀鏈暟鎹被鍨嬶紝鐩存帴杩斿洖 + if (typeof obj !== 'object') return obj; + // 濡傛灉宸叉嫹璐濊繃锛岀洿鎺ヨ繑鍥炰箣鍓嶆嫹璐濈殑缁撴灉 + if (hash.has(obj)) return hash.get(obj); + + // 鍒涘缓涓�涓柊鐨勫璞℃垨鏁扮粍 + let cloneObj = Array.isArray(obj) ? [] : {}; + // 缂撳瓨褰撳墠瀵硅薄鐨勬嫹璐� + hash.set(obj, cloneObj); + + // 閫掑綊鎷疯礉瀵硅薄鎴栨暟缁勭殑姣忎釜灞炴�� + for (let key in obj) { + // 濡傛灉灞炴�у�兼槸鏁扮粍鎴栧璞★紝鍒欓�掑綊鎷疯礉 + cloneObj[key] = this.deepCopy(obj[key], hash); + } + return cloneObj; + }, + initCols() { + this.i = 0; + this.tableCols = this.deepCopyCols(); + this.isOk = true; + for (let index = 0; index < this.tableCols.length; index++) { + const element = this.tableCols[index]; + element.isShow = true; + } + }, + // 閫変腑鍥炶皟 + selectChange(isSelect, row) { + row.loader = true; + this.$emit('select-updated', row); + setTimeout(() => { + row.loader = false; + }, 1000); + }, + // 鎵归噺閫変腑鍥炶皟 + selectBatchChange(isSelect, rows, name) { + rows.forEach((element) => { + element.loader = true; + }); + this.$emit('select-batch-updated', rows, name); + setTimeout(() => { + rows.forEach((element) => { + element.loader = false; + }); + }, 1000); + }, + /** + * 琛ㄦ牸鏁版嵁鏌ヨ锛屼紶閫掍袱缁勫弬鏁帮紝鍒嗛〉淇℃伅鍜屽洖璋冨嚱鏁� + * 鍒嗛〉淇℃伅鍖呮嫭褰撳墠椤电爜currentPage鍜屾瘡椤垫暟鎹噺pageSize + * 鍥炶皟鍑芥暟鎺ユ敹涓�涓璞★紝鍖呮嫭琛ㄦ牸鏁版嵁鏁扮粍data鍜屾暟鎹�绘暟total + */ + onSearch() { + this.loading = true; + this.$emit( + 'search', + { + currentPage: this.currentPage, + pageSize: this.pageSize + }, + (res) => { + this.tableData = res.data; + this.total = res.total ? res.total : 0; + this.loading = false; + } + ); + }, + calcTableHeight() { + const h1 = this.$refs.searchRef.$el.offsetHeight; + const h2 = this.$refs.paginationRef ? this.$refs.paginationRef.$el.offsetHeight : 0; + const h3 = this.$refs.expandRef.$el.offsetHeight; + const h4 = this.$refs.expand2Ref.offsetHeight; + + const h = h1 + h2 + h3 + h4; + // return `calc(100vh - ${h1}px - ${h2}px - var(--el-main-padding) * 2 - var(--el-header-height))`; + return `calc(100vh - ${h}px - 60px - var(--el-main-padding) * 2)`; + }, + tableRowClassName({ row }) { + if (this.rowClassName) { + if (typeof this.rowClassName == 'string') { + return this.rowClassName; + } else if (typeof this.rowClassName == 'function') { + return this.rowClassName({ row }); + } + } else { + return row.extension1 != '0' ? 'online-row' : 'offline-row'; + } + } + }, + created() { + // this.onSearch(); + }, + mounted() { + this.tableHeight = this.calcTableHeight(); + this.initCols(); + this.initTableData(); + this.isOk = true; + } +}; +</script> + +<style> +.l-table .online-row { + /* background-color: rgb(4, 202, 21); */ +} + +.el-table .offline-row { + background-color: var(--el-disabled-bg-color); + color: var(--el-disabled-text-color); +} + +.el-table .cell { + white-space: nowrap; +} + +.el-pagination { + background-color: var(--el-color-white); + padding-top: 20px; + border-top: 1px solid rgba(0, 0, 0, 0.096); + /* margin-top: 2px; */ +} +.no-display { + display: none; +} +.btns { + margin-left: 10px; +} +.flex-div { + display: flex; +} +.loader { + margin-top: 5px; + margin-right: 5px; + border: 4px solid rgba(0, 0, 0, 0.1); /* 杞婚鑹茬殑杈规 */ + border-radius: 50%; /* 鍦嗗舰 */ + border-top: 4px solid #3498db; /* 钃濊壊杈规 */ + width: 20px; /* 鍔犺浇鍣ㄧ殑瀹藉害 */ + height: 20px; /* 鍔犺浇鍣ㄧ殑楂樺害 */ + animation: spin 2s linear infinite; /* 鏃犻檺寰幆鐨勬棆杞姩鐢� */ +} +.tree-btus { + margin-left: 24px; +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +</style> -- Gitblit v1.9.3