From d0c13711e4a03409c28d7a01716218689e52c11c Mon Sep 17 00:00:00 2001
From: WXL (wul) <wl_5969728@163.com>
Date: 星期五, 27 三月 2026 10:44:24 +0800
Subject: [PATCH] 测试完成

---
 src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue |  387 +++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 304 insertions(+), 83 deletions(-)

diff --git a/src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue b/src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue
index 07f6c19..1b59b49 100644
--- a/src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue
+++ b/src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue
@@ -142,9 +142,11 @@
           v-if="queryParams.statisticaltype == 1"
           label="鍑洪櫌鐥呭尯"
           align="center"
+          sortable
           key="leavehospitaldistrictname"
           prop="leavehospitaldistrictname"
           :show-overflow-tooltip="true"
+          :sort-method="sortChineseNumber"
           min-width="120"
         />
 
@@ -191,7 +193,12 @@
           min-width="100"
         >
           <template slot-scope="scope">
-            <span v-if="scope.row.followUpRate !== null && scope.row.followUpRate !== undefined">
+            <span
+              v-if="
+                scope.row.followUpRate !== null &&
+                scope.row.followUpRate !== undefined
+              "
+            >
               {{ formatPercent(scope.row.followUpRate) }}
             </span>
             <span v-else>-</span>
@@ -241,24 +248,20 @@
           min-width="100"
         >
           <template slot-scope="scope">
-            <span v-if="scope.row.joyTotal !== null && scope.row.joyTotal !== undefined">
+            <span
+              v-if="
+                scope.row.joyTotal !== null && scope.row.joyTotal !== undefined
+              "
+            >
               {{ formatPercent(scope.row.joyTotal) }}
             </span>
             <span v-else>-</span>
           </template>
         </el-table-column>
 
-        <el-table-column
-          label="鎿嶄綔"
-          align="center"
-          fixed="right"
-          width="120"
-        >
+        <el-table-column label="鎿嶄綔" align="center" fixed="right" width="120">
           <template slot-scope="scope">
-            <el-button
-              type="text"
-              @click="getinfo(scope.row)"
-            >
+            <el-button type="text" @click="getinfo(scope.row)">
               <i class="el-icon-s-order" style="margin-right: 4px"></i>
               鏌ョ湅璇︽儏
             </el-button>
@@ -303,15 +306,21 @@
       :close-on-click-modal="false"
     >
       <template #title>
-        <div style="display: flex; align-items: center;">
-          <i class="el-icon-s-data" style="margin-right: 8px; color: #409EFF;"></i>
+        <div style="display: flex; align-items: center">
+          <i
+            class="el-icon-s-data"
+            style="margin-right: 8px; color: #409eff"
+          ></i>
           <span>{{ topicvalue.name }}</span>
-          <span style="margin-left: 10px; color: #666; font-size: 14px;">婊℃剰搴︽寚鏍囪鎯�</span>
+          <span style="margin-left: 10px; color: #666; font-size: 14px"
+            >婊℃剰搴︽寚鏍囪鎯�</span
+          >
         </div>
       </template>
       <topic-dialog
         v-if="topicVisible"
         :row-data="currentRow"
+        :topicList="topiclist"
         :query-params="queryParams"
         @close="topicVisible = false"
       />
@@ -320,35 +329,39 @@
 </template>
 
 <script>
-import { getSfStatisticsJoy, getSfStatisticsJoyInfo, selectTimelyRate } from "@/api/system/user";
+import {
+  getSfStatisticsJoy,
+  getSfStatisticsJoyInfo,
+  selectTimelyRate,
+} from "@/api/system/user";
 import ExcelJS from "exceljs";
 import { saveAs } from "file-saver";
