huminmin
6 天以前 be3496a35eb61769776e0e2c57087510e99f0e97
src/main/java/com/ruoyi/production/service/impl/ProductionBomStructureServiceImpl.java
@@ -23,6 +23,7 @@
import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
import com.ruoyi.production.pojo.ProductionProductMain;
import com.ruoyi.production.service.ProductionBomStructureService;
import com.ruoyi.production.util.TaskPlanQuantityUtil;
import com.ruoyi.technology.mapper.TechnologyOperationMapper;
import com.ruoyi.technology.mapper.TechnologyOperationParamMapper;
import com.ruoyi.technology.mapper.TechnologyParamMapper;
@@ -216,19 +217,22 @@
            return;
        }
        List<ProductionBomStructure> updateList = new ArrayList<>();
        BigDecimal lastProcessDemandedQuantity = orderQuantity;
        for (ProductionBomStructure structure : structureList) {
            if (structure == null || structure.getId() == null) {
                continue;
            }
            BigDecimal demandedQuantity = defaultDecimal(structure.getUnitQuantity()).multiply(orderQuantity);
            if (compareDecimal(structure.getDemandedQuantity(), demandedQuantity) == 0) {
                continue;
            }
            BigDecimal demandedQuantity = lastProcessDemandedQuantity.multiply(defaultDecimal(structure.getUnitQuantity()));
//            if (compareDecimal(structure.getDemandedQuantity(), demandedQuantity) == 0) {
//                continue;
//            }
            ProductionBomStructure update = new ProductionBomStructure();
            update.setId(structure.getId());
            update.setDemandedQuantity(demandedQuantity);
            updateList.add(update);
            structure.setDemandedQuantity(demandedQuantity);
            lastProcessDemandedQuantity = demandedQuantity;
        }
        if (!updateList.isEmpty()) {
            this.updateBatchById(updateList);
@@ -259,7 +263,7 @@
                .filter(item -> item != null && item.getId() != null)
                .collect(Collectors.toMap(ProductionOrderRoutingOperation::getId, item -> item, (left, right) -> left));
        // Keep task plan quantities aligned with the same order BOM snapshot demand used during snapshot creation.
        Map<String, BigDecimal> demandedQuantityMap = buildOperationDemandedQuantityMap(structureList, rootProductModelId);
        Map<String, BigDecimal> demandedQuantityMap = TaskPlanQuantityUtil.buildOperationDemandedQuantityMap(structureList, rootProductModelId);
        for (ProductionOperationTask task : taskList) {
            if (task == null || task.getId() == null || task.getProductionOrderRoutingOperationId() == null) {
                continue;
@@ -378,17 +382,32 @@
        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();
@@ -402,6 +421,127 @@
            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) {
@@ -568,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()