| ¶Ô±ÈÐÂÎļþ |
| | |
| | | <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: "joyCount", |
| | | ...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" |
| | | ); |
| | | // 妿éè¦ä¼ ææç
åºä»£ç ï¼å¯ä»¥ä»storeä¸è·å |
| | | 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" |
| | | ); |
| | | // 妿éè¦ä¼ ææç§å®¤ä»£ç ï¼å¯ä»¥ä»storeä¸è·å |
| | | 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); |
| | | |
| | | // å¤çæ æ³è§£æçæ
åµ |
| | | 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; |
| | | }, |
| | | |
| | | // è·åè¡key |
| | | 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: "joyCount", |
| | | ...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 || []; |
| | | 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> |