diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java index 20806f2..b5cb9bc 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java @@ -3,6 +3,7 @@ package com.ruoyi.system.controller; import java.io.*; import java.math.BigDecimal; import java.net.URLEncoder; +import java.text.SimpleDateFormat; import java.util.*; import com.alibaba.excel.EasyExcel; @@ -491,10 +492,10 @@ public class ProcessOrderProController extends BaseController { if (!found) { processDataList.add(item); } - List excelDTOList = iProcessOrderProService.getRouteAndBomDetail( processDataList,orderPro); + } - + List excelDTOList = iProcessOrderProService.getRouteAndBomDetail(processDataList,orderPro); // 使用Excel模板文件 String templatePath = "EXCEL模板/生产及工艺计划模版.xlsx"; String outputPath = "D:/file/" + orderPro.getProductionOrderNo() + "生产及工艺计划表.xlsx"; @@ -551,6 +552,11 @@ public class ProcessOrderProController extends BaseController { List> evoDataList = convertEVOProductsDataToMapList(evoProductsList); dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("EVOProductsDataVO", evoDataList)); } + // 添加工艺路线 + if (!excelDTOList.isEmpty()) { + List> routeExcelList = convertEVORoutesDataToMapList(excelDTOList); + dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessRouteExcelDTO", routeExcelList)); + } // 使用模板导出Excel ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, outputPath, staticDataMap, dynamicDataMappingList); @@ -584,6 +590,7 @@ public class ProcessOrderProController extends BaseController { } } + /** * 读取RawDataTable数据 */ @@ -984,6 +991,65 @@ public class ProcessOrderProController extends BaseController { } return mapList; } + /** + * 转换ProcessRouteExcelDTO为Map列表(用于模板) + */ + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd"); + private String formatDate(Date date) { + return date == null ? "" : DATE_FORMAT.format(date); + } + private List> convertEVORoutesDataToMapList(List evoProductsList) { + + List> mapList = new ArrayList<>(); + int index = 1; + for (ProcessRouteExcelDTO dto : evoProductsList) { + Map map = new HashMap<>(); + map.put("index", index); + // 基础信息 + map.put("routeDescription", dto.getRouteDescription()); + map.put("materialCode", dto.getMaterialCode()); + map.put("materialName", dto.getMaterialName()); + map.put("material", dto.getMaterial()); + map.put("discWeight", dto.getDiscWeight()); + + + // BOM 部分 + map.put("rawMaterialCode", dto.getRawMaterialCode()); + map.put("rawMaterialName", dto.getRawMaterialName()); + map.put("bomMaterial", dto.getBomMaterial()); + map.put("bomDanZhong", dto.getBomDanZhong()); + map.put("discUsage", dto.getDiscUsage()); + map.put("bomUnit", dto.getBomUnit()); + + // 工艺部分 + map.put("processNo", dto.getProcessNo()); + map.put("workCenter", dto.getWorkCenter()); + map.put("processName", dto.getProcessName()); + map.put("processDescription", dto.getProcessDescription()); + map.put("processControl", dto.getProcessControl()); + map.put("activityDuration", dto.getActivityDuration()); + map.put("activityUnit", dto.getActivityUnit()); + + // 数量部分 + map.put("unitQuantity", dto.getUnitQuantity()); + map.put("batchQuantity", dto.getBatchQuantity()); + map.put("firstBatchQuantity", dto.getFirstBatchQuantity()); + + // 时间字段格式化 + map.put("planStartTime", formatDate(dto.getPlanStartTime())); + map.put("planEndTime", formatDate(dto.getPlanEndTime())); + map.put("xuStartTime", formatDate(dto.getXuStartTime())); + map.put("xuEndTime", formatDate(dto.getXuEndTime())); + + mapList.add(map); + index++; + } + return mapList; + } + + + + /** * 转换工艺VO为Map列表(用于模板) diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessRouteExcelDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessRouteExcelDTO.java index b3d5e5f..67beeb3 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessRouteExcelDTO.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/ProcessRouteExcelDTO.java @@ -59,7 +59,7 @@ public class ProcessRouteExcelDTO { /** * 材料BOM用量 */ - private Double discUsage; + private String discUsage; /** * 材料BOM单位 */ @@ -103,13 +103,13 @@ public class ProcessRouteExcelDTO { /** * 单台数量 */ - private Long unitQuantity; + private Double unitQuantity; /** * 本批数量 */ - private Long batchQuantity; + private String batchQuantity; /** * 首批数量 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessOrderProServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessOrderProServiceImpl.java index aa2e4d8..123559c 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessOrderProServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessOrderProServiceImpl.java @@ -1132,17 +1132,191 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { * 将工艺部分 材料BOM部分 合并成ProcessRouteExcelDTO * @return */ - @Override - public List getRouteAndBomDetail(List processDataList,ProcessOrderPro orderPro) { - String proRoot = orderPro.getProductionOrderNo(); - //工艺部分 - List processRoutes = iProcessRouteService.selectByProjectNumber(proRoot); - List materialBoms = materialBomService.selectByProCode(proRoot); - for (ProductionOrderVo productionOrderVo : processDataList) { - ProcessRouteExcelDTO processRouteExcelDTO = new ProcessRouteExcelDTO(); + //@Override + public List getRouteAndBomDetail1(List processDataList, + ProcessOrderPro orderPro) { + String proRoot = orderPro.getProductionOrderNo(); + + // 查出所有工艺路线和BOM + List allRoutes = iProcessRouteService.selectByProjectNumber(proRoot); + List allBoms = materialBomService.selectByProCode(proRoot); + + List resultList = new ArrayList<>(); + + for (ProductionOrderVo orderVo : processDataList) { + String materialCode = orderVo.getDrawingNo(); // 这里我假设 drawingNo == materialCode + + // 按 materialCode 过滤 + List processRoutes = allRoutes.stream() + .filter(r -> materialCode.equals(r.getMaterialCode())) + .collect(Collectors.toList()); + + List materialBoms = allBoms.stream() + .filter(b -> materialCode.equals(b.getParentMaterialCode())) + .collect(Collectors.toList()); + + // 对齐到最长列表 + int maxSize = Math.max(processRoutes.size(), materialBoms.size()); + for (int i = 0; i < maxSize; i++) { + ProcessRouteExcelDTO dto = new ProcessRouteExcelDTO(); + + // 订单基础信息 + dto.setRouteDescription(orderVo.getProductionOrderNo()); + dto.setMaterialCode(orderVo.getDrawingNo()); + dto.setMaterialName(orderVo.getDrawingName()); + dto.setMaterial(orderVo.getMaterial()); + dto.setDiscWeight(orderVo.getSingleWeight()); + dto.setUnitQuantity(orderVo.getQuantity()); + dto.setBatchQuantity(orderVo.getBatchQuantity()); + + + // 工艺部分 + if (i < processRoutes.size()) { + ProcessRoute route = processRoutes.get(i); + dto.setProcessNo(route.getProcessNo()); + dto.setProcessName(route.getProcessName()); + dto.setWorkCenter(route.getWorkCenter()); + dto.setProcessDescription(route.getProcessDescription()); + dto.setProcessControl(route.getProcessControl()); + dto.setActivityDuration(route.getActivityDuration()); + dto.setActivityUnit(route.getActivityUnit()); + dto.setXuEndTime(route.getXuEndTime()); + dto.setXuStartTime(route.getXuStartTime()); + } + + // BOM 部分 + if (i < materialBoms.size()) { + MaterialBom bom = materialBoms.get(i); + dto.setRawMaterialCode(bom.getMaterialCode()); + dto.setRawMaterialName(bom.getMaterialName()); + dto.setBomMaterial(bom.getMaterialType()); + dto.setBomUnit(bom.getUnit()); + dto.setDiscUsage(bom.getQuantity()); + } + + resultList.add(dto); + } + } + return resultList; + } +/** + * 将工艺部分 材料BOM部分 合并成ProcessRouteExcelDTO + * @return + */ +@Override +public List getRouteAndBomDetail(List processDataList, + ProcessOrderPro orderPro) { + String proRoot = orderPro.getProductionOrderNo(); + + // 查出所有工艺路线和BOM + List allRoutes = iProcessRouteService.selectByProjectNumber(proRoot); + List allBoms = materialBomService.selectByProCode(proRoot); + + List resultList = new ArrayList<>(); + + // 规范化 key:trim + upper,避免空格/大小写导致匹配失败 + Function normalize = s -> s == null ? "" : s.trim().toUpperCase(); + + // 按 materialCode 分组(工艺路线) + Map> routeMap = allRoutes.stream() + .collect(Collectors.groupingBy(r -> normalize.apply(r.getMaterialCode()))); + + // 按 parentMaterialCode 分组(BOM 的 parent) + Map> bomMap = allBoms.stream() + .collect(Collectors.groupingBy(b -> normalize.apply(b.getParentMaterialCode()))); + + // 把订单数据做成 Map(key = drawingNo 规范化) + Map orderMap = processDataList.stream() + .collect(Collectors.toMap(vo -> normalize.apply(vo.getDrawingNo()), vo -> vo, (a, b) -> a)); + + // 先把 routeMap 的 key 加入(保证 processRoutes 为基础),再补上 orderMap 中但不在 routeMap 的物料 + LinkedHashSet materialKeys = new LinkedHashSet<>(); + materialKeys.addAll(routeMap.keySet()); // 以工艺路线为主序 + orderMap.keySet().stream() + .filter(key -> !materialKeys.contains(key)) + .forEach(materialKeys::add); // 补充仅在订单里的物料 + + // 遍历每个物料编码(规范化 key) + for (String key : materialKeys) { + List processRoutes = routeMap.getOrDefault(key, Collections.emptyList()); + List materialBoms = bomMap.getOrDefault(key, Collections.emptyList()); + ProductionOrderVo orderVo = orderMap.get(key); // 可能为 null + + // 用于显示在 DTO 中的原始物料编码(未规范化的形式) + String originalMaterialCode = null; + String originalMaterialName = null; + String originalMaterial = null; + String originalDiscWeight = null; + if (orderVo != null) { + originalMaterialCode = orderVo.getDrawingNo(); + originalMaterialName = orderVo.getDrawingName(); + originalMaterial = orderVo.getMaterial(); + originalDiscWeight = String.valueOf(orderVo.getSingleWeight()); + } else if (!processRoutes.isEmpty()) { + originalMaterialCode = processRoutes.get(0).getMaterialCode(); + } else if (!materialBoms.isEmpty()) { + originalMaterialCode = materialBoms.get(0).getParentMaterialCode(); + } else { + originalMaterialCode = key; // 退路:用规范化 key } - return Collections.emptyList(); + // 以 processRoutes 为主,行数 = max(processRoutes.size(), materialBoms.size()) + int maxSize = Math.max(processRoutes.size(), materialBoms.size()); + // 如果两边都为空但有订单(order-only),也至少输出一行 + if (maxSize == 0 && orderVo != null) { + maxSize = 1; + } + + for (int i = 0; i < maxSize; i++) { + ProcessRouteExcelDTO dto = new ProcessRouteExcelDTO(); + + // 订单基础信息(有就填) + if (orderVo != null) { + dto.setRouteDescription(orderVo.getProductionOrderNo()); + dto.setMaterialCode(orderVo.getDrawingNo()); + dto.setMaterialName(orderVo.getDrawingName()); + dto.setMaterial(orderVo.getMaterial()); + dto.setDiscWeight(orderVo.getSingleWeight()); + dto.setUnitQuantity(orderVo.getQuantity()); + dto.setBatchQuantity(orderVo.getBatchQuantity()); + } else { + // 若无订单,则至少把 materialCode 放入显示(用原始值) + dto.setMaterialCode(originalMaterialCode); + dto.setMaterialName(originalMaterialName); + dto.setMaterial(originalMaterial); + dto.setDiscUsage(originalDiscWeight); + } + + // 工艺部分(有就填) + if (i < processRoutes.size()) { + ProcessRoute route = processRoutes.get(i); + dto.setProcessNo(route.getProcessNo()); + dto.setProcessName(route.getProcessName()); + dto.setWorkCenter(route.getWorkCenter()); + dto.setProcessDescription(route.getProcessDescription()); + dto.setProcessControl(route.getProcessControl()); + dto.setActivityDuration(route.getActivityDuration()); + dto.setActivityUnit(route.getActivityUnit()); + dto.setXuEndTime(route.getXuEndTime()); + dto.setXuStartTime(route.getXuStartTime()); + } + + // BOM 部分(以 parentMaterialCode 为匹配依据) + if (i < materialBoms.size()) { + MaterialBom bom = materialBoms.get(i); + dto.setRawMaterialCode(bom.getMaterialCode()); + dto.setRawMaterialName(bom.getMaterialName()); + dto.setBomMaterial(bom.getMaterialType()); + dto.setBomUnit(bom.getUnit()); + dto.setDiscUsage(bom.getQuantity()); + } + + resultList.add(dto); + } } + return resultList; +} + + } diff --git a/ruoyi-system/src/main/resources/EXCEL模板/生产及工艺计划模版.xlsx b/ruoyi-system/src/main/resources/EXCEL模板/生产及工艺计划模版.xlsx index b0ff692..cb29522 100644 Binary files a/ruoyi-system/src/main/resources/EXCEL模板/生产及工艺计划模版.xlsx and b/ruoyi-system/src/main/resources/EXCEL模板/生产及工艺计划模版.xlsx differ