|
@@ -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> 导出</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>
|