WXL (wul)
5 天以前 39c8b288ec8294e026459dfb1955f0bbc49ebb52
src/views/sfstatistics/percentage/components/CombinedFollowUp.vue
@@ -26,8 +26,19 @@
            >
              <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)">
                  <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>
@@ -35,108 +46,317 @@
              </el-table-column>
              <el-table-column label="医生姓名" prop="drname" align="center" />
              <el-table-column label="科室" prop="deptname" align="center" width="120" />
              <el-table-column
                label="科室"
                prop="deptname"
                align="center"
                width="120"
              />
              <!-- 基础列 -->
              <el-table-column label="出院人次" prop="dischargeCount" align="center">
              <el-table-column
                label="出院人次"
                prop="dischargeCount"
                align="center"
              >
                <template slot-scope="scope">
                  <el-button type="text" @click="handleViewDetails(scope.row, 'dischargeCountInfo', '出院患者列表', '1')">
                    <span class="button-zx">{{ scope.row.dischargeCount }}</span>
                  <el-button
                    type="text"
                    @click="
                      handleViewDetails(
                        scope.row,
                        'dischargeCountInfo',
                        '出院患者列表',
                        '1'
                      )
                    "
                  >
                    <span class="button-zx">{{
                      scope.row.dischargeCount
                    }}</span>
                  </el-button>
                </template>
              </el-table-column>
              <!-- 首次随访(医生) -->
              <el-table-column label="首次无需随访" prop="nonFollowUp" align="center">
              <el-table-column
                label="首次无需随访"
                prop="nonFollowUp"
                align="center"
              >
                <template slot-scope="scope">
                  <el-button type="text" @click="handleViewDetails(scope.row, 'nonFollowUpInfo', '首次无需随访列表', '1')">
                  <el-button
                    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="首次应随访" prop="followUpNeeded" align="center">
              <el-table-column
                label="首次应随访"
                prop="followUpNeeded"
                align="center"
              >
                <template slot-scope="scope">
                  <el-button type="text" @click="handleViewDetails(scope.row, 'followUpNeededInfo', '首次应随访列表', '1')">
                    <span class="button-zx">{{ scope.row.followUpNeeded }}</span>
                  <el-button
                    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 label="首次需随访" prop="needFollowUp" align="center">
              <el-table-column
                label="首次需随访"
                prop="needFollowUp"
                align="center"
              >
                <template slot-scope="scope">
                  <el-button type="text" @click="handleViewDetails(scope.row, 'needFollowUpInfo', '首次需随访列表', '1')">
                  <el-button
                    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="首次待随访" prop="pendingFollowUp" align="center">
              <el-table-column
                label="首次待随访"
                prop="pendingFollowUp"
                align="center"
              >
                <template slot-scope="scope">
                  <el-button type="text" @click="handleViewDetails(scope.row, 'pendingFollowUpInfo', '首次待随访列表', '1')">
                    <span class="button-zx">{{ scope.row.pendingFollowUp }}</span>
                  <el-button
                    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="首次完成" prop="followUpSuccess" align="center">
              <el-table-column
                label="首次完成"
                prop="followUpSuccess"
                align="center"
              >
                <template slot-scope="scope">
                  <el-button type="text" @click="handleViewDetails(scope.row, 'followUpSuccessInfo', '首次完成列表', '1')">
                    <span class="button-zx">{{ scope.row.followUpSuccess }}</span>
                  <el-button
                    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="首次失败" prop="followUpFail" align="center">
              <el-table-column
                label="首次失败"
                prop="followUpFail"
                align="center"
              >
                <template slot-scope="scope">
                  <el-button type="text" @click="handleViewDetails(scope.row, 'followUpFailInfo', '首次失败列表', '1')">
                  <el-button
                    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 v-if="orgname != '景宁畲族自治县人民医院'" label="首次成功率" prop="successRate" align="center" :render-header="Tooltipcgl">
              <el-table-column
                v-if="orgname != '景宁畲族自治县人民医院'"
                label="首次成功率"
                prop="successRate"
                align="center"
                :render-header="Tooltipcgl"
              >
                <template slot-scope="scope">
                  <span>{{ calculateSuccessRate(scope.row.followUpSuccess, scope.row.needFollowUp, scope.row.pendingFollowUp) }}</span>
                  <span>{{
                    calculateSuccessRate(
                      scope.row.followUpSuccess,
                      scope.row.needFollowUp,
                      scope.row.pendingFollowUp
                    )
                  }}</span>
                </template>
              </el-table-column>
              <!-- 再次随访(医生) -->
              <el-table-column label="再次需随访" prop="needFollowUpAgain" align="center">
              <el-table-column
                label="再次需随访"
                prop="needFollowUpAgain"
                align="center"
              >
                <template slot-scope="scope">
                  <el-button type="text" @click="handleViewDetails(scope.row, 'needFollowUpAgainInfo', '再次需随访列表', '1')">
                    <span class="button-zx">{{ scope.row.needFollowUpAgain }}</span>
                  <el-button
                    type="text"
                    @click="
                      handleViewDetails(
                        scope.row,
                        'needFollowUpAgainInfo',
                        '再次需随访列表',
                        '1'
                      )
                    "
                  >
                    <span class="button-zx">{{
                      scope.row.needFollowUpAgain
                    }}</span>
                  </el-button>
                </template>
              </el-table-column>
              <el-table-column label="再次待随访" prop="pendingFollowUpAgain" align="center">
              <el-table-column
                label="再次待随访"
                prop="pendingFollowUpAgain"
                align="center"
              >
                <template slot-scope="scope">
                  <el-button type="text" @click="handleViewDetails(scope.row, 'pendingFollowUpAgainInfo', '再次待随访列表', '1')">
                    <span class="button-zx">{{ scope.row.pendingFollowUpAgain }}</span>
                  <el-button
                    type="text"
                    @click="
                      handleViewDetails(
                        scope.row,
                        'pendingFollowUpAgainInfo',
                        '再次待随访列表',
                        '1'
                      )
                    "
                  >
                    <span class="button-zx">{{
                      scope.row.pendingFollowUpAgain
                    }}</span>
                  </el-button>
                </template>
              </el-table-column>
              <el-table-column label="再次完成" prop="followUpSuccessAgain" align="center">
              <el-table-column
                label="再次完成"
                prop="followUpSuccessAgain"
                align="center"
              >
                <template slot-scope="scope">
                  <el-button type="text" @click="handleViewDetails(scope.row, 'followUpSuccessAgainInfo', '再次完成列表', '1')">
                    <span class="button-zx">{{ scope.row.followUpSuccessAgain }}</span>
                  <el-button
                    type="text"
                    @click="
                      handleViewDetails(
                        scope.row,
                        'followUpSuccessAgainInfo',
                        '再次完成列表',
                        '1'
                      )
                    "
                  >
                    <span class="button-zx">{{
                      scope.row.followUpSuccessAgain
                    }}</span>
                  </el-button>
                </template>
              </el-table-column>
              <el-table-column label="再次失败" prop="followUpFailAgain" align="center">
              <el-table-column
                label="再次失败"
                prop="followUpFailAgain"
                align="center"
              >
                <template slot-scope="scope">
                  <el-button type="text" @click="handleViewDetails(scope.row, 'followUpFailAgainInfo', '再次失败列表', '1')">
                    <span class="button-zx">{{ scope.row.followUpFailAgain }}</span>
                  <el-button
                    type="text"
                    @click="
                      handleViewDetails(
                        scope.row,
                        'followUpFailAgainInfo',
                        '再次失败列表',
                        '1'
                      )
                    "
                  >
                    <span class="button-zx">{{
                      scope.row.followUpFailAgain
                    }}</span>
                  </el-button>
                </template>
              </el-table-column>
              <el-table-column v-if="orgname != '景宁畲族自治县人民医院'" label="再次成功率" prop="successRateAgain" align="center" :render-header="Tooltipcgl">
              <el-table-column
                v-if="orgname != '景宁畲族自治县人民医院'"
                label="再次成功率"
                prop="successRateAgain"
                align="center"
                :render-header="Tooltipcgl"
              >
                <template slot-scope="scope">
                  <span>{{ calculateSuccessRate(scope.row.followUpSuccessAgain, scope.row.needFollowUpAgain, scope.row.pendingFollowUpAgain) }}</span>
                  <span>{{
                    calculateSuccessRate(
                      scope.row.followUpSuccessAgain,
                      scope.row.needFollowUpAgain,
                      scope.row.pendingFollowUpAgain
                    )
                  }}</span>
                </template>
              </el-table-column>
              <!-- 新增计算指标(医生) -->
              <el-table-column label="随访率" align="center" prop="followUpRate" :render-header="TooltipFollowUpRate">
              <el-table-column
                label="随访率"
                align="center"
                prop="followUpRate"
                :render-header="TooltipFollowUpRate"
              >
                <template slot-scope="scope">
                  <span>{{ calculateFollowUpRate(scope.row) }}</span>
                </template>
              </el-table-column>
              <el-table-column label="推送率" align="center" prop="pushRate" :render-header="TooltipPushRate">
              <el-table-column
                label="推送率"
                align="center"
                prop="pushRate"
                :render-header="TooltipPushRate"
              >
                <template slot-scope="scope">
                  <span>{{ calculatePushRate(scope.row) }}</span>
                </template>
