WXL (wul)
昨天 03348941a9c44e3b9706a3b6c25c8fb5ba25d9d5
src/views/Satisfaction/sfstatistics/components/FollowupStatistics.vue
@@ -142,9 +142,11 @@
          v-if="queryParams.statisticaltype == 1"
          label="出院病区"
          align="center"
          sortable
          key="leavehospitaldistrictname"
          prop="leavehospitaldistrictname"
          :show-overflow-tooltip="true"
          :sort-method="sortChineseNumber"
          min-width="120"
        />
@@ -191,8 +193,13 @@
          min-width="100"
        >
          <template slot-scope="scope">
            <span v-if="scope.row.followUpRate !== null && scope.row.followUpRate !== undefined">
              {{ formatPercent(scope.row.followUpRate) }}
            <span
              v-if="
                scope.row.followUpRate !== null &&
                scope.row.followUpRate !== undefined
              "
            >
              {{ scope.row.followUpRate }}
            </span>
            <span v-else>-</span>
          </template>
@@ -241,24 +248,20 @@
          min-width="100"
        >
          <template slot-scope="scope">
            <span v-if="scope.row.joyTotal !== null && scope.row.joyTotal !== undefined">
            <span
              v-if="
                scope.row.joyTotal !== null && scope.row.joyTotal !== undefined
              "
            >
              {{ formatPercent(scope.row.joyTotal) }}
            </span>
            <span v-else>-</span>
          </template>
        </el-table-column>
        <el-table-column
          label="操作"
          align="center"
          fixed="right"
          width="120"
        >
        <el-table-column label="操作" align="center" fixed="right" width="120">
          <template slot-scope="scope">
            <el-button
              type="text"
              @click="getinfo(scope.row)"
            >
            <el-button type="text" @click="getinfo(scope.row)">
              <i class="el-icon-s-order" style="margin-right: 4px"></i>
              查看详情
            </el-button>
@@ -303,15 +306,21 @@
      :close-on-click-modal="false"
    >
      <template #title>
        <div style="display: flex; align-items: center;">
          <i class="el-icon-s-data" style="margin-right: 8px; color: #409EFF;"></i>
        <div style="display: flex; align-items: center">
          <i
            class="el-icon-s-data"
            style="margin-right: 8px; color: #409eff"
          ></i>
          <span>{{ topicvalue.name }}</span>
          <span style="margin-left: 10px; color: #666; font-size: 14px;">满意度指标详情</span>
          <span style="margin-left: 10px; color: #666; font-size: 14px"
            >满意度指标详情</span
          >
        </div>
      </template>
      <topic-dialog
        v-if="topicVisible"
        :row-data="currentRow"
        :topicList="topiclist"
        :query-params="queryParams"
        @close="topicVisible = false"
      />
@@ -320,35 +329,39 @@
</template>
<script>
import { getSfStatisticsJoy, getSfStatisticsJoyInfo, selectTimelyRate } from "@/api/system/user";
import {
  getSfStatisticsJoy,
  getSfStatisticsJoyInfo,
  selectTimelyRate,
} from "@/api/system/user";
import ExcelJS from "exceljs";
import { saveAs } from "file-saver";
import SeedetailsDialog from './components/SeedetailsDialog.vue';
import TopicDialog from './components/TopicDialog.vue';
import SeedetailsDialog from "./components/SeedetailsDialog.vue";
import TopicDialog from "./components/TopicDialog.vue";
export default {
  name: 'FollowupStatistics',
  name: "FollowupStatistics",
  components: {
    SeedetailsDialog,
    TopicDialog
    TopicDialog,
  },
  data() {
    return {
      // 查询参数
      queryParams: {
        statisticaltype: 1,
        leavehospitaldistrictcodes: [],
        leavehospitaldistrictcodes: ["all"],
        deptcodes: [],
        serviceType: [2],
        dateRange: [],
        pageNum: 1,
        pageSize: 20
        pageSize: 20,
      },
      // 统计类型列表
      Statisticallist: [
        { label: "病区统计", value: 1 },
        { label: "科室统计", value: 2 }
        { label: "科室统计", value: 2 },
      ],
      // 病区列表
@@ -384,44 +397,44 @@
      // 满意度详情数据
      topiclist: [],
      topicvalue: {
        name: ''
        name: "",
      },
      // 日期选择器选项
      pickerOptions: {
        shortcuts: [
          {
            text: '最近一周',
            text: "最近一周",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
              picker.$emit('pick', [start, end]);
            }
              picker.$emit("pick", [start, end]);
            },
          },
          {
            text: '最近一个月',
            text: "最近一个月",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
              picker.$emit('pick', [start, end]);
            }
              picker.$emit("pick", [start, end]);
            },
          },
          {
            text: '最近三个月',
            text: "最近三个月",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
              picker.$emit('pick', [start, end]);
            }
          }
              picker.$emit("pick", [start, end]);
            },
          },
        ],
        disabledDate(time) {
          return time.getTime() > Date.now();
        }
      }
        },
      },
    };
  },
