liding
2 天以前 acc94dd2dc309e50882f7b10c20d955ed2f14716
src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -292,15 +292,8 @@
                                            ProductionOrderBom orderBom,
                                            List<ProductionBomStructure> structureList,
                                            Long rootProductModelId) {
        // 重新查询BOM结构,按子节点优先排序
        List<ProductionBomStructure> routingStructureList = this.list(
                Wrappers.<ProductionBomStructure>lambdaQuery()
                        .eq(ProductionBomStructure::getProductionOrderBomId, orderBom.getId())
                        .orderByDesc(ProductionBomStructure::getParentId)
                        .orderByAsc(ProductionBomStructure::getId));
        ProductionOrderRouting orderRouting = getOrCreateOrderRoutingSnapshot(productionOrderId, productionOrder, orderBom, rootProductModelId);
        List<ProductionOrderRoutingOperation> desiredOperationList = buildDesiredRoutingOperationList(routingStructureList, rootProductModelId);
        List<ProductionOrderRoutingOperation> desiredOperationList = buildDesiredRoutingOperationList(structureList, rootProductModelId);
        List<ProductionOrderRoutingOperation> existingOperationList = productionOrderRoutingOperationMapper.selectList(
                Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
                        .eq(ProductionOrderRoutingOperation::getOrderRoutingId, orderRouting.getId())
@@ -394,12 +387,27 @@
        Map<Long, List<ProductionBomStructure>> treeMap = buildParentChildMap(structureList);
        // 使用后序遍历构建操作列表(先子后父,确保工艺路线顺序正确)
        Map<String, ProductionBomStructure> uniqueOperationMap = new LinkedHashMap<>();
        buildOperationListPostOrder(null, treeMap, uniqueOperationMap, structureById, rootProductModelId);
        // 使用深度作为排序依据的辅助结构
        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;
            }
            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();
@@ -415,29 +423,102 @@
        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, Integer> childCountMap = new HashMap<>();
        Map<Long, ProductionBomStructure> structureById = new HashMap<>();
        // 第一遍:统计每个节点的子节点数量,同时构建初始映射
        // 构建父-子映射和ID映射
        for (ProductionBomStructure structure : structureList) {
            if (structure == null) continue;
            Long parentId = structure.getParentId();
            childCountMap.merge(parentId, 1, Integer::sum);  // 统计每个父节点有多少个子节点
            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 countA = childCountMap.getOrDefault(a.getId(), 0);
                int countB = childCountMap.getOrDefault(b.getId(), 0);
                return Integer.compare(countB, countA);  // 子节点多的排前面
                // 优先按深度排序,深度大的排前面(最深层优先)
                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,
@@ -456,7 +537,9 @@
            // 再处理当前节点
            if (child.getTechnologyOperationId() != null) {
                Long outputProductModelId = resolveOutputProductModelId(resolveOperationOutputNode(child, structureById), rootProductModelId);
                uniqueOperationMap.putIfAbsent(buildBomOperationDedupKey(child, outputProductModelId), child);
                String key = buildBomOperationDedupKey(child, outputProductModelId);
                // 去重时保留深度最大的操作(后序遍历先遇到深层节点,所以直接覆盖即可)
                uniqueOperationMap.put(key, child);
            }
        }
    }
@@ -536,12 +619,6 @@
        if (!Objects.equals(currentOperation.getIsProduction(), desiredOperation.getIsProduction())) {
            update.setIsProduction(desiredOperation.getIsProduction());
            currentOperation.setIsProduction(desiredOperation.getIsProduction());
            changed = true;
        }
        // 更新 dragSort 字段,确保工艺路线顺序正确
        if (!Objects.equals(currentOperation.getDragSort(), desiredOperation.getDragSort())) {
            update.setDragSort(desiredOperation.getDragSort());
            currentOperation.setDragSort(desiredOperation.getDragSort());
            changed = true;
        }
        if (!Objects.equals(currentOperation.getType(), desiredOperation.getType())) {
@@ -631,7 +708,7 @@
            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()
@@ -804,8 +881,8 @@
            return;
        }
        for (ProductionBomStructureDto node : source) {
            flattenTree(node.getChildren(), result);  // 先递归添加子节点
            result.add(node);
            flattenTree(node.getChildren(), result);
        }
    }