@@ -168,110 +388,280 @@
        <!-- 出院人次 -->
        <el-table-column label="出院人次" align="center" prop="dischargeCount">
          <template slot-scope="scope">
            <el-button type="text" @click="handleViewDetails(scope.row, 'dischargeCountInfo', '出院患者列表')">
            <el-button
              type="text"
              @click="
                handleViewDetails(
                  scope.row,
                  'dischargeCountInfo',
                  '出院患者列表'
                )
              "
            >
              <span class="button-zx">{{ scope.row.dischargeCount }}</span>
            </el-button>
          </template>
        </el-table-column>
             <el-table-column label="无需随访" align="center" prop="nonFollowUp">
            <template slot-scope="scope">
              <el-button type="text" @click="handleViewDetails(scope.row, 'nonFollowUpInfo', '首次无需随访列表')">
                <span class="button-zx">{{ scope.row.nonFollowUp }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="应随访" align="center" prop="followUpNeeded">
            <template slot-scope="scope">
              <el-button type="text" @click="handleViewDetails(scope.row, 'followUpNeededInfo', '首次应随访列表')">
                <span class="button-zx">{{ scope.row.followUpNeeded }}</span>
              </el-button>
            </template>
          </el-table-column>
        <el-table-column label="无需随访" align="center" prop="nonFollowUp">
          <template slot-scope="scope">
            <el-button
              type="text"
              @click="
                handleViewDetails(
                  scope.row,
                  'nonFollowUpInfo',
                  '首次无需随访列表'
                )
              "
            >
              <span class="button-zx">{{ scope.row.nonFollowUp }}</span>
            </el-button>
          </template>
        </el-table-column>
        <el-table-column label="应随访" align="center" prop="followUpNeeded">
          <template slot-scope="scope">
            <el-button
              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 label="需随访" align="center" prop="needFollowUp">
            <template slot-scope="scope">
              <el-button type="text" @click="handleViewDetails(scope.row, 'needFollowUpInfo', '首次需随访列表')">
              <el-button
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'needFollowUpInfo',
                    '首次需随访列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.needFollowUp }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="待随访" align="center" prop="pendingFollowUp">
            <template slot-scope="scope">
              <el-button type="text" @click="handleViewDetails(scope.row, 'pendingFollowUpInfo', '首次待随访列表')">
              <el-button
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'pendingFollowUpInfo',
                    '首次待随访列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.pendingFollowUp }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="完成" align="center" prop="followUpSuccess">
            <template slot-scope="scope">
              <el-button type="text" @click="handleViewDetails(scope.row, 'followUpSuccessInfo', '首次完成列表')">
              <el-button
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'followUpSuccessInfo',
                    '首次完成列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.followUpSuccess }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="失败" align="center" prop="followUpFail">
            <template slot-scope="scope">
              <el-button type="text" @click="handleViewDetails(scope.row, 'followUpFailInfo', '首次失败列表')">
              <el-button
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'followUpFailInfo',
                    '首次失败列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.followUpFail }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column v-if="orgname != '景宁畲族自治县人民医院'" label="成功率" align="center" prop="successRate" :render-header="Tooltipcgl">
          <el-table-column
            v-if="orgname != '景宁畲族自治县人民医院'"
            label="成功率"
            align="center"
            prop="successRate"
            :render-header="Tooltipcgl"
          >
            <template slot-scope="scope">
              <span>{{ calculateSuccessRate(scope.row.followUpSuccess, scope.row.needFollowUp, scope.row.pendingFollowUp) }}</span>
              <span>{{
                calculateSuccessRate(
                  scope.row.followUpSuccess,
                  scope.row.needFollowUp,
                  scope.row.pendingFollowUp
                )
              }}</span>
            </template>
          </el-table-column>
        </el-table-column>
        <!-- ===== 再次随访 ===== -->
        <el-table-column align="center" label="再次随访">
          <el-table-column label="需随访" align="center" prop="needFollowUpAgain">
          <el-table-column
            label="需随访"
            align="center"
            prop="needFollowUpAgain"
          >
            <template slot-scope="scope">
              <el-button type="text" @click="handleViewDetails(scope.row, 'needFollowUpAgainInfo', '再次需随访列表')">
              <el-button
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'needFollowUpAgainInfo',
                    '再次需随访列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.needFollowUpAgain }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="待随访" align="center" prop="pendingFollowUpAgain">
          <el-table-column
            label="待随访"
            align="center"
            prop="pendingFollowUpAgain"
          >
            <template slot-scope="scope">
              <el-button type="text" @click="handleViewDetails(scope.row, 'pendingFollowUpAgainInfo', '再次待随访列表')">
                <span class="button-zx">{{ scope.row.pendingFollowUpAgain }}</span>
              <el-button
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'pendingFollowUpAgainInfo',
                    '再次待随访列表'
                  )
                "
              >
                <span class="button-zx">{{
                  scope.row.pendingFollowUpAgain
                }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="完成" align="center" prop="followUpSuccessAgain">
          <el-table-column
            label="完成"
            align="center"
            prop="followUpSuccessAgain"
          >
            <template slot-scope="scope">
              <el-button type="text" @click="handleViewDetails(scope.row, 'followUpSuccessAgainInfo', '再次完成列表')">
                <span class="button-zx">{{ scope.row.followUpSuccessAgain }}</span>
              <el-button
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'followUpSuccessAgainInfo',
                    '再次完成列表'
                  )
                "
              >
                <span class="button-zx">{{
                  scope.row.followUpSuccessAgain
                }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="失败" align="center" prop="followUpFailAgain">
            <template slot-scope="scope">
              <el-button type="text" @click="handleViewDetails(scope.row, 'followUpFailAgainInfo', '再次失败列表')">
              <el-button
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'followUpFailAgainInfo',
                    '再次失败列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.followUpFailAgain }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column v-if="orgname != '景宁畲族自治县人民医院'" label="成功率" align="center" prop="successRateAgain" :render-header="Tooltipcgl">
          <el-table-column
            v-if="orgname != '景宁畲族自治县人民医院'"
            label="成功率"
            align="center"
            prop="successRateAgain"
            :render-header="Tooltipcgl"
          >
            <template slot-scope="scope">
              <span>{{ calculateSuccessRate(scope.row.followUpSuccessAgain, scope.row.needFollowUpAgain, scope.row.pendingFollowUpAgain) }}</span>
              <span>{{
                calculateSuccessRate(
                  scope.row.followUpSuccessAgain,
                  scope.row.needFollowUpAgain,
                  scope.row.pendingFollowUpAgain
                )
              }}</span>
            </template>
          </el-table-column>
        </el-table-column>
        <!-- ===== 新增计算指标 ===== -->
        <el-table-column label="随访率" align="center" prop="followUpRate" :render-header="TooltipFollowUpRate">
        <el-table-column
          label="随访率"
          align="center"
          prop="followUpRate"
          :render-header="TooltipFollowUpRate"
        >
          <template slot-scope="scope">
            <span>{{ calculateFollowUpRate(scope.row) }}</span>
          </template>
        </el-table-column>
        <el-table-column label="推送率" align="center" prop="pushRate" :render-header="TooltipPushRate">
        <el-table-column
          label="推送率"
          align="center"
          prop="pushRate"
          :render-header="TooltipPushRate"
        >
          <template slot-scope="scope">
            <span>{{ calculatePushRate(scope.row) }}</span>
          </template>
        </el-table-column>
        <el-table-column
          label="已拨通"
          align="center"
          prop="manuallyCalled"
          :render-header="TooltipPushRate"
        >
          <template slot-scope="scope">
            <el-button
              type="text"
              @click="
                handleViewDetails(
                  scope.row,
                  'manuallyCalledInfo',
                  '已拨通列表',
                  '1'
                )
              "
            >
              <span class="button-zx">{{ scope.row.manuallyCalled }}</span>
            </el-button>
          </template>
        </el-table-column>
      </el-table>
@@ -325,9 +715,10 @@
      const params = {
        ...this.queryParams,
        // 不传 visitCount,后端返回包含首次和再次的数据
        leavehospitaldistrictcodes: this.queryParams.leavehospitaldistrictcodes.includes("all")
          ? this.getAllWardCodes()
          : this.queryParams.leavehospitaldistrictcodes,
        leavehospitaldistrictcodes:
          this.queryParams.leavehospitaldistrictcodes.includes("all")
            ? this.getAllWardCodes()
            : this.queryParams.leavehospitaldistrictcodes,
        deptcodes: this.queryParams.deptcodes.includes("all")
          ? this.getAllDeptCodes()
          : this.queryParams.deptcodes,
@@ -351,20 +742,64 @@
    },
    getAllWardCodes() {
      return this.flatArrayhospit.filter((item) => item.value !== "all").map((item) => item.value);
      return this.flatArrayhospit
        .filter((item) => item.value !== "all")
        .map((item) => item.value);
    },
    getAllDeptCodes() {
      return this.flatArraydept.filter((item) => item.value !== "all").map((item) => item.value);
      return this.flatArraydept
        .filter((item) => item.value !== "all")
        .map((item) => item.value);
    },
    // ===================== 排序 =====================
    customSort(data) {
      const order = [
        "一", "二", "三", "四", "五", "六", "七", "八", "九", "十",
        "十一", "十二", "十三", "十四", "十五", "十六", "十七", "十八", "十九", "二十",
        "二十一", "二十二", "二十三", "二十四", "二十五", "二十六", "二十七", "二十八", "二十九", "三十",
        "三十一", "三十二", "三十三", "三十四", "三十五", "三十六", "三十七", "三十八", "三十九", "四十",
        "四十一", "四十二", "四十三", "四十四", "四十五",
        "一",
        "二",
        "三",
        "四",
        "五",
        "六",
        "七",
        "八",
        "九",
        "十",
        "十一",
        "十二",
        "十三",
        "十四",
        "十五",
        "十六",
        "十七",
        "十八",
        "十九",
        "二十",
        "二十一",
        "二十二",
        "二十三",
        "二十四",
        "二十五",
        "二十六",
        "二十七",
        "二十八",
        "二十九",
        "三十",
        "三十一",
        "三十二",
        "三十三",
        "三十四",
        "三十五",
        "三十六",
        "三十七",
        "三十八",
        "三十九",
        "四十",
        "四十一",
        "四十二",
        "四十三",
        "四十四",
        "四十五",
      ];
      return data.sort((a, b) => {
        const getIndex = (name) => {
@@ -383,7 +818,9 @@
        const indexA = getIndex(a.leavehospitaldistrictname);
        const indexB = getIndex(b.leavehospitaldistrictname);
        if (indexA === -1 && indexB === -1) {
          return (a.leavehospitaldistrictname || "").localeCompare(b.leavehospitaldistrictname || "");
          return (a.leavehospitaldistrictname || "").localeCompare(
            b.leavehospitaldistrictname || ""
          );
        }
        if (indexA === -1) return 1;
        if (indexB === -1) return -1;
@@ -396,22 +833,60 @@
      const a = aRow.leavehospitaldistrictname;
      const b = bRow.leavehospitaldistrictname;
      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,
        一: 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;
          return chineseNumMap[chineseNum] !== undefined
            ? chineseNumMap[chineseNum]
            : -1;
        }
        const arabicMatch = text.match(/^(\d+)/);
        if (arabicMatch && arabicMatch[1]) {
@@ -430,7 +905,9 @@
    // ===================== 行展开 =====================
    getRowKey(row) {
      return row.statisticaltype === 1 ? row.leavehospitaldistrictcode : row.deptcode;
      return row.statisticaltype === 1
        ? row.leavehospitaldistrictcode
        : row.deptcode;
    },
    handleRowClick(row) {
@@ -496,7 +973,7 @@
      const nonFollowUp = Number(row.nonFollowUp) || 0;
      const followUpNeeded = Number(row.followUpNeeded) || 0;
      const denominator = followUpNeeded + nonFollowUp;
      console.log(successAgain,nonFollowUp,followUpNeeded);
      console.log(successAgain, nonFollowUp, followUpNeeded);
      if (denominator <= 0) return "0.00%";
      return ((successAgain / denominator) * 100).toFixed(2) + "%";
@@ -522,13 +999,27 @@
          // 因为计算复杂,这里简化为 "-"
          sums[index] = "-";
        } else if (prop === "followUpRate") {
          const values = data.map((row) => parseFloat(this.calculateFollowUpRate(row).replace("%", ""))).filter(v => !isNaN(v));
          const values = data
            .map((row) =>
              parseFloat(this.calculateFollowUpRate(row).replace("%", ""))
            )
            .filter((v) => !isNaN(v));
          if (values.length === 0) sums[index] = "0.00%";
          else sums[index] = (values.reduce((a, b) => a + b, 0) / values.length).toFixed(2) + "%";
          else
            sums[index] =
              (values.reduce((a, b) => a + b, 0) / values.length).toFixed(2) +
              "%";
        } else if (prop === "pushRate") {
          const values = data.map((row) => parseFloat(this.calculatePushRate(row).replace("%", ""))).filter(v => !isNaN(v));
          const values = data
            .map((row) =>
              parseFloat(this.calculatePushRate(row).replace("%", ""))
            )
            .filter((v) => !isNaN(v));
          if (values.length === 0) sums[index] = "0.00%";
          else sums[index] = (values.reduce((a, b) => a + b, 0) / values.length).toFixed(2) + "%";
          else
            sums[index] =
              (values.reduce((a, b) => a + b, 0) / values.length).toFixed(2) +
              "%";
        } else {
          // 数字列求和
          const values = data.map((item) => Number(item[prop]) || 0);
@@ -556,11 +1047,25 @@
        if (prop === "successRate" || prop === "successRateAgain") {
          sums[index] = "-";
        } else if (prop === "followUpRate") {
          const values = data.map((row) => parseFloat(this.calculateFollowUpRate(row).replace("%", ""))).filter(v => !isNaN(v));
          sums[index] = values.length ? (values.reduce((a, b) => a + b, 0) / values.length).toFixed(2) + "%" : "0.00%";
          const values = data
            .map((row) =>
              parseFloat(this.calculateFollowUpRate(row).replace("%", ""))
            )
            .filter((v) => !isNaN(v));
          sums[index] = values.length
            ? (values.reduce((a, b) => a + b, 0) / values.length).toFixed(2) +
              "%"
            : "0.00%";
        } else if (prop === "pushRate") {
          const values = data.map((row) => parseFloat(this.calculatePushRate(row).replace("%", ""))).filter(v => !isNaN(v));
          sums[index] = values.length ? (values.reduce((a, b) => a + b, 0) / values.length).toFixed(2) + "%" : "0.00%";
          const values = data
            .map((row) =>
              parseFloat(this.calculatePushRate(row).replace("%", ""))
            )
            .filter((v) => !isNaN(v));
          sums[index] = values.length
            ? (values.reduce((a, b) => a + b, 0) / values.length).toFixed(2) +
              "%"
            : "0.00%";
        } else {
          const values = data.map((item) => Number(item[prop]) || 0);
          sums[index] = values.reduce((a, b) => a + b, 0);
@@ -577,7 +1082,9 @@
    // ===================== 点击钻取 =====================
    handleViewDetails(row, infoKey, titleSuffix, type) {
      const title = `${row.leavehospitaldistrictname || row.deptname}${titleSuffix}`;
      const title = `${
        row.leavehospitaldistrictname || row.deptname
      }${titleSuffix}`;
      this.$emit("view-details", row, infoKey, title, type);
    },
@@ -598,7 +1105,10 @@
      try {
        let dateRangeString = "";
        const isLishuiHospital = this.orgname === "丽水市中医院";
        if (this.queryParams.dateRange && this.queryParams.dateRange.length === 2) {
        if (
          this.queryParams.dateRange &&
          this.queryParams.dateRange.length === 2
        ) {
          const start = this.queryParams.dateRange[0];
          const end = this.queryParams.dateRange[1];
          if (isLishuiHospital) {
@@ -612,11 +1122,15 @@
          }
        } else {
          const now = new Date();
          dateRangeString = isLishuiHospital ? `${now.getFullYear()}年${now.getMonth() + 1}月` : `${now.getMonth() + 1}月`;
          dateRangeString = isLishuiHospital
            ? `${now.getFullYear()}年${now.getMonth() + 1}月`
            : `${now.getMonth() + 1}月`;
        }
        const serviceTypeLabel = this.getServiceTypeLabel();
        const serviceTypeSuffix = serviceTypeLabel ? `_${serviceTypeLabel}` : "";
        const serviceTypeSuffix = serviceTypeLabel
          ? `_${serviceTypeLabel}`
          : "";
        const excelName = `综合随访统计表${serviceTypeSuffix}_${dateRangeString}.xlsx`;
        if (!this.tableData || this.tableData.length === 0) {
          this.$message.warning("暂无数据可导出");
@@ -645,29 +1159,59 @@
      const titleStyle = {
        font: { name: "微软雅黑", size: 16, bold: true },
        alignment: { horizontal: "center", vertical: "middle" },
        fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FFE6F3FF" } },
        border: { top: { style: "thin" }, left: { style: "thin" }, bottom: { style: "thin" }, right: { style: "thin" } },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFE6F3FF" },
        },
        border: {
          top: { style: "thin" },
          left: { style: "thin" },
          bottom: { style: "thin" },
          right: { style: "thin" },
        },
      };
      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: { horizontal: "center", vertical: "middle", wrapText: true },
        border: { top: { style: "thin" }, left: { style: "thin" }, bottom: { style: "thin" }, right: { style: "thin" } },
        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" } },
        border: {
          top: { style: "thin" },
          left: { style: "thin" },
          bottom: { style: "thin" },
          right: { style: "thin" },
        },
      };
      const summaryStyle = {
        ...cellStyle,
        font: { ...cellStyle.font, bold: true, color: { argb: "FF409EFF" } },
        fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FFF5F7FA" } },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFF5F7FA" },
        },
      };
      // 标题行
      worksheet.mergeCells(1, 1, 1, 20);
      worksheet.getCell(1, 1).value = `综合随访统计表${serviceTypeSuffix}_${dateRangeString}`;
      worksheet.getCell(
        1,
        1
      ).value = `综合随访统计表${serviceTypeSuffix}_${dateRangeString}`;
      worksheet.getCell(1, 1).style = titleStyle;
      worksheet.getRow(1).height = 35;
@@ -679,7 +1223,8 @@
      // 病区/科室
      worksheet.mergeCells(2, 2, 3, 2);
      worksheet.getCell(2, 2).value = this.queryParams.statisticaltype == 1 ? "出院病区" : "科室";
      worksheet.getCell(2, 2).value =
        this.queryParams.statisticaltype == 1 ? "出院病区" : "科室";
      worksheet.getCell(2, 2).style = headerStyle;
      // 出院人次
@@ -691,7 +1236,15 @@
      worksheet.mergeCells(2, 4, 2, 10);
      worksheet.getCell(2, 4).value = "首次随访";
      worksheet.getCell(2, 4).style = headerStyle;
      const firstCols = ["无需随访", "应随访", "需随访", "待随访", "完成", "失败", "成功率"];
      const firstCols = [
        "无需随访",
        "应随访",
        "需随访",
        "待随访",
        "完成",
        "失败",
        "成功率",
      ];
      firstCols.forEach((label, idx) => {
        const col = 4 + idx;
        worksheet.getCell(3, col).value = label;
@@ -729,66 +1282,144 @@
          item.pendingFollowUp || 0,
          item.followUpSuccess || 0,
          item.followUpFail || 0,
          this.calculateSuccessRate(item.followUpSuccess, item.needFollowUp, item.pendingFollowUp),
          this.calculateSuccessRate(
            item.followUpSuccess,
            item.needFollowUp,
            item.pendingFollowUp
          ),
          item.needFollowUpAgain || 0,
          item.pendingFollowUpAgain || 0,
          item.followUpSuccessAgain || 0,
          item.followUpFailAgain || 0,
          this.calculateSuccessRate(item.followUpSuccessAgain, item.needFollowUpAgain, item.pendingFollowUpAgain),
          this.calculateSuccessRate(
            item.followUpSuccessAgain,
            item.needFollowUpAgain,
            item.pendingFollowUpAgain
          ),
          this.calculateFollowUpRate(item),
          this.calculatePushRate(item),
        ];
        const row = worksheet.addRow(rowData);
        row.eachCell((cell) => { cell.style = cellStyle; });
        row.eachCell((cell) => {
          cell.style = cellStyle;
        });
        row.height = 24;
      });
      // 合计行
      const summaries = this.getExportSummaries();
      const summaryRow = worksheet.addRow(summaries);
      summaryRow.eachCell((cell) => { cell.style = summaryStyle; });
      summaryRow.eachCell((cell) => {
        cell.style = summaryStyle;
      });
      // 列宽
      worksheet.columns = [
        { width: 8 },
        { width: 20 },
        { width: 12 },
        { width: 12 }, { width: 12 }, { width: 12 }, { width: 12 }, { width: 12 }, { width: 12 }, { width: 12 },
        { width: 12 }, { width: 12 }, { width: 12 }, { width: 12 }, { width: 12 },
        { width: 12 }, { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
      ];
    },
    getExportSummaries() {
      // 提取数据,计算合计行
      const data = this.tableData;
      const sums = ["合计", "/", 0, 0, 0, 0, 0, 0, 0, "0%", 0, 0, 0, 0, "0%", "0%", "0%"];
      const sums = [
        "合计",
        "/",
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        "0%",
        0,
        0,
        0,
        0,
        "0%",
        "0%",
        "0%",
      ];
      // 数字列索引
      const numIndices = [2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13];
      data.forEach(row => {
        numIndices.forEach(idx => {
      data.forEach((row) => {
        numIndices.forEach((idx) => {
          const val = Number(row[this.getFieldByIndex(idx)]) || 0;
          sums[idx] += val;
        });
      });
      // 格式化数字
      numIndices.forEach(idx => { sums[idx] = this.formatNumber(sums[idx]); });
      numIndices.forEach((idx) => {
        sums[idx] = this.formatNumber(sums[idx]);
      });
      // 计算两个百分比列的平均值
      const followUpRates = data.map(row => parseFloat(this.calculateFollowUpRate(row).replace("%", ""))).filter(v => !isNaN(v));
      const pushRates = data.map(row => parseFloat(this.calculatePushRate(row).replace("%", ""))).filter(v => !isNaN(v));
      sums[15] = followUpRates.length ? (followUpRates.reduce((a,b)=>a+b,0)/followUpRates.length).toFixed(2)+"%" : "0.00%";
      sums[16] = pushRates.length ? (pushRates.reduce((a,b)=>a+b,0)/pushRates.length).toFixed(2)+"%" : "0.00%";
      const followUpRates = data
        .map((row) =>
          parseFloat(this.calculateFollowUpRate(row).replace("%", ""))
        )
        .filter((v) => !isNaN(v));
      const pushRates = data
        .map((row) => parseFloat(this.calculatePushRate(row).replace("%", "")))
        .filter((v) => !isNaN(v));
      sums[15] = followUpRates.length
        ? (
            followUpRates.reduce((a, b) => a + b, 0) / followUpRates.length
          ).toFixed(2) + "%"
        : "0.00%";
      sums[16] = pushRates.length
        ? (pushRates.reduce((a, b) => a + b, 0) / pushRates.length).toFixed(2) +
          "%"
        : "0.00%";
      // 成功率的合计用整体法计算
      const totalSuccess = data.reduce((s, row) => s + (Number(row.followUpSuccess)||0), 0);
      const totalNeed = data.reduce((s, row) => s + (Number(row.needFollowUp)||0), 0);
      const totalPending = data.reduce((s, row) => s + (Number(row.pendingFollowUp)||0), 0);
      const totalSuccess = data.reduce(
        (s, row) => s + (Number(row.followUpSuccess) || 0),
        0
      );
      const totalNeed = data.reduce(
        (s, row) => s + (Number(row.needFollowUp) || 0),
        0
      );
      const totalPending = data.reduce(
        (s, row) => s + (Number(row.pendingFollowUp) || 0),
        0
      );
      const denom = totalNeed - totalPending;
      sums[9] = denom > 0 ? ((totalSuccess/denom)*100).toFixed(2)+"%" : "0.00%";
      const totalSuccessAgain = data.reduce((s, row) => s + (Number(row.followUpSuccessAgain)||0), 0);
      const totalNeedAgain = data.reduce((s, row) => s + (Number(row.needFollowUpAgain)||0), 0);
      const totalPendingAgain = data.reduce((s, row) => s + (Number(row.pendingFollowUpAgain)||0), 0);
      sums[9] =
        denom > 0 ? ((totalSuccess / denom) * 100).toFixed(2) + "%" : "0.00%";
      const totalSuccessAgain = data.reduce(
        (s, row) => s + (Number(row.followUpSuccessAgain) || 0),
        0
      );
      const totalNeedAgain = data.reduce(
        (s, row) => s + (Number(row.needFollowUpAgain) || 0),
        0
      );
      const totalPendingAgain = data.reduce(
        (s, row) => s + (Number(row.pendingFollowUpAgain) || 0),
        0
      );
      const denomAgain = totalNeedAgain - totalPendingAgain;
      sums[14] = denomAgain > 0 ? ((totalSuccessAgain/denomAgain)*100).toFixed(2)+"%" : "0.00%";
      sums[14] =
        denomAgain > 0
          ? ((totalSuccessAgain / denomAgain) * 100).toFixed(2) + "%"
          : "0.00%";
      return sums;
    },
@@ -813,9 +1444,13 @@
    // ===================== 导出医生子表 =====================
    async exportDoctorTable(row) {
      try {
        const areaName = row.leavehospitaldistrictname || row.deptname || "未知病区";
        const areaName =
          row.leavehospitaldistrictname || row.deptname || "未知病区";
        let dateRangeString = "";
        if (this.queryParams.dateRange && this.queryParams.dateRange.length === 2) {
        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}`;
@@ -832,7 +1467,12 @@
        const worksheet = workbook.addWorksheet(sheetName);
        this.buildDoctorExportSheet(worksheet, row.doctorStats, areaName);
        const buffer = await workbook.xlsx.writeBuffer();
        saveAs(new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), fileName);
        saveAs(
          new Blob([buffer], {
            type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
          }),
          fileName
        );
        this.$message.success("医生综合随访列表导出成功");
      } catch (err) {
        console.error(err);
@@ -841,19 +1481,39 @@
    },
    buildDoctorExportSheet(worksheet, data, areaName) {
      const titleStyle = { font: { name: "微软雅黑", size: 16, bold: true }, alignment: { horizontal: "center", vertical: "middle" } };
      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" } },
        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" } },
        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" } },
        border: {
          top: { style: "thin" },
          left: { style: "thin" },
          bottom: { style: "thin" },
          right: { style: "thin" },
        },
      };
      const summaryStyle = { ...cellStyle, font: { ...cellStyle.font, bold: true } };
      const summaryStyle = {
        ...cellStyle,
        font: { ...cellStyle.font, bold: true },
      };
      worksheet.mergeCells(1, 1, 1, 17);
      worksheet.getCell(1, 1).value = `${areaName}医生综合随访列表`;
@@ -861,16 +1521,31 @@
      worksheet.getRow(1).height = 30;
      const headers = [
        "医生姓名", "科室", "出院人次",
        "首次无需随访", "首次应随访", "首次需随访", "首次待随访", "首次完成", "首次失败", "首次成功率",
        "再次需随访", "再次待随访", "再次完成", "再次失败", "再次成功率",
        "随访率", "推送率"
        "医生姓名",
        "科室",
        "出院人次",
        "首次无需随访",
        "首次应随访",
        "首次需随访",
        "首次待随访",
        "首次完成",
        "首次失败",
        "首次成功率",
        "再次需随访",
        "再次待随访",
        "再次完成",
        "再次失败",
        "再次成功率",
        "随访率",
        "推送率",
      ];
      const headerRow = worksheet.addRow(headers);
      headerRow.eachCell((cell) => { cell.style = headerStyle; });
      headerRow.eachCell((cell) => {
        cell.style = headerStyle;
      });
      worksheet.getRow(2).height = 25;
      data.forEach(item => {
      data.forEach((item) => {
        const row = worksheet.addRow([
          item.drname,
          item.deptname,
@@ -881,22 +1556,34 @@
          item.pendingFollowUp,
          item.followUpSuccess,
          item.followUpFail,
          this.calculateSuccessRate(item.followUpSuccess, item.needFollowUp, item.pendingFollowUp),
          this.calculateSuccessRate(
            item.followUpSuccess,
            item.needFollowUp,
            item.pendingFollowUp
          ),
          item.needFollowUpAgain,
          item.pendingFollowUpAgain,
          item.followUpSuccessAgain,
          item.followUpFailAgain,
          this.calculateSuccessRate(item.followUpSuccessAgain, item.needFollowUpAgain, item.pendingFollowUpAgain),
          this.calculateSuccessRate(
            item.followUpSuccessAgain,
            item.needFollowUpAgain,
            item.pendingFollowUpAgain
          ),
          this.calculateFollowUpRate(item),
          this.calculatePushRate(item),
        ]);
        row.eachCell((cell) => { cell.style = cellStyle; });
        row.eachCell((cell) => {
          cell.style = cellStyle;
        });
        row.height = 24;
      });
      // 小计
      const summaryRow = worksheet.addRow(this.getDoctorExportSummary(data));
      summaryRow.eachCell((cell) => { cell.style = summaryStyle; });
      summaryRow.eachCell((cell) => {
        cell.style = summaryStyle;
      });
      worksheet.columns = Array(17).fill({ width: 12 });
      worksheet.columns[0].width = 15;
@@ -904,49 +1591,128 @@
    },
    getDoctorExportSummary(data) {
      const sums = ["小计", "-", 0, 0, 0, 0, 0, 0, 0, "0%", 0, 0, 0, 0, "0%", "0%", "0%"];
      const sums = [
        "小计",
        "-",
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        "0%",
        0,
        0,
        0,
        0,
        "0%",
        "0%",
        "0%",
      ];
      const numIndices = [2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13];
      data.forEach(row => {
        numIndices.forEach(idx => {
      data.forEach((row) => {
        numIndices.forEach((idx) => {
          const val = Number(row[this.getFieldByIndex(idx)]) || 0;
          sums[idx] += val;
        });
      });
      numIndices.forEach(idx => { sums[idx] = this.formatNumber(sums[idx]); });
      numIndices.forEach((idx) => {
        sums[idx] = this.formatNumber(sums[idx]);
      });
      // 平均值
      const followUpRates = data.map(row => parseFloat(this.calculateFollowUpRate(row).replace("%", ""))).filter(v => !isNaN(v));
      const pushRates = data.map(row => parseFloat(this.calculatePushRate(row).replace("%", ""))).filter(v => !isNaN(v));
      sums[15] = followUpRates.length ? (followUpRates.reduce((a,b)=>a+b,0)/followUpRates.length).toFixed(2)+"%" : "0.00%";
      sums[16] = pushRates.length ? (pushRates.reduce((a,b)=>a+b,0)/pushRates.length).toFixed(2)+"%" : "0.00%";
      const followUpRates = data
        .map((row) =>
          parseFloat(this.calculateFollowUpRate(row).replace("%", ""))
        )
        .filter((v) => !isNaN(v));
      const pushRates = data
        .map((row) => parseFloat(this.calculatePushRate(row).replace("%", "")))
        .filter((v) => !isNaN(v));
      sums[15] = followUpRates.length
        ? (
            followUpRates.reduce((a, b) => a + b, 0) / followUpRates.length
          ).toFixed(2) + "%"
        : "0.00%";
      sums[16] = pushRates.length
        ? (pushRates.reduce((a, b) => a + b, 0) / pushRates.length).toFixed(2) +
          "%"
        : "0.00%";
      // 成功率整体法
      const totalSuccess = data.reduce((s, row) => s + (Number(row.followUpSuccess)||0), 0);
      const totalNeed = data.reduce((s, row) => s + (Number(row.needFollowUp)||0), 0);
      const totalPending = data.reduce((s, row) => s + (Number(row.pendingFollowUp)||0), 0);
      const totalSuccess = data.reduce(
        (s, row) => s + (Number(row.followUpSuccess) || 0),
        0
      );
      const totalNeed = data.reduce(
        (s, row) => s + (Number(row.needFollowUp) || 0),
        0
      );
      const totalPending = data.reduce(
        (s, row) => s + (Number(row.pendingFollowUp) || 0),
        0
      );
      const denom = totalNeed - totalPending;
      sums[9] = denom > 0 ? ((totalSuccess/denom)*100).toFixed(2)+"%" : "0.00%";
      const totalSuccessAgain = data.reduce((s, row) => s + (Number(row.followUpSuccessAgain)||0), 0);
      const totalNeedAgain = data.reduce((s, row) => s + (Number(row.needFollowUpAgain)||0), 0);
      const totalPendingAgain = data.reduce((s, row) => s + (Number(row.pendingFollowUpAgain)||0), 0);
      sums[9] =
        denom > 0 ? ((totalSuccess / denom) * 100).toFixed(2) + "%" : "0.00%";
      const totalSuccessAgain = data.reduce(
        (s, row) => s + (Number(row.followUpSuccessAgain) || 0),
        0
      );
      const totalNeedAgain = data.reduce(
        (s, row) => s + (Number(row.needFollowUpAgain) || 0),
        0
      );
      const totalPendingAgain = data.reduce(
        (s, row) => s + (Number(row.pendingFollowUpAgain) || 0),
        0
      );
      const denomAgain = totalNeedAgain - totalPendingAgain;
      sums[14] = denomAgain > 0 ? ((totalSuccessAgain/denomAgain)*100).toFixed(2)+"%" : "0.00%";
      sums[14] =
        denomAgain > 0
          ? ((totalSuccessAgain / denomAgain) * 100).toFixed(2) + "%"
          : "0.00%";
      return sums;
    },
    // ===================== Tooltips =====================
    Tooltipcgl(h, { column }) {
      return h("el-tooltip", {
        props: { content: "随访成功/(需随访-待随访)", placement: "top", effect: "dark" },
      }, [h("span", column.label)]);
      return h(
        "el-tooltip",
        {
          props: {
            content: "随访成功/(需随访-待随访)",
            placement: "top",
            effect: "dark",
          },
        },
        [h("span", column.label)]
      );
    },
    TooltipFollowUpRate(h, { column }) {
      return h("el-tooltip", {
        props: { content: "(首次完成+首次无需随访)/(首次应随访+首次无需随访)", placement: "top", effect: "dark" },
      }, [h("span", column.label)]);
      return h(
        "el-tooltip",
        {
          props: {
            content: "(首次完成+首次无需随访)/(首次应随访+首次无需随访)",
            placement: "top",
            effect: "dark",
          },
        },
        [h("span", column.label)]
      );
    },
    TooltipPushRate(h, { column }) {
      return h("el-tooltip", {
        props: { content: "再次完成/(首次应随访+首次无需随访)", placement: "top", effect: "dark" },
      }, [h("span", column.label)]);
      return h(
        "el-tooltip",
        {
          props: {
            content: "再次完成/(首次应随访+首次无需随访)",
            placement: "top",
            effect: "dark",
          },
        },
        [h("span", column.label)]
      );
    },
  },
};