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

---
 src/views/sfstatistics/percentage/components/FirstFollowUp.vue |  782 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 704 insertions(+), 78 deletions(-)

diff --git a/src/views/sfstatistics/percentage/components/FirstFollowUp.vue b/src/views/sfstatistics/percentage/components/FirstFollowUp.vue
index 922ff51..b463732 100644
--- a/src/views/sfstatistics/percentage/components/FirstFollowUp.vue
+++ b/src/views/sfstatistics/percentage/components/FirstFollowUp.vue
@@ -25,6 +25,26 @@
               show-summary
               :summary-method="getInnerSummaries"
             >
+              <el-table-column label="" align="center" width="96" fixed="left">
+                <template slot="header">
+                  <div
+                    style="
+                      display: flex;
+                      justify-content: space-between;
+                      align-items: center;
+                    "
+                  >
+                    <el-button
+                      type="primary"
+                      size="mini"
+                      icon="el-icon-download"
+                      @click="exportDoctorTable(props.row)"
+                    >
+                      瀵煎嚭
+                    </el-button>
+                  </div>
+                </template>
+              </el-table-column>
               <el-table-column label="鍖荤敓濮撳悕" prop="drname" align="center" />
               <el-table-column
                 label="绉戝"
@@ -32,31 +52,82 @@
                 prop="deptname"
                 align="center"
               />
-              <el-table-column
-                label="鍑洪櫌浜烘"
-                prop="dischargeCount"
-                align="center"
-              />
+
               <el-table-column
                 label="鍑洪櫌浜烘"
                 align="center"
                 key="dischargeCount"
                 prop="dischargeCount"
-              />
+              >
+                <template slot-scope="scope">
+                  <el-button
+                    size="medium"
+                    type="text"
+                    @click="
+                      handleViewDetails(
+                        scope.row,
+                        'dischargeCountInfo',
+                        '鍑洪櫌鎮h�呭垪琛�',
+                        '1'
+                      )
+                    "
+                  >
+                    <span class="button-zx">{{
+                      scope.row.dischargeCount
+                    }}</span>
+                  </el-button>
+                </template>
+              </el-table-column>
               <el-table-column
                 label="鏃犻渶闅忚浜烘"
                 align="center"
                 width="100"
                 key="nonFollowUp"
                 prop="nonFollowUp"
-              />
+              >
+                <template slot-scope="scope">
+                  <el-button
+                    size="medium"
+                    type="text"
+                    @click="
+                      handleViewDetails(
+                        scope.row,
+                        'nonFollowUpInfo',
+                        '鏃犻渶闅忚鍒楄〃',
+                        '1'
+                      )
+                    "
+                  >
+                    <span class="button-zx">{{ scope.row.nonFollowUp }}</span>
+                  </el-button>
+                </template>
+              </el-table-column>
               <el-table-column
                 label="搴旈殢璁夸汉娆�"
                 align="center"
                 width="100"
                 key="followUpNeeded"
                 prop="followUpNeeded"
-              />
+              >
+                <template slot-scope="scope">
+                  <el-button
+                    size="medium"
+                    type="text"
+                    @click="
+                      handleViewDetails(
+                        scope.row,
+                        'followUpNeededInfo',
+                        '搴旈殢璁垮垪琛�',
+                        '1'
+                      )
+                    "
+                  >
+                    <span class="button-zx">{{
+                      scope.row.followUpNeeded
+                    }}</span>
+                  </el-button>
+                </template>
+              </el-table-column>
 
               <el-table-column align="center" label="棣栨鍑洪櫌闅忚">
                 <el-table-column
@@ -64,25 +135,118 @@
                   align="center"
                   key="needFollowUp"
                   prop="needFollowUp"
-                />
+                >
+                  <template slot-scope="scope">
+                    <el-button
+                      size="medium"
+                      type="text"
+                      @click="
+                        handleViewDetails(
+                          scope.row,
+                          'needFollowUpInfo',
+                          '闇�闅忚鍒楄〃',
+                          '1'
+                        )
+                      "
+                    >
+                      <span class="button-zx">{{
+                        scope.row.needFollowUp
+                      }}</span>
+                    </el-button>
+                  </template>
+                </el-table-column>
                 <el-table-column
                   label="寰呴殢璁�"
                   align="center"
                   key="pendingFollowUp"
                   prop="pendingFollowUp"
