月计划人员安排导出合并功能优化

This commit is contained in:
LHD_HY 2025-12-26 13:36:20 +08:00
parent c0aeb2020c
commit 3f41011ea9
7 changed files with 140 additions and 93 deletions

View File

@ -11,9 +11,10 @@ import java.net.URLEncoder;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
/** /**
* 运检人员月度安排导出工具类 * 运检人员月度安排导出工具类关联人员安排表
*/ */
public class MonthPlanExcelExporter { public class MonthPlanExcelExporter {
@ -34,9 +35,9 @@ public class MonthPlanExcelExporter {
private static final int MAX_COL_WIDTH = 30; // 最大列宽字符 private static final int MAX_COL_WIDTH = 30; // 最大列宽字符
/** /**
* 导出运检人员月度安排Excel * 导出运检人员月度安排Excel关联人员安排表
* @param response 响应对象 * @param response 响应对象
* @param dataList 人员月度安排数据 * @param dataList 人员月度安排数据已关联人员安排表
* @param year 年份 * @param year 年份
* @param month 月份 * @param month 月份
* @param sheetName sheet名称 * @param sheetName sheet名称
@ -59,14 +60,13 @@ public class MonthPlanExcelExporter {
// 2. 创建Workbook和Sheet // 2. 创建Workbook和Sheet
Workbook workbook = new XSSFWorkbook(); Workbook workbook = new XSSFWorkbook();
Sheet sheet = workbook.createSheet(sheetName); Sheet sheet = workbook.createSheet(sheetName);
// 移除错误的 sheet.setWrapText(true); 该方法不存在自动换行通过 CellStyle 设置
// 3. 构建样式 // 3. 构建样式
CellStyle titleStyle = buildTitleStyle(workbook); // 标题样式含自动换行 CellStyle titleStyle = buildTitleStyle(workbook); // 标题样式含自动换行
CellStyle headerStyle = buildHeaderStyle(workbook); // 表头样式含自动换行 CellStyle headerStyle = buildHeaderStyle(workbook); // 表头样式含自动换行
CellStyle contentStyle = buildContentStyle(workbook); // 内容样式含自动换行 CellStyle contentStyle = buildContentStyle(workbook); // 内容样式含自动换行
// 4. 转换原始数据为行映射按运检站+姓名分组 // 4. 转换原始数据为行映射按运检站+姓名分组按人员安排表的day填充
List<Map<String, Object>> rowDataList = convertToDailyMapList(finalData, year, month); List<Map<String, Object>> rowDataList = convertToDailyMapList(finalData, year, month);
// 5. 构建表头标题行 + 列头行 // 5. 构建表头标题行 + 列头行
@ -76,10 +76,10 @@ public class MonthPlanExcelExporter {
int dataStartRow = headerRowCount; int dataStartRow = headerRowCount;
fillDataRows(sheet, contentStyle, rowDataList, dataStartRow, daysInMonth); fillDataRows(sheet, contentStyle, rowDataList, dataStartRow, daysInMonth);
// 7. 合并日期列相同内容的连续单元格 // 7. 合并日期列相同内容的连续单元格基于人员安排表的day
mergeSameContentCells(sheet, rowDataList, dataStartRow, daysInMonth); mergeSameContentCells(sheet, rowDataList, dataStartRow, daysInMonth);
// 8. 核心自适应列宽替代固定列宽 // 8. 自适应列宽
autoAdjustColumnWidths(sheet, daysInMonth); autoAdjustColumnWidths(sheet, daysInMonth);
// 9. 响应输出 // 9. 响应输出
@ -97,7 +97,7 @@ public class MonthPlanExcelExporter {
} }
/** /**
* 转换原始数据为按行映射的结构按运检站+姓名分组 * 转换原始数据为按行映射的结构按运检站+姓名分组基于人员安排表的day
*/ */
private static List<Map<String, Object>> convertToDailyMapList( private static List<Map<String, Object>> convertToDailyMapList(
List<ExportMonthPlanPersonVo> dataList, int year, int month) { List<ExportMonthPlanPersonVo> dataList, int year, int month) {
@ -109,45 +109,52 @@ public class MonthPlanExcelExporter {
String key = item.getInspectionStationName() + "_" + item.getName(); String key = item.getInspectionStationName() + "_" + item.getName();
// 初始化行数据 // 初始化行数据
rowMap.computeIfAbsent(key, k -> { Map<String, Object> row = rowMap.computeIfAbsent(key, k -> {
Map<String, Object> row = new LinkedHashMap<>(); Map<String, Object> newRow = new LinkedHashMap<>();
// 固定列空值兜底避免null // 固定列空值兜底
row.put("运检站", item.getInspectionStationName() == null ? "" : item.getInspectionStationName()); newRow.put("运检站", item.getInspectionStationName() == null ? "" : item.getInspectionStationName());
row.put("姓名", item.getName() == null ? "" : item.getName()); newRow.put("姓名", item.getName() == null ? "" : item.getName());
row.put("性别", item.getSex() == null ? "" : item.getSex()); newRow.put("性别", item.getSex() == null ? "" : item.getSex());
row.put("岗位", item.getPositionName() == null ? "" : item.getPositionName()); newRow.put("岗位", item.getPositionName() == null ? "" : item.getPositionName());
row.put("人员性质", item.getPersonnelNatureName() == null ? "" : item.getPersonnelNatureName()); newRow.put("人员性质", item.getPersonnelNatureName() == null ? "" : item.getPersonnelNatureName());
row.put("分类", item.getPersonnelClassificationName() == null ? "" : item.getPersonnelClassificationName()); newRow.put("分类", item.getPersonnelClassificationName() == null ? "" : item.getPersonnelClassificationName());
// 初始化日期列 // 初始化日期列默认空
Map<Integer, String> dailyContent = new HashMap<>(); Map<Integer, String> dailyContent = new HashMap<>();
for (int d = 1; d <= daysInMonth; d++) { for (int d = 1; d <= daysInMonth; d++) {
dailyContent.put(d, ""); dailyContent.put(d, "");
} }
row.put("dailyContent", dailyContent); newRow.put("dailyContent", dailyContent);
return row; return newRow;
}); });
// 填充日期内容空值校验避免日期解析失败 // 填充人员安排表的day对应的内容核心修改
Map<Integer, String> dailyContent = (Map<Integer, String>) rowMap.get(key).get("dailyContent"); Map<Integer, String> dailyContent = (Map<Integer, String>) row.get("dailyContent");
if (item.getPlannedStartTime() == null || item.getPlannedEndTime() == null) { if (item.getArrangeDays() == null || item.getArrangeDays().isEmpty()) {
continue; continue;
} }
LocalDate start = LocalDate.parse(item.getPlannedStartTime(), DATE_FORMATTER);
LocalDate end = LocalDate.parse(item.getPlannedEndTime(), DATE_FORMATTER);
for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) { // 遍历该人员的所有安排日期填充工作内容
if (date.getYear() == year && date.getMonthValue() == month) { for (String dayStr : item.getArrangeDays()) {
int day = date.getDayOfMonth(); try {
LocalDate arrangeDay = LocalDate.parse(dayStr, DATE_FORMATTER);
// 仅处理当月日期
if (arrangeDay.getYear() == year && arrangeDay.getMonthValue() == month) {
int day = arrangeDay.getDayOfMonth();
String currentContent = dailyContent.get(day); String currentContent = dailyContent.get(day);
String newContent = item.getWorkContent() == null ? "" : item.getWorkContent(); String newContent = item.getWorkContent() == null ? "" : item.getWorkContent();
// 多段工作内容换行拼接
if (currentContent == null || currentContent.trim().isEmpty()) { if (currentContent == null || currentContent.trim().isEmpty()) {
dailyContent.put(day, newContent); dailyContent.put(day, newContent);
} else { } else {
dailyContent.put(day, currentContent + "\n" + newContent); dailyContent.put(day, currentContent + "\n" + newContent);
} }
} }
} catch (Exception e) {
// 日期格式错误跳过
continue;
}
} }
} }
@ -159,16 +166,13 @@ public class MonthPlanExcelExporter {
*/ */
private static CellStyle buildTitleStyle(Workbook workbook) { private static CellStyle buildTitleStyle(Workbook workbook) {
CellStyle style = workbook.createCellStyle(); CellStyle style = workbook.createCellStyle();
// 字体配置
Font font = workbook.createFont(); Font font = workbook.createFont();
font.setBold(true); font.setBold(true);
font.setFontName("宋体"); font.setFontName("宋体");
font.setFontHeightInPoints((short) 16); font.setFontHeightInPoints((short) 16);
style.setFont(font); style.setFont(font);
// 对齐方式垂直+水平居中
style.setAlignment(HorizontalAlignment.CENTER); style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER);
// 边框
style.setBorderTop(BorderStyle.THIN); style.setBorderTop(BorderStyle.THIN);
style.setBorderBottom(BorderStyle.THIN); style.setBorderBottom(BorderStyle.THIN);
style.setBorderLeft(BorderStyle.THIN); style.setBorderLeft(BorderStyle.THIN);
@ -177,7 +181,6 @@ public class MonthPlanExcelExporter {
style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
style.setRightBorderColor(IndexedColors.BLACK.getIndex()); style.setRightBorderColor(IndexedColors.BLACK.getIndex());
// 核心单元格自动换行解决长内容遮挡
style.setWrapText(true); style.setWrapText(true);
return style; return style;
} }
@ -202,7 +205,7 @@ public class MonthPlanExcelExporter {
style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
style.setRightBorderColor(IndexedColors.BLACK.getIndex()); style.setRightBorderColor(IndexedColors.BLACK.getIndex());
style.setWrapText(true); // 自动换行 style.setWrapText(true);
return style; return style;
} }
@ -215,7 +218,6 @@ public class MonthPlanExcelExporter {
font.setFontName("宋体"); font.setFontName("宋体");
font.setFontHeightInPoints((short) 11); font.setFontHeightInPoints((short) 11);
style.setFont(font); style.setFont(font);
// 水平+垂直居中解决内容上下/左右遮挡
style.setAlignment(HorizontalAlignment.CENTER); style.setAlignment(HorizontalAlignment.CENTER);
style.setVerticalAlignment(VerticalAlignment.CENTER); style.setVerticalAlignment(VerticalAlignment.CENTER);
style.setBorderTop(BorderStyle.THIN); style.setBorderTop(BorderStyle.THIN);
@ -226,7 +228,7 @@ public class MonthPlanExcelExporter {
style.setBottomBorderColor(IndexedColors.BLACK.getIndex()); style.setBottomBorderColor(IndexedColors.BLACK.getIndex());
style.setLeftBorderColor(IndexedColors.BLACK.getIndex()); style.setLeftBorderColor(IndexedColors.BLACK.getIndex());
style.setRightBorderColor(IndexedColors.BLACK.getIndex()); style.setRightBorderColor(IndexedColors.BLACK.getIndex());
style.setWrapText(true); // 自动换行 style.setWrapText(true);
return style; return style;
} }
@ -241,7 +243,7 @@ public class MonthPlanExcelExporter {
// 行0标题行合并所有列 // 行0标题行合并所有列
Row titleRow = sheet.createRow(0); Row titleRow = sheet.createRow(0);
titleRow.setHeightInPoints(40); // 加高标题行适配换行 titleRow.setHeightInPoints(40);
Cell titleCell = titleRow.createCell(0); Cell titleCell = titleRow.createCell(0);
titleCell.setCellValue(title); titleCell.setCellValue(title);
titleCell.setCellStyle(titleStyle); titleCell.setCellStyle(titleStyle);
@ -249,7 +251,7 @@ public class MonthPlanExcelExporter {
// 行1列头行 // 行1列头行
Row headerRow = sheet.createRow(1); Row headerRow = sheet.createRow(1);
headerRow.setHeightInPoints(30); // 加高表头行 headerRow.setHeightInPoints(30);
// 固定列头 // 固定列头
createCell(headerRow, COL_SERIAL, "序号", headerStyle); createCell(headerRow, COL_SERIAL, "序号", headerStyle);
createCell(headerRow, COL_STATION, "运检站", headerStyle); createCell(headerRow, COL_STATION, "运检站", headerStyle);
@ -264,24 +266,24 @@ public class MonthPlanExcelExporter {
createCell(headerRow, colIndex, d + "", headerStyle); createCell(headerRow, colIndex, d + "", headerStyle);
} }
return 2; // 表头总行数标题行(0) + 列头行(1) return 2;
} }
/** /**
* 填充数据行加高行高适配自动换行 * 填充数据行
*/ */
private static void fillDataRows(Sheet sheet, CellStyle contentStyle, private static void fillDataRows(Sheet sheet, CellStyle contentStyle,
List<Map<String, Object>> rowDataList, List<Map<String, Object>> rowDataList,
int startRowNum, int daysInMonth) { int startRowNum, int daysInMonth) {
int serialNum = 1; // 序号 int serialNum = 1;
for (int i = 0; i < rowDataList.size(); i++) { for (int i = 0; i < rowDataList.size(); i++) {
int rowNum = startRowNum + i; int rowNum = startRowNum + i;
Row row = sheet.createRow(rowNum); Row row = sheet.createRow(rowNum);
row.setHeightInPoints(35); // 加高数据行解决换行内容遮挡 row.setHeightInPoints(35);
Map<String, Object> rowData = rowDataList.get(i); Map<String, Object> rowData = rowDataList.get(i);
// 填充固定列空值兜底 // 填充固定列
createCell(row, COL_SERIAL, serialNum++, contentStyle); createCell(row, COL_SERIAL, serialNum++, contentStyle);
createCell(row, COL_STATION, rowData.get("运检站"), contentStyle); createCell(row, COL_STATION, rowData.get("运检站"), contentStyle);
createCell(row, COL_NAME, rowData.get("姓名"), contentStyle); createCell(row, COL_NAME, rowData.get("姓名"), contentStyle);
@ -290,7 +292,7 @@ public class MonthPlanExcelExporter {
createCell(row, COL_NATURE, rowData.get("人员性质"), contentStyle); createCell(row, COL_NATURE, rowData.get("人员性质"), contentStyle);
createCell(row, COL_CLASSIFY, rowData.get("分类"), contentStyle); createCell(row, COL_CLASSIFY, rowData.get("分类"), contentStyle);
// 填充日期列 // 填充日期列仅人员安排表有数据的日期显示内容
Map<Integer, String> dailyContent = (Map<Integer, String>) rowData.get("dailyContent"); Map<Integer, String> dailyContent = (Map<Integer, String>) rowData.get("dailyContent");
for (int d = 1; d <= daysInMonth; d++) { for (int d = 1; d <= daysInMonth; d++) {
int colIndex = FIRST_DATE_COL + (d - 1); int colIndex = FIRST_DATE_COL + (d - 1);
@ -301,11 +303,10 @@ public class MonthPlanExcelExporter {
} }
/** /**
* 合并日期列中相同内容的连续单元格 * 合并日期列中相同内容的连续单元格基于人员安排表的day
*/ */
private static void mergeSameContentCells(Sheet sheet, List<Map<String, Object>> rowDataList, private static void mergeSameContentCells(Sheet sheet, List<Map<String, Object>> rowDataList,
int dataStartRow, int daysInMonth) { int dataStartRow, int daysInMonth) {
// 遍历每一行
for (int rowIdx = 0; rowIdx < rowDataList.size(); rowIdx++) { for (int rowIdx = 0; rowIdx < rowDataList.size(); rowIdx++) {
int currentRowNum = dataStartRow + rowIdx; int currentRowNum = dataStartRow + rowIdx;
Map<String, Object> rowData = rowDataList.get(rowIdx); Map<String, Object> rowData = rowDataList.get(rowIdx);
@ -330,15 +331,14 @@ public class MonthPlanExcelExporter {
} }
} }
// 若有连续相同内容合并单元格 // 合并连续单元格
if (endDay > d) { if (endDay > d) {
int startCol = FIRST_DATE_COL + (d - 1); int startCol = FIRST_DATE_COL + (d - 1);
int endCol = FIRST_DATE_COL + (endDay - 1); int endCol = FIRST_DATE_COL + (endDay - 1);
sheet.addMergedRegion(new CellRangeAddress( sheet.addMergedRegion(new CellRangeAddress(
currentRowNum, currentRowNum, // 同一行 currentRowNum, currentRowNum,
startCol, endCol // 起始列-结束列 startCol, endCol
)); ));
// 跳过已合并的列
d = endDay + 1; d = endDay + 1;
} else { } else {
d++; d++;
@ -348,25 +348,15 @@ public class MonthPlanExcelExporter {
} }
/** /**
* 核心自适应列宽替代固定列宽 * 自适应列宽
* 1. 自动计算每列的最大内容宽度
* 2. 限制最小/最大宽度避免过窄/过宽
* 3. 兼容合并单元格的列宽计算
*/ */
private static void autoAdjustColumnWidths(Sheet sheet, int daysInMonth) { private static void autoAdjustColumnWidths(Sheet sheet, int daysInMonth) {
// 计算总列数固定列7列 + 日期列
int totalCols = FIRST_DATE_COL + daysInMonth; int totalCols = FIRST_DATE_COL + daysInMonth;
// 遍历所有列自适应宽度
for (int colIndex = 0; colIndex < totalCols; colIndex++) { for (int colIndex = 0; colIndex < totalCols; colIndex++) {
// 第一步自动计算列宽POI原生方法基于列中最长内容
// true忽略合并单元格仅计算真实内容避免合并单元格导致列宽计算异常
sheet.autoSizeColumn(colIndex, true); sheet.autoSizeColumn(colIndex, true);
// 第二步转换列宽单位POI的列宽单位是1/256个字符宽度
int currentWidth = sheet.getColumnWidth(colIndex) / 256; int currentWidth = sheet.getColumnWidth(colIndex) / 256;
// 第三步限制最小/最大宽度兜底
int targetWidth; int targetWidth;
if (currentWidth < MIN_COL_WIDTH) { if (currentWidth < MIN_COL_WIDTH) {
targetWidth = MIN_COL_WIDTH; targetWidth = MIN_COL_WIDTH;
@ -376,13 +366,11 @@ public class MonthPlanExcelExporter {
targetWidth = currentWidth; targetWidth = currentWidth;
} }
// 第四步设置最终列宽加2个字符余量避免中文内容紧贴边框
sheet.setColumnWidth(colIndex, (targetWidth + 2) * 256); sheet.setColumnWidth(colIndex, (targetWidth + 2) * 256);
} }
// 特殊优化序号列强制最小宽度避免过窄 // 特殊列宽优化
sheet.setColumnWidth(COL_SERIAL, (MIN_COL_WIDTH + 1) * 256); sheet.setColumnWidth(COL_SERIAL, (MIN_COL_WIDTH + 1) * 256);
// 特殊优化运检站列放宽最大宽度适配长名称
int stationWidth = sheet.getColumnWidth(COL_STATION) / 256; int stationWidth = sheet.getColumnWidth(COL_STATION) / 256;
if (stationWidth > MAX_COL_WIDTH) { if (stationWidth > MAX_COL_WIDTH) {
sheet.setColumnWidth(COL_STATION, (MAX_COL_WIDTH + 5) * 256); sheet.setColumnWidth(COL_STATION, (MAX_COL_WIDTH + 5) * 256);
@ -390,11 +378,10 @@ public class MonthPlanExcelExporter {
} }
/** /**
* 创建单元格并设置值和样式空值兜底 * 创建单元格并设置值和样式
*/ */
private static void createCell(Row row, int colIndex, Object value, CellStyle style) { private static void createCell(Row row, int colIndex, Object value, CellStyle style) {
Cell cell = row.createCell(colIndex); Cell cell = row.createCell(colIndex);
// 空值兜底避免null导致单元格无内容
Object cellValue = value == null ? "" : value; Object cellValue = value == null ? "" : value;
if (cellValue instanceof String) { if (cellValue instanceof String) {
cell.setCellValue((String) cellValue); cell.setCellValue((String) cellValue);

View File

@ -135,7 +135,7 @@ public class MonthlyPlanController extends BaseController {
int month = LocalDate.now().getMonthValue(); int month = LocalDate.now().getMonthValue();
String monthlyPlan = monthlyPlanVo.getMonthlyPlan(); String monthlyPlan = monthlyPlanVo.getMonthlyPlan();
if (monthlyPlan != null && monthlyPlan.matches("\\d{4}-\\d{1,2}")) { // 校验格式yyyy-MM if (monthlyPlan != null && monthlyPlan.matches("\\d{4}-\\d{1,2}")) {
String[] yearMonthArr = monthlyPlan.split("-"); String[] yearMonthArr = monthlyPlan.split("-");
year = Integer.parseInt(yearMonthArr[0]); year = Integer.parseInt(yearMonthArr[0]);
month = Integer.parseInt(yearMonthArr[1]); month = Integer.parseInt(yearMonthArr[1]);

View File

@ -3,6 +3,8 @@ package com.bonus.digital.dao;
import com.bonus.common.annotation.Excel; import com.bonus.common.annotation.Excel;
import lombok.Data; import lombok.Data;
import java.util.List;
/** /**
* @Authorliang.chao * @Authorliang.chao
* @Date2025/12/17 - 15:32 * @Date2025/12/17 - 15:32
@ -28,4 +30,5 @@ public class ExportMonthPlanPersonVo {
private String personnelNatureName; private String personnelNatureName;
@Excel(name = "分类") @Excel(name = "分类")
private String personnelClassificationName; private String personnelClassificationName;
private List<String> arrangeDays;
} }

View File

@ -203,4 +203,8 @@ public class MonthlyPlanVo {
*/ */
private String keyWord; private String keyWord;
private String arrangeDay;
private String personnelNames;
} }

View File

@ -20,6 +20,12 @@ public interface MonthlyPlanMapper {
*/ */
List<MonthlyPlanVo> getCarUseSummary(MonthlyPlanVo monthlyPlanVo); List<MonthlyPlanVo> getCarUseSummary(MonthlyPlanVo monthlyPlanVo);
/**
* 查询人员安排表关联数据
*
*/
List<MonthlyPlanVo> getPlanWithPersonArrangement(MonthlyPlanVo monthlyPlanVo);
/** /**
* 月计划汇总 * 月计划汇总
*/ */

View File

@ -131,31 +131,64 @@ public class MonthlyPlanServiceImpl implements MonthlyPlanService {
@Override @Override
public List<ExportMonthPlanPersonVo> exportMonthlyPlanPerson(MonthlyPlanVo monthlyPlanVo) { public List<ExportMonthPlanPersonVo> exportMonthlyPlanPerson(MonthlyPlanVo monthlyPlanVo) {
List<MonthlyPlanVo> monthlyPlanVoList = monthlyPlanMapper.getPlanMajorListByMonth(monthlyPlanVo); // 1. 查询月度计划+人员安排表关联数据
List<ExportMonthPlanPersonVo> plannedList= new ArrayList<>(); List<MonthlyPlanVo> planWithArrangementList = monthlyPlanMapper.getPlanWithPersonArrangement(monthlyPlanVo);
for (MonthlyPlanVo monthlyPlanVo2 : monthlyPlanVoList) { List<ExportMonthPlanPersonVo> plannedList = new ArrayList<>();
//获取每个月计划投入的管理人员
List<String> plannedIdList = Arrays.asList(monthlyPlanVo2.getPlanPersonnel().split(",")); // 2. 按人员安排表的personnel_names拆分人员关联人员信息
PersonnelVo personnelVo = new PersonnelVo(); for (MonthlyPlanVo planVo : planWithArrangementList) {
personnelVo.setIdList(plannedIdList); String personnelNames = planVo.getPersonnelNames();
List<PersonnelVo> personnelList = personnelMapper.getPersonnelList(personnelVo); String arrangeDay = planVo.getArrangeDay();
for (PersonnelVo vo : personnelList) { if (personnelNames == null || personnelNames.trim().isEmpty() || arrangeDay == null) {
ExportMonthPlanPersonVo exportMonthPlanPersonVo = new ExportMonthPlanPersonVo(); continue;
exportMonthPlanPersonVo.setInspectionStationName(monthlyPlanVo2.getInspectionStationName());
exportMonthPlanPersonVo.setWorkContent(monthlyPlanVo2.getWorkContent());
exportMonthPlanPersonVo.setPlannedStartTime(monthlyPlanVo2.getPlannedStartTime());
exportMonthPlanPersonVo.setPlannedEndTime(monthlyPlanVo2.getPlannedEndTime());
exportMonthPlanPersonVo.setName(vo.getName());
exportMonthPlanPersonVo.setSex(vo.getSex());
exportMonthPlanPersonVo.setPositionName(vo.getPositionName());
exportMonthPlanPersonVo.setPersonnelNatureName(vo.getPersonnelNatureName());
exportMonthPlanPersonVo.setPersonnelClassificationName(vo.getPersonnelClassificationName());
plannedList.add(exportMonthPlanPersonVo);
}
}
return plannedList;
} }
// 拆分人员姓名逗号分隔
List<String> nameList = Arrays.asList(personnelNames.split(","));
for (String name : nameList) {
if (name.trim().isEmpty()) {
continue;
}
// 3. 查询人员详情
PersonnelVo personnelVo = new PersonnelVo();
personnelVo.setName(name.trim());
List<PersonnelVo> personnelList = personnelMapper.getPersonnelList(personnelVo);
if (personnelList.isEmpty()) {
continue;
}
// 4. 封装导出VO关联人员安排表的日期
for (PersonnelVo personnel : personnelList) {
ExportMonthPlanPersonVo exportVo = new ExportMonthPlanPersonVo();
exportVo.setInspectionStationName(planVo.getInspectionStationName());
exportVo.setWorkContent(planVo.getWorkContent());
exportVo.setName(personnel.getName());
exportVo.setSex(personnel.getSex());
exportVo.setPositionName(personnel.getPositionName());
exportVo.setPersonnelNatureName(personnel.getPersonnelNatureName());
exportVo.setPersonnelClassificationName(personnel.getPersonnelClassificationName());
// 关键设置人员安排表的日期支持多个日期
List<String> arrangeDays = new ArrayList<>();
arrangeDays.add(arrangeDay);
// 若同一人员有多个安排日期合并到arrangeDays需根据实际业务调整
Optional<ExportMonthPlanPersonVo> existVo = plannedList.stream()
.filter(v -> v.getName().equals(personnel.getName())
&& v.getInspectionStationName().equals(planVo.getInspectionStationName()))
.findFirst();
if (existVo.isPresent()) {
existVo.get().getArrangeDays().add(arrangeDay);
} else {
exportVo.setArrangeDays(arrangeDays);
plannedList.add(exportVo);
}
}
}
}
return plannedList;
}
/** /**
* 导出工作量汇总Excel * 导出工作量汇总Excel
* @param monthlyPlanVo 筛选条件 * @param monthlyPlanVo 筛选条件

View File

@ -169,6 +169,20 @@
where tmp.is_active = '1' and tmp.monthly_plan = #{monthlyPlan} where tmp.is_active = '1' and tmp.monthly_plan = #{monthlyPlan}
</select> </select>
<!-- 查询月度计划+人员安排表关联数据 -->
<select id="getPlanWithPersonArrangement" resultType="com.bonus.digital.dao.MonthlyPlanVo">
select
tmp.inspection_station_name,
tmp.work_content,
tmp.monthly_plan_id,
tpa.day as arrange_day,
tpa.personnel_names
from tb_monthly_plan tmp
left join tb_personnel_arrangement tpa on tmp.monthly_plan_id = tpa.monthly_plan_id
where tmp.is_active = '1'
and tmp.monthly_plan = #{monthlyPlan}
</select>
<select id="getWorkloadSummary" resultType="com.bonus.digital.dao.MonthlyPlanVo"> <select id="getWorkloadSummary" resultType="com.bonus.digital.dao.MonthlyPlanVo">
select select
tmp.inspection_station_id, tmp.inspection_station_id,