|
@@ -134,13 +134,17 @@ defineExpose({
|
|
|
</script> -->
|
|
|
|
|
|
<template>
|
|
|
- <div class="w-full">
|
|
|
+ <div class="w-full aa">
|
|
|
+ <vxe-button class="float-right -top-10 mr-20 mb-4" @click="exportEvent"
|
|
|
+ ><el-icon> <Download /> </el-icon>导出</vxe-button
|
|
|
+ >
|
|
|
<vxe-grid
|
|
|
v-if="$route.name != 'workerDrak'"
|
|
|
v-bind="gridOptions"
|
|
|
ref="gridRef"
|
|
|
+ class="mt-10"
|
|
|
:merge-cells="mergeCells"
|
|
|
- v-on="gridEvents"
|
|
|
+ @sortChange="changeSort"
|
|
|
>
|
|
|
<template #imgUrl_default="{ row }">
|
|
|
<div>
|
|
@@ -160,7 +164,13 @@ 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"
|
|
|
+ @sortChange="changeSort"
|
|
|
+ >
|
|
|
<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 +185,15 @@ 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 $route = useRoute();
|
|
|
const RANK_IMG = [rank1, rank2, rank3];
|
|
|
const deptName = ref("");
|
|
@@ -199,7 +212,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 +223,9 @@ const gridOptions = reactive({
|
|
|
loading: false,
|
|
|
height: 500,
|
|
|
sortConfig: {
|
|
|
- multiple: true
|
|
|
+ multiple: false
|
|
|
},
|
|
|
+ exportConfig: {},
|
|
|
columns: [],
|
|
|
data: [],
|
|
|
showOverflow: true,
|
|
@@ -250,27 +265,79 @@ defineExpose({
|
|
|
// 排序状态
|
|
|
const gridEvents = {
|
|
|
sortChange({ column, order }) {
|
|
|
- // 如果没有选择排序列或没有排序方向,则直接返回
|
|
|
if (!column || !order) {
|
|
|
- gridOptions.data = [...originalData.value];
|
|
|
+ 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 = [...originalData.value];
|
|
|
+ // 先将所有 isAverageRow 为 true 的行提取出来
|
|
|
+ const averageRows = sortedData.filter(item => item.isAverageRow);
|
|
|
+ const otherRows = sortedData.filter(item => !item.isAverageRow);
|
|
|
+
|
|
|
+ // 对其他数据进行排序
|
|
|
+ otherRows.sort((a, b) => {
|
|
|
+ const field = column.field;
|
|
|
+ const aValue = a[field];
|
|
|
+ const bValue = b[field];
|
|
|
+
|
|
|
+ // 根据正序倒序来决定排序规则
|
|
|
+ if (order === "ascending") {
|
|
|
+ return aValue > bValue ? 1 : aValue < bValue ? -1 : 0;
|
|
|
+ } else if (order === "descending") {
|
|
|
+ return aValue < bValue ? 1 : aValue > bValue ? -1 : 0;
|
|
|
}
|
|
|
+ return 0;
|
|
|
});
|
|
|
|
|
|
- // 将第一行重新插入到排序后的数据顶部
|
|
|
- const sortedData = [gridOptions.data[0], ...sortedRows];
|
|
|
- gridOptions.data = sortedData; // 更新表格数据
|
|
|
+ // 将排序后的数据与平均分行数据合并,平均分行始终放在最前面
|
|
|
+ gridOptions.data = [...averageRows, ...otherRows];
|
|
|
+
|
|
|
+ // 使用深拷贝确保数据变化被检测到
|
|
|
+ nextTick(() => {
|
|
|
+ if (gridRef.value) {
|
|
|
+ // 使用 loadData 传递深拷贝的数据
|
|
|
+ gridRef.value.loadData([...averageRows, ...otherRows]);
|
|
|
+ }
|
|
|
+ });
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
+function changeSort({ column, order }) {
|
|
|
+ if (!column || !order) {
|
|
|
+ gridOptions.data = [...originalData.value]; // 恢复到原始数据
|
|
|
+ } else {
|
|
|
+ const sortedData = [...originalData.value];
|
|
|
+ // 先将所有 isAverageRow 为 true 的行提取出来
|
|
|
+ const averageRows = sortedData.filter(item => item.isAverageRow);
|
|
|
+ const otherRows = sortedData.filter(item => !item.isAverageRow);
|
|
|
+
|
|
|
+ // 对其他数据进行排序
|
|
|
+ otherRows.sort((a, b) => {
|
|
|
+ const field = column.field;
|
|
|
+ const aValue = a[field];
|
|
|
+ const bValue = b[field];
|
|
|
+
|
|
|
+ // 根据正序倒序来决定排序规则
|
|
|
+ if (order === "ascending") {
|
|
|
+ return aValue > bValue ? 1 : aValue < bValue ? -1 : 0;
|
|
|
+ } else if (order === "descending") {
|
|
|
+ return aValue < bValue ? 1 : aValue > bValue ? -1 : 0;
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
+ });
|
|
|
+
|
|
|
+ // 将排序后的数据与平均分行数据合并,平均分行始终放在最前面
|
|
|
+ gridOptions.data = [...averageRows, ...otherRows];
|
|
|
+ console.log("132131排序", [...averageRows, ...otherRows]);
|
|
|
+ // 使用深拷贝确保数据变化被检测到
|
|
|
+ nextTick(() => {
|
|
|
+ if (gridRef.value) {
|
|
|
+ // 使用 loadData 传递深拷贝的数据
|
|
|
+ gridRef.value.loadData([...averageRows, ...otherRows]);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
// 生成动态表头
|
|
|
const createColumns = () => {
|
|
|
let columns = [];
|
|
@@ -392,7 +459,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,33 +475,28 @@ const loadData = () => {
|
|
|
|
|
|
// 填充维度总分
|
|
|
const totalFieldName = `${dim.dimName}_totalSore`;
|
|
|
- row[totalFieldName] = dim.totalSore || totalScore; // 使用 dim.totalSore 或计算得出的总分
|
|
|
+ row[totalFieldName] = dim.totalSore || totalScore;
|
|
|
});
|
|
|
|
|
|
return row;
|
|
|
});
|
|
|
- originalData.value = [...tableData]; // 深拷贝原始数据
|
|
|
+
|
|
|
+ originalData.value = [...tableData]; // 保存原始数据
|
|
|
+ tableData[0].sortable = true;
|
|
|
gridOptions.data = tableData;
|
|
|
|
|
|
- // 使用 nextTick 确保表格已渲染完成后再合并单元格
|
|
|
+ // 使用 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, () => {
|
|
|
createColumns();
|
|
@@ -455,6 +518,37 @@ 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
|
|
|
+ });
|
|
|
+ // $grid.exportData({
|
|
|
+ // type: "xlsx",
|
|
|
+ // fileName: name
|
|
|
+ // });
|
|
|
+ } else {
|
|
|
+ ElMessage({
|
|
|
+ message: "暂无数据",
|
|
|
+ type: "warning"
|
|
|
+ });
|
|
|
+ }
|
|
|
+};
|
|
|
</script>
|
|
|
<style lang="scss" scoped>
|
|
|
.diamond {
|
|
@@ -490,4 +584,8 @@ onMounted(() => {
|
|
|
.aaaa {
|
|
|
background-color: black !important;
|
|
|
}
|
|
|
+
|
|
|
+.aa {
|
|
|
+ position: relative;
|
|
|
+}
|
|
|
</style>
|