From feb5a669dced68415bc7e32f237f77bf9842fe8b Mon Sep 17 00:00:00 2001
From: WXL (wul) <wl_5969728@163.com>
Date: 星期三, 03 六月 2026 17:42:18 +0800
Subject: [PATCH] 测试完成

---
 src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue |  953 +++++++++++++++++++++++++++++++++++++++++++++++++----------
 1 files changed, 791 insertions(+), 162 deletions(-)

diff --git a/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue b/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue
index c1d3a0a..3ff1958 100644
--- a/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue
+++ b/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue
@@ -24,13 +24,16 @@
             </el-select>
           </el-form-item>
 
-          <el-form-item label="绉戝" prop="deptCode">
+          <!-- 绉戝閫夋嫨 -->
+          <el-form-item label="绉戝" prop="deptCodes">
             <el-select
-              v-model="queryParams.deptCode"
+              v-model="queryParams.deptCodes"
               placeholder="璇烽�夋嫨绉戝"
               clearable
               filterable
-              style="width: 200px"
+              multiple
+              collapse-tags
+              style="width: 300px"
               @change="handleDeptChange"
             >
               <el-option
@@ -42,13 +45,16 @@
             </el-select>
           </el-form-item>
 
-          <el-form-item label="鐥呭尯" prop="wardCode">
+          <!-- 鐥呭尯閫夋嫨 -->
+          <el-form-item label="鐥呭尯" prop="wardCodes">
             <el-select
-              v-model="queryParams.wardCode"
+              v-model="queryParams.wardCodes"
               placeholder="璇烽�夋嫨鐥呭尯"
               clearable
               filterable
-              style="width: 200px"
+              multiple
+              collapse-tags
+              style="width: 300px"
               @change="handleWardChange"
             >
               <el-option
@@ -95,7 +101,7 @@
       <el-card shadow="never">
         <div class="chart-container">
           <div class="chart-header">
-            <h3 class="chart-title">婊℃剰搴︾被鍨嬪~鎶ユ瘮渚嬬粺璁�</h3>
+            <h3 class="chart-title">{{ getChartTitle() }}</h3>
             <div class="statistic-info">
               <div class="statistic-item">
                 <span class="statistic-label">鍙戦�侀棶鍗锋�婚噺锛�</span>
@@ -117,6 +123,20 @@
               </div>
             </div>
           </div>
+
+          <!-- 鏍囩椤靛垏鎹� -->
+          <el-tabs
+            v-model="activeChartTab"
+            @tab-click="handleChartTabClick"
+            class="chart-tabs"
+          >
+            <el-tab-pane
+              label="婊℃剰搴︾被鍨�"
+              name="satisfactionType"
+            ></el-tab-pane>
+            <el-tab-pane label="缁村害缁熻" name="dimension"></el-tab-pane>
+          </el-tabs>
+
           <div
             id="satisfactionBarChart"
             style="width: 100%; height: 400px"
@@ -304,6 +324,179 @@
             </div>
           </el-tab-pane>
 
