From dac4393e8af2646f544f6e1ca24dab11b40c8492 Mon Sep 17 00:00:00 2001
From: WXL (wul) <wl_5969728@163.com>
Date: 星期二, 07 四月 2026 15:16:40 +0800
Subject: [PATCH] 测试完成

---
 src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue | 1809 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 1,809 insertions(+), 0 deletions(-)

diff --git a/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue b/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue
new file mode 100644
index 0000000..c1d3a0a
--- /dev/null
+++ b/src/views/Satisfaction/sfstatistics/components/SatisfactionStatistics.vue
@@ -0,0 +1,1809 @@
+<template>
+  <div class="satisfaction-statistics">
+    <!-- 鏌ヨ鏉′欢鍖哄煙 -->
+    <div class="query-section">
+      <el-card shadow="never">
+        <el-form
+          :model="queryParams"
+          ref="queryForm"
+          size="medium"
+          :inline="true"
+          label-width="100px"
+          class="query-form"
+        >
+          <el-form-item label="缁熻绫诲瀷" prop="patientSource">
+            <el-select
+              v-model="queryParams.type"
+              placeholder="璇烽�夋嫨缁熻绫诲瀷"
+              clearable
+              style="width: 100%"
+            >
+              <el-option label="闂嵎绫诲瀷" :value="2" />
+              <el-option label="璇煶绫诲瀷" :value="1" />
+              <el-option label="鍏ㄩ儴" :value="null" />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="绉戝" prop="deptCode">
+            <el-select
+              v-model="queryParams.deptCode"
+              placeholder="璇烽�夋嫨绉戝"
+              clearable
+              filterable
+              style="width: 200px"
+              @change="handleDeptChange"
+            >
+              <el-option
+                v-for="dept in deptList"
+                :key="dept.value"
+                :label="dept.label"
+                :value="dept.value"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="鐥呭尯" prop="wardCode">
+            <el-select
+              v-model="queryParams.wardCode"
+              placeholder="璇烽�夋嫨鐥呭尯"
+              clearable
+              filterable
+              style="width: 200px"
+              @change="handleWardChange"
+            >
+              <el-option
+                v-for="ward in wardList"
+                :key="ward.value"
+                :label="ward.label"
+                :value="ward.value"
+              />
+            </el-select>
+          </el-form-item>
+
+          <el-form-item label="缁熻鏃堕棿" prop="dateRange">
+            <el-date-picker
+              v-model="queryParams.dateRange"
+              type="daterange"
+              range-separator="鑷�"
+              start-placeholder="寮�濮嬫棩鏈�"
+              end-placeholder="缁撴潫鏃ユ湡"
+              value-format="yyyy-MM-dd"
+              :picker-options="pickerOptions"
+              style="width: 380px"
+            />
+          </el-form-item>
+
+          <el-form-item>
+            <el-button
+              type="primary"
+              icon="el-icon-search"
+              @click="handleSearch"
+              :loading="loading"
+            >
+              鏌ヨ
+            </el-button>
+            <el-button icon="el-icon-refresh" @click="handleReset">
+              閲嶇疆
+            </el-button>
+          </el-form-item>
+        </el-form>
+      </el-card>
+    </div>
+
+    <!-- 婊℃剰搴︾被鍨嬬粺璁″浘琛� -->
+    <div class="chart-section">
+      <el-card shadow="never">
+        <div class="chart-container">
+          <div class="chart-header">
+            <h3 class="chart-title">婊℃剰搴︾被鍨嬪~鎶ユ瘮渚嬬粺璁�</h3>
+            <div class="statistic-info">
+              <div class="statistic-item">
+                <span class="statistic-label">鍙戦�侀棶鍗锋�婚噺锛�</span>
+                <span class="statistic-value">{{
+                  totalSendCount.toLocaleString()
+                }}</span>
+              </div>
+              <div class="statistic-item">
+                <span class="statistic-label">鍥炴敹闂嵎鎬婚噺锛�</span>
+                <span class="statistic-value">{{
+                  totalReceiveCount.toLocaleString()
+                }}</span>
+              </div>
+              <div class="statistic-item">
+                <span class="statistic-label">鎬讳綋鍥炴敹鐜囷細</span>
+                <span class="statistic-value">{{
+                  formatPercent(overallRecoveryRate)
+                }}</span>
+              </div>
+            </div>
+          </div>
+          <div
+            id="satisfactionBarChart"
+            style="width: 100%; height: 400px"
+          ></div>
+        </div>
+      </el-card>
+    </div>
+
+    <!-- Tab鏍囩椤� -->
+    <div class="tab-section">
+      <el-card shadow="never">
+        <el-tabs v-model="activeTab" @tab-click="handleTabClick">
+          <el-tab-pane label="棰樼洰鏄庣粏缁熻" name="questionDetail">
+            <!-- 棰樼洰鏄庣粏琛ㄦ牸 -->
+            <div class="detail-table-section">
+              <el-table
+                v-loading="detailLoading"
+                :data="questionDetailData"
+                :border="true"
+                style="width: 100%"
+                row-class-name="question-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="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="answerCount"
+                  align="center"
+                  width="100"
+                />
+
+                <el-table-column
+                  label="鏈瓟棰樹汉鏁�"
+                  prop="unanswerCount"
+                  align="center"
+                  width="100"
+                >
+                  <template slot-scope="{ row }">
+                    {{ row.noAnswerPerson }}
+                  </template>
+                </el-table-column>
+
+                <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="summary-row">
+                <div class="summary-content">
+                  <div class="summary-item">
+                    <span class="label">鎬荤瓟棰樹汉鏁帮細</span>
+                    <span class="value">{{ totalAnswerCount }}</span>
+                  </div>
+                  <div class="summary-item">
+                    <span class="label">鎬荤瓟棰樼巼锛�</span>
+                    <span class="value">{{
+                      formatPercent(totalAnswerRate)
+                    }}</span>
+                  </div>
+                </div>
+              </div>
+
+              <!-- 鍒嗛〉 -->
+              <div
+                class="pagination-section"
+                v-if="questionDetailData.length > 0"
+              >
+                <el-pagination
+                  background
+                  layout="total, sizes, prev, pager, next, jumper"
+                  :current-page="detailQueryParams.pageNum"
+                  :page-size="detailQueryParams.pageSize"
+                  :page-sizes="[10, 20, 30]"
+                  :total="detailTotal"
+                  @size-change="handleDetailSizeChange"
+                  @current-change="handleDetailPageChange"
+                />
+              </div>
+            </div>
+          </el-tab-pane>
+
+          <el-tab-pane label="鍚勭被鍨嬬粺璁℃槑缁�" name="typeDetail">
+            <!-- 鍚勭被鍨嬬粺璁℃槑缁嗚〃鏍� -->
+            <div class="type-detail-section">
+              <el-table
+                v-loading="typeDetailLoading"
+                :data="typeDetailData"
+                :border="true"
+                style="width: 100%"
+                class="type-detail-table"
+              >
+                <el-table-column
+                  label="搴忓彿"
+                  type="index"
+                  align="center"
+                  width="60"
+                />
+
+                <el-table-column
+                  label="婊℃剰搴︾被鍨�"
+                  prop="typeName"
+                  align="center"
+                  min-width="150"
+                >
+                  <template slot-scope="{ row }">
+                    <div class="type-name-cell">
+                      <span class="type-name">{{ row.typeName }}</span>
+                      <el-tag
+                        v-if="row.isSpecial"
+                        type="warning"
+                        size="mini"
+                        style="margin-left: 5px"
+                      >
+                        鐗规畩
+                      </el-tag>
+                    </div>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="鍙戦�侀棶鍗锋暟"
+                  prop="sendCount"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <span class="number-text">{{
+                      row.sendCount.toLocaleString()
+                    }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="鍥炴敹闂嵎鏁�"
+                  prop="receiveCount"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <span class="number-text">{{
+                      row.receiveCount.toLocaleString()
+                    }}</span>
+                  </template>
+                </el-table-column>
+
+                <el-table-column
+                  label="鍥炴敹鐜�"
+                  prop="recoveryRate"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <span
+                      class="rate-text"
+                      :class="getRateClass(row.recoveryRate)"
+                    >
+                      {{ formatPercent(row.recoveryRate) }}
+                    </span>
+                  </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="satisfactionLevel"
+                  align="center"
+                  width="120"
+                >
+                  <template slot-scope="{ row }">
+                    <el-tag
+                      :type="getLevelTagType(row.satisfactionLevel)"
+                      effect="dark"
+                      size="small"
+                    >
+                      {{ row.satisfactionLevel }}
+                    </el-tag>
+                  </template>
+                </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"
+                  fixed="right"
+                >
+                  <template slot-scope="{ row }">
+                    <el-button
+                      type="text"
+                      size="small"
+                      @click="handleTypeDetail(row)"
+                    >
+                      璇︽儏
+                    </el-button>
+                    <el-button
+                      type="text"
+                      size="small"
+                      @click="handleExportData(row)"
+                    >
+                      瀵煎嚭
+                    </el-button>
+                  </template>
+                </el-table-column>
+              </el-table>
+
+              <!-- 绫诲瀷缁熻姹囨�� -->
+              <div class="type-summary-row">
+                <div class="type-summary-content">
+                  <div class="type-summary-item">
+                    <span class="label">绫诲瀷鎬绘暟锛�</span>
+                    <span class="value">{{ typeDetailData.length }}</span>
+                  </div>
+                  <div class="type-summary-item">
+                    <span class="label">骞冲潎鍥炴敹鐜囷細</span>
+                    <span class="value">{{
+                      formatPercent(averageRecoveryRate)
+                    }}</span>
+                  </div>
+                  <div class="type-summary-item">
+                    <span class="label">绫诲瀷骞冲潎鍒嗭細</span>
+                    <span class="value">{{ averageTypeScore.toFixed(1) }}</span>
+                  </div>
+                  <div class="type-summary-item">
+                    <span class="label">楂樻弧鎰忓害绫诲瀷锛�</span>
+                    <span class="value high-count"
+                      >{{ highSatisfactionCount }} 涓�</span
+                    >
+                  </div>
+                </div>
+              </div>
+            </div>
+          </el-tab-pane>
+        </el-tabs>
+      </el-card>
+    </div>
+  </div>
+</template>
+
+<script>
+import * as echarts from "echarts";
+import { statistics, satisfactionGraph } from "@/api/system/user";
+import store from "@/store";
+
+export default {
+  name: "SatisfactionStatistics",
+  data() {
+    return {
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        type: 2,
+        patientSource: "",
+        deptCode: "",
+        wardCode: "",
+        dateRange: [],
+      },
+
+      // 褰撳墠婵�娲荤殑tab
+      activeTab: "questionDetail",
+
+      // 鎮h�呮潵婧愰�夐」
+      patientSourceList: [
+        { value: "1", label: "闂ㄨ瘖" },
+        { value: "2", label: "浣忛櫌" },
+        { value: "3", label: "鎬ヨ瘖" },
+        { value: "4", label: "鍑洪櫌" },
+      ],
+
+      // 绉戝鍒楄〃
+      deptList: [],
+
+      // 鐥呭尯鍒楄〃
+      wardList: [],
+
+      // 鍥捐〃瀹炰緥
+      barChart: null,
+
+      // 鍔犺浇鐘舵��
+      loading: false,
+      detailLoading: false,
+      typeDetailLoading: false,
+
+      // 棰樼洰鏄庣粏鏁版嵁
+      questionDetailData: [],
+
+      // 棰樼洰鏄庣粏鏌ヨ鍙傛暟
+      detailQueryParams: {
+        pageNum: 1,
+        pageSize: 10,
+      },
+
+      // 棰樼洰鏄庣粏鎬绘暟
+      detailTotal: 0,
+
+      // 缁煎悎寰楀垎
+      totalScore: 0,
+      totalAnswerCount: 0,
+      totalAnswerRate: 0,
+
+      // 鍚勭被鍨嬬粺璁℃槑缁嗘暟鎹�
+      typeDetailData: [],
+
+      // 鏌辩姸鍥炬暟鎹�
+      chartData: [],
+
+      // 缁熻淇℃伅
+      totalSendCount: 0,
+      totalReceiveCount: 0,
+      overallRecoveryRate: 0,
+
+      // 绫诲瀷缁熻姹囨��
+      averageRecoveryRate: 0,
+      averageTypeScore: 0,
+      highSatisfactionCount: 0,
+
+      // 鏃ユ湡閫夋嫨鍣ㄩ�夐」
+      pickerOptions: {
+        shortcuts: [
+          {
+            text: "鏈�杩戜竴鍛�",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+          {
+            text: "鏈�杩戜竴涓湀",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+          {
+            text: "鏈�杩戜笁涓湀",
+            onClick(picker) {
+              const end = new Date();
+              const start = new Date();
+              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+              picker.$emit("pick", [start, end]);
+            },
+          },
+        ],
+        disabledDate(time) {
+          return time.getTime() > Date.now();
+        },
+      },
+
+      // 婊℃剰搴︾被鍨嬫暟鎹�
+      satisfactionTypes: [
+        { id: 401, name: "鍑洪櫌婊℃剰搴�", color: "#36B37E" },
+        { id: 402, name: "浣忛櫌婊℃剰搴�", color: "#4CAF50" },
+        { id: 403, name: "闂ㄨ瘖婊℃剰搴�", color: "#409EFF" },
+        { id: 404, name: "甯哥敤婊℃剰搴�", color: "#FF9D4D" },
+      ],
+
+      // 鏂板锛氶粯璁ゆ湇鍔$被鍨嬫暟缁�
+      defaultServiceTypes: ["6", "14", "15", "16"],
+
+      // 鏂板锛氬熀纭�妯℃澘闂ID闆嗗悎
+      scriptIds: [],
+
+      // 鏂板锛氭ā鏉縄D
+      templateId: null,
+    };
+  },
+
+  computed: {
+    // 璁$畻鏌ヨ寮�濮嬫椂闂�
+    startTime() {
+      if (this.queryParams.dateRange && this.queryParams.dateRange[0]) {
+        return this.queryParams.dateRange[0];
+      }
+      // 榛樿鏈�杩�7澶�
+      const date = new Date();
+      date.setDate(date.getDate() - 7);
+      return this.formatDate(date);
+    },
+
+    // 璁$畻鏌ヨ缁撴潫鏃堕棿
+    endTime() {
+      if (this.queryParams.dateRange && this.queryParams.dateRange[1]) {
+        return this.queryParams.dateRange[1];
+      }
+      // 榛樿浠婂ぉ
+      return this.formatDate(new Date());
+    },
+
+    // 璁$畻绉戝缂栫爜鏁扮粍
+    deptCodes() {
+      if (this.queryParams.deptCode) {
+        return [this.queryParams.deptCode];
+      }
+      return this.deptList.map((dept) => dept.value);
+    },
+
+    // 璁$畻鐥呭尯缂栫爜鏁扮粍
+    hospitalDistrictCodes() {
+      if (this.queryParams.wardCode) {
+        return [this.queryParams.wardCode];
+      }
+      return this.wardList.map((ward) => ward.value);
+    },
+  },
+
+  mounted() {
+    this.initData();
+  },
+
+  beforeDestroy() {
+    if (this.barChart) {
+      this.barChart.dispose();
+      this.barChart = null;
+    }
+  },
+
+  methods: {
+    // 鏍煎紡鍖栨棩鏈�
+    formatDate(date) {
+      const year = date.getFullYear();
+      const month = String(date.getMonth() + 1).padStart(2, "0");
+      const day = String(date.getDate()).padStart(2, "0");
+      return `${year}-${month}-${day}`;
+    },
+
+    // 鍒濆鍖栨暟鎹�
+    async initData() {
+      await this.getDeptList();
+      await this.getWardList();
+      this.initChart();
+      await this.loadData();
+    },
+
+    // 鑾峰彇绉戝鍒楄〃
+    getDeptList() {
+      return new Promise((resolve) => {
+        this.deptList = (this.$store.getters.belongDepts || []).map((dept) => {
+          return {
+            label: dept.deptName,
+            value: dept.deptCode,
+          };
+        });
+        resolve();
+      });
+    },
+
+    // 鑾峰彇鐥呭尯鍒楄〃
+    getWardList() {
+      return new Promise((resolve) => {
+        this.wardList = (this.$store.getters.belongWards || []).map((ward) => {
+          return {
+            label: ward.districtName,
+            value: ward.districtCode,
+          };
+        });
+        resolve();
+      });
+    },
+
+    // 鍔犺浇鏁版嵁
+    async loadData() {
+      await Promise.all([
+        this.loadChartData(),
+        this.loadQuestionDetailData(),
+        this.loadTypeDetailData(),
+      ]);
+    },
+
+    // 鍔犺浇鍥捐〃鏁版嵁
+    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);
+        } else {
+          this.$message.error(response.msg || "鑾峰彇鍥捐〃鏁版嵁澶辫触");
+          // 浣跨敤mock鏁版嵁
+          await this.generateMockChartData();
+        }
+      } catch (error) {
+        console.error("鑾峰彇鍥捐〃鏁版嵁鍑洪敊:", error);
+        this.$message.error("鑾峰彇鍥捐〃鏁版嵁澶辫触");
+        // 閿欒鏃朵娇鐢╩ock鏁版嵁
+        await this.generateMockChartData();
+      } finally {
+        this.loading = false;
+      }
+    },
+
+    // 澶勭悊鍥捐〃鏁版嵁
+    processChartData(apiData) {
+      if (!apiData || !apiData.rows || Object.keys(apiData.rows).length === 0) {
+        this.chartData = [];
+        this.totalSendCount = 0;
+        this.totalReceiveCount = 0;
+        this.overallRecoveryRate = 0;
+        this.renderChart([]);
+        return;
+      }
+
+      const chartData = [];
+      let totalSend = 0;
+      let totalReceive = 0;
+      let index = 0;
+
+      // 澶勭悊鎺ュ彛杩斿洖鐨勬弧鎰忓害绫诲瀷缁熻
+      Object.entries(apiData.rows).forEach(([typeName, typeStat]) => {
+        const sendCount = typeStat.subidAll || 0;
+        const receiveCount = typeStat.fillCountAll || 0;
+        const recoveryRate = typeStat.receiveRate || 0;
+
+        chartData.push({
+          name: typeName,
+          value: recoveryRate * 100, // 杞崲涓虹櫨鍒嗘瘮
+          sendCount: sendCount,
+          receiveCount: receiveCount,
+          averageScore: typeStat.averageScore || 0,
+          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);
+    },
+
+    // 鍔犺浇棰樼洰鏄庣粏鏁版嵁
+    async loadQuestionDetailData() {
+      this.detailLoading = true;
+      try {
+        const params = {
+          type: this.queryParams.type,
+          startTime: this.startTime,
+          endTime: this.endTime,
+          scriptids: this.scriptIds,
+          templateid: this.templateId,
+        };
+
+        const response = await statistics(params);
+
+        if (response.code === 200) {
+          this.processQuestionDetailData(response.rows);
+        } else {
+          this.$message.error(response.msg || "鑾峰彇棰樼洰鏄庣粏鏁版嵁澶辫触");
+          const mockData = await this.generateMockQuestionDetail();
+          this.questionDetailData = mockData.list;
+          this.detailTotal = mockData.total;
+          this.calculateSummary(mockData);
+        }
+      } catch (error) {
+        console.error("鑾峰彇棰樼洰鏄庣粏鏁版嵁鍑洪敊:", error);
+        this.$message.error("鑾峰彇棰樼洰鏄庣粏鏁版嵁澶辫触");
+        const mockData = await this.generateMockQuestionDetail();
+        this.questionDetailData = mockData.list;
+        this.detailTotal = mockData.total;
+        this.calculateSummary(mockData);
+      } finally {
+        this.detailLoading = false;
+      }
+    },
+
+    // 澶勭悊鎺ュ彛杩斿洖鐨勯鐩槑缁嗘暟鎹�
+    processQuestionDetailData(apiData) {
+      if (!apiData || !apiData.patSatisfactionDetailEntities) {
+        this.questionDetailData = [];
+        this.detailTotal = 0;
+        this.totalAnswerCount = 0;
+        this.totalAnswerRate = 0;
+        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 || "",
+          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,
+        };
+      });
+
+      const startIndex =
+        (this.detailQueryParams.pageNum - 1) * this.detailQueryParams.pageSize;
+      const endIndex = startIndex + this.detailQueryParams.pageSize;
+      const paginatedData = detailData.slice(startIndex, endIndex);
+
+      this.questionDetailData = paginatedData;
+      this.detailTotal = detailData.length;
+      this.totalAnswerCount = apiData.totalPerson || 0;
+      this.totalAnswerRate = apiData.totalAnswerRate || 0;
+    },
+
+    // 鍔犺浇绫诲瀷鏄庣粏鏁版嵁
+    async loadTypeDetailData() {
+      this.typeDetailLoading = 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.processTypeDetailData(response.data);
+        } else {
+          this.$message.error(response.msg || "鑾峰彇绫诲瀷鏄庣粏鏁版嵁澶辫触");
+          const mockData = await this.generateMockTypeDetail();
+          this.typeDetailData = mockData;
+          this.calculateTypeSummary(mockData);
+        }
+      } catch (error) {
+        console.error("鑾峰彇绫诲瀷鏄庣粏鏁版嵁鍑洪敊:", error);
+        this.$message.error("鑾峰彇绫诲瀷鏄庣粏鏁版嵁澶辫触");
+        const mockData = await this.generateMockTypeDetail();
+        this.typeDetailData = mockData;
+        this.calculateTypeSummary(mockData);
+      } finally {
+        this.typeDetailLoading = false;
+      }
+    },
+
+    // 澶勭悊绫诲瀷鏄庣粏鏁版嵁
+    processTypeDetailData(apiData) {
+      if (!apiData || !apiData.rows || Object.keys(apiData.rows).length === 0) {
+        this.typeDetailData = [];
+        this.calculateTypeSummary([]);
+        return;
+      }
+
+      const typeDetail = [];
+      Object.entries(apiData.rows).forEach(([typeName, typeStat], index) => {
+        const sendCount = typeStat.subidAll || 0;
+        const receiveCount = typeStat.fillCountAll || 0;
+        const recoveryRate = typeStat.receiveRate || 0;
+        const averageScore = typeStat.averageScore || 0;
+
+        typeDetail.push({
+          id: index + 1,
+          typeName: typeName,
+          isSpecial: false, // 鏍规嵁瀹為檯鎯呭喌鍒ゆ柇
+          sendCount: sendCount,
+          receiveCount: receiveCount,
+          recoveryRate: recoveryRate,
+          averageScore: averageScore,
+          maxScore: 5, // 榛樿鍊�
+          minScore: 0, // 榛樿鍊�
+          satisfactionLevel: this.getSatisfactionLevel(averageScore),
+          trend: "stable", // 榛樿绋冲畾
+        });
+      });
+
+      this.typeDetailData = typeDetail;
+      this.calculateTypeSummary(typeDetail);
+    },
+
+    // 鏍规嵁骞冲潎鍒嗚幏鍙栨弧鎰忓害绛夌骇
+    getSatisfactionLevel(score) {
+      if (score >= 4.5) return "浼樼";
+      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";
+    },
+
+    // 璁$畻缁煎悎寰楀垎
+    calculateSummary(data) {
+      let totalScore = 0;
+      let totalAnswerCount = 0;
+      let totalCount = 0;
+
+      data.list.forEach((item) => {
+        totalScore += item.averageScore;
+        totalAnswerCount += item.answerCount;
+        totalCount += item.totalCount;
+      });
+
+      this.totalScore =
+        data.list.length > 0 ? totalScore / data.list.length : 0;
+      this.totalAnswerCount = totalAnswerCount;
+      this.totalAnswerRate = totalCount > 0 ? totalAnswerCount / totalCount : 0;
+    },
+
+    // 璁$畻绫诲瀷缁熻姹囨��
+    calculateTypeSummary(data) {
+      if (data.length === 0) {
+        this.averageRecoveryRate = 0;
+        this.averageTypeScore = 0;
+        this.highSatisfactionCount = 0;
+        return;
+      }
+
+      let totalRecoveryRate = 0;
+      let totalTypeScore = 0;
+      let highCount = 0;
+
+      data.forEach((item) => {
+        totalRecoveryRate += item.recoveryRate;
+        totalTypeScore += item.averageScore;
+        if (
+          item.satisfactionLevel === "浼樼" ||
+          item.satisfactionLevel === "鑹ソ"
+        ) {
+          highCount++;
+        }
+      });
+
+      this.averageRecoveryRate = totalRecoveryRate / data.length;
+      this.averageTypeScore = totalTypeScore / data.length;
+      this.highSatisfactionCount = highCount;
+    },
+
+    // 鍒濆鍖栧浘琛�
+    initChart() {
+      const chartDom = document.getElementById("satisfactionBarChart");
+      if (!chartDom) return;
+
+      this.barChart = echarts.init(chartDom);
+      window.addEventListener("resize", this.handleChartResize);
+    },
+
+    // 娓叉煋鍥捐〃
+    renderChart(chartData) {
+      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;
+  }
+      const option = {
+        title: {
+          text: "",
+          left: "center",
+        },
+        tooltip: {
+          trigger: "axis",
+          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>
+            `;
+          },
+        },
+        grid: {
+          left: "3%",
+          right: "4%",
+          bottom: "3%",
+          top: 60,
+          containLabel: true,
+        },
+        xAxis: {
+          type: "category",
+          data: chartData.map((item) => item.name),
+          axisLabel: {
+            interval: 0,
+            rotate: 0,
+            fontSize: 12,
+            color: "#666",
+          },
+          axisLine: {
+            lineStyle: {
+              color: "#DCDFE6",
+            },
+          },
+          axisTick: {
+            alignWithLabel: true,
+          },
+        },
+        yAxis: {
+          type: "value",
+          name: "濉姤姣斾緥 (%)",
+          min: 0,
+          max: 100,
+          axisLabel: {
+            formatter: "{value}%",
+            color: "#666",
+          },
+          axisLine: {
+            lineStyle: {
+              color: "#DCDFE6",
+            },
+          },
+          splitLine: {
+            lineStyle: {
+              type: "dashed",
+              color: "#E4E7ED",
+            },
+          },
+        },
+        series: [
+          {
+            name: "濉姤姣斾緥",
+            type: "bar",
+            barWidth: 40,
+            data: chartData,
+            itemStyle: {
+              color: (params) => {
+                return params.data.itemStyle.color;
+              },
+            },
+            label: {
+              show: true,
+              position: "top",
+              formatter: "{c}%",
+              fontSize: 12,
+              color: "#333",
+            },
+          },
+        ],
+      };
+
+      this.barChart.setOption(option);
+    },
+
+    // 鐢熸垚Mock鍥捐〃鏁版嵁
+    generateMockChartData() {
+      return new Promise((resolve) => {
+        setTimeout(() => {
+          const data = this.satisfactionTypes.map((type, index) => ({
+            name: type.name,
+            recoveryRate: Math.random() * 0.3 + 0.6,
+            sendCount: Math.floor(Math.random() * 3000) + 1500,
+            receiveCount: 0,
+            color: type.color,
+          }));
+
+          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,
+            itemStyle: { color: item.color },
+          }));
+
+          this.chartData = chartData;
+          this.renderChart(chartData);
+          resolve();
+        }, 300);
+      });
+    },
+
+    // 鐢熸垚Mock棰樼洰璇︽儏鏁版嵁
+    generateMockQuestionDetail() {
+      return new Promise((resolve) => {
+        setTimeout(() => {
+          const questions = [
+            {
+              scriptContent: "鎮ㄥ鏈灏卞尰鐨勬暣浣撴弧鎰忕▼搴︼紵",
+              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,
+                },
+                {
+                  optionText: "涓嶆弧鎰�",
+                  chosenQuantity: 6,
+                  chosenPercentage: 0.05,
+                },
+              ],
+            },
+            {
+              scriptContent: "鎮ㄥ鍖绘姢浜哄憳鐨勬湇鍔℃�佸害鏄惁婊℃剰锛�",
+              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,
+                },
+                {
+                  optionText: "涓嶆弧鎰�",
+                  chosenQuantity: 2,
+                  chosenPercentage: 0.01,
+                },
+                {
+                  optionText: "闈炲父涓嶆弧鎰�",
+                  chosenQuantity: 1,
+                  chosenPercentage: 0.01,
+                },
+              ],
+            },
+          ];
+
+          const startIndex =
+            (this.detailQueryParams.pageNum - 1) *
+            this.detailQueryParams.pageSize;
+          const endIndex = startIndex + this.detailQueryParams.pageSize;
+          const paginatedData = questions.slice(startIndex, endIndex);
+
+          resolve({
+            list: paginatedData,
+            total: questions.length,
+          });
+        }, 300);
+      });
+    },
+
+    // 鐢熸垚Mock绫诲瀷鏄庣粏鏁版嵁
+    generateMockTypeDetail() {
+      return new Promise((resolve) => {
+        setTimeout(() => {
+          const types = [
+            {
+              id: 401,
+              typeName: "鍑洪櫌婊℃剰搴�",
+              isSpecial: false,
+              sendCount: 2850,
+              receiveCount: 2680,
+              recoveryRate: 0.94,
+              averageScore: 4.8,
+              maxScore: 5,
+              minScore: 3.8,
+              satisfactionLevel: "浼樼",
+              trend: "up",
+            },
+            {
+              id: 402,
+              typeName: "浣忛櫌婊℃剰搴�",
+              isSpecial: false,
+              sendCount: 2620,
+              receiveCount: 2405,
+              recoveryRate: 0.918,
+              averageScore: 4.6,
+              maxScore: 5,
+              minScore: 3.5,
+              satisfactionLevel: "浼樼",
+              trend: "stable",
+            },
+            {
+              id: 403,
+              typeName: "闂ㄨ瘖婊℃剰搴�",
+              isSpecial: false,
+              sendCount: 3780,
+              receiveCount: 3220,
+              recoveryRate: 0.852,
+              averageScore: 4.3,
+              maxScore: 5,
+              minScore: 2.5,
+              satisfactionLevel: "鑹ソ",
+              trend: "up",
+            },
+            {
+              id: 404,
+              typeName: "甯哥敤婊℃剰搴�",
+              isSpecial: true,
+              sendCount: 1950,
+              receiveCount: 1780,
+              recoveryRate: 0.913,
+              averageScore: 4.5,
+              maxScore: 5,
+              minScore: 3.2,
+              satisfactionLevel: "鑹ソ",
+              trend: "stable",
+            },
+          ];
+
+          resolve(types);
+        }, 300);
+      });
+    },
+
+    // 鑾峰彇鍥捐〃棰滆壊
+    getChartColor(index) {
+      const colors = [
+        "#36B37E",
+        "#4CAF50",
+        "#409EFF",
+        "#FF9D4D",
+        "#9B8DFF",
+        "#FF6B6B",
+      ];
+      return colors[index % colors.length];
+    },
+
+    // 澶勭悊鍥捐〃鍝嶅簲寮�
+    handleChartResize() {
+      if (this.barChart) {
+        this.barChart.resize();
+      }
+    },
+
+    // 澶勭悊鏌ヨ
+    handleSearch() {
+      this.detailQueryParams.pageNum = 1;
+      this.loadData();
+      // 寮哄埗閲嶆柊娓叉煋鍥捐〃
+      setTimeout(() => {
+        if (this.chartData.length === 0) {
+          this.renderChart([]);
+        }
+      }, 100);
+    },
+
+    // 澶勭悊閲嶇疆
+    handleReset() {
+      this.$refs.queryForm.resetFields();
+      this.queryParams.dateRange = [];
+      this.detailQueryParams.pageNum = 1;
+      this.loadData();
+    },
+
+    // 澶勭悊Tab鍒囨崲
+    handleTabClick(tab) {
+      if (tab.name === "typeDetail" && this.typeDetailData.length === 0) {
+        this.loadTypeDetailData();
+      }
+    },
+
+    // 澶勭悊鏄庣粏鍒嗛〉澶у皬鍙樺寲
+    handleDetailSizeChange(size) {
+      this.detailQueryParams.pageSize = size;
+      this.detailQueryParams.pageNum = 1;
+      this.loadQuestionDetailData();
+    },
+
+    // 澶勭悊鏄庣粏椤电爜鍙樺寲
+    handleDetailPageChange(page) {
+      this.detailQueryParams.pageNum = page;
+      this.loadQuestionDetailData();
+    },
+
+    // 澶勭悊绫诲瀷璇︽儏
+    handleTypeDetail(row) {
+      this.$message.info(`鏌ョ湅绫诲瀷璇︽儏锛�${row.typeName}`);
+    },
+
+    // 澶勭悊瀵煎嚭鏁版嵁
+    handleExportData(row) {
+      this.$message.success(`姝e湪瀵煎嚭 ${row.typeName} 鏁版嵁...`);
+    },
+
+    // 鏍煎紡鍖栫櫨鍒嗘瘮
+    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)}%`;
+    },
+
+    // 鑾峰彇鍥炴敹鐜囨牱寮忕被
+    getRateClass(rate) {
+      if (rate >= 0.9) return "rate-high";
+      if (rate >= 0.8) return "rate-medium";
+      return "rate-low";
+    },
+
+    // 鑾峰彇婊℃剰搴︾瓑绾ф爣绛剧被鍨�
+    getLevelTagType(level) {
+      const levelMap = {
+        浼樼: "success",
+        鑹ソ: "primary",
+        涓�鑸�: "warning",
+        杈冨樊: "danger",
+        宸�: "info",
+      };
+      return levelMap[level] || "info";
+    },
+
+    // 澶勭悊绉戝閫夋嫨鍙樺寲
+    handleDeptChange() {
+      this.loadData();
+    },
+
+    // 澶勭悊鐥呭尯閫夋嫨鍙樺寲
+    handleWardChange() {
+      this.loadData();
+    },
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.satisfaction-statistics {
+  padding: 20px;
+  background-color: #f5f7fa;
+  min-height: 100vh;
+
+  .query-section {
+    margin-bottom: 20px;
+
+    .query-form {
+      display: flex;
+      flex-wrap: wrap;
+      align-items: center;
+
+      ::v-deep .el-form-item {
+        margin-bottom: 0;
+        margin-right: 20px;
+
+        &:last-child {
+          margin-right: 0;
+        }
+      }
+    }
+  }
+
+  .chart-section {
+    margin-bottom: 20px;
+
+    .chart-container {
+      .chart-header {
+        display: flex;
+        justify-content: space-between;
+        align-items: center;
+        margin-bottom: 20px;
+        padding-bottom: 15px;
+        border-bottom: 1px solid #f0f0f0;
+
+        .chart-title {
+          margin: 0;
+          font-size: 16px;
+          font-weight: 600;
+          color: #303133;
+        }
+
+        .statistic-info {
+          display: flex;
+          gap: 30px;
+          align-items: center;
+
+          .statistic-item {
+            display: flex;
+            align-items: center;
+            gap: 8px;
+
+            .statistic-label {
+              font-size: 14px;
+              color: #606266;
+            }
+
+            .statistic-value {
+              font-size: 18px;
+              font-weight: 600;
+              color: #409eff;
+            }
+          }
+        }
+      }
+    }
+  }
+
+  .tab-section {
+    ::v-deep .el-tabs__header {
+      margin-bottom: 0;
+    }
+
+    ::v-deep .el-tabs__content {
+      padding: 20px 0 0 0;
+    }
+  }
+
+  .detail-table-section {
+    .option-detail {
+      padding: 15px;
+      background: #f8f9fa;
+      border-radius: 4px;
+      margin: 10px 0;
+    }
+
+    ::v-deep .el-table {
+      th {
+        background-color: #f8f9fa;
+        font-weight: 600;
+        color: #333;
+        padding: 12px 0;
+      }
+
+      td {
+        padding: 12px 0;
+      }
+
+      .question-row {
+        td {
+          background-color: #fff;
+        }
+
+        &:hover {
+          td {
+            background-color: #f5f7fa;
+          }
+        }
+      }
+    }
+
+    .score-text {
+      font-weight: 600;
+      color: #1890ff;
+      font-size: 16px;
+    }
+
+    .summary-row {
+      margin-top: 20px;
+      padding: 20px;
+      background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
+      border-radius: 8px;
+      border: 1px solid #dee2e6;
+
+      .summary-content {
+        display: flex;
+        justify-content: space-around;
+        align-items: center;
+
+        .summary-item {
+          text-align: center;
+
+          .label {
+            font-size: 16px;
+            color: #606266;
+            margin-right: 8px;
+          }
+
+          .value {
+            font-size: 24px;
+            font-weight: 600;
+            color: #409eff;
+          }
+        }
+      }
+    }
+
+    .pagination-section {
+      display: flex;
+      justify-content: center;
+      padding: 20px 0 0 0;
+    }
+  }
+
+  .type-detail-section {
+    .type-detail-table {
+      ::v-deep .el-table__header-wrapper {
+        th {
+          background-color: #f0f7ff;
+          font-weight: 600;
+          color: #333;
+        }
+      }
+
+      .type-name-cell {
+        display: flex;
+        align-items: center;
+        justify-content: center;
+
+        .type-name {
+          font-weight: 500;
+        }
+      }
+
+      .number-text {
+        font-weight: 600;
+        color: #333;
+      }
+
+      .rate-text {
+        font-weight: 600;
+        font-size: 14px;
+
+        &.rate-high {
+          color: #67c23a;
+        }
+
+        &.rate-medium {
+          color: #e6a23c;
+        }
+
+        &.rate-low {
+          color: #f56c6c;
+        }
+      }
+
+      .score-text {
+        font-weight: 600;
+        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 {
+      margin-top: 20px;
+      padding: 20px;
+      background: linear-gradient(135deg, #f0f9ff 0%, #e6f7ff 100%);
+      border-radius: 8px;
+      border: 1px solid #d0ebff;
+
+      .type-summary-content {
+        display: flex;
+        justify-content: space-around;
+        align-items: center;
+        flex-wrap: wrap;
+        gap: 20px;
+
+        .type-summary-item {
+          text-align: center;
+          min-width: 150px;
+
+          .label {
+            font-size: 14px;
+            color: #606266;
+            margin-right: 8px;
+          }
+
+          .value {
+            font-size: 20px;
+            font-weight: 600;
+            color: #409eff;
+          }
+
+          .high-count {
+            color: #67c23a;
+          }
+        }
+      }
+    }
+  }
+
+  // 鍐呭眰琛ㄦ牸鏍峰紡
+  .inner-table {
+    ::v-deep .el-table__header-wrapper {
+      th {
+        background-color: #f0f7ff !important;
+        color: #333;
+        font-weight: 600;
+      }
+    }
+
+    ::v-deep .el-table__body-wrapper {
+      tr {
+        background-color: #fff;
+
+        &:hover {
+          background-color: #f5f7fa;
+        }
+      }
+    }
+  }
+}
+
+@media (max-width: 768px) {
+  .satisfaction-statistics {
+    padding: 10px;
+
+    .query-section {
+      .query-form {
+        ::v-deep .el-form-item {
+          width: 100%;
+          margin-right: 0;
+          margin-bottom: 10px;
+        }
+      }
+    }
+
+    .chart-section {
+      .chart-container {
+        .chart-header {
+          flex-direction: column;
+          align-items: flex-start;
+          gap: 15px;
+
+          .statistic-info {
+            width: 100%;
+            justify-content: space-between;
+            flex-wrap: wrap;
+            gap: 10px;
+          }
+        }
+      }
+    }
+
+    .detail-table-section {
+      .summary-content {
+        flex-direction: column;
+        gap: 15px;
+      }
+    }
+
+    .type-detail-section {
+      .type-summary-content {
+        flex-direction: column;
+        gap: 15px;
+      }
+    }
+  }
+}
+</style>

--
Gitblit v1.9.3