月计划整体汇总表导出功能优化
This commit is contained in:
parent
312787de98
commit
b9de1ca09b
|
|
@ -1,5 +1,6 @@
|
|||
package com.bonus.business.controller.tool;
|
||||
|
||||
import com.bonus.digital.dao.BusinessTypeVo;
|
||||
import com.bonus.digital.dao.ResourceSummaryVo;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.ss.util.CellRangeAddress;
|
||||
|
|
@ -17,17 +18,22 @@ import java.util.*;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 月计划资源统计分析Excel导出工具类
|
||||
* 月计划资源统计分析Excel导出工具类(适配动态业务类型)
|
||||
* 修复点:
|
||||
* 1. 运检站A列合并行数多一行问题
|
||||
* 2. 单元格边框缺失问题
|
||||
* 3. 第四行C列表头改为“工日”
|
||||
* 4. 第五行B列清空(移除“总工日”文本)
|
||||
*/
|
||||
public class ResourceSummaryExcelExporter {
|
||||
private static final Logger log = LoggerFactory.getLogger(ResourceSummaryExcelExporter.class);
|
||||
|
||||
// 常量定义
|
||||
private static final int STATION_ROW_TOTAL = 14; // 单个运检站总行数
|
||||
private static final int A_MERGE_START = 3; // A列合并起始行偏移(第4行)
|
||||
private static final int A_MERGE_END = 13; // A列合并结束行偏移(第14行)
|
||||
private static final int MAX_COLUMN = 5; // 最大列索引(F列)
|
||||
private static final int REMARK_COL_INDEX = 5; // 备注列索引(F列)
|
||||
private static final int STATION_ROW_BASE = 5; // 单个运检站基础行数(标题+人员信息+子表头+总工日+分包用工)
|
||||
private static final int A_MERGE_START = 3; // A列合并起始行偏移(第4行)
|
||||
private static final int MAX_COLUMN = 5; // 最大列索引(F列)
|
||||
private static final int REMARK_COL_INDEX = 5; // 备注列索引(F列)
|
||||
private static final int A_MERGE_ROW_REDUCE = 1; // A列合并行数减少1行(修复多合并问题)
|
||||
|
||||
// 固定文本常量
|
||||
private static final String SHEET_PREFIX = "月资源统计分析表";
|
||||
|
|
@ -35,10 +41,13 @@ public class ResourceSummaryExcelExporter {
|
|||
private static final String SUMMARY_TEXT = "汇总";
|
||||
private static final String RESOURCE_STAT_TITLE = "资源统计分析";
|
||||
private static final String LONG_TERM_SUPPORT_REMARK = "长期支援不用统计";
|
||||
private static final String TOTAL_WORKDAY_TEXT = "总工日";
|
||||
private static final String UNARRANGE_TEXT = "未安排";
|
||||
private static final String SUBCONTRACT_TEXT = "分包用工";
|
||||
private static final String WORKDAY_TEXT = "工日"; // 修正后的C列子表头
|
||||
|
||||
// 列宽配置(单位:字符,POI中1字符≈256单位)
|
||||
// 核心调整:C列从12→20,D列从10→15,保证表头文字完整显示
|
||||
private static final int[] COLUMN_WIDTHS = {20, 15, 20, 15, 10, 18}; // A-F列宽(调整后)
|
||||
private static final int[] COLUMN_WIDTHS = {20, 15, 20, 15, 10, 18}; // A-F列宽
|
||||
// 字体配置
|
||||
private static final String FONT_NAME = "微软雅黑";
|
||||
private static final short FONT_SIZE = 11;
|
||||
|
|
@ -107,7 +116,7 @@ public class ResourceSummaryExcelExporter {
|
|||
Workbook workbook = new XSSFWorkbook();
|
||||
Sheet sheet = workbook.createSheet(sheetName);
|
||||
initStyles(workbook); // 初始化样式(含不同数值格式)
|
||||
setColumnWidths(sheet); // 设置列宽(已调整C/D列)
|
||||
setColumnWidths(sheet); // 设置列宽
|
||||
|
||||
// 写入数据
|
||||
int currentRow = 0;
|
||||
|
|
@ -140,7 +149,7 @@ public class ResourceSummaryExcelExporter {
|
|||
}
|
||||
|
||||
/**
|
||||
* 写入单个运检站/汇总的数据
|
||||
* 写入单个运检站/汇总的数据(适配动态类型)
|
||||
* @param sheet 工作表
|
||||
* @param vo 数据VO
|
||||
* @param name 运检站/汇总名称
|
||||
|
|
@ -149,10 +158,17 @@ public class ResourceSummaryExcelExporter {
|
|||
*/
|
||||
private int writeStationData(Sheet sheet, ResourceSummaryVo vo, String name, int startRow) {
|
||||
if (vo == null) {
|
||||
return startRow + STATION_ROW_TOTAL;
|
||||
// 计算默认行数(基础行数+至少1行动态类型)
|
||||
return startRow + STATION_ROW_BASE + 1;
|
||||
}
|
||||
|
||||
int rowIdx = startRow;
|
||||
// 获取动态业务类型列表
|
||||
List<BusinessTypeVo> dynamicTypeList = vo.getBusinessTypeList();
|
||||
// 单个运检站总行数 = 基础行数 + 动态类型行数
|
||||
int stationTotalRows = STATION_ROW_BASE + (dynamicTypeList == null ? 0 : dynamicTypeList.size());
|
||||
// A列合并结束行偏移(修复多合并1行问题)
|
||||
int aMergeEndOffset = A_MERGE_START + (stationTotalRows - 1) - A_MERGE_ROW_REDUCE;
|
||||
|
||||
// 1. 标题行(第1行):合并A-F列,内容"资源统计分析"
|
||||
Row titleRow = createRow(sheet, rowIdx++);
|
||||
|
|
@ -170,10 +186,10 @@ public class ResourceSummaryExcelExporter {
|
|||
setCellValueAndStyle(personHeaderRow, 2, "长期借调、支援人数", headerStyle);
|
||||
// D列:实际在站人数(表头样式)
|
||||
setCellValueAndStyle(personHeaderRow, 3, "实际在站人数", headerStyle);
|
||||
// A/E/F列:空(A列样式兜底,F列内容样式)
|
||||
// A/E/F列:空(填充样式保证边框)
|
||||
setCellValueAndStyle(personHeaderRow, 0, "", headerStyle);
|
||||
setCellValueAndStyle(personHeaderRow, 4, "", headerStyle);
|
||||
setCellValueAndStyle(personHeaderRow, REMARK_COL_INDEX, "", contentStyle);
|
||||
setCellValueAndStyle(personHeaderRow, REMARK_COL_INDEX, "", headerStyle);
|
||||
|
||||
// 3. 人员数据行(第3行):B/C/D列填充对应数据
|
||||
Row personDataRow = createRow(sheet, rowIdx++);
|
||||
|
|
@ -186,87 +202,105 @@ public class ResourceSummaryExcelExporter {
|
|||
// D列:实际在站人数(actualStationNum)
|
||||
int actualStationNum = vo.getActualStationNum() == null ? 0 : vo.getActualStationNum();
|
||||
setCellValueAndStyle(personDataRow, 3, actualStationNum, contentStyle);
|
||||
// A/E/F列:空
|
||||
// A/E/F列:空(填充样式保证边框)
|
||||
setCellValueAndStyle(personDataRow, 0, "", contentStyle);
|
||||
setCellValueAndStyle(personDataRow, 4, "", contentStyle);
|
||||
setCellValueAndStyle(personDataRow, REMARK_COL_INDEX, "", contentStyle);
|
||||
|
||||
// 4. 子表头行(第4行):类型/总工日/比值/人均/备注
|
||||
// 4. 子表头行(第4行):类型/工日/比值/人均/备注(修复C列表头)
|
||||
Row subHeaderRow = createRow(sheet, rowIdx++);
|
||||
setCellValueAndStyle(subHeaderRow, 0, "", headerStyle); // A列空(填充样式)
|
||||
setCellValueAndStyle(subHeaderRow, 1, "类型", headerStyle);
|
||||
setCellValueAndStyle(subHeaderRow, 2, "总工日", headerStyle);
|
||||
setCellValueAndStyle(subHeaderRow, 2, WORKDAY_TEXT, headerStyle); // 修正为“工日”
|
||||
setCellValueAndStyle(subHeaderRow, 3, "比值", headerStyle);
|
||||
setCellValueAndStyle(subHeaderRow, 4, "人均", headerStyle);
|
||||
setCellValueAndStyle(subHeaderRow, REMARK_COL_INDEX, "备注", headerStyle);
|
||||
fillRowStyle(subHeaderRow, headerStyle);
|
||||
fillRowStyle(subHeaderRow, headerStyle); // 强制填充整行样式
|
||||
|
||||
// 5. 总工日行(第5行):C列填充totalWorkday
|
||||
// 5. 总工日行(第5行):B列清空,C列填充totalWorkday(修复点)
|
||||
Row totalWorkdayRow = createRow(sheet, rowIdx++);
|
||||
// A/B/D/E/F列:空
|
||||
// A列:空(填充样式)
|
||||
setCellValueAndStyle(totalWorkdayRow, 0, "", contentStyle);
|
||||
// B列:清空(移除原“总工日”文本)
|
||||
setCellValueAndStyle(totalWorkdayRow, 1, "", contentStyle);
|
||||
setCellValueAndStyle(totalWorkdayRow, 3, "", contentStyle);
|
||||
setCellValueAndStyle(totalWorkdayRow, 4, "", contentStyle);
|
||||
setCellValueAndStyle(totalWorkdayRow, REMARK_COL_INDEX, "", contentStyle);
|
||||
// C列:总工日数据(totalWorkday)
|
||||
int totalWorkday = vo.getTotalWorkday() == null ? 0 : vo.getTotalWorkday();
|
||||
setCellValueAndStyle(totalWorkdayRow, 2, totalWorkday, workdayStyle);
|
||||
// D/E/F列:空(填充样式)
|
||||
setCellValueAndStyle(totalWorkdayRow, 3, "", contentStyle);
|
||||
setCellValueAndStyle(totalWorkdayRow, 4, "", contentStyle);
|
||||
setCellValueAndStyle(totalWorkdayRow, REMARK_COL_INDEX, "", contentStyle);
|
||||
|
||||
// 6. 类型行(第6-13行:8类数据)
|
||||
String[] types = {"休假", "培训", "运行", "运行(视频)", "检修", "值班", "其他", "未安排"};
|
||||
Integer[] workdays = {
|
||||
vo.getRestWorkday(), vo.getTrainWorkday(), vo.getRunWorkday(), vo.getRunVideoWorkday(),
|
||||
vo.getMaintainWorkday(), vo.getDutyWorkday(), vo.getOtherWorkday(), vo.getUnarrangeWorkday()
|
||||
};
|
||||
BigDecimal[] ratios = {
|
||||
vo.getRestRatio(), vo.getTrainRatio(), vo.getRunRatio(), vo.getRunVideoRatio(),
|
||||
vo.getMaintainRatio(), vo.getDutyRatio(), vo.getOtherRatio(), vo.getUnarrangeRatio()
|
||||
};
|
||||
BigDecimal[] avgs = {
|
||||
vo.getRestAvg(), vo.getTrainAvg(), vo.getRunAvg(), vo.getRunVideoAvg(),
|
||||
vo.getMaintainAvg(), vo.getDutyAvg(), vo.getOtherAvg(), vo.getUnarrangeAvg()
|
||||
};
|
||||
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
Row typeRow = createRow(sheet, rowIdx++);
|
||||
// B列:类型名称
|
||||
setCellValueAndStyle(typeRow, 1, types[i], contentStyle);
|
||||
// C列:总工日(整数格式)
|
||||
int workday = workdays[i] == null ? 0 : workdays[i];
|
||||
setCellValueAndStyle(typeRow, 2, workday, workdayStyle);
|
||||
// D列:比值(保留2位小数)
|
||||
BigDecimal ratio = ratios[i] == null ? BigDecimal.ZERO : ratios[i].setScale(2, BigDecimal.ROUND_HALF_UP);
|
||||
setCellValueAndStyle(typeRow, 3, ratio, ratioStyle);
|
||||
// E列:人均(保留1位小数)
|
||||
BigDecimal avg = avgs[i] == null ? BigDecimal.ZERO : avgs[i].setScale(1, BigDecimal.ROUND_HALF_UP);
|
||||
setCellValueAndStyle(typeRow, 4, avg, avgStyle);
|
||||
// F列:备注(仅"其他"行显示)
|
||||
if (i == 6) { // "其他"行
|
||||
setCellValueAndStyle(typeRow, REMARK_COL_INDEX, LONG_TERM_SUPPORT_REMARK, contentStyle);
|
||||
} else {
|
||||
setCellValueAndStyle(typeRow, REMARK_COL_INDEX, "", contentStyle);
|
||||
// 6. 动态类型行(替换原固定类型行)
|
||||
if (dynamicTypeList != null && !dynamicTypeList.isEmpty()) {
|
||||
for (BusinessTypeVo typeVo : dynamicTypeList) {
|
||||
Row typeRow = createRow(sheet, rowIdx++);
|
||||
// 跳过未安排(单独处理)
|
||||
if (UNARRANGE_TEXT.equals(typeVo.getTypeName())) {
|
||||
continue;
|
||||
}
|
||||
// A列:空(填充样式)
|
||||
setCellValueAndStyle(typeRow, 0, "", contentStyle);
|
||||
// B列:类型名称
|
||||
String typeName = Optional.ofNullable(typeVo.getTypeName()).orElse("");
|
||||
setCellValueAndStyle(typeRow, 1, typeName, contentStyle);
|
||||
// C列:总工日(整数格式)
|
||||
int workday = typeVo.getWorkday() == null ? 0 : typeVo.getWorkday();
|
||||
setCellValueAndStyle(typeRow, 2, workday, workdayStyle);
|
||||
// D列:比值(保留2位小数)
|
||||
BigDecimal ratio = Optional.ofNullable(typeVo.getRatio()).orElse(BigDecimal.ZERO)
|
||||
.setScale(2, BigDecimal.ROUND_HALF_UP);
|
||||
setCellValueAndStyle(typeRow, 3, ratio, ratioStyle);
|
||||
// E列:人均(保留1位小数)
|
||||
BigDecimal avg = Optional.ofNullable(typeVo.getAvg()).orElse(BigDecimal.ZERO)
|
||||
.setScale(1, BigDecimal.ROUND_HALF_UP);
|
||||
setCellValueAndStyle(typeRow, 4, avg, avgStyle);
|
||||
// F列:备注("其他"类型显示备注)
|
||||
if (LONG_TERM_SUPPORT_REMARK.contains(typeName) || "其他".equals(typeName)) {
|
||||
setCellValueAndStyle(typeRow, REMARK_COL_INDEX, LONG_TERM_SUPPORT_REMARK, contentStyle);
|
||||
} else {
|
||||
setCellValueAndStyle(typeRow, REMARK_COL_INDEX, "", contentStyle);
|
||||
}
|
||||
}
|
||||
// A列:空
|
||||
setCellValueAndStyle(typeRow, 0, "", contentStyle);
|
||||
}
|
||||
|
||||
// 7. 分包用工行(第14行):C列填充subcontractWorkday,字体不加粗
|
||||
// 7. 未安排行(固定行,单独处理)
|
||||
Row unarrangeRow = createRow(sheet, rowIdx++);
|
||||
// A列:空(填充样式)
|
||||
setCellValueAndStyle(unarrangeRow, 0, "", contentStyle);
|
||||
// B列:未安排
|
||||
setCellValueAndStyle(unarrangeRow, 1, UNARRANGE_TEXT, contentStyle);
|
||||
// C列:未安排工日
|
||||
int unarrangeWorkday = vo.getUnarrangeWorkday() == null ? 0 : vo.getUnarrangeWorkday();
|
||||
setCellValueAndStyle(unarrangeRow, 2, unarrangeWorkday, workdayStyle);
|
||||
// D列:未安排比值
|
||||
BigDecimal unarrangeRatio = Optional.ofNullable(vo.getUnarrangeRatio()).orElse(BigDecimal.ZERO)
|
||||
.setScale(2, BigDecimal.ROUND_HALF_UP);
|
||||
setCellValueAndStyle(unarrangeRow, 3, unarrangeRatio, ratioStyle);
|
||||
// E列:未安排人均
|
||||
BigDecimal unarrangeAvg = Optional.ofNullable(vo.getUnarrangeAvg()).orElse(BigDecimal.ZERO)
|
||||
.setScale(1, BigDecimal.ROUND_HALF_UP);
|
||||
setCellValueAndStyle(unarrangeRow, 4, unarrangeAvg, avgStyle);
|
||||
// F列:空备注(填充样式)
|
||||
setCellValueAndStyle(unarrangeRow, REMARK_COL_INDEX, "", contentStyle);
|
||||
|
||||
// 8. 分包用工行(固定行)
|
||||
Row subcontractRow = createRow(sheet, rowIdx++);
|
||||
// A列:空
|
||||
// A列:空(填充样式)
|
||||
setCellValueAndStyle(subcontractRow, 0, "", contentStyle);
|
||||
// B列:分包用工(内容样式,不加粗)
|
||||
setCellValueAndStyle(subcontractRow, 1, "分包用工", contentStyle);
|
||||
// B列:分包用工
|
||||
setCellValueAndStyle(subcontractRow, 1, SUBCONTRACT_TEXT, contentStyle);
|
||||
// C列:分包用工总工日(subcontractWorkday)
|
||||
int subWorkday = vo.getSubcontractWorkday() == null ? 0 : vo.getSubcontractWorkday();
|
||||
setCellValueAndStyle(subcontractRow, 2, subWorkday, workdayStyle);
|
||||
// D/E/F列:空
|
||||
// D/E/F列:空(填充样式)
|
||||
setCellValueAndStyle(subcontractRow, 3, "", contentStyle);
|
||||
setCellValueAndStyle(subcontractRow, 4, "", contentStyle);
|
||||
setCellValueAndStyle(subcontractRow, REMARK_COL_INDEX, "", contentStyle);
|
||||
|
||||
// A列合并(第4-14行)并填充运检站名称
|
||||
// A列合并(修复多合并1行问题)并填充运检站名称
|
||||
int aMergeFirstRow = startRow + A_MERGE_START;
|
||||
int aMergeLastRow = startRow + A_MERGE_END;
|
||||
int aMergeLastRow = startRow + aMergeEndOffset;
|
||||
sheet.addMergedRegion(new CellRangeAddress(aMergeFirstRow, aMergeLastRow, 0, 0));
|
||||
Row aMergeRow = sheet.getRow(aMergeFirstRow);
|
||||
Cell aMergeCell = createCell(aMergeRow, 0);
|
||||
|
|
@ -301,21 +335,21 @@ public class ResourceSummaryExcelExporter {
|
|||
// 基础内容样式:普通+居中+全边框
|
||||
contentStyle = createBaseCellStyle(workbook, normalFont);
|
||||
|
||||
// 工日列样式:整数格式
|
||||
// 工日列样式:整数格式 + 全边框
|
||||
workdayStyle = createBaseCellStyle(workbook, normalFont);
|
||||
workdayStyle.setDataFormat(workbook.createDataFormat().getFormat("0"));
|
||||
|
||||
// 比值列样式:保留2位小数
|
||||
// 比值列样式:保留2位小数 + 全边框
|
||||
ratioStyle = createBaseCellStyle(workbook, normalFont);
|
||||
ratioStyle.setDataFormat(workbook.createDataFormat().getFormat("0.00"));
|
||||
|
||||
// 人均列样式:保留1位小数
|
||||
// 人均列样式:保留1位小数 + 全边框
|
||||
avgStyle = createBaseCellStyle(workbook, normalFont);
|
||||
avgStyle.setDataFormat(workbook.createDataFormat().getFormat("0.0"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建基础单元格样式
|
||||
* 创建基础单元格样式(保证全边框)
|
||||
*/
|
||||
private CellStyle createBaseCellStyle(Workbook workbook, Font font) {
|
||||
CellStyle style = workbook.createCellStyle();
|
||||
|
|
@ -324,7 +358,7 @@ public class ResourceSummaryExcelExporter {
|
|||
// 对齐方式:水平+垂直居中
|
||||
style.setAlignment(HorizontalAlignment.CENTER);
|
||||
style.setVerticalAlignment(VerticalAlignment.CENTER);
|
||||
// 边框:全边框+黑色
|
||||
// 边框:全边框+黑色(确保边框完整)
|
||||
style.setBorderTop(BorderStyle.THIN);
|
||||
style.setBorderBottom(BorderStyle.THIN);
|
||||
style.setBorderLeft(BorderStyle.THIN);
|
||||
|
|
@ -339,7 +373,7 @@ public class ResourceSummaryExcelExporter {
|
|||
}
|
||||
|
||||
/**
|
||||
* 设置列宽(核心调整:C/D列加宽)
|
||||
* 设置列宽
|
||||
*/
|
||||
private void setColumnWidths(Sheet sheet) {
|
||||
for (int i = 0; i < COLUMN_WIDTHS.length; i++) {
|
||||
|
|
@ -376,7 +410,7 @@ public class ResourceSummaryExcelExporter {
|
|||
if (row == null) {
|
||||
row = sheet.createRow(rowIdx);
|
||||
}
|
||||
// 设置行高
|
||||
// 设置行高(保证单元格显示完整)
|
||||
row.setHeightInPoints(20);
|
||||
return row;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
package com.bonus.digital.dao;
|
||||
|
||||
import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 动态业务类型Vo(存储每个运检站实际存在的业务类型数据)
|
||||
*/
|
||||
@Data
|
||||
public class BusinessTypeVo {
|
||||
// 类型名称(如:休假、培训、运行(视频)等)
|
||||
private String typeName;
|
||||
// 总天数
|
||||
private Integer totalDays;
|
||||
// 参与人数
|
||||
private Integer personCount;
|
||||
// 工日
|
||||
private Integer workday;
|
||||
// 比值(workday/totalWorkday)
|
||||
private BigDecimal ratio;
|
||||
// 人均(workday/actualStationNum)
|
||||
private BigDecimal avg;
|
||||
// 以下两个字段用于计算比值和人均,无需前端返回,仅作中间计算
|
||||
private Integer totalWorkday;
|
||||
private Integer actualStationNum;
|
||||
|
||||
/**
|
||||
* 计算比值和人均(初始化时自动计算)
|
||||
*/
|
||||
public void calculateRatioAndAvg() {
|
||||
// 计算比值(保留4位小数,分母为0时返回0)
|
||||
this.ratio = BigDecimal.ZERO;
|
||||
if (this.totalWorkday != null && this.totalWorkday > 0 && this.workday != null) {
|
||||
this.ratio = new BigDecimal(this.workday)
|
||||
.divide(new BigDecimal(this.totalWorkday), 4, BigDecimal.ROUND_HALF_UP);
|
||||
}
|
||||
// 计算人均(保留3位小数,分母为0时返回0)
|
||||
this.avg = BigDecimal.ZERO;
|
||||
if (this.actualStationNum != null && this.actualStationNum > 0 && this.workday != null) {
|
||||
this.avg = new BigDecimal(this.workday)
|
||||
.divide(new BigDecimal(this.actualStationNum), 3, BigDecimal.ROUND_HALF_UP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -17,32 +17,32 @@ public class ResourceSummaryExcelVo {
|
|||
@ColumnWidth(15)
|
||||
private String inspectionStationName;
|
||||
|
||||
// B列:编制人数/类型(二选一,用ignore避免重复映射)
|
||||
// B列:编制人数/类型
|
||||
@ExcelProperty(value = "编制人数/类型", index = 1)
|
||||
@ColumnWidth(18)
|
||||
private Integer compileNum;
|
||||
@ExcelIgnore // 关键:标记为忽略,避免EasyExcel分配到G列
|
||||
private String type;
|
||||
|
||||
// C列:长期借调、支援人数/工日(二选一)
|
||||
// C列:长期借调、支援人数/工日
|
||||
@ExcelProperty(value = "长期借调、支援人数/工日", index = 2)
|
||||
@ColumnWidth(18)
|
||||
private Integer secondmentNum;
|
||||
@ExcelIgnore // 关键:标记为忽略
|
||||
private Integer workday;
|
||||
|
||||
// D列:实际在站人数/比值(二选一)
|
||||
// D列:实际在站人数/比值
|
||||
@ExcelProperty(value = "实际在站人数/比值", index = 3)
|
||||
@ColumnWidth(12)
|
||||
private Integer actualStationNum;
|
||||
@ExcelIgnore // 关键:标记为忽略
|
||||
private BigDecimal ratio;
|
||||
|
||||
// E列:人均/分包用工(二选一)
|
||||
// E列:人均/分包用工
|
||||
@ExcelProperty(value = "人均/分包用工", index = 4)
|
||||
@ColumnWidth(12)
|
||||
private BigDecimal avg;
|
||||
@ExcelIgnore // 关键:标记为忽略
|
||||
@ExcelIgnore // 标记为忽略
|
||||
private Integer subcontractWorkday;
|
||||
|
||||
// F列:备注
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ package com.bonus.digital.dao;
|
|||
|
||||
import lombok.Data;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ResourceSummaryVo {
|
||||
|
|
@ -15,74 +17,53 @@ public class ResourceSummaryVo {
|
|||
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;
|
||||
|
||||
// 动态业务类型列表(替换原type_json为type_str,存储拼接字符串)
|
||||
private String typeStr; // 数据库返回的拼接字符串,格式:类型1|类型2|...
|
||||
private transient List<BusinessTypeVo> businessTypeList; // 转换后的类型列表,不持久化
|
||||
|
||||
/**
|
||||
* 获取动态业务类型列表(自动解析拼接字符串)
|
||||
* @return 业务类型列表
|
||||
*/
|
||||
public List<BusinessTypeVo> getBusinessTypeList() {
|
||||
if (businessTypeList == null) {
|
||||
businessTypeList = new ArrayList<>();
|
||||
// 解析拼接字符串
|
||||
if (typeStr != null && !typeStr.isEmpty()) {
|
||||
// 按|分割多个类型
|
||||
String[] typeArray = typeStr.split("\\|");
|
||||
for (String singleTypeStr : typeArray) {
|
||||
if (singleTypeStr.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
// 按,分割单个类型的字段
|
||||
String[] fieldArray = singleTypeStr.split(",");
|
||||
// 字段顺序:typeName,totalDays,personCount,workday,totalWorkday,actualStationNum
|
||||
if (fieldArray.length != 6) {
|
||||
continue; // 字段异常,跳过该类型
|
||||
}
|
||||
BusinessTypeVo typeVo = new BusinessTypeVo();
|
||||
// 赋值字段(注意类型转换)
|
||||
typeVo.setTypeName(fieldArray[0].replace(",", ",")); // 还原转义的逗号
|
||||
typeVo.setTotalDays(Integer.parseInt(fieldArray[1]));
|
||||
typeVo.setPersonCount(Integer.parseInt(fieldArray[2]));
|
||||
typeVo.setWorkday(Integer.parseInt(fieldArray[3]));
|
||||
typeVo.setTotalWorkday(Integer.parseInt(fieldArray[4]));
|
||||
typeVo.setActualStationNum(Integer.parseInt(fieldArray[5]));
|
||||
// 计算比值和人均
|
||||
typeVo.calculateRatioAndAvg();
|
||||
businessTypeList.add(typeVo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return businessTypeList;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ import javax.annotation.Resource;
|
|||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author 马三炮
|
||||
|
|
@ -202,108 +203,175 @@ public class MonthlyPlanServiceImpl implements MonthlyPlanService {
|
|||
return exportList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出资源统计汇总数据(适配Excel导出,含各运检站+汇总行)
|
||||
* @param monthlyPlanVo 筛选条件(核心:monthlyPlan 统计月份)
|
||||
* @return 资源统计Vo列表(最后一条为汇总数据)
|
||||
*/
|
||||
@Override
|
||||
public List<ResourceSummaryVo> exportResourceSummary(MonthlyPlanVo monthlyPlanVo) {
|
||||
// 1. 入参:用MonthlyPlanVo传递筛选条件,调用Mapper查询ResourceSummaryVo(统计结果)
|
||||
// (Mapper中会从MonthlyPlanVo取monthlyPlan/inspectionStationId等筛选值)
|
||||
// 1. 入参校验与查询数据
|
||||
if (monthlyPlanVo == null || monthlyPlanVo.getMonthlyPlan() == null) {
|
||||
log.warn("资源统计查询入参无效:MonthlyPlanVo或统计月份为空");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<ResourceSummaryVo> stationResourceList = monthlyPlanMapper.getResourceSummary(monthlyPlanVo);
|
||||
if (stationResourceList.isEmpty()) {
|
||||
if (stationResourceList == null || stationResourceList.isEmpty()) {
|
||||
log.info("资源统计查询无数据,筛选条件:月份={},运检站ID={}",
|
||||
monthlyPlanVo.getMonthlyPlan(), monthlyPlanVo.getInspectionStationId());
|
||||
return Collections.emptyList();
|
||||
}
|
||||
log.info("资源统计查询成功,运检站原始数据量:{}", stationResourceList.size());
|
||||
|
||||
// 2. 计算汇总行(仅用ResourceSummaryVo,全程不混用)
|
||||
ResourceSummaryVo summaryResourceVo = new ResourceSummaryVo();
|
||||
summaryResourceVo.setInspectionStationName("汇总"); // 汇总行名称
|
||||
// 2. 数据去重(按运检站名称去重,避免重复数据)
|
||||
List<ResourceSummaryVo> distinctStationList = stationResourceList.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(vo -> Objects.nonNull(vo.getInspectionStationName()))
|
||||
.collect(Collectors.collectingAndThen(
|
||||
Collectors.toMap(
|
||||
ResourceSummaryVo::getInspectionStationName,
|
||||
vo -> vo,
|
||||
(existing, newVo) -> {
|
||||
log.warn("运检站名称重复,保留第一条数据:{}", existing.getInspectionStationName());
|
||||
return existing;
|
||||
}
|
||||
),
|
||||
map -> new ArrayList<>(map.values())
|
||||
));
|
||||
log.info("运检站数据去重后数量:{}", distinctStationList.size());
|
||||
|
||||
// 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());
|
||||
// 3. 构建汇总行数据
|
||||
ResourceSummaryVo summaryResourceVo = buildSummaryResourceVo(distinctStationList);
|
||||
|
||||
// 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);
|
||||
// 4. 组装最终结果列表(运检站数据+汇总数据)
|
||||
List<ResourceSummaryVo> finalResourceList = new ArrayList<>(distinctStationList);
|
||||
finalResourceList.add(summaryResourceVo);
|
||||
|
||||
log.info("资源统计汇总完成,最终数据量:{}(运检站{}个+汇总1条)",
|
||||
finalResourceList.size(), distinctStationList.size());
|
||||
return finalResourceList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建汇总行数据(独立方法,降低耦合)
|
||||
* @param distinctStationList 去重后的运检站数据列表
|
||||
* @return 汇总行ResourceSummaryVo
|
||||
*/
|
||||
private ResourceSummaryVo buildSummaryResourceVo(List<ResourceSummaryVo> distinctStationList) {
|
||||
ResourceSummaryVo summaryVo = new ResourceSummaryVo();
|
||||
summaryVo.setInspectionStationName("汇总");
|
||||
|
||||
// 3.1 人员基础数据累加
|
||||
int totalCompileNum = distinctStationList.stream()
|
||||
.mapToInt(vo -> Optional.ofNullable(vo.getCompileNum()).orElse(0))
|
||||
.sum();
|
||||
int totalSecondmentNum = distinctStationList.stream()
|
||||
.mapToInt(vo -> Optional.ofNullable(vo.getSecondmentNum()).orElse(0))
|
||||
.sum();
|
||||
int totalActualStationNum = distinctStationList.stream()
|
||||
.mapToInt(vo -> Optional.ofNullable(vo.getActualStationNum()).orElse(0))
|
||||
.sum();
|
||||
int totalWorkday = distinctStationList.stream()
|
||||
.mapToInt(vo -> Optional.ofNullable(vo.getTotalWorkday()).orElse(0))
|
||||
.sum();
|
||||
|
||||
summaryVo.setCompileNum(totalCompileNum);
|
||||
summaryVo.setSecondmentNum(totalSecondmentNum);
|
||||
summaryVo.setActualStationNum(totalActualStationNum);
|
||||
summaryVo.setTotalWorkday(totalWorkday);
|
||||
// 3.2 分包用工累加
|
||||
int totalSubcontractWorkday = distinctStationList.stream()
|
||||
.mapToInt(vo -> Optional.ofNullable(vo.getSubcontractWorkday()).orElse(0))
|
||||
.sum();
|
||||
summaryVo.setSubcontractWorkday(totalSubcontractWorkday);
|
||||
|
||||
// 3.3 动态业务类型汇总(按类型名称分组累加)
|
||||
Map<String, BusinessTypeVo> summaryTypeMap = aggregateDynamicTypeData(distinctStationList);
|
||||
List<BusinessTypeVo> summaryTypeList = new ArrayList<>(summaryTypeMap.values());
|
||||
|
||||
// 3.4 处理汇总类型的比值与人均计算
|
||||
summaryTypeList.forEach(typeVo -> {
|
||||
typeVo.setTotalWorkday(totalWorkday);
|
||||
typeVo.setActualStationNum(totalActualStationNum);
|
||||
typeVo.calculateRatioAndAvg();
|
||||
});
|
||||
|
||||
// 3.5 未安排工日计算(动态扣除所有有效类型工日,避免负数)
|
||||
int totalDynamicWorkday = summaryTypeList.stream()
|
||||
.mapToInt(typeVo -> Optional.ofNullable(typeVo.getWorkday()).orElse(0))
|
||||
.sum();
|
||||
int unarrangeWorkday = Math.max(totalWorkday - totalDynamicWorkday, 0);
|
||||
summaryVo.setUnarrangeWorkday(unarrangeWorkday);
|
||||
// 3.6 未安排字段比值/人均计算
|
||||
summaryVo.setUnarrangeRatio(calcRatio(unarrangeWorkday, totalWorkday));
|
||||
summaryVo.setUnarrangeAvg(calcAvg(unarrangeWorkday, totalActualStationNum));
|
||||
|
||||
String summaryTypeStr = buildDynamicTypeStr(summaryTypeList);
|
||||
summaryVo.setTypeStr(summaryTypeStr);
|
||||
|
||||
return summaryVo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 聚合所有运检站的动态类型数据(按类型名称分组)
|
||||
* @param stationList 运检站数据列表
|
||||
* @return 分组后的汇总类型Map
|
||||
*/
|
||||
private Map<String, BusinessTypeVo> aggregateDynamicTypeData(List<ResourceSummaryVo> stationList) {
|
||||
return stationList.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(ResourceSummaryVo::getBusinessTypeList) // 获取每个运检站的动态类型列表
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(List::stream) // 扁平化所有类型
|
||||
.filter(typeVo -> Objects.nonNull(typeVo.getTypeName()))
|
||||
.filter(typeVo -> !"未安排".equals(typeVo.getTypeName())) // 排除未安排(单独处理)
|
||||
.collect(Collectors.toMap(
|
||||
BusinessTypeVo::getTypeName, // 按类型名称分组
|
||||
typeVo -> {
|
||||
// 新建汇总类型对象,避免修改原数据
|
||||
BusinessTypeVo newTypeVo = new BusinessTypeVo();
|
||||
newTypeVo.setTypeName(typeVo.getTypeName());
|
||||
newTypeVo.setTotalDays(Optional.ofNullable(typeVo.getTotalDays()).orElse(0));
|
||||
newTypeVo.setPersonCount(Optional.ofNullable(typeVo.getPersonCount()).orElse(0));
|
||||
newTypeVo.setWorkday(Optional.ofNullable(typeVo.getWorkday()).orElse(0));
|
||||
return newTypeVo;
|
||||
},
|
||||
(existingType, newType) -> {
|
||||
// 累加数据
|
||||
existingType.setTotalDays(existingType.getTotalDays() + Optional.ofNullable(newType.getTotalDays()).orElse(0));
|
||||
existingType.setPersonCount(existingType.getPersonCount() + Optional.ofNullable(newType.getPersonCount()).orElse(0));
|
||||
existingType.setWorkday(existingType.getWorkday() + Optional.ofNullable(newType.getWorkday()).orElse(0));
|
||||
return existingType;
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建动态类型拼接字符串
|
||||
* @param typeList 动态类型列表
|
||||
* @return 拼接后的字符串(格式:类型1|类型2|...;单个类型:名称,总天数,人数,工日,总工日,在站人数)
|
||||
*/
|
||||
private String buildDynamicTypeStr(List<BusinessTypeVo> typeList) {
|
||||
if (typeList == null || typeList.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return typeList.stream()
|
||||
.map(typeVo -> {
|
||||
// 转义类型名称中的逗号,避免分隔符冲突
|
||||
String typeName = Optional.ofNullable(typeVo.getTypeName()).orElse("").replace(",", ",");
|
||||
int totalDays = Optional.ofNullable(typeVo.getTotalDays()).orElse(0);
|
||||
int personCount = Optional.ofNullable(typeVo.getPersonCount()).orElse(0);
|
||||
int workday = Optional.ofNullable(typeVo.getWorkday()).orElse(0);
|
||||
int totalWorkday = Optional.ofNullable(typeVo.getTotalWorkday()).orElse(0);
|
||||
int actualStationNum = Optional.ofNullable(typeVo.getActualStationNum()).orElse(0);
|
||||
return String.join(",", typeName,
|
||||
String.valueOf(totalDays),
|
||||
String.valueOf(personCount),
|
||||
String.valueOf(workday),
|
||||
String.valueOf(totalWorkday),
|
||||
String.valueOf(actualStationNum));
|
||||
})
|
||||
.collect(Collectors.joining("|"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取月计划详情
|
||||
|
|
|
|||
|
|
@ -196,105 +196,38 @@
|
|||
|
||||
<select id="getResourceSummary" resultType="com.bonus.digital.dao.ResourceSummaryVo">
|
||||
<![CDATA[
|
||||
-- 外层:仅格式化计算结果(如ROUND),所有数值字段做null兜底
|
||||
-- 外层:基础信息+未安排+分包用工 + 动态类型聚合结果(字符串拼接格式)
|
||||
SELECT
|
||||
base_data.inspection_station_id,
|
||||
base_data.inspection_station_name,
|
||||
-- 基础人员字段兜底
|
||||
IFNULL(base_data.compile_num, 0) AS compile_num,
|
||||
IFNULL(base_data.secondment_num, 0) AS secondment_num,
|
||||
IFNULL(base_data.actual_station_num, 0) AS actual_station_num,
|
||||
IFNULL(base_data.total_workday, 0) AS total_workday,
|
||||
|
||||
-- 休假相关(所有字段null转0,比值分母为0时返回0)
|
||||
IFNULL(base_data.rest_total_days, 0) AS rest_total_days,
|
||||
IFNULL(base_data.rest_person_count, 0) AS rest_person_count,
|
||||
IFNULL(base_data.rest_workday, 0) AS rest_workday,
|
||||
ROUND(IFNULL(base_data.rest_workday / NULLIF(base_data.total_workday, 0), 0), 4) AS rest_ratio,
|
||||
ROUND(IFNULL(base_data.rest_workday / NULLIF(base_data.actual_station_num, 0), 0), 3) AS rest_avg,
|
||||
|
||||
-- 培训相关
|
||||
IFNULL(base_data.train_total_days, 0) AS train_total_days,
|
||||
IFNULL(base_data.train_person_count, 0) AS train_person_count,
|
||||
IFNULL(base_data.train_workday, 0) AS train_workday,
|
||||
ROUND(IFNULL(base_data.train_workday / NULLIF(base_data.total_workday, 0), 0), 4) AS train_ratio,
|
||||
ROUND(IFNULL(base_data.train_workday / NULLIF(base_data.actual_station_num, 0), 0), 3) AS train_avg,
|
||||
|
||||
-- 运行相关
|
||||
IFNULL(base_data.run_total_days, 0) AS run_total_days,
|
||||
IFNULL(base_data.run_person_count, 0) AS run_person_count,
|
||||
IFNULL(base_data.run_workday, 0) AS run_workday,
|
||||
ROUND(IFNULL(base_data.run_workday / NULLIF(base_data.total_workday, 0), 0), 4) AS run_ratio,
|
||||
ROUND(IFNULL(base_data.run_workday / NULLIF(base_data.actual_station_num, 0), 0), 3) AS run_avg,
|
||||
|
||||
-- 运行(视频)相关
|
||||
IFNULL(base_data.run_video_total_days, 0) AS run_video_total_days,
|
||||
IFNULL(base_data.run_video_person_count, 0) AS run_video_person_count,
|
||||
IFNULL(base_data.run_video_workday, 0) AS run_video_workday,
|
||||
ROUND(IFNULL(base_data.run_video_workday / NULLIF(base_data.total_workday, 0), 0), 4) AS run_video_ratio,
|
||||
ROUND(IFNULL(base_data.run_video_workday / NULLIF(base_data.actual_station_num, 0), 0), 3) AS run_video_avg,
|
||||
|
||||
-- 检修相关
|
||||
IFNULL(base_data.maintain_total_days, 0) AS maintain_total_days,
|
||||
IFNULL(base_data.maintain_person_count, 0) AS maintain_person_count,
|
||||
IFNULL(base_data.maintain_workday, 0) AS maintain_workday,
|
||||
ROUND(IFNULL(base_data.maintain_workday / NULLIF(base_data.total_workday, 0), 0), 4) AS maintain_ratio,
|
||||
ROUND(IFNULL(base_data.maintain_workday / NULLIF(base_data.actual_station_num, 0), 0), 3) AS maintain_avg,
|
||||
|
||||
-- 值班相关
|
||||
IFNULL(base_data.duty_total_days, 0) AS duty_total_days,
|
||||
IFNULL(base_data.duty_person_count, 0) AS duty_person_count,
|
||||
IFNULL(base_data.duty_workday, 0) AS duty_workday,
|
||||
ROUND(IFNULL(base_data.duty_workday / NULLIF(base_data.total_workday, 0), 0), 4) AS duty_ratio,
|
||||
ROUND(IFNULL(base_data.duty_workday / NULLIF(base_data.actual_station_num, 0), 0), 3) AS duty_avg,
|
||||
|
||||
-- 抢修相关
|
||||
IFNULL(base_data.repair_total_days, 0) AS repair_total_days,
|
||||
IFNULL(base_data.repair_person_count, 0) AS repair_person_count,
|
||||
IFNULL(base_data.repair_workday, 0) AS repair_workday,
|
||||
ROUND(IFNULL(base_data.repair_workday / NULLIF(base_data.total_workday, 0), 0), 4) AS repair_ratio,
|
||||
ROUND(IFNULL(base_data.repair_workday / NULLIF(base_data.actual_station_num, 0), 0), 3) AS repair_avg,
|
||||
|
||||
-- 学习相关
|
||||
IFNULL(base_data.study_total_days, 0) AS study_total_days,
|
||||
IFNULL(base_data.study_person_count, 0) AS study_person_count,
|
||||
IFNULL(base_data.study_workday, 0) AS study_workday,
|
||||
ROUND(IFNULL(base_data.study_workday / NULLIF(base_data.total_workday, 0), 0), 4) AS study_ratio,
|
||||
ROUND(IFNULL(base_data.study_workday / NULLIF(base_data.actual_station_num, 0), 0), 3) AS study_avg,
|
||||
|
||||
-- 其他相关
|
||||
IFNULL(base_data.other_total_days, 0) AS other_total_days,
|
||||
IFNULL(base_data.other_person_count, 0) AS other_person_count,
|
||||
IFNULL(base_data.other_workday, 0) AS other_workday,
|
||||
ROUND(IFNULL(base_data.other_workday / NULLIF(base_data.total_workday, 0), 0), 4) AS other_ratio,
|
||||
ROUND(IFNULL(base_data.other_workday / NULLIF(base_data.actual_station_num, 0), 0), 3) AS other_avg,
|
||||
|
||||
-- 未安排相关
|
||||
IFNULL(base_data.unarrange_workday, 0) AS unarrange_workday,
|
||||
ROUND(IFNULL(base_data.unarrange_workday / NULLIF(base_data.total_workday, 0), 0), 4) AS unarrange_ratio,
|
||||
ROUND(IFNULL(base_data.unarrange_workday / NULLIF(base_data.actual_station_num, 0), 0), 3) AS unarrange_avg,
|
||||
|
||||
base_info.inspection_station_id,
|
||||
base_info.inspection_station_name,
|
||||
-- 基础字段
|
||||
IFNULL(base_info.compile_num, 0) AS compile_num,
|
||||
IFNULL(base_info.secondment_num, 0) AS secondment_num,
|
||||
IFNULL(base_info.actual_station_num, 0) AS actual_station_num,
|
||||
IFNULL(base_info.total_workday, 0) AS total_workday,
|
||||
-- 未安排
|
||||
IFNULL(base_info.unarrange_workday, 0) AS unarrange_workday,
|
||||
ROUND(IFNULL(base_info.unarrange_workday / NULLIF(base_info.total_workday, 0), 0), 4) AS unarrange_ratio,
|
||||
ROUND(IFNULL(base_info.unarrange_workday / NULLIF(base_info.actual_station_num, 0), 0), 3) AS unarrange_avg,
|
||||
-- 分包用工
|
||||
IFNULL(base_data.subcontract_workday, 0) AS subcontract_workday
|
||||
|
||||
IFNULL(base_info.subcontract_workday, 0) AS subcontract_workday,
|
||||
-- 动态类型数据(左关联动态类型聚合结果)
|
||||
IFNULL(type_data.type_str, '') AS type_str
|
||||
FROM (
|
||||
-- 内层:计算所有基础字段,所有数值结果做IFNULL兜底
|
||||
-- 子查询1:运检站基础信息+未安排+分包用工(逻辑优化,统一参数)
|
||||
SELECT
|
||||
ista_inner.inspection_station_id,
|
||||
ista_inner.inspection_station_name,
|
||||
|
||||
-- 1. 人员基础数据(null转0)
|
||||
IFNULL((SELECT COUNT(p.id)
|
||||
FROM tb_personnel p
|
||||
WHERE p.inspection_station_id = ista_inner.inspection_station_id
|
||||
AND p.is_active = '1'), 0) AS compile_num,
|
||||
|
||||
IFNULL((SELECT COUNT(p.id)
|
||||
FROM tb_personnel p
|
||||
WHERE p.inspection_station_id = ista_inner.inspection_station_id
|
||||
AND p.long_term_secondment = '1'
|
||||
AND p.is_active = '1'), 0) AS secondment_num,
|
||||
|
||||
-- 实际在站人数(减法结果兜底)
|
||||
IFNULL((SELECT COUNT(p.id)
|
||||
FROM tb_personnel p
|
||||
|
|
@ -305,8 +238,15 @@
|
|||
WHERE p.inspection_station_id = ista_inner.inspection_station_id
|
||||
AND p.long_term_secondment = '1'
|
||||
AND p.is_active = '1'), 0) AS actual_station_num,
|
||||
|
||||
-- 总工日(乘法结果兜底,避免null)
|
||||
-- 总工日(先计算当月天数,避免重复查询)
|
||||
IFNULL(
|
||||
(SELECT DATEDIFF(
|
||||
LAST_DAY(STR_TO_DATE(CONCAT(#{monthlyPlan}, '-01'), '%Y-%m-%d')),
|
||||
DATE_FORMAT(STR_TO_DATE(CONCAT(#{monthlyPlan}, '-01'), '%Y-%m-%d'), '%Y-%m-01')
|
||||
) + 1),
|
||||
0
|
||||
) AS month_days,
|
||||
-- 总工日=当月天数*实际在站人数
|
||||
IFNULL(
|
||||
(SELECT DATEDIFF(
|
||||
LAST_DAY(STR_TO_DATE(CONCAT(#{monthlyPlan}, '-01'), '%Y-%m-%d')),
|
||||
|
|
@ -325,611 +265,173 @@
|
|||
AND p.long_term_secondment = '1'
|
||||
AND p.is_active = '1'), 0)
|
||||
), 0) AS total_workday,
|
||||
|
||||
-- ======================================
|
||||
-- 类型1:休假(所有子查询结果IFNULL兜底)
|
||||
-- ======================================
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '休假'
|
||||
AND pm.category = '0'), 0) AS rest_total_days,
|
||||
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '休假'
|
||||
AND pm.category = '0'), 0) AS rest_person_count,
|
||||
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '休假'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '休假'
|
||||
AND pm.category = '0'), 0) AS rest_workday,
|
||||
|
||||
-- ======================================
|
||||
-- 类型2:培训(同休假逻辑,全量IFNULL兜底)
|
||||
-- ======================================
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '培训'
|
||||
AND pm.category = '0'), 0) AS train_total_days,
|
||||
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '培训'
|
||||
AND pm.category = '0'), 0) AS train_person_count,
|
||||
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '培训'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '培训'
|
||||
AND pm.category = '0'), 0) AS train_workday,
|
||||
|
||||
-- ======================================
|
||||
-- 类型3:运行
|
||||
-- ======================================
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行'
|
||||
AND pm.category = '0'), 0) AS run_total_days,
|
||||
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行'
|
||||
AND pm.category = '0'), 0) AS run_person_count,
|
||||
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行'
|
||||
AND pm.category = '0'), 0) AS run_workday,
|
||||
|
||||
-- ======================================
|
||||
-- 类型4:运行(视频)
|
||||
-- ======================================
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行(视频)'
|
||||
AND pm.category = '0'), 0) AS run_video_total_days,
|
||||
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行(视频)'
|
||||
AND pm.category = '0'), 0) AS run_video_person_count,
|
||||
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行(视频)'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行(视频)'
|
||||
AND pm.category = '0'), 0) AS run_video_workday,
|
||||
|
||||
-- ======================================
|
||||
-- 类型5:检修
|
||||
-- ======================================
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '检修'
|
||||
AND pm.category = '0'), 0) AS maintain_total_days,
|
||||
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '检修'
|
||||
AND pm.category = '0'), 0) AS maintain_person_count,
|
||||
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '检修'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '检修'
|
||||
AND pm.category = '0'), 0) AS maintain_workday,
|
||||
|
||||
-- ======================================
|
||||
-- 类型6:值班
|
||||
-- ======================================
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '值班'
|
||||
AND pm.category = '0'), 0) AS duty_total_days,
|
||||
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '值班'
|
||||
AND pm.category = '0'), 0) AS duty_person_count,
|
||||
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '值班'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '值班'
|
||||
AND pm.category = '0'), 0) AS duty_workday,
|
||||
|
||||
-- ======================================
|
||||
-- 类型7:抢修
|
||||
-- ======================================
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '抢修'
|
||||
AND pm.category = '0'), 0) AS repair_total_days,
|
||||
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '抢修'
|
||||
AND pm.category = '0'), 0) AS repair_person_count,
|
||||
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '抢修'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '抢修'
|
||||
AND pm.category = '0'), 0) AS repair_workday,
|
||||
|
||||
-- ======================================
|
||||
-- 类型8:学习
|
||||
-- ======================================
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '学习'
|
||||
AND pm.category = '0'), 0) AS study_total_days,
|
||||
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '学习'
|
||||
AND pm.category = '0'), 0) AS study_person_count,
|
||||
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '学习'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '学习'
|
||||
AND pm.category = '0'), 0) AS study_workday,
|
||||
|
||||
-- ======================================
|
||||
-- 类型9:其他
|
||||
-- ======================================
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '其他'
|
||||
AND pm.category = '0'), 0) AS other_total_days,
|
||||
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '其他'
|
||||
AND pm.category = '0'), 0) AS other_person_count,
|
||||
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '其他'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '其他'
|
||||
AND pm.category = '0'), 0) AS other_workday,
|
||||
|
||||
-- ======================================
|
||||
-- 类型10:未安排(核心修改:移除“其他”类型工日的扣除)
|
||||
-- ======================================
|
||||
-- 未安排(核心:扣除所有有效类型工日,不硬编码类型)
|
||||
IFNULL(
|
||||
IFNULL(
|
||||
(SELECT DATEDIFF(
|
||||
LAST_DAY(STR_TO_DATE(CONCAT(#{monthlyPlan}, '-01'), '%Y-%m-%d')),
|
||||
DATE_FORMAT(STR_TO_DATE(CONCAT(#{monthlyPlan}, '-01'), '%Y-%m-%d'), '%Y-%m-01')
|
||||
) + 1),
|
||||
0
|
||||
) *
|
||||
IFNULL((
|
||||
IFNULL((SELECT COUNT(p.id)
|
||||
FROM tb_personnel p
|
||||
WHERE p.inspection_station_id = ista_inner.inspection_station_id
|
||||
AND p.is_active = '1'), 0) -
|
||||
IFNULL((SELECT COUNT(p.id)
|
||||
FROM tb_personnel p
|
||||
WHERE p.inspection_station_id = ista_inner.inspection_station_id
|
||||
AND p.long_term_secondment = '1'
|
||||
AND p.is_active = '1'), 0)
|
||||
), 0) -
|
||||
IFNULL((
|
||||
-- 休假工时
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '休假'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '休假'
|
||||
AND pm.category = '0'), 0) +
|
||||
|
||||
-- 培训工时
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '培训'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '培训'
|
||||
AND pm.category = '0'), 0) +
|
||||
|
||||
-- 运行工时
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行'
|
||||
AND pm.category = '0'), 0) +
|
||||
|
||||
-- 运行(视频)工时
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行(视频)'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '运行(视频)'
|
||||
AND pm.category = '0'), 0) +
|
||||
|
||||
-- 检修工时
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '检修'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '检修'
|
||||
AND pm.category = '0'), 0) +
|
||||
|
||||
-- 值班工时
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '值班'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '值班'
|
||||
AND pm.category = '0'), 0) +
|
||||
|
||||
-- 抢修工时
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '抢修'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '抢修'
|
||||
AND pm.category = '0'), 0) +
|
||||
|
||||
-- 学习工时
|
||||
IFNULL((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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '学习'
|
||||
AND pm.category = '0'), 0) *
|
||||
IFNULL((SELECT IFNULL(SUM(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.plan_major_name = '学习'
|
||||
AND pm.category = '0'), 0)
|
||||
-- 移除:其他工时的累加(核心修改点)
|
||||
), 0), 0) AS unarrange_workday,
|
||||
|
||||
-- ======================================
|
||||
-- 类型11:分包用工
|
||||
-- ======================================
|
||||
(
|
||||
-- 总工日
|
||||
IFNULL(
|
||||
(SELECT DATEDIFF(
|
||||
LAST_DAY(STR_TO_DATE(CONCAT(#{monthlyPlan}, '-01'), '%Y-%m-%d')),
|
||||
DATE_FORMAT(STR_TO_DATE(CONCAT(#{monthlyPlan}, '-01'), '%Y-%m-%d'), '%Y-%m-01')
|
||||
) + 1),
|
||||
0
|
||||
) *
|
||||
IFNULL((
|
||||
IFNULL((SELECT COUNT(p.id)
|
||||
FROM tb_personnel p
|
||||
WHERE p.inspection_station_id = ista_inner.inspection_station_id
|
||||
AND p.is_active = '1'), 0) -
|
||||
IFNULL((SELECT COUNT(p.id)
|
||||
FROM tb_personnel p
|
||||
WHERE p.inspection_station_id = ista_inner.inspection_station_id
|
||||
AND p.long_term_secondment = '1'
|
||||
AND p.is_active = '1'), 0)
|
||||
), 0) -
|
||||
-- 扣除所有有效业务类型的总工日
|
||||
IFNULL((
|
||||
SELECT IFNULL(SUM(
|
||||
IFNULL(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1, 0) *
|
||||
IFNULL(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END,
|
||||
0
|
||||
)
|
||||
), 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_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.category = '0'
|
||||
AND pm.plan_major_name != '分包用工'
|
||||
), 0)
|
||||
), 0) AS unarrange_workday,
|
||||
-- 分包用工
|
||||
IFNULL((SELECT IFNULL(SUM(tmp.plan_skilled_worker_day + tmp.plan_auxiliary_worker_day), 0)
|
||||
FROM tb_monthly_plan tmp
|
||||
WHERE tmp.inspection_station_id = ista_inner.inspection_station_id
|
||||
AND tmp.monthly_plan = #{monthlyPlan}), 0) AS subcontract_workday
|
||||
|
||||
FROM tb_inspection_station ista_inner
|
||||
WHERE ista_inner.category = '0'
|
||||
AND ista_inner.is_active = '1'
|
||||
) AS base_data
|
||||
ORDER BY base_data.inspection_station_name ASC;
|
||||
) AS base_info
|
||||
-- 左关联动态类型聚合结果
|
||||
LEFT JOIN (
|
||||
-- 子查询2:动态类型聚合(按运检站分组,拼接字符串)
|
||||
SELECT
|
||||
tg.inspection_station_id,
|
||||
-- 聚合多个类型为字符串,|分隔类型,,分隔字段
|
||||
GROUP_CONCAT(
|
||||
CONCAT(
|
||||
REPLACE(tg.plan_major_name, ',', ','), -- 转义逗号,避免分隔符冲突
|
||||
',', tg.total_days,
|
||||
',', tg.person_count,
|
||||
',', tg.workday,
|
||||
',', bi.total_workday, -- 关联基础信息获取总工日
|
||||
',', bi.actual_station_num -- 关联基础信息获取实际在站人数
|
||||
)
|
||||
SEPARATOR '|' -- 类型之间的分隔符
|
||||
) AS type_str
|
||||
FROM (
|
||||
-- 子查询2.1:按运检站+专业分组,汇总单个类型数据
|
||||
SELECT
|
||||
tmp.inspection_station_id,
|
||||
pm.plan_major_name,
|
||||
-- 总天数(汇总单个计划的天数)
|
||||
SUM(IFNULL(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1, 0)) AS total_days,
|
||||
-- 总人数(汇总单个计划的参与人数)
|
||||
SUM(
|
||||
IFNULL(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END,
|
||||
0
|
||||
)
|
||||
) AS person_count,
|
||||
-- 总工日(汇总单个计划的工日)
|
||||
SUM(
|
||||
IFNULL(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1, 0) *
|
||||
IFNULL(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END,
|
||||
0
|
||||
)
|
||||
) AS workday
|
||||
FROM tb_monthly_plan tmp
|
||||
LEFT JOIN tb_plan_major pm ON tmp.plan_major_id = pm.plan_major_id
|
||||
WHERE tmp.monthly_plan = #{monthlyPlan}
|
||||
AND pm.category = '0'
|
||||
AND pm.plan_major_name != '分包用工'
|
||||
-- 过滤工日为0的无效数据
|
||||
AND IFNULL(
|
||||
IFNULL(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1, 0) *
|
||||
IFNULL(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END,
|
||||
0
|
||||
), 0) > 0
|
||||
GROUP BY tmp.inspection_station_id, pm.plan_major_name
|
||||
HAVING SUM(
|
||||
IFNULL(DATEDIFF(tmp.planned_end_time, tmp.planned_start_time) + 1, 0) *
|
||||
IFNULL(
|
||||
CASE
|
||||
WHEN tmp.plan_personnel IS NULL OR tmp.plan_personnel = '' THEN 0
|
||||
ELSE LENGTH(tmp.plan_personnel) - LENGTH(REPLACE(tmp.plan_personnel, ',', '')) + 1
|
||||
END,
|
||||
0
|
||||
)
|
||||
) > 0
|
||||
) AS tg
|
||||
-- 关联基础信息表,获取总工日和实际在站人数
|
||||
INNER JOIN (
|
||||
-- 复用基础信息查询,避免重复计算
|
||||
SELECT
|
||||
ista_inner.inspection_station_id,
|
||||
IFNULL((SELECT COUNT(p.id)
|
||||
FROM tb_personnel p
|
||||
WHERE p.inspection_station_id = ista_inner.inspection_station_id
|
||||
AND p.is_active = '1'), 0) -
|
||||
IFNULL((SELECT COUNT(p.id)
|
||||
FROM tb_personnel p
|
||||
WHERE p.inspection_station_id = ista_inner.inspection_station_id
|
||||
AND p.long_term_secondment = '1'
|
||||
AND p.is_active = '1'), 0) AS actual_station_num,
|
||||
IFNULL(
|
||||
(SELECT DATEDIFF(
|
||||
LAST_DAY(STR_TO_DATE(CONCAT(#{monthlyPlan}, '-01'), '%Y-%m-%d')),
|
||||
DATE_FORMAT(STR_TO_DATE(CONCAT(#{monthlyPlan}, '-01'), '%Y-%m-%d'), '%Y-%m-01')
|
||||
) + 1),
|
||||
0
|
||||
) *
|
||||
IFNULL((
|
||||
IFNULL((SELECT COUNT(p.id)
|
||||
FROM tb_personnel p
|
||||
WHERE p.inspection_station_id = ista_inner.inspection_station_id
|
||||
AND p.is_active = '1'), 0) -
|
||||
IFNULL((SELECT COUNT(p.id)
|
||||
FROM tb_personnel p
|
||||
WHERE p.inspection_station_id = ista_inner.inspection_station_id
|
||||
AND p.long_term_secondment = '1'
|
||||
AND p.is_active = '1'), 0)
|
||||
), 0) AS total_workday
|
||||
FROM tb_inspection_station ista_inner
|
||||
WHERE ista_inner.category = '0'
|
||||
AND ista_inner.is_active = '1'
|
||||
) AS bi ON tg.inspection_station_id = bi.inspection_station_id
|
||||
-- 按运检站分组,聚合类型字符串
|
||||
GROUP BY tg.inspection_station_id
|
||||
) AS type_data ON base_info.inspection_station_id = type_data.inspection_station_id
|
||||
-- 按运检站名称排序
|
||||
ORDER BY base_info.inspection_station_name ASC;
|
||||
]]>
|
||||
</select>
|
||||
|
||||
<select id="getMonthlyPlanById" resultType="com.bonus.digital.dao.MonthlyPlanVo">
|
||||
select tmp.monthly_plan_id,
|
||||
tmp.monthly_plan,
|
||||
|
|
|
|||
Loading…
Reference in New Issue