-                />
+                >
+                  <template slot-scope="scope">
+                    <el-button
+                      size="medium"
+                      type="text"
+                      @click="
+                        handleViewDetails(
+                          scope.row,
+                          'pendingFollowUpInfo',
+                          '寰呴殢璁垮垪琛�',
+                          '1'
+                        )
+                      "
+                    >
+                      <span class="button-zx">{{
+                        scope.row.pendingFollowUp
+                      }}</span>
+                    </el-button>
+                  </template>
+                </el-table-column>
                 <el-table-column
                   label="闅忚鎴愬姛"
                   align="center"
                   key="followUpSuccess"
                   prop="followUpSuccess"
-                />
+                >
+                  <template slot-scope="scope">
+                    <el-button
+                      size="medium"
+                      type="text"
+                      @click="
+                        handleViewDetails(
+                          scope.row,
+                          'followUpSuccessInfo',
+                          '闅忚鎴愬姛鍒楄〃',
+                          '1'
+                        )
+                      "
+                    >
+                      <span class="button-zx">{{
+                        scope.row.followUpSuccess
+                      }}</span>
+                    </el-button>
+                  </template>
+                </el-table-column>
                 <el-table-column
                   label="闅忚澶辫触"
                   align="center"
                   key="followUpFail"
                   prop="followUpFail"
-                />
+                >
+                  <template slot-scope="scope">
+                    <el-button
+                      size="medium"
+                      type="text"
+                      @click="
+                        handleViewDetails(
+                          scope.row,
+                          'followUpFailInfo',
+                          '闅忚澶辫触鍒楄〃',
+                          '1'
+                        )
+                      "
+                    >
+                      <span class="button-zx">{{
+                        scope.row.followUpFail
+                      }}</span>
+                    </el-button>
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  label="鎴愬姛鐜�"
+                  align="center"
+                  width="120"
+                  key="successRate"
+                  prop="successRate"
+                >
+                  <template slot-scope="scope">
+                    <span class="success-rate">{{
+                      calculateSuccessRate(
+                        scope.row.followUpSuccess,
+                        scope.row.needFollowUp,
+                        scope.row.pendingFollowUp
+                      )
+                    }}</span>
+                  </template>
+                </el-table-column>
                 <el-table-column
                   label="闅忚鐜�"
                   align="center"
@@ -111,26 +275,101 @@
                   </template>
                 </el-table-column>
                 <el-table-column
-                 v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
+                  v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
                   label="浜哄伐"
                   align="center"
                   key="manual"
                   prop="manual"
-                />
+                >
+                  <template slot-scope="scope">
+                    <el-button
+                      size="medium"
+                      type="text"
+                      @click="
+                        handleViewDetails(
+                          scope.row,
+                          'manualInfo',
+                          '浜哄伐闅忚鍒楄〃',
+                          '1'
+                        )
+                      "
+                    >
+                      <span class="button-zx">{{ scope.row.manual }}</span>
+                    </el-button>
+                  </template>
+                </el-table-column>
                 <el-table-column
-                 v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
+                  v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
+                  label="璇煶"
+                  align="center"
+                  key="voice"
+                  prop="voice"
+                >
+                  <template slot-scope="scope">
+                    <el-button
+                      size="medium"
+                      type="text"
+                      @click="
+                        handleViewDetails(
+                          scope.row,
+                          'voiceInfo',
+                          '璇煶闅忚鍒楄〃',
+                          '1'
+                        )
+                      "
+                    >
+                      <span class="button-zx">{{ scope.row.voice }}</span>
+                    </el-button>
+                  </template>
+                </el-table-column>
+                <el-table-column
+                  v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
                   label="鐭俊"
                   align="center"
                   key="sms"
                   prop="sms"
