WXL (wul)
昨天 acac65122fbac5295e4b7c8eed468e9b9181e366
src/views/sfstatistics/percentage/components/FirstFollowUp.vue
@@ -26,28 +26,108 @@
              :summary-method="getInnerSummaries"
            >
              <el-table-column label="医生姓名" prop="drname" align="center" />
              <el-table-column label="科室" width="120" prop="deptname" align="center" />
              <el-table-column label="出院人次" prop="dischargeCount" align="center" />
              <el-table-column label="出院人次" align="center" key="dischargeCount" prop="dischargeCount" />
              <el-table-column label="无需随访人次" align="center" width="100" key="nonFollowUp" prop="nonFollowUp" />
              <el-table-column label="应随访人次" align="center" width="100" key="followUpNeeded" prop="followUpNeeded" />
              <el-table-column
                label="科室"
                width="120"
                prop="deptname"
                align="center"
              />
              <el-table-column
                label="出院人次"
                prop="dischargeCount"
                align="center"
              />
              <el-table-column
                label="出院人次"
                align="center"
                key="dischargeCount"
                prop="dischargeCount"
              />
              <el-table-column
                label="无需随访人次"
                align="center"
                width="100"
                key="nonFollowUp"
                prop="nonFollowUp"
              />
              <el-table-column
                label="应随访人次"
                align="center"
                width="100"
                key="followUpNeeded"
                prop="followUpNeeded"
              />
              <el-table-column align="center" label="首次出院随访">
                <el-table-column label="需随访" align="center" key="needFollowUp" prop="needFollowUp" />
                <el-table-column label="待随访" align="center" key="pendingFollowUp" prop="pendingFollowUp" />
                <el-table-column label="随访成功" align="center" key="followUpSuccess" prop="followUpSuccess" />
                <el-table-column label="随访失败" align="center" key="followUpFail" prop="followUpFail" />
                <el-table-column label="随访率" align="center" width="120" key="followUpRate" prop="followUpRate" />
                <el-table-column v-if="orgname != '丽水市中医院'" label="及时率" align="center" width="120" key="rate" prop="rate">
                <el-table-column
                  label="需随访"
                  align="center"
                  key="needFollowUp"
                  prop="needFollowUp"
                />
                <el-table-column
                  label="待随访"
                  align="center"
                  key="pendingFollowUp"
                  prop="pendingFollowUp"
                />
                <el-table-column
                  label="随访成功"
                  align="center"
                  key="followUpSuccess"
                  prop="followUpSuccess"
                />
                <el-table-column
                  label="随访失败"
                  align="center"
                  key="followUpFail"
                  prop="followUpFail"
                />
                <el-table-column
                  label="随访率"
                  align="center"
                  width="120"
                  key="followUpRate"
                  prop="followUpRate"
                />
                <el-table-column
                  v-if="orgname != '丽水市中医院'"
                  label="及时率"
                  align="center"
                  width="120"
                  key="rate"
                  prop="rate"
                >
                  <template slot-scope="scope">
                    <el-button size="medium" type="text" @click="handleSeeDetails(scope.row)">
                      <span class="button-zx">{{ (Number(scope.row.rate) * 100).toFixed(2) }}%</span>
                    <el-button
                      size="medium"
                      type="text"
                      @click="handleSeeDetails(scope.row)"
                    >
                      <span class="button-zx"
                        >{{ (Number(scope.row.rate) * 100).toFixed(2) }}%</span
                      >
                    </el-button>
                  </template>
                </el-table-column>
                <el-table-column label="人工" align="center" key="manual" prop="manual" />
                <el-table-column label="短信" align="center" key="sms" prop="sms" />
                <el-table-column label="微信" align="center" key="weChat" prop="weChat" />
                <el-table-column
                  label="人工"
                  align="center"
                  key="manual"
                  prop="manual"
                />
                <el-table-column
                  label="短信"
                  align="center"
                  key="sms"
                  prop="sms"
                />
                <el-table-column
                  label="微信"
                  align="center"
                  key="weChat"
                  prop="weChat"
                />
              </el-table-column>
            </el-table>
          </template>
