gongchunyi
3 天以前 3faea5bad90c8e55e8bf83f7a9c603f789ed6c84
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -36,6 +36,8 @@
import com.ruoyi.productionPlan.enums.AddressRegionEnum;
import com.ruoyi.productionPlan.mapper.SalesDeliveryMapper;
import com.ruoyi.productionPlan.pojo.SalesDelivery;
import com.ruoyi.productionPlan.pojo.ProductionPlan;
import com.ruoyi.productionPlan.service.ProductionPlanService;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysDictData;
import com.ruoyi.project.system.mapper.SysDeptMapper;
@@ -58,8 +60,10 @@
import com.ruoyi.staff.mapper.StaffOnJobMapper;
import com.ruoyi.staff.pojo.StaffOnJob;
import com.ruoyi.stock.mapper.StockInventoryMapper;
import com.ruoyi.energy.mapper.EnergyConsumptionDetailMapper;
import com.ruoyi.energy.mapper.EnergyMapper;
import com.ruoyi.energy.pojo.Energy;
import com.ruoyi.energy.dto.EnergyCostDto;
import com.ruoyi.energy.mapper.EnergyConsumptionDetailMapper;
import com.ruoyi.energy.vo.EnergyStatisticsVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -158,6 +162,10 @@
    @Autowired
    private SalesDeliveryMapper salesDeliveryMapper;
    @Autowired
    private EnergyMapper energyMapper;
    @Override
    public HomeBusinessDto business() {
@@ -2558,7 +2566,7 @@
                lastDay = date.with(TemporalAdjusters.lastDayOfYear());
            }
            LocalDate finalLastDay = lastDay;
            salesDeliveries = salesDeliveries
            List<SalesDelivery> salesDeliverie = salesDeliveries
                    .stream()
                    .filter(delivery -> {
                        LocalDate deliveryDate = delivery.getDeliveryDate();
@@ -2570,9 +2578,9 @@
                            AddressRegionEnum::getRegionName, // 区域名作为key
                            enumItem -> 0L                    // 初始值全部为0
                    ));
            if (!CollectionUtils.isEmpty(salesDeliveries)) {
            if (!CollectionUtils.isEmpty(salesDeliverie)) {
                // 按区域分组,统计每个区域的销量总和
                regionCountMap = salesDeliveries.stream()
                regionCountMap = salesDeliverie.stream()
                        .filter(delivery -> delivery.getDeliveryPlace() != null)
                        .collect(Collectors.groupingBy(
                                delivery -> {
@@ -2582,7 +2590,7 @@
                                Collectors.summingLong(delivery -> delivery.getVolume() != null ? delivery.getVolume().longValue() : 0L)
                        ));
            }
            regionCountMap.put("全部", salesDeliveries.stream()
            regionCountMap.put("全部", salesDeliverie.stream()
                    .mapToLong(item -> item.getVolume() != null ? item.getVolume().longValue() : 0L)
                    .sum());
            maps.add(regionCountMap);
@@ -2590,54 +2598,6 @@
        salesTotalDto.setDates(dates);
        salesTotalDto.setCustomerTrends(maps);
        return salesTotalDto;
    }
    @Override
    public List<SalesTotalDetailDto> salesRanking(SalesDeliveryDto salesDeliveryDto) {
        List<SalesTotalDetailDto> salesTotalDetailDtos = new ArrayList<>();
        List<LocalDate> dates = convertDateList(salesDeliveryDto.getDays());
        List<SalesDelivery> salesDeliveries = salesDeliveryMapper.selectList(Wrappers.<SalesDelivery>lambdaQuery()
                .eq(SalesDelivery::getProductName, salesDeliveryDto.getType()));
        for (LocalDate date : dates) {
            LocalDate firstDay = date.with(TemporalAdjusters.firstDayOfMonth());
            LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth());
            if (salesDeliveryDto.getDays().equals("年")) {
                lastDay = date.with(TemporalAdjusters.lastDayOfYear());
            }
            LocalDate finalLastDay = lastDay;
            salesDeliveries = salesDeliveries
                    .stream()
                    .filter(delivery -> {
                        LocalDate deliveryDate = delivery.getDeliveryDate();
                        return !deliveryDate.isBefore(firstDay) && !deliveryDate.isAfter(finalLastDay);
                    })
                    .collect(Collectors.toList());
            Map<String, Long> regionCountMap = Arrays.stream(AddressRegionEnum.values())
                    .collect(Collectors.toMap(
                            AddressRegionEnum::getRegionName, // 区域名作为key
                            enumItem -> 0L                    // 初始值全部为0
                    ));
            if (!CollectionUtils.isEmpty(salesDeliveries)) {
                // 按区域分组,统计每个区域的销量总和
                regionCountMap = salesDeliveries.stream()
                        .filter(delivery -> delivery.getDeliveryPlace() != null)
                        .collect(Collectors.groupingBy(
                                delivery -> {
                                    AddressRegionEnum regionEnum = AddressRegionEnum.matchRegion(delivery.getDeliveryPlace());
                                    return regionEnum != null ? regionEnum.getRegionName() : null;
                                },
                                Collectors.summingLong(delivery -> delivery.getVolume() != null ? delivery.getVolume().longValue() : 0L)
                        ));
            }
            regionCountMap.put("全部", salesDeliveries.stream()
                    .mapToLong(item -> item.getVolume() != null ? item.getVolume().longValue() : 0L)
                    .sum());
            SalesTotalDetailDto salesTotalDetailDto = new SalesTotalDetailDto();
            salesTotalDetailDto.setDate(date);
            salesTotalDetailDto.setType(salesDeliveryDto.getType());
            salesTotalDetailDtos.add(salesTotalDetailDto);
        }
        return salesTotalDetailDtos;
    }
    @Override
@@ -2654,7 +2614,7 @@
                lastDay = date.with(TemporalAdjusters.lastDayOfYear());
            }
            LocalDate finalLastDay = lastDay;
            salesDeliveries = salesDeliveries
            List<SalesDelivery> salesDeliverie = salesDeliveries
                    .stream()
                    .filter(delivery -> {
                        LocalDate deliveryDate = delivery.getDeliveryDate();
@@ -2666,9 +2626,9 @@
                            AddressRegionEnum::getRegionName, // 区域名作为key
                            enumItem -> 0L                    // 初始值全部为0
                    ));
            if (!CollectionUtils.isEmpty(salesDeliveries)) {
            if (!CollectionUtils.isEmpty(salesDeliverie)) {
                // 按区域分组,统计每个区域的销量总和
                regionCountMap = salesDeliveries.stream()
                regionCountMap = salesDeliverie.stream()
                        .filter(delivery -> delivery.getDeliveryPlace() != null)
                        .collect(Collectors.groupingBy(
                                delivery -> {
@@ -2678,7 +2638,7 @@
                                Collectors.summingLong(delivery -> delivery.getPrice() != null ? delivery.getPrice().longValue() : 0L)
                        ));
            }
            regionCountMap.put("全部", salesDeliveries.stream()
            regionCountMap.put("全部", salesDeliverie.stream()
                    .mapToLong(item -> item.getPrice() != null ? item.getPrice().longValue() : 0L)
                    .sum());
            maps.add(regionCountMap);
@@ -2686,14 +2646,6 @@
        salesTotalDto.setDates(dates);
        salesTotalDto.setCustomerTrends(maps);
        return salesTotalDto;
    }
    @Override
    public List<SalesTotalDetailDto> salesDataRanking(SalesDeliveryDto salesDeliveryDto) {
        List<SalesTotalDetailDto> salesTotalDetailDtos = new ArrayList<>();
        List<LocalDate> dates = convertDateList(salesDeliveryDto.getDays());
        return salesTotalDetailDtos;
    }
    @Override
@@ -3405,6 +3357,13 @@
        }
        if (!CollectionUtils.isEmpty(costDtos)) {
            // 获取单位
            List<Energy> energies = energyMapper.selectList(Wrappers.<Energy>lambdaQuery()
                    .in(Energy::getEnergyTyep, Arrays.asList("水", "电", "气")));
            String waterUnit = energies.stream().filter(e -> "水".equals(e.getEnergyTyep())).map(Energy::getUnit).findFirst().orElse("");
            String electricityUnit = energies.stream().filter(e -> "电".equals(e.getEnergyTyep())).map(Energy::getUnit).findFirst().orElse("");
            String steamUnit = energies.stream().filter(e -> "气".equals(e.getEnergyTyep())).map(Energy::getUnit).findFirst().orElse("");
            for (EnergyCostDto costDto : costDtos) {
                String dateStr = costDto.getMeterReadingDate();
                String label = "";
@@ -3427,10 +3386,413 @@
                    dayDto.setWater(water);
                    dayDto.setElectricity(electricity);
                    dayDto.setSteam(steam);
                    dayDto.setWaterUnit(waterUnit);
                    dayDto.setElectricityUnit(electricityUnit);
                    dayDto.setSteamUnit(steamUnit);
                }
            }
        }
        return new ArrayList<>(resultData.values());
    }
    @Override
    public SolidWasteCoreIndicatorsDto coreIndicators(productionStatisticsDto dto) {
        if (dto == null) {
            dto = new productionStatisticsDto();
            dto.setDateType(1);
        }
        LocalDate now = LocalDate.now();
        LocalDate startDate = null;
        if (dto.getDateType() != null && dto.getDateType() == 1) { // 本月至今
            startDate = now.withDayOfMonth(1);
        } else { // 本年至今
            startDate = now.withDayOfYear(1);
        }
        // 累计消纳量从2022-01-01开始
        LocalDate cumulativeStartDate = LocalDate.of(2022, 1, 1);
        // 查询从2022-01-01至今的所有报工数据
        List<ProductionProductMain> mainList = productionProductMainService.list(Wrappers.<ProductionProductMain>lambdaQuery()
                .ge(ProductionProductMain::getReportingTime, cumulativeStartDate.atStartOfDay()));
        if (CollectionUtils.isEmpty(mainList)) return new SolidWasteCoreIndicatorsDto();
        List<Long> mainIds = mainList.stream().map(ProductionProductMain::getId).collect(Collectors.toList());
        Map<Long, ProductionProductMain> mainMap = mainList.stream().collect(Collectors.toMap(ProductionProductMain::getId, m -> m));
        // 获取投入明细
        List<ProductionProductInput> allInputs = productionProductInputService.list(Wrappers.<ProductionProductInput>lambdaQuery()
                .in(ProductionProductInput::getProductMainId, mainIds));
        if (CollectionUtils.isEmpty(allInputs)) return new SolidWasteCoreIndicatorsDto();
        // 获取规格和物料名称
        Set<Long> skuIds = allInputs.stream().map(ProductionProductInput::getProductId).filter(Objects::nonNull).collect(Collectors.toSet());
        Map<Long, String> skuToMaterialNameMap = new HashMap<>();
        if (!skuIds.isEmpty()) {
            List<ProductMaterialSku> skus = productMaterialSkuService.listByIds(skuIds);
            Set<Long> productIds = skus.stream().map(ProductMaterialSku::getProductId).filter(Objects::nonNull).collect(Collectors.toSet());
            Map<Long, String> materialNameMap = productMaterialService.listByIds(productIds).stream()
                    .collect(Collectors.toMap(ProductMaterial::getId, ProductMaterial::getProductName));
            skuToMaterialNameMap = skus.stream()
                    .filter(s -> s.getProductId() != null && materialNameMap.containsKey(s.getProductId()))
                    .collect(Collectors.toMap(ProductMaterialSku::getId, s -> materialNameMap.get(s.getProductId())));
        }
        BigDecimal totalAmount = BigDecimal.ZERO;
        BigDecimal cumulativeAmount = BigDecimal.ZERO;
        Set<String> targetMaterials = new HashSet<>(Arrays.asList("粉煤灰", "石膏", "石灰"));
        for (ProductionProductInput input : allInputs) {
            String materialName = skuToMaterialNameMap.get(input.getProductId());
            if (materialName == null || !targetMaterials.contains(materialName)) continue;
            ProductionProductMain main = mainMap.get(input.getProductMainId());
            if (main == null || main.getReportingTime() == null) continue;
            BigDecimal qty = UnitUtils.convertValueToTon(input.getQuantity(), input.getUnit());
            // 累加累计消纳量
            cumulativeAmount = cumulativeAmount.add(qty);
            if (!main.getReportingTime().toLocalDate().isBefore(startDate)) {
                totalAmount = totalAmount.add(qty);
            }
        }
        SolidWasteCoreIndicatorsDto result = new SolidWasteCoreIndicatorsDto();
        result.setTotalAmount(totalAmount.setScale(2, RoundingMode.HALF_UP));
        result.setCumulativeAmount(cumulativeAmount.setScale(2, RoundingMode.HALF_UP));
        return result;
    }
    @Override
    public List<SolidWasteStatisticsDto> trends(productionStatisticsDto dto) {
        return solidWaste(dto);
    }
    @Override
    public List<MapDto> typeDistribution(productionStatisticsDto dto) {
        if (dto == null) {
            dto = new productionStatisticsDto();
            dto.setDateType(1);
        }
        LocalDate now = LocalDate.now();
        LocalDate startDate = null;
        if (dto.getDateType() != null && dto.getDateType() == 1) { // 本月至今
            startDate = now.withDayOfMonth(1);
        } else { // 本年至今
            startDate = now.withDayOfYear(1);
        }
        // 查询报工主表
        List<ProductionProductMain> mainList = productionProductMainService.list(Wrappers.<ProductionProductMain>lambdaQuery()
                .ge(ProductionProductMain::getReportingTime, startDate.atStartOfDay()));
        if (CollectionUtils.isEmpty(mainList)) return new ArrayList<>();
        List<Long> mainIds = mainList.stream().map(ProductionProductMain::getId).collect(Collectors.toList());
        // 获取投入明细
        List<ProductionProductInput> allInputs = productionProductInputService.list(Wrappers.<ProductionProductInput>lambdaQuery()
                .in(ProductionProductInput::getProductMainId, mainIds));
        if (CollectionUtils.isEmpty(allInputs)) return new ArrayList<>();
        // 获取规格和物料名称
        Set<Long> skuIds = allInputs.stream().map(ProductionProductInput::getProductId).filter(Objects::nonNull).collect(Collectors.toSet());
        Map<Long, String> skuToMaterialNameMap = new HashMap<>();
        if (!skuIds.isEmpty()) {
            List<ProductMaterialSku> skus = productMaterialSkuService.listByIds(skuIds);
            Set<Long> productIds = skus.stream().map(ProductMaterialSku::getProductId).filter(Objects::nonNull).collect(Collectors.toSet());
            Map<Long, String> materialNameMap = productMaterialService.listByIds(productIds).stream()
                    .collect(Collectors.toMap(ProductMaterial::getId, ProductMaterial::getProductName));
            skuToMaterialNameMap = skus.stream()
                    .filter(s -> s.getProductId() != null && materialNameMap.containsKey(s.getProductId()))
                    .collect(Collectors.toMap(ProductMaterialSku::getId, s -> materialNameMap.get(s.getProductId())));
        }
        Map<String, BigDecimal> countMap = new HashMap<>();
        countMap.put("粉煤灰", BigDecimal.ZERO);
        countMap.put("石膏", BigDecimal.ZERO);
        countMap.put("石灰", BigDecimal.ZERO);
        BigDecimal total = BigDecimal.ZERO;
        for (ProductionProductInput input : allInputs) {
            String materialName = skuToMaterialNameMap.get(input.getProductId());
            if (materialName == null || !countMap.containsKey(materialName)) continue;
            BigDecimal qty = UnitUtils.convertValueToTon(input.getQuantity(), input.getUnit());
            countMap.put(materialName, countMap.get(materialName).add(qty));
            total = total.add(qty);
        }
        List<MapDto> result = new ArrayList<>();
        for (Map.Entry<String, BigDecimal> entry : countMap.entrySet()) {
            MapDto mapDto = new MapDto();
            mapDto.setName(entry.getKey());
            BigDecimal value = entry.getValue().setScale(2, RoundingMode.HALF_UP);
            mapDto.setValue(value.toString());
            if (total.compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal rate = entry.getValue().divide(total, 4, RoundingMode.HALF_UP)
                        .multiply(new BigDecimal("100")).setScale(2, RoundingMode.HALF_UP);
                mapDto.setRate(rate.toString());
            } else {
                mapDto.setRate("0.00");
            }
            result.add(mapDto);
        }
        return result;
    }
    @Override
    public Map<String, Long> manage() {
        Map<String, Long> map = new HashMap<>();
        //生产订单总数
        Long total = productOrderMapper.selectCount(new QueryWrapper<ProductOrder>().ne("status", 4));
        map.put("total", total);
        //已完成订单数
        Long completed = productOrderMapper.selectCount(new QueryWrapper<ProductOrder>().eq("status", 3));
        map.put("completed", completed);
        //未完成订单数
        Long uncompleted = productOrderMapper.selectCount(new QueryWrapper<ProductOrder>().eq("status", 1));
        map.put("uncompleted", uncompleted);
        //部分完成订单数
        Long partialCompleted = productOrderMapper.selectCount(new QueryWrapper<ProductOrder>().eq("status", 2));
        map.put("partialCompleted", partialCompleted);
        //来料检总数
        Long materialInspection = qualityInspectMapper.selectCount(new QueryWrapper<QualityInspect>().eq("inspect_type", 0));
        map.put("materialInspection", materialInspection);
        return map;
    }
    @Autowired
    private ProductionPlanService productionPlanService;
    @Override
    public List<PlanTrendsDto> planTrends(Integer type) {
        LocalDate now = LocalDate.now();
        LocalDate startDate;
        DateTimeFormatter formatter;
        int points;
        if (type == null) type = 1;
        if (type == 1) { // 周
            startDate = now.with(DayOfWeek.MONDAY);
            points = (int) ChronoUnit.DAYS.between(startDate, now) + 1;
            formatter = DateTimeFormatter.ofPattern("MM-dd");
        } else if (type == 2) { // 月
            startDate = now.with(TemporalAdjusters.firstDayOfMonth());
            points = now.getDayOfMonth();
            formatter = DateTimeFormatter.ofPattern("MM-dd");
        } else { // 年
            startDate = now.with(TemporalAdjusters.firstDayOfYear());
            points = now.getMonthValue();
            formatter = DateTimeFormatter.ofPattern("yyyy-MM");
        }
        Map<String, PlanTrendsDto> resultMap = new LinkedHashMap<>();
        for (int i = 0; i < points; i++) {
            String label = (type == 3)
                ? startDate.plusMonths(i).format(formatter)
                : startDate.plusDays(i).format(formatter);
            PlanTrendsDto dto = new PlanTrendsDto();
            dto.setDateStr(label);
            dto.setPlannedVolume(BigDecimal.ZERO);
            dto.setLowerVolume(BigDecimal.ZERO);
            dto.setCompletionVolume(BigDecimal.ZERO);
            resultMap.put(label, dto);
        }
        //  统计计划量
        List<ProductionPlan> plans = productionPlanService.list(Wrappers.<ProductionPlan>lambdaQuery()
                .ge(ProductionPlan::getStartDate, Date.from(startDate.atStartOfDay(ZoneId.systemDefault()).toInstant())));
        for (ProductionPlan plan : plans) {
            if (plan.getStartDate() == null || plan.getVolume() == null) continue;
            LocalDate d = plan.getStartDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            String label = d.format(formatter);
            if (resultMap.containsKey(label)) {
                PlanTrendsDto dto = resultMap.get(label);
                dto.setPlannedVolume(dto.getPlannedVolume().add(plan.getVolume()));
            }
        }
        //  统计下发量
        List<ProductOrder> orders = productOrderMapper.selectList(Wrappers.<ProductOrder>lambdaQuery()
                .ge(ProductOrder::getStartTime, startDate.atStartOfDay()));
        for (ProductOrder order : orders) {
            if (order.getStartTime() == null || order.getQuantity() == null) continue;
            LocalDate d = order.getStartTime().toLocalDate();
            String label = d.format(formatter);
            if (resultMap.containsKey(label)) {
                PlanTrendsDto dto = resultMap.get(label);
                dto.setLowerVolume(dto.getLowerVolume().add(order.getQuantity()));
            }
        }
        //  统计完成量
        List<ProductionProductOutput> outputs = productionProductOutputMapper.selectList(Wrappers.<ProductionProductOutput>lambdaQuery()
                .ge(ProductionProductOutput::getCreateTime, startDate.atStartOfDay()));
        for (ProductionProductOutput output : outputs) {
            if (output.getCreateTime() == null || output.getQuantity() == null) continue;
            LocalDate d = output.getCreateTime().toLocalDate();
            String label = d.format(formatter);
            if (resultMap.containsKey(label)) {
                PlanTrendsDto dto = resultMap.get(label);
                dto.setCompletionVolume(dto.getCompletionVolume().add(output.getQuantity()));
            }
        }
        return new ArrayList<>(resultMap.values());
    }
    @Override
    public List<RawMaterialProductionDto> rawMaterialProductions(String month) {
        YearMonth yearMonth;
        try {
            yearMonth = YearMonth.parse(month);
        } catch (Exception e) {
            log.error("解析月份失败: {}", month);
            return Collections.emptyList();
        }
        LocalDateTime monthStart = yearMonth.atDay(1).atStartOfDay();
        LocalDateTime monthEnd = yearMonth.atEndOfMonth().atTime(LocalTime.MAX);
        //  获取产品类型字典
        List<SysDictData> sysDictDataList = sysDictDataMapper.selectDictDataByType("product_type");
        Map<Long, String> dictCodeToLabelMap = sysDictDataList.stream()
                .filter(d -> d.getDictCode() != null && d.getDictLabel() != null)
                .collect(Collectors.toMap(SysDictData::getDictCode, SysDictData::getDictLabel));
        //  查询当月报工主表
        List<ProductionProductMain> mainList = productionProductMainService.list(Wrappers.<ProductionProductMain>lambdaQuery()
                .between(ProductionProductMain::getReportingTime, monthStart, monthEnd));
        if (CollectionUtils.isEmpty(mainList)) {
            return Collections.emptyList();
        }
        List<Long> mainIds = mainList.stream().map(ProductionProductMain::getId).collect(Collectors.toList());
        List<Long> orderIds = mainList.stream().map(ProductionProductMain::getProductOrderId).distinct().collect(Collectors.toList());
        Map<Long, ProductionProductMain> mainMap = mainList.stream().collect(Collectors.toMap(ProductionProductMain::getId, m -> m));
        //  获取订单对应的产品类型
        Map<Long, Long> orderRouteMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(orderIds)) {
            List<ProductionOrderRoute> routes = productionOrderRouteService.list(Wrappers.<ProductionOrderRoute>lambdaQuery()
                    .in(ProductionOrderRoute::getOrderId, orderIds));
            orderRouteMap = routes.stream()
                    .filter(r -> r.getOrderId() != null && r.getDictCode() != null)
                    .collect(Collectors.toMap(ProductionOrderRoute::getOrderId, ProductionOrderRoute::getDictCode, (v1, v2) -> v1));
        }
        //  获取投入和产出明细
        List<ProductionProductInput> allInputs = productionProductInputService.list(Wrappers.<ProductionProductInput>lambdaQuery()
                .in(ProductionProductInput::getProductMainId, mainIds));
        List<ProductionProductOutput> allOutputs = productionProductOutputService.list(Wrappers.<ProductionProductOutput>lambdaQuery()
                .in(ProductionProductOutput::getProductMainId, mainIds));
        //  获取 SKU 的物料名称
        Set<Long> inputSkuIds = allInputs.stream().map(ProductionProductInput::getProductId).filter(Objects::nonNull).collect(Collectors.toSet());
        Map<Long, String> skuToMaterialNameMap = new HashMap<>();
        if (!inputSkuIds.isEmpty()) {
            List<ProductMaterialSku> skus = productMaterialSkuService.listByIds(inputSkuIds);
            Set<Long> productIds = skus.stream().map(ProductMaterialSku::getProductId).filter(Objects::nonNull).collect(Collectors.toSet());
            Map<Long, String> materialNameMap = productMaterialService.listByIds(productIds).stream()
                    .collect(Collectors.toMap(ProductMaterial::getId, ProductMaterial::getProductName));
            skuToMaterialNameMap = skus.stream()
                    .filter(s -> s.getProductId() != null && materialNameMap.containsKey(s.getProductId()))
                    .collect(Collectors.toMap(ProductMaterialSku::getId, s -> materialNameMap.get(s.getProductId())));
        }
        BigDecimal yield35 = BigDecimal.ZERO;
        BigDecimal yield50 = BigDecimal.ZERO;
        BigDecimal yieldPlate = BigDecimal.ZERO;
        // 材质名称 -> [3.5用量, 5.0用量, 板材用量]
        Map<String, BigDecimal[]> materialConsumptionMap = new LinkedHashMap<>();
        //  统计产量
        for (ProductionProductOutput output : allOutputs) {
            ProductionProductMain main = mainMap.get(output.getProductMainId());
            if (main == null) continue;
            Long dictCode = orderRouteMap.get(main.getProductOrderId());
            String label = dictCodeToLabelMap.get(dictCode);
            BigDecimal qty = output.getQuantity() != null ? output.getQuantity() : BigDecimal.ZERO;
            if (label != null) {
                if (label.contains("3.5")) yield35 = yield35.add(qty);
                else if (label.contains("5.0")) yield50 = yield50.add(qty);
                else if (label.contains("板材")) yieldPlate = yieldPlate.add(qty);
            }
        }
        //  统计消耗量
        for (ProductionProductInput input : allInputs) {
            ProductionProductMain main = mainMap.get(input.getProductMainId());
            if (main == null) continue;
            Long dictCode = orderRouteMap.get(main.getProductOrderId());
            String label = dictCodeToLabelMap.get(dictCode);
            String materialName = skuToMaterialNameMap.get(input.getProductId());
            if (materialName == null) continue;
            BigDecimal qty = UnitUtils.convertValueToTon(input.getQuantity(), input.getUnit());
            materialConsumptionMap.putIfAbsent(materialName, new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO});
            BigDecimal[] consumptions = materialConsumptionMap.get(materialName);
            if (label != null) {
                if (label.contains("3.5")) consumptions[0] = consumptions[0].add(qty);
                else if (label.contains("5.0")) consumptions[1] = consumptions[1].add(qty);
                else if (label.contains("板材")) consumptions[2] = consumptions[2].add(qty);
            }
        }
        List<RawMaterialProductionDto> result = new ArrayList<>();
        // 产量行
        RawMaterialProductionDto yieldRow = new RawMaterialProductionDto();
        yieldRow.setItemName("产量");
        yieldRow.setUsage35(yield35);
        yieldRow.setUsage50(yield50);
        yieldRow.setUsagePlate(yieldPlate);
        yieldRow.setTotalUsage(yield35.add(yield50).add(yieldPlate));
        yieldRow.setBlockTotalUsage(yield35.add(yield50));
        result.add(yieldRow);
        // 物料行
        List<String> targetMaterials = Arrays.asList(
                "粉煤灰", "水泥", "石灰", "铝粉", "石膏", "脱模剂",
                "打包带", "冷拔丝", "氧化镁", "卡扣", "防腐剂"
        );
        for (String materialName : targetMaterials) {
            BigDecimal[] consumptions = materialConsumptionMap.getOrDefault(materialName,
                    new BigDecimal[]{BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO});
            RawMaterialProductionDto row = new RawMaterialProductionDto();
            row.setItemName(materialName);
            row.setUsage35(consumptions[0]);
            row.setUsage50(consumptions[1]);
            row.setUsagePlate(consumptions[2]);
            // 计算单耗
            row.setUnitConsumption35(calculateUnitConsumption(consumptions[0], yield35));
            row.setUnitConsumption50(calculateUnitConsumption(consumptions[1], yield50));
            row.setUnitConsumptionPlate(calculateUnitConsumption(consumptions[2], yieldPlate));
            row.setTotalUsage(consumptions[0].add(consumptions[1]).add(consumptions[2]));
            row.setBlockTotalUsage(consumptions[0].add(consumptions[1]));
            result.add(row);
        }
        return result;
    }
    private BigDecimal calculateUnitConsumption(BigDecimal usage, BigDecimal yield) {
        if (yield == null || yield.compareTo(BigDecimal.ZERO) == 0) {
            return BigDecimal.ZERO;
        }
        return usage.divide(yield, 4, RoundingMode.HALF_UP);
    }
}