From 8b3dcf419b45e9655314e7d556a7417b6a619d92 Mon Sep 17 00:00:00 2001 From: LHD_HY <2872546851@qq.com> Date: Fri, 19 Dec 2025 17:38:19 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=88=E8=AE=A1=E5=88=92=E6=95=B4=E4=BD=93?= =?UTF-8?q?=E6=B1=87=E6=80=BB=E5=AF=BC=E5=87=BA=E6=8E=A5=E5=8F=A3=20?= =?UTF-8?q?=E6=9C=88=E8=AE=A1=E5=88=92=E5=B7=A5=E4=BD=9C=E9=87=8F=E5=AF=BC?= =?UTF-8?q?=E5=87=BA=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tool/ResourceSummaryExcelExporter.java | 232 ++++++++++ .../WorkloadAndCarSummaryExcelExporter.java | 195 ++++++++ .../controller/MonthlyPlanController.java | 41 +- .../digital/dao/CarUseSummaryExcelVo.java | 28 ++ .../bonus/digital/dao/CarUseTotalExcelVo.java | 26 ++ .../com/bonus/digital/dao/MonthlyPlanVo.java | 25 ++ .../digital/dao/ResourceSummaryExcelVo.java | 47 ++ .../bonus/digital/dao/ResourceSummaryVo.java | 88 ++++ .../digital/dao/WorkloadSummaryExcelVo.java | 32 ++ .../digital/dao/WorkloadTotalExcelVo.java | 25 ++ .../digital/mapper/MonthlyPlanMapper.java | 16 + .../digital/service/MonthlyPlanService.java | 10 +- .../service/impl/MonthlyPlanServiceImpl.java | 189 ++++++++ .../main/resources/mapper/MonthPlanMapper.xml | 422 ++++++++++++++++++ 14 files changed, 1372 insertions(+), 4 deletions(-) create mode 100644 bonus-business/src/main/java/com/bonus/business/controller/tool/ResourceSummaryExcelExporter.java create mode 100644 bonus-business/src/main/java/com/bonus/business/controller/tool/WorkloadAndCarSummaryExcelExporter.java create mode 100644 bonus-business/src/main/java/com/bonus/digital/dao/CarUseSummaryExcelVo.java create mode 100644 bonus-business/src/main/java/com/bonus/digital/dao/CarUseTotalExcelVo.java create mode 100644 bonus-business/src/main/java/com/bonus/digital/dao/ResourceSummaryExcelVo.java create mode 100644 bonus-business/src/main/java/com/bonus/digital/dao/ResourceSummaryVo.java create mode 100644 bonus-business/src/main/java/com/bonus/digital/dao/WorkloadSummaryExcelVo.java create mode 100644 bonus-business/src/main/java/com/bonus/digital/dao/WorkloadTotalExcelVo.java diff --git a/bonus-business/src/main/java/com/bonus/business/controller/tool/ResourceSummaryExcelExporter.java b/bonus-business/src/main/java/com/bonus/business/controller/tool/ResourceSummaryExcelExporter.java new file mode 100644 index 0000000..e4e5f5b --- /dev/null +++ b/bonus-business/src/main/java/com/bonus/business/controller/tool/ResourceSummaryExcelExporter.java @@ -0,0 +1,232 @@ +package com.bonus.business.controller.tool; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.merge.AbstractMergeStrategy; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; +import com.bonus.digital.dao.ResourceSummaryExcelVo; +import com.bonus.digital.dao.ResourceSummaryVo; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.math.BigDecimal; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +/** + * 月计划资源统计分析导出工具类(补全TotalDays/PersonCount兼容,新增运行视频/值班) + */ +public class ResourceSummaryExcelExporter { + + public static void export(HttpServletResponse response, + List dataList, + String month) throws IOException { + // 1. 拆分“运检站列表”和“汇总行”(最后一条是汇总) + List stationList = new ArrayList<>(); + ResourceSummaryVo summaryVo = null; + if (!dataList.isEmpty()) { + summaryVo = dataList.get(dataList.size() - 1); + if (dataList.size() > 1) { + stationList = dataList.subList(0, dataList.size() - 1); + } + } + + // 2. 按运检站分组 + Map stationMap = stationList.stream() + .collect(Collectors.toMap(ResourceSummaryVo::getInspectionStationName, vo -> vo)); + + // 3. 构造导出数据列表 + List exportList = new ArrayList<>(); + // 3.1 运检站表格 + for (ResourceSummaryVo stationData : stationMap.values()) { + exportList.addAll(buildStationRows(stationData)); + exportList.add(new ResourceSummaryExcelVo()); // 空行分隔 + } + // 3.2 汇总表(最后添加) + if (summaryVo != null) { + exportList.addAll(buildStationRows(summaryVo)); + } + + // 4. 响应头设置 + String sheetName = month + "月资源统计分析表"; + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + String fileName = URLEncoder.encode(sheetName, "UTF-8"); + response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); + + // 5. EasyExcel导出 + EasyExcel.write(response.getOutputStream(), ResourceSummaryExcelVo.class) + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) + .registerWriteHandler(new MergeStrategy(stationMap.size() + (summaryVo != null ? 1 : 0))) + .sheet(sheetName) + .doWrite(exportList); + } + + /** + * 构建单个运检站/汇总的表格行(保留TotalDays/PersonCount兼容,新增运行视频/值班) + */ + private static List buildStationRows(ResourceSummaryVo data) { + List rows = new ArrayList<>(); + // 1. 标题行 + ResourceSummaryExcelVo titleVo = new ResourceSummaryExcelVo(); + titleVo.setInspectionStationName(data.getInspectionStationName()); + rows.add(titleVo); + + // 2. 统计表头行(F列备注) + ResourceSummaryExcelVo statHeaderVo = new ResourceSummaryExcelVo(); + statHeaderVo.setRemark("备注"); + rows.add(statHeaderVo); + + // 3. 统计数值行 + ResourceSummaryExcelVo statValueVo = new ResourceSummaryExcelVo(); + statValueVo.setCompileNum(data.getCompileNum()); + statValueVo.setSecondmentNum(data.getSecondmentNum()); + statValueVo.setActualStationNum(data.getActualStationNum()); + rows.add(statValueVo); + + // 4. 子表头行 + ResourceSummaryExcelVo subHeaderVo = new ResourceSummaryExcelVo(); + rows.add(subHeaderVo); + + // 5. 类型行(按表格顺序,补全所有类型) + rows.add(buildTypeVo("休假", data.getRestWorkday(), data.getRestRatio(), data.getRestAvg(), null)); + rows.add(buildTypeVo("培训", data.getTrainWorkday(), data.getTrainRatio(), data.getTrainAvg(), null)); + rows.add(buildTypeVo("运行", data.getRunWorkday(), data.getRunRatio(), data.getRunAvg(), null)); + rows.add(buildTypeVo("运行(视频)", data.getRunVideoWorkday(), data.getRunVideoRatio(), data.getRunVideoAvg(), null)); + rows.add(buildTypeVo("检修", data.getMaintainWorkday(), data.getMaintainRatio(), data.getMaintainAvg(), null)); + rows.add(buildTypeVo("值班", data.getDutyWorkday(), data.getDutyRatio(), data.getDutyAvg(), null)); + rows.add(buildTypeVo("抢修", data.getRepairWorkday(), data.getRepairRatio(), data.getRepairAvg(), null)); + rows.add(buildTypeVo("学习", data.getStudyWorkday(), data.getStudyRatio(), data.getStudyAvg(), null)); + // 其他类型:F列固定写“长期支援不用统计” + rows.add(buildTypeVo("其他", data.getOtherWorkday(), data.getOtherRatio(), data.getOtherAvg(), "长期支援不用统计")); + rows.add(buildTypeVo("未安排", data.getUnarrangeWorkday(), data.getUnarrangeRatio(), data.getUnarrangeAvg(), null)); + + // 6. 分包用工行 + ResourceSummaryExcelVo subcontractVo = new ResourceSummaryExcelVo(); + subcontractVo.setType("分包用工"); + subcontractVo.setSubcontractWorkday(data.getSubcontractWorkday()); + rows.add(subcontractVo); + + return rows; + } + + /** + * 构建单个类型Vo(含备注,兼容原有字段) + */ + private static ResourceSummaryExcelVo buildTypeVo(String type, Integer workday, BigDecimal ratio, BigDecimal avg, String remark) { + ResourceSummaryExcelVo vo = new ResourceSummaryExcelVo(); + vo.setType(type); + vo.setWorkday(workday); + vo.setRatio(ratio); + vo.setAvg(avg); + vo.setRemark(remark); + return vo; + } + + /** + * 自定义合并策略(适配汇总+备注+新增类型) + */ + static class MergeStrategy extends AbstractMergeStrategy { + private final int totalStationCount; // 运检站+汇总总数 + private final int stationRowSize = 14; // 新增类型后,每个表格占用14行(原13行+运行视频) + + public MergeStrategy(int totalStationCount) { + this.totalStationCount = totalStationCount; + } + + @Override + protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { + int currentRow = cell.getRowIndex(); + int currentCol = cell.getColumnIndex(); + + for (int i = 0; i < totalStationCount; i++) { + int startRow = i * stationRowSize; + int endRow = startRow + 12; // 调整合并行范围 + + // 1. A列合并(运检站/汇总) + if (currentRow == startRow && currentCol == 0) { + CellRangeAddress merge = new CellRangeAddress(startRow, endRow, 0, 0); + sheet.addMergedRegion(merge); + setTitleStyle(cell, sheet.getWorkbook()); + } + + // 2. 资源统计分析标题合并(B1-D1) + if (currentRow == startRow + 1 && currentCol == 1) { + CellRangeAddress titleMerge = new CellRangeAddress(startRow + 1, startRow + 1, 1, 3); + sheet.addMergedRegion(titleMerge); + cell.setCellValue("资源统计分析"); + setTitleStyle(cell, sheet.getWorkbook()); + } + + // 3. 统计表头填充 + if (currentRow == startRow + 2) { + if (currentCol == 1) cell.setCellValue("编制人数"); + else if (currentCol == 2) cell.setCellValue("长期借调、支援人数"); + else if (currentCol == 3) cell.setCellValue("实际在站人数"); + setHeaderStyle(cell, sheet.getWorkbook()); + } + + // 4. 子表头填充 + if (currentRow == startRow + 4) { + if (currentCol == 1) cell.setCellValue("类型"); + else if (currentCol == 2) cell.setCellValue("工日"); + else if (currentCol == 3) cell.setCellValue("比值"); + else if (currentCol == 4) cell.setCellValue("人均"); + setHeaderStyle(cell, sheet.getWorkbook()); + } + + // 5. 分包用工合并 + if (currentRow == startRow + 13 && currentCol == 2) { + CellRangeAddress subMerge = new CellRangeAddress(startRow + 13, startRow + 13, 2, 4); + sheet.addMergedRegion(subMerge); + setTotalStyle(cell, sheet.getWorkbook()); + } + + // 6. 汇总表A列合并(第四行到第十四行) + if ("汇总".equals(sheet.getRow(startRow).getCell(0).getStringCellValue()) + && currentRow == startRow + 3 && currentCol == 0) { + CellRangeAddress summaryMerge = new CellRangeAddress(startRow + 3, startRow + 13, 0, 0); + sheet.addMergedRegion(summaryMerge); + setTitleStyle(cell, sheet.getWorkbook()); + } + } + } + + // 样式方法(复用原逻辑) + private void setTitleStyle(Cell cell, Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setBold(true); + font.setFontHeightInPoints((short) 14); + style.setFont(font); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + cell.setCellStyle(style); + } + + private void setHeaderStyle(Cell cell, Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setBold(true); + style.setFont(font); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + cell.setCellStyle(style); + } + + private void setTotalStyle(Cell cell, Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setBold(true); + style.setFont(font); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + cell.setCellStyle(style); + } + } +} diff --git a/bonus-business/src/main/java/com/bonus/business/controller/tool/WorkloadAndCarSummaryExcelExporter.java b/bonus-business/src/main/java/com/bonus/business/controller/tool/WorkloadAndCarSummaryExcelExporter.java new file mode 100644 index 0000000..5e0dc65 --- /dev/null +++ b/bonus-business/src/main/java/com/bonus/business/controller/tool/WorkloadAndCarSummaryExcelExporter.java @@ -0,0 +1,195 @@ +package com.bonus.business.controller.tool; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.merge.AbstractMergeStrategy; +import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy; +import com.bonus.digital.dao.CarUseSummaryExcelVo; +import com.bonus.digital.dao.CarUseTotalExcelVo; +import com.bonus.digital.dao.WorkloadSummaryExcelVo; +import com.bonus.digital.dao.WorkloadTotalExcelVo; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; + +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; + +/** + * 工作量+车辆清单合并导出工具类(匹配模板:左右分栏+合并单元格+自动求和) + * @author 马三炮 + * @date 2025/12/19 + */ +public class WorkloadAndCarSummaryExcelExporter { + + /** + * 导出合并Excel(左侧工作量清单+右侧车辆清单) + * @param response 响应流 + * @param workloadData 工作量数据列表 + * @param carData 车辆数据列表 + * @param month 计划月份(如:2025-11 → 11月份) + * @throws IOException 导出异常 + */ + public static void exportMergeSummary(HttpServletResponse response, + List workloadData, + List carData, + String month) throws IOException { + // 1. 计算工作量总计(合计列求和) + int workloadTotalAmount = workloadData.stream() + .mapToInt(WorkloadSummaryExcelVo::getTotalAmount) + .sum(); + // 2. 计算车辆总计(管理/分包用车天数求和) + int carTotalManage = carData.stream() + .mapToInt(CarUseSummaryExcelVo::getTotalManageCarDays) + .sum(); + int carTotalSub = carData.stream() + .mapToInt(CarUseSummaryExcelVo::getTotalSubCarDays) + .sum(); + + // 3. 构造最终导出列表(工作量数据+工作量合计+车辆数据+车辆合计) + List exportList = new ArrayList<>(); + // 3.1 工作量数据行 + exportList.addAll(workloadData); + // 3.2 工作量合计行 + WorkloadTotalExcelVo workloadTotalVo = new WorkloadTotalExcelVo(); + workloadTotalVo.setTotalLabel("合计"); + workloadTotalVo.setTotalAmountSum(workloadTotalAmount); + exportList.add(workloadTotalVo); + // 3.3 车辆数据行(补空行对齐行数) + int emptyRowCount = workloadData.size() + 1 - carData.size(); + for (int i = 0; i < emptyRowCount; i++) { + exportList.add(new CarUseSummaryExcelVo()); // 空行占位 + } + exportList.addAll(carData); + // 3.4 车辆合计行 + CarUseTotalExcelVo carTotalVo = new CarUseTotalExcelVo(); + carTotalVo.setTotalLabel("合计"); + carTotalVo.setTotalManageCarDaysSum(carTotalManage); + carTotalVo.setTotalSubCarDaysSum(carTotalSub); + exportList.add(carTotalVo); + + // 4. 设置响应头(下载Excel) + String sheetName = month + "月份工作量及用车清单"; + response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + response.setCharacterEncoding("utf-8"); + String fileName = URLEncoder.encode(sheetName, "UTF-8"); + response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx"); + + // 5. EasyExcel核心导出(自定义合并策略) + EasyExcel.write(response.getOutputStream()) + .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()) // 列宽自适应 + .registerWriteHandler(new MergeStrategy(workloadData.size(), carData.size())) // 合并策略 + .head(WorkloadSummaryExcelVo.class) // 主表头(工作量) + .includeColumnFiledNames(getAllColumnFields()) // 包含所有列(工作量+车辆) + .sheet(sheetName) + .doWrite(exportList); + } + + /** + * 获取所有列的字段名(工作量+车辆) + */ + private static List getAllColumnFields() { + List fields = new ArrayList<>(); + // 工作量列字段 + fields.add("serialNumber"); + fields.add("inspectionStationName"); + fields.add("workloadCategoryName"); + fields.add("totalWorkload"); + fields.add("unitPrice"); + fields.add("totalAmount"); + // 车辆列字段(从H列开始) + fields.add("serialNumber"); // 车辆序号(H列) + fields.add("inspectionStationName"); // 车辆运检站(I列) + fields.add("totalManageCarDays"); // 管理用车天数(J列) + fields.add("totalSubCarDays"); // 分包用车天数(K列) + return fields; + } + + /** + * 自定义合并策略:同时处理工作量+车辆清单的合并 + */ + static class MergeStrategy extends AbstractMergeStrategy { + private final int workloadDataRowCount; // 工作量数据行数 + private final int carDataRowCount; // 车辆数据行数 + + public MergeStrategy(int workloadDataRowCount, int carDataRowCount) { + this.workloadDataRowCount = workloadDataRowCount; + this.carDataRowCount = carDataRowCount; + } + + @Override + protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { + int currentRow = cell.getRowIndex(); + int currentCol = cell.getColumnIndex(); + + // ========== 左侧:工作量清单合并逻辑 ========== + // 1. 工作量标题行(A1-F1) + if (currentRow == 0 && currentCol == 0) { + CellRangeAddress workloadTitle = new CellRangeAddress(0, 0, 0, 5); + sheet.addMergedRegion(workloadTitle); + // 标题样式+内容 + Row titleRow = sheet.getRow(0); + Cell workloadCell = titleRow.getCell(0); + workloadCell.setCellValue(sheet.getSheetName().replace("及用车", "") + "工作量清单"); + setTitleStyle(workloadCell, sheet.getWorkbook()); + } + // 2. 工作量合计行(A[合计行]-E[合计行]) + int workloadTotalRow = 1 + workloadDataRowCount; + if (currentRow == workloadTotalRow && currentCol == 0) { + CellRangeAddress workloadTotal = new CellRangeAddress(workloadTotalRow, workloadTotalRow, 0, 4); + sheet.addMergedRegion(workloadTotal); + // 合计行样式 + setTotalStyle(sheet.getRow(currentRow).getCell(0), sheet.getWorkbook()); + } + + // ========== 右侧:车辆清单合并逻辑 ========== + // 1. 车辆标题行(H1-K1) + if (currentRow == 0 && currentCol == 7) { + CellRangeAddress carTitle = new CellRangeAddress(0, 0, 7, 10); + sheet.addMergedRegion(carTitle); + // 标题样式+内容 + Row titleRow = sheet.getRow(0); + Cell carCell = titleRow.createCell(7); // 手动创建H1单元格 + carCell.setCellValue(sheet.getSheetName().replace("工作量及", "") + "用车清单"); + setTitleStyle(carCell, sheet.getWorkbook()); + } + // 2. 车辆合计行(H[合计行]-J[合计行]) + int carTotalRow = 1 + carDataRowCount; + if (currentRow == carTotalRow && currentCol == 7) { + CellRangeAddress carTotal = new CellRangeAddress(carTotalRow, carTotalRow, 7, 9); + sheet.addMergedRegion(carTotal); + // 合计行样式 + setTotalStyle(sheet.getRow(currentRow).getCell(7), sheet.getWorkbook()); + } + } + + /** + * 设置标题样式(加粗+居中) + */ + private void setTitleStyle(Cell cell, Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setBold(true); + font.setFontHeightInPoints((short) 14); + style.setFont(font); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + cell.setCellStyle(style); + } + + /** + * 设置合计行样式(加粗+居中) + */ + private void setTotalStyle(Cell cell, Workbook workbook) { + CellStyle style = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setBold(true); + style.setFont(font); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + cell.setCellStyle(style); + } + } +} diff --git a/bonus-business/src/main/java/com/bonus/digital/controller/MonthlyPlanController.java b/bonus-business/src/main/java/com/bonus/digital/controller/MonthlyPlanController.java index 338afd2..a4511f6 100644 --- a/bonus-business/src/main/java/com/bonus/digital/controller/MonthlyPlanController.java +++ b/bonus-business/src/main/java/com/bonus/digital/controller/MonthlyPlanController.java @@ -1,13 +1,14 @@ package com.bonus.digital.controller; import com.bonus.business.controller.tool.MonthPlanExcelExporter; +import com.bonus.business.controller.tool.ResourceSummaryExcelExporter; +import com.bonus.business.controller.tool.WorkloadAndCarSummaryExcelExporter; import com.bonus.common.annotation.Log; import com.bonus.common.core.controller.BaseController; import com.bonus.common.core.domain.AjaxResult; import com.bonus.common.core.page.TableDataInfo; import com.bonus.common.enums.BusinessType; -import com.bonus.digital.dao.MonthlyPlanVo; -import com.bonus.digital.dao.ExportMonthPlanPersonVo; +import com.bonus.digital.dao.*; import com.bonus.digital.service.MonthlyPlanService; import lombok.extern.slf4j.Slf4j; import org.springframework.security.access.prepost.PreAuthorize; @@ -16,6 +17,7 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.*; @@ -120,4 +122,39 @@ public class MonthlyPlanController extends BaseController { List list = monthlyPlanService.exportMonthlyPlanPerson(monthlyPlanVo); MonthPlanExcelExporter.exportToExcel(response, list, 2025, 10, "10月运检人员安排"); } + + @Log(title = "导出工作量汇总表", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('monthly:plan:export')") // 复用原有导出权限,无需新增 + @PostMapping("/exportWorkloadSummary") + public void exportWorkloadSummary(HttpServletResponse response, + @RequestBody MonthlyPlanVo monthlyPlanVo) throws IOException { + // 1. 获取工作量导出数据(原有逻辑保留) + List workloadList = monthlyPlanService.exportWorkloadSummary(monthlyPlanVo); + + // 2. 新增:获取车辆导出数据(复用相同筛选条件:月份/运检站/专业等) + List carList = monthlyPlanService.exportCarUseSummary(monthlyPlanVo); + + // 3. 生成sheet名称(调整为包含车辆的名称) + String month = monthlyPlanVo.getMonthlyPlan(); // 格式如:2025-11 + String sheetName; + if (month == null || month.isEmpty()) { + sheetName = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy年MM月")) + "工作量及用车清单"; + } else { + sheetName = month.replace("-", "年") + "月工作量及用车清单"; + } + + // 4. 调用合并导出工具类(替换原有仅工作量的导出方法) + WorkloadAndCarSummaryExcelExporter.exportMergeSummary(response, workloadList, carList, sheetName); + } + + @Log(title = "导出月计划资源汇总表", businessType = BusinessType.EXPORT) + @PreAuthorize("@ss.hasPermi('monthly:plan:export')") + @PostMapping("/exportResourceSummary") + public void exportResourceSummary(HttpServletResponse response, + @RequestBody MonthlyPlanVo monthlyPlanVo) throws IOException { + // 1. 查询汇总数据 + List dataList = monthlyPlanService.exportResourceSummary(monthlyPlanVo); + // 2. 调用工具类导出 + ResourceSummaryExcelExporter.export(response, dataList, monthlyPlanVo.getMonthlyPlan()); + } } diff --git a/bonus-business/src/main/java/com/bonus/digital/dao/CarUseSummaryExcelVo.java b/bonus-business/src/main/java/com/bonus/digital/dao/CarUseSummaryExcelVo.java new file mode 100644 index 0000000..38c58e4 --- /dev/null +++ b/bonus-business/src/main/java/com/bonus/digital/dao/CarUseSummaryExcelVo.java @@ -0,0 +1,28 @@ +package com.bonus.digital.dao; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import lombok.Data; + +/** + * 车辆使用清单导出Vo(数据行) + * 匹配模板:H列(序号)、I列(运检站)、J列(管理用车天数)、K列(分包用车天数) + */ +@Data +public class CarUseSummaryExcelVo { + @ExcelProperty(value = "序号", index = 7) // H列(索引7) + @ColumnWidth(8) + private Integer serialNumber; // 序号(H列) + + @ExcelProperty(value = "运检站", index = 8) // I列(索引8) + @ColumnWidth(15) + private String inspectionStationName; // 运检站(I列) + + @ExcelProperty(value = "管理用车天数", index = 9) // J列(索引9) + @ColumnWidth(20) + private Integer totalManageCarDays; // 管理用车天数(J列) + + @ExcelProperty(value = "分包用车天数", index = 10) // K列(索引10) + @ColumnWidth(20) + private Integer totalSubCarDays; // 分包用车天数(K列) +} diff --git a/bonus-business/src/main/java/com/bonus/digital/dao/CarUseTotalExcelVo.java b/bonus-business/src/main/java/com/bonus/digital/dao/CarUseTotalExcelVo.java new file mode 100644 index 0000000..2ef805d --- /dev/null +++ b/bonus-business/src/main/java/com/bonus/digital/dao/CarUseTotalExcelVo.java @@ -0,0 +1,26 @@ +package com.bonus.digital.dao; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +/** + * 车辆使用清单合计行Vo(表尾合计) + * 匹配模板:H列-K列合并逻辑 + */ +@Data +public class CarUseTotalExcelVo { + @ExcelProperty(value = "合计", index = 7) // H列(合并H-J列显示「合计」) + private String totalLabel; + + @ExcelProperty(value = "", index = 8) // I列(占位) + private String empty1; + + @ExcelProperty(value = "", index = 9) // J列(占位) + private String empty2; + + @ExcelProperty(value = "", index = 10) // K列(总计分包用车天数) + private Integer totalSubCarDaysSum; + + // 管理用车天数总计(用于Excel合计行计算) + private Integer totalManageCarDaysSum; +} diff --git a/bonus-business/src/main/java/com/bonus/digital/dao/MonthlyPlanVo.java b/bonus-business/src/main/java/com/bonus/digital/dao/MonthlyPlanVo.java index ce24fc9..282d1a5 100644 --- a/bonus-business/src/main/java/com/bonus/digital/dao/MonthlyPlanVo.java +++ b/bonus-business/src/main/java/com/bonus/digital/dao/MonthlyPlanVo.java @@ -137,4 +137,29 @@ public class MonthlyPlanVo { */ private List workloadList; + /** + * 单价 + */ + private Integer unitPrice; + + /** + * 工作量类别 + */ + private String workloadCategoryName; + + /** + * 总工作量 + */ + private Integer totalWorkload; + + /** + * 合计金额 + */ + private Integer totalAmount; + + private Integer totalManageCarDays; + + + private Integer totalSubCarDays; + } diff --git a/bonus-business/src/main/java/com/bonus/digital/dao/ResourceSummaryExcelVo.java b/bonus-business/src/main/java/com/bonus/digital/dao/ResourceSummaryExcelVo.java new file mode 100644 index 0000000..3492596 --- /dev/null +++ b/bonus-business/src/main/java/com/bonus/digital/dao/ResourceSummaryExcelVo.java @@ -0,0 +1,47 @@ +package com.bonus.digital.dao; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import lombok.Data; +import java.math.BigDecimal; + +/** + * 资源统计分析导出专用VO(新增F列备注) + * 列索引对应:A(0)、B(1)、C(2)、D(3)、E(4)、F(5) + */ +@Data +public class ResourceSummaryExcelVo { + // A列:运检站名称/汇总(合并单元格) + @ExcelProperty(value = "运检站/汇总", index = 0) + @ColumnWidth(15) + private String inspectionStationName; + + // B列:编制人数/类型 + @ExcelProperty(value = "编制人数/类型", index = 1) + @ColumnWidth(18) + private Integer compileNum; + private String type; + + // C列:长期借调、支援人数/工日 + @ExcelProperty(value = "长期借调、支援人数/工日", index = 2) + @ColumnWidth(18) + private Integer secondmentNum; + private Integer workday; + + // D列:实际在站人数/比值 + @ExcelProperty(value = "实际在站人数/比值", index = 3) + @ColumnWidth(12) + private Integer actualStationNum; + private BigDecimal ratio; + + // E列:人均/分包用工 + @ExcelProperty(value = "人均/分包用工", index = 4) + @ColumnWidth(12) + private BigDecimal avg; + private Integer subcontractWorkday; + + // F列:备注 + @ExcelProperty(value = "备注", index = 5) + @ColumnWidth(15) + private String remark; +} diff --git a/bonus-business/src/main/java/com/bonus/digital/dao/ResourceSummaryVo.java b/bonus-business/src/main/java/com/bonus/digital/dao/ResourceSummaryVo.java new file mode 100644 index 0000000..e4ae68b --- /dev/null +++ b/bonus-business/src/main/java/com/bonus/digital/dao/ResourceSummaryVo.java @@ -0,0 +1,88 @@ +package com.bonus.digital.dao; + +import lombok.Data; +import java.math.BigDecimal; + +@Data +public class ResourceSummaryVo { + // 运检站基础信息 + private String inspectionStationId; + private String inspectionStationName; + + // 人员基础数据 + private Integer compileNum; // 编制人数 + private Integer secondmentNum; // 借调人数 + private Integer actualStationNum; // 实际在站人数 + private Integer totalWorkday; // 总工日 + + // 休假 + private Integer restTotalDays; // 休假总天数 + private Integer restPersonCount; // 休假参与人数 + private Integer restWorkday; + private BigDecimal restRatio; + private BigDecimal restAvg; + + // 培训 + private Integer trainTotalDays; + private Integer trainPersonCount; + private Integer trainWorkday; + private BigDecimal trainRatio; + private BigDecimal trainAvg; + + // 运行 + private Integer runTotalDays; + private Integer runPersonCount; + private Integer runWorkday; + private BigDecimal runRatio; + private BigDecimal runAvg; + + // 运行(视频) + private Integer runVideoTotalDays; + private Integer runVideoPersonCount; + private Integer runVideoWorkday; + private BigDecimal runVideoRatio; + private BigDecimal runVideoAvg; + + // 检修 + private Integer maintainTotalDays; + private Integer maintainPersonCount; + private Integer maintainWorkday; + private BigDecimal maintainRatio; + private BigDecimal maintainAvg; + + // 值班 + private Integer dutyTotalDays; + private Integer dutyPersonCount; + private Integer dutyWorkday; + private BigDecimal dutyRatio; + private BigDecimal dutyAvg; + + // 抢修 + private Integer repairTotalDays; + private Integer repairPersonCount; + private Integer repairWorkday; + private BigDecimal repairRatio; + private BigDecimal repairAvg; + + // 学习 + private Integer studyTotalDays; + private Integer studyPersonCount; + private Integer studyWorkday; + private BigDecimal studyRatio; + private BigDecimal studyAvg; + + // 其他 + private Integer otherTotalDays; + private Integer otherPersonCount; + private Integer otherWorkday; + private BigDecimal otherRatio; + private BigDecimal otherAvg; + + // 未安排 + private Integer unarrangeWorkday; + private BigDecimal unarrangeRatio; + private BigDecimal unarrangeAvg; + + // 分包用工 + private Integer subcontractWorkday; +} diff --git a/bonus-business/src/main/java/com/bonus/digital/dao/WorkloadSummaryExcelVo.java b/bonus-business/src/main/java/com/bonus/digital/dao/WorkloadSummaryExcelVo.java new file mode 100644 index 0000000..7145838 --- /dev/null +++ b/bonus-business/src/main/java/com/bonus/digital/dao/WorkloadSummaryExcelVo.java @@ -0,0 +1,32 @@ +package com.bonus.digital.dao; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ColumnWidth; +import lombok.Data; + +@Data +public class WorkloadSummaryExcelVo { + @ExcelProperty(value = "序号", index = 0) + @ColumnWidth(8) + private Integer serialNumber; + + @ExcelProperty(value = "运检站", index = 1) + @ColumnWidth(15) + private String inspectionStationName; + + @ExcelProperty(value = "工作量类型", index = 2) + @ColumnWidth(18) + private String workloadCategoryName; + + @ExcelProperty(value = "工作量", index = 3) + @ColumnWidth(10) + private Integer totalWorkload; + + @ExcelProperty(value = "单价", index = 4) + @ColumnWidth(10) + private Integer unitPrice; + + @ExcelProperty(value = "合计", index = 5) + @ColumnWidth(12) + private Integer totalAmount; +} diff --git a/bonus-business/src/main/java/com/bonus/digital/dao/WorkloadTotalExcelVo.java b/bonus-business/src/main/java/com/bonus/digital/dao/WorkloadTotalExcelVo.java new file mode 100644 index 0000000..c7f52b5 --- /dev/null +++ b/bonus-business/src/main/java/com/bonus/digital/dao/WorkloadTotalExcelVo.java @@ -0,0 +1,25 @@ +package com.bonus.digital.dao; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; + +@Data +public class WorkloadTotalExcelVo { + @ExcelProperty(value = "合计", index = 0) + private String totalLabel; + + @ExcelProperty(value = "", index = 1) + private String empty1; + + @ExcelProperty(value = "", index = 2) + private String empty2; + + @ExcelProperty(value = "", index = 3) + private String empty3; + + @ExcelProperty(value = "", index = 4) + private String empty4; + + @ExcelProperty(value = "", index = 5) + private Integer totalAmountSum; +} diff --git a/bonus-business/src/main/java/com/bonus/digital/mapper/MonthlyPlanMapper.java b/bonus-business/src/main/java/com/bonus/digital/mapper/MonthlyPlanMapper.java index 976372a..4d8414e 100644 --- a/bonus-business/src/main/java/com/bonus/digital/mapper/MonthlyPlanMapper.java +++ b/bonus-business/src/main/java/com/bonus/digital/mapper/MonthlyPlanMapper.java @@ -2,6 +2,7 @@ package com.bonus.digital.mapper; import com.bonus.digital.dao.MonthlyPlanVo; import com.bonus.digital.dao.PersonnelArrangementVo; +import com.bonus.digital.dao.ResourceSummaryVo; import com.bonus.digital.dao.WorkloadVo; import java.util.List; @@ -12,6 +13,21 @@ public interface MonthlyPlanMapper { */ List getPlanMajorList(MonthlyPlanVo monthlyPlanVo); + /** + * 月计划总工作量汇总 + */ + List getWorkloadSummary(MonthlyPlanVo monthlyPlanVo); + + /** + * 用车总量汇总 + */ + List getCarUseSummary(MonthlyPlanVo monthlyPlanVo); + + /** + * 月计划汇总 + */ + List getResourceSummary(MonthlyPlanVo monthlyPlanVo); + /** * 人员列表 */ diff --git a/bonus-business/src/main/java/com/bonus/digital/service/MonthlyPlanService.java b/bonus-business/src/main/java/com/bonus/digital/service/MonthlyPlanService.java index 22c08ae..8d626c0 100644 --- a/bonus-business/src/main/java/com/bonus/digital/service/MonthlyPlanService.java +++ b/bonus-business/src/main/java/com/bonus/digital/service/MonthlyPlanService.java @@ -1,7 +1,6 @@ package com.bonus.digital.service; -import com.bonus.digital.dao.MonthlyPlanVo; -import com.bonus.digital.dao.ExportMonthPlanPersonVo; +import com.bonus.digital.dao.*; import java.util.List; @@ -27,4 +26,11 @@ public interface MonthlyPlanService { int updateMonthlyPlan(MonthlyPlanVo monthlyPlanVo); List exportMonthlyPlanPerson(MonthlyPlanVo monthlyPlanVo); + + List exportWorkloadSummary(MonthlyPlanVo monthlyPlanVo); + + List exportCarUseSummary(MonthlyPlanVo monthlyPlanVo); + + List exportResourceSummary(MonthlyPlanVo monthlyPlanVo); + } diff --git a/bonus-business/src/main/java/com/bonus/digital/service/impl/MonthlyPlanServiceImpl.java b/bonus-business/src/main/java/com/bonus/digital/service/impl/MonthlyPlanServiceImpl.java index 39c218c..965809c 100644 --- a/bonus-business/src/main/java/com/bonus/digital/service/impl/MonthlyPlanServiceImpl.java +++ b/bonus-business/src/main/java/com/bonus/digital/service/impl/MonthlyPlanServiceImpl.java @@ -10,6 +10,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.*; /** @@ -138,4 +140,191 @@ public class MonthlyPlanServiceImpl implements MonthlyPlanService { } return plannedList; } + + /** + * 导出工作量汇总Excel + * @param monthlyPlanVo 筛选条件 + * @return 导出专用Vo列表 + */ + @Override + public List exportWorkloadSummary(MonthlyPlanVo monthlyPlanVo) { + // 1. 查询汇总数据 + List workloadSummaryList = monthlyPlanMapper.getWorkloadSummary(monthlyPlanVo); + + // 2. 转换为导出专用Vo(解耦业务Vo和导出Vo) + List exportList = new ArrayList<>(); + int serialNum = 1; // Excel序号 + for (MonthlyPlanVo vo : workloadSummaryList) { + WorkloadSummaryExcelVo exportVo = new WorkloadSummaryExcelVo(); + // 映射核心字段(和Excel模板列一一对应) + exportVo.setSerialNumber(serialNum++); // 序号 + exportVo.setInspectionStationName(vo.getInspectionStationName()); // 运检站 + exportVo.setWorkloadCategoryName(vo.getWorkloadCategoryName()); // 工作量类别 + exportVo.setTotalWorkload(vo.getTotalWorkload()); // 总工作量 + exportVo.setUnitPrice(vo.getUnitPrice()); // 单价 + exportVo.setTotalAmount(vo.getTotalAmount()); // 合计金额 + + exportList.add(exportVo); + } + + return exportList; + } + + /** + * 导出车辆使用清单Excel + * @param monthlyPlanVo 筛选条件 + * @return 车辆汇总导出专用Vo列表 + */ + @Override + public List exportCarUseSummary(MonthlyPlanVo monthlyPlanVo) { + // 1. 调用Mapper查询车辆汇总数据 + List carUseSummaryList = monthlyPlanMapper.getCarUseSummary(monthlyPlanVo); + + // 2. 转换为导出专用Vo(适配H列开始的列索引) + List exportList = new ArrayList<>(); + int serialNum = 1; // Excel序号(从1开始) + for (MonthlyPlanVo vo : carUseSummaryList) { + CarUseSummaryExcelVo exportVo = new CarUseSummaryExcelVo(); + // 映射核心字段(适配H-K列索引) + exportVo.setSerialNumber(serialNum++); // 序号(H列,index=7) + exportVo.setInspectionStationName(vo.getInspectionStationName()); // 运检站(I列,index=8) + exportVo.setTotalManageCarDays(vo.getTotalManageCarDays()); + exportVo.setTotalSubCarDays(vo.getTotalSubCarDays()); + + exportList.add(exportVo); + } + + return exportList; + } + + /** + * 导出资源统计汇总数据(适配Excel导出,含各运检站+汇总行) + * @param monthlyPlanVo 筛选条件(核心:monthlyPlan 统计月份) + * @return 资源统计Vo列表(最后一条为汇总数据) + */ + @Override + public List exportResourceSummary(MonthlyPlanVo monthlyPlanVo) { + // 1. 入参:用MonthlyPlanVo传递筛选条件,调用Mapper查询ResourceSummaryVo(统计结果) + // (Mapper中会从MonthlyPlanVo取monthlyPlan/inspectionStationId等筛选值) + List stationResourceList = monthlyPlanMapper.getResourceSummary(monthlyPlanVo); + if (stationResourceList.isEmpty()) { + log.info("资源统计查询无数据,筛选条件:月份={},运检站ID={}", + monthlyPlanVo.getMonthlyPlan(), monthlyPlanVo.getInspectionStationId()); + return Collections.emptyList(); + } + + // 2. 计算汇总行(仅用ResourceSummaryVo,全程不混用) + ResourceSummaryVo summaryResourceVo = new ResourceSummaryVo(); + summaryResourceVo.setInspectionStationName("汇总"); // 汇总行名称 + + // 2.1 人员基础数据累加(纯ResourceSummaryVo字段) + summaryResourceVo.setCompileNum(stationResourceList.stream().mapToInt(ResourceSummaryVo::getCompileNum).sum()); + summaryResourceVo.setSecondmentNum(stationResourceList.stream().mapToInt(ResourceSummaryVo::getSecondmentNum).sum()); + summaryResourceVo.setActualStationNum(stationResourceList.stream().mapToInt(ResourceSummaryVo::getActualStationNum).sum()); + summaryResourceVo.setTotalWorkday(stationResourceList.stream().mapToInt(ResourceSummaryVo::getTotalWorkday).sum()); + + // 2.2 各类型中间字段累加(TotalDays/PersonCount,纯ResourceSummaryVo) + // 休假 + summaryResourceVo.setRestTotalDays(stationResourceList.stream().mapToInt(ResourceSummaryVo::getRestTotalDays).sum()); + summaryResourceVo.setRestPersonCount(stationResourceList.stream().mapToInt(ResourceSummaryVo::getRestPersonCount).sum()); + summaryResourceVo.setRestWorkday(stationResourceList.stream().mapToInt(ResourceSummaryVo::getRestWorkday).sum()); + // 培训 + summaryResourceVo.setTrainTotalDays(stationResourceList.stream().mapToInt(ResourceSummaryVo::getTrainTotalDays).sum()); + summaryResourceVo.setTrainPersonCount(stationResourceList.stream().mapToInt(ResourceSummaryVo::getTrainPersonCount).sum()); + summaryResourceVo.setTrainWorkday(stationResourceList.stream().mapToInt(ResourceSummaryVo::getTrainWorkday).sum()); + // 运行 + summaryResourceVo.setRunTotalDays(stationResourceList.stream().mapToInt(ResourceSummaryVo::getRunTotalDays).sum()); + summaryResourceVo.setRunPersonCount(stationResourceList.stream().mapToInt(ResourceSummaryVo::getRunPersonCount).sum()); + summaryResourceVo.setRunWorkday(stationResourceList.stream().mapToInt(ResourceSummaryVo::getRunWorkday).sum()); + // 运行(视频) + summaryResourceVo.setRunVideoTotalDays(stationResourceList.stream().mapToInt(ResourceSummaryVo::getRunVideoTotalDays).sum()); + summaryResourceVo.setRunVideoPersonCount(stationResourceList.stream().mapToInt(ResourceSummaryVo::getRunVideoPersonCount).sum()); + summaryResourceVo.setRunVideoWorkday(stationResourceList.stream().mapToInt(ResourceSummaryVo::getRunVideoWorkday).sum()); + // 检修(原维护) + summaryResourceVo.setMaintainTotalDays(stationResourceList.stream().mapToInt(ResourceSummaryVo::getMaintainTotalDays).sum()); + summaryResourceVo.setMaintainPersonCount(stationResourceList.stream().mapToInt(ResourceSummaryVo::getMaintainPersonCount).sum()); + summaryResourceVo.setMaintainWorkday(stationResourceList.stream().mapToInt(ResourceSummaryVo::getMaintainWorkday).sum()); + // 值班 + summaryResourceVo.setDutyTotalDays(stationResourceList.stream().mapToInt(ResourceSummaryVo::getDutyTotalDays).sum()); + summaryResourceVo.setDutyPersonCount(stationResourceList.stream().mapToInt(ResourceSummaryVo::getDutyPersonCount).sum()); + summaryResourceVo.setDutyWorkday(stationResourceList.stream().mapToInt(ResourceSummaryVo::getDutyWorkday).sum()); + // 抢修 + summaryResourceVo.setRepairTotalDays(stationResourceList.stream().mapToInt(ResourceSummaryVo::getRepairTotalDays).sum()); + summaryResourceVo.setRepairPersonCount(stationResourceList.stream().mapToInt(ResourceSummaryVo::getRepairPersonCount).sum()); + summaryResourceVo.setRepairWorkday(stationResourceList.stream().mapToInt(ResourceSummaryVo::getRepairWorkday).sum()); + // 学习 + summaryResourceVo.setStudyTotalDays(stationResourceList.stream().mapToInt(ResourceSummaryVo::getStudyTotalDays).sum()); + summaryResourceVo.setStudyPersonCount(stationResourceList.stream().mapToInt(ResourceSummaryVo::getStudyPersonCount).sum()); + summaryResourceVo.setStudyWorkday(stationResourceList.stream().mapToInt(ResourceSummaryVo::getStudyWorkday).sum()); + // 其他 + summaryResourceVo.setOtherTotalDays(stationResourceList.stream().mapToInt(ResourceSummaryVo::getOtherTotalDays).sum()); + summaryResourceVo.setOtherPersonCount(stationResourceList.stream().mapToInt(ResourceSummaryVo::getOtherPersonCount).sum()); + summaryResourceVo.setOtherWorkday(stationResourceList.stream().mapToInt(ResourceSummaryVo::getOtherWorkday).sum()); + // 分包用工 + summaryResourceVo.setSubcontractWorkday(stationResourceList.stream().mapToInt(ResourceSummaryVo::getSubcontractWorkday).sum()); + + // 2.3 未安排工日计算(纯ResourceSummaryVo字段) + int unarrangeWorkday = summaryResourceVo.getTotalWorkday() + - (summaryResourceVo.getRestWorkday() + summaryResourceVo.getTrainWorkday() + summaryResourceVo.getRunWorkday() + + summaryResourceVo.getRunVideoWorkday() + summaryResourceVo.getMaintainWorkday() + summaryResourceVo.getDutyWorkday() + + summaryResourceVo.getRepairWorkday() + summaryResourceVo.getStudyWorkday()); + summaryResourceVo.setUnarrangeWorkday(unarrangeWorkday); + + // 2.4 比值/人均计算(纯ResourceSummaryVo字段,复用通用方法) + summaryResourceVo.setRestRatio(calcRatio(summaryResourceVo.getRestWorkday(), summaryResourceVo.getTotalWorkday())); + summaryResourceVo.setRestAvg(calcAvg(summaryResourceVo.getRestWorkday(), summaryResourceVo.getActualStationNum())); + summaryResourceVo.setTrainRatio(calcRatio(summaryResourceVo.getTrainWorkday(), summaryResourceVo.getTotalWorkday())); + summaryResourceVo.setTrainAvg(calcAvg(summaryResourceVo.getTrainWorkday(), summaryResourceVo.getActualStationNum())); + summaryResourceVo.setRunRatio(calcRatio(summaryResourceVo.getRunWorkday(), summaryResourceVo.getTotalWorkday())); + summaryResourceVo.setRunAvg(calcAvg(summaryResourceVo.getRunWorkday(), summaryResourceVo.getActualStationNum())); + summaryResourceVo.setRunVideoRatio(calcRatio(summaryResourceVo.getRunVideoWorkday(), summaryResourceVo.getTotalWorkday())); + summaryResourceVo.setRunVideoAvg(calcAvg(summaryResourceVo.getRunVideoWorkday(), summaryResourceVo.getActualStationNum())); + summaryResourceVo.setMaintainRatio(calcRatio(summaryResourceVo.getMaintainWorkday(), summaryResourceVo.getTotalWorkday())); + summaryResourceVo.setMaintainAvg(calcAvg(summaryResourceVo.getMaintainWorkday(), summaryResourceVo.getActualStationNum())); + summaryResourceVo.setDutyRatio(calcRatio(summaryResourceVo.getDutyWorkday(), summaryResourceVo.getTotalWorkday())); + summaryResourceVo.setDutyAvg(calcAvg(summaryResourceVo.getDutyWorkday(), summaryResourceVo.getActualStationNum())); + summaryResourceVo.setRepairRatio(calcRatio(summaryResourceVo.getRepairWorkday(), summaryResourceVo.getTotalWorkday())); + summaryResourceVo.setRepairAvg(calcAvg(summaryResourceVo.getRepairWorkday(), summaryResourceVo.getActualStationNum())); + summaryResourceVo.setStudyRatio(calcRatio(summaryResourceVo.getStudyWorkday(), summaryResourceVo.getTotalWorkday())); + summaryResourceVo.setStudyAvg(calcAvg(summaryResourceVo.getStudyWorkday(), summaryResourceVo.getActualStationNum())); + summaryResourceVo.setOtherRatio(calcRatio(summaryResourceVo.getOtherWorkday(), summaryResourceVo.getTotalWorkday())); + summaryResourceVo.setOtherAvg(calcAvg(summaryResourceVo.getOtherWorkday(), summaryResourceVo.getActualStationNum())); + summaryResourceVo.setUnarrangeRatio(calcRatio(summaryResourceVo.getUnarrangeWorkday(), summaryResourceVo.getTotalWorkday())); + summaryResourceVo.setUnarrangeAvg(calcAvg(summaryResourceVo.getUnarrangeWorkday(), summaryResourceVo.getActualStationNum())); + + // 3. 汇总行加入结果列表(纯ResourceSummaryVo列表) + List finalResourceList = new ArrayList<>(stationResourceList); + finalResourceList.add(summaryResourceVo); + + return finalResourceList; + } + + /** + * 通用计算比值(工日/总工日 ×100%,保留2位小数) + * @param workday 某类型工日(ResourceSummaryVo字段) + * @param totalWorkday 总工日(ResourceSummaryVo字段) + * @return 比值(BigDecimal,保留2位小数) + */ + private BigDecimal calcRatio(Integer workday, Integer totalWorkday) { + if (totalWorkday == 0 || workday == 0) { + return BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); + } + return BigDecimal.valueOf(workday * 100.0 / totalWorkday) + .setScale(2, RoundingMode.HALF_UP); + } + + /** + * 通用计算人均(工日/实际在站人数,保留1位小数) + * @param workday 某类型工日(ResourceSummaryVo字段) + * @param actualStationNum 实际在站人数(ResourceSummaryVo字段) + * @return 人均(BigDecimal,保留1位小数) + */ + private BigDecimal calcAvg(Integer workday, Integer actualStationNum) { + if (actualStationNum == 0 || workday == 0) { + return BigDecimal.ZERO.setScale(1, RoundingMode.HALF_UP); + } + return BigDecimal.valueOf(workday * 1.0 / actualStationNum) + .setScale(1, RoundingMode.HALF_UP); + } + } diff --git a/bonus-business/src/main/resources/mapper/MonthPlanMapper.xml b/bonus-business/src/main/resources/mapper/MonthPlanMapper.xml index b66c4ae..4668c11 100644 --- a/bonus-business/src/main/resources/mapper/MonthPlanMapper.xml +++ b/bonus-business/src/main/resources/mapper/MonthPlanMapper.xml @@ -138,4 +138,426 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" from tb_monthly_plan tmp where tmp.is_active = '1' and tmp.monthly_plan = #{monthlyPlan} + + + + + + + + +