@@ -64,65 +144,189 @@
          :show-overflow-tooltip="true"
          :sort-method="sortChineseNumber"
        />
        <el-table-column label="科室" align="center" key="deptname" prop="deptname" :show-overflow-tooltip="true" />
        <el-table-column label="出院人次" align="center" key="dischargeCount" prop="dischargeCount" />
        <el-table-column label="无需随访人次" align="center" width="100" key="nonFollowUp" prop="nonFollowUp" />
        <el-table-column label="应随访人次" align="center" width="100" key="followUpNeeded" prop="followUpNeeded" />
        <el-table-column
          label="科室"
          align="center"
          key="deptname"
          prop="deptname"
          :show-overflow-tooltip="true"
        />
        <el-table-column
          label="出院人次"
          align="center"
          key="dischargeCount"
          prop="dischargeCount"
        />
        <el-table-column
          label="无需随访人次"
          align="center"
          width="100"
          key="nonFollowUp"
          prop="nonFollowUp"
        />
        <el-table-column
          label="应随访人次"
          align="center"
          width="100"
          key="followUpNeeded"
          prop="followUpNeeded"
        />
        <el-table-column align="center" label="首次出院随访">
          <el-table-column label="需随访" align="center" key="needFollowUp" prop="needFollowUp">
          <el-table-column
            label="需随访"
            align="center"
            key="needFollowUp"
            prop="needFollowUp"
          >
            <template slot-scope="scope">
              <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'needFollowUpInfo', '需随访列表')">
              <el-button
                size="medium"
                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" key="pendingFollowUp" prop="pendingFollowUp">
          <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', '待随访列表')">
              <el-button
                size="medium"
                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" key="followUpSuccess" prop="followUpSuccess">
          <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', '随访成功列表')">
              <el-button
                size="medium"
                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" key="followUpFail" prop="followUpFail">
          <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', '随访失败列表')">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(
                    scope.row,
                    'followUpFailInfo',
                    '随访失败列表'
                  )
                "
              >
                <span class="button-zx">{{ scope.row.followUpFail }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="随访率" align="center" width="120" key="followUpRate" prop="followUpRate" />
          <el-table-column v-if="orgname != '丽水市中医院'" label="及时率" align="center" width="120" key="rate" prop="rate">
          <el-table-column
            label="随访率"
            align="center"
            width="120"
            key="followUpRate"
            prop="followUpRate"
          />
          <el-table-column
            v-if="orgname != '丽水市中医院'"
            label="及时率"
            align="center"
            width="120"
            key="rate"
            prop="rate"
          >
            <template slot-scope="scope">
              <el-button size="medium" type="text" @click="handleSeeDetails(scope.row)">
                <span class="button-zx">{{ (Number(scope.row.rate) * 100).toFixed(2) }}%</span>
              <el-button
                size="medium"
                type="text"
                @click="handleSeeDetails(scope.row)"
              >
                <span class="button-zx"
                  >{{ (Number(scope.row.rate) * 100).toFixed(2) }}%</span
                >
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="人工" align="center" key="manual" prop="manual">
          <el-table-column
            label="人工"
            align="center"
            key="manual"
            prop="manual"
          >
            <template slot-scope="scope">
              <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'manualInfo', '人工随访列表')">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(scope.row, 'manualInfo', '人工随访列表')
                "
              >
                <span class="button-zx">{{ scope.row.manual }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="短信" align="center" key="sms" prop="sms">
            <template slot-scope="scope">
              <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'smsInfo', '短信随访列表')">
              <el-button
                size="medium"
                type="text"
                @click="handleViewDetails(scope.row, 'smsInfo', '短信随访列表')"
              >
                <span class="button-zx">{{ scope.row.sms }}</span>
              </el-button>
            </template>
          </el-table-column>
          <el-table-column label="微信" align="center" key="weChat" prop="weChat">
          <el-table-column
            label="微信"
            align="center"
            key="weChat"
            prop="weChat"
          >
            <template slot-scope="scope">
              <el-button size="medium" type="text" @click="handleViewDetails(scope.row, 'weChatInfo', '微信随访列表')">
              <el-button
                size="medium"
                type="text"
                @click="
                  handleViewDetails(scope.row, 'weChatInfo', '微信随访列表')
                "
              >
                <span class="button-zx">{{ scope.row.weChat }}</span>
              </el-button>
            </template>
