diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/poi/ExcelTemplateProc.java b/ruoyi-common/src/main/java/com/ruoyi/common/poi/ExcelTemplateProc.java index 6d30b38..1f7180d 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/poi/ExcelTemplateProc.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/poi/ExcelTemplateProc.java @@ -7,10 +7,12 @@ import org.apache.poi.xssf.usermodel.XSSFCell; import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.springframework.core.io.ClassPathResource; import org.springframework.util.ResourceUtils; import java.io.*; +import java.nio.file.Files; import java.util.List; import java.util.Map; @@ -22,27 +24,29 @@ import java.util.Map; public class ExcelTemplateProc { /** - * @param templateFileName - * @param exportFilePathAndName - * @param staticDataMap - * @param dynamicDataMappingList - * @return void - * @description: 根据模版导出Excel入口 - * @author susu - * @date 2024/2/20 + * 根据模版导出Excel入口 + * @param templateFileName 模板文件路径,可以是classpath路径 或 本地绝对路径 + * @param exportFilePathAndName 导出文件完整路径 + * @param staticDataMap 静态数据 + * @param dynamicDataMappingList 动态数据 */ - public static void doExportExcelByTemplateProc(String templateFileName, String exportFilePathAndName, + public static void doExportExcelByTemplateProc(String templateFileName, + String exportFilePathAndName, Map staticDataMap, List dynamicDataMappingList) throws IOException { - /** - * 1. 从resources下加载模板并替换 - * 使用 ResourceUtils 加载文件 - */ - File file = ResourceUtils.getFile("classpath:"+templateFileName); - InputStream inputStream = new FileInputStream(file); + + InputStream inputStream; + + if (templateFileName.startsWith("/") || templateFileName.contains(":")) { + // 绝对路径 (Windows: D:/... Linux: /opt/...) + inputStream = Files.newInputStream(new File(templateFileName).toPath()); + } else { + // classpath 路径 + ClassPathResource resource = new ClassPathResource(templateFileName); + inputStream = resource.getInputStream(); + } Workbook workbook = dealAllSheetsByTemplate(inputStream, staticDataMap, dynamicDataMappingList); - // 2. 保存到本地 saveExportFile(workbook, exportFilePathAndName); } @@ -87,15 +91,15 @@ public class ExcelTemplateProc { Map staticDataMap, List dynamicDataMappingList) throws IOException { XSSFWorkbook workbook = new XSSFWorkbook(inputStream); - - + + // 处理所有sheet页 for (int sheetIndex = 0; sheetIndex < workbook.getNumberOfSheets(); sheetIndex++) { XSSFSheet sheet = workbook.getSheetAt(sheetIndex); // 按模板处理sheet页 dealSheetDataByTemplate(sheet, staticDataMap, dynamicDataMappingList); } - + return workbook; } @@ -134,7 +138,7 @@ public class ExcelTemplateProc { if (row == null) { continue; // 跳过空行 } - + // 添加调试信息:检查每一行是否有静态数据占位符 if (row.getFirstCellNum() != -1 && row.getLastCellNum() != -1) { for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) { @@ -147,10 +151,10 @@ public class ExcelTemplateProc { } } } - + // 先处理静态数据,再处理动态数据 dealTemplateDataRow(row, null, staticDataMap); - + DynamicDataMapping dynamicDataMapping = getDynamicRowDataByMatch(row, dynamicDataMappingList); if (dynamicDataMapping != null) { i = getTemplateLastRowIndexAfterDealTemplate(sheet, i, dynamicDataMapping); @@ -177,21 +181,21 @@ public class ExcelTemplateProc { if (dataMap == null || row == null) { return; } - + int firstCellNum = row.getFirstCellNum(); int lastCellNum = row.getLastCellNum(); - + // 检查是否有有效的单元格范围 if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) { return; } - + // 添加调试信息:显示静态数据处理 if (dataPrefix == null || dataPrefix.isEmpty()) { System.out.println("开始处理静态数据行: " + row.getRowNum() + ", dataMap=" + dataMap.toString()); } - - + + for (int i = firstCellNum; i < lastCellNum; i++) { XSSFCell cell = row.getCell(i); if (cell != null) { @@ -224,16 +228,16 @@ public class ExcelTemplateProc { if (StringUtils.isEmpty(cellValue)) { return; } - - - + + + boolean flag = false; dataPrefix = StringUtils.isEmpty(dataPrefix) ? "" : (dataPrefix + "."); for (Map.Entry entry : dataMap.entrySet()) { // 循环所有,因为可能一行有多个占位符 String cellTemplateStr = "{{" + dataPrefix + entry.getKey() + "}}"; - - + + if (cellValue.contains(cellTemplateStr)) { // 替换模版中单元格的数据 String replacementValue = entry.getValue() == null ? "" : entry.getValue().toString(); @@ -267,29 +271,29 @@ public class ExcelTemplateProc { if (dynamicDataMappingList == null || dynamicDataMappingList.size() < 1) { return null; } - + // 检查行是否为空 if (row == null) { return null; } - + int firstCellNum = row.getFirstCellNum(); int lastCellNum = row.getLastCellNum(); - + // 检查是否有有效的单元格范围 if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) { return null; } - + for (int j = firstCellNum; j < lastCellNum; j++) { XSSFCell cell = row.getCell(j); if (cell == null) { continue; } - + String value = cell.getStringCellValue(); if (value != null) { - + for (DynamicDataMapping dynamicData : dynamicDataMappingList) { if (value.startsWith("{{" + dynamicData.getDataId() + ".")) { return dynamicData; @@ -361,20 +365,20 @@ public class ExcelTemplateProc { if (row == null) { return false; } - + int firstCellNum = row.getFirstCellNum(); int lastCellNum = row.getLastCellNum(); - + if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) { return false; } - + for (int j = firstCellNum; j < lastCellNum; j++) { XSSFCell cell = row.getCell(j); if (cell == null) { continue; } - + String value = cell.getStringCellValue(); if (value != null && value.contains("{{") && value.contains("}}")) { return true; @@ -390,24 +394,24 @@ public class ExcelTemplateProc { if (dynamicDataMappingList == null || dynamicDataMappingList.size() < 1) { return false; } - + if (row == null) { return false; } - + int firstCellNum = row.getFirstCellNum(); int lastCellNum = row.getLastCellNum(); - + if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) { return false; } - + for (int j = firstCellNum; j < lastCellNum; j++) { XSSFCell cell = row.getCell(j); if (cell == null) { continue; } - + String value = cell.getStringCellValue(); if (value != null) { for (DynamicDataMapping dynamicData : dynamicDataMappingList) { @@ -427,20 +431,20 @@ public class ExcelTemplateProc { if (row == null) { return; } - + int firstCellNum = row.getFirstCellNum(); int lastCellNum = row.getLastCellNum(); - + if (firstCellNum == -1 || lastCellNum == -1 || firstCellNum >= lastCellNum) { return; } - + for (int j = firstCellNum; j < lastCellNum; j++) { XSSFCell cell = row.getCell(j); if (cell == null) { continue; } - + String value = cell.getStringCellValue(); if (value != null && value.contains("{{") && value.contains("}}")) { // 清理动态数据占位符,保留静态内容 diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/result/BOMUploadResult.java b/ruoyi-common/src/main/java/com/ruoyi/common/result/BOMUploadResult.java new file mode 100644 index 0000000..45f9c0b --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/result/BOMUploadResult.java @@ -0,0 +1,26 @@ +package com.ruoyi.common.result; + +import lombok.Data; + +@Data +public class BOMUploadResult { + private boolean success; // 是否成功 + private String id; // 金蝶内部ID + private String number; // 单据编号 + private String errorMessage; // 错误信息(失败时才有) + + public static BOMUploadResult success(String id, String number) { + BOMUploadResult result = new BOMUploadResult(); + result.setSuccess(true); + result.setId(id); + result.setNumber(number); + return result; + } + + public static BOMUploadResult fail(String errorMessage) { + BOMUploadResult result = new BOMUploadResult(); + result.setSuccess(false); + result.setErrorMessage(errorMessage); + return result; + } +} diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/VersionComparator.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/VersionComparator.java new file mode 100644 index 0000000..d691228 --- /dev/null +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/VersionComparator.java @@ -0,0 +1,179 @@ +package com.ruoyi.common.utils; + +import java.util.Comparator; + +/** + * 版本号排序比较器 + * 支持类似 30AD.1, 30AD.2, 30AD.01.1, 30AD.01.2, 30AD.01A.1, 30AD.01A.2 的排序 + * + * 排序规则: + * 1. 先按主要部分排序(如 30AD) + * 2. 再按数字部分排序(如 1, 2, 01, 10) + * 3. 最后按字母部分排序(如 A, B) + * + * @author system + */ +public class VersionComparator implements Comparator { + + @Override + public int compare(String s1, String s2) { + if (s1 == null && s2 == null) { + return 0; + } + if (s1 == null) { + return -1; + } + if (s2 == null) { + return 1; + } + + // 按点分割字符串 + String[] parts1 = s1.split("\\."); + String[] parts2 = s2.split("\\."); + + int maxLength = Math.max(parts1.length, parts2.length); + + for (int i = 0; i < maxLength; i++) { + String part1 = i < parts1.length ? parts1[i] : ""; + String part2 = i < parts2.length ? parts2[i] : ""; + + int result = comparePart(part1, part2); + if (result != 0) { + return result; + } + } + + return 0; + } + + /** + * 比较单个部分 + * 支持数字和字母混合的比较 + */ + private int comparePart(String part1, String part2) { + if (part1.equals(part2)) { + return 0; + } + + // 如果其中一个为空,空的小于非空的 + if (part1.isEmpty()) { + return -1; + } + if (part2.isEmpty()) { + return 1; + } + + // 特殊处理:如果都是纯数字,按数值比较 + Integer num1 = parseNumber(part1); + Integer num2 = parseNumber(part2); + if (num1 != null && num2 != null) { + return num1.compareTo(num2); + } + + // 分离数字和字母部分 + String[] segments1 = splitNumberAndLetter(part1); + String[] segments2 = splitNumberAndLetter(part2); + + // 比较每个段 + int maxSegments = Math.max(segments1.length, segments2.length); + for (int i = 0; i < maxSegments; i++) { + String seg1 = i < segments1.length ? segments1[i] : ""; + String seg2 = i < segments2.length ? segments2[i] : ""; + + int result = compareSegment(seg1, seg2); + if (result != 0) { + return result; + } + } + + return 0; + } + + /** + * 将字符串分离为数字和字母段 + * 例如: "01A" -> ["01", "A"] + * "2" -> ["2"] + * "A" -> ["A"] + * "01FV" -> ["01", "FV"] + */ + private String[] splitNumberAndLetter(String str) { + if (str == null || str.isEmpty()) { + return new String[]{""}; + } + + StringBuilder result = new StringBuilder(); + boolean lastWasDigit = false; + + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + boolean isDigit = Character.isDigit(c); + + if (i > 0 && isDigit != lastWasDigit) { + result.append("|"); + } + + result.append(c); + lastWasDigit = isDigit; + } + + return result.toString().split("\\|"); + } + + /** + * 比较单个段 + */ + private int compareSegment(String seg1, String seg2) { + if (seg1.equals(seg2)) { + return 0; + } + + if (seg1.isEmpty()) { + return -1; + } + if (seg2.isEmpty()) { + return 1; + } + + // 尝试解析为数字 + Integer num1 = parseNumber(seg1); + Integer num2 = parseNumber(seg2); + + // 如果都是数字,按数字比较 + if (num1 != null && num2 != null) { + return num1.compareTo(num2); + } + + // 如果一个是数字,一个是字符串,数字优先 + if (num1 != null && num2 == null) { + return -1; + } + if (num1 == null && num2 != null) { + return 1; + } + + // 如果都是字符串,按字符串比较(忽略大小写) + return seg1.compareToIgnoreCase(seg2); + } + + /** + * 尝试将字符串解析为数字 + * 如果字符串只包含数字,则返回对应的Integer + * 否则返回null + */ + private Integer parseNumber(String str) { + if (str == null || str.isEmpty()) { + return null; + } + + try { + // 检查是否只包含数字 + if (str.matches("\\d+")) { + return Integer.parseInt(str); + } + } catch (NumberFormatException e) { + // 忽略异常,返回null + } + + return null; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/BomDetailsController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/BomDetailsController.java index e3d79d2..57d44de 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/BomDetailsController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/BomDetailsController.java @@ -3,6 +3,9 @@ package com.ruoyi.system.controller; import cn.dev33.satoken.annotation.SaCheckPermission; import cn.hutool.core.bean.BeanUtil; import cn.hutool.json.JSONArray; +import cn.hutool.json.JSONUtil; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -18,16 +21,20 @@ import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.core.validate.AddGroup; import com.ruoyi.common.core.validate.EditGroup; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.result.BOMUploadResult; import com.ruoyi.common.utils.JdUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.system.domain.BomDetails; import com.ruoyi.system.domain.FigureSave; import com.ruoyi.system.domain.MaterialProperties; +import com.ruoyi.system.domain.ProcessOrderPro; import com.ruoyi.system.domain.bo.BomDetailsBo; import com.ruoyi.system.domain.bo.ProcessOrderProBo; import com.ruoyi.system.domain.dto.JdValidateBomDTO; import com.ruoyi.system.domain.dto.JdChildDTO; +import com.ruoyi.system.domain.dto.KindegeeLogDTO; import com.ruoyi.system.domain.vo.BomDetailsVo; +import com.ruoyi.system.domain.vo.ElectricalMaterialBomVO; import com.ruoyi.system.mapper.FigureSaveMapper; import com.ruoyi.system.mapper.ProcessOrderProMapper; import com.ruoyi.system.runner.JdUtil; @@ -49,6 +56,7 @@ import javax.servlet.http.HttpServletResponse; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.io.IOException; +import java.math.BigDecimal; import java.util.*; import static org.aspectj.bridge.MessageUtil.fail; @@ -354,12 +362,13 @@ public class BomDetailsController extends BaseController { @PostMapping("/updateFBMaterial") public R updateFBMaterial(@RequestBody List> bomDetailParams) { List bomDetailsList = new ArrayList<>(); - Set processedMaterials = new HashSet<>(); // 用于跟踪已处理的物料编码 + List logDTOS = new ArrayList<>(); List failedMaterials = new ArrayList<>(); // 用于跟踪处理失败的物料 String totalWeight = ""; // 遍历前端传来的数据 for (Map param : bomDetailParams) { String fnumber = param.get("fnumber"); // 物料编码 + String fname = param.get("fname"); // 物料编码 totalWeight = param.get("totalWeight"); // 生产令号 // 根据物料编码和生产令号查询 @@ -367,15 +376,9 @@ public class BomDetailsController extends BaseController { log.info("处理物料编码: {}, 生产令号: {}", fnumber, totalWeight); if (bomDetails != null && !bomDetails.isEmpty()) { //TODO 处理父级物料 - ProcessOrderProBo bo = iProcessOrderProService.selectByProjectNumber(totalWeight); + ProcessOrderPro bo = iProcessOrderProService.selectByProjectNumber(totalWeight); - List list = iFigureSaveService.selectByProCode(totalWeight); - if (list.size() > 0) { - for (FigureSave figureSave : list) { - String figureNumber = figureSave.getFigureNumber(); - List bomDetails1 = iBomDetailsService.selectByFNumberAndTotalWeight(figureNumber, totalWeight); - } - } + // 第一步:处理所有物料的保存 for (BomDetails material : bomDetails) { // 获取工艺表中的非委外工时 Double fbWorkTime = iProcessRouteService.getFbWorkTime(material); @@ -383,7 +386,6 @@ public class BomDetailsController extends BaseController { if (material.getPartNumber() != null && material.getName() != null && material.getUnitWeight().equals("否")) { String state = determineState(material); log.info("开始新增不存在的物料 ==> 物料图号: {}, 物料名称: {}", material.getPartNumber(), material.getName()); - try { int result = loadMaterialPreservation(material, state, fbWorkTime); if (result == 1) { @@ -405,69 +407,179 @@ public class BomDetailsController extends BaseController { } } - // 保存物料清单之前进行BOM校验 - if (validateBOM(fnumber, bomDetails)) { - failedMaterials.add(fnumber); + // 第二步:BOM校验和上传(在循环外部) + boolean needUpload = !validateBOM(fnumber, bomDetails); + if (needUpload) { + try { + // 物料清单保存方法 + BOMUploadResult bomUploadResult = FBloadBillOfMaterialsPreservation(bomDetails, bo); + if (bomUploadResult.isSuccess()) { + KindegeeLogDTO logDTO = new KindegeeLogDTO(); + logDTO.setProjectCode(bo.getProductionOrderNo()); + logDTO.setMaterialCode(fnumber); // 使用物料编码而不是单个物料的编码 + logDTO.setMaterialName(fname); + logDTO.setCode(bomUploadResult.getNumber()); + logDTO.setReason(bomUploadResult.getNumber()+"OK"); + logDTOS.add(logDTO); + } else { + KindegeeLogDTO logDTO = new KindegeeLogDTO(); + logDTO.setProjectCode(bo.getProductionOrderNo()); + logDTO.setMaterialCode(fnumber); + logDTO.setMaterialName(fname); + logDTO.setCode(bomUploadResult.getNumber()); + logDTO.setReason(bomUploadResult.getErrorMessage()); + logDTOS.add(logDTO); + } + bomDetailsList.addAll(bomDetails); + } catch (Exception e) { + log.error("保存BOM失败, 物料编码: {}, 错误: {}", fnumber, e.getMessage()); + failedMaterials.add(fnumber); + } + } else { + KindegeeLogDTO logDTO = new KindegeeLogDTO(); + logDTO.setProjectCode(bo.getProductionOrderNo()); + logDTO.setMaterialCode(fnumber); + logDTO.setMaterialName(fname); + logDTO.setCode("200"); + logDTO.setReason("BOM已存在且一致"); + logDTOS.add(logDTO); + log.info("BOM已存在且一致,物料编码: {},跳过保存", fnumber); } - - // 物料清单保存方法 - FBloadBillOfMaterialsPreservation(bomDetails, bo); - bomDetailsList.addAll(bomDetails); } } //更新项目进度 - ProcessOrderProBo processOrderProBo = iProcessOrderProService.selectByProjectNumber(totalWeight); + ProcessOrderPro processOrderProBo = iProcessOrderProService.selectByProjectNumber(totalWeight); + + processOrderProBo.setDrawingType( JSONUtil.toJsonStr(logDTOS)); processOrderProBo.setBomStatus(2L); - processOrderProMapper.selectById(processOrderProBo); + processOrderProMapper.updateById(processOrderProBo); // 返回处理结果 return R.ok("成功", bomDetailsList); } - private boolean validateBOM(String fnumber, List bomDetails) { List JDBomList = JdUtil.getSelectBomList(fnumber); - // 1. 判断BOM是否为空 if (JDBomList == null || JDBomList.isEmpty()) { - log.error("未在金蝶中找到相同的BOM,需要上传,物料编码: {}", fnumber); - return false; // BOM为空,需要上传 + log.error("未在金蝶中找到相同的BOM,需要上传,物料编码: {}", fnumber); + return false; } - for (JdValidateBomDTO jdBom : JDBomList) { - // 3. 检查子项数量是否一致 - if (jdBom.getChilds().size() != bomDetails.size()) { - continue; // 数量不一致,跳过这个BOM,继续检查下一个 + // 子项排序:按 PartNumber -> Name -> PartdiagramCode -> PartdiagramName 保证顺序唯一 + bomDetails.sort(Comparator.comparing(BomDetails::getPartNumber, Comparator.nullsFirst(String::compareTo)) + .thenComparing(BomDetails::getName, Comparator.nullsFirst(String::compareTo)) + .thenComparing(BomDetails::getPartdiagramCode, Comparator.nullsFirst(String::compareTo)) + .thenComparing(BomDetails::getPartdiagramName, Comparator.nullsFirst(String::compareTo))); + + log.info("开始验证BOM - 物料编码: {}, 金蝶BOM数量: {}, 输入BOM子项数量: {}", + fnumber, JDBomList.size(), bomDetails.size()); + + for (int bomIndex = 0; bomIndex < JDBomList.size(); bomIndex++) { + JdValidateBomDTO jdBom = JDBomList.get(bomIndex); + List childs = jdBom.getChilds(); + + log.debug("正在比较第{}个金蝶BOM - 子项数量: {}", bomIndex + 1, childs.size()); + + childs.sort(Comparator.comparing(JdChildDTO::getPartNumber, Comparator.nullsFirst(String::compareTo)) + .thenComparing(JdChildDTO::getName, Comparator.nullsFirst(String::compareTo)) + .thenComparing(JdChildDTO::getPartdiagramCode, Comparator.nullsFirst(String::compareTo)) + .thenComparing(JdChildDTO::getPartdiagramName, Comparator.nullsFirst(String::compareTo))); + + if (childs.size() != bomDetails.size()) { + log.warn("BOM子项数量不一致 - 物料编码: {}, 金蝶BOM子项数量: {}, 输入BOM子项数量: {}", + fnumber, childs.size(), bomDetails.size()); + continue; // 数量不一致,跳过当前金蝶BOM } - // 4. 比较每个子项的内容 boolean isMatch = true; - for (int i = 0; i < jdBom.getChilds().size(); i++) { - JdChildDTO jdChild = jdBom.getChilds().get(i); + List mismatchDetails = new ArrayList<>(); + + for (int i = 0; i < childs.size(); i++) { + JdChildDTO jdChild = childs.get(i); BomDetails inputBomDetail = bomDetails.get(i); - // 比较物料编码和名称 - if (!jdChild.getPartNumber().equals(inputBomDetail.getPartNumber()) || !jdChild.getName().equals(inputBomDetail.getName())) { - isMatch = false; - break; + List itemMismatches = new ArrayList<>(); + + // 字符串比较(null/空格统一处理) + if (!equalsStr(jdChild.getPartNumber(), inputBomDetail.getPartNumber())) { + itemMismatches.add(String.format("PartNumber [金蝶:'%s' vs 输入:'%s']", + jdChild.getPartNumber(), inputBomDetail.getPartNumber())); } - // 比较分子和分母 - if (!jdChild.getDenominator().equals(inputBomDetail.getDenominator()) || !jdChild.getQuantity().equals(inputBomDetail.getQuantity())) { + /* if (!equalsStr(jdChild.getName(), inputBomDetail.getName())) { + itemMismatches.add(String.format("Name [金蝶:'%s' vs 输入:'%s']", + jdChild.getName(), inputBomDetail.getName())); + } + */ + if (!equalsStr(jdChild.getPartdiagramCode(), inputBomDetail.getPartdiagramCode())) { + itemMismatches.add(String.format("PartdiagramCode [金蝶:'%s' vs 输入:'%s']", + jdChild.getPartdiagramCode(), inputBomDetail.getPartdiagramCode())); + } + + /* if (!equalsStr(jdChild.getPartdiagramName(), inputBomDetail.getPartdiagramName())) { + itemMismatches.add(String.format("PartdiagramName [金蝶:'%s' vs 输入:'%s']", + jdChild.getPartdiagramName(), inputBomDetail.getPartdiagramName())); + } +*/ + // 数值比较(BigDecimal + stripTrailingZeros) + BigDecimal jdQuantity = new BigDecimal(String.valueOf(jdChild.getQuantity())).stripTrailingZeros(); + BigDecimal inputQuantity = new BigDecimal(String.valueOf(inputBomDetail.getQuantity())).stripTrailingZeros(); + + BigDecimal jdDenominator = new BigDecimal(String.valueOf(jdChild.getDenominator())).stripTrailingZeros(); + BigDecimal inputDenominator = new BigDecimal(String.valueOf(inputBomDetail.getDenominator())).stripTrailingZeros(); + + if (jdQuantity.compareTo(inputQuantity) != 0) { + itemMismatches.add(String.format("Quantity [金蝶:%s vs 输入:%s]", + jdQuantity, inputQuantity)); + } + + if (jdDenominator.compareTo(inputDenominator) != 0) { + itemMismatches.add(String.format("Denominator [金蝶:%s vs 输入:%s]", + jdDenominator, inputDenominator)); + } + + // 如果有不匹配的字段,记录详细信息 + if (!itemMismatches.isEmpty()) { + String mismatchInfo = String.format("第%d项不匹配: %s", i + 1, String.join(", ", itemMismatches)); + mismatchDetails.add(mismatchInfo); isMatch = false; - break; + } + + // 调试日志 + log.debug("对比第{}项 -> PartNumber [{} vs {}], Name [{} vs {}], Code [{} vs {}], DiagramName [{} vs {}], Quantity [{} vs {}], Denominator [{} vs {}]", + i + 1, + jdChild.getPartNumber(), inputBomDetail.getPartNumber(), + jdChild.getName(), inputBomDetail.getName(), + jdChild.getPartdiagramCode(), inputBomDetail.getPartdiagramCode(), + jdChild.getPartdiagramName(), inputBomDetail.getPartdiagramName(), + jdQuantity, inputQuantity, + jdDenominator, inputDenominator); + } + + // 如果不匹配,打印详细的不一致信息 + if (!isMatch) { + log.warn("BOM不匹配详情 - 物料编码: {}", fnumber); + log.warn("金蝶BOM子项数量: {}, 输入BOM子项数量: {}", childs.size(), bomDetails.size()); + for (String mismatch : mismatchDetails) { + log.warn(" {}", mismatch); } } if (isMatch) { - // 找到匹配的BOM,无需上传 log.info("BOM完全相同,物料编码: {},无需上传", fnumber); - return true; + return true; // 找到匹配BOM } } - // 所有BOM都不匹配,需要上传 log.info("BOM不存在或不一致,物料编码: {},需要上传", fnumber); - return false; + return false; // 所有BOM都不匹配 + } + + // null/空格统一处理方法 + private boolean equalsStr(String a, String b) { + String s1 = (a == null || a.trim().isEmpty()) ? "" : a.trim(); + String s2 = (b == null || b.trim().isEmpty()) ? "" : b.trim(); + return s1.equals(s2); } @@ -589,7 +701,7 @@ public class BomDetailsController extends BaseController { } // FBOM物料清单保存 - public void FBloadBillOfMaterialsPreservation(List bomlist, ProcessOrderProBo bo) { + public BOMUploadResult FBloadBillOfMaterialsPreservation(List bomlist, ProcessOrderPro bo) { BomDetails bomDetails1 = bomlist.get(0); int verification = isMaterialVerification(bomDetails1.getFNumber(), bomDetails1.getFName()); @@ -648,7 +760,7 @@ public class BomDetailsController extends BaseController { List fTreeEntityList = new ArrayList<>(); for (BomDetails details : bomlist) { if (bomlist.isEmpty()) { - return; + return null; } // 创建FTreeEntity对象,并加入FTreeEntity数组 JsonObject fTreeEntityItem = new JsonObject(); @@ -673,7 +785,6 @@ public class BomDetailsController extends BaseController { } fTreeEntityItem.addProperty("FSupplyType", supplyType); } - fTreeEntityItem.addProperty("FMATERIALTYPE", "1"); // 创建FMATERIALIDCHILD对象,并加入FTreeEntity JsonObject fMaterialIdChild = new JsonObject(); @@ -708,30 +819,23 @@ public class BomDetailsController extends BaseController { fTreeEntityItem.add("FOWNERID", FOWNERID); FOWNERID.addProperty("FNumber", "GYS_070"); } - fTreeEntityList.add(fTreeEntityItem); } String jsonData = json.toString(); - log.info("打印json:" + jsonData); try { - // 业务对象标识 - String formId = "ENG_BOM"; - // 调用接口 - String resultJson = client.save(formId, jsonData); - - // 用于记录结果 - Gson gson = new Gson(); - // 对返回结果进行解析和校验 - RepoRet repoRet = gson.fromJson(resultJson, RepoRet.class); - if (repoRet.getResult().getResponseStatus().isIsSuccess()) { - log.debug("物料清单bom 保存成功===================>" + "图号:" + bomDetails1.getFNumber()); + String resultJson = new K3CloudApi().save("ENG_BOM", json.toString()); + // 直接用 Jackson 解析 + BOMUploadResult result = parseK3Response(resultJson); + if (result.isSuccess()) { + log.info("✅ BOM保存成功, 图号={}", bomDetails1.getFNumber()); } else { - log.error("物料清单bom 保存失败===================>" + "图号:" + bomDetails1.getFNumber()); + log.error("❌ BOM保存失败, 图号={}, 错误={}", bomDetails1.getFNumber(), result.getErrorMessage()); } + return result; } catch (Exception e) { - R.fail(e.getMessage()); + log.error("保存BOM异常,图号={}, 错误={}", bomDetails1.getFNumber(), e.getMessage(), e); + return BOMUploadResult.fail("保存BOM异常: " + e.getMessage()); } - // 输出生成的Json } /* @@ -2031,5 +2135,51 @@ public class BomDetailsController extends BaseController { } return 1; } + public BOMUploadResult parseK3Response(String jsonResponse) { + try { + ObjectMapper mapper = new ObjectMapper(); + JsonNode root = mapper.readTree(jsonResponse); + JsonNode result = root.path("Result"); + JsonNode responseStatus = result.path("ResponseStatus"); + + boolean isSuccess = responseStatus.path("IsSuccess").asBoolean(false); + if (isSuccess) { + String id = result.path("Id").asText(); + String number = result.path("Number").asText(); + return BOMUploadResult.success(id, number); + } else { + JsonNode errors = responseStatus.path("Errors"); + String errorMsg = (errors != null && errors.isArray() && !errors.isEmpty()) + ? errors.toString() + : "未知错误"; + return BOMUploadResult.fail(errorMsg); + } + } catch (Exception e) { + return BOMUploadResult.fail("解析返回信息失败: " + e.getMessage()); + } + } + + /** + * 导入BOM + * daorubaon + * + * @param file 导入文件 + */ + + @Log(title = "明细导入", businessType = BusinessType.IMPORT) + @SaCheckPermission("system:details:import") + @PostMapping(value = "/importData21", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData21(@RequestPart("file") MultipartFile file) throws Exception { + List electricalMaterialBomVOS = ExcelUtil.importExcel(file.getInputStream(), ElectricalMaterialBomVO.class); + for (ElectricalMaterialBomVO bomVO : electricalMaterialBomVOS) { + BomDetails bomDetails = new BomDetails(); + bomDetails.setTotalWeight(bomVO.getProductionOrderNo()); + bomDetails.setFNumber(bomVO.getDrawingNo()); + bomDetails.setFName(bomVO.getDrawingName()); + bomDetails.setPartdiagramCode(bomVO.getParentDrawingNo()); + bomDetails.setPartdiagramName(bomVO.getParentPart()); + } + return null; + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/EleMaterialsController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/EleMaterialsController.java index a965df1..889746c 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/EleMaterialsController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/EleMaterialsController.java @@ -527,5 +527,17 @@ public class EleMaterialsController extends BaseController { return R.ok("更新成功"); } + @Log(title = "更新物料单重", businessType = BusinessType.IMPORT) + @SaCheckPermission("system:materials:importEleBom") + @PostMapping(value = "/importEleBom", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importEleBom(@RequestParam("file") MultipartFile file) throws Exception { + String originalFilename = file.getOriginalFilename(); + log.info("读取文件名: " + originalFilename); + ExcelResult result = ExcelUtil.importExcelSheet1(file.getInputStream(), JdDanZhong.class, true); + List list = result.getList(); + + + return R.ok("更新成功"); + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ImMaterialController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ImMaterialController.java index 4f5921f..3707ac6 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ImMaterialController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ImMaterialController.java @@ -270,7 +270,7 @@ public class ImMaterialController extends BaseController { @XxlJob("updateMaterials") public Boolean updateMaterials() throws Exception { - Date date = new Date(); + Date date = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); List imMaterials = updateJdMaterial(sdf.format(date)); Boolean result = iImMaterialService.updateByFMid(imMaterials); @@ -284,14 +284,14 @@ public class ImMaterialController extends BaseController { json.addProperty("FormId", "BD_MATERIAL"); json.addProperty("FieldKeys", "FMATERIALID,FNumber,FName,FCategoryID.FNumber,F_HBYT_DZ,F_SVRI_Assistant.FNumber,FErpClsID,FBaseUnitId.FName,FModifyDate,FForbidStatus"); JsonArray filterString = new JsonArray(); - JsonObject filterObject = new JsonObject(); + /*JsonObject filterObject = new JsonObject(); filterObject.addProperty("FieldName", "FForbidStatus"); // 使用传入的 fieldName filterObject.addProperty("Compare", "105"); filterObject.addProperty("Value", "A"); filterObject.addProperty("Left", ""); filterObject.addProperty("Right", ""); filterObject.addProperty("Logic", 0); - filterString.add(filterObject); + filterString.add(filterObject);*/ JsonObject filterObject1 = new JsonObject(); filterObject1.addProperty("FieldName", "FCreateDate"); // 使用传入的 fieldName filterObject1.addProperty("Compare", "93"); @@ -301,7 +301,7 @@ public class ImMaterialController extends BaseController { filterObject1.addProperty("Logic", 1); filterString.add(filterObject1); JsonObject filterObject2 = new JsonObject(); - filterObject2.addProperty("FieldName", "FCreateDate"); // 使用传入的 fieldName + filterObject2.addProperty("FieldName", "FModifyDate"); // 使用传入的 fieldName filterObject2.addProperty("Compare", "93"); filterObject2.addProperty("Value", date); filterObject2.addProperty("Left", ""); @@ -356,7 +356,7 @@ public class ImMaterialController extends BaseController { //请求参数,要求为json字符串 JsonObject json = new JsonObject(); json.addProperty("FormId", "BD_MATERIAL"); - json.addProperty("FieldKeys", "FMATERIALID,FNumber,FName,FCategoryID.FNumber,F_HBYT_DZ,F_SVRI_Assistant.FNumber,FErpClsID,FBaseUnitId.FName,FModifyDate,FForbidStatus,FIsVmiBusiness"); + json.addProperty("FieldKeys", "FMATERIALID,FNumber,FName,F_HBYT_PP,FCategoryID.FNumber,F_HBYT_DZ,F_SVRI_Assistant.FNumber,FErpClsID,FBaseUnitId.FName,FModifyDate,FForbidStatus,FIsVmiBusiness"); JsonArray filterString = new JsonArray(); log.debug("构建查询条件..."); @@ -407,6 +407,7 @@ public class ImMaterialController extends BaseController { * 保存所有的物料编码 * @return List */ + @XxlJob("insertJDMaterial") @GetMapping("/insertJDMaterial") public List insertJDMaterial() throws Exception { List materialList = loadMaterial(); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/KingdeeWorkCenterDataController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/KingdeeWorkCenterDataController.java index 14297c0..3feff7d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/KingdeeWorkCenterDataController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/KingdeeWorkCenterDataController.java @@ -476,28 +476,28 @@ public class KingdeeWorkCenterDataController extends BaseController { // 转入 long transInQty = item.getLong("FTransInQty"); //转出小于转入数量 - if (transOutQty new HashMap<>()) - .put(materialCode, stock); + .put(materialCode, stock); break; } } @@ -706,9 +706,9 @@ public class KingdeeWorkCenterDataController extends BaseController { // 查找对应的安全库存配置 SafetyStock matchingSafetyStock = safetyStocks.stream() - .filter(s -> s.getMaterialCode().equals(materialCode)) - .findFirst() - .orElse(null); + .filter(s -> s.getMaterialCode().equals(materialCode)) + .findFirst() + .orElse(null); if (matchingSafetyStock == null) { log.warn("物料 {} 未找到对应的安全库存配置", materialCode); @@ -744,14 +744,14 @@ public class KingdeeWorkCenterDataController extends BaseController { int result = baseMapper.insert(newStock); if (result > 0) { log.info("成功补充物料到数据库: 物料编码={}, 组={}, 使用模板物料={}", - materialCode, groupType, template.getMaterialCode()); + materialCode, groupType, template.getMaterialCode()); allStocks.add(newStock); } else { log.error("补充物料到数据库失败: 物料编码={}, 组={}", materialCode, groupType); } } catch (Exception e) { log.error("补充物料到数据库失败: 物料编码={}, 组={}, 错误信息={}", - materialCode, groupType, e.getMessage(), e); + materialCode, groupType, e.getMessage(), e); } } } @@ -763,6 +763,7 @@ public class KingdeeWorkCenterDataController extends BaseController { log.info("物料处理完成,最终物料总数: {}", allStocks.size()); return allStocks; } + @Log(title = "金蝶安全库存数据", businessType = BusinessType.OTHER) @XxlJob("getKuCunTo40SB") public R getKuCunTo40SB() { @@ -775,13 +776,13 @@ public class KingdeeWorkCenterDataController extends BaseController { String materialCode = "40SB/L"; // 获取即时库存 double inventoryQty = Optional.ofNullable(JdUtil.getKuCun(materialCode)) - .map(list ->list.stream() + .map(list -> list.stream() .mapToDouble(JDInventoryDTO::getFBaseQty) .sum()) .orElse(0.0); // 查询子项物料的未领料量 - double fNoPickedQty = Optional.ofNullable(JdUtil.getWeiLingliao(materialCode)) - .map(list ->list.stream() + double fNoPickedQty = Optional.ofNullable(JdUtil.getWeiLingliao(materialCode)) + .map(list -> list.stream() .mapToDouble(JDProductionDTO::getFNoPickedQty) .sum()) .orElse(0.0); @@ -818,9 +819,8 @@ public class KingdeeWorkCenterDataController extends BaseController { .append("> **创建时间:** ").append(DateUtil.formatDateTime(new Date())).append("\n"); - - String part = markdownMsg.toString(); - wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId); + String part = markdownMsg.toString(); + wxRobotUtil.sendMarkdownMsgToWeChatGroup(part, robotId); return R.ok(); } @@ -1011,10 +1011,10 @@ public class KingdeeWorkCenterDataController extends BaseController { for (PurchaseRequestExcelDTO allOrder : allOrders) { String productionOrderNo = allOrder.getFUCHNText(); String deliveryDate = allOrder.getFArrivalDate(); - if (allOrder.getFCloseStatus().equals("A")){ + if (allOrder.getFCloseStatus().equals("A")) { allOrder.setFCloseStatus("未关闭"); } - if (allOrder.getFDocumentStatus().equals("C")){ + if (allOrder.getFDocumentStatus().equals("C")) { allOrder.setFDocumentStatus("已审核"); } @@ -1048,6 +1048,7 @@ public class KingdeeWorkCenterDataController extends BaseController { log.info("过滤完成,剩余数量: {}", filteredOrders.size()); return filteredOrders; } + @Log(title = "采购订单和采购申请单临期数据") @XxlJob("getPurchaseOrder2") @PostMapping("/getPurchaseOrder2") diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/PcRigidChainController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/PcRigidChainController.java index e12af75..f5f0032 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/PcRigidChainController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/PcRigidChainController.java @@ -119,7 +119,7 @@ public class PcRigidChainController extends BaseController { } - @SaCheckPermission("system:pcRigidChain:importVariableData')") + @SaCheckPermission("system:pcRigidChain:importVariableData") @PostMapping("/importVariableData") public R> importVariableData(@RequestParam("file") MultipartFile file) throws Exception { if (file == null || file.isEmpty()) { @@ -131,8 +131,10 @@ public class PcRigidChainController extends BaseController { if (originalFilename == null || originalFilename.isEmpty()) { return R.fail("文件名不能为空"); } - String type = ""; + log.info("开始处理文件: {}, 文件大小: {} bytes", originalFilename, fileBytes.length); + + String type = ""; if (originalFilename.contains("30D")) { type = "30D"; } else if (originalFilename.contains("30S")) { @@ -153,28 +155,45 @@ public class PcRigidChainController extends BaseController { type = "125R"; } + log.info("检测到文件类型: {}", type); + //每个产品都会有 左,右,左+右 - List AxialDirection = Arrays.asList("R", "L", "L+R"); + List axialDirection = Arrays.asList("R", "L", "L+R"); ExcelReaderBuilder read = EasyExcel.read(new ByteArrayInputStream(fileBytes)); - List pcRigidChainsToUpdate = null; - for (ReadSheet readSheet : read.build().excelExecutor().sheetList()) { + List pcRigidChainsToUpdate = new ArrayList<>(); + + List sheetList = read.build().excelExecutor().sheetList(); + log.info("Excel文件包含 {} 个工作表", sheetList.size()); + + for (ReadSheet readSheet : sheetList) { + log.info("正在处理工作表: {} (第{}页)", readSheet.getSheetName(), readSheet.getSheetNo() + 1); + DefaultExcelListener excelListener = new DefaultExcelListener<>(true); EasyExcel.read(new ByteArrayInputStream(fileBytes), PcRigidChainVo.class, excelListener) .excelType(ExcelTypeEnum.XLS) .sheet(readSheet.getSheetNo()) - .headRowNumber(3) + .headRowNumber(4) .doRead(); List list = excelListener.getExcelResult().getList(); - pcRigidChainsToUpdate = new ArrayList<>(); + log.info("工作表 {} 解析完成,共读取 {} 行数据", readSheet.getSheetName(), list.size()); // 批量查询数据库中的记录 + log.debug("开始查询数据库中类型为 {} 的记录", type); List chains = iPcRigidChainService.selectPcRigidChainByType(type); + log.info("数据库中共找到 {} 条类型为 {} 的记录", chains.size(), type); + Map chainMap = chains.stream() .collect(Collectors.toMap(c -> c.getTypeName() + "_" + c.getAxialDirection(), c -> c)); + log.debug("数据库记录映射表构建完成,共 {} 个键值对", chainMap.size()); - for (String s : AxialDirection) { + int processedCount = 0; + int matchedCount = 0; + + for (String s : axialDirection) { + log.debug("开始处理轴向方向: {}", s); for (PcRigidChainVo pcRigidChainVO : list) { + processedCount++; Long vOne = pcRigidChainVO.getVOne(); String sheetName = readSheet.getSheetName(); String box = ""; @@ -187,40 +206,139 @@ public class PcRigidChainController extends BaseController { } String typeName = type + "/" + s + "-" + vOne + "/" + box; + String searchKey = typeName + "_" + s; - log.debug("此物料的完整图号:=====================>{}", typeName); + log.debug("处理记录 {}: 完整图号={}, 搜索键={}", processedCount, typeName, searchKey); // 从缓存中查找 - PcRigidChain dbChain = chainMap.get(typeName + "_" + s); + PcRigidChain dbChain = chainMap.get(searchKey); if (dbChain != null) { + matchedCount++; + log.info("找到匹配记录: {}", typeName); + + // 记录修改前的关键字段值 + log.info("修改前字段值:"); + log.info(" - ID: {}", dbChain.getId()); + log.info(" - Journey: {} -> {}", dbChain.getJourney(), vOne); + log.info(" - TypeName: {} -> {}", dbChain.getTypeName(), typeName); + log.info(" - Type: {} -> {}", dbChain.getType(), type); + log.info(" - Box: {} -> {}", dbChain.getBox(), box); + log.info(" - AxialDirection: {} -> {}", dbChain.getAxialDirection(), s); + + // 记录Excel中的关键字段值 + log.info("Excel数据关键字段:"); + log.info(" - VOne: {}", pcRigidChainVO.getVOne()); + log.info(" - VTwo: {}", pcRigidChainVO.getVTwo()); + log.info(" - VThree: {}", pcRigidChainVO.getVThree()); + log.info(" - LOne: {}", pcRigidChainVO.getLOne()); + log.info(" - LTwo: {}", pcRigidChainVO.getLTwo()); + log.info(" - LThree: {}", pcRigidChainVO.getLThree()); + log.info(" - SumWeight: {}", pcRigidChainVO.getSumWeight()); + log.info(" - ChainWeight: {}", pcRigidChainVO.getChainWeight()); + log.info(" - DynamicLoad: {}", pcRigidChainVO.getDynamicLoad()); + log.info(" - DeadLoad: {}", pcRigidChainVO.getDeadLoad()); + log.info(" - Speed: {}", pcRigidChainVO.getSpeed()); + log.info(" - Efficiency: {}", pcRigidChainVO.getEfficiency()); + log.info(" - ChainPitch: {}", pcRigidChainVO.getChainPitch()); + log.info(" - PitchRadius: {}", pcRigidChainVO.getPitchRadius()); + log.info(" - MinimumAltitude: {}", pcRigidChainVO.getMinimumAltitude()); + log.info(" - SingleMeterChainWeight: {}", pcRigidChainVO.getSingleMeterChainWeight()); + log.info(" - DrivingBoxWeight: {}", pcRigidChainVO.getDrivingBoxWeight()); + log.info(" - ChainBoxWeight: {}", pcRigidChainVO.getChainBoxWeight()); + log.info(" - Univalence: {}", pcRigidChainVO.getUnivalence()); + + // 执行字段复制和更新 BeanUtil.copyProperties(pcRigidChainVO, dbChain, "id"); dbChain.setJourney(vOne); dbChain.setTypeName(typeName); dbChain.setType(type); dbChain.setBox(box); dbChain.setAxialDirection(s); - // dbChain.setUpdateBy(SecurityUtils.getUsername()); dbChain.setCreateTime(new Date()); + dbChain.setUpdateTime(new Date()); + + // 记录修改后的关键字段值 + log.info("修改后字段值:"); + log.info(" - Journey: {}", dbChain.getJourney()); + log.info(" - TypeName: {}", dbChain.getTypeName()); + log.info(" - Type: {}", dbChain.getType()); + log.info(" - Box: {}", dbChain.getBox()); + log.info(" - AxialDirection: {}", dbChain.getAxialDirection()); + log.info(" - LOne: {}", dbChain.getLOne()); + log.info(" - LTwo: {}", dbChain.getLTwo()); + log.info(" - LThree: {}", dbChain.getLThree()); + log.info(" - SumWeight: {}", dbChain.getSumWeight()); + log.info(" - ChainWeight: {}", dbChain.getChainWeight()); + log.info(" - DynamicLoad: {}", dbChain.getDynamicLoad()); + log.info(" - DeadLoad: {}", dbChain.getDeadLoad()); + log.info(" - Speed: {}", dbChain.getSpeed()); + log.info(" - Efficiency: {}", dbChain.getEfficiency()); + log.info(" - ChainPitch: {}", dbChain.getChainPitch()); + log.info(" - PitchRadius: {}", dbChain.getPitchRadius()); + log.info(" - MinimumAltitude: {}", dbChain.getMinimumAltitude()); + log.info(" - SingleMeterChainWeight: {}", dbChain.getSingleMeterChainWeight()); + log.info(" - DrivingBoxWeight: {}", dbChain.getDrivingBoxWeight()); + log.info(" - ChainBoxWeight: {}", dbChain.getChainBoxWeight()); + log.info(" - Univalence: {}", dbChain.getUnivalence()); + log.info(" - CreateTime: {}", dbChain.getCreateTime()); + log.info(" - UpdateTime: {}", dbChain.getUpdateTime()); + pcRigidChainsToUpdate.add(dbChain); - } - } - } - - if (!pcRigidChainsToUpdate.isEmpty()) { - - for (PcRigidChain pcRigidChain : pcRigidChainsToUpdate) { - int i = pcRigidChainMapper.updateById(pcRigidChain); - if (i > 0) { - log.debug("物料:{}更新成功!!", pcRigidChain.getTypeName()); + log.info("物料: {} 已添加到更新列表", typeName); } else { - log.debug("物料:{}更新失败!!", pcRigidChain.getTypeName()); + log.warn("未找到对应的数据库记录: {}", searchKey); } } - } else { - return R.fail("没有找到要更新的数据"); } + + log.info("工作表 {} 处理完成 - 处理记录数: {}, 匹配成功数: {}", + readSheet.getSheetName(), processedCount, matchedCount); } + if (!pcRigidChainsToUpdate.isEmpty()) { + log.info("开始批量更新数据库,共 {} 条记录", pcRigidChainsToUpdate.size()); + int successCount = 0; + int failCount = 0; + + for (PcRigidChain pcRigidChain : pcRigidChainsToUpdate) { + log.info("正在更新物料: {}, ID: {}", pcRigidChain.getTypeName(), pcRigidChain.getId()); + // 记录更新前的关键字段值 + log.info("更新前数据库字段值:"); + log.info(" - Journey: {}", pcRigidChain.getJourney()); + log.info(" - LOne: {}", pcRigidChain.getLOne()); + log.info(" - LTwo: {}", pcRigidChain.getLTwo()); + log.info(" - LThree: {}", pcRigidChain.getLThree()); + log.info(" - SumWeight: {}", pcRigidChain.getSumWeight()); + log.info(" - ChainWeight: {}", pcRigidChain.getChainWeight()); + log.info(" - DynamicLoad: {}", pcRigidChain.getDynamicLoad()); + log.info(" - DeadLoad: {}", pcRigidChain.getDeadLoad()); + log.info(" - Speed: {}", pcRigidChain.getSpeed()); + log.info(" - Efficiency: {}", pcRigidChain.getEfficiency()); + log.info(" - ChainPitch: {}", pcRigidChain.getChainPitch()); + log.info(" - PitchRadius: {}", pcRigidChain.getPitchRadius()); + log.info(" - MinimumAltitude: {}", pcRigidChain.getMinimumAltitude()); + log.info(" - SingleMeterChainWeight: {}", pcRigidChain.getSingleMeterChainWeight()); + log.info(" - DrivingBoxWeight: {}", pcRigidChain.getDrivingBoxWeight()); + log.info(" - ChainBoxWeight: {}", pcRigidChain.getChainBoxWeight()); + log.info(" - Univalence: {}", pcRigidChain.getUnivalence()); + + int i = pcRigidChainMapper.updateById(pcRigidChain); + if (i > 0) { + successCount++; + log.info("物料:{} 更新成功!影响行数: {}", pcRigidChain.getTypeName(), i); + } else { + failCount++; + log.warn("物料:{} 更新失败!影响行数: {}", pcRigidChain.getTypeName(), i); + } + } + + log.info("批量更新完成 - 成功: {} 条, 失败: {} 条", successCount, failCount); + } else { + log.warn("没有找到要更新的数据"); + return R.fail("没有找到要更新的数据"); + } + + log.info("Excel导入处理完成,共处理 {} 条记录", pcRigidChainsToUpdate.size()); return R.ok("导入成功", pcRigidChainsToUpdate); } } 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..964faee 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,12 +3,14 @@ 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; import com.ruoyi.common.excel.DefaultExcelListener; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.VersionComparator; import com.ruoyi.common.utils.file.SmbUtil; import com.ruoyi.common.poi.ExcelTemplateProc; import com.ruoyi.common.poi.DynamicDataMapping; @@ -60,16 +62,13 @@ import org.springframework.web.multipart.MultipartFile; @Slf4j @RequestMapping("/system/orderPro") public class ProcessOrderProController extends BaseController { - private final IProcessOrderProService iProcessOrderProService; @Autowired - private final ProductionOrderServiceImpl productionOrderService; private final IMrpResultCheckService iMrpResultCheckService; - private final IBomDetailsService iBomDetailsService; private final ProcessOrderProMapper processOrderProMapper; private final IImMaterialService imMaterialService; private final ISafetyStockService iSafetyStockService; - + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy年MM月dd日"); /** * 查询项目令号列表 */ @@ -344,7 +343,8 @@ public class ProcessOrderProController extends BaseController { public List getOverdueProjects() { return iProcessOrderProService.getOverdueProjects(); } - + @SaCheckPermission("system:orderPro:geMRPResults") + @Log(title = "获取MRP复核结果", businessType = BusinessType.OTHER) @PostMapping("/getMRPResults/{id}") public R> geMRPResults(@PathVariable Long id) { return iMrpResultCheckService.getMRPResults(id); @@ -371,7 +371,7 @@ public class ProcessOrderProController extends BaseController { // 1. 读取第一个sheet的数据list - 使用POI直接读取以保留空格 List allDataList = readExcelWithPOI(excelName); - + List routeList = readExcelPOIRoute(excelName); // 2. 读取原始表数据 List rawDataList = readRawDataTable(rawDataFile); @@ -391,7 +391,7 @@ public class ProcessOrderProController extends BaseController { if (materialCode != null) { String drawingNo = item.getDrawingNo(); String drawingName = item.getDrawingName(); - if (drawingNo != null && drawingName != null) { + if (drawingName != null) { ImMaterial material = imMaterialService.selectByCodeAndName(drawingNo, drawingName); if (material != null) { //判断是否是VMI物料 @@ -406,7 +406,7 @@ public class ProcessOrderProController extends BaseController { existingVmi.setQuantity(currentQuantity + itemQuantity); Integer currentBatchQuantity = existingVmi.getBatchQuantity() != null ? existingVmi.getBatchQuantity() : 0; - Integer itemBatchQuantity = item.getBatchQuantity() != null ? Integer.valueOf(item.getBatchQuantity()) : 0; + Integer itemBatchQuantity = item.getBatchQuantity() != null ? Integer.parseInt(item.getBatchQuantity()) : 0; existingVmi.setBatchQuantity(currentBatchQuantity + itemBatchQuantity); found = true; break; @@ -431,15 +431,44 @@ public class ProcessOrderProController extends BaseController { || materialCode.startsWith("009001") || materialCode.startsWith("009081") || (remark != null && remark.contains("外购"))) { // 过滤安全库存:如果属于安全库存,则进入工艺数据列表 - Boolean isSafeStock = iSafetyStockService.isSafeCode(materialCode); + Boolean isSafeStock = iSafetyStockService.isSafeCode(materialCode.trim()); if (isSafeStock) { // 属于安全库存,添加到工艺数据列表 processDataList.add(item); continue; // 已分类,跳过后续检查 } else { - // 不属于安全库存,添加到电气外包列表 - ElecOutDataVO elecData = convertToElecOutDataVO(item); - elecOutList.add(elecData); + // 不属于安全库存,检查是否已存在相同的DrawingNo + boolean found = false; + for (ElecOutDataVO existingElec : elecOutList) { + if (item.getDrawingNo() != null && item.getDrawingNo().equals(existingElec.getDrawingNo())) { + // 将数量和批次数量相加 + Double currentQuantity = existingElec.getQuantity() != null ? existingElec.getQuantity() : 0.0; + Double itemQuantity = item.getQuantity() != null ? item.getQuantity() : 0.0; + Double newQuantity = currentQuantity + itemQuantity; + existingElec.setQuantity(newQuantity); + + // 批次数量相加(String类型) + String currentBatchQuantity = existingElec.getBatchQuantity() != null ? (existingElec.getBatchQuantity()).toString() : "0"; + String itemBatchQuantity = item.getBatchQuantity() != null ? item.getBatchQuantity() : "0"; + try { + Integer currentBatch = Integer.valueOf(currentBatchQuantity); + Integer itemBatch = Integer.valueOf(itemBatchQuantity); + String newBatchQuantity = String.valueOf(currentBatch + itemBatch); + existingElec.setBatchQuantity(Integer.valueOf(newBatchQuantity)); + } catch (NumberFormatException e) { + // 如果转换失败,保持原值 + existingElec.setBatchQuantity(Integer.valueOf(currentBatchQuantity)); + } + found = true; + break; + } + } + + // 如果没有找到相同的DrawingNo,则添加新的电气外包数据 + if (!found) { + ElecOutDataVO elecData = convertToElecOutDataVO(item); + elecOutList.add(elecData); + } continue; // 已分类,跳过后续检查 } } @@ -463,7 +492,7 @@ public class ProcessOrderProController extends BaseController { // 检查是否已存在相同的DrawingNo boolean found = false; for (ProductionOrderVo existingProcess : processDataList) { - if (materialCode != null && materialCode.equals(existingProcess.getDrawingNo())) { + if (item.getDrawingNo() != null && item.getDrawingNo().equals(existingProcess.getDrawingNo())) { // 将数量和批次数量相加 Double currentQuantity = existingProcess.getQuantity() != null ? existingProcess.getQuantity() : 0.0; Double itemQuantity = item.getQuantity() != null ? item.getQuantity() : 0.0; @@ -491,12 +520,12 @@ public class ProcessOrderProController extends BaseController { if (!found) { processDataList.add(item); } - List excelDTOList = iProcessOrderProService.getRouteAndBomDetail( processDataList,orderPro); + } // 使用Excel模板文件 - String templatePath = "EXCEL模板/生产及工艺计划模版.xlsx"; + String templatePath = "D:/java/excel-template/生产及工艺计划模版.xlsx"; String outputPath = "D:/file/" + orderPro.getProductionOrderNo() + "生产及工艺计划表.xlsx"; // 准备模板数据 @@ -504,9 +533,29 @@ public class ProcessOrderProController extends BaseController { staticDataMap.put("productionOrderNo", orderPro.getProductionOrderNo()); staticDataMap.put("productionName", orderPro.getProductionName()); - // 添加静态数据调试信息 - log.info("静态数据: {}", staticDataMap); - + //获取工艺数据信息 + List excelDTOList = iProcessOrderProService.getRouteAndBomDetail(routeList,processDataList,orderPro); + excelDTOList.sort(Comparator.comparing( + ProcessRouteExcelDTO::getMaterial, + Comparator.nullsLast((m1, m2) -> { + // 总装部件优先 + boolean isTotal1 = "总装部件".equals(m1); + boolean isTotal2 = "总装部件".equals(m2); + + if (isTotal1 && !isTotal2) return -1; + if (!isTotal1 && isTotal2) return 1; + if (isTotal1 && isTotal2) return 0; + + // 其他材质按字母顺序排序 + if (m1 == null && m2 == null) return 0; + if (m1 == null) return 1; + if (m2 == null) return -1; + return m1.compareTo(m2); + }) + ).thenComparing( + ProcessRouteExcelDTO::getMaterialCode, + Comparator.nullsLast(new VersionComparator()) + )); // 准备动态数据映射 List dynamicDataMappingList = new ArrayList<>(); @@ -551,6 +600,11 @@ public class ProcessOrderProController extends BaseController { List> evoDataList = convertEVOProductsDataToMapList(evoProductsList); dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("EVOProductsDataVO", evoDataList)); } + // 添加伊特产品数据 + if (!excelDTOList.isEmpty()) { + List> evoRouteDataList = convertRouteDataToMapList(excelDTOList); + dynamicDataMappingList.addAll(DynamicDataMapping.createOneDataList("ProcessRouteExcelDTO", evoRouteDataList)); + } // 使用模板导出Excel ExcelTemplateProc.doExportExcelByTemplateProc(templatePath, outputPath, staticDataMap, dynamicDataMappingList); @@ -584,6 +638,44 @@ public class ProcessOrderProController extends BaseController { } } + private List readExcelPOIRoute(String excelName) { + List resultList = new ArrayList<>(); + + try (FileInputStream fis = new FileInputStream(excelName); + XSSFWorkbook workbook = new XSSFWorkbook(fis)) { + + XSSFSheet sheet = workbook.getSheetAt(6); // 读取第一个sheet + + // 从第3行开始读取(headRowNumber=2,所以从第3行开始) + for (int rowIndex = 2; rowIndex <= sheet.getLastRowNum(); rowIndex++) { + XSSFRow row = sheet.getRow(rowIndex); + if (row == null) { + continue; + } + + ProcessRoute vo = new ProcessRoute(); + + // 根据列索引读取数据,保留原始空格 + vo.setMaterialCode(getCellValueAsString(row.getCell(0))); // 图号 + vo.setMaterialName(getCellValueAsString(row.getCell(1))); // 名称 + vo.setMaterial(getCellValueAsString(row.getCell(2))); // 数量 + vo.setDiscWeight(getCellValueAsDouble(row.getCell(3))); // 单重 + vo.setBatchQuantity(getCellValueAsLong(row.getCell(18))); // 批次数量 + vo.setUnitQuantity(getCellValueAsDouble(row.getCell(17))); // 批次数量 + + resultList.add(vo); + } + + log.info("使用POI读取Excel成功,共{}条记录", resultList.size()); + + } catch (Exception e) { + log.error("使用POI读取Excel失败", e); + throw new ServiceException("读取Excel文件失败: " + e.getMessage()); + } + + return resultList; + } + /** * 读取RawDataTable数据 */ @@ -850,7 +942,7 @@ public class ProcessOrderProController extends BaseController { elecData.setIndex(null); // ProductionOrder没有index字段 elecData.setDrawingNo(item.getDrawingNo()); elecData.setName(item.getDrawingName()); - elecData.setQuantity(item.getQuantity() != null ? item.getQuantity().intValue() : null); + elecData.setQuantity(Double.valueOf(item.getQuantity() != null ? item.getQuantity().intValue() : null)); elecData.setMaterial(item.getMaterial()); elecData.setUnitWeight(item.getSingleWeight() != null ? BigDecimal.valueOf(item.getSingleWeight()) : null); elecData.setTotalWeight(item.getTotalWeight() != null ? BigDecimal.valueOf(item.getTotalWeight()) : null); @@ -984,14 +1076,16 @@ public class ProcessOrderProController extends BaseController { } return mapList; } - + private String formatDate(Date date) { + return date == null ? "" : DATE_FORMAT.format(date); + } /** * 转换工艺VO为Map列表(用于模板) */ - private List> convertRouteDataToMapList(List routeDataList) { + private List> convertRouteDataToMapList(List routeDataList) { List> mapList = new ArrayList<>(); int index = 1; - for (ProcessRouteVo item : routeDataList) { + for (ProcessRouteExcelDTO item : routeDataList) { Map map = new HashMap<>(); map.put("index", index); map.put("routeDescription", item.getRouteDescription()); // 生产令号 @@ -1015,10 +1109,10 @@ public class ProcessOrderProController extends BaseController { map.put("unitQuantity", item.getUnitQuantity()); // 单台数量 map.put("batchQuantity", item.getBatchQuantity()); // 本批数量 map.put("firstBatchQuantity", item.getFirstBatchQuantity()); // 首批数量 - map.put("planStartTime", item.getPlanStartTime()); // 计划开始时间 - map.put("planEndTime", item.getPlanEndTime()); // 计划结束时间 - map.put("xuStartTime", item.getXuStartTime()); // 序开始时间 - map.put("xuEndTime", item.getXuEndTime()); // 序结束时间 + map.put("planStartTime", formatDate(item.getPlanStartTime())); + map.put("planEndTime", formatDate(item.getPlanEndTime())); + map.put("xuStartTime", formatDate(item.getXuStartTime())); + map.put("xuEndTime", formatDate(item.getXuEndTime())); mapList.add(map); index++; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessRouteController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessRouteController.java index c852fb9..f15f33b 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessRouteController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessRouteController.java @@ -27,6 +27,7 @@ import com.ruoyi.system.domain.vo.*; import com.ruoyi.system.jdmain.rouplan.Model; import com.ruoyi.system.mapper.BomDetailsMapper; import com.ruoyi.system.mapper.MaterialBomMapper; +import com.ruoyi.system.mapper.ProcessOrderProMapper; import com.ruoyi.system.mapper.ProcessRouteMapper; import com.ruoyi.system.runner.JdUtil; import com.ruoyi.system.service.IBomDetailsService; @@ -70,6 +71,7 @@ public class ProcessRouteController extends BaseController { @Autowired MaterialBomMapper materialBomMapper; private final IBomDetailsService iBomDetailsService; + private final ProcessOrderProMapper proMapper; private Long generateUniqueParentId(Long originalId) { return originalId + 1000; } @@ -393,7 +395,7 @@ public class ProcessRouteController extends BaseController { if (!route.isEmpty()){ return R.fail("项目 "+productionOrderNo+"已导入过工艺 ,请先清空再上传"); } - if (iProcessRouteService.saveData(result.getList(), list)) { + if (iProcessRouteService.saveData(list1, list)) { return R.ok("上传物料成功"); } else { return R.fail("导入失败"); @@ -475,8 +477,9 @@ public class ProcessRouteController extends BaseController { public void generatePDFs(String rooteProdet, HttpServletResponse response) throws IOException { // 调用服务层方法生成 ZIP 文件并获取其路径 String zipFilePath = iProcessRouteService.generatePDFs(rooteProdet); - System.out.println("ZIP 文件路径: " + zipFilePath); - + ProcessOrderPro processOrderPro = proMapper.selectByProjectNumber(rooteProdet); + processOrderPro.setBomStatus(5L); + proMapper.updateById(processOrderPro); // 读取文件为字节数组 File zipFile = new File(zipFilePath); if (!zipFile.exists()) { diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/BomDetails.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/BomDetails.java index c482c5c..73ea2a7 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/BomDetails.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/BomDetails.java @@ -36,16 +36,19 @@ public class BomDetails extends BaseEntity { */ @JsonProperty("F_HBYT_BJMC") private String partdiagramName; + /** * 父级物料编码 */ @JsonProperty("FMATERIALID.FNumber") private String fNumber; + /** * 父级物料名称 */ @JsonProperty("FITEMNAME") private String fName; + /** * 子项物料单位 */ @@ -57,11 +60,13 @@ public class BomDetails extends BaseEntity { */ @JsonProperty("FMATERIALIDCHILD.FNumber") private String partNumber; + /** *子项物料名称 */ @JsonProperty("FCHILDITEMNAME") private String name; + /** *属性 */ diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/ImMaterial.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/ImMaterial.java index b3fce81..27851fe 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/ImMaterial.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/ImMaterial.java @@ -86,7 +86,8 @@ public class ImMaterial extends BaseEntity { /** * 搜索次数 */ - private Long searchCount; + @JsonProperty("F_HBYT_PP") + private String searchCount; /** * 金蝶修改时间当日 */ diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/KindegeeLogDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/KindegeeLogDTO.java new file mode 100644 index 0000000..ae3f6f9 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/KindegeeLogDTO.java @@ -0,0 +1,12 @@ +package com.ruoyi.system.domain.dto; + +import lombok.Data; + +@Data +public class KindegeeLogDTO { + private String projectCode; + private String materialCode; + private String materialName; + private String code; + private String reason; +} 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..b889538 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 @@ -6,8 +6,6 @@ import java.util.Date; @Data public class ProcessRouteExcelDTO { - - private Long id; /** @@ -35,7 +33,7 @@ public class ProcessRouteExcelDTO { /** * 单重KG */ - private Double discWeight; + private String discWeight; /** * 材料BOM物料编码 */ @@ -59,7 +57,7 @@ public class ProcessRouteExcelDTO { /** * 材料BOM用量 */ - private Double discUsage; + private String discUsage; /** * 材料BOM单位 */ @@ -103,13 +101,13 @@ public class ProcessRouteExcelDTO { /** * 单台数量 */ - private Long unitQuantity; + private String unitQuantity; /** * 本批数量 */ - private Long batchQuantity; + private String batchQuantity; /** * 首批数量 diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/EleMaterialsVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/EleMaterialsVo.java index 0755bec..cfea510 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/EleMaterialsVo.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/EleMaterialsVo.java @@ -73,7 +73,7 @@ public class EleMaterialsVo { /** * 物料值 */ - @ExcelProperty(value = "总工时") + @ExcelProperty(value = "工时") private String materialValue; diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ElecOutDataVO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ElecOutDataVO.java index 5bfc17b..25f0adf 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ElecOutDataVO.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ElecOutDataVO.java @@ -21,7 +21,7 @@ public class ElecOutDataVO { private String name; /** 数量 */ - private Integer quantity; + private Double quantity; /** 材料 */ private String material; diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ElectricalMaterialBomVO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ElectricalMaterialBomVO.java new file mode 100644 index 0000000..9edc78e --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/ElectricalMaterialBomVO.java @@ -0,0 +1,93 @@ +package com.ruoyi.system.domain.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import lombok.Data; +/** + * 电气物料BOM + * 2025-09-25 + */ +@Data +public class ElectricalMaterialBomVO { + + /** + * ID + */ + private Long id; + + /** + * 生产令号 + */ + @ExcelProperty(value = "生产令号") + private String productionOrderNo; + + /** + * 生产图号 + */ + @ExcelProperty(value = "物料编码") + private String drawingNo; + + /** + * 生产名称 + */ + @ExcelProperty(value = "物料名称") + private String drawingName; + /** + * 型号 + */ + @ExcelProperty(value = "型号") + private String Model; + + /** + * 品牌 + */ + @ExcelProperty(value = "品牌") + private Double Brand; + + /** + * 单台数量 + */ + @ExcelProperty(value = "单台数量") + private Double quantity; + /** + * 批次数量 + */ + @ExcelProperty(value = "批次数量") + private String batchQuantity; + + /** + * 单位 + */ + @ExcelProperty(value = "单位") + private Double unit; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + + + /** + * 部件名称 + */ + @ExcelProperty(value = "上级部件") + private String parentPart; + + /** + * 部件图号 + */ + @ExcelProperty(value = "上级部件图号") + private String parentDrawingNo; + + /** + * 主产品图号 + */ + @ExcelProperty(value = "主产品图号") + private String mainProducts; + + /** + * 主产品名称 + */ + @ExcelProperty(value = "主产品名称") + private String mainProductsName; +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/PcRigidChainVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/PcRigidChainVo.java index f43e034..7d64fd6 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/PcRigidChainVo.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/PcRigidChainVo.java @@ -52,7 +52,7 @@ public class PcRigidChainVo extends BaseEntity private String box; /** 行程(mm) */ - @ExcelProperty( "{V1}") + //@ExcelProperty( "{V1}") private Long journey; /** 标记号 */ diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/runner/JdUtil.java b/ruoyi-system/src/main/java/com/ruoyi/system/runner/JdUtil.java index ec40e3b..ffb28d6 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/runner/JdUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/runner/JdUtil.java @@ -1528,7 +1528,6 @@ public class JdUtil { needUpdateFields.add("FMATERIALID"); needUpdateFields.add("FStandHourUnitId"); - // 创建 NeedReturnFields 数组 JsonArray needReturnFields = new JsonArray(); needReturnFields.add("SubHeadEntity5_FEntryId"); needReturnFields.add("FStdLaborProcessTime"); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IProcessOrderProService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IProcessOrderProService.java index 29861f8..4c25b20 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IProcessOrderProService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IProcessOrderProService.java @@ -58,7 +58,7 @@ public interface IProcessOrderProService { List selectProList(ProcessOrderProBo bo); - ProcessOrderProBo selectByProjectNumber(String routeDescription); + ProcessOrderPro selectByProjectNumber(String routeDescription); void batchUpdateProjectTimeRanges(); List selectByProjectNumbers(Set routeDescSet); @@ -78,5 +78,5 @@ public interface IProcessOrderProService { List getOverdueProjects(); - List getRouteAndBomDetail(List processDataList,ProcessOrderPro orderPro); + List getRouteAndBomDetail(List routlist,List processDataList,ProcessOrderPro orderPro); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ImMaterialServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ImMaterialServiceImpl.java index b46a92d..d1569a2 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ImMaterialServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ImMaterialServiceImpl.java @@ -726,7 +726,7 @@ public class ImMaterialServiceImpl implements IImMaterialService { */ @Override public Boolean insertJDMaterial(List materialList) { - if (materialList.size()<0 || materialList.isEmpty()){ + if (materialList.isEmpty()){ return false; } return baseMapper.insertBatch(materialList); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/MrpResultCheckServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/MrpResultCheckServiceImpl.java index 1c63b35..b6093a9 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/MrpResultCheckServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/MrpResultCheckServiceImpl.java @@ -37,11 +37,9 @@ import java.util.*; public class MrpResultCheckServiceImpl implements IMrpResultCheckService { private final MrpResultCheckMapper baseMapper; - private final FigureSaveMapper figureSaveMapper; private final ProcessOrderProMapper processOrderProMapper; private final IMaterialBomService iMaterialBomService; private final IProductionOrderService iProductionOrderService; - private final IBomDetailsService iBomDetailsService; private final IProcessRouteService iProcessRouteService; /** * 查询MRP运算结果复查 @@ -281,7 +279,8 @@ public class MrpResultCheckServiceImpl implements IMrpResultCheckService { baseMapper.insert(vo); } - + processOrderPro.setBomStatus(4L); + processOrderProMapper.updateById(processOrderPro); } 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..e75191d 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 @@ -2,6 +2,7 @@ package com.ruoyi.system.service.impl; import cn.hutool.core.bean.BeanUtil; import com.alibaba.fastjson.JSONObject; +import java.math.BigDecimal; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.lowagie.text.Rectangle; import com.lowagie.text.pdf.PdfReader; @@ -28,13 +29,14 @@ import com.ruoyi.system.domain.vo.ProductionOrderVo; import com.ruoyi.system.listener.FileToZip; import com.ruoyi.system.listener.SmbUtils; import com.ruoyi.system.mapper.FigureSaveMapper; -import com.ruoyi.system.mapper.MaterialBomMapper; import com.ruoyi.system.mapper.ProcessRouteMapper; import com.ruoyi.system.service.*; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FileUtils; import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeanWrapperImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ruoyi.system.domain.bo.ProcessOrderProBo; @@ -138,6 +140,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { lqw.eq(bo.getProjectEndTime() != null, ProcessOrderPro::getProjectEndTime, bo.getProjectEndTime()); lqw.eq(StringUtils.isNotBlank(bo.getUnit()), ProcessOrderPro::getUnit, bo.getUnit()); lqw.eq(bo.getQuantity() != null, ProcessOrderPro::getQuantity, bo.getQuantity()); + lqw.eq(bo.getBomStatus() != null, ProcessOrderPro::getBomStatus, bo.getBomStatus()); lqw.eq(bo.getIsEnterpriseStandard() != null, ProcessOrderPro::getIsEnterpriseStandard, bo.getIsEnterpriseStandard()); lqw.eq(bo.getDrawingPath() != null, ProcessOrderPro::getDrawingPath, bo.getDrawingPath()); //按照创建时间排序,最新的在顶端 @@ -245,18 +248,10 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { * @return */ @Override - public ProcessOrderProBo selectByProjectNumber(String routeDescription) { + public ProcessOrderPro selectByProjectNumber(String routeDescription) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(ProcessOrderPro::getProductionOrderNo, routeDescription); - ProcessOrderPro processOrderPro = baseMapper.selectOne(wrapper); - ProcessOrderProBo processOrderProBo = new ProcessOrderProBo(); - - // 添加null检查 - if (processOrderPro != null) { - BeanUtils.copyProperties(processOrderPro, processOrderProBo); - } - - return processOrderProBo; + return baseMapper.selectOne(wrapper); } @@ -288,7 +283,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { // 更新至计划模块中 if (earliestStartTime != null && latestEndTime != null) { - ProcessOrderProBo processOrderPro = selectByProjectNumber(projectNumber); + ProcessOrderPro processOrderPro = selectByProjectNumber(projectNumber); if (processOrderPro != null) { processOrderPro.setPlanStartTime(earliestStartTime); @@ -359,7 +354,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { pwProductionBill.setProduct(productInfos); // 6. 调用API - return callDrawingApi(pwProductionBill,orderPro); + return callDrawingApi(pwProductionBill, orderPro); } @@ -533,7 +528,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { datainfo.setG20(String.valueOf(rigidChain.getGTwenty())); } - private String callDrawingApi(PwProductionBill pwProductionBill,ProcessOrderProBo orderPro) { + private String callDrawingApi(PwProductionBill pwProductionBill, ProcessOrderProBo orderPro) { try { String drawingDate = JSONObject.toJSONString(pwProductionBill); log.info("请求出图报文=====>{}", drawingDate); @@ -557,7 +552,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { // 判断完成条件processstate=4 表示完成 if ("idle".equals(currentStatus) && processState == 4) { ProcessOrderPro processOrderPro = new ProcessOrderPro(); - BeanUtils.copyProperties(orderPro,processOrderPro); + BeanUtils.copyProperties(orderPro, processOrderPro); processOrderPro.setBomStatus(1L);// baseMapper.updateById(processOrderPro); @@ -1072,7 +1067,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { OverdueProjectVo projectVo = new OverdueProjectVo(); projectVo.setProjectCode(processOrderPro.getProductionName()); - // projectVo.setDesigner(processOrderPro.getProgramDesigner()); + // projectVo.setDesigner(processOrderPro.getProgramDesigner()); projectVo.setStartDate(processOrderPro.getPlanStartTime().toString()); projectVo.setPlanDate(processOrderPro.getPlanEndTime().toString()); @@ -1106,6 +1101,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { /** * 递归删除目录及其内容 + * * @param directory 要删除的目录 * @throws IOException 删除失败时抛出异常 */ @@ -1128,21 +1124,170 @@ 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(); + public List getRouteAndBomDetail(List routlist,List processDataList, ProcessOrderPro orderPro) { + String proRoot = orderPro.getProductionOrderNo(); + + // 查出所有工艺路线和BOM + List allRoutes = iProcessRouteService.selectByProjectNumber(proRoot); + List allBoms = materialBomService.selectByProCode(proRoot); + + // 建立 routlist 的 Map 方便查找 + Map routeMap1 = routlist.stream() + .filter(r -> r.getMaterialCode() != null) + .collect(Collectors.toMap(ProcessRoute::getMaterialCode, r -> r)); + + // 合并数据 + for (ProcessRoute route : allRoutes) { + ProcessRoute source = routeMap1.get(route.getMaterialCode()); + if (source != null) { + copyPropertiesIgnoreNull(source, route); // 用 routlist 的非空字段补充 allRoutes + } + } + List resultList = new ArrayList<>(); + + // 规范化 key + Function normalize = s -> s == null ? "" : s.trim().toUpperCase(); + + // 按 materialCode 分组(工艺路线) + Map> routeMap = allRoutes.stream() + .collect(Collectors.groupingBy(r -> normalize.apply(r.getMaterialCode()))); + + // 按 parentMaterialCode 分组(BOM) + Map> bomMap = allBoms.stream() + .collect(Collectors.groupingBy(b -> normalize.apply(b.getParentMaterialCode()))); + + // 把订单数据做成 Map + Map orderMap = processDataList.stream() + .collect(Collectors.toMap(vo -> normalize.apply(vo.getDrawingNo()), vo -> vo, (a, b) -> a)); + + // 合并 material keys + LinkedHashSet materialKeys = new LinkedHashSet<>(); + materialKeys.addAll(routeMap.keySet()); + orderMap.keySet().stream() + .filter(key -> !materialKeys.contains(key)) + .forEach(materialKeys::add); + + for (String key : materialKeys) { + List processRoutes = routeMap.getOrDefault(key, Collections.emptyList()); + List materialBoms = bomMap.getOrDefault(key, Collections.emptyList()); + ProductionOrderVo orderVo = orderMap.get(key); + + // 优先从 processRoutes 取值,其次才用 orderVo,最后才用 BOM 或 key + String originalMaterialCode = !processRoutes.isEmpty() + ? processRoutes.get(0).getMaterialCode().trim() + : (orderVo != null + ? (orderVo.getDrawingNo() != null ? orderVo.getDrawingNo().trim() : null) + : (!materialBoms.isEmpty() + ? (materialBoms.get(0).getParentMaterialCode() != null ? materialBoms.get(0).getParentMaterialCode().trim() : null) + : key)); + + String originalMaterialName = !processRoutes.isEmpty() + ? (processRoutes.get(0).getMaterialName() != null ? processRoutes.get(0).getMaterialName().trim() : null) + : (orderVo != null ? (orderVo.getDrawingName() != null ? orderVo.getDrawingName().trim() : null) : null); + + String originalMaterial = !processRoutes.isEmpty() + ? (processRoutes.get(0).getMaterial() != null ? processRoutes.get(0).getMaterial().trim() : null) + : (orderVo != null ? (orderVo.getMaterial() != null ? orderVo.getMaterial().trim() : null) : null); + + Double originalUnitWeight = !processRoutes.isEmpty() ? processRoutes.get(0).getDiscWeight() : (orderVo != null ? orderVo.getSingleWeight() : null); + // 🔹 新增两个数量字段 + Double unitQuantity = !processRoutes.isEmpty() + ? processRoutes.get(0).getUnitQuantity() + : (orderVo != null ? orderVo.getQuantity() : null); + + Double batchQuantity = !processRoutes.isEmpty() + ? (processRoutes.get(0).getBatchQuantity() != null ? processRoutes.get(0).getBatchQuantity() : 0) + : (orderVo != null + ? (orderVo.getBatchQuantity() != null + ? Double.valueOf(orderVo.getBatchQuantity()) + : null) + : null); + + int maxSize = Math.max(processRoutes.size(), materialBoms.size()); + if (maxSize == 0 && orderVo != null) maxSize = 1; + + for (int i = 0; i < maxSize; i++) { + ProcessRouteExcelDTO dto = new ProcessRouteExcelDTO(); + + // 补充名称/材质/单重字段 + dto.setMaterialCode(originalMaterialCode); + dto.setMaterialName(originalMaterialName); + dto.setMaterial(originalMaterial); + dto.setDiscWeight(String.valueOf(originalUnitWeight)); + dto.setUnitQuantity(String.valueOf(unitQuantity)); + dto.setBatchQuantity(String.valueOf(batchQuantity)); + + // 订单数量信息 + if (orderVo != null) { + dto.setRouteDescription(orderVo.getProductionOrderNo()); + dto.setUnitQuantity(String.valueOf(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.setXuStartTime(route.getXuStartTime()); + dto.setXuEndTime(route.getXuEndTime()); + } + + // 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()); + + // 单位转换:如果单位为mm,则数值乘以1000 + String quantity = bom.getQuantity(); + if ("mm".equals(bom.getUnit()) && quantity != null) { + try { + BigDecimal originalValue = new BigDecimal(quantity); + BigDecimal convertedValue = originalValue.multiply(new BigDecimal("1000")); + dto.setDiscUsage(convertedValue.toString()); + } catch (NumberFormatException e) { + // 如果转换失败,使用原值 + dto.setDiscUsage(quantity); + } + } else { + dto.setDiscUsage(quantity); + } + } + resultList.add(dto); + } } - return Collections.emptyList(); + return resultList; } + public static String[] getNullPropertyNames(Object source) { + BeanWrapper src = new BeanWrapperImpl(source); + java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors(); + + Set emptyNames = new HashSet<>(); + for (java.beans.PropertyDescriptor pd : pds) { + Object srcValue = src.getPropertyValue(pd.getName()); + if (srcValue == null) emptyNames.add(pd.getName()); + } + return emptyNames.toArray(new String[0]); + } + + public static void copyPropertiesIgnoreNull(Object src, Object target) { + BeanUtils.copyProperties(src, target, getNullPropertyNames(src)); + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessRouteServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessRouteServiceImpl.java index 905c436..aaf0fe1 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessRouteServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessRouteServiceImpl.java @@ -569,19 +569,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { saveBomDetails(bomDetailsVos); List routeArrayList = new ArrayList<>(); Map inventoryCache = new HashMap<>(); - // 批量查询所有需要的库存信息 - /* for (ProcessRoute processRoute : processRoutes) { - String materialCode = processRoute.getMaterialCode(); - if (!inventoryCache.containsKey(materialCode)) { - try { - Double kucun = JdUtil.getKeyong(materialCode); - inventoryCache.put(materialCode, kucun); - } catch (Exception e) { - log.error("查询库存失败: {}", materialCode, e); - inventoryCache.put(materialCode, 0.0); - } - } - }*/ + boolean allEmpty = processRoutes.stream().allMatch(route -> route.getProcessNo() == null && route.getProcessName() == null); //获取工艺中所有的时间 挑选出最早的时间和最晚的时间 @@ -622,8 +610,7 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { for (ProcessRoute processRoute : processRoutes) { String materialCode = processRoute.getMaterialCode(); Double kucun = inventoryCache.get(materialCode); - boolean isDuplicateWelding = "组焊件".equals(processRoute.getMaterial()) - && duplicateWeldingMaterials.contains(materialCode); + boolean isDuplicateWelding = "组焊件".equals(processRoute.getMaterial()) && duplicateWeldingMaterials.contains(materialCode); if (isDuplicateWelding && processedWeldingMaterials.contains(materialCode)) { continue; @@ -663,7 +650,6 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { defaultRoute.setProcessControl(null); defaultRoute.setActivityDuration(null); defaultRoute.setActivityUnit("分"); - defaultRoute.setFirstBatchQuantity(kucun); defaultRoute.setCreateTime(new Date()); defaultRoute.setUpdateTime(new Date()); routeArrayList.add(defaultRoute); @@ -696,11 +682,14 @@ public class ProcessRouteServiceImpl implements IProcessRouteService { } } else { for (ProcessRoute processRoute : processRoutes) { - if (processRoute.getProcessNo() != null || processRoute.getProcessName() != null) { + if (processRoute.getProcessNo() != null + ||processRoute.getWorkCenter()!= null + ||processRoute.getProcessName() != null + ||processRoute.getMaterial().equals("总装部件")) { processRoute.setActivityUnit("分"); processRoute.setCreateTime(new Date()); processRoute.setUpdateTime(new Date()); - processRoute.setFirstBatchQuantity(processRoute.getFirstBatchQuantity()); + processRoute.setBatchQuantity(processRoute.getBatchQuantity()); processRoute.setUnitQuantity(processRoute.getUnitQuantity()); routeArrayList.add(processRoute); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SafetyStockServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SafetyStockServiceImpl.java index e523efa..0420cfe 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SafetyStockServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SafetyStockServiceImpl.java @@ -158,9 +158,8 @@ public class SafetyStockServiceImpl implements ISafetyStockService { public Boolean isSafeCode(String materialCode) { LambdaQueryWrapper safetyStockLambdaQueryWrapper = new LambdaQueryWrapper<>(); safetyStockLambdaQueryWrapper.eq(SafetyStock::getMaterialCode,materialCode); - SafetyStock safetyStock = baseMapper.selectOne(safetyStockLambdaQueryWrapper); - return safetyStock != null; - + List safetyStocks = baseMapper.selectList(safetyStockLambdaQueryWrapper); + return !safetyStocks.isEmpty(); } /** diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WorkProcedureServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WorkProcedureServiceImpl.java index 054de3c..f92d76a 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WorkProcedureServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/WorkProcedureServiceImpl.java @@ -79,7 +79,7 @@ public class WorkProcedureServiceImpl implements IWorkProcedureService { parentTask.setParent(null); // 获取工艺订单信息 - ProcessOrderProBo processOrderProBo = iProcessOrderProService.selectByProjectNumber(processRoute.getRouteDescription()); + ProcessOrderPro processOrderProBo = iProcessOrderProService.selectByProjectNumber(processRoute.getRouteDescription()); Date start = processOrderProBo.getPlanStartTime(); Date end = processOrderProBo.getPlanEndTime(); diff --git a/ruoyi-system/src/main/resources/EXCEL模板/生产及工艺计划模版.xlsx b/ruoyi-system/src/main/resources/EXCEL模板/生产及工艺计划模版.xlsx index b0ff692..82479b5 100644 Binary files a/ruoyi-system/src/main/resources/EXCEL模板/生产及工艺计划模版.xlsx and b/ruoyi-system/src/main/resources/EXCEL模板/生产及工艺计划模版.xlsx differ diff --git a/ruoyi-system/src/main/resources/EXCEL模板/采购订单模板1.xlsx b/ruoyi-system/src/main/resources/EXCEL模板/采购订单模板1.xlsx index d824baa..45fe0f5 100644 Binary files a/ruoyi-system/src/main/resources/EXCEL模板/采购订单模板1.xlsx and b/ruoyi-system/src/main/resources/EXCEL模板/采购订单模板1.xlsx differ