yuan
6 天以前 f00a59b4f30accf2b23ae0d58fac23d966a48d24
src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -22,6 +22,8 @@
import com.ruoyi.production.bean.vo.ProductionOrderVo;
import com.ruoyi.production.bean.vo.ProductionPlanVo;
import com.ruoyi.production.bean.vo.ProductionOrderWorkOrderDetailVo;
import com.ruoyi.production.bean.vo.ProcessRouteStatusVo;
import com.ruoyi.production.bean.vo.ProductionOrderProcessTaskVo;
import com.ruoyi.production.enums.ProductOrderStatusEnum;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
@@ -59,6 +61,7 @@
    private final ProductionOperationTaskMapper productionOperationTaskMapper;
    private final ProductionOrderBomMapper productionOrderBomMapper;
    private final ProductionBomStructureMapper productionBomStructureMapper;
    private final ProductionOrderMapper productionOrderMapper;
    private final ProductionProductMainMapper productionProductMainMapper;
    private final ProductionProductOutputMapper productionProductOutputMapper;
    private final ProductionOrderPickMapper productionOrderPickMapper;
@@ -85,6 +88,7 @@
        // 分页查询生产订单
        Page<ProductionOrderVo> result = (Page<ProductionOrderVo>) baseMapper.pageProductionOrder(page, dto);
        fillProductImages(result.getRecords());
        fillProcessRouteStatus(result.getRecords());
        return result;
    }
@@ -93,6 +97,7 @@
        // 查询生产订单列表
        List<ProductionOrderVo> records = baseMapper.listProductionOrder(dto);
        fillProductImages(records);
        fillProcessRouteStatus(records);
        return records;
    }
@@ -132,7 +137,7 @@
                || !Objects.equals(oldOrder.getProductModelId(), productionOrder.getProductModelId())
                || compareDecimal(oldOrder.getQuantity(), productionOrder.getQuantity()) != 0
                || productionOrderRoutingMapper.selectCount(Wrappers.<ProductionOrderRouting>lambdaQuery()
                        .eq(ProductionOrderRouting::getProductionOrderId, productionOrder.getId())) == 0);
                .eq(ProductionOrderRouting::getProductionOrderId, productionOrder.getId())) == 0);
        if (needSync) {
            syncProductionOrderSnapshot(productionOrder.getId());
        }
@@ -258,7 +263,7 @@
        Map<String, BigDecimal> operationDemandedQuantityMap =
                buildOperationDemandedQuantityMap(orderBomStructureList, rootProductModelId);
        Map<Long, String> operationNameMap = technologyOperationMapper.selectBatchIds(
        // 遍历处理数据并组装结果
                        // 遍历处理数据并组装结果
                        routingOperations.stream()
                                .map(TechnologyRoutingOperation::getTechnologyOperationId)
                                .filter(Objects::nonNull)
@@ -437,6 +442,7 @@
        productionOrderBomMapper.insert(orderBom);
        Map<Long, Long> idMap = new HashMap<>();
        BigDecimal lastProcessDemandedQuantity = orderQuantity;
        for (TechnologyBomStructure source : structureList) {
            // 子节点 parentId 需要映射成新快照节点 id,才能保留原始 BOM 层级。
            ProductionBomStructure target = new ProductionBomStructure();
@@ -446,10 +452,11 @@
            target.setProductModelId(source.getProductModelId());
            target.setTechnologyOperationId(source.getOperationId());
            target.setUnitQuantity(source.getUnitQuantity());
            target.setDemandedQuantity(source.getUnitQuantity().multiply(orderQuantity));
            target.setDemandedQuantity(lastProcessDemandedQuantity.multiply(source.getUnitQuantity()));
            target.setUnit(source.getUnit());
            productionBomStructureMapper.insert(target);
            idMap.put(source.getId(), target.getId());
            lastProcessDemandedQuantity = target.getDemandedQuantity();
        }
        return orderBom;
    }
