| | |
| | | // 替换您原来的 exportTable 方法 |
| | | async exportTable() { |
| | | try { |
| | | // 获取当前日期 |
| | | const now = new Date(); |
| | | // 获取当前月份(注意月份从0开始,需要加1) |
| | | const currentMonth = now.getMonth() + 1; |
| | | // 构建文件名 |
| | | const excelName = `${currentMonth}月出院随访统计表.xlsx`; |
| | | // 1. 获取并格式化日期范围 |
| | | let dateRangeString = ""; // 用于文件名 |
| | | let sheetNameSuffix = ""; // 用于工作表名 |
| | | |
| | | // 检查是否存在选中的日期范围 |
| | | if ( |
| | | this.queryParams.dateRange && |
| | | this.queryParams.dateRange.length === 2 |
| | | ) { |
| | | const startDateStr = this.queryParams.dateRange[0]; // 开始日期字符串,例如 "2026-01-01 00:00:00" |
| | | const endDateStr = this.queryParams.dateRange[1]; // 结束日期字符串 |
| | | |
| | | // 格式化日期为 YYYY-MM-DD(去掉时间部分) |
| | | const formatDateForDisplay = (dateTimeStr) => { |
| | | return dateTimeStr.split(" ")[0]; // 取空格前的部分,即 "YYYY-MM-DD" |
| | | }; |
| | | |
| | | 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}月`; |
| | | } |
| | | |
| | | // 2. 动态构建文件名和工作表名 |
| | | const excelName = `出院随访统计表_${dateRangeString}.xlsx`; |
| | | const worksheetName = `随访统计_${sheetNameSuffix}`; // 工作表名不能超过31个字符[2](@ref) |
| | | // 创建新的工作簿和工作表 |
| | | const workbook = new ExcelJS.Workbook(); |
| | | const worksheet = workbook.addWorksheet(`${currentMonth}月出院随访统计表`); |
| | | // 定义样式(新增总标题样式) |
| | | const titleStyle = { |
| | | font: { |
| | | name: "微软雅黑", |
| | | size: 16, |
| | | bold: true, |
| | | color: { argb: "FF000000" }, |
| | | }, |
| | | fill: { |
| | | type: "pattern", |
| | | pattern: "solid", |
| | | fgColor: { argb: "FFE6F3FF" }, |
| | | }, |
| | | 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 worksheet = workbook.addWorksheet(worksheetName); // 使用动态工作表名 |
| | | // 定义样式(新增总标题样式) |
| | | const titleStyle = { |
| | | font: { |
| | | name: "微软雅黑", |
| | | size: 16, |
| | | bold: true, |
| | | color: { argb: "FF000000" }, |
| | | }, |
| | | fill: { |
| | | type: "pattern", |
| | | pattern: "solid", |
| | | fgColor: { argb: "FFE6F3FF" }, |
| | | }, |
| | | 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 headerStyle = { |
| | | font: { |
| | |
| | | right: { style: "thin", color: { argb: "FFD0D0D0" } }, |
| | | }, |
| | | }; |
| | | // 1. 添加总标题行(第一行) |
| | | worksheet.mergeCells(1, 1, 1, 23); // 合并A1到W1的所有列[1,4](@ref) |
| | | const titleCell = worksheet.getCell(1, 1); |
| | | titleCell.value = `${currentMonth}月出院随访统计表`; // 使用文件名作为总标题 |
| | | titleCell.style = titleStyle; |
| | | worksheet.getRow(1).height = 35; // 设置总标题行高 |
| | | // 1. 添加总标题行(第一行) |
| | | worksheet.mergeCells(1, 1, 1, 23); // 合并A1到W1的所有列[1,4](@ref) |
| | | const titleCell = worksheet.getCell(1, 1); |
| | | titleCell.value = `${sheetNameSuffix}出院随访统计表`; // 使用文件名作为总标题 |
| | | titleCell.style = titleStyle; |
| | | worksheet.getRow(1).height = 35; // 设置总标题行高 |
| | | // 1. 首先,创建并设置第二行(子表头)的所有单元格 |
| | | const secondRowHeaders = [ |
| | | "", // A2 展开列占位(其值将由第一行合并后的主单元格决定) |
| | |
| | | ]; |
| | | |
| | | // 添加第二行(原第一行下移) |
| | | secondRowHeaders.forEach((header, index) => { |
| | | const cell = worksheet.getCell(3, index + 1); // 改为第3行 |
| | | cell.value = header; |
| | | cell.style = headerStyle; |
| | | }); |
| | | secondRowHeaders.forEach((header, index) => { |
| | | const cell = worksheet.getCell(3, index + 1); // 改为第3行 |
| | | cell.value = header; |
| | | cell.style = headerStyle; |
| | | }); |
| | | |
| | | // 3. 调整原合并单元格位置(原第1行合并单元格下移到第2行) |
| | | // 合并 A2:A3 |
| | | worksheet.mergeCells(2, 1, 3, 1); |
| | | worksheet.getCell(2, 1).value = ""; |
| | | worksheet.getCell(2, 1).style = headerStyle; |
| | | // 3. 调整原合并单元格位置(原第1行合并单元格下移到第2行) |
| | | // 合并 A2:A3 |
| | | worksheet.mergeCells(2, 1, 3, 1); |
| | | worksheet.getCell(2, 1).value = ""; |
| | | worksheet.getCell(2, 1).style = headerStyle; |
| | | |
| | | // 合并 B2:B3 |
| | | worksheet.mergeCells(2, 2, 3, 2); |
| | | worksheet.getCell(2, 2).value = "出院病区"; |
| | | worksheet.getCell(2, 2).style = headerStyle; |
| | | // 合并 B2:B3 |
| | | worksheet.mergeCells(2, 2, 3, 2); |
| | | worksheet.getCell(2, 2).value = "出院病区"; |
| | | worksheet.getCell(2, 2).style = headerStyle; |
| | | |
| | | // 合并 C2:C3 |
| | | worksheet.mergeCells(2, 3, 3, 3); |
| | | worksheet.getCell(2, 3).value = "科室"; |
| | | worksheet.getCell(2, 3).style = headerStyle; |
| | | // 合并 C2:C3 |
| | | worksheet.mergeCells(2, 3, 3, 3); |
| | | worksheet.getCell(2, 3).value = "科室"; |
| | | worksheet.getCell(2, 3).style = headerStyle; |
| | | |
| | | // 合并 D2:D3 |
| | | worksheet.mergeCells(2, 4, 3, 4); |
| | | worksheet.getCell(2, 4).value = "出院人次"; |
| | | worksheet.getCell(2, 4).style = headerStyle; |
| | | // 合并 D2:D3 |
| | | worksheet.mergeCells(2, 4, 3, 4); |
| | | worksheet.getCell(2, 4).value = "出院人次"; |
| | | worksheet.getCell(2, 4).style = headerStyle; |
| | | |
| | | // 合并 E2:E3 |
| | | worksheet.mergeCells(2, 5, 3, 5); |
| | | worksheet.getCell(2, 5).value = "无需随访人次"; |
| | | worksheet.getCell(2, 5).style = headerStyle; |
| | | // 合并 E2:E3 |
| | | worksheet.mergeCells(2, 5, 3, 5); |
| | | worksheet.getCell(2, 5).value = "无需随访人次"; |
| | | worksheet.getCell(2, 5).style = headerStyle; |
| | | |
| | | // 合并 F2:F3 |
| | | worksheet.mergeCells(2, 6, 3, 6); |
| | | worksheet.getCell(2, 6).value = "应随访人次"; |
| | | worksheet.getCell(2, 6).style = headerStyle; |
| | | // 合并 F2:F3 |
| | | worksheet.mergeCells(2, 6, 3, 6); |
| | | worksheet.getCell(2, 6).value = "应随访人次"; |
| | | worksheet.getCell(2, 6).style = headerStyle; |
| | | |
| | | // 4. 调整横向合并标题位置(下移到第2行) |
| | | // 首次出院随访(合并G2:O2) |
| | | worksheet.mergeCells(2, 7, 2, 15); // G2:O2 |
| | | worksheet.getCell(2, 7).value = "首次出院随访"; |
| | | worksheet.getCell(2, 7).style = headerStyle; |
| | | // 4. 调整横向合并标题位置(下移到第2行) |
| | | // 首次出院随访(合并G2:O2) |
| | | worksheet.mergeCells(2, 7, 2, 15); // G2:O2 |
| | | worksheet.getCell(2, 7).value = "首次出院随访"; |
| | | worksheet.getCell(2, 7).style = headerStyle; |
| | | |
| | | // 再次出院随访(合并P2:W2) |
| | | worksheet.mergeCells(2, 16, 2, 23); // P2:W2 |
| | | worksheet.getCell(2, 16).value = "再次出院随访"; |
| | | worksheet.getCell(2, 16).style = headerStyle; |
| | | // 再次出院随访(合并P2:W2) |
| | | worksheet.mergeCells(2, 16, 2, 23); // P2:W2 |
| | | worksheet.getCell(2, 16).value = "再次出院随访"; |
| | | worksheet.getCell(2, 16).style = headerStyle; |
| | | |
| | | // 5. 设置行高 |
| | | worksheet.getRow(1).height = 35; // 总标题行高 |
| | | worksheet.getRow(2).height = 28; // 原第一行下移 |
| | | worksheet.getRow(3).height = 25; // 原第二行下移 |
| | | // 5. 设置行高 |
| | | worksheet.getRow(1).height = 35; // 总标题行高 |
| | | worksheet.getRow(2).height = 28; // 原第一行下移 |
| | | worksheet.getRow(3).height = 25; // 原第二行下移 |
| | | |
| | | // 6. 添加数据行(注意行索引需要+1,因为上面插入了一行) |
| | | 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, |
| | | ], rowIndex + 4); // 从第4行开始添加数据(原第3行) |
| | | // 6. 添加数据行(注意行索引需要+1,因为上面插入了一行) |
| | | 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, |
| | | ], |
| | | rowIndex + 4 |
| | | ); // 从第4行开始添加数据(原第3行) |
| | | |
| | | // 应用数据行样式 |
| | | dataRow.eachCell((cell) => { |
| | | cell.style = cellStyle; |
| | | }); |
| | | dataRow.height = 24; |
| | | }); |
| | | // 应用数据行样式 |
| | | dataRow.eachCell((cell) => { |
| | | cell.style = cellStyle; |
| | | }); |
| | | dataRow.height = 24; |
| | | }); |
| | | |
| | | // 添加合计行 |
| | | const summaries = this.getSummaries({ |