11
gongchunyi
6 天以前 1f5fdca1ab73461fb930f64c26dcb4038a9d4bf7
11
已修改2个文件
157 ■■■■ 文件已修改
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java 131 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -1019,7 +1019,7 @@
    public List<Map<String, Object>> productInOutAnalysis(Integer type) {
        String targetName;
        if (type == 1) {
            targetName = "原材料";
            targetName = "原料";
        } else if (type == 2) {
            targetName = "成品";
        } else if (type == 3) {
@@ -1478,95 +1478,80 @@
        String endStr = endDate.atTime(LocalTime.MAX).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        List<ProductionTaskStatisticsDto> startList = productionOperationTaskMapper.selectTaskStartStats(startStr, endStr);
        List<ProductionProductOutputDto> outputList = productionProductOutputMapper
                .selectOutputStats(startStr, endStr);
        List<ProductionProductOutputDto> outputList = productionProductOutputMapper.selectOutputStats(startStr, endStr);
        Map<String, WorkOrderEfficiencyDto> dateMap = new HashMap<>();
        // 1. 处理开工数量(统一将时间转为 LocalDate 字符串,去除时分秒)
        if (!CollectionUtils.isEmpty(startList)) {
            for (ProductionTaskStatisticsDto item : startList) {
                if (item.getActualStartTime() != null) {
                    String date = item.getActualStartTime().toString();
                    WorkOrderEfficiencyDto dto = dateMap.getOrDefault(date, new WorkOrderEfficiencyDto());
                    dto.setDate(date);
                    BigDecimal qty = item.getPlanQuantity() != null ? item.getPlanQuantity() : BigDecimal.ZERO;
                    dto.setStartQuantity(dto.getStartQuantity() != null ? dto.getStartQuantity().add(qty) : qty);
                    dateMap.put(date, dto);
                }
            }
        }
        // 完工数量和良品率
        if (!CollectionUtils.isEmpty(outputList)) {
            for (ProductionProductOutputDto item : outputList) {
                if (item.getCreateTime() != null) {
                    String date = item.getCreateTime().toLocalDate().toString();
                    WorkOrderEfficiencyDto dto = dateMap.getOrDefault(date, new WorkOrderEfficiencyDto());
                    dto.setDate(date);
                    BigDecimal finishQty = item.getQuantity() != null ? item.getQuantity() : BigDecimal.ZERO;
                    BigDecimal scrapQty = item.getScrapQty() != null ? item.getScrapQty() : BigDecimal.ZERO;
                    dto.setFinishQuantity(
                            dto.getFinishQuantity() != null ? dto.getFinishQuantity().add(finishQty) : finishQty);
                }
            }
            Map<String, BigDecimal> scrapMap = outputList.stream()
                    .filter(i -> i.getCreateTime() != null)
                    .collect(Collectors.groupingBy(
                            i -> i.getCreateTime().toLocalDate().toString(),
                            Collectors.reducing(BigDecimal.ZERO,
                                    i -> i.getScrapQty() != null ? i.getScrapQty() : BigDecimal.ZERO,
                                    BigDecimal::add)));
            Map<String, BigDecimal> finishMap = outputList.stream()
                    .filter(i -> i.getCreateTime() != null)
                    .collect(Collectors.groupingBy(
                            i -> i.getCreateTime().toLocalDate().toString(),
                            Collectors.reducing(BigDecimal.ZERO, i -> {
                                BigDecimal qty = (i.getQuantity() != null) ? i.getQuantity() : BigDecimal.ZERO;
                                BigDecimal scrap = (i.getScrapQty() != null) ? i.getScrapQty() : BigDecimal.ZERO;
                                return qty.subtract(scrap);
                            }, BigDecimal::add)));
            finishMap.forEach((date, qty) -> {
                WorkOrderEfficiencyDto dto = dateMap.getOrDefault(date, new WorkOrderEfficiencyDto());
                dto.setDate(date);
                dto.setFinishQuantity(qty);
                dateMap.put(date, dto);
                    // 💡 关键修改:如果是 LocalDateTime,必须先 toLocalDate() 再 toString()
                    String dateStr = item.getActualStartTime().toString();
                    WorkOrderEfficiencyDto dto = dateMap.computeIfAbsent(dateStr, k -> {
                        WorkOrderEfficiencyDto newDto = new WorkOrderEfficiencyDto();
                        newDto.setDate(k);
                        newDto.setStartQuantity(BigDecimal.ZERO);
                        newDto.setFinishQuantity(BigDecimal.ZERO);
                        newDto.setYieldRate("0.00");
                        return newDto;
            });
            dateMap.forEach((date, dto) -> {
                BigDecimal finish = dto.getFinishQuantity() != null ? dto.getFinishQuantity() : BigDecimal.ZERO;
                BigDecimal scrap = scrapMap.getOrDefault(date, BigDecimal.ZERO);
                    BigDecimal qty = item.getPlanQuantity() != null ? item.getPlanQuantity() : BigDecimal.ZERO;
                    dto.setStartQuantity(dto.getStartQuantity().add(qty));
                }
            }
        }
        // 2. 处理完工数量和报废数量(仅通过 1 次循环搞定,大幅提升性能)
        if (!CollectionUtils.isEmpty(outputList)) {
            // 定义一个临时的报废数计数器,方便后面算良品率
            Map<String, BigDecimal> scrapMap = new HashMap<>();
            for (ProductionProductOutputDto item : outputList) {
                if (item.getCreateTime() != null) {
                    String dateStr = item.getCreateTime().toLocalDate().toString();
                    WorkOrderEfficiencyDto dto = dateMap.computeIfAbsent(dateStr, k -> {
                        WorkOrderEfficiencyDto newDto = new WorkOrderEfficiencyDto();
                        newDto.setDate(k);
                        newDto.setStartQuantity(BigDecimal.ZERO);
                        newDto.setFinishQuantity(BigDecimal.ZERO);
                        newDto.setYieldRate("0.00");
                        return newDto;
                    });
                    BigDecimal qty = item.getQuantity() != null ? item.getQuantity() : BigDecimal.ZERO;
                    BigDecimal scrap = item.getScrapQty() != null ? item.getScrapQty() : BigDecimal.ZERO;
                    // 良品数 = 总投入数 - 报废数 (对应你原代码中 finishMap 的逻辑)
                    BigDecimal goodQty = qty.subtract(scrap);
                    dto.setFinishQuantity(dto.getFinishQuantity().add(goodQty));
                    // 累加报废数
                    scrapMap.put(dateStr, scrapMap.getOrDefault(dateStr, BigDecimal.ZERO).add(scrap));
                }
            }
            // 3. 计算良品率
            dateMap.forEach((dateStr, dto) -> {
                BigDecimal finish = dto.getFinishQuantity();
                BigDecimal scrap = scrapMap.getOrDefault(dateStr, BigDecimal.ZERO);
                BigDecimal total = finish.add(scrap);
                if (total.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal rate = finish.divide(total, 4, RoundingMode.HALF_UP).multiply(new BigDecimal("100"))
                            .setScale(2, RoundingMode.HALF_UP);
                    // 💡 延续你之前的逻辑:使用 RoundingMode.DOWN 截断,防止 99.999% 四舍五入变成 100.00
                    BigDecimal rate = finish.divide(total, 4, RoundingMode.DOWN)
                            .multiply(new BigDecimal("100"))
                            .setScale(2, RoundingMode.DOWN);
                    dto.setYieldRate(rate.toString());
                } else {
                    dto.setYieldRate("0.00");
                }
                if (dto.getStartQuantity() == null)
                    dto.setStartQuantity(BigDecimal.ZERO);
                if (dto.getFinishQuantity() == null)
                    dto.setFinishQuantity(BigDecimal.ZERO);
            });
        }
        dateMap.values().forEach(dto -> {
            if (dto.getStartQuantity() == null)
                dto.setStartQuantity(BigDecimal.ZERO);
            if (dto.getFinishQuantity() == null)
                dto.setFinishQuantity(BigDecimal.ZERO);
            if (dto.getYieldRate() == null)
                dto.setYieldRate("0.00");
        });
        // 4. 排序并输出
        return dateMap.values().stream()
                .sorted(Comparator.comparing(WorkOrderEfficiencyDto::getDate))
                .collect(Collectors.toList());
@@ -1915,7 +1900,7 @@
            }
            switch (parent.getProductName()) {
                case "原材料":
                case "原料":
                    rawMaterialCount = rawMaterialCount.add(quantity);
                    break;
                case "半成品":
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -183,7 +183,7 @@
            JOIN product pr ON slp.product_id = pr.id
        WHERE
            slp.type = 2
            AND pr.parent_id = ( SELECT id FROM product WHERE product_name = '原材料' )
            AND pr.parent_id = ( SELECT id FROM product WHERE product_name = '原料' )
        GROUP BY
            pr.id,
            pr.product_name
@@ -194,20 +194,36 @@
    <select id="selectProductCountByTypeAndDate" resultType="int">
        SELECT IFNULL(COUNT(*), 0)
        FROM sales_ledger_product
        FROM sales_ledger_product slp
        LEFT JOIN sales_ledger sl ON sl.id = slp.sales_ledger_id
        LEFT JOIN purchase_ledger pl ON pl.id = slp.sales_ledger_id
        WHERE type = #{type}
        <choose>
            <when test="type == 1">
        <if test="startDate != null">
            AND register_date &gt;= #{startDate}
                    AND sl.entry_date &gt;= #{startDate}
        </if>
        <if test="endDate != null">
            AND register_date &lt;= #{endDate}
                    AND sl.entry_date &lt;= #{endDate}
        </if>
            </when>
            <when test="type == 2">
                <if test="startDate != null">
                    AND pl.entry_date &gt;= #{startDate}
                </if>
                <if test="endDate != null">
                    AND pl.entry_date &lt;= #{endDate}
                </if>
            </when>
        </choose>
    </select>
    <select id="selectRawMaterialExpense" resultType="java.math.BigDecimal">
        WITH RECURSIVE product_tree AS (SELECT id
                                        FROM product
                                        WHERE product_name = '原材料'
                                        WHERE product_name = '原料'
                                        UNION ALL