@@ -457,7 +464,7 @@
    private void clearProductionSnapshot(Long productionOrderId) {
        // 清理订单已生成的工艺与BOM快照数据
        boolean hasPickRecord = productionOrderPickRecordMapper.selectCount(
        // 查询并准备业务数据
                // 查询并准备业务数据
                Wrappers.<ProductionOrderPickRecord>lambdaQuery()
                        .eq(ProductionOrderPickRecord::getProductionOrderId, productionOrderId)) > 0;
        // 参数与前置条件校验
@@ -467,7 +474,7 @@
        List<Long> taskIds = productionOperationTaskMapper.selectList(
                        Wrappers.<ProductionOperationTask>lambdaQuery()
                                .eq(ProductionOperationTask::getProductionOrderId, productionOrderId))
        // 遍历处理数据并组装结果
                // 遍历处理数据并组装结果
                .stream().map(ProductionOperationTask::getId).collect(Collectors.toList());
        if (!taskIds.isEmpty()) {
            // 已有报工记录说明订单已开工,此时不允许再重建快照。
@@ -809,6 +816,46 @@
        }
    }
    private void fillProcessRouteStatus(List<ProductionOrderVo> records) {
        if (records == null || records.isEmpty()) {
            return;
        }
        List<Long> orderIds = records.stream()
                .map(ProductionOrderVo::getId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        if (orderIds.isEmpty()) {
            return;
        }
        List<ProductionOrderProcessTaskVo> tasks = productionOperationTaskMapper.listProcessStatusByOrderIds(orderIds);
        Map<Long, List<ProcessRouteStatusVo>> statusMap = new LinkedHashMap<>();
        if (tasks != null) {
            for (ProductionOrderProcessTaskVo task : tasks) {
                if (task == null || task.getProductionOrderId() == null) {
                    continue;
                }
                ProcessRouteStatusVo status = new ProcessRouteStatusVo();
                status.setName(task.getOperationName() != null && !task.getOperationName().isBlank()
                        ? task.getOperationName()
                        : "未知工序");
                BigDecimal percentage = task.getCompletionStatus() == null
                        ? BigDecimal.ZERO
                        : task.getCompletionStatus();
                if (percentage.compareTo(new BigDecimal("100")) > 0) {
                    percentage = new BigDecimal("100");
                }
                status.setPercentage(percentage);
                statusMap.computeIfAbsent(task.getProductionOrderId(), key -> new ArrayList<>()).add(status);
            }
        }
        for (ProductionOrderVo record : records) {
            record.setProcessRouteStatus(statusMap.getOrDefault(record.getId(), Collections.emptyList()));
        }
    }
    private StorageBlobVO toStorageBlobVO(StorageBlob blob) {
        // 将存储文件对象转换为VO
        StorageBlobVO vo = BeanUtil.copyProperties(blob, StorageBlobVO.class);
@@ -836,7 +883,7 @@
                new Page<ProductionOperationTaskVo>(1, -1), taskQuery);
        List<ProductionOperationTaskVo> workOrderList = workOrderPage == null || workOrderPage.getRecords() == null
                ? Collections.emptyList()
        // 遍历处理数据并组装结果
                // 遍历处理数据并组装结果
                : workOrderPage.getRecords().stream()
                .filter(Objects::nonNull)
                .sorted(Comparator.comparing(ProductionOperationTaskVo::getId, Comparator.nullsLast(Comparator.naturalOrder())))
@@ -852,7 +899,7 @@
                .collect(Collectors.toList());
        List<ProductionProductMain> reportMainList = workOrderIdList.isEmpty()
                ? Collections.emptyList()
        // 查询并准备业务数据
                // 查询并准备业务数据
                : productionProductMainMapper.selectList(
                Wrappers.<ProductionProductMain>lambdaQuery()
                        .in(ProductionProductMain::getProductionOperationTaskId, workOrderIdList)
@@ -1027,13 +1074,46 @@
            return Collections.emptyList();
        }
        List<ProductionBomStructureVo> bomStructureList = productionBomStructureMapper.pickByBomId(orderBom.getId());
        // 查询完整的BOM结构(包括根节点),用于计算层级需求数量
        List<ProductionBomStructureVo> bomStructureList = productionBomStructureMapper.listByBomId(orderBom.getId());
        if (bomStructureList == null || bomStructureList.isEmpty()) {
            return Collections.emptyList();
        }
        // 查询生产订单获取订单数量
        ProductionOrder productionOrder = productionOrderMapper.selectById(productionOrderId);
        BigDecimal orderQuantity = productionOrder != null ? defaultDecimal(productionOrder.getQuantity()) : BigDecimal.ZERO;
        // 构建树形结构并计算层级需求数量
        Map<Long, ProductionBomStructureVo> structureByIdMap = bomStructureList.stream()
                .filter(s -> s != null && s.getId() != null)
                .collect(Collectors.toMap(ProductionBomStructureVo::getId, s -> s));
        // 按层级计算需求数量:子级需求数量 = 父级需求数量 × 子级单位产出所需数量
        for (ProductionBomStructureVo structure : bomStructureList) {
            if (structure == null) continue;
            if (structure.getParentId() == null || structure.getParentId() == 0) {
                // 根节点:需求数量 = 订单数量
                structure.setDemandedQuantity(orderQuantity);
            } else {
                // 子节点:需求数量 = 父级需求数量 × 子级单位产出所需数量
                ProductionBomStructureVo parent = structureByIdMap.get(structure.getParentId());
                if (parent != null) {
                    BigDecimal parentDemandedQty = defaultDecimal(parent.getDemandedQuantity());
                    BigDecimal unitQuantity = defaultDecimal(structure.getUnitQuantity());
                    structure.setDemandedQuantity(parentDemandedQty.multiply(unitQuantity));
                }
            }
        }
        // 过滤出非根节点(实际领料项)
        List<ProductionBomStructureVo> childStructureList = bomStructureList.stream()
                .filter(s -> s != null && s.getParentId() != null && s.getParentId() != 0)
                .collect(Collectors.toList());
        // 遍历处理数据并组装结果
        List<Long> productModelIds = bomStructureList.stream()
        List<Long> productModelIds = childStructureList.stream()
                .map(ProductionBomStructureVo::getProductModelId)
                .filter(Objects::nonNull)
                .distinct()
@@ -1043,7 +1123,8 @@
        if (!productModelIds.isEmpty()) {
            List<StockInventory> stockList = stockInventoryMapper.selectList(
                    Wrappers.<StockInventory>lambdaQuery()
                            .in(StockInventory::getProductModelId, productModelIds));
                            .in(StockInventory::getProductModelId, productModelIds)
                            .gt(StockInventory::getQualitity, BigDecimal.ZERO));
            for (StockInventory stockItem : stockList) {
                if (stockItem == null || stockItem.getProductModelId() == null) {
                    continue;
@@ -1058,7 +1139,7 @@
        }
        Map<String, ProductionOrderPickVo> mergedPickMap = new LinkedHashMap<>();
        for (ProductionBomStructureVo structure : bomStructureList) {
        for (ProductionBomStructureVo structure : childStructureList) {
            if (structure == null || structure.getProductModelId() == null) {
                continue;
            }