-import SeedetailsDialog from './components/SeedetailsDialog.vue';
-import TopicDialog from './components/TopicDialog.vue';
+import SeedetailsDialog from "./components/SeedetailsDialog.vue";
+import TopicDialog from "./components/TopicDialog.vue";
 
 export default {
-  name: 'FollowupStatistics',
+  name: "FollowupStatistics",
   components: {
     SeedetailsDialog,
-    TopicDialog
+    TopicDialog,
   },
   data() {
     return {
       // 鏌ヨ鍙傛暟
       queryParams: {
         statisticaltype: 1,
-        leavehospitaldistrictcodes: [],
+        leavehospitaldistrictcodes: ["all"],
         deptcodes: [],
         serviceType: [2],
         dateRange: [],
         pageNum: 1,
-        pageSize: 20
+        pageSize: 20,
       },
 
       // 缁熻绫诲瀷鍒楄〃
       Statisticallist: [
         { label: "鐥呭尯缁熻", value: 1 },
-        { label: "绉戝缁熻", value: 2 }
+        { label: "绉戝缁熻", value: 2 },
       ],
 
       // 鐥呭尯鍒楄〃
@@ -384,44 +397,44 @@
       // 婊℃剰搴﹁鎯呮暟鎹�
       topiclist: [],
       topicvalue: {
-        name: ''
+        name: "",
       },
 
       // 鏃ユ湡閫夋嫨鍣ㄩ�夐」
       pickerOptions: {
         shortcuts: [
           {
-            text: '鏈�杩戜竴鍛�',
+            text: "鏈�杩戜竴鍛�",
             onClick(picker) {
               const end = new Date();
               const start = new Date();
               start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
-              picker.$emit('pick', [start, end]);
-            }
+              picker.$emit("pick", [start, end]);
+            },
           },
           {
-            text: '鏈�杩戜竴涓湀',
+            text: "鏈�杩戜竴涓湀",
             onClick(picker) {
               const end = new Date();
               const start = new Date();
               start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
-              picker.$emit('pick', [start, end]);
-            }
+              picker.$emit("pick", [start, end]);
+            },
           },
           {
-            text: '鏈�杩戜笁涓湀',
+            text: "鏈�杩戜笁涓湀",
             onClick(picker) {
               const end = new Date();
               const start = new Date();
               start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
-              picker.$emit('pick', [start, end]);
-            }
-          }
+              picker.$emit("pick", [start, end]);
+            },
+          },
         ],
         disabledDate(time) {
           return time.getTime() > Date.now();
-        }
-      }
+        },
+      },
     };
   },
 
@@ -442,20 +455,24 @@
       this.options = this.$store.getters.tasktypes || [];
 
       // 鑾峰彇绉戝鍒楄〃
-      this.flatArraydept = (this.$store.getters.belongDepts || []).map((dept) => {
-        return {
-          label: dept.deptName,
-          value: dept.deptCode
-        };
-      });
+      this.flatArraydept = (this.$store.getters.belongDepts || []).map(
+        (dept) => {
+          return {
+            label: dept.deptName,
+            value: dept.deptCode,
+          };
+        }
+      );
 
       // 鑾峰彇鐥呭尯鍒楄〃
-      this.flatArrayhospit = (this.$store.getters.belongWards || []).map((ward) => {
-        return {
-          label: ward.districtName,
-          value: ward.districtCode
-        };
-      });
+      this.flatArrayhospit = (this.$store.getters.belongWards || []).map(
+        (ward) => {
+          return {
+            label: ward.districtName,
+            value: ward.districtCode,
+          };
+        }
+      );
 
       // 娣诲姞鍏ㄩ儴閫夐」
       this.flatArraydept.push({ label: "鍏ㄩ儴", value: "all" });
@@ -469,11 +486,14 @@
         // 澶勭悊鏌ヨ鍙傛暟
         const params = {
           configKey: "joyCount",
-          ...this.queryParams
+          ...this.queryParams,
         };
 
         // 澶勭悊鏃ユ湡鑼冨洿