@@ -442,20 +455,24 @@
      this.options = this.$store.getters.tasktypes || [];
      // 获取科室列表
      this.flatArraydept = (this.$store.getters.belongDepts || []).map((dept) => {
        return {
          label: dept.deptName,
          value: dept.deptCode
        };
      });
      this.flatArraydept = (this.$store.getters.belongDepts || []).map(
        (dept) => {
          return {
            label: dept.deptName,
            value: dept.deptCode,
          };
        }
      );
      // 获取病区列表
      this.flatArrayhospit = (this.$store.getters.belongWards || []).map((ward) => {
        return {
          label: ward.districtName,
          value: ward.districtCode
        };
      });
      this.flatArrayhospit = (this.$store.getters.belongWards || []).map(
        (ward) => {
          return {
            label: ward.districtName,
            value: ward.districtCode,
          };
        }
      );
      // 添加全部选项
      this.flatArraydept.push({ label: "全部", value: "all" });
@@ -469,11 +486,14 @@
        // 处理查询参数
        const params = {
          configKey: "joyCount",
          ...this.queryParams
          ...this.queryParams,
        };
        // 处理日期范围
        if (this.queryParams.dateRange && this.queryParams.dateRange.length === 2) {
        if (
          this.queryParams.dateRange &&
          this.queryParams.dateRange.length === 2
        ) {
          params.startTime = this.queryParams.dateRange[0];
          params.endTime = this.queryParams.dateRange[1];
        }
@@ -483,31 +503,215 @@
          // 病区统计
          if (params.leavehospitaldistrictcodes.includes("all")) {
            // 如果选择了"全部",则移除"all"值
            params.leavehospitaldistrictcodes = params.leavehospitaldistrictcodes.filter(item => item !== "all");
            params.leavehospitaldistrictcodes =
              params.leavehospitaldistrictcodes.filter(
                (item) => item !== "all"
              );
            // 如果需要传所有病区代码,可以从store中获取
            params.leavehospitaldistrictcodes = (this.$store.getters.belongWards || []).map(ward => ward.districtCode);
            params.leavehospitaldistrictcodes = (
              this.$store.getters.belongWards || []
            ).map((ward) => ward.districtCode);
          }
        } else if (params.statisticaltype == 2) {
          // 科室统计
          if (params.deptcodes.includes("all")) {
            // 如果选择了"全部",则移除"all"值
            params.deptcodes = params.deptcodes.filter(item => item !== "all");
            params.deptcodes = params.deptcodes.filter(
              (item) => item !== "all"
            );
            // 如果需要传所有科室代码,可以从store中获取
            params.deptcodes = (this.$store.getters.belongDepts || []).map(dept => dept.deptCode);
            params.deptcodes = (this.$store.getters.belongDepts || []).map(
              (dept) => dept.deptCode
            );
          }
        }
        const response = await getSfStatisticsJoy(params);
        this.userList = response.data || [];
        this.userList = this.customSort(response.data) || [];
        this.total = response.total || 0;
      } catch (error) {
        console.error('获取统计列表失败:', error);
        this.$message.error('获取数据失败');
        console.error("获取统计列表失败:", error);
        this.$message.error("获取数据失败");
      } finally {
        this.loading = false;
      }
    },
    sortChineseNumber(aRow, bRow) {
      const a = aRow.leavehospitaldistrictname;
      const b = bRow.leavehospitaldistrictname;
      // 中文数字到阿拉伯数字的映射(扩展到45)
      const chineseNumMap = {
        一: 1,
        二: 2,
        三: 3,
        四: 4,
        五: 5,
        六: 6,
        七: 7,
        八: 8,
        九: 9,
        十: 10,
        十一: 11,
        十二: 12,
        十三: 13,
        十四: 14,
        十五: 15,
        十六: 16,
        十七: 17,
        十八: 18,
        十九: 19,
        二十: 20,
        二十一: 21,
        二十二: 22,
        二十三: 23,
        二十四: 24,
        二十五: 25,
        二十六: 26,
        二十七: 27,
        二十八: 28,
        二十九: 29,
        三十: 30,
        三十一: 31,
        三十二: 32,
        三十三: 33,
        三十四: 34,
        三十五: 35,
        三十六: 36,
        三十七: 37,
        三十八: 38,
        三十九: 39,
        四十: 40,
        四十一: 41,
        四十二: 42,
        四十三: 43,
        四十四: 44,
        四十五: 45,
      };
      // 提取中文数字
      const getNumberFromText = (text) => {
        if (!text || typeof text !== "string") return -1;
        // 匹配中文数字,支持一到四十五
        const match = text.match(/^([一二三四五六七八九十]+)/);
        if (match && match[1]) {
          const chineseNum = match[1];
          return chineseNumMap[chineseNum] !== undefined
            ? chineseNumMap[chineseNum]
            : -1;
        }
        // 如果没有匹配到中文数字,尝试匹配阿拉伯数字
        const arabicMatch = text.match(/^(\d+)/);
        if (arabicMatch && arabicMatch[1]) {
          const num = parseInt(arabicMatch[1], 10);
          return num >= 1 && num <= 45 ? num : -1;
        }
        return -1;
      };
      const numA = getNumberFromText(a);
      const numB = getNumberFromText(b);
      // 处理无法解析的情况
      if (numA === -1 && numB === -1) {
        return (a || "").localeCompare(b || "");
      }
      if (numA === -1) return 1;
      if (numB === -1) return -1;
      return numA - numB;
    },
    customSort(data) {
      // 定义您期望的病区顺序(扩展到四十五)
      const order = [
        "一",
        "二",
        "三",
        "四",
        "五",
        "六",
        "七",
        "八",
        "九",
        "十",
        "十一",
        "十二",
        "十三",
        "十四",
        "十五",
        "十六",
        "十七",
        "十八",
        "十九",
        "二十",
        "二十一",
        "二十二",
        "二十三",
        "二十四",
        "二十五",
        "二十六",
        "二十七",
        "二十八",
        "二十九",
        "三十",
        "三十一",
        "三十二",
        "三十三",
        "三十四",
        "三十五",
        "三十六",
        "三十七",
        "三十八",
        "三十九",
        "四十",
        "四十一",
        "四十二",
        "四十三",
        "四十四",
        "四十五",
      ];
      return data.sort((a, b) => {
        // 提取病区名称中的中文数字部分
        const getIndex = (name) => {
          if (!name || typeof name !== "string") return -1;
          // 匹配中文数字
          const chineseMatch = name.match(/^([一二三四五六七八九十]+)/);
          if (chineseMatch && chineseMatch[1]) {
            return order.indexOf(chineseMatch[1]);
          }
          // 匹配阿拉伯数字
          const arabicMatch = name.match(/^(\d+)/);
          if (arabicMatch && arabicMatch[1]) {
            const num = parseInt(arabicMatch[1], 10);
            if (num >= 1 && num <= 45) {
              return num - 1; // 因为数组索引从0开始
            }
          }
          return -1;
        };
        const indexA = getIndex(a.leavehospitaldistrictname);
        const indexB = getIndex(b.leavehospitaldistrictname);
        // 排序逻辑
        if (indexA === -1 && indexB === -1) {
          return (a.leavehospitaldistrictname || "").localeCompare(
            b.leavehospitaldistrictname || ""
          );
        }
        if (indexA === -1) return 1;
        if (indexB === -1) return -1;
        return indexA - indexB;
      });
    },
    // 处理统计类型变化
    handleStatisticalTypeChange(value) {
      if (value === 1) {
@@ -534,7 +738,7 @@
        serviceType: [2],
        dateRange: [],
        pageNum: 1,
        pageSize: 20
        pageSize: 20,
      };
      this.getList();
    },
