From 77970a545af56e946e439ead97b23557d0b44f0f Mon Sep 17 00:00:00 2001
From: WXL (wul) <wl_5969728@163.com>
Date: 星期三, 12 八月 2026 15:54:08 +0800
Subject: [PATCH] 提交

---
 src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue    |  268 +++++++++++++++++++++++++++++
 vue.config.js                                                     |    4 
 src/views/Satisfaction/sfstatistics/components/DataOverview.vue   |  195 +++++++++++++++++++++
 src/views/sfstatistics/percentage/index.vue                       |   10 
 src/views/Satisfaction/sfstatistics/index.vue                     |   20 +
 src/views/sfstatistics/percentage/components/CombinedFollowUp.vue |    9 
 6 files changed, 490 insertions(+), 16 deletions(-)

diff --git a/src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue b/src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue
new file mode 100644
index 0000000..c8a13c6
--- /dev/null
+++ b/src/views/Satisfaction/sfstatistics/components/ChartsPanel.vue
@@ -0,0 +1,268 @@
+<template>
+  <div class="charts-panel" ref="pdfTarget">
+    <!-- PDF瀵煎嚭鎸夐挳 -->
+    <div class="export-bar">
+      <el-button type="danger" size="small" icon="el-icon-download" @click="exportPDF">瀵煎嚭PDF</el-button>
+    </div>
+
+    <el-row :gutter="20">
+      <!-- 1. 鏃堕棿缁村害 - 鎶樼嚎鍥� -->
+      <el-col :span="12">
+        <el-card shadow="never" class="chart-card">
+          <div slot="header" class="card-header">
+            <span>鏃堕棿缁村害 路 闂ㄨ瘖鎮h�呮弧鎰忓害瓒嬪娍</span>
+            <el-tag type="success" size="small">鐜瘮 +0.97</el-tag>
+          </div>
+          <div ref="chart1" class="chart-box"></div>
+        </el-card>
+      </el-col>
+
+      <!-- 2. 鍒嗙被缁村害 - 鍒嗙粍鏌辩姸鍥� -->
+      <el-col :span="12">
+        <el-card shadow="never" class="chart-card">
+          <div slot="header" class="card-header">
+            <span>鍒嗙被缁村害 路 鍚勬寚鏍囧勾搴﹀姣�</span>
+          </div>
+          <div ref="chart2" class="chart-box"></div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <el-row :gutter="20" style="margin-top: 20px">
+      <!-- 3. 鍗曢閫夐」 - 鏁版嵁琛ㄦ牸 -->
+      <el-col :span="12">
+        <el-card shadow="never" class="chart-card">
+          <div slot="header" class="card-header">
+            <span>鍗曢 路 绗�22棰橈細鎶辨�ㄥ拰涓嶆弧鑳藉惁鍙婃椂寰楀埌鍥炲簲锛�</span>
+          </div>
+          <el-table :data="singleQuestionData" border size="small">
+            <el-table-column prop="option" label="閫夐」" />
+            <el-table-column prop="count" label="鍚堣鏁伴噺" width="120" align="center" />
+            <el-table-column prop="rate" label="鍗犳瘮姣斾緥" width="120" align="center" />
+          </el-table>
+          <div class="table-footer">鏈鏈夋晥濉啓浜烘锛�<b>26,233</b>銆�缁煎悎婊℃剰搴︼細<b>83.20%</b></div>
+        </el-card>
+      </el-col>
+
+      <!-- 4. 闄㈠尯缁村害 - 鍒嗙粍鏌辩姸鍥� -->
+      <el-col :span="12">
+        <el-card shadow="never" class="chart-card">
+          <div slot="header" class="card-header">
+            <span>闄㈠尯缁村害 路 鍚勯櫌鍖哄勾搴﹀姣�</span>
+          </div>
+          <div ref="chart4" class="chart-box"></div>
+        </el-card>
+      </el-col>
+    </el-row>
+
+    <el-row :gutter="20" style="margin-top: 20px">
+      <!-- 5. 绉戝缁村害 - 鎺掑悕琛ㄦ牸 -->
+      <el-col :span="12">
+        <el-card shadow="never" class="chart-card">
+          <div slot="header" class="card-header">
+            <span>绉戝缁村害 路 闂ㄨ瘖鎮h�呮弧鎰忓害寰楀垎鎺掑悕</span>
+          </div>
+          <el-table :data="deptRankData" border size="small">
+            <el-table-column type="index" label="鎺掑悕" width="60" align="center" />
+            <el-table-column prop="dept" label="绉戝" />
+            <el-table-column prop="score" label="缁煎悎寰楀垎" width="120" align="center" />
+          </el-table>
+        </el-card>
+      </el-col>
+
+      <!-- 6. 鍗曢绉戝 - 浜ゅ弶鍒嗘瀽琛ㄦ牸 -->
+      <el-col :span="12">
+        <el-card shadow="never" class="chart-card">
+          <div slot="header" class="card-header">
+            <span>鍗曢脳绉戝 路 绗�22棰樺悇绉戝寰楀垎</span>
+          </div>
+          <el-table :data="crossDeptData" border size="small" max-height="400">
+            <el-table-column type="index" label="鎺掑悕" width="60" align="center" />
+            <el-table-column prop="dept" label="绉戝" />
+            <el-table-column prop="score" label="缁煎悎寰楀垎" width="120" align="center" />
+          </el-table>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import * as echarts from 'echarts';
+
+export default {
+  name: "ChartsPanel",
+  data() {
+    return {
+      singleQuestionData: [
+        { option: "闈炲父婊℃剰", count: 16513, rate: "62.95%" },
+        { option: "婊℃剰", count: 7088, rate: "27.02%" },
+        { option: "涓�鑸�", count: 1760, rate: "6.71%" },
+        { option: "涓嶆弧鎰�", count: 872, rate: "3.32%" },
+      ],
+      deptRankData: [
+        { dept: "淇濆仴绉�", score: "81.54" }, { dept: "浠嬪叆娌荤枟绉�", score: "80.72" },
+        { dept: "涓撶鎶ゅ+闂ㄨ瘖", score: "79.27" }, { dept: "搴峰鍖诲绉�", score: "78.65" },
+        { dept: "鐨偆绉�", score: "78.12" }, { dept: "鍐呭垎娉岀", score: "77.89" },
+        { dept: "娑堝寲鍐呯", score: "77.34" }, { dept: "鑲惧唴绉�", score: "76.50" },
+        { dept: "鍛煎惛鍐呯", score: "75.88" }, { dept: "蹇冭绠″唴绉�", score: "75.21" },
+      ],
+      crossDeptData: [
+        { dept: "淇濆仴绉�", score: "81.24" }, { dept: "浠嬪叆娌荤枟绉�", score: "81.22" },
+        { dept: "涓撶鎶ゅ+闂ㄨ瘖", score: "80.15" }, { dept: "搴峰鍖诲绉�", score: "79.88" },
+        { dept: "鐨偆绉�", score: "79.01" }, { dept: "鍐呭垎娉岀", score: "78.45" },
+        { dept: "娑堝寲鍐呯", score: "77.92" }, { dept: "鑲惧唴绉�", score: "77.13" },
+        { dept: "鍛煎惛鍐呯", score: "76.80" }, { dept: "蹇冭绠″唴绉�", score: "76.05" },
+        { dept: "绁炵粡鍐呯", score: "75.62" }, { dept: "琛�娑茬", score: "75.01" },
+        { dept: "椋庢箍鍏嶇柅绉�", score: "74.38" }, { dept: "鑲跨槫鍐呯", score: "73.85" },
+        { dept: "鎰熸煋绉�", score: "73.12" }, { dept: "鑰佸勾绉�", score: "72.56" },
+        { dept: "鏅绉�", score: "71.90" }, { dept: "楠ㄧ", score: "71.23" },
+        { dept: "娉屽翱澶栫", score: "70.55" }, { dept: "濡囦骇绉�", score: "69.88" },
+      ],
+    };
+  },
+  mounted() { this.$nextTick(() => { this.initCharts(); }); },
+  methods: {
+    initCharts() {
+      const quarters = ['绗竴瀛e害', '绗簩瀛e害', '绗笁瀛e害', '绗洓瀛e害'];
+      const categories = ['闅愮淇濇姢', '鐜涓庢爣璇�', '鍖诲姟浜哄憳鍥炲簲', '鍖荤敓娌熼��', '鎸傚彿浣撻獙', '鎶ゅ+娌熼��'];
+      const hospitals = ['闄㈠尯涓�', '闄㈠尯浜�', '闄㈠尯涓�'];
+      const baseGrid = { top: 20, right: 30, bottom: 30, left: 50 };
+      const baseTooltip = { backgroundColor: 'rgba(255,255,255,0.95)', borderColor: '#e8e8e8', textStyle: { color: '#333', fontSize: 13 }, extraCssText: 'box-shadow: 0 2px 12px rgba(0,0,0,0.1); border-radius: 6px; padding: 10px 14px;' };
+      const baseXAxis = { axisLine: { lineStyle: { color: '#e0e0e0' } }, axisTick: { show: false }, axisLabel: { color: '#666', fontSize: 12 } };
+      const baseYAxis = { splitLine: { lineStyle: { color: '#f0f0f0', type: 'dashed' } }, axisLine: { show: false }, axisTick: { show: false }, axisLabel: { color: '#999', fontSize: 11 } };
+
+      // 1. 鎶樼嚎鍥� - 鏃堕棿缁村害
+      const c1 = echarts.init(this.$refs.chart1);
+      c1.setOption({
+        color: ['#5B8FF9'],
+        grid: { ...baseGrid, top: 25 },
+        tooltip: { ...baseTooltip, trigger: 'axis' },
+        xAxis: [{ ...baseXAxis, data: quarters, boundaryGap: false }],
+        yAxis: [{ ...baseYAxis, min: 86, max: 91, name: '婊℃剰搴﹀緱鍒�', nameTextStyle: { color: '#999', fontSize: 11 } }],
+        series: [{
+          name: '闂ㄨ瘖鎮h�呮弧鎰忓害', type: 'line', smooth: true, symbol: 'circle', symbolSize: 8,
+          data: [88.20, 87.32, 88.50, 89.17],
+          lineStyle: { width: 3, shadowBlur: 8, shadowColor: 'rgba(91,143,249,0.3)' },
+          itemStyle: { color: '#5B8FF9' },
+          areaStyle: { color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+            { offset: 0, color: 'rgba(91,143,249,0.25)' }, { offset: 1, color: 'rgba(91,143,249,0.02)' }
+          ])},
+        }],
+      });
+
+      // 2. 鍒嗙粍鏌辩姸鍥� - 鍒嗙被缁村害
+      const c2 = echarts.init(this.$refs.chart2);
+      c2.setOption({
+        color: ['#6DC8EC', '#5B8FF9'],
+        grid: baseGrid,
+        tooltip: { ...baseTooltip, trigger: 'axis', axisPointer: { type: 'shadow', shadowStyle: { color: 'rgba(0,0,0,0.03)' } } },
+        legend: { data: ['2023骞�', '2024骞�'], bottom: 0, textStyle: { color: '#666', fontSize: 12 } },
+        xAxis: [{ ...baseXAxis, data: categories, axisLabel: { ...baseXAxis.axisLabel, interval: 0 } }],
+        yAxis: [{ ...baseYAxis, name: '寰楀垎', nameTextStyle: { color: '#999', fontSize: 11 } }],
+        series: [
+          { name: '2023骞�', type: 'bar', barWidth: 22, barGap: '30%',
+            itemStyle: { borderRadius: [6, 6, 0, 0], color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#6DC8EC' }, { offset: 1, color: '#48B0D5' }]) },
+            data: [86.34, 85.12, 83.45, 86.22, 88.55, 87.33] },
+          { name: '2024骞�', type: 'bar', barWidth: 22,
+            itemStyle: { borderRadius: [6, 6, 0, 0], color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#5B8FF9' }, { offset: 1, color: '#3D6FDB' }]) },
+            data: [88.06, 84.57, 82.88, 87.77, 88.12, 87.00] },
+        ],
+      });
+
+      // 4. 闄㈠尯缁村害 - 鍒嗙粍鏌辩姸鍥�
+      const c4 = echarts.init(this.$refs.chart4);
+      c4.setOption({
+        color: ['#6DC8EC', '#5B8FF9'],
+        grid: baseGrid,
+        tooltip: { ...baseTooltip, trigger: 'axis', axisPointer: { type: 'shadow' } },
+        legend: { data: ['2023骞�', '2024骞�'], bottom: 0, textStyle: { color: '#666', fontSize: 12 } },
+        xAxis: [{ ...baseXAxis, data: hospitals }],
+        yAxis: [{ ...baseYAxis, name: '婊℃剰搴﹀緱鍒�', nameTextStyle: { color: '#999', fontSize: 11 } }],
+        series: [
+          { name: '2023骞�', type: 'bar', barWidth: 24, barGap: '30%',
+            itemStyle: { borderRadius: [6, 6, 0, 0], color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#6DC8EC' }, { offset: 1, color: '#48B0D5' }]) },
+            data: [86.20, 87.69, 85.55],
+            label: { show: true, position: 'top', color: '#666', fontSize: 12, fontWeight: 500, formatter: p => p.value.toFixed(2) } },
+          { name: '2024骞�', type: 'bar', barWidth: 24,
+            itemStyle: { borderRadius: [6, 6, 0, 0], color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ offset: 0, color: '#5B8FF9' }, { offset: 1, color: '#3D6FDB' }]) },
+            data: [88.15, 88.14, 85.88],
+            label: { show: true, position: 'top', color: '#666', fontSize: 12, fontWeight: 500, formatter: p => p.value.toFixed(2) } },
+        ],
+      });
+
+      // 鍝嶅簲寮�
+      window.addEventListener('resize', () => { c1.resize(); c2.resize(); c4.resize(); });
+    },
+
+    async exportPDF() {
+      // 鍏堝皢 ECharts 瀹炰緥杞负鍥剧墖 dataURL
+      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' });
+          }
+        }
+      }
+
+      // 鍏嬮殕鍐呭骞舵浛鎹㈠浘琛ㄤ负鍥剧墖
+      const printContent = this.$refs.pdfTarget.cloneNode(true);
+      for (const { ref, id } of chartRefs) {
+        if (chartImages[id] && ref) {
+          const boxes = printContent.querySelectorAll('.chart-box');
+          for (const box of boxes) {
+            if (box.innerHTML.includes(id) || boxes.length === chartRefs.length) {
+              box.innerHTML = `<img src="${chartImages[id]}" style="width:100%;height:auto;" />`;
+            }
+          }
+        }
+      }
+      // 鏇村彲闈犵殑鏂瑰紡锛氭寜浣嶇疆鍖归厤
+      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, .el-tag { 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();
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.export-bar { text-align: right; margin-bottom: 16px; }
+.chart-card { margin-bottom: 0; }
+.chart-box { width: 100%; height: 360px; }
+.card-header { display: flex; justify-content: space-between; align-items: center; span { font-size: 15px; font-weight: 600; color: #303133; } }
+.table-footer { text-align: right; padding: 10px 0 0; font-size: 13px; color: #606266; }
+</style>
diff --git a/src/views/Satisfaction/sfstatistics/components/DataOverview.vue b/src/views/Satisfaction/sfstatistics/components/DataOverview.vue
new file mode 100644
index 0000000..18b5142
--- /dev/null
+++ b/src/views/Satisfaction/sfstatistics/components/DataOverview.vue
@@ -0,0 +1,195 @@
+<template>
+  <div class="data-overview">
+    <!-- 琛ㄦ牸涓�锛氬悇鏈嶅姟椤圭洰婊℃剰搴︾粺璁� -->
+    <el-card shadow="never" class="overview-card">
+      <div slot="header" class="card-header">
+        <span class="card-title">鍚勬湇鍔¢」鐩弧鎰忓害缁熻</span>
+        <el-button type="warning" size="small" icon="el-icon-download" @click="exportTable('table1')">瀵煎嚭Excel</el-button>
+      </div>
+      <el-table id="table1" :data="serviceSatisfaction" border size="small" :header-cell-style="{ background: '#f5f7fa', color: '#303133' }">
+        <el-table-column prop="category" label="鍒嗙被/棰樼洰" min-width="220" fixed="left" />
+        <el-table-column label="闈炲父婊℃剰" align="center">
+          <el-table-column prop="veryGoodCount" label="鏁伴噺" width="90" />
+          <el-table-column prop="veryGoodRate" label="姣斾緥" width="90" />
+        </el-table-column>
+        <el-table-column label="婊℃剰" align="center">
+          <el-table-column prop="goodCount" label="鏁伴噺" width="90" />
+          <el-table-column prop="goodRate" label="姣斾緥" width="90" />
+        </el-table-column>
+        <el-table-column label="涓�鑸�" align="center">
+          <el-table-column prop="normalCount" label="鏁伴噺" width="90" />
+          <el-table-column prop="normalRate" label="姣斾緥" width="90" />
+        </el-table-column>
+        <el-table-column label="涓嶆弧鎰�" align="center">
+          <el-table-column prop="badCount" label="鏁伴噺" width="90" />
+          <el-table-column prop="badRate" label="姣斾緥" width="90" />
+        </el-table-column>
+        <el-table-column label="涓嶉�傜敤" align="center">
+          <el-table-column prop="naCount" label="鏁伴噺" width="90" />
+          <el-table-column prop="naRate" label="姣斾緥" width="90" />
+        </el-table-column>
+        <el-table-column prop="score" label="缁煎悎寰楀垎" width="100" align="center" />
+      </el-table>
+    </el-card>
+
+    <!-- 琛ㄦ牸浜岋細鍗曢�夐/澶氶�夐缁熻 -->
+    <el-card shadow="never" class="overview-card">
+      <div slot="header" class="card-header">
+        <span class="card-title">鍗曢�夐/澶氶�夐缁熻</span>
+        <el-button type="warning" size="small" icon="el-icon-download" @click="exportTable('table2')">瀵煎嚭Excel</el-button>
+      </div>
+      <div class="question-block" v-for="(q, qi) in questionStats" :key="qi">
+        <h4 class="q-title">{{ q.title }}</h4>
+        <el-table :data="q.options" border size="small" :header-cell-style="{ background: '#f5f7fa', color: '#303133' }">
+          <el-table-column prop="option" label="閫夐」" min-width="180" />
+          <el-table-column prop="count" label="鏁伴噺" width="100" align="center" />
+          <el-table-column prop="rate" label="姣斾緥" width="100" align="center" />
+        </el-table>
+        <div v-if="q.total" class="q-footer">鏈鏈夋晥濉啓浜烘锛�<b>{{ q.total }}</b></div>
+      </div>
+    </el-card>
+
+    <!-- 琛ㄦ牸涓夛細鍚勭瀹ゆ弧鎰忓害璇勫垎瀵规瘮 -->
+    <el-card shadow="never" class="overview-card">
+      <div slot="header" class="card-header">
+        <span class="card-title">鍚勭瀹ゆ弧鎰忓害璇勫垎瀵规瘮</span>
+        <el-button type="warning" size="small" icon="el-icon-download" @click="exportTable('table3')">瀵煎嚭Excel</el-button>
+      </div>
+      <el-table id="table3" :data="deptComparison" border size="small" :header-cell-style="{ background: '#f5f7fa', color: '#303133' }">
+        <el-table-column prop="dept" label="绉戝"fixed="left" align="center" />
+        <el-table-column label="绗�1棰�" align="center">
+          <el-table-column prop="q1VeryGood" label="闈炲父婊℃剰" width="100" />
+          <el-table-column prop="q1Good" label="婊℃剰" width="90" />
+          <el-table-column prop="q1Normal" label="涓�鑸�" width="90" />
+          <el-table-column prop="q1Bad" label="涓嶆弧鎰�" width="90" />
+          <el-table-column prop="q1Score" label="寰楀垎" width="100" />
+        </el-table-column>
+        <el-table-column label="绗�2棰�" align="center">
+          <el-table-column prop="q2VeryGood" label="闈炲父婊℃剰" width="100" />
+          <el-table-column prop="q2Good" label="婊℃剰" width="90" />
+          <el-table-column prop="q2Normal" label="涓�鑸�" width="90" />
+          <el-table-column prop="q2Bad" label="涓嶆弧鎰�" width="90" />
+          <el-table-column prop="q2Score" label="寰楀垎" width="100" />
+        </el-table-column>
+        <el-table-column prop="totalScore" label="缁煎悎寰楀垎"  align="center" />
+      </el-table>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import XLSX from 'xlsx';
+
+export default {
+  name: "DataOverview",
+  data() {
+    return {
+      serviceSatisfaction: [
+        { category: "璇婄枟杩囩▼涓紝鍖诲姟浜哄憳鏄惁娉ㄦ剰淇濇姢鎮ㄧ殑闅愮锛�", veryGoodCount: 3219, veryGoodRate: "67.84%", goodCount: 1351, goodRate: "28.47%", normalCount: 142, normalRate: "2.99%", badCount: 33, badRate: "0.70%", naCount: 0, naRate: "0.00%", score: "87.82" },
+        { category: "鎮ㄥ鍖婚櫌鏈嶅姟璁炬柦鐨勬�讳綋鍗拌薄濡備綍锛�", veryGoodCount: 3110, veryGoodRate: "65.54%", goodCount: 1369, goodRate: "28.85%", normalCount: 217, normalRate: "4.57%", badCount: 49, badRate: "1.03%", naCount: 0, naRate: "0.00%", score: "86.30" },
+        { category: "鍖婚櫌鐨勫帟鎵�鏄惁娓呮磥鏃犲紓鍛筹紵", veryGoodCount: 2973, veryGoodRate: "62.66%", goodCount: 1504, goodRate: "31.70%", normalCount: 235, normalRate: "4.95%", badCount: 33, badRate: "0.70%", naCount: 0, naRate: "0.00%", score: "85.44" },
+        { category: "鍖婚櫌鍐呯殑璺爣鍜屾寚绀烘槸鍚︽槑纭紵", veryGoodCount: 3234, veryGoodRate: "68.16%", goodCount: 1289, goodRate: "27.17%", normalCount: 196, normalRate: "4.13%", badCount: 26, badRate: "0.55%", naCount: 0, naRate: "0.00%", score: "87.64" },
+        { category: "鍖婚櫌鐨勭┖闂村竷灞�鏄惁渚垮埄锛�", veryGoodCount: 3037, veryGoodRate: "64.00%", goodCount: 1460, goodRate: "30.77%", normalCount: 209, normalRate: "4.40%", badCount: 39, badRate: "0.82%", naCount: 0, naRate: "0.00%", score: "85.99" },
+        { category: "鐪嬬梾鏈熼棿锛屾偍鐨勬姳鎬ㄥ拰涓嶆弧鑳藉惁鍙婃椂寰楀埌鍥炲簲锛�", veryGoodCount: 3019, veryGoodRate: "63.62%", goodCount: 1317, goodRate: "27.76%", normalCount: 294, normalRate: "6.20%", badCount: 115, badRate: "2.42%", naCount: 0, naRate: "0.00%", score: "84.19" },
+        { category: "鍖荤敓鏄惁鐢ㄦ偍鍚緱鎳傜殑鏂瑰紡瑙i噴闂锛�", veryGoodCount: 3402, veryGoodRate: "71.70%", goodCount: 967, goodRate: "20.38%", normalCount: 254, normalRate: "5.35%", badCount: 122, badRate: "2.57%", naCount: 0, naRate: "0.00%", score: "87.07" },
+        { category: "鍖荤敓瀵规偍鏄惁灏婇噸锛�", veryGoodCount: 3495, veryGoodRate: "73.66%", goodCount: 897, goodRate: "18.90%", normalCount: 249, normalRate: "5.25%", badCount: 104, badRate: "2.19%", naCount: 0, naRate: "0.00%", score: "88.01" },
+        { category: "鍖荤敓鏄惁浠旂粏鍊惧惉鎮ㄨ璇濓紵", veryGoodCount: 3422, veryGoodRate: "72.12%", goodCount: 937, goodRate: "19.75%", normalCount: 251, normalRate: "5.29%", badCount: 135, badRate: "2.85%", naCount: 0, naRate: "0.00%", score: "87.05" },
+        { category: "瀵规寕鍙锋湇鍔′汉鍛樻湇鍔℃�佸害鏄惁婊℃剰", veryGoodCount: 3458, veryGoodRate: "72.88%", goodCount: 1205, goodRate: "25.40%", normalCount: 52, normalRate: "1.10%", badCount: 30, badRate: "0.63%", naCount: 0, naRate: "0.00%", score: "90.17" },
+        { category: "鎮ㄥ棰勭害鎸傚彿鏄惁婊℃剰锛�", veryGoodCount: 3527, veryGoodRate: "74.33%", goodCount: 1088, goodRate: "22.93%", normalCount: 72, normalRate: "1.52%", badCount: 58, badRate: "1.22%", naCount: 0, naRate: "0.00%", score: "90.12" },
+        { category: "鎶ゅ+瀵规偍鏄惁灏婇噸锛�", veryGoodCount: 3420, veryGoodRate: "72.08%", goodCount: 1184, goodRate: "24.95%", normalCount: 113, normalRate: "2.38%", badCount: 28, badRate: "0.59%", naCount: 0, naRate: "0.00%", score: "89.50" },
+        { category: "鎶ゅ+鏄惁鐢ㄦ偍鍚緱鎳傜殑鏂瑰紡瑙i噴闂锛�", veryGoodCount: 3346, veryGoodRate: "70.52%", goodCount: 1250, goodRate: "26.34%", normalCount: 122, normalRate: "2.57%", badCount: 27, badRate: "0.57%", naCount: 0, naRate: "0.00%", score: "88.94" },
+        { category: "鎶ゅ+鏄惁浠旂粏鍊惧惉鎮ㄨ璇濓紵", veryGoodCount: 3378, veryGoodRate: "71.19%", goodCount: 1205, goodRate: "25.40%", normalCount: 134, normalRate: "2.82%", badCount: 28, badRate: "0.59%", naCount: 0, naRate: "0.00%", score: "89.06" },
+        { category: "鎬昏", veryGoodCount: 54863, veryGoodRate: "69.02%", goodCount: 20800, goodRate: "26.17%", normalCount: 2920, normalRate: "3.67%", badCount: 908, badRate: "1.14%", naCount: 0, naRate: "0.00%", score: "87.66" },
+      ],
+      questionStats: [
+        {
+          title: "绗�1棰橈細鎮ㄥ鎴戦櫌宸ヤ綔浜哄憳鐨勬湇鍔¤川閲忔弧鎰忎笉婊℃剰锛熴�愬垎鍊煎崟閫夐銆�- 缁煎悎寰楀垎",
+          options: [
+            { option: "闈炲父婊℃剰", count: 1084, rate: "75.66%" },
+            { option: "婊℃剰", count: 1959, rate: "20.92%" },
+            { option: "涓�鑸�", count: 167, rate: "1.78%" },
+            { option: "涓嶆弧鎰�", count: 153, rate: "1.63%" },
+          ],
+          total: 3363
+        },
+        {
+          title: "绗�2棰橈細鎮ㄥ鍝儴鍒嗘湇鍔′笉婊℃剰锛熴�愬閫夐銆�",
+          options: [
+            { option: "鍖荤敓璇婃柇鍜岃瘖鐤�", count: 131, rate: "32.11%" },
+            { option: "鎶ょ悊鏈嶅姟", count: 47, rate: "11.52%" },
+            { option: "鍏朵粬鍖诲姟浜哄憳鎶�鏈按骞�", count: 30, rate: "7.33%" },
+            { option: "宸ヤ汉", count: 72, rate: "17.65%" },
+          ],
+          total: 408
+        },
+        {
+          title: "绗�3棰橈細鍖荤敓璇婃柇鍜屾不鐤椾腑鍝簺鏈嶅姟璐ㄩ噺涓嶆弧鎰忥紵銆愬閫夐銆�",
+          options: [
+            { option: "鍖荤敓璇婃柇閿欒", count: 23, rate: "15.44%" },
+            { option: "瀵规不鐤楁晥鏋滀笉婊℃剰", count: 72, rate: "48.32%" },
+            { option: "鍏朵粬", count: 54, rate: "36.24%" },
+          ],
+          total: 131
+        },
+      ],
+      deptComparison: [
+        { dept: "鍐呭垎娉岀", q1VeryGood: 103, q1Good: 34, q1Normal: 0, q1Bad: 0, q1Score: "377.00", q2VeryGood: 101, q2Good: 35, q2Normal: 1, q2Bad: 0, q2Score: "374.00", totalScore: "75.25" },
+        { dept: "鐨偆绉�", q1VeryGood: 112, q1Good: 25, q1Normal: 2, q1Bad: 3, q1Score: "388.00", q2VeryGood: 111, q2Good: 27, q2Normal: 3, q2Bad: 1, q2Score: "390.00", totalScore: "76.12" },
+        { dept: "鑲跨槫鍐呯", q1VeryGood: 24, q1Good: 12, q1Normal: 2, q1Bad: 0, q1Score: "98.00", q2VeryGood: 25, q2Good: 12, q2Normal: 1, q2Bad: 0, q2Score: "100.00", totalScore: "70.22" },
+        { dept: "娑堝寲鍐呯", q1VeryGood: 180, q1Good: 52, q1Normal: 1, q1Bad: 0, q1Score: "645.00", q2VeryGood: 168, q2Good: 62, q2Normal: 3, q2Bad: 0, q2Score: "631.00", totalScore: "73.56" },
+        { dept: "鑲惧唴绉�", q1VeryGood: 21, q1Good: 4, q1Normal: 0, q1Bad: 0, q1Score: "71.00", q2VeryGood: 19, q2Good: 6, q2Normal: 0, q2Bad: 0, q2Score: "65.00", totalScore: "68.50" },
+      ],
+    };
+  },
+  methods: {
+    exportTable(tableId) {
+      const tableNames = { table1: '鍚勬湇鍔¢」鐩弧鎰忓害缁熻', table2: '鍗曢�夐澶氶�夐缁熻', table3: '鍚勭瀹ゆ弧鎰忓害璇勫垎瀵规瘮' };
+      const name = tableNames[tableId] || '缁熻鏁版嵁';
+      const table = document.getElementById(tableId);
+      if (!table) return;
+
+      try {
+        // 浠庤〃鏍兼彁鍙栨暟鎹瀯寤哄甫鏍峰紡鐨� Excel
+        const wb = XLSX.utils.book_new();
+        const data = [];
+        table.querySelectorAll('tr').forEach(tr => {
+          const row = [];
+          tr.querySelectorAll('th,td').forEach(td => {
+            row.push((td.innerText || '').trim());
+          });
+          if (row.length) data.push(row);
+        });
+
+        const ws = XLSX.utils.aoa_to_sheet(data);
+        // 璁剧疆鍒楀
+        const colWidths = data[0] ? data[0].map(() => ({ wch: 16 })) : [];
+        ws['!cols'] = colWidths;
+
+        XLSX.utils.book_append_sheet(wb, ws, 'Sheet1');
+        XLSX.writeFile(wb, name + '.xlsx');
+      } catch (e) {
+        // fallback: CSV
+        let csv = '锘�';
+        table.querySelectorAll('tr').forEach(tr => {
+          const row = [];
+          tr.querySelectorAll('th,td').forEach(td => row.push('"' + (td.innerText || '').replace(/"/g, '""') + '"'));
+          csv += row.join(',') + '\n';
+        });
+        const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
+        const link = document.createElement('a');
+        link.href = URL.createObjectURL(blob); link.download = name + '.csv'; link.click();
+      }
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.data-overview { .overview-card { margin-bottom: 20px; } }
+.card-header { display: flex; justify-content: space-between; align-items: center; }
+.card-title { font-size: 16px; font-weight: 600; color: #303133; }
+.question-block { margin-bottom: 24px;
+  .q-title { margin: 0 0 12px 0; font-size: 14px; color: #606266; }
+  .q-footer { margin-top: 8px; font-size: 13px; color: #909399; text-align: right; }
+}
+</style>
diff --git a/src/views/Satisfaction/sfstatistics/index.vue b/src/views/Satisfaction/sfstatistics/index.vue
index 40a875d..a6a22f1 100644
--- a/src/views/Satisfaction/sfstatistics/index.vue
+++ b/src/views/Satisfaction/sfstatistics/index.vue
@@ -3,16 +3,16 @@
   <div class="statistics-main">
     <el-tabs v-model="activeTab" @tab-click="handleTabChange">
       <el-tab-pane label="婊℃剰搴﹂殢璁跨粺璁�" name="followup">
-        <followup-statistics
-          v-if="activeTab === 'followup'"
-          ref="followupRef"
-        />
+        <followup-statistics v-if="activeTab === 'followup'" ref="followupRef" />
       </el-tab-pane>
       <el-tab-pane label="婊℃剰搴︽槑缁嗙粺璁�" name="satisfaction">
-        <satisfaction-statistics
-          v-if="activeTab === 'satisfaction'"
-          ref="satisfactionRef"
-        />
+        <satisfaction-statistics v-if="activeTab === 'satisfaction'" ref="satisfactionRef" />
+      </el-tab-pane>
+      <el-tab-pane label="缁熻鏁版嵁鎬昏" name="dataOverview">
+        <data-overview v-if="activeTab === 'dataOverview'" />
+      </el-tab-pane>
+      <el-tab-pane label="鍚勯」缁熻琛�" name="chartsPanel">
+        <charts-panel v-if="activeTab === 'chartsPanel'" />
       </el-tab-pane>
     </el-tabs>
   </div>
@@ -21,12 +21,16 @@
 <script>
 import FollowupStatistics from "./components/FollowupStatistics.vue";
 import SatisfactionStatistics from "./components/SatisfactionStatistics.vue";
+import DataOverview from "./components/DataOverview.vue";
+import ChartsPanel from "./components/ChartsPanel.vue";
 
 export default {
   name: "Satisfaction",
   components: {
     FollowupStatistics,
     SatisfactionStatistics,
+    DataOverview,
+    ChartsPanel,
   },
   data() {
     return {
diff --git a/src/views/sfstatistics/percentage/components/CombinedFollowUp.vue b/src/views/sfstatistics/percentage/components/CombinedFollowUp.vue
index d5f8cb8..fc3823c 100644
--- a/src/views/sfstatistics/percentage/components/CombinedFollowUp.vue
+++ b/src/views/sfstatistics/percentage/components/CombinedFollowUp.vue
@@ -173,10 +173,7 @@
             </el-button>
           </template>
         </el-table-column>
-
-        <!-- ===== 棣栨闅忚 ===== -->
-        <el-table-column align="center" label="棣栨闅忚">
-          <el-table-column label="鏃犻渶闅忚" align="center" prop="nonFollowUp">
+             <el-table-column label="鏃犻渶闅忚" align="center" prop="nonFollowUp">
             <template slot-scope="scope">
               <el-button type="text" @click="handleViewDetails(scope.row, 'nonFollowUpInfo', '棣栨鏃犻渶闅忚鍒楄〃')">
                 <span class="button-zx">{{ scope.row.nonFollowUp }}</span>
@@ -190,6 +187,10 @@
               </el-button>
             </template>
           </el-table-column>
+
+        <!-- ===== 棣栨闅忚 ===== -->
+        <el-table-column align="center" label="棣栨闅忚">
+
           <el-table-column label="闇�闅忚" align="center" prop="needFollowUp">
             <template slot-scope="scope">
               <el-button type="text" @click="handleViewDetails(scope.row, 'needFollowUpInfo', '棣栨闇�闅忚鍒楄〃')">
diff --git a/src/views/sfstatistics/percentage/index.vue b/src/views/sfstatistics/percentage/index.vue
index b6cb27c..9a068e7 100644
--- a/src/views/sfstatistics/percentage/index.vue
+++ b/src/views/sfstatistics/percentage/index.vue
@@ -475,8 +475,14 @@
         obj.deptcodes = [row.deptcode];
         obj.leavehospitaldistrictcodes = [];
       }
-      obj.endTime = this.queryParams.endTime;
-      obj.startTime = this.queryParams.startTime;
+      if (this.queryParams.endTime) {
+        obj.endTime = this.queryParams.endTime;
+        obj.startTime = this.queryParams.startTime;
+      } else {
+        obj.startTime = this.parseTime(this.queryParams.dateRange[0]);
+        obj.endTime = this.parseTime(this.queryParams.dateRange[1]);
+      }
+
       obj.statisticaltype = this.queryParams.statisticaltype;
 
       getSfStatisticsHyperlink(obj).then((response) => {
diff --git a/vue.config.js b/vue.config.js
index 7f985b0..fd08b34 100644
--- a/vue.config.js
+++ b/vue.config.js
@@ -36,8 +36,8 @@
       // detail: https://cli.vuejs.org/config/#devserver-proxy
       [process.env.VUE_APP_BASE_API]: {
         // target: `https://www.health-y.cn/lssf`,
-        // target: `http://192.168.100.10:8096`,
-        target: `http://192.168.100.10:8094`,//鐪佺珛鍚屽痉
+        target: `http://192.168.100.10:8096`,
+        // target: `http://192.168.100.10:8094`,//鐪佺珛鍚屽痉
         // target: `http://192.168.100.10:8095`,//鏂板崕
         // target: `http://192.168.100.10:8098`,//甯備竴
         // target:`http://localhost:8095`,

--
Gitblit v1.9.3