-        if (this.queryParams.dateRange && this.queryParams.dateRange.length === 2) {
+        if (
+          this.queryParams.dateRange &&
+          this.queryParams.dateRange.length === 2
+        ) {
           params.startTime = this.queryParams.dateRange[0];
           params.endTime = this.queryParams.dateRange[1];
         }
@@ -483,31 +503,215 @@
           // 鐥呭尯缁熻
           if (params.leavehospitaldistrictcodes.includes("all")) {
             // 濡傛灉閫夋嫨浜�"鍏ㄩ儴"锛屽垯绉婚櫎"all"鍊�
-            params.leavehospitaldistrictcodes = params.leavehospitaldistrictcodes.filter(item => item !== "all");
+            params.leavehospitaldistrictcodes =
+              params.leavehospitaldistrictcodes.filter(
+                (item) => item !== "all"
+              );
             // 濡傛灉闇�瑕佷紶鎵�鏈夌梾鍖轰唬鐮侊紝鍙互浠巗tore涓幏鍙�
-            params.leavehospitaldistrictcodes = (this.$store.getters.belongWards || []).map(ward => ward.districtCode);
+            params.leavehospitaldistrictcodes = (
+              this.$store.getters.belongWards || []
+            ).map((ward) => ward.districtCode);
           }
         } else if (params.statisticaltype == 2) {
           // 绉戝缁熻
           if (params.deptcodes.includes("all")) {
             // 濡傛灉閫夋嫨浜�"鍏ㄩ儴"锛屽垯绉婚櫎"all"鍊�
-            params.deptcodes = params.deptcodes.filter(item => item !== "all");
+            params.deptcodes = params.deptcodes.filter(
+              (item) => item !== "all"
+            );
             // 濡傛灉闇�瑕佷紶鎵�鏈夌瀹や唬鐮侊紝鍙互浠巗tore涓幏鍙�
-            params.deptcodes = (this.$store.getters.belongDepts || []).map(dept => dept.deptCode);
+            params.deptcodes = (this.$store.getters.belongDepts || []).map(
+              (dept) => dept.deptCode
+            );
           }
         }
 
         const response = await getSfStatisticsJoy(params);
-        this.userList = response.data || [];
+        this.userList = this.customSort(response.data) || [];
         this.total = response.total || 0;
       } catch (error) {
-        console.error('鑾峰彇缁熻鍒楄〃澶辫触:', error);
-        this.$message.error('鑾峰彇鏁版嵁澶辫触');
+        console.error("鑾峰彇缁熻鍒楄〃澶辫触:", error);
+        this.$message.error("鑾峰彇鏁版嵁澶辫触");
       } finally {
         this.loading = false;
       }
     },