@@ -554,7 +758,7 @@
    // 处理行选择
    handleSelectionChange(selection) {
      this.ids = selection.map(item => item.id);
      this.ids = selection.map((item) => item.id);
      this.single = selection.length !== 1;
      this.multiple = !selection.length;
    },
@@ -568,9 +772,9 @@
    // 格式化百分比
    formatPercent(value) {
      if (value === null || value === undefined) return '-';
      if (value === null || value === undefined) return "-";
      const num = parseFloat(value);
      if (isNaN(num)) return '-';
      if (isNaN(num)) return "-";
      return `${(num * 100).toFixed(2)}%`;
    },
@@ -583,17 +787,19 @@
    // 查看满意度详情
    async getinfo(row) {
      this.currentRow = row;
      this.topicVisible = true;
      try {
        // 处理查询参数
        const params = {
          configKey: "joyCount",
          ...this.queryParams
          ...this.queryParams,
        };
        // 处理日期范围
        if (this.queryParams.dateRange && this.queryParams.dateRange.length === 2) {
        if (
          this.queryParams.dateRange &&
          this.queryParams.dateRange.length === 2
        ) {
          params.startTime = this.queryParams.dateRange[0];
          params.endTime = this.queryParams.dateRange[1];
        }
@@ -608,16 +814,18 @@
        const response = await getSfStatisticsJoyInfo(params);
        this.topiclist = response.data || [];
      this.topicVisible = true;
      } catch (error) {
        console.error('获取满意度详情失败:', error);
        this.$message.error('获取详情失败');
        console.error("获取满意度详情失败:", error);
        this.$message.error("获取详情失败");
      }
    },
    // 导出数据
    async handleExport() {
      if (!this.userList.length) {
        this.$message.warning('没有数据可导出');
        this.$message.warning("没有数据可导出");
        return;
      }
@@ -628,7 +836,10 @@
        let dateRangeString = "";
        let sheetNameSuffix = "";
        if (this.queryParams.dateRange && this.queryParams.dateRange.length === 2) {
        if (
          this.queryParams.dateRange &&
          this.queryParams.dateRange.length === 2
        ) {
          const startDateFormatted = this.queryParams.dateRange[0];
          const endDateFormatted = this.queryParams.dateRange[1];
          dateRangeString = `${startDateFormatted}至${endDateFormatted}`;
@@ -650,26 +861,34 @@
        // 定义样式
        const titleStyle = {
          font: { name: "微软雅黑", size: 16, bold: true },
          fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FFE6F3FF" } },
          fill: {
            type: "pattern",
            pattern: "solid",
            fgColor: { argb: "FFE6F3FF" },
          },
          alignment: { vertical: "middle", horizontal: "center" },
          border: {
            top: { style: "thin", color: { argb: "FFD0D0D0" } },
            left: { style: "thin", color: { argb: "FFD0D0D0" } },
            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
            right: { style: "thin", color: { argb: "FFD0D0D0" } }
          }
            right: { style: "thin", color: { argb: "FFD0D0D0" } },
          },
        };
        const headerStyle = {
          font: { name: "微软雅黑", size: 11, bold: true },
          fill: { type: "pattern", pattern: "solid", fgColor: { argb: "FFF5F7FA" } },
          fill: {
            type: "pattern",
            pattern: "solid",
            fgColor: { argb: "FFF5F7FA" },
          },
          alignment: { vertical: "middle", horizontal: "center" },
          border: {
            top: { style: "thin", color: { argb: "FFD0D0D0" } },
            left: { style: "thin", color: { argb: "FFD0D0D0" } },
            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
            right: { style: "thin", color: { argb: "FFD0D0D0" } }
          }
            right: { style: "thin", color: { argb: "FFD0D0D0" } },
          },
        };
        const cellStyle = {
@@ -679,8 +898,8 @@
            top: { style: "thin", color: { argb: "FFD0D0D0" } },
            left: { style: "thin", color: { argb: "FFD0D0D0" } },
            bottom: { style: "thin", color: { argb: "FFD0D0D0" } },
            right: { style: "thin", color: { argb: "FFD0D0D0" } }
          }
            right: { style: "thin", color: { argb: "FFD0D0D0" } },
          },
        };
        // 添加总标题