-                />
+                >
+                  <template slot-scope="scope">
+                    <el-button
+                      size="medium"
+                      type="text"
+                      @click="
+                        handleViewDetails(
+                          scope.row,
+                          'smsInfo',
+                          '鐭俊闅忚鍒楄〃',
+                          '1'
+                        )
+                      "
+                    >
+                      <span class="button-zx">{{ scope.row.sms }}</span>
+                    </el-button>
+                  </template>
+                </el-table-column>
                 <el-table-column
-                 v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
+                  v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
                   label="寰俊"
                   align="center"
                   key="weChat"
                   prop="weChat"
-                />
+                >
+                  <template slot-scope="scope">
+                    <el-button
+                      size="medium"
+                      type="text"
+                      @click="
+                        handleViewDetails(
+                          scope.row,
+                          'weChatInfo',
+                          '寰俊闅忚鍒楄〃',
+                          '1'
+                        )
+                      "
+                    >
+                      <span class="button-zx">{{ scope.row.weChat }}</span>
+                    </el-button>
+                  </template>
+                </el-table-column>
               </el-table-column>
             </el-table>
           </template>
@@ -138,6 +377,7 @@
 
         <!-- 琛ㄦ牸鍒楀畾涔� -->
         <el-table-column
+          v-if="queryParams.statisticaltype == 1"
           label="鍑洪櫌鐥呭尯"
           align="center"
           sortable
@@ -148,6 +388,7 @@
           :sort-method="sortChineseNumber"
         />
         <el-table-column
+          v-if="queryParams.statisticaltype == 2"
           label="绉戝"
           align="center"
           key="deptname"
@@ -159,21 +400,61 @@
           align="center"
           key="dischargeCount"
           prop="dischargeCount"
-        />
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="
+                handleViewDetails(
+                  scope.row,
+                  'dischargeCountInfo',
+                  '鍑洪櫌鎮h�呭垪琛�'
+                )
+              "
+            >
+              <span class="button-zx">{{ scope.row.dischargeCount }}</span>
+            </el-button>
+          </template>
+        </el-table-column>
         <el-table-column
           label="鏃犻渶闅忚浜烘"
           align="center"
           width="100"
           key="nonFollowUp"
           prop="nonFollowUp"
-        />
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="
+                handleViewDetails(scope.row, 'nonFollowUpInfo', '鏃犻渶闅忚鍒楄〃')
+              "
+            >
+              <span class="button-zx">{{ scope.row.nonFollowUp }}</span>
+            </el-button>
+          </template>
+        </el-table-column>
         <el-table-column
           label="搴旈殢璁夸汉娆�"
           align="center"
           width="100"
           key="followUpNeeded"
           prop="followUpNeeded"
-        />
+        >
+          <template slot-scope="scope">
+            <el-button
+              size="medium"
+              type="text"
+              @click="
+                handleViewDetails(scope.row, 'followUpNeededInfo', '搴旈殢璁垮垪琛�')
+              "
+            >
+              <span class="button-zx">{{ scope.row.followUpNeeded }}</span>
+            </el-button>
+          </template>
+        </el-table-column>
 
         <el-table-column align="center" label="棣栨鍑洪櫌闅忚">
           <el-table-column
@@ -261,6 +542,23 @@
             </template>
           </el-table-column>
           <el-table-column
