From d725dc65cf7f74df3aa3f5a0297fd6f8b767cdbc Mon Sep 17 00:00:00 2001
From: liusheng <337615773@qq.com>
Date: 星期五, 30 十月 2026 10:23:03 +0800
Subject: [PATCH] Merge branch 'subtask' of http://116.62.18.175:6699/r/~yxh/smartor-web into subtask

---
 src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue |  175 ++++++++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 127 insertions(+), 48 deletions(-)

diff --git a/src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue b/src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue
index 86c5b41..e5b5e64 100644
--- a/src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue
+++ b/src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue
@@ -41,7 +41,7 @@
         <el-button type="primary" size="small" icon="el-icon-search" @click="refreshAll">鏌ヨ</el-button>
         <el-button size="small" icon="el-icon-refresh" @click="handleReset">閲嶇疆</el-button>
       </div>
-      <el-button type="danger" size="small" icon="el-icon-download" @click="exportPDF">瀵煎嚭PDF</el-button>
+      <el-button type="danger" size="small" icon="el-icon-download" @click="exportExcel">瀵煎嚭Excel</el-button>
     </div>
 
     <el-row :gutter="20">
@@ -171,6 +171,8 @@
 
 <script>
 import * as echarts from 'echarts';
+import ExcelJS from 'exceljs';
+import { saveAs } from 'file-saver';
 import { mydTrend, sltdMydTotalByDimension, sltdMydTotalByScore ,mzMydScoreRank} from "@/api/AiCentre/satisfaction";
 import { getissuelist } from "@/api/AiCentre/questionnaire";
 
@@ -198,10 +200,10 @@
       singleQuestionContent: '',
       singleDeptWards: [],
 
-      // 鎺掑悕缁村害绛涢��
-      rankDimension: 'dept',
+      // 鎺掑悕缁村害绛涢�夛紙榛樿鎸夌梾鍖猴級
+      rankDimension: 'ward',
       rankDeptWards: [],
-      crossDimension: 'dept',
+      crossDimension: 'ward',
       crossDeptWards: [],
 
       // 鍥捐〃鏁版嵁
@@ -845,52 +847,129 @@
       });
     },
 
