parent
1f19a6d852
commit
8b3dcf419b
|
|
@ -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<ResourceSummaryVo> dataList,
|
||||
String month) throws IOException {
|
||||
// 1. 拆分“运检站列表”和“汇总行”(最后一条是汇总)
|
||||
List<ResourceSummaryVo> 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<String, ResourceSummaryVo> stationMap = stationList.stream()
|
||||
.collect(Collectors.toMap(ResourceSummaryVo::getInspectionStationName, vo -> vo));
|
||||
|
||||
// 3. 构造导出数据列表
|
||||
List<Object> 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<ResourceSummaryExcelVo> buildStationRows(ResourceSummaryVo data) {
|
||||
List<ResourceSummaryExcelVo> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<WorkloadSummaryExcelVo> workloadData,
|
||||
List<CarUseSummaryExcelVo> 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<Object> 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<String> getAllColumnFields() {
|
||||
List<String> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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<ExportMonthPlanPersonVo> 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<WorkloadSummaryExcelVo> workloadList = monthlyPlanService.exportWorkloadSummary(monthlyPlanVo);
|
||||
|
||||
// 2. 新增:获取车辆导出数据(复用相同筛选条件:月份/运检站/专业等)
|
||||
List<CarUseSummaryExcelVo> 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<ResourceSummaryVo> dataList = monthlyPlanService.exportResourceSummary(monthlyPlanVo);
|
||||
// 2. 调用工具类导出
|
||||
ResourceSummaryExcelExporter.export(response, dataList, monthlyPlanVo.getMonthlyPlan());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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列)
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -137,4 +137,29 @@ public class MonthlyPlanVo {
|
|||
*/
|
||||
private List<WorkloadVo> workloadList;
|
||||
|
||||
/**
|
||||
* 单价
|
||||
*/
|
||||
private Integer unitPrice;
|
||||
|
||||
/**
|
||||
* 工作量类别
|
||||
*/
|
||||
private String workloadCategoryName;
|
||||
|
||||
/**
|
||||
* 总工作量
|
||||
*/
|
||||
private Integer totalWorkload;
|
||||
|
||||
/**
|
||||
* 合计金额
|
||||
*/
|
||||
private Integer totalAmount;
|
||||
|
||||
private Integer totalManageCarDays;
|
||||
|
||||
|
||||
private Integer totalSubCarDays;
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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<MonthlyPlanVo> getPlanMajorList(MonthlyPlanVo monthlyPlanVo);
|
||||
|
||||
/**
|
||||
* 月计划总工作量汇总
|
||||
*/
|
||||
List<MonthlyPlanVo> getWorkloadSummary(MonthlyPlanVo monthlyPlanVo);
|
||||
|
||||
/**
|
||||
* 用车总量汇总
|
||||
*/
|
||||
List<MonthlyPlanVo> getCarUseSummary(MonthlyPlanVo monthlyPlanVo);
|
||||
|
||||
/**
|
||||
* 月计划汇总
|
||||
*/
|
||||
List<ResourceSummaryVo> getResourceSummary(MonthlyPlanVo monthlyPlanVo);
|
||||
|
||||
/**
|
||||
* 人员列表
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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<ExportMonthPlanPersonVo> exportMonthlyPlanPerson(MonthlyPlanVo monthlyPlanVo);
|
||||
|
||||
List<WorkloadSummaryExcelVo> exportWorkloadSummary(MonthlyPlanVo monthlyPlanVo);
|
||||
|
||||
List<CarUseSummaryExcelVo> exportCarUseSummary(MonthlyPlanVo monthlyPlanVo);
|
||||
|
||||
List<ResourceSummaryVo> exportResourceSummary(MonthlyPlanVo monthlyPlanVo);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<WorkloadSummaryExcelVo> exportWorkloadSummary(MonthlyPlanVo monthlyPlanVo) {
|
||||
// 1. 查询汇总数据
|
||||
List<MonthlyPlanVo> workloadSummaryList = monthlyPlanMapper.getWorkloadSummary(monthlyPlanVo);
|
||||
|
||||
// 2. 转换为导出专用Vo(解耦业务Vo和导出Vo)
|
||||
List<WorkloadSummaryExcelVo> 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<CarUseSummaryExcelVo> exportCarUseSummary(MonthlyPlanVo monthlyPlanVo) {
|
||||
// 1. 调用Mapper查询车辆汇总数据
|
||||
List<MonthlyPlanVo> carUseSummaryList = monthlyPlanMapper.getCarUseSummary(monthlyPlanVo);
|
||||
|
||||
// 2. 转换为导出专用Vo(适配H列开始的列索引)
|
||||
List<CarUseSummaryExcelVo> 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<ResourceSummaryVo> exportResourceSummary(MonthlyPlanVo monthlyPlanVo) {
|
||||
// 1. 入参:用MonthlyPlanVo传递筛选条件,调用Mapper查询ResourceSummaryVo(统计结果)
|
||||
// (Mapper中会从MonthlyPlanVo取monthlyPlan/inspectionStationId等筛选值)
|
||||
List<ResourceSummaryVo> 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<ResourceSummaryVo> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
</select>
|
||||
|
||||
<select id="getWorkloadSummary" resultType="com.bonus.digital.dao.MonthlyPlanVo">
|
||||
select
|
||||
tmp.inspection_station_id,
|
||||
tmp.inspection_station_name,
|
||||
tw.workload_category_name,
|
||||
IFNULL(tw.unit_price, 0) as unit_price,
|
||||
IFNULL(SUM(tw.workload_num), 0) as total_workload,
|
||||
IFNULL(SUM(tw.workload_num), 0) * IFNULL(tw.unit_price, 0) as total_amount
|
||||
from tb_monthly_plan tmp
|
||||
left join tb_workload tw
|
||||
on tw.plan_id = tmp.monthly_plan_id
|
||||
and tw.data_source = '0'
|
||||
left join tb_plan_management pm
|
||||
on pm.plan_management_id = tmp.plan_management_id
|
||||
where tmp.is_active = '1'
|
||||
<!-- 计划月份筛选 -->
|
||||
<if test="monthlyPlan != null and monthlyPlan != ''">
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
</if>
|
||||
<!-- 运检站筛选 -->
|
||||
<if test="inspectionStationId != null and inspectionStationId != ''">
|
||||
AND tmp.inspection_station_id = #{inspectionStationId}
|
||||
</if>
|
||||
<!-- 计划专业筛选 -->
|
||||
<if test="planMajorId != null and planMajorId != ''">
|
||||
AND tmp.plan_major_id = #{planMajorId}
|
||||
</if>
|
||||
<!-- 业务类型筛选 -->
|
||||
<if test="businessTypeId != null and businessTypeId != ''">
|
||||
AND tmp.business_type_id = #{businessTypeId}
|
||||
</if>
|
||||
<!-- 风险等级筛选 -->
|
||||
<if test="riskLevel != null and riskLevel != ''">
|
||||
AND pm.risk_level = #{riskLevel}
|
||||
</if>
|
||||
GROUP BY
|
||||
tmp.inspection_station_id,
|
||||
tmp.inspection_station_name,
|
||||
tw.workload_category_name,
|
||||
tw.unit_price
|
||||
ORDER BY tmp.inspection_station_name ASC;
|
||||
</select>
|
||||
|
||||
<select id="getCarUseSummary" resultType="com.bonus.digital.dao.MonthlyPlanVo">
|
||||
select
|
||||
tmp.inspection_station_id,
|
||||
tmp.inspection_station_name,
|
||||
-- 汇总管理用车天数(空则补0)
|
||||
IFNULL(SUM(tmp.plan_car_num), 0) as total_manage_car_days,
|
||||
-- 汇总分包用车天数(空则补0)
|
||||
IFNULL(SUM(tmp.plan_sub_car_num), 0) as total_sub_car_days
|
||||
from tb_monthly_plan tmp
|
||||
-- 关联计划管理表
|
||||
left join tb_plan_management pm
|
||||
on pm.plan_management_id = tmp.plan_management_id
|
||||
where tmp.is_active = '1'
|
||||
<!-- 计划月份筛选 -->
|
||||
<if test="monthlyPlan != null and monthlyPlan != ''">
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
</if>
|
||||
<!-- 运检站筛选 -->
|
||||
<if test="inspectionStationId != null and inspectionStationId != ''">
|
||||
AND tmp.inspection_station_id = #{inspectionStationId}
|
||||
</if>
|
||||
<!-- 计划专业筛选 -->
|
||||
<if test="planMajorId != null and planMajorId != ''">
|
||||
AND tmp.plan_major_id = #{planMajorId}
|
||||
</if>
|
||||
<!-- 业务类型筛选 -->
|
||||
<if test="businessTypeId != null and businessTypeId != ''">
|
||||
AND tmp.business_type_id = #{businessTypeId}
|
||||
</if>
|
||||
<!-- 风险等级筛选 -->
|
||||
<if test="riskLevel != null and riskLevel != ''">
|
||||
AND pm.risk_level = #{riskLevel}
|
||||
</if>
|
||||
GROUP BY
|
||||
tmp.inspection_station_id,
|
||||
tmp.inspection_station_name
|
||||
ORDER BY tmp.inspection_station_name ASC;
|
||||
</select>
|
||||
|
||||
<select id="getOverallSummary" resultType="com.bonus.digital.dao.MonthlyPlanVo">
|
||||
select
|
||||
tis.inspection_station_id,
|
||||
tis.inspection_station_name,
|
||||
from tb_inspection_station tis
|
||||
left join tb_monthly_plan tmp
|
||||
on tis.inspection_station_id = tmp.inspection_station_id
|
||||
where tis.category = '0'
|
||||
-- 关联计划管理表
|
||||
left join tb_plan_management pm
|
||||
on pm.plan_management_id = tmp.plan_management_id
|
||||
where tmp.is_active = '1'
|
||||
<!-- 计划月份筛选 -->
|
||||
<if test="monthlyPlan != null and monthlyPlan != ''">
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
</if>
|
||||
<!-- 运检站筛选 -->
|
||||
<if test="inspectionStationId != null and inspectionStationId != ''">
|
||||
AND tmp.inspection_station_id = #{inspectionStationId}
|
||||
</if>
|
||||
<!-- 计划专业筛选 -->
|
||||
<if test="planMajorId != null and planMajorId != ''">
|
||||
AND tmp.plan_major_id = #{planMajorId}
|
||||
</if>
|
||||
<!-- 业务类型筛选 -->
|
||||
<if test="businessTypeId != null and businessTypeId != ''">
|
||||
AND tmp.business_type_id = #{businessTypeId}
|
||||
</if>
|
||||
<!-- 风险等级筛选 -->
|
||||
<if test="riskLevel != null and riskLevel != ''">
|
||||
AND pm.risk_level = #{riskLevel}
|
||||
</if>
|
||||
GROUP BY
|
||||
tis.inspection_station_id,
|
||||
tis.inspection_station_name
|
||||
ORDER BY tmp.inspection_station_name ASC;
|
||||
</select>
|
||||
|
||||
<select id="getResourceSummary" resultType="com.bonus.digital.dao.ResourceSummaryVo">
|
||||
<![CDATA[
|
||||
SELECT
|
||||
-- 运检站基础信息
|
||||
ista.inspection_station_id,
|
||||
ista.inspection_station_name,
|
||||
|
||||
-- 1. 人员基础数据(编制/借调/实际在站)
|
||||
(SELECT COUNT(p.id)
|
||||
FROM tb_personnel p
|
||||
WHERE p.inspection_station_id = ista.inspection_station_id
|
||||
AND p.is_active = '1') AS compile_num, -- 编制人数
|
||||
|
||||
(SELECT COUNT(p.id)
|
||||
FROM tb_personnel p
|
||||
WHERE p.inspection_station_id = ista.inspection_station_id
|
||||
AND p.long_term_secondment = '1'
|
||||
AND p.is_active = '1') AS secondment_num, -- 长期借调人数
|
||||
|
||||
-- 实际在站人数 = 编制 - 借调
|
||||
compile_num - secondment_num AS actual_station_num,
|
||||
|
||||
-- 2. 总工日 = 月份天数 × 实际在站人数
|
||||
(SELECT DATEDIFF(LAST_DAY(STR_TO_DATE(#{monthlyPlan}, '%Y-%m')),
|
||||
DATE_FORMAT(STR_TO_DATE(#{monthlyPlan}, '%Y-%m'), '%Y-%m-01')) + 1)
|
||||
* actual_station_num AS total_workday,
|
||||
|
||||
-- ======================================
|
||||
-- 类型1:休假
|
||||
-- ======================================
|
||||
(SELECT IFNULL(SUM(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '休假'
|
||||
AND pm.category = '0') AS rest_total_days,
|
||||
|
||||
(SELECT IFNULL(COUNT(DISTINCT t.person_id), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
LEFT JOIN JSON_TABLE(
|
||||
IF(tmp.plan_personnel IS NULL OR tmp.plan_personnel = '', '[]',
|
||||
CONCAT('["', REPLACE(tmp.plan_personnel, ',', '","'), '"]')),
|
||||
'$[*]' COLUMNS (person_id VARCHAR(50) PATH '$')
|
||||
) t
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '休假'
|
||||
AND pm.category = '0') AS rest_person_count,
|
||||
|
||||
rest_total_days * rest_person_count AS rest_workday,
|
||||
ROUND(rest_workday / total_workday, 2) AS rest_ratio,
|
||||
ROUND(rest_workday / actual_station_num, 1) AS rest_avg,
|
||||
|
||||
-- ======================================
|
||||
-- 类型2:培训
|
||||
-- ======================================
|
||||
(SELECT IFNULL(SUM(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '培训'
|
||||
AND pm.category = '0') AS train_total_days,
|
||||
|
||||
(SELECT IFNULL(COUNT(DISTINCT t.person_id), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
LEFT JOIN JSON_TABLE(
|
||||
IF(tmp.plan_personnel IS NULL OR tmp.plan_personnel = '', '[]',
|
||||
CONCAT('["', REPLACE(tmp.plan_personnel, ',', '","'), '"]')),
|
||||
'$[*]' COLUMNS (person_id VARCHAR(50) PATH '$')
|
||||
) t
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '培训'
|
||||
AND pm.category = '0') AS train_person_count,
|
||||
|
||||
train_total_days * train_person_count AS train_workday,
|
||||
ROUND(train_workday / total_workday, 2) AS train_ratio,
|
||||
ROUND(train_workday / actual_station_num, 1) AS train_avg,
|
||||
|
||||
-- ======================================
|
||||
-- 类型3:运行
|
||||
-- ======================================
|
||||
(SELECT IFNULL(SUM(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行'
|
||||
AND pm.category = '0') AS run_total_days,
|
||||
|
||||
(SELECT IFNULL(COUNT(DISTINCT t.person_id), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
LEFT JOIN JSON_TABLE(
|
||||
IF(tmp.plan_personnel IS NULL OR tmp.plan_personnel = '', '[]',
|
||||
CONCAT('["', REPLACE(tmp.plan_personnel, ',', '","'), '"]')),
|
||||
'$[*]' COLUMNS (person_id VARCHAR(50) PATH '$')
|
||||
) t
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行'
|
||||
AND pm.category = '0') AS run_person_count,
|
||||
|
||||
run_total_days * run_person_count AS run_workday,
|
||||
ROUND(run_workday / total_workday, 2) AS run_ratio,
|
||||
ROUND(run_workday / actual_station_num, 1) AS run_avg,
|
||||
|
||||
-- ======================================
|
||||
-- 新增:类型4:运行(视频)
|
||||
-- ======================================
|
||||
(SELECT IFNULL(SUM(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行(视频)'
|
||||
AND pm.category = '0') AS run_video_total_days,
|
||||
|
||||
(SELECT IFNULL(COUNT(DISTINCT t.person_id), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
LEFT JOIN JSON_TABLE(
|
||||
IF(tmp.plan_personnel IS NULL OR tmp.plan_personnel = '', '[]',
|
||||
CONCAT('["', REPLACE(tmp.plan_personnel, ',', '","'), '"]')),
|
||||
'$[*]' COLUMNS (person_id VARCHAR(50) PATH '$')
|
||||
) t
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行(视频)'
|
||||
AND pm.category = '0') AS run_video_person_count,
|
||||
|
||||
run_video_total_days * run_video_person_count AS run_video_workday,
|
||||
ROUND(run_video_workday / total_workday, 2) AS run_video_ratio,
|
||||
ROUND(run_video_workday / actual_station_num, 1) AS run_video_avg,
|
||||
|
||||
-- ======================================
|
||||
-- 类型5:检修(原维护,补全TotalDays/PersonCount)
|
||||
-- ======================================
|
||||
(SELECT IFNULL(SUM(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '检修'
|
||||
AND pm.category = '0') AS maintain_total_days,
|
||||
|
||||
(SELECT IFNULL(COUNT(DISTINCT t.person_id), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
LEFT JOIN JSON_TABLE(
|
||||
IF(tmp.plan_personnel IS NULL OR tmp.plan_personnel = '', '[]',
|
||||
CONCAT('["', REPLACE(tmp.plan_personnel, ',', '","'), '"]')),
|
||||
'$[*]' COLUMNS (person_id VARCHAR(50) PATH '$')
|
||||
) t
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '检修'
|
||||
AND pm.category = '0') AS maintain_person_count,
|
||||
|
||||
maintain_total_days * maintain_person_count AS maintain_workday,
|
||||
ROUND(maintain_workday / total_workday, 2) AS maintain_ratio,
|
||||
ROUND(maintain_workday / actual_station_num, 1) AS maintain_avg,
|
||||
|
||||
-- ======================================
|
||||
-- 新增:类型6:值班
|
||||
-- ======================================
|
||||
(SELECT IFNULL(SUM(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '值班'
|
||||
AND pm.category = '0') AS duty_total_days,
|
||||
|
||||
(SELECT IFNULL(COUNT(DISTINCT t.person_id), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
LEFT JOIN JSON_TABLE(
|
||||
IF(tmp.plan_personnel IS NULL OR tmp.plan_personnel = '', '[]',
|
||||
CONCAT('["', REPLACE(tmp.plan_personnel, ',', '","'), '"]')),
|
||||
'$[*]' COLUMNS (person_id VARCHAR(50) PATH '$')
|
||||
) t
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '值班'
|
||||
AND pm.category = '0') AS duty_person_count,
|
||||
|
||||
duty_total_days * duty_person_count AS duty_workday,
|
||||
ROUND(duty_workday / total_workday, 2) AS duty_ratio,
|
||||
ROUND(duty_workday / actual_station_num, 1) AS duty_avg,
|
||||
|
||||
-- ======================================
|
||||
-- 类型7:抢修
|
||||
-- ======================================
|
||||
(SELECT IFNULL(SUM(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '抢修'
|
||||
AND pm.category = '0') AS repair_total_days,
|
||||
|
||||
(SELECT IFNULL(COUNT(DISTINCT t.person_id), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
LEFT JOIN JSON_TABLE(
|
||||
IF(tmp.plan_personnel IS NULL OR tmp.plan_personnel = '', '[]',
|
||||
CONCAT('["', REPLACE(tmp.plan_personnel, ',', '","'), '"]')),
|
||||
'$[*]' COLUMNS (person_id VARCHAR(50) PATH '$')
|
||||
) t
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '抢修'
|
||||
AND pm.category = '0') AS repair_person_count,
|
||||
|
||||
repair_total_days * repair_person_count AS repair_workday,
|
||||
ROUND(repair_workday / total_workday, 2) AS repair_ratio,
|
||||
ROUND(repair_workday / actual_station_num, 1) AS repair_avg,
|
||||
|
||||
-- ======================================
|
||||
-- 类型8:学习
|
||||
-- ======================================
|
||||
(SELECT IFNULL(SUM(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '学习'
|
||||
AND pm.category = '0') AS study_total_days,
|
||||
|
||||
(SELECT IFNULL(COUNT(DISTINCT t.person_id), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
LEFT JOIN JSON_TABLE(
|
||||
IF(tmp.plan_personnel IS NULL OR tmp.plan_personnel = '', '[]',
|
||||
CONCAT('["', REPLACE(tmp.plan_personnel, ',', '","'), '"]')),
|
||||
'$[*]' COLUMNS (person_id VARCHAR(50) PATH '$')
|
||||
) t
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '学习'
|
||||
AND pm.category = '0') AS study_person_count,
|
||||
|
||||
study_total_days * study_person_count AS study_workday,
|
||||
ROUND(study_workday / total_workday, 2) AS study_ratio,
|
||||
ROUND(study_workday / actual_station_num, 1) AS study_avg,
|
||||
|
||||
-- ======================================
|
||||
-- 类型9:其他
|
||||
-- ======================================
|
||||
(SELECT IFNULL(SUM(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '其他'
|
||||
AND pm.category = '0') AS other_total_days,
|
||||
|
||||
(SELECT IFNULL(COUNT(DISTINCT t.person_id), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
LEFT JOIN JSON_TABLE(
|
||||
IF(tmp.plan_personnel IS NULL OR tmp.plan_personnel = '', '[]',
|
||||
CONCAT('["', REPLACE(tmp.plan_personnel, ',', '","'), '"]')),
|
||||
'$[*]' COLUMNS (person_id VARCHAR(50) PATH '$')
|
||||
) t
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '其他'
|
||||
AND pm.category = '0') AS other_person_count,
|
||||
|
||||
other_total_days * other_person_count AS other_workday,
|
||||
ROUND(other_workday / total_workday, 2) AS other_ratio,
|
||||
ROUND(other_workday / actual_station_num, 1) AS other_avg,
|
||||
|
||||
-- ======================================
|
||||
-- 类型10:未安排(修正计算逻辑,包含新增类型)
|
||||
-- ======================================
|
||||
total_workday - (rest_workday + train_workday + run_workday + run_video_workday + maintain_workday + duty_workday + repair_workday + study_workday) AS unarrange_workday,
|
||||
ROUND(unarrange_workday / total_workday, 2) AS unarrange_ratio,
|
||||
ROUND(unarrange_workday / actual_station_num, 1) AS unarrange_avg,
|
||||
|
||||
-- ======================================
|
||||
-- 类型11:分包用工
|
||||
-- ======================================
|
||||
(SELECT IFNULL(SUM(tmp.plan_skilled_worker_num + tmp.plan_auxiliary_worker_num), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
WHERE tmp.inspection_station_id = ista.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}) AS subcontract_workday
|
||||
|
||||
FROM tb_inspection_station ista
|
||||
WHERE ista.category = '0' -- 只统计category为0的运检站
|
||||
AND ista.is_active = '1'
|
||||
ORDER BY ista.inspection_station_name ASC;
|
||||
]]>
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
|
|
|||
Loading…
Reference in New Issue