liusheng
20 小时以前 9903954c85f651dd5cc6d4b538cfe66b17fc5baa
src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue
@@ -9,6 +9,19 @@
        label-width="100px"
        class="query-form"
      >
        <el-form-item label="满意度类型" prop="satisfactionScope">
          <el-select
            v-model="satisfactionScope"
            placeholder="默认在院"
            clearable
            style="width: 150px"
            @change="handleSatisfactionScopeChange"
          >
            <el-option label="离院满意度" value="leave" />
            <el-option label="在院满意度" value="hospital" />
          </el-select>
        </el-form-item>
        <el-form-item label="统计类型" prop="statisticaltype">
          <el-select
            v-model="queryParams.statisticaltype"
@@ -137,29 +150,67 @@
        @selection-change="handleSelectionChange"
        :row-key="getRowKey"
      >
        <!-- 病区列 -->
        <!-- 病区统计:在院病区 + 离院病区 -->
        <el-table-column
          v-if="queryParams.statisticaltype == 1"
          label="出院病区"
          label="在院病区"
          align="center"
          sortable
          key="hospitaldistrictname"
          prop="hospitaldistrictname"
          :show-overflow-tooltip="true"
          :sort-method="sortHospitalWard"
          min-width="120"
        >
          <template slot-scope="scope">
            {{ scope.row.hospitaldistrictname || "-" }}
          </template>
        </el-table-column>
        <el-table-column
          v-if="queryParams.statisticaltype == 1"
          label="离院病区"
          align="center"
          sortable
          key="leavehospitaldistrictname"
          prop="leavehospitaldistrictname"
          :show-overflow-tooltip="true"
          :sort-method="sortChineseNumber"
          :sort-method="sortLeaveWard"
          min-width="120"
        />
        >
          <template slot-scope="scope">
            {{ scope.row.leavehospitaldistrictname || "-" }}
          </template>
        </el-table-column>
        <!-- 科室列 -->
        <!-- 科室统计:在院科室 + 离院科室 -->
        <el-table-column
          v-if="queryParams.statisticaltype == 2"
          label="科室"
          label="在院科室"
          align="center"
          key="hospitaldeptname"
          prop="hospitaldeptname"
          :show-overflow-tooltip="true"
          min-width="120"
        >
          <template slot-scope="scope">
            {{ scope.row.hospitaldeptname || "-" }}
          </template>
        </el-table-column>
        <el-table-column
          v-if="queryParams.statisticaltype == 2"
          label="离院科室"
          align="center"
          key="deptname"
          prop="deptname"
          :show-overflow-tooltip="true"
          min-width="120"
        />
        >
          <template slot-scope="scope">
            {{ scope.row.deptname || "-" }}
          </template>
        </el-table-column>
        <el-table-column
          label="出院人次"
@@ -199,13 +250,14 @@
                scope.row.followUpRate !== undefined
              "
            >
              {{ formatPercent(scope.row.followUpRate) }}
              {{ scope.row.followUpRate }}
            </span>
            <span v-else>-</span>
          </template>
        </el-table-column>
        <el-table-column
          v-if="orgname == '景宁畲族自治县人民医院'"
          label="及时率"
          align="center"
          key="rate"
@@ -322,6 +374,7 @@
        :row-data="currentRow"
        :topicList="topiclist"
        :query-params="queryParams"
        :topType="2"
        @close="topicVisible = false"
      />
    </el-dialog>