+            label="鎴愬姛鐜�"
+            align="center"
+            width="120"
+            key="successRate"
+            prop="successRate"
+          >
+            <template slot-scope="scope">
+              <span class="success-rate">{{
+                calculateSuccessRate(
+                  scope.row.followUpSuccess,
+                  scope.row.needFollowUp,
+                  scope.row.pendingFollowUp
+                )
+              }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column
             label="闅忚鐜�"
             align="center"
             width="120"
@@ -288,7 +586,7 @@
             </template>
           </el-table-column>
           <el-table-column
-          v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
+            v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
             label="浜哄伐"
             align="center"
             key="manual"
@@ -306,7 +604,32 @@
               </el-button>
             </template>
           </el-table-column>
-          <el-table-column v-if="orgname != '涓芥按甯備腑鍖婚櫌'" label="鐭俊" align="center" key="sms" prop="sms">
+          <el-table-column
+            v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
+            label="璇煶"
+            align="center"
+            key="voice"
+            prop="voice"
+          >
+            <template slot-scope="scope">
+              <el-button
+                size="medium"
+                type="text"
+                @click="
+                  handleViewDetails(scope.row, 'voiceInfo', '璇煶闅忚鍒楄〃')
+                "
+              >
+                <span class="button-zx">{{ scope.row.voice }}</span>
+              </el-button>
+            </template>
+          </el-table-column>
+          <el-table-column
+            v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
+            label="鐭俊"
+            align="center"
+            key="sms"
+            prop="sms"
+          >
             <template slot-scope="scope">
               <el-button
                 size="medium"
@@ -318,7 +641,7 @@
             </template>
           </el-table-column>
           <el-table-column
-          v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
+            v-if="orgname != '涓芥按甯備腑鍖婚櫌'"
             label="寰俊"
             align="center"
             key="weChat"
@@ -340,7 +663,9 @@
 
         <!-- 闅忚鎯呭喌鍒楋紙浠呬附姘村競涓尰闄㈡樉绀猴級 -->
         <el-table-column
-          v-if="orgname == '涓芥按甯備腑鍖婚櫌'"
+          v-if="
+            orgname == '涓芥按甯備腑鍖婚櫌' || orgname == '鏅畞鐣叉棌鑷不鍘夸汉姘戝尰闄�'
+          "
           align="center"
           label="闅忚鎯呭喌"
         >
@@ -393,6 +718,8 @@
 </template>
 
 <script>
+import { getSfStatisticsHyperlink } from "@/api/AiCentre/index";
+
 import { getSfStatistics, selectTimelyRate } from "@/api/system/user";
 import ExcelJS from "exceljs";
 import { saveAs } from "file-saver";
@@ -447,7 +774,7 @@
 
       delete params.leavehospitaldistrictcodes.all;
       delete params.deptcodes.all;
-
+      params.rateDay = 7;
       getSfStatistics(params)
         .then((response) => {
           this.tableData = this.customSort(response.data);
@@ -660,6 +987,8 @@
 
       if (!row.doctorStats) {
         this.loading = true;
+        params.rateDay = 7;
+
         getSfStatistics(params).then((res) => {
           this.$set(row, "doctorStats", res.data);
           this.expands = [this.getRowKey(row)];
@@ -669,7 +998,23 @@
         this.expands = [this.getRowKey(row)];
       }
     },
+    // 璁$畻鎴愬姛鐜囩殑鏂规硶
+    calculateSuccessRate(followUpSuccess, needFollowUp, pendingFollowUp) {
+      const success = Number(followUpSuccess) || 0;
+      const need = Number(needFollowUp) || 0;
+      const pending = Number(pendingFollowUp) || 0;
 
+      // 鍒嗘瘝 = 闇�闅忚 - 寰呴殢璁�
+      const denominator = need - pending;
+
+      if (denominator <= 0) {
+        return "0.00%";
+      }
+
+      const rate = (success / denominator) * 100;
+      return rate.toFixed(2) + "%";
+    },
+    // 鍦ㄧ粺璁℃眹鎬绘柟娉曚腑澶勭悊鎴愬姛鐜�
     getSummaries(param) {
       const { columns, data } = param;
       const sums = [];
@@ -679,12 +1024,36 @@
           sums[index] = "鍚堣";
           return;
         }
-        if (index === 1 || index === 2) {
+        if (index === 1) {
           sums[index] = "/";
           return;
         }
 
-        if (column.property === "followUpRate" || column.property === "rate") {
+        if (column.property === "successRate") {
+          // 鎴愬姛鐜囬渶瑕侀噸鏂拌绠楁�荤殑鎴愬姛鐜囷紝鑰屼笉鏄钩鍧囧��
+          const totalSuccess = data.reduce((sum, item) => {
+            return sum + (Number(item.followUpSuccess) || 0);
+          }, 0);
+
+          const totalNeed = data.reduce((sum, item) => {
+            return sum + (Number(item.needFollowUp) || 0);
+          }, 0);
+
+          const totalPending = data.reduce((sum, item) => {
+            return sum + (Number(item.pendingFollowUp) || 0);
+          }, 0);
+
+          const denominator = totalNeed - totalPending;
+
+          if (denominator > 0) {
+            sums[index] = ((totalSuccess / denominator) * 100).toFixed(2) + "%";
+          } else {
+            sums[index] = "0.00%";
+          }
+        } else if (
+          column.property === "followUpRate" ||
+          column.property === "rate"
+        ) {
           const percentageValues = data
             .map((item) => {
               const value = item[column.property];
@@ -741,7 +1110,31 @@
           return;
         }
 
-        if (column.property === "followUpRate" || column.property === "rate") {
+        if (column.property === "successRate") {
+          // 鎴愬姛鐜囬渶瑕侀噸鏂拌绠楁�荤殑鎴愬姛鐜囷紝鑰屼笉鏄钩鍧囧��
+          const totalSuccess = data.reduce((sum, item) => {
+            return sum + (Number(item.followUpSuccess) || 0);
+          }, 0);
+
+          const totalNeed = data.reduce((sum, item) => {
+            return sum + (Number(item.needFollowUp) || 0);
+          }, 0);
+
+          const totalPending = data.reduce((sum, item) => {
+            return sum + (Number(item.pendingFollowUp) || 0);
+          }, 0);
+
+          const denominator = totalNeed - totalPending;
+
+          if (denominator > 0) {
+            sums[index] = ((totalSuccess / denominator) * 100).toFixed(2) + "%";
+          } else {
+            sums[index] = "0.00%";
+          }
+        } else if (
+          column.property === "followUpRate" ||
+          column.property === "rate"
+        ) {
           const percentageValues = data
             .map((item) => {
               const value = item[column.property];
@@ -792,17 +1185,17 @@
       this.ids = selection.map((item) => item.tagid);
     },
 
-    handleViewDetails(row, infoKey, titleSuffix) {
+    handleViewDetails(row, infoKey, titleSuffix, type) {
       const title = `${
         row.leavehospitaldistrictname || row.deptname
       }${titleSuffix}`;
-      this.$emit("view-details", row[infoKey], title);
+      this.$emit("view-details", row, infoKey, title, type);
     },
 
     handleSeeDetails(row) {
       this.$emit("see-details", row);
     },
-
+    // 涓昏〃瀵煎嚭
     async exportTable() {
       try {
         let dateRangeString = "";
@@ -856,7 +1249,219 @@
         return false;
       }
     },
+    // 瀛愯〃瀵煎嚭
+    /** 瀵煎嚭鍖荤敓瀛愯〃 */
+    async exportDoctorTable(row) {
+      try {
+        const areaName =
+          row.leavehospitaldistrictname || row.deptname || "鏈煡鐥呭尯";
 
+        let dateRangeString = "";
+        if (
+          this.queryParams.dateRange &&
+          this.queryParams.dateRange.length === 2
+        ) {
+          const start = this.queryParams.dateRange[0].split(" ")[0];
+          const end = this.queryParams.dateRange[1].split(" ")[0];
+          dateRangeString = `${start}鑷�${end}`;
+        } else {
+          dateRangeString = `${new Date().getMonth() + 1}鏈坄;
+        }
+
+        const fileName = `${areaName}鍖荤敓闅忚鍒楄〃_${dateRangeString}.xlsx`;
+        const sheetName = `${areaName}鍖荤敓闅忚`;
+
+        if (!row.doctorStats || row.doctorStats.length === 0) {
+          this.$message.warning("褰撳墠鐥呭尯鏆傛棤鍖荤敓闅忚鏁版嵁");
+          return;
+        }
+
+        const workbook = new ExcelJS.Workbook();
+        const worksheet = workbook.addWorksheet(sheetName);
+        console.log(111);
+
+        this.buildDoctorExportSheet(worksheet, row.doctorStats, areaName);
+        console.log(222);
+
+        const buffer = await workbook.xlsx.writeBuffer();
+        saveAs(
+          new Blob([buffer], {
+            type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+          }),
+          fileName
+        );
+
+        this.$message.success("鍖荤敓闅忚鍒楄〃瀵煎嚭鎴愬姛");
+      } catch (err) {
+        console.error(err);
+        this.$message.error("瀵煎嚭澶辫触");
+      }
+    },
+    buildDoctorExportSheet(worksheet, data, areaName) {
+      const titleStyle = {
+        font: { name: "寰蒋闆呴粦", size: 16, bold: true },
+        alignment: { horizontal: "center", vertical: "middle" },
+      };
+
+      const headerStyle = {
+        font: { name: "寰蒋闆呴粦", size: 11, bold: true },
+        fill: {
+          type: "pattern",
+          pattern: "solid",
+          fgColor: { argb: "FFF5F7FA" },
+        },
+        alignment: { horizontal: "center", vertical: "middle", wrapText: true },
+        border: {
+          top: { style: "thin" },
+          left: { style: "thin" },
+          bottom: { style: "thin" },
+          right: { style: "thin" },
+        },
+      };
+
+      const cellStyle = {
+        font: { name: "瀹嬩綋", size: 10 },
+        alignment: { horizontal: "center", vertical: "middle" },
+        border: {
+          top: { style: "thin" },
+          left: { style: "thin" },
+          bottom: { style: "thin" },
+          right: { style: "thin" },
+        },
+      };
+
+      // 鏍囬
+      worksheet.mergeCells(1, 1, 1, 10);
+      worksheet.getCell(1, 1).value = `${areaName}鍖荤敓闅忚鍒楄〃`;
+      worksheet.getCell(1, 1).style = titleStyle;
+      worksheet.getRow(1).height = 30;
+
+      // 琛ㄥご
+      const headers = [
+        "鍖荤敓濮撳悕",
+        "绉戝",
+        "鍑洪櫌浜烘",
+        "鏃犻渶闅忚",
+        "搴旈殢璁�",
+        "闇�闅忚",
+        "寰呴殢璁�",
+        "闅忚鎴愬姛",
+        "闅忚澶辫触",
+        "鎴愬姛鐜�", // 鏂板
+        "闅忚鐜�", // 鍘熸潵鍦ㄦ垚鍔熺巼浣嶇疆
+      ];
+
+      const headerRow = worksheet.addRow(headers);
+      headerRow.eachCell((cell) => {
+        cell.style = headerStyle;
+      });
+      worksheet.getRow(2).height = 25;
+
+      // 鏁版嵁
+      data.forEach((item) => {
+        const row = worksheet.addRow([
+          item.drname,
+          item.deptname,
+          item.dischargeCount,
+          item.nonFollowUp,
+          item.followUpNeeded,
+          item.needFollowUp,
+          item.pendingFollowUp,
+          item.followUpSuccess,
+          item.followUpFail,
+          this.calculateSuccessRate(
+            item.followUpSuccess,
+            item.needFollowUp,
+            item.pendingFollowUp
+          ),
+          item.followUpRate,
+        ]);
+        row.eachCell((cell) => {
+          cell.style = cellStyle;
+        });
+      });
+
+      // 灏忚琛�
+      const summaryRow = worksheet.addRow(this.getDoctorExportSummary(data));
+      summaryRow.eachCell((cell) => {
+        cell.font = { bold: true };
+        cell.fill = {
+          type: "pattern",
+          pattern: "solid",
+          fgColor: { argb: "FFF5F7FA" },
+        };
+      });
+
+      // 鍒楀
+      worksheet.columns = [
+        { width: 15 },
+        { width: 15 },
+        { width: 12 },
+        { width: 12 },
+        { width: 12 },
+        { width: 12 },
+        { width: 12 },
+        { width: 12 },
+        { width: 12 },
+        { width: 12 }, // 鎴愬姛鐜�
+        { width: 12 }, // 闅忚鐜�
+      ];
+    },
+    getDoctorExportSummary(data) {
+      const sums = ["灏忚"];
+
+      const keys = [
+        "dischargeCount",
+        "nonFollowUp",
+        "followUpNeeded",
+        "needFollowUp",
+        "pendingFollowUp",
+        "followUpSuccess",
+        "followUpFail",
+      ];
+
+      keys.forEach((key) => {
+        sums.push(data.reduce((t, r) => t + (Number(r[key]) || 0), 0));
+      });
+
+      // 鎴愬姛鐜囷紙骞冲潎鍊硷級
+      const successRates = data
+        .map((item) => {
+          const success = Number(item.followUpSuccess) || 0;
+          const need = Number(item.needFollowUp) || 0;
+          const pending = Number(item.pendingFollowUp) || 0;
+          const denominator = need - pending;
+          if (denominator <= 0) return 0;
+          return success / denominator;
+        })
+        .filter((rate) => !isNaN(rate));
+
+      sums.push(
+        successRates.length
+          ? (
+              (successRates.reduce((a, b) => a + b, 0) / successRates.length) *
+              100
+            ).toFixed(2) + "%"
+          : "0.00%"
+      );
+
+      // 闅忚鐜囷紙骞冲潎鍊硷級
+      const followUpRates = data
+        .map((i) => this.extractPercentageValue(i.followUpRate))
+        .filter(Boolean);
+
+      sums.push(
+        followUpRates.length
+          ? (
+              (followUpRates.reduce((a, b) => a + b, 0) /
+                followUpRates.length) *
+              100
+            ).toFixed(2) + "%"
+          : "0.00%"
+      );
+
+      return sums;
+    },
     buildExportSheet(worksheet, sheetNameSuffix) {
       const titleStyle = {
         font: {
@@ -951,11 +1556,13 @@
         "寰呴殢璁�",
         "闅忚鎴愬姛",
         "闅忚澶辫触",
-        "闅忚鐜�",
-        "鍙婃椂鐜�",
+        "鎴愬姛鐜�", // 鏂板
+        "闅忚鐜�", // 鍘熶綅缃悗绉�
+        "鍙婃椂鐜�", // 鍙婃椂鐜囧悗绉�
         "浜哄伐",
-        "鐭俊",
-        "寰俊",
+        "璇煶", // 淇锛氬簲璇ユ槸璇煶
+        "鐭俊", // 鐭俊
+        "寰俊", // 寰俊
       ];
 
       secondRowHeaders.forEach((header, index) => {
@@ -978,7 +1585,7 @@
       worksheet.getCell(2, 5).value = "鏃犻渶闅忚浜烘";
       worksheet.getCell(2, 6).value = "搴旈殢璁夸汉娆�";
 
-      worksheet.mergeCells(2, 7, 2, 15);
+      worksheet.mergeCells(2, 7, 2, 16); // 浠�7鍚堝苟鍒�16锛堝師鏉ユ槸7-15锛�
       worksheet.getCell(2, 7).value = "棣栨鍑洪櫌闅忚";
       worksheet.getCell(2, 7).style = headerStyle;
 
@@ -999,15 +1606,21 @@
             item.pendingFollowUp || 0,
             item.followUpSuccess || 0,
             item.followUpFail || 0,
-            item.followUpRate || "0%",
-            item.rate ? (Number(item.rate) * 100).toFixed(2) + "%" : "0%",
+            // 鎴愬姛鐜� - 闇�瑕佸姩鎬佽绠�
+            this.calculateSuccessRate(
+              item.followUpSuccess,
+              item.needFollowUp,
+              item.pendingFollowUp
+            ),
+            item.followUpRate || "0%", // 闅忚鐜�
+            item.rate ? (Number(item.rate) * 100).toFixed(2) + "%" : "0%", // 鍙婃椂鐜�
             item.manual || 0,
-            item.sms || 0,
-            item.weChat || 0,
+            item.voice || 0, // 璇煶
+            item.sms || 0, // 鐭俊
+            item.weChat || 0, // 寰俊
           ],
           rowIndex + 4
         );
-
         dataRow.eachCell((cell) => {
           cell.style = cellStyle;
         });
@@ -1037,11 +1650,13 @@
         { width: 10 },
         { width: 10 },
         { width: 10 },
-        { width: 12 },
-        { width: 12 },
-        { width: 8 },
-        { width: 8 },
-        { width: 8 },
+        { width: 12 }, // 鎴愬姛鐜�
+        { width: 12 }, // 闅忚鐜�
+        { width: 12 }, // 鍙婃椂鐜�
+        { width: 8 }, // 浜哄伐
+        { width: 8 }, // 璇煶
+        { width: 8 }, // 鐭俊
+        { width: 8 }, // 寰俊
       ];
     },
 
@@ -1050,18 +1665,20 @@
         "鍚堣",
         "/",
         "/",
-        0,
-        0,
-        0,
-        0,
-        0,
-        0,
-        0,
-        "0%",
-        "0%",
-        0,
-        0,
-        0,
+        0, // 3: dischargeCount
+        0, // 4: nonFollowUp
+        0, // 5: followUpNeeded
+        0, // 6: needFollowUp
+        0, // 7: pendingFollowUp
+        0, // 8: followUpSuccess
+        0, // 9: followUpFail
+        "0%", // 10: 鎴愬姛鐜�
+        "0%", // 11: 闅忚鐜�
+        "0%", // 12: 鍙婃椂鐜�
+        0, // 13: manual
+        0, // 14: voice
+        0, // 15: sms
+        0, // 16: weChat
       ];
 
       this.tableData.forEach((item) => {
@@ -1072,42 +1689,51 @@
         summaries[7] += Number(item.pendingFollowUp) || 0;
         summaries[8] += Number(item.followUpSuccess) || 0;
         summaries[9] += Number(item.followUpFail) || 0;
-        summaries[12] += Number(item.manual) || 0;
-        summaries[13] += Number(item.sms) || 0;
-        summaries[14] += Number(item.weChat) || 0;
+        summaries[13] += Number(item.manual) || 0;
+        summaries[14] += Number(item.voice) || 0;
+        summaries[15] += Number(item.sms) || 0;
+        summaries[16] += Number(item.weChat) || 0;
       });
 
+      // 鎴愬姛鐜囪绠�
+      const totalSuccess = summaries[8]; // followUpSuccess鐨勬�诲拰
+      const totalNeed = summaries[6]; // needFollowUp鐨勬�诲拰
+      const totalPending = summaries[7]; // pendingFollowUp鐨勬�诲拰
+      const denominator = totalNeed - totalPending;
+
+      if (denominator > 0) {
+        summaries[10] = ((totalSuccess / denominator) * 100).toFixed(2) + "%";
+      } else {
+        summaries[10] = "0.00%";
+      }
+
+      // 闅忚鐜囪绠�
       const followUpRateValues = this.tableData
         .map((item) => this.extractPercentageValue(item.followUpRate))
-        .filter((value) => value !== null);
-
-      const rateValues = this.tableData
-        .map((item) => this.extractPercentageValue(item.rate))
         .filter((value) => value !== null);
 
       if (followUpRateValues.length > 0) {
         const avgFollowUpRate =
           followUpRateValues.reduce((sum, val) => sum + val, 0) /
           followUpRateValues.length;
-        summaries[10] = (avgFollowUpRate * 100).toFixed(2) + "%";
+        summaries[11] = (avgFollowUpRate * 100).toFixed(2) + "%";
       }
+
+      // 鍙婃椂鐜囪绠�
+      const rateValues = this.tableData
+        .map((item) => this.extractPercentageValue(item.rate))
+        .filter((value) => value !== null);
 
       if (rateValues.length > 0) {
         const avgRate =
           rateValues.reduce((sum, val) => sum + val, 0) / rateValues.length;
-        summaries[11] = (avgRate * 100).toFixed(2) + "%";
+        summaries[12] = (avgRate * 100).toFixed(2) + "%";
       }
 
-      summaries[3] = this.formatNumber(summaries[3]);
-      summaries[4] = this.formatNumber(summaries[4]);
-      summaries[5] = this.formatNumber(summaries[5]);
-      summaries[6] = this.formatNumber(summaries[6]);
-      summaries[7] = this.formatNumber(summaries[7]);
-      summaries[8] = this.formatNumber(summaries[8]);
-      summaries[9] = this.formatNumber(summaries[9]);
-      summaries[12] = this.formatNumber(summaries[12]);
-      summaries[13] = this.formatNumber(summaries[13]);
-      summaries[14] = this.formatNumber(summaries[14]);
+      // 鏍煎紡鍖栨暟瀛�
+      [3, 4, 5, 6, 7, 8, 9, 13, 14, 15, 16].forEach((index) => {
+        summaries[index] = this.formatNumber(summaries[index]);
+      });
 
       return summaries;
     },

--
Gitblit v1.9.3