+    sortChineseNumber(aRow, bRow) {
+      const a = aRow.leavehospitaldistrictname;
+      const b = bRow.leavehospitaldistrictname;
 
+      // 涓枃鏁板瓧鍒伴樋鎷変集鏁板瓧鐨勬槧灏勶紙鎵╁睍鍒�45锛�
+      const chineseNumMap = {
+        涓�: 1,
+        浜�: 2,
+        涓�: 3,
+        鍥�: 4,
+        浜�: 5,
+        鍏�: 6,
+        涓�: 7,
+        鍏�: 8,
+        涔�: 9,
+        鍗�: 10,
+        鍗佷竴: 11,
+        鍗佷簩: 12,
+        鍗佷笁: 13,
+        鍗佸洓: 14,
+        鍗佷簲: 15,
+        鍗佸叚: 16,
+        鍗佷竷: 17,
+        鍗佸叓: 18,
+        鍗佷節: 19,
+        浜屽崄: 20,
+        浜屽崄涓�: 21,
+        浜屽崄浜�: 22,
+        浜屽崄涓�: 23,
+        浜屽崄鍥�: 24,
+        浜屽崄浜�: 25,
+        浜屽崄鍏�: 26,
+        浜屽崄涓�: 27,
+        浜屽崄鍏�: 28,
+        浜屽崄涔�: 29,
+        涓夊崄: 30,
+        涓夊崄涓�: 31,
+        涓夊崄浜�: 32,
+        涓夊崄涓�: 33,
+        涓夊崄鍥�: 34,
+        涓夊崄浜�: 35,
+        涓夊崄鍏�: 36,
+        涓夊崄涓�: 37,
+        涓夊崄鍏�: 38,
+        涓夊崄涔�: 39,
+        鍥涘崄: 40,
+        鍥涘崄涓�: 41,
+        鍥涘崄浜�: 42,
+        鍥涘崄涓�: 43,
+        鍥涘崄鍥�: 44,
+        鍥涘崄浜�: 45,
+      };
+
+      // 鎻愬彇涓枃鏁板瓧
+      const getNumberFromText = (text) => {
+        if (!text || typeof text !== "string") return -1;
+
+        // 鍖归厤涓枃鏁板瓧锛屾敮鎸佷竴鍒板洓鍗佷簲
+        const match = text.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/);
+
+        if (match && match[1]) {
+          const chineseNum = match[1];
+          return chineseNumMap[chineseNum] !== undefined
+            ? chineseNumMap[chineseNum]
+            : -1;
+        }
+
+        // 濡傛灉娌℃湁鍖归厤鍒颁腑鏂囨暟瀛楋紝灏濊瘯鍖归厤闃挎媺浼暟瀛�
+        const arabicMatch = text.match(/^(\d+)/);
+        if (arabicMatch && arabicMatch[1]) {
+          const num = parseInt(arabicMatch[1], 10);
+          return num >= 1 && num <= 45 ? num : -1;
+        }
+
+        return -1;
+      };
+
+      const numA = getNumberFromText(a);
+      const numB = getNumberFromText(b);
+
+      // 澶勭悊鏃犳硶瑙f瀽鐨勬儏鍐�
+      if (numA === -1 && numB === -1) {
+        return (a || "").localeCompare(b || "");
+      }
+      if (numA === -1) return 1;
+      if (numB === -1) return -1;
+
+      return numA - numB;
+    },
+    customSort(data) {
+      // 瀹氫箟鎮ㄦ湡鏈涚殑鐥呭尯椤哄簭锛堟墿灞曞埌鍥涘崄浜旓級
+      const order = [
+        "涓�",
+        "浜�",
+        "涓�",
+        "鍥�",
+        "浜�",
+        "鍏�",
+        "涓�",
+        "鍏�",
+        "涔�",
+        "鍗�",
+        "鍗佷竴",
+        "鍗佷簩",
+        "鍗佷笁",
+        "鍗佸洓",
+        "鍗佷簲",
+        "鍗佸叚",
+        "鍗佷竷",
+        "鍗佸叓",
+        "鍗佷節",
+        "浜屽崄",
+        "浜屽崄涓�",
+        "浜屽崄浜�",
+        "浜屽崄涓�",
+        "浜屽崄鍥�",
+        "浜屽崄浜�",
+        "浜屽崄鍏�",
+        "浜屽崄涓�",
+        "浜屽崄鍏�",
+        "浜屽崄涔�",
+        "涓夊崄",
+        "涓夊崄涓�",
+        "涓夊崄浜�",
+        "涓夊崄涓�",
+        "涓夊崄鍥�",
+        "涓夊崄浜�",
+        "涓夊崄鍏�",
+        "涓夊崄涓�",
+        "涓夊崄鍏�",
+        "涓夊崄涔�",
+        "鍥涘崄",
+        "鍥涘崄涓�",
+        "鍥涘崄浜�",
+        "鍥涘崄涓�",
+        "鍥涘崄鍥�",
+        "鍥涘崄浜�",
+      ];
+
+      return data.sort((a, b) => {
+        // 鎻愬彇鐥呭尯鍚嶇О涓殑涓枃鏁板瓧閮ㄥ垎
+        const getIndex = (name) => {
+          if (!name || typeof name !== "string") return -1;
+
+          // 鍖归厤涓枃鏁板瓧
+          const chineseMatch = name.match(/^([涓�浜屼笁鍥涗簲鍏竷鍏節鍗乚+)/);
+          if (chineseMatch && chineseMatch[1]) {
+            return order.indexOf(chineseMatch[1]);
+          }
+
+          // 鍖归厤闃挎媺浼暟瀛�
+          const arabicMatch = name.match(/^(\d+)/);
+          if (arabicMatch && arabicMatch[1]) {
+            const num = parseInt(arabicMatch[1], 10);
+            if (num >= 1 && num <= 45) {
+              return num - 1; // 鍥犱负鏁扮粍绱㈠紩浠�0寮�濮�
+            }
+          }
+
+          return -1;
+        };
+
+        const indexA = getIndex(a.leavehospitaldistrictname);
+        const indexB = getIndex(b.leavehospitaldistrictname);
+
+        // 鎺掑簭閫昏緫
+        if (indexA === -1 && indexB === -1) {
+          return (a.leavehospitaldistrictname || "").localeCompare(
+            b.leavehospitaldistrictname || ""
+          );
+        }
+        if (indexA === -1) return 1;
+        if (indexB === -1) return -1;
+        return indexA - indexB;
+      });
+    },
     // 澶勭悊缁熻绫诲瀷鍙樺寲
     handleStatisticalTypeChange(value) {
       if (value === 1) {
@@ -534,7 +738,7 @@
         serviceType: [2],
         dateRange: [],
         pageNum: 1,
-        pageSize: 20
+        pageSize: 20,
       };
       this.getList();
     },
@@ -554,7 +758,7 @@
 
     // 澶勭悊琛岄�夋嫨
     handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.id);