@@ -130,13 +334,53 @@
        </el-table-column>
        <!-- 随访情况列(仅丽水市中医院显示) -->
        <el-table-column v-if="orgname == '丽水市中医院'" align="center" label="随访情况">
          <el-table-column label="正常语音" align="center" width="100" key="taskSituation1" prop="taskSituation1" />
          <el-table-column label="患者拒接或拒访" align="center" width="100" key="taskSituation2" prop="taskSituation2" />
          <el-table-column label="面访或者接诊" align="center" width="100" key="taskSituation3" prop="taskSituation3" />
          <el-table-column label="微信随访" align="center" width="100" key="taskSituation4" prop="taskSituation4" />
          <el-table-column label="随访电话不正确" align="center" width="100" key="taskSituation5" prop="taskSituation5" />
          <el-table-column label="其他情况不宜随访" align="center" width="100" key="taskSituation6" prop="taskSituation6" />
        <el-table-column
          v-if="orgname == '丽水市中医院'"
          align="center"
          label="随访情况"
        >
          <el-table-column
            label="正常语音"
            align="center"
            width="100"
            key="taskSituation1"
            prop="taskSituation1"
          />
          <el-table-column
            label="患者拒接或拒访"
            align="center"
            width="100"
            key="taskSituation2"
            prop="taskSituation2"
          />
          <el-table-column
            label="面访或者接诊"
            align="center"
            width="100"
            key="taskSituation3"
            prop="taskSituation3"
          />
          <el-table-column
            label="微信随访"
            align="center"
            width="100"
            key="taskSituation4"
            prop="taskSituation4"
          />
          <el-table-column
            label="随访电话不正确"
            align="center"
            width="100"
            key="taskSituation5"
            prop="taskSituation5"
          />
          <el-table-column
            label="其他情况不宜随访"
            align="center"
            width="100"
            key="taskSituation6"
            prop="taskSituation6"
          />
        </el-table-column>
      </el-table>
    </div>
