| | |
| | | if (matchedOperation == null) { |
| | | matchedOperation = insertRoutingOperationSnapshot(orderRouting.getId(), productionOrderId, desiredOperation); |
| | | } else { |
| | | updateRoutingOperationSnapshotIfNecessary(desiredOperation, orderRouting.getId(), productionOrderId, matchedOperation); |
| | | updateRoutingOperationSnapshotIfNecessary(matchedOperation, orderRouting.getId(), productionOrderId, desiredOperation); |
| | | } |
| | | finalOperationList.add(matchedOperation); |
| | | } |
| | |
| | | Map<Long, ProductionBomStructure> structureById = structureList.stream() |
| | | .filter(item -> item != null && item.getId() != null) |
| | | .collect(Collectors.toMap(ProductionBomStructure::getId, item -> item, (left, right) -> left)); |
| | | Map<String, ProductionBomStructure> uniqueOperationMap = new LinkedHashMap<>(); |
| | | for (ProductionBomStructure bomStructure : structureList) { |
| | | if (bomStructure == null || bomStructure.getTechnologyOperationId() == null) { |
| | | continue; |
| | | |
| | | // 构建父-子映射关系 |
| | | Map<Long, List<ProductionBomStructure>> treeMap = buildParentChildMap(structureList); |
| | | |
| | | // 使用后序遍历构建操作列表(先子后父,确保工艺路线顺序正确) |
| | | // 使用深度作为排序依据的辅助结构 |
| | | Map<String, ProductionBomStructure> operationMap = new LinkedHashMap<>(); |
| | | Map<String, Integer> depthMap = new HashMap<>(); |
| | | buildOperationListPostOrderWithDepth(null, treeMap, operationMap, depthMap, structureById, rootProductModelId, 1); |
| | | |
| | | // 按深度排序,深度大的排前面 |
| | | List<Map.Entry<String, ProductionBomStructure>> sortedEntries = new ArrayList<>(operationMap.entrySet()); |
| | | sortedEntries.sort((a, b) -> { |
| | | int depthCompare = Integer.compare( |
| | | depthMap.getOrDefault(b.getKey(), 0), |
| | | depthMap.getOrDefault(a.getKey(), 0)); |
| | | if (depthCompare != 0) { |
| | | return depthCompare; |
| | | } |
| | | Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId); |
| | | uniqueOperationMap.putIfAbsent(buildBomOperationDedupKey(bomStructure, outputProductModelId), bomStructure); |
| | | } |
| | | return 0; |
| | | }); |
| | | |
| | | List<ProductionOrderRoutingOperation> desiredOperationList = new ArrayList<>(); |
| | | int dragSort = 1; |
| | | for (ProductionBomStructure bomStructure : uniqueOperationMap.values()) { |
| | | for (Map.Entry<String, ProductionBomStructure> entry : sortedEntries) { |
| | | ProductionBomStructure bomStructure = entry.getValue(); |
| | | Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(bomStructure, structureById), rootProductModelId); |
| | | TechnologyOperation technologyOperation = getTechnologyOperation(bomStructure.getTechnologyOperationId()); |
| | | ProductionOrderRoutingOperation routingOperation = new ProductionOrderRoutingOperation(); |
| | |
| | | desiredOperationList.add(routingOperation); |
| | | } |
| | | return desiredOperationList; |
| | | } |
| | | |
| | | private void buildOperationListPostOrderWithDepth(Long parentId, |
| | | Map<Long, List<ProductionBomStructure>> treeMap, |
| | | Map<String, ProductionBomStructure> operationMap, |
| | | Map<String, Integer> depthMap, |
| | | Map<Long, ProductionBomStructure> structureById, |
| | | Long rootProductModelId, |
| | | int currentDepth) { |
| | | List<ProductionBomStructure> children = treeMap.get(parentId); |
| | | if (children == null || children.isEmpty()) { |
| | | return; |
| | | } |
| | | for (ProductionBomStructure child : children) { |
| | | // 先递归处理子节点 |
| | | buildOperationListPostOrderWithDepth(child.getId(), treeMap, operationMap, depthMap, structureById, rootProductModelId, currentDepth + 1); |
| | | |
| | | // 再处理当前节点 |
| | | if (child.getTechnologyOperationId() != null) { |
| | | Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(child, structureById), rootProductModelId); |
| | | String key = buildBomOperationDedupKey(child, outputProductModelId); |
| | | // 保留深度最大的操作 |
| | | Integer existingDepth = depthMap.get(key); |
| | | if (existingDepth == null || currentDepth > existingDepth) { |
| | | operationMap.put(key, child); |
| | | depthMap.put(key, currentDepth); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | private Map<Long, List<ProductionBomStructure>> buildParentChildMap(List<ProductionBomStructure> structureList) { |
| | | Map<Long, List<ProductionBomStructure>> treeMap = new LinkedHashMap<>(); |
| | | Map<Long, ProductionBomStructure> structureById = new HashMap<>(); |
| | | |
| | | // 构建父-子映射和ID映射 |
| | | for (ProductionBomStructure structure : structureList) { |
| | | if (structure == null) continue; |
| | | Long parentId = structure.getParentId(); |
| | | treeMap.computeIfAbsent(parentId, k -> new ArrayList<>()).add(structure); |
| | | if (structure.getId() != null) { |
| | | structureById.put(structure.getId(), structure); |
| | | } |
| | | } |
| | | |
| | | // 计算每个节点的深度(从根节点到当前节点的距离,根节点深度为1) |
| | | Map<Long, Integer> depthMap = new HashMap<>(); |
| | | for (ProductionBomStructure structure : structureList) { |
| | | if (structure == null || structure.getId() == null) continue; |
| | | computeDepthFromRoot(structure.getId(), structureById, depthMap); |
| | | } |
| | | |
| | | // 对每个父节点下的子节点按深度倒序排序(最深层的优先) |
| | | for (Map.Entry<Long, List<ProductionBomStructure>> entry : treeMap.entrySet()) { |
| | | List<ProductionBomStructure> children = entry.getValue(); |
| | | children.sort((a, b) -> { |
| | | // 优先按深度排序,深度大的排前面(最深层优先) |
| | | int depthCompare = Integer.compare( |
| | | depthMap.getOrDefault(b.getId(), 0), |
| | | depthMap.getOrDefault(a.getId(), 0)); |
| | | if (depthCompare != 0) { |
| | | return depthCompare; |
| | | } |
| | | // 深度相同时按ID排序保证稳定性 |
| | | return Long.compare(a.getId(), b.getId()); |
| | | }); |
| | | } |
| | | |
| | | return treeMap; |
| | | } |
| | | |
| | | /** |
| | | * 计算节点深度(从根节点到当前节点的距离) |
| | | * 根节点深度为1,每向下一层深度加1 |
| | | */ |
| | | private int computeDepthFromRoot(Long nodeId, Map<Long, ProductionBomStructure> structureById, Map<Long, Integer> depthMap) { |
| | | if (depthMap.containsKey(nodeId)) { |
| | | return depthMap.get(nodeId); |
| | | } |
| | | |
| | | ProductionBomStructure structure = structureById.get(nodeId); |
| | | if (structure == null) { |
| | | depthMap.put(nodeId, 1); |
| | | return 1; |
| | | } |
| | | |
| | | Long parentId = structure.getParentId(); |
| | | if (parentId == null || parentId == 0L) { |
| | | // 根节点深度为1 |
| | | depthMap.put(nodeId, 1); |
| | | return 1; |
| | | } |
| | | |
| | | // 子节点深度 = 父节点深度 + 1 |
| | | int parentDepth = computeDepthFromRoot(parentId, structureById, depthMap); |
| | | int depth = parentDepth + 1; |
| | | depthMap.put(nodeId, depth); |
| | | return depth; |
| | | } |
| | | |
| | | private void buildOperationListPostOrder(Long parentId, |
| | | Map<Long, List<ProductionBomStructure>> treeMap, |
| | | Map<String, ProductionBomStructure> uniqueOperationMap, |
| | | Map<Long, ProductionBomStructure> structureById, |
| | | Long rootProductModelId) { |
| | | List<ProductionBomStructure> children = treeMap.get(parentId); |
| | | if (children == null || children.isEmpty()) { |
| | | return; |
| | | } |
| | | for (ProductionBomStructure child : children) { |
| | | // 先递归处理子节点 |
| | | buildOperationListPostOrder(child.getId(), treeMap, uniqueOperationMap, structureById, rootProductModelId); |
| | | |
| | | // 再处理当前节点 |
| | | if (child.getTechnologyOperationId() != null) { |
| | | Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(child, structureById), rootProductModelId); |
| | | String key = buildBomOperationDedupKey(child, outputProductModelId); |
| | | // 去重时保留深度最大的操作(后序遍历先遇到深层节点,所以直接覆盖即可) |
| | | uniqueOperationMap.put(key, child); |
| | | } |
| | | } |
| | | } |
| | | |
| | | private Map<String, Deque<ProductionOrderRoutingOperation>> buildExistingRoutingOperationBucketMap(List<ProductionOrderRoutingOperation> existingOperationList) { |
| | |
| | | return; |
| | | } |
| | | if (defaultDecimal(task.getCompleteQuantity()).compareTo(BigDecimal.ZERO) > 0) { |
| | | throw new ServiceException("工序已产生报工记录,无法根据 BOM 变更删除对应工序快照"); |
| | | throw new ServiceException("工序已产生报工记录,无法根据 BOM 变更删除对应工序快照" + task.getWorkOrderNo()); |
| | | } |
| | | long reportCount = productionProductMainMapper.selectCount( |
| | | Wrappers.<ProductionProductMain>lambdaQuery() |