@@ -700,7 +919,7 @@
          "及时率",
          "满意度题目总量",
          "满意度填报量",
          "完成比率"
          "完成比率",
        ];
        const headerRow = worksheet.addRow(headers);
@@ -712,7 +931,9 @@
        // 添加数据行
        this.userList.forEach((item) => {
          const dataRow = worksheet.addRow([
            this.queryParams.statisticaltype == 1 ? item.leavehospitaldistrictname : item.deptname,
            this.queryParams.statisticaltype == 1
              ? item.leavehospitaldistrictname
              : item.deptname,
            item.dischargeCount || 0,
            item.nonFollowUp || 0,
            item.followUpNeeded || 0,
@@ -720,7 +941,7 @@
            item.rate ? this.formatPercent(item.rate) : "0%",
            item.joyAllCount || 0,
            item.joyCount || 0,
            item.joyTotal ? this.formatPercent(item.joyTotal) : "0%"
            item.joyTotal ? this.formatPercent(item.joyTotal) : "0%",
          ]);
          dataRow.eachCell((cell) => {
@@ -739,13 +960,13 @@
          { width: 12 },
          { width: 15 },
          { width: 15 },
          { width: 12 }
          { width: 12 },
        ];
        // 生成并下载文件
        const buffer = await workbook.xlsx.writeBuffer();
        const blob = new Blob([buffer], {
          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        });
        saveAs(blob, excelName);
@@ -756,8 +977,8 @@
      } finally {
        this.loading = false;
      }
    }
  }
    },
  },
};
</script>