@@ -149,163 +393,251 @@
import { saveAs } from "file-saver";
export default {
  name: 'FirstFollowUp',
  name: "FirstFollowUp",
  props: {
    queryParams: {
      type: Object,
      required: true
      required: true,
    },
    flatArrayhospit: {
      type: Array,
      default: () => []
      default: () => [],
    },
    flatArraydept: {
      type: Array,
      default: () => []
      default: () => [],
    },
    options: {
      type: Array,
      default: () => []
      default: () => [],
    },
    orgname: {
      type: String,
      default: ''
    }
      default: "",
    },
  },
  data() {
    return {
      tableData: [],
      loading: false,
      expands: [],
      ids: []
    }
      ids: [],
      patientqueryParams: { pn: 1, ps: 10 },
    };
  },
  methods: {
    loadData() {
      this.loading = true
      this.loading = true;
      const params = {
        ...this.queryParams,
        visitCount: 1,
        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
      }
          : this.queryParams.deptcodes,
      };
      delete params.leavehospitaldistrictcodes.all
      delete params.deptcodes.all
      delete params.leavehospitaldistrictcodes.all;
      delete params.deptcodes.all;
      getSfStatistics(params)
        .then(response => {
          this.tableData = this.customSort(response.data)
        .then((response) => {
          this.tableData = this.customSort(response.data);
        })
        .catch(error => {
          console.error("获取首次随访数据失败:", error)
          this.$message.error("获取首次随访数据失败")
        .catch((error) => {
          console.error("获取首次随访数据失败:", error);
          this.$message.error("获取首次随访数据失败");
        })
        .finally(() => {
          this.loading = false
        })
          this.loading = false;
        });
    },
    getAllWardCodes() {
      return this.flatArrayhospit
        .filter(item => item.value !== 'all')
        .map(item => item.value)
        .filter((item) => item.value !== "all")
        .map((item) => item.value);
    },
    getAllDeptCodes() {
      return this.flatArraydept
        .filter(item => item.value !== 'all')
        .map(item => item.value)
        .filter((item) => item.value !== "all")
        .map((item) => item.value);
    },
    customSort(data) {
      const order = [
        "一","二","三","四","五","六","七","八","九","十",
        "十一","十二","十三","十四","十五","十六","十七","十八","十九","二十",
        "二十一","二十二","二十三","二十四","二十五","二十六","二十七","二十八","二十九","三十",
        "三十一","三十二","三十三","三十四","三十五","三十六","三十七","三十八","三十九","四十",
        "四十一","四十二","四十三","四十四","四十五"
      ]
        "一",
        "二",
        "三",
        "四",
        "五",
        "六",
        "七",
        "八",
        "九",
        "十",
        "十一",
        "十二",
        "十三",
        "十四",
        "十五",
        "十六",
        "十七",
        "十八",
        "十九",
        "二十",
        "二十一",
        "二十二",
        "二十三",
        "二十四",
        "二十五",
        "二十六",
        "二十七",
        "二十八",
        "二十九",
        "三十",
        "三十一",
        "三十二",
        "三十三",
        "三十四",
        "三十五",
        "三十六",
        "三十七",
        "三十八",
        "三十九",
        "四十",
        "四十一",
        "四十二",
        "四十三",
        "四十四",
        "四十五",
      ];
      return data.sort((a, b) => {
        const getIndex = (name) => {
          if (!name || typeof name !== "string") return -1
          const chineseMatch = name.match(/^([一二三四五六七八九十]+)/)
          if (!name || typeof name !== "string") return -1;
          const chineseMatch = name.match(/^([一二三四五六七八九十]+)/);
          if (chineseMatch && chineseMatch[1]) {
            return order.indexOf(chineseMatch[1])
            return order.indexOf(chineseMatch[1]);
          }
          const arabicMatch = name.match(/^(\d+)/)
          const arabicMatch = name.match(/^(\d+)/);
          if (arabicMatch && arabicMatch[1]) {
            const num = parseInt(arabicMatch[1], 10)
            const num = parseInt(arabicMatch[1], 10);
            if (num >= 1 && num <= 45) {
              return num - 1
              return num - 1;
            }
          }
          return -1
        }
          return -1;
        };
        const indexA = getIndex(a.leavehospitaldistrictname)
        const indexB = getIndex(b.leavehospitaldistrictname)
        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
        return indexA - indexB
      })
        if (indexA === -1) return 1;
        if (indexB === -1) return -1;
        return indexA - indexB;
      });
    },
    sortChineseNumber(aRow, bRow) {
      const a = aRow.leavehospitaldistrictname
      const b = bRow.leavehospitaldistrictname
      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 (!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 chineseNum = match[1];
          return chineseNumMap[chineseNum] !== undefined
            ? chineseNumMap[chineseNum]
            : -1;
        }
        const arabicMatch = text.match(/^(\d+)/)
        const arabicMatch = text.match(/^(\d+)/);
        if (arabicMatch && arabicMatch[1]) {
          const num = parseInt(arabicMatch[1], 10)
          return num >= 1 && num <= 45 ? num : -1
          const num = parseInt(arabicMatch[1], 10);
          return num >= 1 && num <= 45 ? num : -1;
        }
        return -1
      }
        return -1;
      };
      const numA = getNumberFromText(a)
      const numB = getNumberFromText(b)
      const numA = getNumberFromText(a);
      const numB = getNumberFromText(b);
      if (numA === -1 && numB === -1) {
        return (a || "").localeCompare(b || "")
        return (a || "").localeCompare(b || "");
      }
      if (numA === -1) return 1
      if (numB === -1) return -1
      return numA - numB
      if (numA === -1) return 1;
      if (numB === -1) return -1;
      return numA - numB;
    },
    getRowKey(row) {
      return row.statisticaltype === 1 ? row.leavehospitaldistrictcode : row.deptcode
      return row.statisticaltype === 1
        ? row.leavehospitaldistrictcode
        : row.deptcode;
    },
    handleRowClick(row) {
      if (this.expands.includes(this.getRowKey(row))) {
        this.expands = []
        return
        this.expands = [];
        return;
      }
      const params = {
@@ -315,226 +647,253 @@
          : this.queryParams.deptcodes,
        leavehospitaldistrictcodes: [row.leavehospitaldistrictcode],
        drcode: "1",
        visitCount: 1
      }
        visitCount: 1,
      };
      delete params.leavehospitaldistrictcodes.all
      delete params.deptcodes.all
      delete params.leavehospitaldistrictcodes.all;
      delete params.deptcodes.all;
      if (!row.doctorStats) {
        this.loading = true
        this.loading = true;
        getSfStatistics(params).then((res) => {
          this.$set(row, "doctorStats", res.data)
          this.expands = [this.getRowKey(row)]
          this.loading = false
        })
          this.$set(row, "doctorStats", res.data);
          this.expands = [this.getRowKey(row)];
          this.loading = false;
        });
      } else {
        this.expands = [this.getRowKey(row)]
        this.expands = [this.getRowKey(row)];
      }
    },
    getSummaries(param) {
      const { columns, data } = param
      const sums = []
      const { columns, data } = param;
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = "合计"
          return
          sums[index] = "合计";
          return;
        }
        if (index === 1 || index === 2) {
          sums[index] = "/"
          return
          sums[index] = "/";
          return;
        }
        if (column.property === "followUpRate" || column.property === "rate") {
          const percentageValues = data
            .map((item) => {
              const value = item[column.property]
              if (!value || value === "-" || value === "0%") return null
              const value = item[column.property];
              if (!value || value === "-" || value === "0%") return null;
              if (typeof value === "string" && value.includes("%")) {
                const numValue = parseFloat(value.replace("%", "")) / 100
                return isNaN(numValue) ? null : numValue
                const numValue = parseFloat(value.replace("%", "")) / 100;
                return isNaN(numValue) ? null : numValue;
              } else {
                const numValue = parseFloat(value)
                return isNaN(numValue) ? null : numValue
                const numValue = parseFloat(value);
                return isNaN(numValue) ? null : numValue;
              }
            })
            .filter((value) => value !== null && value !== 0)
            .filter((value) => value !== null && value !== 0);
          if (percentageValues.length > 0) {
            const average = percentageValues.reduce((sum, value) => sum + value, 0) / percentageValues.length
            sums[index] = (average * 100).toFixed(2) + "%"
            const average =
              percentageValues.reduce((sum, value) => sum + value, 0) /
              percentageValues.length;
            sums[index] = (average * 100).toFixed(2) + "%";
          } else {
            sums[index] = "0.00%"
            sums[index] = "0.00%";
          }
        } else {
          const values = data.map((item) => {
            const value = item[column.property]
            if (value === "-" || value === "" || value === null) return 0
            return Number(value) || 0
          })
            const value = item[column.property];
            if (value === "-" || value === "" || value === null) return 0;
            return Number(value) || 0;
          });
          if (!values.every((value) => isNaN(value))) {
            sums[index] = values.reduce((prev, curr) => prev + curr, 0)
            sums[index] = this.formatNumber(sums[index])
            sums[index] = values.reduce((prev, curr) => prev + curr, 0);
            sums[index] = this.formatNumber(sums[index]);
          } else {
            sums[index] = "-"
            sums[index] = "-";
          }
        }
      })
      });
      return sums
      return sums;
    },
    getInnerSummaries(param) {
      const { columns, data } = param
      const sums = []
      const { columns, data } = param;
      const sums = [];
      columns.forEach((column, index) => {
        if (index === 0) {
          sums[index] = "小计"
          return
          sums[index] = "小计";
          return;
        }
        if (column.property === "drname" || column.property === "deptname") {
          sums[index] = "-"
          return
          sums[index] = "-";
          return;
        }
        if (column.property === "followUpRate" || column.property === "rate") {
          const percentageValues = data
            .map((item) => {
              const value = item[column.property]
              if (!value || value === "-" || value === "0%") return null
              const value = item[column.property];
              if (!value || value === "-" || value === "0%") return null;
              if (typeof value === "string" && value.includes("%")) {
                const numValue = parseFloat(value.replace("%", "")) / 100
                return isNaN(numValue) ? null : numValue
                const numValue = parseFloat(value.replace("%", "")) / 100;
                return isNaN(numValue) ? null : numValue;
              } else {
                const numValue = parseFloat(value)
                return isNaN(numValue) ? null : numValue
                const numValue = parseFloat(value);
                return isNaN(numValue) ? null : numValue;
              }
            })
            .filter((value) => value !== null && value !== 0)
            .filter((value) => value !== null && value !== 0);
          if (percentageValues.length > 0) {
            const average = percentageValues.reduce((sum, value) => sum + value, 0) / percentageValues.length
            sums[index] = (average * 100).toFixed(2) + "%"
            const average =
              percentageValues.reduce((sum, value) => sum + value, 0) /
              percentageValues.length;
            sums[index] = (average * 100).toFixed(2) + "%";
          } else {
            sums[index] = "0.00%"
            sums[index] = "0.00%";
          }
        } else {
          const values = data.map((item) => {
            const value = item[column.property]
            if (value === "-" || value === "" || value === null) return 0
            return Number(value) || 0
          })
            const value = item[column.property];
            if (value === "-" || value === "" || value === null) return 0;
            return Number(value) || 0;
          });
          if (!values.every((value) => isNaN(value))) {
            sums[index] = values.reduce((prev, curr) => prev + curr, 0)
            sums[index] = this.formatNumber(sums[index])
            sums[index] = values.reduce((prev, curr) => prev + curr, 0);
            sums[index] = this.formatNumber(sums[index]);
          } else {
            sums[index] = "-"
            sums[index] = "-";
          }
        }
      })
      });
      return sums
      return sums;
    },
    formatNumber(num) {
      if (isNaN(num)) return "-"
      return Number.isInteger(num) ? num.toString() : num.toFixed(0)
      if (isNaN(num)) return "-";
      return Number.isInteger(num) ? num.toString() : num.toFixed(0);
    },
    handleSelectionChange(selection) {
      this.ids = selection.map((item) => item.tagid)
      this.ids = selection.map((item) => item.tagid);
    },
    handleViewDetails(row, infoKey, titleSuffix) {
      const title = `${row.leavehospitaldistrictname || row.deptname}${titleSuffix}`
      this.$emit('view-details', row[infoKey], title)
      const title = `${
        row.leavehospitaldistrictname || row.deptname
      }${titleSuffix}`;
      this.$emit("view-details", row[infoKey], title);
    },
    handleSeeDetails(row) {
      this.$emit('see-details', row)
      this.$emit("see-details", row);
    },
    async exportTable() {
      try {
        let dateRangeString = ""
        let sheetNameSuffix = ""
        let dateRangeString = "";
        let sheetNameSuffix = "";
        if (this.queryParams.dateRange && this.queryParams.dateRange.length === 2) {
          const startDateStr = this.queryParams.dateRange[0]
          const endDateStr = this.queryParams.dateRange[1]
        if (
          this.queryParams.dateRange &&
          this.queryParams.dateRange.length === 2
        ) {
          const startDateStr = this.queryParams.dateRange[0];
          const endDateStr = this.queryParams.dateRange[1];
          const formatDateForDisplay = (dateTimeStr) => {
            return dateTimeStr.split(" ")[0]
          }
          const startDateFormatted = formatDateForDisplay(startDateStr)
          const endDateFormatted = formatDateForDisplay(endDateStr)
          dateRangeString = `${startDateFormatted}至${endDateFormatted}`
          sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`
            return dateTimeStr.split(" ")[0];
          };
          const startDateFormatted = formatDateForDisplay(startDateStr);
          const endDateFormatted = formatDateForDisplay(endDateStr);
          dateRangeString = `${startDateFormatted}至${endDateFormatted}`;
          sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`;
        } else {
          const now = new Date()
          const currentMonth = now.getMonth() + 1
          dateRangeString = `${currentMonth}月`
          sheetNameSuffix = `${currentMonth}月`
          const now = new Date();
          const currentMonth = now.getMonth() + 1;
          dateRangeString = `${currentMonth}月`;
          sheetNameSuffix = `${currentMonth}月`;
        }
        const excelName = `首次出院随访统计表_${dateRangeString}.xlsx`
        const worksheetName = `首次随访统计_${sheetNameSuffix}`
        const excelName = `首次出院随访统计表_${dateRangeString}.xlsx`;
        const worksheetName = `首次随访统计_${sheetNameSuffix}`;
        if (!this.tableData || this.tableData.length === 0) {
          this.$message.warning("暂无首次随访数据可导出")
          return false
          this.$message.warning("暂无首次随访数据可导出");
          return false;
        }
        const workbook = new ExcelJS.Workbook()
        const worksheet = workbook.addWorksheet(worksheetName)
        const workbook = new ExcelJS.Workbook();
        const worksheet = workbook.addWorksheet(worksheetName);
        // 构建表格
        this.buildExportSheet(worksheet, sheetNameSuffix)
        this.buildExportSheet(worksheet, sheetNameSuffix);
        const buffer = await workbook.xlsx.writeBuffer()
        const buffer = await workbook.xlsx.writeBuffer();
        const blob = new Blob([buffer], {
          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
        })
        saveAs(blob, excelName)
          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        });
        saveAs(blob, excelName);
        this.$message.success("导出成功")
        return true
        this.$message.success("导出成功");
        return true;
      } catch (error) {
        console.error("导出失败:", error)
        this.$message.error(`导出失败: ${error.message}`)
        return false
        console.error("导出失败:", error);
        this.$message.error(`导出失败: ${error.message}`);
        return false;
      }
    },
    buildExportSheet(worksheet, sheetNameSuffix) {
      const titleStyle = {
        font: { name: "微软雅黑", size: 16, bold: true, color: { argb: "FF000000" } },
        fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FFE6F3FF" } },
        font: {
          name: "微软雅黑",
          size: 16,
          bold: true,
          color: { argb: "FF000000" },
        },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFE6F3FF" },
        },
        alignment: { vertical: "middle", horizontal: "center", wrapText: true },
        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, color: { argb: "FF000000" } },
        fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FFF5F7FA" } },
        font: {
          name: "微软雅黑",
          size: 11,
          bold: true,
          color: { argb: "FF000000" },
        },
        fill: {
          type: "pattern",
          pattern: "solid",
          fgColor: { argb: "FFF5F7FA" },
        },
        alignment: { vertical: "middle", horizontal: "center", wrapText: true },
        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 = {
        font: { name: "宋体", size: 10, color: { argb: "FF000000" } },
@@ -543,176 +902,243 @@
          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 summaryStyle = {
        font: { name: "宋体", size: 10, bold: true, color: { argb: "FF409EFF" } },
        fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FFF5F7FA" } },
        font: {
          name: "宋体",
          size: 10,
          bold: true,
          color: { argb: "FF409EFF" },
        },
        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" } },
        },
      };
      // 添加标题行
      worksheet.mergeCells(1, 1, 1, 16)
      const titleCell = worksheet.getCell(1, 1)
      titleCell.value = `首次出院随访统计表_${sheetNameSuffix}`
      titleCell.style = titleStyle
      worksheet.getRow(1).height = 35
      worksheet.mergeCells(1, 1, 1, 16);
      const titleCell = worksheet.getCell(1, 1);
      titleCell.value = `首次出院随访统计表_${sheetNameSuffix}`;
      titleCell.style = titleStyle;
      worksheet.getRow(1).height = 35;
      // 表头
      const secondRowHeaders = [
        "", "出院病区", "科室", "出院人次", "无需随访人次", "应随访人次",
        "需随访", "待随访", "随访成功", "随访失败", "随访率", "及时率", "人工", "短信", "微信"
      ]
        "",
        "出院病区",
        "科室",
        "出院人次",
        "无需随访人次",
        "应随访人次",
        "需随访",
        "待随访",
        "随访成功",
        "随访失败",
        "随访率",
        "及时率",
        "人工",
        "短信",
        "微信",
      ];
      secondRowHeaders.forEach((header, index) => {
        const cell = worksheet.getCell(3, index + 1)
        cell.value = header
        cell.style = headerStyle
      })
        const cell = worksheet.getCell(3, index + 1);
        cell.value = header;
        cell.style = headerStyle;
      });
      // 合并单元格
      for (let i = 1; i <= 6; i++) {
        worksheet.mergeCells(2, i, 3, i)
        const cell = worksheet.getCell(2, i)
        cell.style = headerStyle
        worksheet.mergeCells(2, i, 3, i);
        const cell = worksheet.getCell(2, i);
        cell.style = headerStyle;
      }
      worksheet.getCell(2, 1).value = ""
      worksheet.getCell(2, 2).value = "出院病区"
      worksheet.getCell(2, 3).value = "科室"
      worksheet.getCell(2, 4).value = "出院人次"
      worksheet.getCell(2, 5).value = "无需随访人次"
      worksheet.getCell(2, 6).value = "应随访人次"
      worksheet.getCell(2, 1).value = "";
      worksheet.getCell(2, 2).value = "出院病区";
      worksheet.getCell(2, 3).value = "科室";
      worksheet.getCell(2, 4).value = "出院人次";
      worksheet.getCell(2, 5).value = "无需随访人次";
      worksheet.getCell(2, 6).value = "应随访人次";
      worksheet.mergeCells(2, 7, 2, 15)
      worksheet.getCell(2, 7).value = "首次出院随访"
      worksheet.getCell(2, 7).style = headerStyle
      worksheet.mergeCells(2, 7, 2, 15);
      worksheet.getCell(2, 7).value = "首次出院随访";
      worksheet.getCell(2, 7).style = headerStyle;
      worksheet.getRow(2).height = 28
      worksheet.getRow(3).height = 25
      worksheet.getRow(2).height = 28;
      worksheet.getRow(3).height = 25;
      // 数据行
      this.tableData.forEach((item, rowIndex) => {
        const dataRow = worksheet.addRow([
          "",
          item.leavehospitaldistrictname || "",
          item.deptname || "",
          item.dischargeCount || 0,
          item.nonFollowUp || 0,
          item.followUpNeeded || 0,
          item.needFollowUp || 0,
          item.pendingFollowUp || 0,
          item.followUpSuccess || 0,
          item.followUpFail || 0,
          item.followUpRate || "0%",
          item.rate ? (Number(item.rate) * 100).toFixed(2) + "%" : "0%",
          item.manual || 0,
          item.sms || 0,
          item.weChat || 0
        ], rowIndex + 4)
        const dataRow = worksheet.addRow(
          [
            "",
            item.leavehospitaldistrictname || "",
            item.deptname || "",
            item.dischargeCount || 0,
            item.nonFollowUp || 0,
            item.followUpNeeded || 0,
            item.needFollowUp || 0,
            item.pendingFollowUp || 0,
            item.followUpSuccess || 0,
            item.followUpFail || 0,
            item.followUpRate || "0%",
            item.rate ? (Number(item.rate) * 100).toFixed(2) + "%" : "0%",
            item.manual || 0,
            item.sms || 0,
            item.weChat || 0,
          ],
          rowIndex + 4
        );
        dataRow.eachCell((cell) => {
          cell.style = cellStyle
        })
        dataRow.height = 24
      })
          cell.style = cellStyle;
        });
        dataRow.height = 24;
      });
      // 合计行
      const summaries = this.getExportSummaries()
      const summaryRow = worksheet.addRow(summaries)
      const summaries = this.getExportSummaries();
      const summaryRow = worksheet.addRow(summaries);
      summaryRow.eachCell((cell, colNumber) => {
        cell.style = summaryStyle
        cell.style = summaryStyle;
        if (colNumber === 1) {
          cell.value = "合计"
          cell.value = "合计";
        }
      })
      summaryRow.height = 28
      });
      summaryRow.height = 28;
      // 列宽
      worksheet.columns = [
        { width: 8 }, { width: 20 }, { width: 15 }, { width: 12 }, { width: 12 }, { width: 12 },
        { width: 10 }, { width: 10 }, { width: 10 }, { width: 10 }, { width: 12 }, { width: 12 },
        { width: 8 }, { width: 8 }, { width: 8 }
      ]
        { width: 8 },
        { width: 20 },
        { width: 15 },
        { width: 12 },
        { width: 12 },
        { width: 12 },
        { width: 10 },
        { width: 10 },
        { width: 10 },
        { width: 10 },
        { width: 12 },
        { width: 12 },
        { width: 8 },
        { width: 8 },
        { width: 8 },
      ];
    },
    getExportSummaries() {
      const summaries = ["合计", "/", "/", 0, 0, 0, 0, 0, 0, 0, "0%", "0%", 0, 0, 0]
      const summaries = [
        "合计",
        "/",
        "/",
        0,
        0,
        0,
        0,
        0,
        0,
        0,
        "0%",
        "0%",
        0,
        0,
        0,
      ];
      this.tableData.forEach((item) => {
        summaries[3] += Number(item.dischargeCount) || 0
        summaries[4] += Number(item.nonFollowUp) || 0
        summaries[5] += Number(item.followUpNeeded) || 0
        summaries[6] += Number(item.needFollowUp) || 0
        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[3] += Number(item.dischargeCount) || 0;
        summaries[4] += Number(item.nonFollowUp) || 0;
        summaries[5] += Number(item.followUpNeeded) || 0;
        summaries[6] += Number(item.needFollowUp) || 0;
        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;
      });
      const followUpRateValues = this.tableData
        .map((item) => this.extractPercentageValue(item.followUpRate))
        .filter((value) => value !== null)
        .filter((value) => value !== null);
      const rateValues = this.tableData
        .map((item) => this.extractPercentageValue(item.rate))
        .filter((value) => value !== null)
        .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) + "%"
        const avgFollowUpRate =
          followUpRateValues.reduce((sum, val) => sum + val, 0) /
          followUpRateValues.length;
        summaries[10] = (avgFollowUpRate * 100).toFixed(2) + "%";
      }
      if (rateValues.length > 0) {
        const avgRate = rateValues.reduce((sum, val) => sum + val, 0) / rateValues.length
        summaries[11] = (avgRate * 100).toFixed(2) + "%"
        const avgRate =
          rateValues.reduce((sum, val) => sum + val, 0) / rateValues.length;
        summaries[11] = (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])
      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]);
      return summaries
      return summaries;
    },
    extractPercentageValue(value) {
      if (!value) return null
      if (!value) return null;
      if (typeof value === "string" && value.includes("%")) {
        const num = parseFloat(value.replace("%", ""))
        return isNaN(num) ? null : num / 100
        const num = parseFloat(value.replace("%", ""));
        return isNaN(num) ? null : num / 100;
      }
      const num = parseFloat(value)
      return isNaN(num) ? null : num
      const num = parseFloat(value);
      return isNaN(num) ? null : num;
    },
    selectTimelyRate(row, dateRange) {
      const params = {
        ...this.patientqueryParams,
        starttime: this.parseTime(dateRange[0]),
        endtime: this.parseTime(dateRange[1]),
        deptcode: row.deptcode
      }
      return selectTimelyRate(params)
    }
  }
}
      console.log(row, dateRange, 88);
      // const params = {
      //   ...this.patientqueryParams,
      //   starttime: this.parseTime(dateRange[0]),
      //   endtime: this.parseTime(dateRange[1]),
      //   deptcode: row.deptcode,
      // };
      this.patientqueryParams.starttime = this.parseTime(dateRange[0]);
      this.patientqueryParams.endtime = this.parseTime(dateRange[1]);
      this.patientqueryParams.deptcode = row.deptcode;
      return selectTimelyRate(this.patientqueryParams);
    },
    selectTimelyRates(dateRange) {
      this.patientqueryParams.pn = dateRange.pageNum;
      this.patientqueryParams.ps = dateRange.pageSize;
      return selectTimelyRate(this.patientqueryParams);
    },
  },
};
</script>
<style lang="scss" scoped>