From fbb61549bf96e9e0910b676a5524b0760d29c4be Mon Sep 17 00:00:00 2001
From: WXL (wul) <wl_5969728@163.com>
Date: 星期二, 07 四月 2026 15:16:54 +0800
Subject: [PATCH] 测试完成
---
src/views/Satisfaction/sfstatistics/components/visitStatistics.vue | 1030 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 1,030 insertions(+), 0 deletions(-)
diff --git a/src/views/Satisfaction/sfstatistics/components/visitStatistics.vue b/src/views/Satisfaction/sfstatistics/components/visitStatistics.vue
new file mode 100644
index 0000000..1b77e5a
--- /dev/null
+++ b/src/views/Satisfaction/sfstatistics/components/visitStatistics.vue
@@ -0,0 +1,1030 @@
+<template>
+ <div class="followup-statistics">
+ <div class="query-section">
+ <el-form
+ :model="queryParams"
+ ref="queryForm"
+ size="medium"
+ :inline="true"
+ label-width="100px"
+ class="query-form"
+ >
+ <el-form-item label="缁熻绫诲瀷" prop="statisticaltype">
+ <el-select
+ v-model="queryParams.statisticaltype"
+ placeholder="璇烽�夋嫨缁熻绫诲瀷"
+ clearable
+ @change="handleStatisticalTypeChange"
+ >
+ <el-option
+ v-for="item in Statisticallist"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+
+ <!-- 鐥呭尯閫夋嫨 -->
+ <el-form-item
+ v-if="queryParams.statisticaltype == 1"
+ label="鐥呭尯"
+ prop="leavehospitaldistrictcodes"
+ >
+ <el-select
+ v-model="queryParams.leavehospitaldistrictcodes"
+ placeholder="璇烽�夋嫨鐥呭尯"
+ multiple
+ collapse-tags
+ filterable
+ clearable
+ style="width: 300px"
+ >
+ <el-option
+ v-for="item in flatArrayhospit"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+
+ <!-- 绉戝閫夋嫨 -->
+ <el-form-item
+ v-if="queryParams.statisticaltype == 2"
+ label="绉戝"
+ prop="deptcodes"
+ >
+ <el-select
+ v-model="queryParams.deptcodes"
+ placeholder="璇烽�夋嫨绉戝"
+ multiple
+ collapse-tags
+ filterable
+ clearable
+ style="width: 300px"
+ >
+ <el-option
+ v-for="item in flatArraydept"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+
+ <el-form-item label="鏈嶅姟绫诲瀷" prop="serviceType">
+ <el-select
+ v-model="queryParams.serviceType"
+ placeholder="璇烽�夋嫨鏈嶅姟绫诲瀷"
+ multiple
+ collapse-tags
+ clearable
+ style="width: 300px"
+ >
+ <el-option
+ v-for="item in options"
+ :key="item.value"
+ :label="item.label"
+ :value="item.value"
+ />
+ </el-select>
+ </el-form-item>
+
+ <el-form-item label="闅忚鏃堕棿" prop="dateRange">
+ <el-date-picker
+ v-model="queryParams.dateRange"
+ type="daterange"
+ range-separator="鑷�"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ value-format="yyyy-MM-dd"
+ :picker-options="pickerOptions"
+ style="width: 380px"
+ />
+ </el-form-item>
+
+ <el-form-item>
+ <el-button
+ type="primary"
+ icon="el-icon-search"
+ @click="handleQuery"
+ :loading="loading"
+ >
+ 鎼滅储
+ </el-button>
+ <el-button icon="el-icon-refresh" @click="resetQuery">
+ 閲嶇疆
+ </el-button>
+ <el-button
+ type="warning"
+ icon="el-icon-download"
+ @click="handleExport"
+ :disabled="!userList.length"
+ >
+ 瀵煎嚭
+ </el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+
+ <div class="table-section">
+ <el-table
+ v-loading="loading"
+ :data="userList"
+ :border="true"
+ style="width: 100%"
+ @selection-change="handleSelectionChange"
+ :row-key="getRowKey"
+ >
+ <!-- 鐥呭尯鍒� -->
+ <el-table-column
+ v-if="queryParams.statisticaltype == 1"
+ label="鍑洪櫌鐥呭尯"
+ align="center"
+ sortable
+ key="leavehospitaldistrictname"
+ prop="leavehospitaldistrictname"
+ :show-overflow-tooltip="true"
+ :sort-method="sortChineseNumber"
+ min-width="120"
+ />
+
+ <!-- 绉戝鍒� -->
+ <el-table-column
+ v-if="queryParams.statisticaltype == 2"
+ label="绉戝"
+ align="center"
+ key="deptname"
+ prop="deptname"
+ :show-overflow-tooltip="true"
+ min-width="120"
+ />
+
+ <el-table-column
+ label="鍑洪櫌浜烘"
+ align="center"
+ key="dischargeCount"
+ prop="dischargeCount"
+ min-width="100"
+ />
+
+ <el-table-column
+ label="鏃犻渶闅忚浜烘"
+ align="center"
+ key="nonFollowUp"
+ prop="nonFollowUp"
+ min-width="120"
+ />
+
+ <el-table-column
+ label="搴旈殢璁夸汉娆�"
+ align="center"
+ key="followUpNeeded"
+ prop="followUpNeeded"
+ min-width="120"
+ />
+
+ <el-table-column
+ label="闅忚鐜�"
+ align="center"
+ key="followUpRate"
+ prop="followUpRate"
+ min-width="100"
+ >
+ <template slot-scope="scope">
+ <span
+ v-if="
+ scope.row.followUpRate !== null &&
+ scope.row.followUpRate !== undefined
+ "
+ >
+ {{ scope.row.followUpRate }}
+ </span>
+ <span v-else>-</span>
+ </template>
+ </el-table-column>
+
+ <el-table-column
+ label="鍙婃椂鐜�"
+ align="center"
+ key="rate"
+ prop="rate"
+ min-width="100"
+ >
+ <template slot-scope="scope">
+ <el-button
+ v-if="scope.row.rate !== null && scope.row.rate !== undefined"
+ type="text"
+ @click="handleSeedetails(scope.row)"
+ >
+ {{ formatPercent(scope.row.rate) }}
+ </el-button>
+ <span v-else style="color: #909399">-</span>
+ </template>
+ </el-table-column>
+
+ <el-table-column
+ label="澶嶈瘖閫氱煡棰樼洰鎬婚噺"
+ align="center"
+ key="joyAllCount"
+ prop="joyAllCount"
+ min-width="140"
+ />
+
+ <el-table-column
+ label="澶嶈瘖閫氱煡濉姤閲�"
+ align="center"
+ key="joyCount"
+ prop="joyCount"
+ min-width="120"
+ />
+
+ <el-table-column
+ label="瀹屾垚姣旂巼"
+ align="center"
+ key="joyTotal"
+ prop="joyTotal"
+ min-width="100"
+ >
+ <template slot-scope="scope">
+ <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">
+ <template slot-scope="scope">
+ <el-button type="text" @click="getinfo(scope.row)">
+ <i class="el-icon-s-order" style="margin-right: 4px"></i>
+ 鏌ョ湅璇︽儏
+ </el-button>
+ </template>
+ </el-table-column>
+ </el-table>
+ </div>
+
+ <!-- 鍒嗛〉 -->
+ <div class="pagination-section" v-if="total > 0">
+ <el-pagination
+ background
+ layout="total, sizes, prev, pager, next, jumper"
+ :current-page="queryParams.pageNum"
+ :page-size="queryParams.pageSize"
+ :page-sizes="[10, 20, 30, 50]"
+ :total="total"
+ @size-change="handleSizeChange"
+ @current-change="handlePageChange"
+ />
+ </div>
+
+ <!-- 鏈強鏃堕殢璁胯鎯呭璇濇 -->
+ <el-dialog
+ title="鏈強鏃堕殢璁挎偅鑰呮湇鍔�"
+ :visible.sync="SeedetailsVisible"
+ width="80%"
+ :close-on-click-modal="false"
+ >
+ <SeedetailsDialog
+ v-if="SeedetailsVisible"
+ :row-data="currentRow"
+ :query-params="queryParams"
+ @close="SeedetailsVisible = false"
+ />
+ </el-dialog>
+
+ <!-- 澶嶈瘖閫氱煡璇︽儏瀵硅瘽妗� -->
+ <el-dialog
+ :visible.sync="topicVisible"
+ width="60%"
+ :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>
+ <span>{{ topicvalue.name }}</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"
+ />
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+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";
+
+export default {
+ name: "FollowupStatistics",
+ components: {
+ SeedetailsDialog,
+ TopicDialog,
+ },
+ data() {
+ return {
+ // 鏌ヨ鍙傛暟
+ queryParams: {
+ statisticaltype: 1,
+ leavehospitaldistrictcodes: ["all"],
+ deptcodes: [],
+ serviceType: [2],
+ dateRange: [],
+ pageNum: 1,
+ pageSize: 20,
+ },
+
+ // 缁熻绫诲瀷鍒楄〃
+ Statisticallist: [
+ { label: "鐥呭尯缁熻", value: 1 },
+ { label: "绉戝缁熻", value: 2 },
+ ],
+
+ // 鐥呭尯鍒楄〃
+ flatArrayhospit: [],
+
+ // 绉戝鍒楄〃
+ flatArraydept: [],
+
+ // 鏈嶅姟绫诲瀷閫夐」
+ options: [],
+
+ // 琛ㄦ牸鏁版嵁
+ userList: [],
+
+ // 鎬绘潯鏁�
+ total: 0,
+
+ // 鍔犺浇鐘舵��
+ loading: false,
+
+ // 閫変腑鐨勮
+ ids: [],
+ single: true,
+ multiple: true,
+
+ // 褰撳墠鎿嶄綔鐨勮
+ currentRow: null,
+
+ // 瀵硅瘽妗嗘樉绀烘帶鍒�
+ SeedetailsVisible: false,
+ topicVisible: false,
+
+ // 澶嶈瘖閫氱煡璇︽儏鏁版嵁
+ topiclist: [],
+ topicvalue: {
+ name: "",
+ },
+
+ // 鏃ユ湡閫夋嫨鍣ㄩ�夐」
+ pickerOptions: {
+ shortcuts: [
+ {
+ text: "鏈�杩戜竴鍛�",
+ onClick(picker) {
+ const end = new Date();
+ const start = new Date();
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
+ picker.$emit("pick", [start, end]);
+ },
+ },
+ {
+ text: "鏈�杩戜竴涓湀",
+ onClick(picker) {
+ const end = new Date();
+ const start = new Date();
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
+ picker.$emit("pick", [start, end]);
+ },
+ },
+ {
+ text: "鏈�杩戜笁涓湀",
+ onClick(picker) {
+ const end = new Date();
+ const start = new Date();
+ start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
+ picker.$emit("pick", [start, end]);
+ },
+ },
+ ],
+ disabledDate(time) {
+ return time.getTime() > Date.now();
+ },
+ },
+ };
+ },
+
+ created() {
+ this.initData();
+ },
+
+ methods: {
+ // 鍒濆鍖栨暟鎹�
+ async initData() {
+ await this.getDeptTree();
+ await this.getList();
+ },
+
+ // 鑾峰彇绉戝鏍�
+ getDeptTree() {
+ // 鑾峰彇鏈嶅姟绫诲瀷
+ this.options = this.$store.getters.tasktypes || [];
+
+ // 鑾峰彇绉戝鍒楄〃
+ 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.flatArraydept.push({ label: "鍏ㄩ儴", value: "all" });
+ this.flatArrayhospit.push({ label: "鍏ㄩ儴", value: "all" });
+ },
+
+ // 鑾峰彇缁熻鍒楄〃
+ async getList() {
+ this.loading = true;
+ try {
+ // 澶勭悊鏌ヨ鍙傛暟
+ const params = {
+ configKey: "returnVisitCount",
+ ...this.queryParams,
+ };
+
+ // 澶勭悊鏃ユ湡鑼冨洿
+ if (
+ this.queryParams.dateRange &&
+ this.queryParams.dateRange.length === 2
+ ) {
+ params.startTime = this.queryParams.dateRange[0];
+ params.endTime = this.queryParams.dateRange[1];
+ }
+
+ // 澶勭悊鐥呭尯/绉戝閫夋嫨
+ if (params.statisticaltype == 1) {
+ // 鐥呭尯缁熻
+ if (params.leavehospitaldistrictcodes.includes("all")) {
+ // 濡傛灉閫夋嫨浜�"鍏ㄩ儴"锛屽垯绉婚櫎"all"鍊�
+ params.leavehospitaldistrictcodes =
+ params.leavehospitaldistrictcodes.filter(
+ (item) => item !== "all"
+ );
+ // 濡傛灉闇�瑕佷紶鎵�鏈夌梾鍖轰唬鐮侊紝鍙互浠巗tore涓幏鍙�
+ 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"
+ );
+ // 濡傛灉闇�瑕佷紶鎵�鏈夌瀹や唬鐮侊紝鍙互浠巗tore涓幏鍙�
+ params.deptcodes = (this.$store.getters.belongDepts || []).map(
+ (dept) => dept.deptCode
+ );
+ }
+ }
+
+ const response = await getSfStatisticsJoy(params);
+ this.userList = this.customSort(response.data) || [];
+ this.total = response.total || 0;
+ } catch (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);
+
+ // 澶勭悊鏃犳硶瑙f瀽鐨勬儏鍐�
+ 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) {
+ this.queryParams.deptcodes = [];
+ } else {
+ this.queryParams.leavehospitaldistrictcodes = [];
+ }
+ this.queryParams.pageNum = 1;
+ this.getList();
+ },
+
+ // 澶勭悊鏌ヨ
+ handleQuery() {
+ this.queryParams.pageNum = 1;
+ this.getList();
+ },
+
+ // 閲嶇疆鏌ヨ
+ resetQuery() {
+ this.queryParams = {
+ statisticaltype: 1,
+ leavehospitaldistrictcodes: [],
+ deptcodes: [],
+ serviceType: [2],
+ dateRange: [],
+ pageNum: 1,
+ pageSize: 20,
+ };
+ this.getList();
+ },
+
+ // 澶勭悊鍒嗛〉澶у皬鍙樺寲
+ handleSizeChange(size) {
+ this.queryParams.pageSize = size;
+ this.queryParams.pageNum = 1;
+ this.getList();
+ },
+
+ // 澶勭悊椤电爜鍙樺寲
+ handlePageChange(page) {
+ this.queryParams.pageNum = page;
+ this.getList();
+ },
+
+ // 澶勭悊琛岄�夋嫨
+ handleSelectionChange(selection) {
+ this.ids = selection.map((item) => item.id);
+ this.single = selection.length !== 1;
+ this.multiple = !selection.length;
+ },
+
+ // 鑾峰彇琛宬ey
+ getRowKey(row) {
+ return row.statisticaltype === 1
+ ? row.leavehospitaldistrictcode
+ : row.deptcode;
+ },
+
+ // 鏍煎紡鍖栫櫨鍒嗘瘮
+ formatPercent(value) {
+ if (value === null || value === undefined) return "-";
+ const num = parseFloat(value);
+ if (isNaN(num)) return "-";
+ return `${(num * 100).toFixed(2)}%`;
+ },
+
+ // 鏌ョ湅鏈強鏃堕殢璁胯鎯�
+ handleSeedetails(row) {
+ this.currentRow = row;
+ this.SeedetailsVisible = true;
+ },
+
+ // 鏌ョ湅澶嶈瘖閫氱煡璇︽儏
+ async getinfo(row) {
+ this.currentRow = row;
+
+ try {
+ // 澶勭悊鏌ヨ鍙傛暟
+ const params = {
+ configKey: "returnVisitCount",
+ ...this.queryParams,
+ };
+
+ // 澶勭悊鏃ユ湡鑼冨洿
+ if (
+ this.queryParams.dateRange &&
+ this.queryParams.dateRange.length === 2
+ ) {
+ params.startTime = this.queryParams.dateRange[0];
+ params.endTime = this.queryParams.dateRange[1];
+ }
+
+ if (this.queryParams.statisticaltype == 1) {
+ this.topicvalue.name = row.leavehospitaldistrictname;
+ params.leavehospitaldistrictcodes = [row.leavehospitaldistrictcode];
+ } else {
+ this.topicvalue.name = row.deptname;
+ params.deptcodes = [row.deptcode];
+ }
+
+ const response = await getSfStatisticsJoyInfo(params);
+ this.topiclist = response.data || [];
+ console.log(this.topiclist);
+ this.topicVisible = true;
+ } catch (error) {
+ console.error("鑾峰彇澶嶈瘖閫氱煡璇︽儏澶辫触:", error);
+ this.$message.error("鑾峰彇璇︽儏澶辫触");
+ }
+ },
+
+ // 瀵煎嚭鏁版嵁
+ async handleExport() {
+ if (!this.userList.length) {
+ this.$message.warning("娌℃湁鏁版嵁鍙鍑�");
+ return;
+ }
+
+ try {
+ this.loading = true;
+
+ // 鏋勫缓鏃ユ湡鑼冨洿瀛楃涓�
+ let dateRangeString = "";
+ let sheetNameSuffix = "";
+
+ 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}`;
+ } else {
+ const now = new Date();
+ const currentMonth = now.getMonth() + 1;
+ dateRangeString = `${currentMonth}鏈坄;
+ sheetNameSuffix = `${currentMonth}鏈坄;
+ }
+
+ const excelName = `闅忚缁熻琛╛${dateRangeString}.xlsx`;
+ const worksheetName = `闅忚缁熻_${sheetNameSuffix}`;
+
+ // 鍒涘缓Excel宸ヤ綔绨�
+ const workbook = new ExcelJS.Workbook();
+ const worksheet = workbook.addWorksheet(worksheetName);
+
+ // 瀹氫箟鏍峰紡
+ const titleStyle = {
+ font: { name: "寰蒋闆呴粦", size: 16, bold: true },
+ 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" } },
+ },
+ };
+
+ const headerStyle = {
+ font: { name: "寰蒋闆呴粦", size: 11, bold: true },
+ 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" } },
+ },
+ };
+
+ const cellStyle = {
+ font: { name: "瀹嬩綋", size: 10 },
+ 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" } },
+ },
+ };
+
+ // 娣诲姞鎬绘爣棰�
+ worksheet.mergeCells(1, 1, 1, 10);
+ const titleCell = worksheet.getCell(1, 1);
+ titleCell.value = `闅忚缁熻琛紙${sheetNameSuffix}锛塦;
+ titleCell.style = titleStyle;
+ worksheet.getRow(1).height = 35;
+
+ // 娣诲姞琛ㄥご
+ const headers = [
+ this.queryParams.statisticaltype == 1 ? "鍑洪櫌鐥呭尯" : "绉戝",
+ "鍑洪櫌浜烘",
+ "鏃犻渶闅忚浜烘",
+ "搴旈殢璁夸汉娆�",
+ "闅忚鐜�",
+ "鍙婃椂鐜�",
+ "澶嶈瘖閫氱煡棰樼洰鎬婚噺",
+ "澶嶈瘖閫氱煡濉姤閲�",
+ "瀹屾垚姣旂巼",
+ ];
+
+ const headerRow = worksheet.addRow(headers);
+ headerRow.eachCell((cell) => {
+ cell.style = headerStyle;
+ });
+ headerRow.height = 25;
+
+ // 娣诲姞鏁版嵁琛�
+ this.userList.forEach((item) => {
+ const dataRow = worksheet.addRow([
+ this.queryParams.statisticaltype == 1
+ ? item.leavehospitaldistrictname
+ : item.deptname,
+ item.dischargeCount || 0,
+ item.nonFollowUp || 0,
+ item.followUpNeeded || 0,
+ item.followUpRate || "0%",
+ item.rate ? this.formatPercent(item.rate) : "0%",
+ item.joyAllCount || 0,
+ item.joyCount || 0,
+ item.joyTotal ? this.formatPercent(item.joyTotal) : "0%",
+ ]);
+
+ dataRow.eachCell((cell) => {
+ cell.style = cellStyle;
+ });
+ dataRow.height = 22;
+ });
+
+ // 璁剧疆鍒楀
+ worksheet.columns = [
+ { width: 20 },
+ { width: 12 },
+ { width: 12 },
+ { width: 12 },
+ { width: 12 },
+ { width: 12 },
+ { width: 15 },
+ { width: 15 },
+ { width: 12 },
+ ];
+
+ // 鐢熸垚骞朵笅杞芥枃浠�
+ const buffer = await workbook.xlsx.writeBuffer();
+ const blob = new Blob([buffer], {
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+ });
+
+ saveAs(blob, excelName);
+ this.$message.success("瀵煎嚭鎴愬姛");
+ } catch (error) {
+ console.error("瀵煎嚭澶辫触:", error);
+ this.$message.error(`瀵煎嚭澶辫触: ${error.message}`);
+ } finally {
+ this.loading = false;
+ }
+ },
+ },
+};
+</script>
+
+<style lang="scss" scoped>
+.followup-statistics {
+ .query-section {
+ background: #fff;
+ padding: 20px;
+ border-radius: 4px;
+ margin-bottom: 20px;
+
+ .query-form {
+ display: flex;
+ flex-wrap: wrap;
+
+ ::v-deep .el-form-item {
+ margin-bottom: 20px;
+
+ &:not(:last-child) {
+ margin-right: 20px;
+ }
+ }
+ }
+ }
+
+ .table-section {
+ background: #fff;
+ padding: 20px;
+ border-radius: 4px;
+ margin-bottom: 20px;
+
+ ::v-deep .el-table {
+ th {
+ background-color: #f8f9fa;
+ font-weight: 600;
+ color: #333;
+ }
+ }
+ }
+
+ .pagination-section {
+ display: flex;
+ justify-content: flex-end;
+ background: #fff;
+ padding: 20px;
+ border-radius: 4px;
+ }
+}
+</style>
--
Gitblit v1.9.3