| | |
| | | plain |
| | | icon="el-icon-download" |
| | | size="medium" |
| | | @click="handleExport" |
| | | @click="exportTable" |
| | | >导出</el-button |
| | | > |
| | | <el-button |
| | |
| | | </el-form> |
| | | <div class="your-table-container"> |
| | | <el-table |
| | | ref="exportTable" |
| | | id="exportTableid" |
| | | v-loading="loading" |
| | | :data="userList" |
| | | :border="true" |
| | |
| | | } from "@/api/system/label"; |
| | | import store from "@/store"; |
| | | import { getSfStatistics, selectTimelyRate } from "@/api/system/user"; |
| | | |
| | | import * as XLSX from "xlsx"; |
| | | import FileSaver from "file-saver"; |
| | | import ExcelJS from "exceljs"; |
| | | import { saveAs } from "file-saver"; |
| | | import Treeselect from "@riophae/vue-treeselect"; |
| | | import "@riophae/vue-treeselect/dist/vue-treeselect.css"; |
| | | const shortcuts = [ |
| | |
| | | sums[index] = "合计"; |
| | | return; |
| | | } |
| | | if (index === 1||index === 2) { |
| | | if (index === 1 || index === 2) { |
| | | sums[index] = "/"; |
| | | return; |
| | | } |
| | |
| | | }) |
| | | .catch(() => {}); |
| | | }, |
| | | /** 导出按钮操作 */ |
| | | handleExport() { |
| | | const params = { |
| | | ...this.queryParams, |
| | | // 如果选择了"全部",则传所有病区/科室代码 |
| | | leavehospitaldistrictcodes: |
| | | this.queryParams.leavehospitaldistrictcodes.includes("all") |
| | | ? this.allWardCodes |
| | | : this.queryParams.leavehospitaldistrictcodes, |
| | | deptcodes: this.queryParams.deptcodes.includes("all") |
| | | ? this.allDeptCodes |
| | | : this.queryParams.deptcodes, |
| | | }; |
| | | delete params.leavehospitaldistrictcodes.all; |
| | | delete params.deptcodes.all; |
| | | console.log(params); |
| | | // 导出方法 |
| | | // 替换您原来的 exportTable 方法 |
| | | async exportTable() { |
| | | try { |
| | | // 获取当前日期 |
| | | const now = new Date(); |
| | | // 获取当前月份(注意月份从0开始,需要加1) |
| | | const currentMonth = now.getMonth() + 1; |
| | | // 构建文件名 |
| | | const excelName = `${currentMonth}月出院随访统计表.xlsx`; |
| | | // 创建新的工作簿和工作表 |
| | | const workbook = new ExcelJS.Workbook(); |
| | | const worksheet = workbook.addWorksheet("随访统计"); |
| | | |
| | | this.download( |
| | | "smartor/serviceSubtask/getSfStatisticsExport", |
| | | { |
| | | ...params, |
| | | }, |
| | | `user_${new Date().getTime()}.xlsx` |
| | | ); |
| | | // 定义样式 |
| | | const headerStyle = { |
| | | 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" } }, |
| | | }, |
| | | }; |
| | | |
| | | const cellStyle = { |
| | | font: { |
| | | name: "宋体", |
| | | size: 10, |
| | | color: { argb: "FF000000" }, |
| | | }, |
| | | 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 summaryStyle = { |
| | | 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" } }, |
| | | }, |
| | | }; |
| | | |
| | | // 1. 首先,创建并设置第二行(子表头)的所有单元格 |
| | | const secondRowHeaders = [ |
| | | "", // A2 展开列占位(其值将由第一行合并后的主单元格决定) |
| | | "出院病区", |
| | | "科室", |
| | | "出院人次", |
| | | "无需随访人次", |
| | | "应随访人次", // B2 to F2 |
| | | // 首次出院随访子表头 |
| | | "需随访", |
| | | "待随访", |
| | | "随访成功", |
| | | "随访失败", |
| | | "随访率", |
| | | "及时率", |
| | | "人工", |
| | | "短信", |
| | | "微信", |
| | | // 再次出院随访子表头 |
| | | "需随访", |
| | | "待随访", |
| | | "随访成功", |
| | | "随访失败", |
| | | "随访率", |
| | | "人工", |
| | | "短信", |
| | | "微信", |
| | | ]; |
| | | |
| | | // 添加第二行并设置样式 |
| | | secondRowHeaders.forEach((header, index) => { |
| | | // 注意:列索引从1开始,对应A列是1,B列是2,以此类推。 |
| | | const cell = worksheet.getCell(2, index + 1); |
| | | cell.value = header; |
| | | cell.style = headerStyle; |
| | | }); |
| | | |
| | | // 2. 然后,创建第一行的主标题单元格并设置样式,紧接着进行纵向合并 |
| | | // 合并 A1:A2 并设置值 |
| | | worksheet.mergeCells(1, 1, 2, 1); // 合并 A1 到 A2 |
| | | worksheet.getCell(1, 1).value = ""; // 设置主单元格(A1)的值 |
| | | worksheet.getCell(1, 1).style = headerStyle; // 设置主单元格样式 |
| | | |
| | | // 合并 B1:B2 并设置值 |
| | | worksheet.mergeCells(1, 2, 2, 2); // 合并 B1 到 B2 |
| | | worksheet.getCell(1, 2).value = "出院病区"; |
| | | worksheet.getCell(1, 2).style = headerStyle; |
| | | |
| | | // 合并 C1:C2 并设置值 |
| | | worksheet.mergeCells(1, 3, 2, 3); // 合并 C1 到 C2 |
| | | worksheet.getCell(1, 3).value = "科室"; |
| | | worksheet.getCell(1, 3).style = headerStyle; |
| | | |
| | | // 合并 D1:D2 并设置值 |
| | | worksheet.mergeCells(1, 4, 2, 4); // 合并 D1 到 D2 |
| | | worksheet.getCell(1, 4).value = "出院人次"; |
| | | worksheet.getCell(1, 4).style = headerStyle; |
| | | |
| | | // 合并 E1:E2 并设置值 |
| | | worksheet.mergeCells(1, 5, 2, 5); // 合并 E1 到 E2 |
| | | worksheet.getCell(1, 5).value = "无需随访人次"; |
| | | worksheet.getCell(1, 5).style = headerStyle; |
| | | |
| | | // 合并 F1:F2 并设置值 |
| | | worksheet.mergeCells(1, 6, 2, 6); // 合并 F1 到 F2 |
| | | worksheet.getCell(1, 6).value = "应随访人次"; |
| | | worksheet.getCell(1, 6).style = headerStyle; |
| | | |
| | | // 3. 设置第一行的横向合并标题(这些保持不变,因为只涉及第一行) |
| | | // 首次出院随访(合并G1到O1) |
| | | worksheet.mergeCells("G1:O1"); |
| | | worksheet.getCell("G1").value = "首次出院随访"; |
| | | worksheet.getCell("G1").style = headerStyle; |
| | | |
| | | // 再次出院随访(合并P1到W1) |
| | | worksheet.mergeCells("P1:W1"); |
| | | worksheet.getCell("P1").value = "再次出院随访"; |
| | | worksheet.getCell("P1").style = headerStyle; |
| | | |
| | | // 4. 设置行高(可选,但建议设置) |
| | | worksheet.getRow(1).height = 28; // 第一行行高 |
| | | worksheet.getRow(2).height = 25; // 第二行行高 |
| | | |
| | | // 添加数据行 |
| | | this.userList.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, |
| | | // 再次出院随访数据 |
| | | item.needFollowUpAgain || 0, |
| | | item.pendingFollowUpAgain || 0, |
| | | item.followUpSuccessAgain || 0, |
| | | item.followUpFailAgain || 0, |
| | | item.followUpRateAgain || "0%", |
| | | item.manualAgain || 0, |
| | | item.smsAgain || 0, |
| | | item.weChatAgain || 0, |
| | | ]); |
| | | |
| | | // 应用数据行样式 |
| | | dataRow.eachCell((cell) => { |
| | | cell.style = cellStyle; |
| | | }); |
| | | dataRow.height = 24; |
| | | }); |
| | | |
| | | // 添加合计行 |
| | | const summaries = this.getSummaries({ |
| | | columns: [ |
| | | { property: "" }, |
| | | { property: "leavehospitaldistrictname" }, |
| | | { property: "deptname" }, |
| | | { property: "dischargeCount" }, |
| | | { property: "nonFollowUp" }, |
| | | { property: "followUpNeeded" }, |
| | | { property: "needFollowUp" }, |
| | | { property: "pendingFollowUp" }, |
| | | { property: "followUpSuccess" }, |
| | | { property: "followUpFail" }, |
| | | { property: "followUpRate" }, |
| | | { property: "rate" }, |
| | | { property: "manual" }, |
| | | { property: "sms" }, |
| | | { property: "weChat" }, |
| | | { property: "needFollowUpAgain" }, |
| | | { property: "pendingFollowUpAgain" }, |
| | | { property: "followUpSuccessAgain" }, |
| | | { property: "followUpFailAgain" }, |
| | | { property: "followUpRateAgain" }, |
| | | { property: "manualAgain" }, |
| | | { property: "smsAgain" }, |
| | | { property: "weChatAgain" }, |
| | | ], |
| | | data: this.userList, |
| | | }); |
| | | |
| | | const summaryRow = worksheet.addRow(summaries); |
| | | summaryRow.eachCell((cell, colNumber) => { |
| | | cell.style = summaryStyle; |
| | | // 第一列显示"合计" |
| | | if (colNumber === 1) { |
| | | cell.value = "合计"; |
| | | } |
| | | }); |
| | | 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: 10 }, |
| | | { width: 10 }, |
| | | { width: 10 }, |
| | | { width: 10 }, |
| | | { width: 12 }, |
| | | { width: 8 }, |
| | | { width: 8 }, |
| | | { width: 8 }, |
| | | ]; |
| | | |
| | | // 生成并下载文件 |
| | | const buffer = await workbook.xlsx.writeBuffer(); |
| | | const blob = new Blob([buffer], { |
| | | type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", |
| | | }); |
| | | saveAs(blob, excelName); |
| | | |
| | | this.$message.success("导出成功"); |
| | | return true; |
| | | } catch (error) { |
| | | console.error("导出失败:", error); |
| | | this.$message.error(`导出失败: ${error.message}`); |
| | | return false; |
| | | } |
| | | }, |
| | | |
| | | // 显示图表弹窗 |
| | | |
| | | showChartDialog() { |
| | |
| | | } |
| | | |
| | | // 百分比字段特殊样式 |
| | | .your-table-container ::v-deep .el-table__footer .el-table__cell[data-field="followUpRate"] .cell, |
| | | .your-table-container ::v-deep .el-table__footer .el-table__cell[data-field="rate"] .cell, |
| | | .your-table-container ::v-deep .el-table__footer .el-table__cell[data-field="followUpRateAgain"] .cell { |
| | | .your-table-container |
| | | ::v-deep |
| | | .el-table__footer |
| | | .el-table__cell[data-field="followUpRate"] |
| | | .cell, |
| | | .your-table-container |
| | | ::v-deep |
| | | .el-table__footer |
| | | .el-table__cell[data-field="rate"] |
| | | .cell, |
| | | .your-table-container |
| | | ::v-deep |
| | | .el-table__footer |
| | | .el-table__cell[data-field="followUpRateAgain"] |
| | | .cell { |
| | | color: #e6a23c !important; |
| | | font-weight: 700 !important; |
| | | } |