+      this.ids = selection.map((item) => item.id);
       this.single = selection.length !== 1;
       this.multiple = !selection.length;
     },
@@ -568,9 +772,9 @@
 
     // 鏍煎紡鍖栫櫨鍒嗘瘮
     formatPercent(value) {
-      if (value === null || value === undefined) return '-';
+      if (value === null || value === undefined) return "-";
       const num = parseFloat(value);
-      if (isNaN(num)) return '-';
+      if (isNaN(num)) return "-";
       return `${(num * 100).toFixed(2)}%`;
     },
 
@@ -583,17 +787,19 @@
     // 鏌ョ湅婊℃剰搴﹁鎯�
     async getinfo(row) {
       this.currentRow = row;
-      this.topicVisible = true;
 
       try {
         // 澶勭悊鏌ヨ鍙傛暟
         const params = {
           configKey: "joyCount",
-          ...this.queryParams
+          ...this.queryParams,
         };
 
         // 澶勭悊鏃ユ湡鑼冨洿
-        if (this.queryParams.dateRange && this.queryParams.dateRange.length === 2) {
+        if (
+          this.queryParams.dateRange &&
+          this.queryParams.dateRange.length === 2
+        ) {
           params.startTime = this.queryParams.dateRange[0];
           params.endTime = this.queryParams.dateRange[1];
         }
@@ -608,16 +814,18 @@
 
         const response = await getSfStatisticsJoyInfo(params);
         this.topiclist = response.data || [];
+      this.topicVisible = true;
+
       } catch (error) {
-        console.error('鑾峰彇婊℃剰搴﹁鎯呭け璐�:', error);
-        this.$message.error('鑾峰彇璇︽儏澶辫触');
+        console.error("鑾峰彇婊℃剰搴﹁鎯呭け璐�:", error);
+        this.$message.error("鑾峰彇璇︽儏澶辫触");
       }
     },
 
     // 瀵煎嚭鏁版嵁
     async handleExport() {
       if (!this.userList.length) {
-        this.$message.warning('娌℃湁鏁版嵁鍙鍑�');
+        this.$message.warning("娌℃湁鏁版嵁鍙鍑�");
         return;
       }
 
@@ -628,7 +836,10 @@
         let dateRangeString = "";
         let sheetNameSuffix = "";
 
-        if (this.queryParams.dateRange && this.queryParams.dateRange.length === 2) {
+        if (
+          this.queryParams.dateRange &&
+          this.queryParams.dateRange.length === 2
+        ) {
           const startDateFormatted = this.queryParams.dateRange[0];
           const endDateFormatted = this.queryParams.dateRange[1];
           dateRangeString = `${startDateFormatted}鑷�${endDateFormatted}`;
@@ -650,26 +861,34 @@
         // 瀹氫箟鏍峰紡
         const titleStyle = {
           font: { name: "寰蒋闆呴粦", size: 16, bold: true },
-          fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FFE6F3FF" } },
+          fill: {
+            type: "pattern",
+            pattern: "solid",
+            fgColor: { argb: "FFE6F3FF" },
+          },
           alignment: { vertical: "middle", horizontal: "center" },
           border: {
             top: { style: "thin", color: { argb: "FFD0D0D0" } },
             left: { style: "thin", color: { argb: "FFD0D0D0" } },
             bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
-            right: { style: "thin", color: { argb: "FFD0D0D0" } }
-          }
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
         };
 
         const headerStyle = {
           font: { name: "寰蒋闆呴粦", size: 11, bold: true },
-          fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FFF5F7FA" } },
+          fill: {
+            type: "pattern",
+            pattern: "solid",
+            fgColor: { argb: "FFF5F7FA" },
+          },
           alignment: { vertical: "middle", horizontal: "center" },
           border: {
             top: { style: "thin", color: { argb: "FFD0D0D0" } },
             left: { style: "thin", color: { argb: "FFD0D0D0" } },
             bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
-            right: { style: "thin", color: { argb: "FFD0D0D0" } }
-          }
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
         };
 
         const cellStyle = {
@@ -679,8 +898,8 @@
             top: { style: "thin", color: { argb: "FFD0D0D0" } },
             left: { style: "thin", color: { argb: "FFD0D0D0" } },
             bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
-            right: { style: "thin", color: { argb: "FFD0D0D0" } }
-          }
+            right: { style: "thin", color: { argb: "FFD0D0D0" } },
+          },
         };
 
         // 娣诲姞鎬绘爣棰�
@@ -700,7 +919,7 @@
           "鍙婃椂鐜�",
           "婊℃剰搴﹂鐩�婚噺",
           "婊℃剰搴﹀~鎶ラ噺",
-          "瀹屾垚姣旂巼"
+          "瀹屾垚姣旂巼",
         ];
 
         const headerRow = worksheet.addRow(headers);
@@ -712,7 +931,9 @@
         // 娣诲姞鏁版嵁琛�
         this.userList.forEach((item) => {
           const dataRow = worksheet.addRow([
-            this.queryParams.statisticaltype == 1 ? item.leavehospitaldistrictname : item.deptname,
+            this.queryParams.statisticaltype == 1
+              ? item.leavehospitaldistrictname
+              : item.deptname,
             item.dischargeCount || 0,
             item.nonFollowUp || 0,
             item.followUpNeeded || 0,
@@ -720,7 +941,7 @@
             item.rate ? this.formatPercent(item.rate) : "0%",
             item.joyAllCount || 0,
             item.joyCount || 0,
-            item.joyTotal ? this.formatPercent(item.joyTotal) : "0%"
+            item.joyTotal ? this.formatPercent(item.joyTotal) : "0%",
           ]);
 
           dataRow.eachCell((cell) => {
@@ -739,13 +960,13 @@
           { width: 12 },
           { width: 15 },
           { width: 15 },
-          { width: 12 }
+          { width: 12 },
         ];
 
         // 鐢熸垚骞朵笅杞芥枃浠�
         const buffer = await workbook.xlsx.writeBuffer();
         const blob = new Blob([buffer], {
-          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
         });
 
         saveAs(blob, excelName);
@@ -756,8 +977,8 @@
       } finally {
         this.loading = false;
       }
-    }
-  }
+    },
+  },
 };
 </script>
 

--
Gitblit v1.9.3