From da65acd978c10cf75c91334ee1a768e7d82884f7 Mon Sep 17 00:00:00 2001
From: WXL (wul) <wl_5969728@163.com>
Date: 星期一, 09 十一月 2026 17:04:56 +0800
Subject: [PATCH] 测试完成
---
src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue | 417 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 362 insertions(+), 55 deletions(-)
diff --git a/src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue b/src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue
index d8687d5..92cd112 100644
--- a/src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue
+++ b/src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue
@@ -149,6 +149,8 @@
style="width: 100%"
@selection-change="handleSelectionChange"
:row-key="getRowKey"
+ show-summary
+ :summary-method="getSummaries"
>
<!-- 鐥呭尯缁熻锛氬湪闄㈢梾鍖� + 绂婚櫌鐥呭尯 -->
<el-table-column
@@ -1291,6 +1293,92 @@
return `${(num * 100).toFixed(2)}%`;
},
+ // 琛ㄦ牸鍚堣琛�
+ getSummaries(param) {
+ const { columns, data } = param;
+ const sums = [];
+
+ columns.forEach((column, index) => {
+ if (index === 0) {
+ sums[index] = "鍚堣";
+ return;
+ }
+
+ const prop = column.property;
+
+ // 鏁板�煎垪姹傚拰
+ if (
+ [
+ "dischargeCount",
+ "nonFollowUp",
+ "followUpNeeded",
+ "joyAllCount",
+ "joyCount",
+ ].includes(prop)
+ ) {
+ sums[index] = data.reduce(
+ (sum, item) => sum + (Number(item[prop]) || 0),
+ 0
+ );
+ return;
+ }
+
+ // 瀹屾垚姣旂巼锛氭弧鎰忓害濉姤閲� / 婊℃剰搴﹂鐩�婚噺
+ if (prop === "joyTotal") {
+ const totalJoyAllCount = data.reduce(
+ (sum, item) => sum + (Number(item.joyAllCount) || 0),
+ 0
+ );
+ const totalJoyCount = data.reduce(
+ (sum, item) => sum + (Number(item.joyCount) || 0),
+ 0
+ );
+ sums[index] =
+ totalJoyAllCount > 0
+ ? ((totalJoyCount / totalJoyAllCount) * 100).toFixed(2) + "%"
+ : "0.00%";
+ return;
+ }
+
+ // 鐧惧垎姣斿垪锛堥殢璁跨巼/鍙婃椂鐜囷級锛氬彇骞冲潎鍊硷紙0 鍊间篃鍙備笌骞冲潎锛�
+ if (prop === "followUpRate" || prop === "rate") {
+ const percentageValues = data
+ .map((item) => {
+ const value = item[prop];
+ if (
+ value === null ||
+ value === undefined ||
+ value === "" ||
+ value === "-"
+ ) {
+ return null;
+ }
+ if (typeof value === "string" && value.includes("%")) {
+ const num = parseFloat(value.replace("%", "")) / 100;
+ return isNaN(num) ? null : num;
+ }
+ const num = parseFloat(value);
+ return isNaN(num) ? null : num;
+ })
+ .filter((value) => value !== null);
+
+ sums[index] =
+ percentageValues.length > 0
+ ? (
+ (percentageValues.reduce((sum, value) => sum + value, 0) /
+ percentageValues.length) *
+ 100
+ ).toFixed(2) + "%"
+ : "0.00%";
+ return;
+ }
+
+ sums[index] = "";
+ });
+
+ return sums;
+ },
+
// 鏌ョ湅鏈強鏃堕殢璁胯鎯�
handleSeedetails(row) {
this.currentRow = row;
@@ -1353,6 +1441,113 @@
console.error("鑾峰彇婊℃剰搴﹁鎯呭け璐�:", error);
this.$message.error("鑾峰彇璇︽儏澶辫触");
}
+ },
+
+ // 鑾峰彇鎸囧畾鐥呭尯/绉戝鐨勯鐩鎯�
+ async fetchTopicDetail(row) {
+ const params = {
+ configKey: "joyCount",
+ ...this.queryParams,
+ };
+ // 瀵煎嚭闇�瑕佽鐥呭尯/绉戝鐨勫叏閮ㄩ鐩紝瑕嗙洊涓昏〃鍒嗛〉鍙傛暟
+ params.pageNum = 1;
+ params.pageSize = 1000;
+ if (
+ this.queryParams.dateRange &&
+ this.queryParams.dateRange.length === 2
+ ) {
+ params.startTime = this.queryParams.dateRange[0];
+ params.endTime = this.queryParams.dateRange[1];
+ }
+ if (this.queryParams.statisticaltype == 1) {
+ params.leavehospitaldistrictcodes = [row.leavehospitaldistrictcode];
+ } else {
+ params.deptcodes = [row.deptcode];
+ }
+ const response = await getSfStatisticsJoyInfo(params);
+ return response.data || {};
+ },
+
+ // 涓昏〃瀵煎嚭琛屾暟鎹�
+ getMainExportRow(item) {
+ return [
+ this.queryParams.statisticaltype == 1
+ ? item.leavehospitaldistrictname
+ : item.deptname,
+ item.dischargeCount || 0,
+ item.nonFollowUp || 0,
+ item.followUpNeeded || 0,
+ item.followUpRate || "0%",
+ item.rate ? this.formatPercent(item.rate) : "0%",
+ item.joyAllCount || 0,
+ item.joyCount || 0,
+ item.joyTotal ? this.formatPercent(item.joyTotal) : "0%",
+ ];
+ },
+
+ // 璁$畻鏂囨湰鏄剧ず瀹藉害锛堜腑鏂囨寜 2銆佽嫳鏂�/鏁板瓧鎸� 1锛�
+ textWidth(str) {
+ if (!str) return 0;
+ let width = 0;
+ for (const ch of String(str)) {
+ width += ch.charCodeAt(0) > 255 ? 2 : 1;
+ }
+ return width;
+ },
+
+ // 涓芥按甯備腑鍖婚櫌锛氭媺鍙栨墍鏈夌瀹ら鐩槑缁嗭紝鎵佸钩鍖栦负銆岄鐩�夐」銆嶅垪缁撴瀯
+ async buildLishuiTopicColumns() {
+ const topicMap = new Map();
+ const rowQuantities = [];
+
+ for (const item of this.userList) {
+ const topiclist = await this.fetchTopicDetail(item);
+ const qMap = new Map();
+
+ if (topiclist && Object.keys(topiclist).length) {
+ Object.keys(topiclist).forEach((key) => {
+ const topic = topiclist[key];
+ if (!topic || !topic.scriptContent) return;
+
+ const tKey =
+ topic.scriptid != null && topic.scriptid !== ""
+ ? String(topic.scriptid)
+ : topic.scriptContent;
+
+ if (!topicMap.has(tKey)) {
+ topicMap.set(tKey, {
+ key: tKey,
+ scriptContent: topic.scriptContent,
+ options: [],
+ optionSet: new Set(),
+ });
+ }
+
+ const t = topicMap.get(tKey);
+ const topicQ = new Map();
+ (topic.details || []).forEach((detail) => {
+ if (!detail || !detail.optionText) return;
+ if (!t.optionSet.has(detail.optionText)) {
+ t.optionSet.add(detail.optionText);
+ t.options.push(detail.optionText);
+ }
+ topicQ.set(detail.optionText, Number(detail.chosenQuantity) || 0);
+ });
+ qMap.set(tKey, topicQ);
+ });
+ }
+
+ rowQuantities.push(qMap);
+ }
+
+ const topics = Array.from(topicMap.values());
+ // 娌℃湁閫夐」鐨勯鐩粯璁ゅ~鍏呬竴涓┖閫夐」鍒楋紝閬垮厤琛ㄥご/鏁版嵁閿欎綅
+ topics.forEach((t) => {
+ if (!t.options.length) {
+ t.options = [""];
+ }
+ });
+ return { topics, rowQuantities };
},
// 瀵煎嚭鏁版嵁
@@ -1446,7 +1641,11 @@
pattern: "solid",
fgColor: { argb: "FFF5F7FA" },
},
- alignment: { vertical: "middle", horizontal: "center" },
+ alignment: {
+ vertical: "middle",
+ horizontal: "center",
+ wrapText: true,
+ },
border: {
top: { style: "thin", color: { argb: "FFD0D0D0" } },
left: { style: "thin", color: { argb: "FFD0D0D0" } },
@@ -1466,74 +1665,182 @@
},
};
- // 琛ㄥご鎸夐〉闈㈠垪鍔ㄦ�佺敓鎴愶細绉戝/鐥呭尯缁熻鍒椾笉鍚岋紝銆屽強鏃剁巼銆嶅彧鏈夋櫙瀹侀櫌鍖洪〉闈㈡墠鏄剧ず
- const isWardStatistics = this.queryParams.statisticaltype == 1;
- const showTimelyRate = this.orgname === "鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�";
- const headers = [
- isWardStatistics ? "鍦ㄩ櫌鐥呭尯" : "鍦ㄩ櫌绉戝",
- isWardStatistics ? "绂婚櫌鐥呭尯" : "绂婚櫌绉戝",
+ // 涓芥按甯備腑鍖婚櫌锛氶鍏堟媺鍙栭鐩槑缁嗭紝鎵佸钩鍖栦负銆岄鐩�夐」銆嶅垪
+ let lishuiTopics = [];
+ let lishuiRowQuantities = [];
+ if (isLishuiHospital) {
+ const built = await this.buildLishuiTopicColumns();
+ lishuiTopics = built.topics;
+ lishuiRowQuantities = built.rowQuantities;
+ }
+
+ // 涓昏〃鍒�
+ const mainHeaders = [
+ this.queryParams.statisticaltype == 1 ? "鍑洪櫌鐥呭尯" : "绉戝",
"鍑洪櫌浜烘",
"鏃犻渶闅忚浜烘",
"搴旈殢璁夸汉娆�",
"闅忚鐜�",
+ "鍙婃椂鐜�",
+ "婊℃剰搴﹂鐩�婚噺",
+ "婊℃剰搴﹀~鎶ラ噺",
+ "瀹屾垚姣旂巼",
];
- if (showTimelyRate) {
- headers.push("鍙婃椂鐜�");
- }
- headers.push("婊℃剰搴﹂鐩�婚噺", "婊℃剰搴﹀~鎶ラ噺", "瀹屾垚姣旂巼");
- const colCount = headers.length;
+ const mainColumnCount = mainHeaders.length;
+
+ // 鎬诲垪鏁帮紙涓芥按甯備腑鍖婚櫌鍦ㄦ湯灏捐拷鍔犻鐩�夐」鍒楋級
+ const topicColumnCount = lishuiTopics.reduce(
+ (sum, t) => sum + (t.options.length || 1),
+ 0
+ );
+ const totalColumns = mainColumnCount + topicColumnCount;
// 娣诲姞鎬绘爣棰�
- worksheet.mergeCells(1, 1, 1, colCount);
+ worksheet.mergeCells(1, 1, 1, totalColumns);
const titleCell = worksheet.getCell(1, 1);
titleCell.value = `婊℃剰搴﹂殢璁跨粺璁¤〃锛�${sheetNameSuffix}锛塦;
titleCell.style = titleStyle;
worksheet.getRow(1).height = 35;
- const headerRow = worksheet.addRow(headers);
- headerRow.eachCell((cell) => {
- cell.style = headerStyle;
- });
- headerRow.height = 25;
-
- // 娣诲姞鏁版嵁琛岋紙绌哄�肩粺涓�鏄剧ず鈥�-鈥濓紝涓庨〉闈繚鎸佷竴鑷达級
- const dash = (v, formatter) => {
- if (v === null || v === undefined || v === "") return "-";
- return formatter ? formatter(v) : v;
- };
- this.userList.forEach((item) => {
- const rowData = [
- isWardStatistics
- ? item.hospitaldistrictname || "-"
- : item.hospitaldeptname || "-",
- isWardStatistics
- ? item.leavehospitaldistrictname || "-"
- : item.deptname || "-",
- item.dischargeCount || 0,
- item.nonFollowUp || 0,
- item.followUpNeeded || 0,
- dash(item.followUpRate),
- ];
- if (showTimelyRate) {
- rowData.push(dash(item.rate, (v) => this.formatPercent(v)));
- }
- rowData.push(
- item.joyAllCount || 0,
- item.joyCount || 0,
- dash(item.joyTotal, (v) => this.formatPercent(v))
- );
- const dataRow = worksheet.addRow(rowData);
-
- dataRow.eachCell((cell) => {
- cell.style = cellStyle;
+ if (isLishuiHospital && lishuiTopics.length) {
+ // 璁$畻姣忎釜棰樼洰鐨勯�夐」鍒楀锛堥�夐」鏂囧瓧鑷�傚簲锛岄骞茶繃闀挎椂鎽婂鍒椼�佸繀瑕佹椂鎹㈣锛�
+ const topicColumns = lishuiTopics.map((topic) => {
+ const n = topic.options.length || 1;
+ const baseWidths = topic.options.map((opt) =>
+ opt === "" ? 10 : Math.max(10, this.textWidth(opt) + 4)
+ );
+ const sumWidth = baseWidths.reduce((s, w) => s + w, 0);
+ const topicWidth = this.textWidth(topic.scriptContent) + 4;
+ const groupWidth = Math.max(sumWidth, topicWidth);
+ const extra = (groupWidth - sumWidth) / n;
+ const widths = baseWidths.map((w) => w + extra);
+ const lines = Math.max(1, Math.ceil(topicWidth / groupWidth));
+ return { widths, lines };
});
- dataRow.height = 22;
- });
+ const maxHeaderLines = topicColumns.reduce(
+ (m, t) => Math.max(m, t.lines),
+ 1
+ );
- // 璁剧疆鍒楀锛堣窡鍒楁暟涓�鑷达級
- worksheet.columns = headers.map((h, i) => ({
- width: i < 2 ? 20 : h.length > 6 ? 15 : 12,
- }));
+ // 涓よ琛ㄥご锛氱涓�琛� = 涓昏〃鍒� + 棰樼洰鍚嶏紱绗簩琛� = 閫夐」鍚�
+ const headerRow1 = worksheet.addRow([]);
+ const headerRow2 = worksheet.addRow([]);
+
+ mainHeaders.forEach((h, i) => {
+ const col = i + 1;
+ headerRow1.getCell(col).value = h;
+ headerRow1.getCell(col).style = headerStyle;
+ headerRow2.getCell(col).style = headerStyle;
+ worksheet.mergeCells(
+ headerRow1.number,
+ col,
+ headerRow2.number,
+ col
+ );
+ });
+
+ let colIndex = mainColumnCount + 1;
+ lishuiTopics.forEach((topic) => {
+ const optCount = topic.options.length || 1;
+ for (let k = 0; k < optCount; k++) {
+ headerRow1.getCell(colIndex + k).style = headerStyle;
+ }
+ headerRow1.getCell(colIndex).value = topic.scriptContent;
+ if (optCount > 1) {
+ worksheet.mergeCells(
+ headerRow1.number,
+ colIndex,
+ headerRow1.number,
+ colIndex + optCount - 1
+ );
+ }
+ topic.options.forEach((opt, k) => {
+ headerRow2.getCell(colIndex + k).value = opt;
+ headerRow2.getCell(colIndex + k).style = headerStyle;
+ });
+ colIndex += optCount;
+ });
+
+ // 琛ㄥご楂樺害锛氶骞叉崲琛屾椂鎸夋渶闀块鐩鐣�
+ headerRow1.height = Math.max(30, 15 * maxHeaderLines + 8);
+ headerRow2.height = 25;
+
+ // 鏁版嵁琛�
+ this.userList.forEach((item, idx) => {
+ const row = worksheet.addRow([]);
+ const main = this.getMainExportRow(item);
+ main.forEach((v, i) => {
+ const cell = row.getCell(i + 1);
+ cell.value = v;
+ cell.style = cellStyle;
+ });
+
+ const qMap = lishuiRowQuantities[idx] || new Map();
+ let cIndex = mainColumnCount + 1;
+ for (const topic of lishuiTopics) {
+ const topicQ = qMap.get(topic.key);
+ topic.options.forEach((opt) => {
+ const cell = row.getCell(cIndex);
+ if (opt === "") {
+ // 绌洪�夐」鍗犱綅鍒椾笉濉暟瀛�
+ cell.value = "";
+ } else {
+ const val = topicQ ? topicQ.get(opt) : undefined;
+ cell.value = val === undefined || val === null ? 0 : val;
+ }
+ cell.style = cellStyle;
+ cIndex++;
+ });
+ }
+ row.height = 22;
+ });
+
+ // 鍒楀锛氫富琛ㄥ垪 + 棰樼洰閫夐」鍒�
+ const columns = [
+ { width: 20 },
+ { width: 12 },
+ { width: 12 },
+ { width: 12 },
+ { width: 12 },
+ { width: 12 },
+ { width: 15 },
+ { width: 15 },
+ { width: 12 },
+ ];
+ lishuiTopics.forEach((topic, ti) => {
+ topicColumns[ti].widths.forEach((w) => {
+ columns.push({ width: w });
+ });
+ });
+ worksheet.columns = columns;
+ } else {
+ // 鍏朵粬鍖婚櫌锛氬崟琛岃〃澶�
+ const headerRow = worksheet.addRow(mainHeaders);
+ headerRow.eachCell((cell) => {
+ cell.style = headerStyle;
+ });
+ headerRow.height = 25;
+
+ this.userList.forEach((item) => {
+ const dataRow = worksheet.addRow(this.getMainExportRow(item));
+ dataRow.eachCell((cell) => {
+ cell.style = cellStyle;
+ });
+ dataRow.height = 22;
+ });
+
+ worksheet.columns = [
+ { width: 20 },
+ { width: 12 },
+ { width: 12 },
+ { width: 12 },
+ { width: 12 },
+ { width: 12 },
+ { width: 15 },
+ { width: 15 },
+ { width: 12 },
+ ];
+ }
// 鐢熸垚骞朵笅杞芥枃浠�
const buffer = await workbook.xlsx.writeBuffer();
--
Gitblit v1.9.3