4 Commits c733d54e6b ... 978ae883d7

Autor SHA1 Mensagem Data
  ystl_myq 978ae883d7 fix: 排行榜导出数据 há 2 meses atrás
  ystl_myq 54806f2207 fix: 排行榜导出数据 há 2 meses atrás
  ystl_myq 2d16a9da74 feat: 排行榜导出排序 há 2 meses atrás
  ystl_myq 283100c433 fix: 排行榜导出 há 2 meses atrás

+ 1 - 1
.vscode/settings.json

@@ -2,7 +2,7 @@
   "editor.formatOnType": true,
   "editor.formatOnSave": true,
   "[vue]": {
-    "editor.defaultFormatter": "vscode.typescript-language-features"
+    "editor.defaultFormatter": "Vue.volar"
   },
   "editor.tabSize": 2,
   "editor.formatOnPaste": true,

+ 4 - 1
package.json

@@ -63,6 +63,7 @@
     "default-passive-events": "^2.0.0",
     "echarts": "^5.5.0",
     "element-plus": "^2.6.2",
+    "exceljs": "^4.4.0",
     "js-cookie": "^3.0.5",
     "jsencrypt": "^3.3.2",
     "localforage": "^1.10.0",
@@ -79,7 +80,9 @@
     "vue-router": "^4.3.0",
     "vue-tippy": "^6.4.1",
     "vue-types": "^5.1.1",