-    async exportPDF() {
-      const chartRefs = [
-        { ref: this.$refs.chart1, id: 'chart1' },
-        { ref: this.$refs.chart2, id: 'chart2' },
-        { ref: this.$refs.chart4, id: 'chart4' },
-      ];
-      const chartImages = {};
-      for (const { ref, id } of chartRefs) {
-        if (ref) {
-          const instance = echarts.getInstanceByDom(ref);
-          if (instance) {
-            chartImages[id] = instance.getDataURL({ type: 'png', pixelRatio: 2, backgroundColor: '#fff' });
+    // 瀵煎嚭锛氬浘琛ㄨ浆鍥剧墖 + 琛ㄦ牸锛屽唴瀹逛笌椤甸潰涓�鑷达紙鐩存帴涓嬭浇 xlsx锛屼笉渚濊禆鎵撳嵃锛�
+    async exportExcel() {
+      try {
+        const wb = new ExcelJS.Workbook();
+
+        // 鍥捐〃 sheet
+        const addImageSheet = (sheetName, title, refEl, tip) => {
+          const ws = wb.addWorksheet(sheetName, {
+            views: [{ showGridLines: false }],
+          });
+          ws.getCell('A1').value = title;
+          ws.getCell('A1').font = { size: 14, bold: true };
+          ws.mergeCells('A1:F1');
+          let anchorRow = 2.2;
+          if (tip) {
+            ws.getCell('A2').value = tip;
+            ws.mergeCells('A2:F2');
+            anchorRow = 2.8;
           }
-        }
+          for (let c = 1; c <= 6; c++) {
+            ws.getColumn(c).width = 18;
+          }
+          const inst = refEl ? echarts.getInstanceByDom(refEl) : null;
+          if (inst) {
+            const url = inst.getDataURL({
+              type: 'png',
+              pixelRatio: 2,
+              backgroundColor: '#fff',
+            });
+            const imgId = wb.addImage({
+              base64: url.split(',')[1],
+              extension: 'png',
+            });
+            ws.addImage(imgId, {
+              tl: { col: 0.1, row: anchorRow },
+              ext: { width: 900, height: 400 },
+            });
+          } else {
+            ws.getCell(`A${Math.ceil(anchorRow)}`).value = '鏆傛棤鏁版嵁';
+          }
+          return ws;
+        };
+
+        addImageSheet(
+          '缁煎悎寰楀垎瓒嬪娍',
+          '鎮h�呮弧鎰忓害缁煎悎寰楀垎瓒嬪娍',
+          this.$refs.chart1,
+          `鐜瘮 ${this.trendMoM}`
+        );
+        addImageSheet(
+          '鍒嗙被缁村害瀵规瘮',
+          `鍒嗙被缁村害 路 鍚勬寚鏍�${this.intervalLabel}瀵规瘮`,
+          this.$refs.chart2,
+          ''
+        );
+        addImageSheet(
+          '闄㈠尯缁村害瀵规瘮',
+          `闄㈠尯缁村害 路 鍚勯櫌鍖�${this.intervalLabel}瀵规瘮`,
+          this.$refs.chart4,
+          ''
+        );
+
+        // 鍗曢 路 閫夐」缁熻
+        const wsQ = wb.addWorksheet('鍗曢閫夐」缁熻');
+        wsQ.addRow(['鍗曢 路 閫夐」缁熻']).font = { size: 14, bold: true };
+        wsQ.mergeCells(1, 1, 1, 3);
+        const qHead = wsQ.addRow(['閫夐」', '鍚堣鏁伴噺', '鍗犳瘮姣斾緥']);
+        qHead.font = { bold: true };
+        (this.singleQuestionData || []).forEach((r) => {
+          wsQ.addRow([r.option, r.count, r.rate]);
+        });
+        wsQ.addRow([]);
+        wsQ.addRow([
+          `鏈鏈夋晥濉啓浜烘锛�${this.singleQuestionMeta.total}銆�缁煎悎寰楀垎锛�${this.singleQuestionMeta.score}`,
+          '',
+          '',
+        ]);
+        wsQ.mergeCells(wsQ.rowCount, 1, wsQ.rowCount, 3);
+        wsQ.columns.forEach((c, i) => {
+          c.width = i === 0 ? 36 : 16;
+        });
+
+        // 鎺掑悕琛ㄦ牸
+        const addRankSheet = (sheetName, title, rows, dimLabel) => {
+          const ws = wb.addWorksheet(sheetName);
+          ws.addRow([title]).font = { size: 14, bold: true };
+          ws.mergeCells(1, 1, 1, 4);
+          const head = ws.addRow(['鎺掑悕', dimLabel, '缁煎悎寰楀垎', '椤规暟']);
+          head.font = { bold: true };
+          (rows || []).forEach((r) => {
+            ws.addRow([r.rank, r.name, r.score, r.itemCount]);
+          });
+          if (!rows || !rows.length) {
+            ws.addRow(['鏆傛棤鏁版嵁', '', '', '']);
+          }
+          ws.columns.forEach((c, i) => {
+            c.width = i === 1 ? 30 : 12;
+          });
+        };
+        addRankSheet(
+          `${this.rankDimLabel}鎺掑悕`,
+          `${this.rankDimLabel}缁村害 路 闂ㄨ瘖鎮h�呮弧鎰忓害寰楀垎鎺掑悕`,
+          this.rankRows,
+          this.rankDimLabel
+        );
+        addRankSheet(
+          `鍗曢脳${this.crossDimLabel}鎺掑悕`,
+          `鍗曢脳${this.crossDimLabel} 路 寰楀垎鎺掑悕`,
+          this.crossRows,
+          this.crossDimLabel
+        );
+
+        const buffer = await wb.xlsx.writeBuffer();
+        const blob = new Blob([buffer], {
+          type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+        });
+        const range = (this.queryParams.dateRange || []).join('_');
+        saveAs(blob, `鍚勯」缁熻琛�${range ? '_' + range : ''}.xlsx`);
+        this.$message.success('瀵煎嚭鎴愬姛');
+      } catch (e) {
+        console.error('瀵煎嚭澶辫触:', e);
+        this.$message.error('瀵煎嚭澶辫触锛�' + (e.message || e));
       }
-
-      const printContent = this.$refs.pdfTarget.cloneNode(true);
-      const chartBoxes = printContent.querySelectorAll('.chart-box');
-      const imgKeys = Object.keys(chartImages);
-      chartBoxes.forEach((box, i) => {
-        if (imgKeys[i] && chartImages[imgKeys[i]]) {
-          box.innerHTML = `<img src="${chartImages[imgKeys[i]]}" style="width:100%;height:auto;" />`;
-        }
-      });
-
-      const win = window.open('', '_blank', 'width=900,height=800');
-      if (!win) { this.$message.warning('璇峰厑璁稿脊鍑虹獥鍙d互瀵煎嚭PDF'); return; }
-      win.document.write(`
-        <html><head><meta charset="utf-8"><title>鍚勯」缁熻琛�</title>
-        <style>
-          body { font-family: 'Microsoft YaHei',sans-serif; padding: 20px; }
-          .chart-card { break-inside: avoid; margin-bottom: 20px; border: 1px solid #ebeef5; border-radius: 6px; }
-          .card-header { padding: 12px 16px; border-bottom: 1px solid #ebeef5; font-size: 15px; font-weight: 600; color: #303133; background: #f5f7fa; }
-          .chart-box img { max-width: 100%; display: block; }
-          table { width: 100%; border-collapse: collapse; margin: 12px 0; }
-          th, td { border: 1px solid #d9d9d9; padding: 8px 12px; text-align: center; font-size: 12px; }
-          th { background: #f0f2f5; font-weight: 600; }
-          .table-footer { text-align: right; padding: 8px 0; font-size: 13px; color: #606266; }
-          .export-bar, .filter-bar, .el-tag, .el-select, .el-radio-group { display: none; }
-          @media print { @page { size: A4; margin: 10mm; } }
-        </style></head><body>
-        ${printContent.innerHTML}
-        <script>window.onload=function(){window.print();}<\/script>
-        </body></html>
-      `);
-      win.document.close();
     },
   },
 };

--
Gitblit v1.9.3