@@ -347,12 +400,17 @@
  },
  data() {
    return {
      // 满意度类型:leave=离院满意度(按出院病区统计),hospital=在院满意度(按在院病区统计)
      // 默认在院满意度
      satisfactionScope: "hospital",
      // 查询参数
      queryParams: {
        statisticaltype: 1,
        leavehospitaldistrictcodes: ["all"],
        deptcodes: [],
        serviceType: [2],
        // 默认服务类型:6=住院满意度(出入院满意度)
        serviceType: [6],
        dateRange: [],
        pageNum: 1,
        pageSize: 20,
@@ -371,7 +429,25 @@
      flatArraydept: [],
      // 服务类型选项
      options: [],
      options: [
        {
          value: 6,
          label: "住院满意度",
          raw: {
            cssClass: "",
            listClass: "",
          },
        },
        {
          value: 14,
          label: "门诊满意度",
          raw: {
            cssClass: "",
            listClass: "",
          },
        },
      ],
      // 表格数据
      userList: [],
@@ -381,6 +457,7 @@
      // 加载状态
      loading: false,
      orgname: "",
      // 选中的行
      ids: [],
@@ -438,7 +515,18 @@
    };
  },
  computed: {
    // 是否按「在院满意度」口径统计:在院用 hospitaldistrictcodes / hospitaldeptcodes,
    // 离院用 leavehospitaldistrictcodes / leaveldeptcodes
    // 默认在院,所以清空下拉时仍按在院口径处理
    isInHospitalSatisfaction() {
      return this.satisfactionScope !== "leave";
    },
  },
  created() {
    this.orgname = localStorage.getItem("orgname");
    this.initData();
  },
@@ -446,7 +534,7 @@
    // 初始化数据
    async initData() {
      await this.getDeptTree();
      await this.getList();
      // await this.getList();
    },
    // 获取科室树
@@ -498,36 +586,56 @@
          params.endTime = this.queryParams.dateRange[1];
        }
        // 处理病区/科室选择
        // 处理病区/科室选择:只保留当前统计类型 + 当前满意度类型对应的字段,
        // 避免在院/离院两套条件同时拼进 SQL
        if (params.statisticaltype == 1) {
          // 病区统计
          if (params.leavehospitaldistrictcodes.includes("all")) {
            // 如果选择了"全部",则移除"all"值
            params.leavehospitaldistrictcodes =
              params.leavehospitaldistrictcodes.filter(
                (item) => item !== "all"
              );
            // 如果需要传所有病区代码,可以从store中获取
            params.leavehospitaldistrictcodes = (
              this.$store.getters.belongWards || []
            ).map((ward) => ward.districtCode);
          let wardCodes = params.leavehospitaldistrictcodes || [];
          if (wardCodes.includes("all")) {
            // 如果选择了"全部",则使用当前用户所属的全部病区
            wardCodes = (this.$store.getters.belongWards || []).map(
              (ward) => ward.districtCode
            );
          }
          delete params.leavehospitaldistrictcodes;
          delete params.hospitaldistrictcodes;
          delete params.deptcodes;
          delete params.leaveldeptcodes;
          delete params.hospitaldeptcodes;
          if (this.isInHospitalSatisfaction) {
            params.hospitaldistrictcodes = wardCodes;
          } else {
            params.leavehospitaldistrictcodes = wardCodes;
          }
        } else if (params.statisticaltype == 2) {
          // 科室统计
          if (params.deptcodes.includes("all")) {
          let deptCodes = params.deptcodes || [];
          if (deptCodes.includes("all")) {
            // 如果选择了"全部",则移除"all"值
            params.deptcodes = params.deptcodes.filter(
              (item) => item !== "all"
            );
            deptCodes = deptCodes.filter((item) => item !== "all");
            // 如果需要传所有科室代码,可以从store中获取
            params.deptcodes = (this.$store.getters.belongDepts || []).map(
            deptCodes = (this.$store.getters.belongDepts || []).map(
              (dept) => dept.deptCode
            );
          }
          delete params.deptcodes;
          delete params.leaveldeptcodes;
          delete params.hospitaldeptcodes;
          delete params.leavehospitaldistrictcodes;
          delete params.hospitaldistrictcodes;
          if (this.isInHospitalSatisfaction) {
            params.hospitaldeptcodes = deptCodes;
          } else {
            params.leaveldeptcodes = deptCodes;
          }
        }
        const response = await getSfStatisticsJoy(params);
        this.userList = this.customSort(response.data) || [];
        // 科室统计按接口返回顺序,病区统计保持原有的中文序号排序
        this.userList =
          this.queryParams.statisticaltype == 1
            ? this.customSort(response.data) || []
            : response.data || [];
        this.total = response.total || 0;
      } catch (error) {
        console.error("获取统计列表失败:", error);
@@ -537,9 +645,22 @@
      }
    },
    sortChineseNumber(aRow, bRow) {
      const a = aRow.leavehospitaldistrictname;
      const b = bRow.leavehospitaldistrictname;
      return this.compareWardNames(this.getWardName(aRow), this.getWardName(bRow));
    },
    sortHospitalWard(aRow, bRow) {
      return this.compareWardNames(
        aRow && aRow.hospitaldistrictname,
        bRow && bRow.hospitaldistrictname
      );
    },
    sortLeaveWard(aRow, bRow) {
      return this.compareWardNames(
        aRow && aRow.leavehospitaldistrictname,
        bRow && bRow.leavehospitaldistrictname
      );
    },
    // 比较两个病区名称的中文序号;无序号时按字符串比较
    compareWardNames(a, b) {
      // 中文数字到阿拉伯数字的映射(扩展到45)
      const chineseNumMap = {
        一: 1,
@@ -698,14 +819,12 @@
          return -1;
        };
        const indexA = getIndex(a.leavehospitaldistrictname);
        const indexB = getIndex(b.leavehospitaldistrictname);
        const indexA = getIndex(this.getWardName(a));
        const indexB = getIndex(this.getWardName(b));
        // 排序逻辑
        if (indexA === -1 && indexB === -1) {
          return (a.leavehospitaldistrictname || "").localeCompare(
            b.leavehospitaldistrictname || ""
          );
          return this.getWardName(a).localeCompare(this.getWardName(b));
        }
        if (indexA === -1) return 1;
        if (indexB === -1) return -1;
@@ -729,13 +848,20 @@
      this.getList();
    },
    // 重置查询
    // 切换满意度类型(离院/在院)后重新查询
    handleSatisfactionScopeChange() {
      this.queryParams.pageNum = 1;
      this.getList();
    },
    // 重置查询(恢复默认:在院满意度 + 服务类型 6)
    resetQuery() {
      this.satisfactionScope = "hospital";
      this.queryParams = {
        statisticaltype: 1,
        leavehospitaldistrictcodes: [],
        deptcodes: [],
        serviceType: [2],
        serviceType: [6],
        dateRange: [],
        pageNum: 1,
        pageSize: 20,
@@ -763,11 +889,19 @@
      this.multiple = !selection.length;
    },
    // 获取行key
    // 获取行key(按当前统计类型取对应维度编码)
    getRowKey(row) {
      return row.statisticaltype === 1
        ? row.leavehospitaldistrictcode
        : row.deptcode;
      return this.queryParams.statisticaltype == 1
        ? row.hospitaldistrictcode || row.leavehospitaldistrictcode
        : row.hospitaldeptcode || row.deptcode;
    },
    // 当前满意度类型对应的病区名称(用于排序/导出/详情标题)
    getWardName(row) {
      if (!row) return "";
      return this.isInHospitalSatisfaction
        ? row.hospitaldistrictname || ""
        : row.leavehospitaldistrictname || "";
    },
    // 格式化百分比
@@ -804,18 +938,38 @@
          params.endTime = this.queryParams.dateRange[1];
        }
        // 详情只按当前分组维度过滤,清掉其余维度,避免在院/离院条件互相干扰
        delete params.deptcodes;
        delete params.leaveldeptcodes;
        delete params.hospitaldeptcodes;
        delete params.leavehospitaldistrictcodes;
        delete params.hospitaldistrictcodes;
        if (this.queryParams.statisticaltype == 1) {
          this.topicvalue.name = row.leavehospitaldistrictname;
          params.leavehospitaldistrictcodes = [row.leavehospitaldistrictcode];
          if (this.isInHospitalSatisfaction) {
            this.topicvalue.name = row.hospitaldistrictname || "-";
            params.hospitaldistrictcodes = [row.hospitaldistrictcode].filter(
              Boolean
            );
          } else {
            this.topicvalue.name = row.leavehospitaldistrictname || "-";
            params.leavehospitaldistrictcodes = [
              row.leavehospitaldistrictcode,
            ].filter(Boolean);
          }
        } else {
          this.topicvalue.name = row.deptname;
          params.deptcodes = [row.deptcode];
          if (this.isInHospitalSatisfaction) {
            this.topicvalue.name = row.hospitaldeptname || "-";
            params.hospitaldeptcodes = [row.hospitaldeptcode].filter(Boolean);
          } else {
            this.topicvalue.name = row.deptname || "-";
            params.leaveldeptcodes = [row.deptcode].filter(Boolean);
          }
        }
        const response = await getSfStatisticsJoyInfo(params);
        this.topiclist = response.data || [];
      this.topicVisible = true;
        this.topicVisible = true;
      } catch (error) {
        console.error("获取满意度详情失败:", error);
        this.$message.error("获取详情失败");
@@ -835,23 +989,54 @@
        // 构建日期范围字符串
        let dateRangeString = "";
        let sheetNameSuffix = "";
        const isLishuiHospital = this.orgname == "丽水市中医院";
        if (
          this.queryParams.dateRange &&
          this.queryParams.dateRange.length === 2
        ) {
          const startDateFormatted = this.queryParams.dateRange[0];
          const endDateFormatted = this.queryParams.dateRange[1];
          dateRangeString = `${startDateFormatted}至${endDateFormatted}`;
          sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`;
          const startDateStr = this.queryParams.dateRange[0];
          const endDateStr = this.queryParams.dateRange[1];
          if (isLishuiHospital) {
            // 丽水市中医院:只显示年月
            const formatMonthOnly = (dateTimeStr) => {
              const date = new Date(dateTimeStr);
              const year = date.getFullYear();
              const month = date.getMonth() + 1;
              return `${year}年${month}月`;
            };
            const startDateFormatted = formatMonthOnly(startDateStr);
            const endDateFormatted = formatMonthOnly(endDateStr);
            dateRangeString = `${startDateFormatted}至${endDateFormatted}`;
            sheetNameSuffix = `${startDateFormatted}至${endDateFormatted}`;
          } else {
            // 其他医院:显示年月日
            const formatDateForDisplay = (dateTimeStr) => {
              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 currentYear = now.getFullYear();
          if (isLishuiHospital) {
            // 丽水市中医院:显示年月
            dateRangeString = `${currentYear}年${currentMonth}月`;
            sheetNameSuffix = `${currentYear}年${currentMonth}月`;
          } else {
            // 其他医院:显示月份
            dateRangeString = `${currentMonth}月`;
            sheetNameSuffix = `${currentMonth}月`;
          }
        }
        const excelName = `随访统计表_${dateRangeString}.xlsx`;
        const excelName = `满意度随访统计表_${dateRangeString}.xlsx`;
        const worksheetName = `随访统计_${sheetNameSuffix}`;
        // 创建Excel工作簿
@@ -902,16 +1087,18 @@
          },
        };
        // 添加总标题
        // 添加总标题(两列维度 + 八个指标列,共 10 列)
        worksheet.mergeCells(1, 1, 1, 10);
        const titleCell = worksheet.getCell(1, 1);
        titleCell.value = `随访统计表(${sheetNameSuffix})`;
        titleCell.value = `满意度随访统计表(${sheetNameSuffix})`;
        titleCell.style = titleStyle;
        worksheet.getRow(1).height = 35;
        // 添加表头
        // 添加表头(科室统计导出在院科室+离院科室,病区统计导出在院病区+离院病区)
        const isWardStatistics = this.queryParams.statisticaltype == 1;
        const headers = [
          this.queryParams.statisticaltype == 1 ? "出院病区" : "科室",
          isWardStatistics ? "在院病区" : "在院科室",
          isWardStatistics ? "离院病区" : "离院科室",
          "出院人次",
          "无需随访人次",
          "应随访人次",
@@ -931,9 +1118,12 @@
        // 添加数据行
        this.userList.forEach((item) => {
          const dataRow = worksheet.addRow([
            this.queryParams.statisticaltype == 1
              ? item.leavehospitaldistrictname
              : item.deptname,
            isWardStatistics
              ? item.hospitaldistrictname || "-"
              : item.hospitaldeptname || "-",
            isWardStatistics
              ? item.leavehospitaldistrictname || "-"
              : item.deptname || "-",
            item.dischargeCount || 0,
            item.nonFollowUp || 0,
            item.followUpNeeded || 0,
@@ -953,6 +1143,7 @@
        // 设置列宽
        worksheet.columns = [
          { width: 20 },
          { width: 20 },
          { width: 12 },
          { width: 12 },
          { width: 12 },