+          <el-tab-pane label="缁村害棰樼洰鏄庣粏" name="dimensionDetail">
+            <!-- 缁村害棰樼洰鏄庣粏琛ㄦ牸 -->
+            <div class="dimension-detail-section">
+              <el-table
+                v-loading="dimensionDetailLoading"
+                :data="dimensionDetailData"
+                :border="true"
+                style="width: 100%"
+                row-class-name="dimension-row"
+              >
+                <el-table-column type="expand" width="60">
+                  <template slot-scope="{ row }">
+                    <div class="option-detail">
+                      <el-table
+                        :data="row.options"
+                        :border="true"
+                        style="width: 100%"
+                        class="inner-table"
+                      >
+                        <el-table-column
+                          label="閫夐」"
+                          prop="optionText"
+                          align="center"
+                          min-width="200"
+                        />
+                        <el-table-column
+                          label="閫夋嫨浜烘暟"
+                          prop="chosenQuantity"
+                          align="center"
+                          min-width="120"
+                        />
+                        <el-table-column
+                          label="閫夋嫨姣斾緥"
+                          prop="chosenPercentage"
+                          align="center"
+                          min-width="120"
+                        >
+                          <template slot-scope="{ row: option }">
+                            {{ formatPercent(option.chosenPercentage) }}
+                          </template>
+                        </el-table-column>
+                      </el-table>
+                    </div>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="搴忓彿"
+                  type="index"
+                  align="center"
+                  width="60"
+                />
+
+                <el-table-column
+                  label="棰樼洰"
+                  prop="scriptContent"
+                  align="center"
+                  min-width="300"
+                >
+                  <template slot-scope="{ row }">
+                    <span>{{ row.scriptContent }}</span>
+                    <el-tag
+                      :type="row.scriptType === 1 ? 'primary' : 'success'"
+                      size="mini"
+                      style="margin-left: 5px"
+                    >
+                      {{ row.scriptType === 1 ? "鍗曢�夐" : "澶氶�夐" }}
+                    </el-tag>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="缁村害"
+                  prop="dimensionName"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <el-tag type="info" size="small">
+                      {{ getDimensionLabel(row.dimension) }}
+                    </el-tag>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="骞冲潎寰楀垎"
+                  prop="averageScore"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <span class="score-text">{{
+                      row.averageScore.toFixed(1)
+                    }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="鏈�楂樺緱鍒�"
+                  prop="maxScore"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <span class="score-text">{{
+                      row.maxScore.toFixed(1)
+                    }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="鏈�浣庡緱鍒�"
+                  prop="minScore"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <span class="score-text">{{
+                      row.minScore.toFixed(1)
+                    }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="绛旈浜烘暟"
+                  prop="answerPerson"
+                  align="center"
+                  width="100"
+                />
+
+                <el-table-column
+                  label="鏈瓟棰樹汉鏁�"
+                  prop="noAnswerPerson"
+                  align="center"
+                  width="100"
+                />
+
+                <el-table-column
+                  label="绛旈鐜�"
+                  prop="answerRate"
+                  align="center"
+                  width="100"
+                >
+                  <template slot-scope="{ row }">
+                    {{ formatPercent(row.answerRate) }}
+                  </template>
+                </el-table-column>
+              </el-table>
+
+              <!-- 缁村害缁熻姹囨�� -->
+              <div class="dimension-summary-row">
+                <div class="dimension-summary-content">
+                  <div class="dimension-summary-item">
+                    <span class="label">棰樼洰鎬绘暟锛�</span>
+                    <span class="value">{{ dimensionDetailData.length }}</span>
+                  </div>
+                  <div class="dimension-summary-item">
+                    <span class="label">缁村害骞冲潎鍒嗭細</span>
+                    <span class="value">{{
+                      dimensionAverageScore.toFixed(1)
+                    }}</span>
+                  </div>
+                  <div class="dimension-summary-item">
+                    <span class="label">鎬讳綋绛旈鐜囷細</span>
+                    <span class="value">{{
+                      formatPercent(dimensionTotalAnswerRate)
+                    }}</span>
+                  </div>
+                </div>
+              </div>
+            </div>
+          </el-tab-pane>
+
           <el-tab-pane label="鍚勭被鍨嬬粺璁℃槑缁�" name="typeDetail">
             <!-- 鍚勭被鍨嬬粺璁℃槑缁嗚〃鏍� -->
             <div class="type-detail-section">
@@ -415,40 +608,6 @@
                 </el-table-column>
 
                 <el-table-column
-                  label="瓒嬪娍"
-                  prop="trend"
-                  align="center"
-                  width="120"
-                >
-                  <template slot-scope="{ row }">
-                    <div class="trend-cell">
-                      <i
-                        v-if="row.trend === 'up'"
-                        class="el-icon-top trend-up"
-                        :style="{ color: '#67C23A' }"
-                      />
-                      <i
-                        v-else-if="row.trend === 'down'"
-                        class="el-icon-bottom trend-down"
-                        :style="{ color: '#F56C6C' }"
-                      />
-                      <i
-                        v-else
-                        class="el-icon-minus trend-stable"
-                        :style="{ color: '#909399' }"
-                      />
-                      <span class="trend-text">{{
-                        row.trend === "up"
-                          ? "涓婂崌"
-                          : row.trend === "down"
-                          ? "涓嬮檷"
-                          : "绋冲畾"
-                      }}</span>
-                    </div>
-                  </template>
-                </el-table-column>
-
-                <el-table-column
                   label="鎿嶄綔"
                   align="center"
                   width="120"
@@ -508,25 +667,31 @@
 
 <script>
 import * as echarts from "echarts";
-import { statistics, satisfactionGraph } from "@/api/system/user";
+import {
+  statistics,
+  satisfactionGraph,
+  statisticsByDimension,
+  satisfactionGraphDimension,
+} from "@/api/system/user";
 import store from "@/store";
 
 export default {
   name: "SatisfactionStatistics",
+  dicts: ["dimensionality_type"],
   data() {
     return {
       // 鏌ヨ鍙傛暟
       queryParams: {
         type: 2,
         patientSource: "",
-        deptCode: "",
-        wardCode: "",
+        deptCodes: [], // 鏀逛负鏁扮粍锛屾敮鎸佸閫�
+        wardCodes: [], // 鏀逛负鏁扮粍锛屾敮鎸佸閫�
         dateRange: [],
       },
-
       // 褰撳墠婵�娲荤殑tab
       activeTab: "questionDetail",
-
+      // 褰撳墠婵�娲荤殑鍥捐〃tab
+      activeChartTab: "satisfactionType",
       // 鎮h�呮潵婧愰�夐」
       patientSourceList: [
         { value: "1", label: "闂ㄨ瘖" },
@@ -548,9 +713,13 @@
       loading: false,
       detailLoading: false,
       typeDetailLoading: false,
+      dimensionDetailLoading: false,
 
       // 棰樼洰鏄庣粏鏁版嵁
       questionDetailData: [],
+
+      // 缁村害棰樼洰鏄庣粏鏁版嵁
+      dimensionDetailData: [],
 
       // 棰樼洰鏄庣粏鏌ヨ鍙傛暟
       detailQueryParams: {
@@ -561,10 +730,24 @@
       // 棰樼洰鏄庣粏鎬绘暟
       detailTotal: 0,
 
+      // 缁村害鏄庣粏鏌ヨ鍙傛暟
+      dimensionQueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+      },
+
+      // 缁村害鏄庣粏鎬绘暟
+      dimensionTotal: 0,
+
       // 缁煎悎寰楀垎
       totalScore: 0,
       totalAnswerCount: 0,
       totalAnswerRate: 0,
+
+      // 缁村害缁熻姹囨��
+      dimensionTotalAnswerCount: 0,
+      dimensionTotalAnswerRate: 0,
+      dimensionAverageScore: 0,
 
       // 鍚勭被鍨嬬粺璁℃槑缁嗘暟鎹�
       typeDetailData: [],
@@ -660,16 +843,16 @@
 
     // 璁$畻绉戝缂栫爜鏁扮粍
     deptCodes() {
-      if (this.queryParams.deptCode) {
-        return [this.queryParams.deptCode];
+      if (this.queryParams.deptCodes && this.queryParams.deptCodes.length > 0) {
+        return this.queryParams.deptCodes;
       }
       return this.deptList.map((dept) => dept.value);
     },
 
     // 璁$畻鐥呭尯缂栫爜鏁扮粍
     hospitalDistrictCodes() {
-      if (this.queryParams.wardCode) {
-        return [this.queryParams.wardCode];
+      if (this.queryParams.wardCodes && this.queryParams.wardCodes.length > 0) {
+        return this.queryParams.wardCodes;
       }
       return this.wardList.map((ward) => ward.value);
     },
@@ -729,6 +912,13 @@
       });
     },
 
+    // 鑾峰彇鍥捐〃鏍囬
+    getChartTitle() {
+      return this.activeChartTab === "satisfactionType"
+        ? "婊℃剰搴︾被鍨嬪~鎶ユ瘮渚嬬粺璁�"
+        : "缁村害濉姤姣斾緥缁熻";
+    },
+
     // 鍔犺浇鏁版嵁
     async loadData() {
       await Promise.all([
@@ -742,23 +932,10 @@
     async loadChartData() {
       this.loading = true;
       try {
-        const params = {
-          type: this.queryParams.type,
-          startTime: this.startTime,
-          endTime: this.endTime,
-          deptcodes: this.deptCodes,
-          hospitaldistrictcodes: this.hospitalDistrictCodes,
-          templateid: this.templateId,
-        };
-
-        const response = await satisfactionGraph(params);
-
-        if (response.code === 200) {
-          this.processChartData(response);
+        if (this.activeChartTab === "satisfactionType") {
+          await this.loadSatisfactionTypeChartData();
         } else {
-          this.$message.error(response.msg || "鑾峰彇鍥捐〃鏁版嵁澶辫触");
-          // 浣跨敤mock鏁版嵁
-          await this.generateMockChartData();
+          await this.loadDimensionChartData();
         }
       } catch (error) {
         console.error("鑾峰彇鍥捐〃鏁版嵁鍑洪敊:", error);
@@ -770,14 +947,54 @@
       }
     },
 
-    // 澶勭悊鍥捐〃鏁版嵁
-    processChartData(apiData) {
+    // 鍔犺浇婊℃剰搴︾被鍨嬪浘琛ㄦ暟鎹�
+    async loadSatisfactionTypeChartData() {
+      const params = {
+        type: this.queryParams.type,
+        startTime: this.startTime,
+        endTime: this.endTime,
+        deptcodes: this.deptCodes, // 浣跨敤璁$畻灞炴��
+        hospitaldistrictcodes: this.hospitalDistrictCodes, // 浣跨敤璁$畻灞炴��
+        templateid: this.templateId,
+      };
+
+      const response = await satisfactionGraph(params);
+      if (response.code === 200) {
+        this.processSatisfactionTypeChartData(response);
+      } else {
+        this.$message.error(response.msg || "鑾峰彇鍥捐〃鏁版嵁澶辫触");
+        await this.generateMockChartData();
+      }
+    },
+
+    // 鍔犺浇缁村害鍥捐〃鏁版嵁
+    async loadDimensionChartData() {
+      const params = {
+        type: this.queryParams.type,
+        startTime: this.startTime,
+        endTime: this.endTime,
+        deptcodes: this.deptCodes, // 浣跨敤璁$畻灞炴��
+        hospitaldistrictcodes: this.hospitalDistrictCodes, // 浣跨敤璁$畻灞炴��
+        templateid: this.templateId,
+      };
+
+      const response = await satisfactionGraphDimension(params);
+      if (response.code === 200) {
+        this.processDimensionChartData(response);
+      } else {
+        this.$message.error(response.msg || "鑾峰彇缁村害鍥捐〃鏁版嵁澶辫触");
+        await this.generateMockDimensionChartData();
+      }
+    },
+
+    // 澶勭悊婊℃剰搴︾被鍨嬪浘琛ㄦ暟鎹�
+    processSatisfactionTypeChartData(apiData) {
       if (!apiData || !apiData.rows || Object.keys(apiData.rows).length === 0) {
         this.chartData = [];
         this.totalSendCount = 0;
         this.totalReceiveCount = 0;
         this.overallRecoveryRate = 0;
-        this.renderChart([]);
+        this.renderChart([], "satisfactionType");
         return;
       }
 
@@ -790,11 +1007,11 @@
       Object.entries(apiData.rows).forEach(([typeName, typeStat]) => {
         const sendCount = typeStat.subidAll || 0;
         const receiveCount = typeStat.fillCountAll || 0;
-        const recoveryRate = typeStat.receiveRate || 0;
+        const recoveryRate = typeStat.receiveRate.toFixed(2) || 0;
 
         chartData.push({
           name: typeName,
-          value: recoveryRate * 100, // 杞崲涓虹櫨鍒嗘瘮
+          value: (recoveryRate * 100).toFixed(2), // 杞崲涓虹櫨鍒嗘瘮
           sendCount: sendCount,
           receiveCount: receiveCount,
           averageScore: typeStat.averageScore || 0,
@@ -811,7 +1028,64 @@
       this.overallRecoveryRate = totalSend > 0 ? totalReceive / totalSend : 0;
       this.chartData = chartData;
 
-      this.renderChart(chartData);
+      this.renderChart(chartData, "satisfactionType");
+    },
+
+    // 澶勭悊缁村害鍥捐〃鏁版嵁
+    processDimensionChartData(apiData) {
+      if (!apiData || !apiData.rows || Object.keys(apiData.rows).length === 0) {
+        this.chartData = [];
+        this.totalSendCount = 0;
+        this.totalReceiveCount = 0;
+        this.overallRecoveryRate = 0;
+        this.renderChart([], "dimension");
+        return;
+      }
+
+      const chartData = [];
+      let totalSend = 0;
+      let totalReceive = 0;
+      let index = 0;
+
+      // 澶勭悊鎺ュ彛杩斿洖鐨勭淮搴︾粺璁�
+      Object.entries(apiData.rows).forEach(([dimensionCode, dimensionStat]) => {
+        const sendCount = dimensionStat.subidAll || 0;
+        const receiveCount = dimensionStat.fillCountAll || 0;
+        const recoveryRate = dimensionStat.receiveRate || 0;
+
+        // 鑾峰彇缁村害鏍囩
+        const dimensionName = this.getDimensionLabel(dimensionCode);
+
+        chartData.push({
+          name: dimensionName,
+          value: (recoveryRate * 100).toFixed(2), // 杞崲涓虹櫨鍒嗘瘮
+          sendCount: sendCount,
+          receiveCount: receiveCount,
+          averageScore: dimensionStat.averageScore || 0,
+          dimension: dimensionCode,
+          itemStyle: { color: this.getChartColor(index) },
+        });
+
+        totalSend += sendCount;
+        totalReceive += receiveCount;
+        index++;
+      });
+
+      this.totalSendCount = totalSend;
+      this.totalReceiveCount = totalReceive;
+      this.overallRecoveryRate = totalSend > 0 ? totalReceive / totalSend : 0;
+      this.chartData = chartData;
+
+      this.renderChart(chartData, "dimension");
+    },
+
+    // 鑾峰彇缁村害鏍囩
+    getDimensionLabel(dimensionCode) {
+      if (!this.dict.type.dimensionality_type) return dimensionCode;
+      const dimension = this.dict.type.dimensionality_type.find(
+        (item) => item.value.toString() === dimensionCode.toString()
+      );
+      return dimension ? dimension.label : dimensionCode;
     },
 
     // 鍔犺浇棰樼洰鏄庣粏鏁版嵁
@@ -823,6 +1097,8 @@
           startTime: this.startTime,
           endTime: this.endTime,
           scriptids: this.scriptIds,
+          deptcodes: this.deptCodes, // 浣跨敤璁$畻灞炴��
+          hospitaldistrictcodes: this.hospitalDistrictCodes, // 浣跨敤璁$畻灞炴��
           templateid: this.templateId,
         };
 
@@ -898,6 +1174,85 @@
       this.totalAnswerRate = apiData.totalAnswerRate || 0;
     },
 
+    // 鍔犺浇缁村害鏄庣粏鏁版嵁
+    async loadDimensionDetailData() {
+      this.dimensionDetailLoading = true;
+      try {
+        const params = {
+          type: this.queryParams.type,
+          startTime: this.startTime,
+          endTime: this.endTime,
+          deptcodes: this.deptCodes, // 浣跨敤璁$畻灞炴��
+          hospitaldistrictcodes: this.hospitalDistrictCodes, // 浣跨敤璁$畻灞炴��
+          templateid: this.templateId,
+          questionType: this.queryParams.type || null,
+          serviceTypes: this.defaultServiceTypes,
+        };
+
+        const response = await statisticsByDimension(params);
+
+        if (response.code === 200) {
+          this.processDimensionDetailData(response.rows);
+        } else {
+          this.$message.error(response.msg || "鑾峰彇缁村害鏄庣粏鏁版嵁澶辫触");
+          const mockData = await this.generateMockDimensionDetail();
+          this.dimensionDetailData = mockData;
+          this.calculateDimensionSummary(mockData);
+        }
+      } catch (error) {
+        console.error("鑾峰彇缁村害鏄庣粏鏁版嵁鍑洪敊:", error);
+        this.$message.error("鑾峰彇缁村害鏄庣粏鏁版嵁澶辫触");
+        const mockData = await this.generateMockDimensionDetail();
+        this.dimensionDetailData = mockData;
+        this.calculateDimensionSummary(mockData);
+      } finally {
+        this.dimensionDetailLoading = false;
+      }
+    },
+
+    // 澶勭悊缁村害鏄庣粏鏁版嵁
+    processDimensionDetailData(apiData) {
+      if (!apiData || !apiData.patSatisfactionDetailEntities) {
+        this.dimensionDetailData = [];
+        this.calculateDimensionSummary([]);
+        return;
+      }
+
+      const detailData = apiData.patSatisfactionDetailEntities.map((item) => {
+        const options = [];
+        if (item.matchedtextStats) {
+          Object.keys(item.matchedtextStats).forEach((key) => {
+            const stat = item.matchedtextStats[key];
+            options.push({
+              optionText: key,
+              chosenQuantity: stat.count || 0,
+              chosenPercentage: (stat.ratio || 0) / 100,
+            });
+          });
+        }
+
+        return {
+          scriptContent: item.scriptContent || "",
+          dimension: item.dimension || "0", // 缁村害浠g爜
+          dimensionName: this.getDimensionLabel(item.dimension || "0"), // 缁村害鍚嶇О
+          scriptType: 1,
+          answerPerson: item.answerPerson || 0,
+          noAnswerPerson: item.noAnswerPerson || 0,
+          answerCount: item.answerPerson || 0,
+          averageScore: item.averageScore || 0,
+          maxScore: item.maxScore || 0,
+          minScore: item.minScore || 0,
+          answerRate: item.answerRate || 0,
+          totalCount: (item.answerPerson || 0) + (item.noAnswerPerson || 0),
+          options: options,
+        };
+      });
+
+      this.dimensionDetailData = detailData;
+      this.dimensionTotal = detailData.length;
+      this.calculateDimensionSummary(detailData);
+    },
+
     // 鍔犺浇绫诲瀷鏄庣粏鏁版嵁
     async loadTypeDetailData() {
       this.typeDetailLoading = true;
@@ -906,15 +1261,15 @@
           type: this.queryParams.type,
           startTime: this.startTime,
           endTime: this.endTime,
-          deptcodes: this.deptCodes,
-          hospitaldistrictcodes: this.hospitalDistrictCodes,
+          deptcodes: this.deptCodes, // 浣跨敤璁$畻灞炴��
+          hospitaldistrictcodes: this.hospitalDistrictCodes, // 浣跨敤璁$畻灞炴��
           templateid: this.templateId,
         };
 
         const response = await satisfactionGraph(params);
 
         if (response.code === 200) {
-          this.processTypeDetailData(response.data);
+          this.processTypeDetailData(response);
         } else {
           this.$message.error(response.msg || "鑾峰彇绫诲瀷鏄庣粏鏁版嵁澶辫触");
           const mockData = await this.generateMockTypeDetail();
@@ -944,7 +1299,7 @@
       Object.entries(apiData.rows).forEach(([typeName, typeStat], index) => {
         const sendCount = typeStat.subidAll || 0;
         const receiveCount = typeStat.fillCountAll || 0;
-        const recoveryRate = typeStat.receiveRate || 0;
+        const recoveryRate = typeStat.receiveRate.toFixed(2) || 0;
         const averageScore = typeStat.averageScore || 0;
 
         typeDetail.push({
@@ -972,14 +1327,7 @@
       if (score >= 4.0) return "鑹ソ";
       if (score >= 3.0) return "涓�鑸�";
       if (score >= 2.0) return "杈冨樊";
-      return "宸�";
-    },
-
-    // 鑾峰彇瓒嬪娍
-    getTrend(trend) {
-      if (trend > 0.1) return "up";
-      if (trend < -0.1) return "down";
-      return "stable";
+      return "鏈煡";
     },
 
     // 璁$畻缁煎悎寰楀垎
@@ -998,6 +1346,32 @@
         data.list.length > 0 ? totalScore / data.list.length : 0;
       this.totalAnswerCount = totalAnswerCount;
       this.totalAnswerRate = totalCount > 0 ? totalAnswerCount / totalCount : 0;
+    },
+
+    // 璁$畻缁村害缁熻姹囨��
+    calculateDimensionSummary(data) {
+      if (data.length === 0) {
+        this.dimensionTotalAnswerCount = 0;
+        this.dimensionTotalAnswerRate = 0;
+        this.dimensionAverageScore = 0;
+        return;
+      }
+
+      let totalScore = 0;
+      let totalAnswerCount = 0;
+      let totalCount = 0;
+
+      data.forEach((item) => {
+        totalScore += item.averageScore;
+        totalAnswerCount += item.answerPerson;
+        totalCount += item.answerPerson + item.noAnswerPerson;
+      });
+
+      this.dimensionAverageScore =
+        data.length > 0 ? totalScore / data.length : 0;
+      this.dimensionTotalAnswerCount = totalAnswerCount;
+      this.dimensionTotalAnswerRate =
+        totalCount > 0 ? totalAnswerCount / totalCount : 0;
     },
 
     // 璁$畻绫诲瀷缁熻姹囨��
@@ -1039,26 +1413,34 @@
     },
 
     // 娓叉煋鍥捐〃
-    renderChart(chartData) {
+    renderChart(chartData, chartType = "satisfactionType") {
       if (!this.barChart) return;
- if (!chartData || chartData.length === 0) {
-    const emptyOption = {
-      title: {
-        text: "鏆傛棤鏁版嵁",
-        left: "center",
-        top: "center",
-        textStyle: {
-          color: "#999",
-          fontSize: 16,
-          fontWeight: "normal"
-        }
-      },
-      xAxis: { show: false },
-      yAxis: { show: false }
-    };
-    this.barChart.setOption(emptyOption);
-    return;
-  }
+      if (!chartData || chartData.length === 0) {
+        const emptyOption = {
+          title: {
+            text: "鏆傛棤鏁版嵁",
+            left: "center",
+            top: "center",
+            textStyle: {
+              color: "#999",
+              fontSize: 16,
+              fontWeight: "normal",
+            },
+          },
+          xAxis: { show: false },
+          yAxis: { show: false },
+        };
+        this.barChart.setOption(emptyOption);
+        return;
+      }
+
+      const yAxisName =
+        chartType === "satisfactionType" ? "濉姤姣斾緥 (%)" : "濉姤姣斾緥 (%)";
+      const tooltipFormatter =
+        chartType === "satisfactionType"
+          ? this.getSatisfactionTypeTooltipFormatter
+          : this.getDimensionTooltipFormatter;
+
       const option = {
         title: {
           text: "",
@@ -1069,28 +1451,7 @@
           axisPointer: {
             type: "shadow",
           },
-          formatter: (params) => {
-            const data = params[0];
-            return `
-              <div style="margin-bottom: 5px; font-weight: bold; color: #333;">
-                ${data.name}
-              </div>
-              <div style="margin: 2px 0;">
-                <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:${
-                  data.color
-                };margin-right:5px;"></span>
-                濉姤姣斾緥: <strong>${data.value.toFixed(1)}%</strong>
-              </div>
-              <div style="margin: 2px 0;">
-                <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#eee;margin-right:5px;"></span>
-                鍙戦�侀棶鍗�: <strong>${data.data.sendCount.toLocaleString()}</strong>
-              </div>
-              <div style="margin: 2px 0;">
-                <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#eee;margin-right:5px;"></span>
-                鍥炴敹闂嵎: <strong>${data.data.receiveCount.toLocaleString()}</strong>
-              </div>
-            `;
-          },
+          formatter: tooltipFormatter,
         },
         grid: {
           left: "3%",
@@ -1119,7 +1480,7 @@
         },
         yAxis: {
           type: "value",
-          name: "濉姤姣斾緥 (%)",
+          name: yAxisName,
           min: 0,
           max: 100,
           axisLabel: {
@@ -1163,6 +1524,66 @@
       this.barChart.setOption(option);
     },
 
+    // 婊℃剰搴︾被鍨媡ooltip鏍煎紡鍖�
+    getSatisfactionTypeTooltipFormatter(params) {
+      const data = params[0];
+      return `
+        <div style="margin-bottom: 5px; font-weight: bold; color: #333;">
+          ${data.name}
+        </div>
+        <div style="margin: 2px 0;">
+          <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:${
+            data.color
+          };margin-right:5px;"></span>
+          濉姤姣斾緥: <strong>${data.value}%</strong>
+        </div>
+        <div style="margin: 2px 0;">
+          <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#eee;margin-right:5px;"></span>
+          鍙戦�侀棶鍗�: <strong>${data.data.sendCount.toLocaleString()}</strong>
+        </div>
+        <div style="margin: 2px 0;">
+          <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#eee;margin-right:5px;"></span>
+          鍥炴敹闂嵎: <strong>${data.data.receiveCount.toLocaleString()}</strong>
+        </div>
+        <div style="margin: 2px 0;">
+          <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#eee;margin-right:5px;"></span>
+          骞冲潎鍒�: <strong>${data.data.averageScore.toFixed(1)}</strong>
+        </div>
+      `;
+    },
+
+    // 缁村害tooltip鏍煎紡鍖�
+    getDimensionTooltipFormatter(params) {
+      const data = params[0];
+      return `
+        <div style="margin-bottom: 5px; font-weight: bold; color: #333;">
+          ${data.name}
+        </div>
+        <div style="margin: 2px 0;">
+          <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:${
+            data.color
+          };margin-right:5px;"></span>
+          濉姤姣斾緥: <strong>${data.value}%</strong>
+        </div>
+        <div style="margin: 2px 0;">
+          <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#eee;margin-right:5px;"></span>
+          鍙戦�侀棶鍗�: <strong>${data.data.sendCount.toLocaleString()}</strong>
+        </div>
+        <div style="margin: 2px 0;">
+          <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#eee;margin-right:5px;"></span>
+          鍥炴敹闂嵎: <strong>${data.data.receiveCount.toLocaleString()}</strong>
+        </div>
+        <div style="margin: 2px 0;">
+          <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#eee;margin-right:5px;"></span>
+          骞冲潎鍒�: <strong>${data.data.averageScore.toFixed(1)}</strong>
+        </div>
+        <div style="margin: 2px 0;">
+          <span style="display:inline-block;width:10px;height:10px;border-radius:2px;background:#eee;margin-right:5px;"></span>
+          缁村害浠g爜: <strong>${data.data.dimension}</strong>
+        </div>
+      `;
+    },
+
     // 鐢熸垚Mock鍥捐〃鏁版嵁
     generateMockChartData() {
       return new Promise((resolve) => {
@@ -1197,11 +1618,69 @@
             value: item.recoveryRate * 100,
             sendCount: item.sendCount,
             receiveCount: item.receiveCount,
+            averageScore: 4.2 + Math.random() * 0.8,
             itemStyle: { color: item.color },
           }));
 
           this.chartData = chartData;
-          this.renderChart(chartData);
+          this.renderChart(chartData, "satisfactionType");
+          resolve();
+        }, 300);
+      });
+    },
+
+    // 鐢熸垚Mock缁村害鍥捐〃鏁版嵁
+    generateMockDimensionChartData() {
+      return new Promise((resolve) => {
+        setTimeout(() => {
+          // 妯℃嫙缁村害鏁版嵁
+          const dimensionLabels = this.dict.type.dimensionality_type || [
+            { value: "1", label: "缁村害1" },
+            { value: "2", label: "缁村害2" },
+            { value: "3", label: "缁村害3" },
+            { value: "4", label: "缁村害4" },
+            { value: "5", label: "缁村害5" },
+          ];
+
+          const data = dimensionLabels.map((dim, index) => ({
+            name: dim.label,
+            recoveryRate: Math.random() * 0.3 + 0.6,
+            sendCount: Math.floor(Math.random() * 2000) + 1000,
+            receiveCount: 0,
+            averageScore: 3.5 + Math.random() * 1.5,
+            dimension: dim.value,
+            color: this.getChartColor(index),
+          }));
+
+          data.forEach((item) => {
+            item.receiveCount = Math.floor(item.sendCount * item.recoveryRate);
+          });
+
+          this.totalSendCount = data.reduce(
+            (sum, item) => sum + item.sendCount,
+            0
+          );
+          this.totalReceiveCount = data.reduce(
+            (sum, item) => sum + item.receiveCount,
+            0
+          );
+          this.overallRecoveryRate =
+            this.totalSendCount > 0
+              ? this.totalReceiveCount / this.totalSendCount
+              : 0;
+
+          const chartData = data.map((item) => ({
+            name: item.name,
+            value: item.recoveryRate * 100,
+            sendCount: item.sendCount,
+            receiveCount: item.receiveCount,
+            averageScore: item.averageScore,
+            dimension: item.dimension,
+            itemStyle: { color: item.color },
+          }));
+
+          this.chartData = chartData;
+          this.renderChart(chartData, "dimension");
           resolve();
         }, 300);
       });
@@ -1301,6 +1780,111 @@
       });
     },
 
+    // 鐢熸垚Mock缁村害璇︽儏鏁版嵁
+    generateMockDimensionDetail() {
+      return new Promise((resolve) => {
+        setTimeout(() => {
+          const questions = [
+            {
+              scriptContent: "鍖绘姢浜哄憳鏈嶅姟鎬佸害",
+              dimension: "1",
+              dimensionName: "鏈嶅姟鎬佸害",
+              scriptType: 1,
+              answerPerson: 120,
+              noAnswerPerson: 30,
+              answerCount: 120,
+              totalCount: 150,
+              averageScore: 4.2,
+              maxScore: 5.0,
+              minScore: 1.0,
+              answerRate: 0.8,
+              options: [
+                {
+                  optionText: "闈炲父婊℃剰",
+                  chosenQuantity: 60,
+                  chosenPercentage: 0.5,
+                },
+                {
+                  optionText: "婊℃剰",
+                  chosenQuantity: 36,
+                  chosenPercentage: 0.3,
+                },
+                {
+                  optionText: "涓�鑸�",
+                  chosenQuantity: 18,
+                  chosenPercentage: 0.15,
+                },
+              ],
+            },
+            {
+              scriptContent: "鍖荤枟鎶�鏈按骞�",
+              dimension: "2",
+              dimensionName: "鎶�鏈按骞�",
+              scriptType: 1,
+              answerPerson: 145,
+              noAnswerPerson: 11,
+              answerCount: 145,
+              totalCount: 156,
+              averageScore: 4.5,
+              maxScore: 5,
+              minScore: 3,
+              answerRate: 0.93,
+              options: [
+                {
+                  optionText: "闈炲父婊℃剰",
+                  chosenQuantity: 89,
+                  chosenPercentage: 0.61,
+                },
+                {
+                  optionText: "婊℃剰",
+                  chosenQuantity: 45,
+                  chosenPercentage: 0.31,
+                },
+                {
+                  optionText: "涓�鑸�",
+                  chosenQuantity: 8,
+                  chosenPercentage: 0.06,
+                },
+              ],
+            },
+            {
+              scriptContent: "灏卞尰鐜璁炬柦",
+              dimension: "3",
+              dimensionName: "鐜璁炬柦",
+              scriptType: 1,
+              answerPerson: 98,
+              noAnswerPerson: 22,
+              answerCount: 98,
+              totalCount: 120,
+              averageScore: 4.0,
+              maxScore: 5,
+              minScore: 2,
+              answerRate: 0.82,
+              options: [
+                {
+                  optionText: "闈炲父婊℃剰",
+                  chosenQuantity: 45,
+                  chosenPercentage: 0.46,
+                },
+                {
+                  optionText: "婊℃剰",
+                  chosenQuantity: 40,
+                  chosenPercentage: 0.41,
+                },
+                {
+                  optionText: "涓�鑸�",
+                  chosenQuantity: 10,
+                  chosenPercentage: 0.1,
+                },
+              ],
+            },
+          ];
+
+          resolve(questions);
+        }, 300);
+      });
+    },
+
     // 鐢熸垚Mock绫诲瀷鏄庣粏鏁版嵁
     generateMockTypeDetail() {
       return new Promise((resolve) => {
@@ -1374,6 +1958,12 @@
         "#FF9D4D",
         "#9B8DFF",
         "#FF6B6B",
+        "#66C2A5",
+        "#FC8D62",
+        "#8DA0CB",
+        "#E78AC3",
+        "#A6D854",
+        "#FFD92F",
       ];
       return colors[index % colors.length];
     },
@@ -1385,14 +1975,21 @@
       }
     },
 
+    // 澶勭悊鍥捐〃Tab鍒囨崲
+    handleChartTabClick(tab) {
+      this.activeChartTab = tab.name;
+      this.loadChartData();
+    },
+
     // 澶勭悊鏌ヨ
     handleSearch() {
       this.detailQueryParams.pageNum = 1;
+      this.dimensionQueryParams.pageNum = 1;
       this.loadData();
       // 寮哄埗閲嶆柊娓叉煋鍥捐〃
       setTimeout(() => {
         if (this.chartData.length === 0) {
-          this.renderChart([]);
+          this.renderChart([], this.activeChartTab);
         }
       }, 100);
     },
@@ -1401,14 +1998,30 @@
     handleReset() {
       this.$refs.queryForm.resetFields();
       this.queryParams.dateRange = [];
+        this.queryParams.deptCodes = [];  // 閲嶇疆涓烘暟缁�
+  this.queryParams.wardCodes = [];  // 閲嶇疆涓烘暟缁�
       this.detailQueryParams.pageNum = 1;
+      this.dimensionQueryParams.pageNum = 1;
       this.loadData();
     },
 
     // 澶勭悊Tab鍒囨崲
     handleTabClick(tab) {
-      if (tab.name === "typeDetail" && this.typeDetailData.length === 0) {
+      if (
+        tab.name === "dimensionDetail" &&
+        this.dimensionDetailData.length === 0
+      ) {
+        this.loadDimensionDetailData();
+      } else if (
+        tab.name === "typeDetail" &&
+        this.typeDetailData.length === 0
+      ) {
         this.loadTypeDetailData();
+      } else if (
+        tab.name === "questionDetail" &&
+        this.questionDetailData.length === 0
+      ) {
+        this.loadQuestionDetailData();
       }
     },
 
@@ -1425,6 +2038,19 @@
       this.loadQuestionDetailData();
     },
 
+    // 澶勭悊缁村害鏄庣粏鍒嗛〉澶у皬鍙樺寲
+    handleDimensionSizeChange(size) {
+      this.dimensionQueryParams.pageSize = size;
+      this.dimensionQueryParams.pageNum = 1;
+      this.loadDimensionDetailData();
+    },
+
+    // 澶勭悊缁村害鏄庣粏椤电爜鍙樺寲
+    handleDimensionPageChange(page) {
+      this.dimensionQueryParams.pageNum = page;
+      this.loadDimensionDetailData();
+    },
+
     // 澶勭悊绫诲瀷璇︽儏
     handleTypeDetail(row) {
       this.$message.info(`鏌ョ湅绫诲瀷璇︽儏锛�${row.typeName}`);
@@ -1437,12 +2063,12 @@
 
     // 鏍煎紡鍖栫櫨鍒嗘瘮
     formatPercent(value) {
-   if (value === null || value === undefined) return "-";
-  const num = parseFloat(value);
-  if (isNaN(num)) return "-";
-  // 濡傛灉鍊煎皬浜�1锛岃涓烘槸灏忔暟姣斾緥锛岄渶瑕佷箻浠�100
-  const percentValue = num < 1 ? num * 100 : num;
-  return `${percentValue.toFixed(2)}%`;
+      if (value === null || value === undefined) return "-";
+      const num = parseFloat(value);
+      if (isNaN(num)) return "-";
+      // 濡傛灉鍊煎皬浜�1锛岃涓烘槸灏忔暟姣斾緥锛岄渶瑕佷箻浠�100
+      const percentValue = num < 1 ? num * 100 : num;
+      return `${percentValue.toFixed(2)}%`;
     },
 
     // 鑾峰彇鍥炴敹鐜囨牱寮忕被
@@ -1459,7 +2085,7 @@
         鑹ソ: "primary",
         涓�鑸�: "warning",
         杈冨樊: "danger",
-        宸�: "info",
+        鏈煡: "info",
       };
       return levelMap[level] || "info";
     },
@@ -1545,6 +2171,14 @@
         }
       }
     }
+
+    .chart-tabs {
+      margin-bottom: 20px;
+
+      ::v-deep .el-tabs__header {
+        margin-bottom: 0;
+      }
+    }
   }
 
   .tab-section {
@@ -1557,7 +2191,8 @@
     }
   }
 
-  .detail-table-section {
+  .detail-table-section,
+  .dimension-detail-section {
     .option-detail {
       padding: 15px;
       background: #f8f9fa;
@@ -1577,7 +2212,8 @@
         padding: 12px 0;
       }
 
-      .question-row {
+      .question-row,
+      .dimension-row {
         td {
           background-color: #fff;
         }
@@ -1596,19 +2232,22 @@
       font-size: 16px;
     }
 
-    .summary-row {
+    .summary-row,
+    .dimension-summary-row {
       margin-top: 20px;
       padding: 20px;
       background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
       border-radius: 8px;
       border: 1px solid #dee2e6;
 
-      .summary-content {
+      .summary-content,
+      .dimension-summary-content {
         display: flex;
         justify-content: space-around;
         align-items: center;
 
-        .summary-item {
+        .summary-item,
+        .dimension-summary-item {
           text-align: center;
 
           .label {
@@ -1680,24 +2319,6 @@
         color: #409eff;
         font-size: 15px;
       }
-
-      .trend-cell {
-        display: flex;
-        align-items: center;
-        justify-content: center;
-        gap: 5px;
-
-        .trend-up,
-        .trend-down,
-        .trend-stable {
-          font-size: 16px;
-        }
-
-        .trend-text {
-          font-size: 13px;
-          color: #666;
-        }
-      }
     }
 
     .type-summary-row {
@@ -1759,7 +2380,13 @@
     }
   }
 }
-
+/* 纭繚澶氶�変笅鎷夋鏍峰紡姝g‘ */
+::v-deep .el-select__tags {
+  max-width: 200px;
+  .el-tag {
+    margin: 2px 0 2px 6px;
+  }
+}
 @media (max-width: 768px) {
   .satisfaction-statistics {
     padding: 10px;
@@ -1791,8 +2418,10 @@
       }
     }
 
-    .detail-table-section {
-      .summary-content {
+    .detail-table-section,
+    .dimension-detail-section {
+      .summary-content,
+      .dimension-summary-content {
         flex-direction: column;
         gap: 15px;
       }

--
Gitblit v1.9.3