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