-    "vxe-table": "^4.6.23",
+    "vxe-table": "^4.6.25",
+    "vxe-table-plugin-export-xlsx": "^4.0.7",
+    "xe-utils": "^3.5.32",
     "xlsx": "^0.18.5"
   },
   "devDependencies": {

Diff do ficheiro suprimidas por serem muito extensas
+ 460 - 6
pnpm-lock.yaml


+ 1 - 1
src/components/echarts/radar.vue

@@ -4,7 +4,7 @@ import { useDark, useECharts } from "@pureadmin/utils";
 import { getPersonDimensionChartsList } from "@/api/draw";
 const $props = defineProps({
   radarRefList: {
-    type: Array
+    type: Object
   }
 });
 onMounted(() => {

+ 168 - 74
src/components/rankTable/draw.vue

@@ -122,12 +122,16 @@ defineExpose({
 });
 </script> -->
 <template>
-  <div class="w-full">
+  <div class="w-full aa">
+    <vxe-button class="float-right -top-0 mr-20 mb-4" @click="exportEvent"
+      ><el-icon> <Download /> </el-icon>&nbsp;&nbsp;导出</vxe-button
+    >
     <vxe-grid
       v-if="$route.name != 'workerDrak'"
       v-bind="gridOptions"
+      ref="gridRef"
       :merge-cells="mergeCells"
-      v-on="gridEvents"
+      class="mt-10"
     >
       <template #imgUrl_default="{ row }">
         <div>
@@ -147,7 +151,7 @@ defineExpose({
         {{ row.allScore }}
       </template>
     </vxe-grid>
-    <vxe-grid v-else v-bind="gridOptions">
+    <vxe-grid v-else v-bind="gridOptions" ref="gridRef1" class="mt-10">
       <template #imgUrl_default="{ row }">
         <div v-if="row.ranking <= 3" class="text-center">
           <img class="mt-auto" :src="RANK_IMG[Number(row.ranking) - 1]" />
@@ -166,11 +170,14 @@ import { ref, reactive, watch, onMounted } from "vue";
 import rank1 from "@/assets/rank/rank1.png";
 import rank2 from "@/assets/rank/rank2.png";
 import rank3 from "@/assets/rank/rank3.png";
+import dayjs from "dayjs";
 import { useRoute } from "vue-router";
 import { useUserStoreHook } from "@/store/modules//user";
 const $prop = defineProps({
   rankTableRefList: Object
 });
+const gridRef = ref(null);
+const gridRef1 = ref(null);
 onMounted(() => {
   // 员工排行榜无法获取组件渲染问题
   if ($prop.rankTableRefList) {
@@ -182,6 +189,7 @@ onMounted(() => {
   }
 });
 const $route = useRoute();
+const fileData = ref();
 const RANK_IMG = [rank1, rank2, rank3];
 const deptName = ref("");
 const name = ref("");
@@ -200,7 +208,8 @@ const averageData = averageSore => {
     // num = (num / rawData.value.length).toFixed(2);
     rawData.value.unshift({
       dimensionList: [],
-      allScore: rawData.value[0].averageSore
+      allScore: rawData.value[0].averageSore,
+      isAverageRow: true // 标记为平均分行
     });
   }
 };
@@ -211,6 +220,10 @@ const gridOptions = reactive({
   height: 500,
   columns: [],
   data: [],
+  sortConfig: {
+    multiple: false,
+    chronological: true
+  },
   showOverflow: true,
   showHeaderOverflow: true,
   showFooterOverflow: true,
@@ -222,30 +235,14 @@ const gridOptions = reactive({
     gt: 0
   }
 });
-// 排序状态
-const gridEvents = {
-  sortChange({ column, order }) {
-    // 如果没有选择排序列或没有排序方向,则直接返回
-    if (!column || !order) {
-      gridOptions.data = [...originalData.value];
-    } else {
-      // 排除第一行,如果路由名称不是 "workerDrak"
-      const rowsToSort = gridOptions.data.slice(1); // 排除第一行
-      const sortedRows = rowsToSort.sort((a, b) => {
-        // 根据点击的列字段和排序方向进行排序
-        if (order === "asc") {
-          return a[column.field] < b[column.field] ? -1 : 1;
-        } else {
-          return a[column.field] > b[column.field] ? -1 : 1;
-        }
-      });
 
-      // 将第一行重新插入到排序后的数据顶部
-      const sortedData = [gridOptions.data[0], ...sortedRows];
-      gridOptions.data = sortedData; // 更新表格数据
-    }
+// 判断key值是否相同返回具体值
+function getValueByKey(obj, key) {
+  if (key in obj) {
+    return obj[key];
   }
-};
+  return null; // 如果 key 不存在则返回 null
+}
 // 模拟接口数据
 const rawData = ref([]);
 const init = (item, deptNames, names) => {
@@ -301,7 +298,24 @@ const createColumns = () => {
         sortable: true,
         width: 150,
         fixed: "right", // 将此列固定在右侧
-        slots: { default: "dim-allScore" }
+        slots: { default: "dim-allScore" },
+        sortBy({ column, row }) {
+          // 如果是平均行(isAverageRow为true),则返回一个很大的值,避免被排序
+          if (column.field in row && typeof row[column.field] === "number") {
+            if (column.order == "asc") {
+              if (row.isAverageRow) {
+                return -9999999999;
+              }
+            } else {
+              if (row.isAverageRow) {
+                return 99999999999;
+              }
+            }
+          } else {
+            return -9999999999;
+          }
+          return row.allScore; // 返回正常的得分,进行排序
+        }
       }
     ];
   } else {
@@ -325,54 +339,32 @@ const createColumns = () => {
         width: 150,
         sortable: true,
         fixed: "right", // 将此列固定在右侧
-        slots: { default: "dim-allScore" }
+        slots: { default: "dim-allScore" },
+        sortBy({ column, row }) {
+          // 如果是平均行(isAverageRow为true),则返回一个很大的值,避免被排序
+
+          // console.log(123, column)
+          // console.log("1231row", row)
+          if (column.field in row && typeof row[column.field] === "number") {
+            if (column.order == "asc") {
+              if (row.isAverageRow) {
+                return -9999999999;
+              }
+            } else {
+              if (row.isAverageRow) {
+                return 99999999999;
+              }
+            }
+          } else {
+            return -9999999999;
+          }
+          return getValueByKey(row, column.field); // 返回正常的得分,进行排序
+        }
       }
     ];
   }
   const headerMap = new Map();
   // 遍历数据生成表头结构
-  // rawData.value.forEach(item => {
-  //   item.dimensionList.forEach(dim => {
-  //     if (!headerMap.has(dim.dimName)) {
-  //       // 存储维度相关信息,包括 totalSore
-  //       console.log("dim", dim);
-  //       headerMap.set(dim.dimName, {
-  //         totalSore: dim.totalSore,
-  //         quotas: [] // 用于存储 quota 列表
-  //       });
-  //     }
-  //     dim.quotaList.forEach(quota => {
-  //       const dimData = headerMap.get(dim.dimName);
-  //       if (!dimData.quotas.some(q => q.quotaName === quota.quotaName)) {
-  //         dimData.quotas.push({ quotaName: quota.quotaName });
-  //       }
-  //     });
-  //   });
-  // });
-
-  // // 构建多级表头
-  // headerMap.forEach((dimData, dimName) => {
-  //   const children = dimData.quotas.map(quota => ({
-  //     title: quota.quotaName,
-  //     width: 120,
-  //     sortable: true,
-  //     field: `${dimName}_${quota.quotaName}` // 确保字段唯一
-  //   }));
-
-  //   // 添加维度名称及其对应的子列
-  //   columns.push({
-  //     title: dimName,
-  //     children
-  //   });
-
-  //   // 添加该维度的总分列
-  //   columns.push({
-  //     title: `总分`, // 可根据需要调整标题
-  //     field: `${dimName}_totalSore`,
-  //     width: 120,
-  //     sortable: true
-  //   });
-  // });
   rawData.value.forEach(item => {
     item.dimensionList.forEach(dim => {
       if (!headerMap.has(dim.dimName)) {
@@ -401,7 +393,38 @@ const createColumns = () => {
       title: `${quota.quotaName} (${quota.quotaWeight}%)`, // 在 title 后拼接 quotaWeight
       width: 120,
       sortable: true,
-      field: `${dimName}_${quota.quotaName}` // 确保字段唯一
+      field: `${dimName}_${quota.quotaName}`, // 确保字段唯一
+      sortBy({ column, row }) {
+        // 如果是平均行(isAverageRow为true),则返回一个很大的值,避免被排序
+        let aa = Number(row[column.field]);
+        if (typeof aa === "number" && !isNaN(aa)) {
+          if (column.order == "asc") {
+            if (row.isAverageRow) {
+              return -9999999999;
+            }
+          } else {
+            if (row.isAverageRow) {
+              return 99999999999;
+            }
+          }
+        } else {
+          // 倒序在最后
+          if (column.order == "asc") {
+            if (!row.isAverageRow) {
+              return 9999999999999;
+            } else {
+              return -999999999999;
+            }
+          } else {
+            if (!row.isAverageRow) {
+              return -999999999999;
+            } else {
+              return 999999999999;
+            }
+          }
+        }
+        return getValueByKey(row, column.field); // 返回正常的得分,进行排序
+      }
     }));
 
     // 添加维度名称及其对应的子列
@@ -415,7 +438,38 @@ const createColumns = () => {
       title: `总分`, // 可根据需要调整标题
       field: `${dimName}_totalSore`,
       width: 120,
-      sortable: true
+      sortable: true,
+      sortBy({ column, row }) {
+        // 如果是平均行(isAverageRow为true),则返回一个很大的值,避免被排序
+        let aa = Number(row[column.field]);
+        if (typeof aa === "number" && !isNaN(aa)) {
+          if (column.order == "asc") {
+            if (row.isAverageRow) {
+              return -9999999999;
+            }
+          } else {
+            if (row.isAverageRow) {
+              return 99999999999;
+            }
+          }
+        } else {
+          // 倒序在最后
+          if (column.order == "asc") {
+            if (!row.isAverageRow) {
+              return 9999999999999;
+            } else {
+              return -999999999999;
+            }
+          } else {
+            if (!row.isAverageRow) {
+              return -999999999999;
+            } else {
+              return 999999999999;
+            }
+          }
+        }
+        return getValueByKey(row, column.field); // 返回正常的得分,进行排序
+      }
     });
   });
   gridOptions.columns = columns;
@@ -432,7 +486,8 @@ const loadData = () => {
       assessmentObjectName: item.assessmentObjectName,
       deptName: item.deptName,
       ranking: item.ranking,
-      allScore: item.allScore
+      allScore: item.allScore,
+      isAverageRow: item.isAverageRow || false // 确保数据里标记了是否为平均分行
     };
 
     item.dimensionList.forEach(dim => {
@@ -455,16 +510,51 @@ const loadData = () => {
 
   setTimeout(() => {
     gridOptions.data = tableData;
+    fileData.value = JSON.parse(JSON.stringify(tableData));
+    if ($route.name != "workerDrak") {
+      fileData.value[0].ranking = "平均得分";
+    }
     gridOptions.loading = false;
     useUserStoreHook().tabload = false;
   }, 500);
 };
 
 // 监听年份变化,重新渲染
-watch(selectYear, () => {
+watch($prop.rankTableRefList, newVal => {
+  init(newVal.data, newVal.dept, newVal.name);
   createColumns();
   loadData();
+  gridRef.value.setMergeCells([
+    // 合并第一行前两列
+    { row: 0, col: 0, rowspan: 1, colspan: 2 },
+    { row: 2, col: 1, rowspan: 0, colspan: 0 }
+  ]);
 });
+// 导出
+const exportEvent = () => {
+  let $grid;
+  let fileName =
+    localStorage.getItem("fileName") + dayjs().format("YYYY-MM-DD HH:mm:ss");
+  if ($route.name != "workerDrak") {
+    $grid = gridRef.value;
+  } else {
+    $grid = gridRef1.value;
+  }
+  if ($grid) {
+    $grid.exportData({
+      type: "xlsx",
+      filename: fileName,
+      useStyle: true,
+      isMerge: true,
+      data: fileData.value
+    });
+  } else {
+    ElMessage({
+      message: "暂无数据",
+      type: "warning"
+    });
+  }
+};
 </script>
 
 <style lang="scss" scoped>
@@ -490,4 +580,8 @@ watch(selectYear, () => {
 
   /* 背景颜色 */
 }
+
+.aa {
+  position: relative;
+}
 </style>

+ 173 - 182
src/components/rankTable/index.vue

@@ -1,146 +1,14 @@
-<!-- <template>
-  <vxe-table
-    border
-    style="width: 100%"
-    :data="tableData"
-    show-overflow
-    show-header-overflow
-    show-footer-overflow
-    :column-config="{ resizable: true }"
-    :scroll-x="{ enabled: true, gt: 0 }"
-    :merge-cells="mergeCells"
-  >
-    <vxe-column field="index" title="排名" width="80" fixed="left">
-      <template #default="scope">
-        <div
-          v-if="scope._rowIndex == 0"
-          class="text-center text-sm font-extrabold text-[#000000] pt-4"
-        >
-          平均得分
-        </div>
-        <div v-if="scope._rowIndex > 3" class="diamond">
-          {{ scope.row.ranking }}
-        </div>
-        <div v-else class="text-center">
-          <img :src="RANK_IMG[scope.row.ranking - 1]" alt="" />
-        </div>
-      </template>
-    </vxe-column>
-    <vxe-column
-      v-if="$route.name == 'workerDrak' || $route.name == 'workerRank'"
-      field="deptName"
-      :title="tabTitle"
-      fixed="left"
-      width="150"
-    />
-    <vxe-column
-      v-else
-      field="assessmentObjectName"
-      :title="deptName"
-      fixed="left"
-      width="150"
-    />
-    <vxe-column
-      v-if="$route.name == 'workerDrak' || $route.name == 'workerRank'"
-      field="assessmentObjectName"
-      fixed="left"
-      title="姓名"
-      width="100"
-    />
-    <template v-for="(ita, itk) in tableData" :key="itk">
-      <template v-for="item in ita.dimensionList" :key="item.dimId">
-        <vxe-colgroup
-          :title="`${item.dimName}(${soreRate(item.soreRate)}%)`"
-          width="150"
-        >
-          <template v-for="it in item.quotaList" :key="it.quotaId">
-            <vxe-column
-              :field="it.quotaScore"
-              :title="`${it.quotaName}(${soreRate(it.quotaWeight)}%)`"
-              width="150"
-            />
-          </template>
-        </vxe-colgroup>
-        <vxe-column field="totalSore" title="总分" width="150" />
-      </template>
-    </template>
-    <vxe-column field="allScore" title="总得分" fixed="right" width="150" />
-  </vxe-table>
-</template>
-
-<script lang="ts" setup>
-import { computed, reactive, ref, onMounted } from "vue";
-import rank1 from "@/assets/rank/rank1.png";
-import rank2 from "@/assets/rank/rank2.png";
-import rank3 from "@/assets/rank/rank3.png";
-import { useRoute } from "vue-router";
-const $route = useRoute();
-const RANK_IMG = [rank1, rank2, rank3];
-const deptName = ref("");
-const name = ref("");
-const tableData = ref();
-const tabTitle = ref("");
-const mergeCells = ref([
-  // 合并第一行前两列
-  { row: 0, col: 0, rowspan: 1, colspan: 2 },
-  { row: 2, col: 1, rowspan: 0, colspan: 0 }
-]);
-onMounted(() => {
-  cellTable();
-});
-const cellTable = () => {
-  // if ($route.name == "workerRank") {
-  //   mergeCells.value = [
-  //     { row: 0, col: 0, rowspan: 1, colspan: 3 },
-  //     { row: 2, col: 1, rowspan: 1, colspan: 3 }
-  //   ];
-  // }
-  if ($route.name == "healthDrank" || $route.name == "healthRank") {
-    tabTitle.value = "医疗组";
-  } else {
-    tabTitle.value = "科室";
-  }
-};
-const averageData = averageSore => {
-  if ($route.name != "workerDrak" || $route.name != "workerRank") {
-    if (tableData.value.length > 0) {
-      tableData.value.unshift({
-        dimensionList: [],
-        allScore: averageSore
-      });
-    }
-  }
-};
-const init = (item, deptNames, names) => {
-  tableData.value = item;
-  deptName.value = deptNames;
-  name.value = names;
-  if ($route.name != "workerDrak") {
-    averageData(item.averageSore);
-  }
-  console.log("tableData.value", tableData.value);
-  console.log("deptName.value", item);
-};
-const soreRate = row => {
-  if (row) {
-    return row;
-  } else {
-    return 0;
-  }
-};
-defineExpose({
-  init
-});
-</script> -->
-
 <template>
-  <div class="w-full">
+  <div class="w-full aa">
+    <vxe-button class="float-right -top-20 mr-20 mb-4 z-50" @click="exportEvent"
+      ><el-icon> <Download /> </el-icon>&nbsp;&nbsp;导出</vxe-button
+    >
     <vxe-grid
       v-if="$route.name != 'workerDrak'"
       v-bind="gridOptions"
       ref="gridRef"
+      class="mt-10"
       :merge-cells="mergeCells"
-      v-on="gridEvents"
     >
       <template #imgUrl_default="{ row }">
         <div>
@@ -160,7 +28,7 @@ defineExpose({
         {{ row.allScore }}
       </template>
     </vxe-grid>
-    <vxe-grid v-else v-bind="gridOptions">
+    <vxe-grid v-else v-bind="gridOptions" ref="gridRef1" class="mt-10">
       <template #imgUrl_default="{ row }">
         <div v-if="row.ranking <= 3" class="text-center">
           <img class="mt-auto" :src="RANK_IMG[Number(row.ranking) - 1]" />
@@ -175,12 +43,17 @@ defineExpose({
 </template>
 
 <script setup>
+import { ElMessage } from "element-plus";
 import { ref, reactive, watch, onMounted, nextTick } from "vue";
 import rank1 from "@/assets/rank/rank1.png";
 import rank2 from "@/assets/rank/rank2.png";
 import rank3 from "@/assets/rank/rank3.png";
+import dayjs from "dayjs";
 import { useRoute } from "vue-router";
 const gridRef = ref(null);
+const gridRef1 = ref(null);
+// 导出数据
+const fileData = ref([]);
 const $route = useRoute();
 const RANK_IMG = [rank1, rank2, rank3];
 const deptName = ref("");
@@ -199,7 +72,8 @@ const averageData = averageSore => {
     // num = num / rawData.value.length;
     rawData.value.unshift({
       dimensionList: [],
-      allScore: rawData.value[0].averageSore
+      allScore: rawData.value[0].averageSore,
+      isAverageRow: true // 标记为平均分行
     });
   }
 };
@@ -209,8 +83,9 @@ const gridOptions = reactive({
   loading: false,
   height: 500,
   sortConfig: {
-    multiple: true
+    multiple: false
   },
+  exportConfig: {},
   columns: [],
   data: [],
   showOverflow: true,
@@ -246,31 +121,14 @@ const init = (item, deptNames, names) => {
 defineExpose({
   init
 });
-
-// 排序状态
-const gridEvents = {
-  sortChange({ column, order }) {
-    // 如果没有选择排序列或没有排序方向,则直接返回
-    if (!column || !order) {
-      gridOptions.data = [...originalData.value];
-    } else {
-      // 排除第一行,如果路由名称不是 "workerDrak"
-      const rowsToSort = gridOptions.data.slice(1); // 排除第一行
-      const sortedRows = rowsToSort.sort((a, b) => {
-        // 根据点击的列字段和排序方向进行排序
-        if (order === "asc") {
-          return a[column.field] < b[column.field] ? -1 : 1;
-        } else {
-          return a[column.field] > b[column.field] ? -1 : 1;
-        }
-      });
-
-      // 将第一行重新插入到排序后的数据顶部
-      const sortedData = [gridOptions.data[0], ...sortedRows];
-      gridOptions.data = sortedData; // 更新表格数据
-    }
+// 判断key值是否相同返回具体值
+function getValueByKey(obj, key) {
+  if (key in obj) {
+    return obj[key];
   }
-};
+  return null; // 如果 key 不存在则返回 null
+}
+
 // 生成动态表头
 const createColumns = () => {
   let columns = [];
@@ -301,7 +159,24 @@ const createColumns = () => {
         sortable: true,
         width: 150,
         fixed: "right", // 将此列固定在右侧
-        slots: { default: "dim-allScore" }
+        slots: { default: "dim-allScore" },
+        sortBy({ column, row }) {
+          // 如果是平均行(isAverageRow为true),则返回一个很大的值,避免被排序
+          if (column.field in row && typeof row[column.field] === "number") {
+            if (column.order == "asc") {
+              if (row.isAverageRow) {
+                return -9999999999;
+              }
+            } else {
+              if (row.isAverageRow) {
+                return 99999999999;
+              }
+            }
+          } else {
+            return -9999999999;
+          }
+          return row.allScore; // 返回正常的得分,进行排序
+        }
       }
     ];
   } else {
@@ -325,7 +200,24 @@ const createColumns = () => {
         width: 150,
         sortable: true,
         fixed: "right", // 将此列固定在右侧
-        slots: { default: "dim-allScore" }
+        slots: { default: "dim-allScore" },
+        sortBy({ column, row }) {
+          // 如果是平均行(isAverageRow为true),则返回一个很大的值,避免被排序
+          if (column.field in row && typeof row[column.field] === "number") {
+            if (column.order == "asc") {
+              if (row.isAverageRow) {
+                return -9999999999;
+              }
+            } else {
+              if (row.isAverageRow) {
+                return 99999999999;
+              }
+            }
+          } else {
+            return -9999999999;
+          }
+          return row.allScore; // 返回正常的得分,进行排序
+        }
       }
     ];
   }
@@ -361,7 +253,38 @@ const createColumns = () => {
       title: `${quota.quotaName} (${quota.quotaWeight}%)`, // 在 title 后拼接 quotaWeight
       width: 120,
       sortable: true,
-      field: `${dimName}_${quota.quotaName}` // 确保字段唯一
+      field: `${dimName}_${quota.quotaName}`, // 确保字段唯一
+      sortBy({ column, row }) {
+        // 如果是平均行(isAverageRow为true),则返回一个很大的值,避免被排序
+        let aa = Number(row[column.field]);
+        if (typeof aa === "number" && !isNaN(aa)) {
+          if (column.order == "asc") {
+            if (row.isAverageRow) {
+              return -9999999999;
+            }
+          } else {
+            if (row.isAverageRow) {
+              return 99999999999;
+            }
+          }
+        } else {
+          // 倒序在最后
+          if (column.order == "asc") {
+            if (!row.isAverageRow) {
+              return 9999999999999;
+            } else {
+              return -999999999999;
+            }
+          } else {
+            if (!row.isAverageRow) {
+              return -999999999999;
+            } else {
+              return 999999999999;
+            }
+          }
+        }
+        return getValueByKey(row, column.field); // 返回正常的得分,进行排序
+      }
     }));
 
     // 添加维度名称及其对应的子列
@@ -375,7 +298,38 @@ const createColumns = () => {
       title: `总分`, // 可根据需要调整标题
       field: `${dimName}_totalSore`,
       width: 120,
-      sortable: true
+      sortable: true,
+      sortBy({ column, row }) {
+        // 如果是平均行(isAverageRow为true),则返回一个很大的值,避免被排序
+        let aa = Number(row[column.field]);
+        if (typeof aa === "number" && !isNaN(aa)) {
+          if (column.order == "asc") {
+            if (row.isAverageRow) {
+              return -9999999999;
+            }
+          } else {
+            if (row.isAverageRow) {
+              return 99999999999;
+            }
+          }
+        } else {
+          // 倒序在最后
+          if (column.order == "asc") {
+            if (!row.isAverageRow) {
+              return 9999999999999;
+            } else {
+              return -999999999999;
+            }
+          } else {
+            if (!row.isAverageRow) {
+              return -999999999999;
+            } else {
+              return 999999999999;
+            }
+          }
+        }
+        return getValueByKey(row, column.field); // 返回正常的得分,进行排序
+      }
     });
   });
   gridOptions.columns = columns;
@@ -392,7 +346,8 @@ const loadData = () => {
       assessmentObjectName: item.assessmentObjectName,
       deptName: item.deptName,
       ranking: item.ranking,
-      allScore: item.allScore
+      allScore: item.allScore,
+      isAverageRow: item.isAverageRow || false // 确保数据里标记了是否为平均分行
     };
 
     item.dimensionList.forEach(dim => {
@@ -407,35 +362,34 @@ const loadData = () => {
 
       // 填充维度总分
       const totalFieldName = `${dim.dimName}_totalSore`;
-      row[totalFieldName] = dim.totalSore || totalScore; // 使用 dim.totalSore 或计算得出的总分
+      row[totalFieldName] = dim.totalSore || totalScore;
     });
 
     return row;
   });
-  originalData.value = [...tableData]; // 深拷贝原始数据
-  gridOptions.data = tableData;
 
-  // 使用 nextTick 确保表格已渲染完成后再合并单元格
+  originalData.value = [...tableData]; // 保存原始数据
+  tableData[0].sortable = true;
+  gridOptions.data = tableData;
+  fileData.value = JSON.parse(JSON.stringify(tableData));
+  if ($route.name != "workerDrak") {
+    fileData.value[0].ranking = "平均得分";
+  }
+  // 使用 nextTick 确保表格渲染完成后再合并单元格
   nextTick(() => {
     if (gridRef.value) {
       gridRef.value.setMergeCells([
-        // 合并第一行前两列
         { row: 0, col: 0, rowspan: 1, colspan: 2 },
         { row: 2, col: 1, rowspan: 0, colspan: 0 }
-      ]); // 重新合并单元格
+      ]);
     }
   });
-  // setTimeout(() => {
-  //   // 重新应用合并单元格
-  //   if (gridRef.value) {
-  //     gridRef.value.mergeCells(); // 重新合并单元格
-  //   }
-  // }, 500);
+
   gridOptions.loading = false;
 };
-
 // 监听年份变化,重新渲染
 watch(selectYear, () => {
+  // init(newVal.data, newVal.dept, newVal.name);
   createColumns();
   loadData();
   gridRef.value.setMergeCells([
@@ -455,6 +409,39 @@ onMounted(() => {
   // 监听窗口大小变化,动态调整表格高度
   window.addEventListener("resize", setGridHeight);
 });
+// 导出
+const exportEvent = () => {
+  let $grid;
+  let fileName =
+    localStorage.getItem("fileName") + dayjs().format("YYYY-MM-DD HH:mm:ss");
+  if ($route.name != "workerDrak") {
+    $grid = gridRef.value;
+  } else {
+    $grid = gridRef1.value;
+  }
+  if ($grid) {
+    // gridOptions.exportConfig = {
+    //   type: "xlsx",
+    //   fileName: name
+    // };
+    $grid.exportData({
+      type: "xlsx",
+      filename: fileName,
+      useStyle: true,
+      isMerge: true,
+      data: fileData.value
+    });
+    // $grid.exportData({
+    //   type: "xlsx",
+    //   fileName: name
+    // });
+  } else {
+    ElMessage({
+      message: "暂无数据",
+      type: "warning"
+    });
+  }
+};
 </script>
 <style lang="scss" scoped>
 .diamond {
@@ -490,4 +477,8 @@ onMounted(() => {
 .aaaa {
   background-color: black !important;
 }
+
+.aa {
+  position: relative;
+}
 </style>

+ 6 - 0
src/main.ts

@@ -35,6 +35,12 @@ Object.keys(directives).forEach(key => {
 });
 import VxeUITable from "vxe-table";
 import "vxe-table/lib/style.css";
+
+import VXETablePluginExportXLSX from "vxe-table-plugin-export-xlsx";
+import ExcelJS from "exceljs";
+VxeUITable.use(VXETablePluginExportXLSX, {
+  ExcelJS
+});
 // 全局注册@iconify/vue图标库
 import {
   IconifyIconOffline,

+ 1 - 0
src/views/draw/children/department/componements/seach.vue

@@ -68,6 +68,7 @@ const handClickInit1 = value => {
   if (value) {
     const selectedItem = dataList.magList.find(item => item.id === value);
     init.assessmentName = selectedItem.name;
+    localStorage.setItem("fileName", selectedItem.name);
     getTemplateInfoListApi(selectedItem);
   }
   Object.assign(dataList.params, {

+ 3 - 2
src/views/draw/children/head/componements/seach.vue

@@ -43,7 +43,7 @@ const userPageWhitOrganizationApi = async () => {
     dataList.personList = data.records;
   }
 };
-userPageWhitOrganizationApi();
+// userPageWhitOrganizationApi();
 // 考核活动
 // const getAssessmentPageListApi = async () => {
 //   const { data, code } = await getAssessmentList({
@@ -88,6 +88,7 @@ const handClickInit1 = value => {
   if (value) {
     const selectedItem = dataList.magList.find(item => item.id === value);
     init.assessmentName = selectedItem.name;
+    localStorage.setItem("fileName", selectedItem.name);
     getTemplateInfoListApi(selectedItem);
   }
   Object.assign(dataList.params, {
@@ -168,7 +169,7 @@ const getSearchFrom = () => {
       const selectedItems = dataList.teplist.find(
         item => item.assessmentModelId === assessmentModelId
       );
-      userPageWhitOrganizationApi(selectedItems);
+      // userPageWhitOrganizationApi(selectedItems);
       getLeaderListApi(selectedItems);
       setTimeout(() => {
         $emit(

+ 1 - 0
src/views/draw/children/health/componements/seach.vue

@@ -68,6 +68,7 @@ const handClickInit1 = value => {
   if (value) {
     const selectedItem = dataList.magList.find(item => item.id === value);
     init.assessmentName = selectedItem.name;
+    localStorage.setItem("fileName", selectedItem.name);
     getTemplateInfoListApi(selectedItem);
   }
   Object.assign(dataList.params, {

+ 1 - 14
src/views/draw/children/worker/componements/seach.vue

@@ -101,6 +101,7 @@ const handClickInit1 = value => {
   if (value) {
     const selectedItem = dataList.magList.find(item => item.id === value);
     init.assessmentName = selectedItem.name;
+    localStorage.setItem("fileName", selectedItem.name);
     getTemplateInfoListApi(selectedItem);
   }
   Object.assign(dataList.params, {
@@ -295,20 +296,6 @@ const handClickClear3 = () => {
               :value="item.deptCode"
             />
           </el-select>
-          <!-- <el-tree-select
-            v-model="dataList.params.deptCode"
-            :data="dataList.deptList"
-            check-strictly
-            filterable
-            clearable
-            :props="{
-              label: 'deptName',
-              value: 'deptCode',
-              children: 'childrenRes'
-            }"
-            style="width: 200px"
-            @node-click="handClickInit3"
-          /> -->
         </div>
         <div class="flex mr-2">
           <div class="text-sm leading-8 mr-3">员工</div>

+ 2 - 3
src/views/draw/children/worker/workerDrak.vue

@@ -24,7 +24,7 @@ const rankTableRef = ref();
 const activeName = ref("1");
 const barEchartsRef = ref();
 const barDimEchartsRef = ref();
-const seachParams = ref();
+const seachParams = ref<any>();
 // 排行榜
 const showLength = ref(0);
 const rankTableRefList = reactive({
@@ -136,7 +136,7 @@ const barDimEchartsList = reactive({
   data: null,
   type: null
 });
-const init = (item, type) => {
+const init = (item: any, type: any) => {
   seachParams.value = item;
   barDimEchartsList.data = null;
   barDimEchartsList.type = null;
@@ -150,7 +150,6 @@ const init = (item, type) => {
     // getPersonDimensionChartsRankingApi();
     getPersonDimensionChartsListApiDimList();
     getChartsListApi();
-    // debugger;
     activeName.value = "1";
   }
   setTimeout(() => {

+ 0 - 1
src/views/evaluate/children/change/components/newAdd.vue

@@ -335,7 +335,6 @@ const onStart = (e: DraggableEvent) => {};
 const onUpdate = (e: DraggableEvent) => {};
 
 const postUpdateApi = async row => {
-  console.log();
   // indexOf.indName = indexOf.name
   const { code, msg } = await postUpdate(row);
   if (code == 200) {

+ 0 - 1
src/views/login/index.vue

@@ -71,7 +71,6 @@ const onLogin = async (formEl: FormInstance | undefined) => {
             // @ts-ignore
             localStorage.setItem("userName", res.data.realName);
             //  获取后端路由动态路由逻辑,不可删除
-            // debugger;
             initRouter().then(() => {
               // router.push(getTopMenu(true).path);
               router.push("/");

+ 5 - 0
src/views/password/index.vue

@@ -22,6 +22,11 @@ const UpdatePasswordApi = async () => {
     if (valid) {
       const { code } = await postUpdatePassword(formLabelAlign);
       if (code === 200) {
+        Object.assign(formLabelAlign, {
+          oldPwd: "",
+          newPwd: "",
+          reNewPwd: ""
+        });
         ElMessage({
           message: "修改成功",
           type: "success"

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff