From a610cbd7e6b7631254f15c832afce6e747b3581d Mon Sep 17 00:00:00 2001
From: huminmin <mac@MacBook-Pro.local>
Date: 星期四, 02 四月 2026 14:36:02 +0800
Subject: [PATCH] 生产报表相关接口

---
 src/main/java/com/ruoyi/production/service/ProductionStatisticService.java          |   46 ++++
 src/main/java/com/ruoyi/production/controller/ProductionStatisticController.java    |   61 ++++++
 src/main/java/com/ruoyi/production/service/impl/ProductionStatisticServiceImpl.java |  430 +++++++++++++++++++++++++++++++++++++++++++
 src/main/java/com/ruoyi/production/dto/ProductionStatisticDto.java                  |   11 +
 4 files changed, 548 insertions(+), 0 deletions(-)

diff --git a/src/main/java/com/ruoyi/production/controller/ProductionStatisticController.java b/src/main/java/com/ruoyi/production/controller/ProductionStatisticController.java
new file mode 100644
index 0000000..e72254d
--- /dev/null
+++ b/src/main/java/com/ruoyi/production/controller/ProductionStatisticController.java
@@ -0,0 +1,61 @@
+package com.ruoyi.production.controller;
+
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.home.dto.processDataProductionStatisticsDto;
+import com.ruoyi.production.service.ProductionStatisticService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RequestMapping("productStatistics")
+@RestController
+@Api(tags = "鐢熶骇缁熻")
+public class ProductionStatisticController {
+
+    @Autowired
+    private ProductionStatisticService productionStatisticService;
+
+    @ApiOperation(value = "鑾峰彇鐢熶骇宸ュ崟鏁伴噺缁熻鏁版嵁")
+    @GetMapping("/workOrderCount")
+    public AjaxResult getWorkOrderCount() {
+        return AjaxResult.success(productionStatisticService.getWorkOrderCount());
+    }
+
+    @ApiOperation(value = "鑾峰彇璐ㄩ噺缁熻鏁版嵁")
+    @GetMapping("/qualityStatistics")
+    public AjaxResult getQualityStatistics() {
+        return AjaxResult.success(productionStatisticService.getQualityStatistics());
+    }
+
+    @ApiOperation(value = "鑾峰彇浜ч噺缁熻鏁版嵁")
+    @GetMapping("/productionStatistics")
+    public AjaxResult getProductionStatistics() {
+        return AjaxResult.success(productionStatisticService.getProductionStatistics());
+    }
+
+    @ApiOperation(value = "鑾峰彇浜у搧浜у嚭鍒嗘瀽锛堥ゼ鐘跺浘锛�")
+    @GetMapping("/productOutputCategoryPieData")
+    public AjaxResult getProductOutputCategoryPieData() {
+        return AjaxResult.success(productionStatisticService.getProductOutputCategoryPieData());
+    }
+
+    @ApiOperation(value = "鑾峰彇宸ュ崟浜у嚭涓嶈壇鍘熷洜缁熻鍒嗘瀽")
+    @GetMapping("/defectReasonAnalysis")
+    public AjaxResult getDefectReasonAnalysis() {
+        return AjaxResult.success(productionStatisticService.getDefectReasonAnalysis());
+    }
+
+    @ApiOperation(value = "鑾峰彇宸ュ簭涓嶈壇鐜囧垎鏋�")
+    @GetMapping("/processDefectRateAnalysis")
+    public AjaxResult getProcessDefectRateAnalysis(
+            @RequestParam(required = false) String startDate,
+            @RequestParam(required = false) String endDate) {
+        return AjaxResult.success(productionStatisticService.getProcessDefectRateAnalysis(startDate, endDate));
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/production/dto/ProductionStatisticDto.java b/src/main/java/com/ruoyi/production/dto/ProductionStatisticDto.java
new file mode 100644
index 0000000..83ac7f9
--- /dev/null
+++ b/src/main/java/com/ruoyi/production/dto/ProductionStatisticDto.java
@@ -0,0 +1,11 @@
+package com.ruoyi.production.dto;
+
+import lombok.Data;
+
+@Data
+public class ProductionStatisticDto {
+    private Long totalCount;
+    private Long inProgressCount;
+    private Long completedCount;
+    private Long pendingCount;
+}
diff --git a/src/main/java/com/ruoyi/production/service/ProductionStatisticService.java b/src/main/java/com/ruoyi/production/service/ProductionStatisticService.java
new file mode 100644
index 0000000..54c6409
--- /dev/null
+++ b/src/main/java/com/ruoyi/production/service/ProductionStatisticService.java
@@ -0,0 +1,46 @@
+package com.ruoyi.production.service;
+
+import com.ruoyi.home.dto.processDataProductionStatisticsDto;
+import com.ruoyi.production.dto.ProductionStatisticDto;
+
+import java.util.List;
+import java.util.Map;
+
+public interface ProductionStatisticService {
+    
+    /**
+     * 鑾峰彇宸ュ崟缁熻鏁版嵁
+     * @return 鍖呭惈宸ュ崟鎬绘暟銆佽繘琛屼腑宸ュ崟銆佸畬鎴愬伐鍗曠殑Map
+     */
+    ProductionStatisticDto getWorkOrderCount();
+    
+    /**
+     * 鑾峰彇璐ㄩ噺缁熻鏁版嵁
+     * @return 鍖呭惈鍚堟牸鐜囥�佷笉鑹巼銆佹姤搴熸�绘暟鐨凪ap
+     */
+    Map<String, Object> getQualityStatistics();
+    
+    /**
+     * 鑾峰彇浜ч噺缁熻鏁版嵁
+     * @return 鍖呭惈鎬讳骇閲忔�婚銆佺敓浜ф�讳骇銆佺敓浜ф�绘秷鑰椼�佷骇鍝佹�讳緵搴斿叕鍙哥殑Map
+     */
+    Map<String, Object> getProductionStatistics();
+    
+    /**
+     * 鑾峰彇鍚勫伐搴忓畬鎴愬垎鏋愭暟鎹紙楗肩姸鍥撅級
+     * @return 宸ュ簭瀹屾垚鍒嗘瀽鏁版嵁鍒楄〃
+     */
+    List<Map<String, Object>> getProductOutputCategoryPieData();
+    
+    /**
+     * 鑾峰彇宸ュ崟浜у嚭涓嶈壇鍘熷洜缁熻鍒嗘瀽
+     * @return 涓嶈壇鍘熷洜缁熻鏁版嵁鍒楄〃
+     */
+    List<Map<String, Object>> getDefectReasonAnalysis();
+    
+    /**
+     * 鑾峰彇宸ュ簭涓嶈壇鐜囧垎鏋愶紙鎶樼嚎鍥撅級
+     * @return 鍚勫伐搴忎笉鑹巼鏁版嵁鍒楄〃
+     */
+    List<Map<String, Object>> getProcessDefectRateAnalysis(String startDate, String endDate);
+}
\ No newline at end of file
diff --git a/src/main/java/com/ruoyi/production/service/impl/ProductionStatisticServiceImpl.java b/src/main/java/com/ruoyi/production/service/impl/ProductionStatisticServiceImpl.java
new file mode 100644
index 0000000..17dc1c4
--- /dev/null
+++ b/src/main/java/com/ruoyi/production/service/impl/ProductionStatisticServiceImpl.java
@@ -0,0 +1,430 @@
+package com.ruoyi.production.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.ruoyi.basic.mapper.ProductMapper;
+import com.ruoyi.basic.mapper.ProductModelMapper;
+import com.ruoyi.basic.mapper.SupplierManageMapper;
+import com.ruoyi.basic.pojo.Product;
+import com.ruoyi.basic.pojo.ProductModel;
+import com.ruoyi.basic.pojo.SupplierManage;
+import com.ruoyi.home.dto.processDataProductionStatisticsDto;
+import com.ruoyi.production.dto.ProductionStatisticDto;
+import com.ruoyi.production.mapper.ProductProcessMapper;
+import com.ruoyi.production.mapper.ProductWorkOrderMapper;
+import com.ruoyi.production.mapper.ProductionProductInputMapper;
+import com.ruoyi.production.mapper.ProductionProductOutputMapper;
+import com.ruoyi.production.pojo.ProductProcess;
+import com.ruoyi.production.pojo.ProductWorkOrder;
+import com.ruoyi.production.pojo.ProductionProductInput;
+import com.ruoyi.production.pojo.ProductionProductOutput;
+import com.ruoyi.production.service.ProductionStatisticService;
+import com.ruoyi.quality.mapper.QualityInspectMapper;
+import com.ruoyi.quality.pojo.QualityInspect;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.YearMonth;
+import java.time.ZoneId;
+import java.util.Date;
+import java.util.Set;
+import java.util.TreeSet;
+import java.time.temporal.TemporalAdjusters;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鐢熶骇缁熻鏈嶅姟瀹炵幇绫�
+ */
+@Service
+public class ProductionStatisticServiceImpl implements ProductionStatisticService {
+
+    @Autowired
+    private ProductProcessMapper productProcessMapper;
+
+    @Autowired
+    private ProductWorkOrderMapper productWorkOrderMapper;
+
+    @Autowired
+    private ProductionProductOutputMapper productionProductOutputMapper;
+
+    @Autowired
+    private ProductionProductInputMapper productionProductInputMapper;
+
+    @Autowired
+    private QualityInspectMapper qualityInspectMapper;
+
+    @Autowired
+    private SupplierManageMapper supplierManageMapper;
+
+    @Autowired
+    private ProductModelMapper productModelMapper;
+
+    @Autowired
+    private ProductMapper productMapper;
+
+    @Override
+    public ProductionStatisticDto getWorkOrderCount() {
+        ProductionStatisticDto dto = new ProductionStatisticDto();
+
+        // 鏌ヨ宸ュ崟鎬绘暟
+        Long totalCount = productWorkOrderMapper.selectCount(null);
+        dto.setTotalCount(totalCount);
+
+        // 鏌ヨ杩涜涓伐鍗曪紙瀹屾垚鏁伴噺灏忎簬闇�姹傛暟閲忥級
+        Long inProgressCount = productWorkOrderMapper.selectCount(
+                new LambdaQueryWrapper<ProductWorkOrder>()
+                        .apply("complete_quantity < plan_quantity and complete_quantity > 0")
+        );
+        dto.setInProgressCount(inProgressCount);
+
+        // 鏌ヨ宸插畬鎴愬伐鍗曪紙瀹屾垚鏁伴噺澶т簬绛変簬闇�姹傛暟閲忥級
+        Long completedCount = productWorkOrderMapper.selectCount(
+                new LambdaQueryWrapper<ProductWorkOrder>()
+                        .apply("complete_quantity >= plan_quantity and complete_quantity > 0")
+        );
+        dto.setCompletedCount(completedCount);
+
+        // 鏌ヨ寰呭畬鎴愬伐鍗曪紙瀹屾垚鏁伴噺涓�0锛�
+        Long pendingCount = productWorkOrderMapper.selectCount(
+                new LambdaQueryWrapper<ProductWorkOrder>()
+                        .eq(ProductWorkOrder::getCompleteQuantity, 0)
+        );
+        dto.setPendingCount(pendingCount);
+
+        return dto;
+    }
+
+    @Override
+    public Map<String, Object> getQualityStatistics() {
+        Map<String, Object> result = new HashMap<>();
+        
+        // 鏌ヨ鎵�鏈夋姤宸ヨ褰�
+        List<ProductionProductOutput> outputList = productionProductOutputMapper.selectList(null);
+        
+        // 璁$畻鎶ュ伐鎬绘暟銆佹姤搴熸�绘暟鍜屼笉鑹�绘暟
+        BigDecimal totalOutput = BigDecimal.ZERO;
+        BigDecimal totalScrap = BigDecimal.ZERO;
+        BigDecimal totalDefect = BigDecimal.ZERO;
+        
+        for (ProductionProductOutput output : outputList) {
+            // 鎶ュ伐鎬绘暟
+            if (output.getQuantity() != null) {
+                totalOutput = totalOutput.add(output.getQuantity());
+            }
+            // 鎶ュ簾鏁伴噺
+            if (output.getScrapQty() != null) {
+                totalScrap = totalScrap.add(output.getScrapQty());
+            }
+            // 涓嶈壇鏁伴噺锛堜粠QualityInspect琛ㄦ煡璇級
+            List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
+                    new LambdaQueryWrapper<QualityInspect>()
+                            .eq(QualityInspect::getProductMainId, output.getProductMainId())
+            );
+            for (QualityInspect inspect : qualityInspects) {
+                if (inspect.getDefectiveQuantity() != null) {
+                    totalDefect = totalDefect.add(inspect.getDefectiveQuantity());
+                }
+            }
+        }
+        
+        // 璁$畻鍚堟牸鏁伴噺
+        BigDecimal qualifiedQuantity = totalOutput.subtract(totalScrap).subtract(totalDefect);
+        
+        // 璁$畻鍚堟牸鐜囧拰涓嶈壇鐜�
+        double qualifiedRate = 0.0;
+        double defectRate = 0.0;
+        if (totalOutput.compareTo(BigDecimal.ZERO) > 0) {
+            // 浣跨敤BigDecimal纭繚绮惧害
+            BigDecimal qualifiedRateBD = qualifiedQuantity.divide(totalOutput, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
+            BigDecimal defectRateBD = totalDefect.divide(totalOutput, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
+            // 淇濈暀涓や綅灏忔暟
+            qualifiedRate = qualifiedRateBD.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+            defectRate = defectRateBD.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+        }
+        
+        result.put("qualifiedRate", qualifiedRate); // 鍚堟牸鐜�
+        result.put("defectRate", defectRate); // 涓嶈壇鐜�
+        result.put("scrapCount", totalScrap.intValue()); // 鎶ュ簾鎬绘暟
+
+        return result;
+    }
+
+    @Override
+    public Map<String, Object> getProductionStatistics() {
+        Map<String, Object> result = new HashMap<>();
+        
+        // 鑾峰彇褰撳墠鏈堜唤鍜屼笂涓�涓湀浠界殑寮�濮嬪拰缁撴潫鏃堕棿
+        LocalDateTime now = LocalDateTime.now();
+        YearMonth currentMonth = YearMonth.from(now);
+        LocalDateTime currentMonthStart = now.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
+        LocalDateTime currentMonthEnd =  currentMonth.atEndOfMonth().atTime(23, 59, 59);
+        LocalDateTime lastMonth = now.minusMonths(1);
+        LocalDateTime lastMonthStart = lastMonth.with(TemporalAdjusters.firstDayOfMonth()).with(LocalTime.MIN);
+        LocalDateTime lastMonthEnd = currentMonthStart.minusDays(1).withHour(23).withMinute(59).withSecond(59);
+
+        // 璁$畻鐢熶骇鎬讳骇鍑猴紙褰撳墠鏈堬級
+        List<ProductionProductOutput> currentOutputList = productionProductOutputMapper.selectList(
+                new LambdaQueryWrapper<ProductionProductOutput>()
+                        .ge(ProductionProductOutput::getCreateTime, currentMonthStart)
+                        .le(ProductionProductOutput::getCreateTime, currentMonthEnd)
+        );
+        BigDecimal currentProductionOutput = BigDecimal.ZERO;
+        for (ProductionProductOutput output : currentOutputList) {
+            if (output.getQuantity() != null) {
+                currentProductionOutput = currentProductionOutput.add(output.getQuantity());
+            }
+        }
+        
+        // 璁$畻鐢熶骇鎬讳骇鍑猴紙涓婃湀锛�
+        List<ProductionProductOutput> lastOutputList = productionProductOutputMapper.selectList(
+                new LambdaQueryWrapper<ProductionProductOutput>()
+                        .ge(ProductionProductOutput::getCreateTime, lastMonthStart)
+                        .le(ProductionProductOutput::getCreateTime, lastMonthEnd)
+        );
+        BigDecimal lastProductionOutput = BigDecimal.ZERO;
+        for (ProductionProductOutput output : lastOutputList) {
+            if (output.getQuantity() != null) {
+                lastProductionOutput = lastProductionOutput.add(output.getQuantity());
+            }
+        }
+        
+        // 璁$畻鐢熶骇鎬绘秷鑰楋紙褰撳墠鏈堬級
+        List<ProductionProductInput> currentInputList = productionProductInputMapper.selectList(
+                new LambdaQueryWrapper<ProductionProductInput>()
+                        .ge(ProductionProductInput::getCreateTime, currentMonthStart)
+                        .le(ProductionProductInput::getCreateTime, currentMonthEnd)
+        );
+        BigDecimal currentProductionConsumption = BigDecimal.ZERO;
+        for (ProductionProductInput input : currentInputList) {
+            if (input.getQuantity() != null) {
+                currentProductionConsumption = currentProductionConsumption.add(input.getQuantity());
+            }
+        }
+        
+        // 璁$畻鐢熶骇鎬绘秷鑰楋紙涓婃湀锛�
+        List<ProductionProductInput> lastInputList = productionProductInputMapper.selectList(
+                new LambdaQueryWrapper<ProductionProductInput>()
+                        .ge(ProductionProductInput::getCreateTime, lastMonthStart)
+                        .le(ProductionProductInput::getCreateTime, lastMonthEnd)
+        );
+        BigDecimal lastProductionConsumption = BigDecimal.ZERO;
+        for (ProductionProductInput input : lastInputList) {
+            if (input.getQuantity() != null) {
+                lastProductionConsumption = lastProductionConsumption.add(input.getQuantity());
+            }
+        }
+        
+        // 璁$畻渚涘簲鍟嗘暟閲忥紙褰撳墠鏈堬級
+        List<SupplierManage> currentSuppliers = supplierManageMapper.selectList(
+                new LambdaQueryWrapper<SupplierManage>()
+                        .ge(SupplierManage::getCreateTime, currentMonthStart)
+                        .le(SupplierManage::getCreateTime, currentMonthEnd)
+        );
+        int currentSupplierCount = currentSuppliers != null ? currentSuppliers.size() : 0;
+        
+        // 璁$畻渚涘簲鍟嗘暟閲忥紙涓婃湀锛�
+        List<SupplierManage> lastSuppliers = supplierManageMapper.selectList(
+                new LambdaQueryWrapper<SupplierManage>()
+                        .ge(SupplierManage::getCreateTime, lastMonthStart)
+                        .le(SupplierManage::getCreateTime, lastMonthEnd)
+        );
+        int lastSupplierCount = lastSuppliers != null ? lastSuppliers.size() : 0;
+        
+        // 璁$畻瓒嬪娍
+        double productionOutputMonthlyChange = 0.0;
+        if (lastProductionOutput.compareTo(BigDecimal.ZERO) > 0) {
+            productionOutputMonthlyChange = (currentProductionOutput.subtract(lastProductionOutput)
+                    .divide(lastProductionOutput, 4, BigDecimal.ROUND_HALF_UP).doubleValue()) * 100;
+        }
+        
+        double productionConsumptionMonthlyChange = 0.0;
+        if (lastProductionConsumption.compareTo(BigDecimal.ZERO) > 0) {
+            productionConsumptionMonthlyChange = (currentProductionConsumption.subtract(lastProductionConsumption)
+                    .divide(lastProductionConsumption, 4, BigDecimal.ROUND_HALF_UP).doubleValue()) * 100;
+        }
+        
+        double supplierCountMonthlyChange = 0.0;
+        if (lastSupplierCount > 0) {
+            supplierCountMonthlyChange = ((currentSupplierCount - lastSupplierCount) * 100.0) / lastSupplierCount;
+        }
+        
+        result.put("productionOutput", currentProductionOutput.doubleValue()); // 鐢熶骇鎬讳骇
+        result.put("productionConsumption", currentProductionConsumption.doubleValue()); // 鐢熶骇鎬绘秷鑰�
+        result.put("productionOutputMonthlyChange", productionOutputMonthlyChange); // 鐢熶骇鎬讳骇鏈堝害鍙樺寲
+        result.put("productionConsumptionMonthlyChange", productionConsumptionMonthlyChange); // 鐢熶骇鎬绘秷鑰楁湀搴﹀彉鍖�
+        result.put("supplierCount", currentSupplierCount); // 浜у搧鎬讳緵搴斿叕鍙�
+        result.put("supplierCountMonthlyChange", supplierCountMonthlyChange); // 渚涘簲鍟嗘暟閲忔湀搴﹀彉鍖�
+        
+        return result;
+    }
+
+    @Override
+    public List<Map<String, Object>> getProductOutputCategoryPieData() {
+        List<Map<String, Object>> result = new ArrayList<>();
+        // 鎸変骇鍝佸ぇ绫�
+        // 鏌ヨ鎵�鏈夋姤宸ヨ褰�
+        List<ProductionProductOutput> outputList = productionProductOutputMapper.selectList(null);
+
+        // 鎸変骇鍝佸垎缁勮绠椾骇鍑烘暟閲�
+        Map<Long, BigDecimal> productOutputMap = new HashMap<>();
+
+        for (ProductionProductOutput output : outputList) {
+            if (output.getProductModelId() != null && output.getQuantity() != null) {
+                // 鏍规嵁productModelId鏌ヨProductModel
+                ProductModel productModel = productModelMapper.selectById(output.getProductModelId());
+                if (productModel != null && productModel.getProductId() != null) {
+                    // 鏍规嵁productId鏌ヨProduct
+                    Product product = productMapper.selectById(productModel.getProductId());
+                    if (product != null) {
+                        // 鎸変骇鍝両D鍒嗙粍璁$畻浜у嚭鏁伴噺
+                        productOutputMap.put(product.getId(),
+                            productOutputMap.getOrDefault(product.getId(), BigDecimal.ZERO).add(output.getQuantity()));
+                    }
+                }
+            }
+        }
+
+        // 杞崲涓虹粨鏋滄牸寮�
+        for (Map.Entry<Long, BigDecimal> entry : productOutputMap.entrySet()) {
+            Product product = productMapper.selectById(entry.getKey());
+            if (product != null) {
+                Map<String, Object> item = new HashMap<>();
+                item.put("name", product.getProductName());
+                item.put("value", entry.getValue().intValue());
+                result.add(item);
+            }
+        }
+
+        return result;
+    }
+
+    @Override
+    public List<Map<String, Object>> getDefectReasonAnalysis() {
+        List<Map<String, Object>> result = new ArrayList<>();
+        
+        // 鏌ヨ鎵�鏈夎川閲忔楠岃褰�
+        List<QualityInspect> qualityInspectList = qualityInspectMapper.selectList(null);
+        
+        // 鎸変笉鑹師鍥犲垎缁勭粺璁℃暟閲�
+        Map<String, Integer> reasonCountMap = new HashMap<>();
+        
+        for (QualityInspect inspect : qualityInspectList) {
+            if (inspect.getDefectiveReason() != null && !inspect.getDefectiveReason().isEmpty()) {
+                String reason = inspect.getDefectiveReason();
+                reasonCountMap.put(reason, reasonCountMap.getOrDefault(reason, 0) + 1);
+            }
+        }
+        
+        // 杞崲涓虹粨鏋滄牸寮�
+        for (Map.Entry<String, Integer> entry : reasonCountMap.entrySet()) {
+            Map<String, Object> item = new HashMap<>();
+            item.put("name", entry.getKey());
+            item.put("value", entry.getValue());
+            result.add(item);
+        }
+        
+        return result;
+    }
+
+    @Override
+    public List<Map<String, Object>> getProcessDefectRateAnalysis(String startDate, String endDate) {
+        List<Map<String, Object>> result = new ArrayList<>();
+        
+        // 榛樿鏌ヨ杩戜竴涓湀鏁版嵁
+        if (startDate == null || endDate == null) {
+            LocalDate now = LocalDate.now();
+            startDate = now.minusMonths(1).toString();
+            endDate = now.toString();
+        }
+        
+        // 瑙f瀽鏃ユ湡
+        LocalDate startLocalDate = LocalDate.parse(startDate);
+        LocalDate endLocalDate = LocalDate.parse(endDate);
+
+        // 鏌ヨ鎵�鏈夊伐搴�
+        List<ProductProcess> processList = productProcessMapper.selectList(null);
+        
+        // 鏀堕泦鎵�鏈夋棩鏈�
+        Set<LocalDate> dateSet = new TreeSet<>();
+        LocalDate currentDate = startLocalDate;
+        while (!currentDate.isAfter(endLocalDate)) {
+            dateSet.add(currentDate);
+            currentDate = currentDate.plusDays(1);
+        }
+        
+        // 鏋勫缓缁撴灉鏁版嵁
+        for (LocalDate date : dateSet) {
+            Map<String, Object> item = new HashMap<>();
+            item.put("date", date.toString());
+            
+            // 鍒濆鍖栨瘡鏃ユ�绘暟閲忓拰涓嶈壇鏁伴噺
+            BigDecimal dailyTotalQuantity = BigDecimal.ZERO;
+            BigDecimal dailyDefectiveQuantity = BigDecimal.ZERO;
+            
+            // 鍒濆鍖栧伐搴忔暟鎹垪琛�
+            List<Map<String, Object>> processesList = new ArrayList<>();
+            
+            for (ProductProcess process : processList) {
+                if (process.getName() != null) {
+                    // 鏌ヨ璇ュ伐搴忓湪鎸囧畾鏃ユ湡鐨勮川閲忔楠岃褰�
+                    List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
+                            new LambdaQueryWrapper<QualityInspect>()
+                                    .eq(QualityInspect::getProcess, process.getName())
+                                    .ge(QualityInspect::getCheckTime, Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant()))
+                                    .lt(QualityInspect::getCheckTime, Date.from(date.plusDays(1).atStartOfDay(ZoneId.systemDefault()).toInstant()))
+                    );
+                    
+                    // 璁$畻璇ュ伐搴忕殑鎬绘楠屾暟閲忓拰涓嶈壇鏁伴噺
+                    BigDecimal processTotalQuantity = BigDecimal.ZERO;
+                    BigDecimal processDefectiveQuantity = BigDecimal.ZERO;
+                    
+                    for (QualityInspect inspect : qualityInspects) {
+                        if (inspect.getQuantity() != null) {
+                            processTotalQuantity = processTotalQuantity.add(inspect.getQuantity());
+                            dailyTotalQuantity = dailyTotalQuantity.add(inspect.getQuantity());
+                        }
+                        if (inspect.getDefectiveQuantity() != null) {
+                            processDefectiveQuantity = processDefectiveQuantity.add(inspect.getDefectiveQuantity());
+                            dailyDefectiveQuantity = dailyDefectiveQuantity.add(inspect.getDefectiveQuantity());
+                        }
+                    }
+                    
+                    // 璁$畻璇ュ伐搴忕殑涓嶈壇鐜�
+                    double processDefectRate = 0.0;
+                    if (processTotalQuantity.compareTo(BigDecimal.ZERO) > 0) {
+                        // 璁$畻涓嶈壇鐜囷紝淇濈暀涓や綅灏忔暟
+                        BigDecimal defectRateDecimal = processDefectiveQuantity.divide(processTotalQuantity, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
+                        processDefectRate = defectRateDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+                    }
+                    
+                    // 鏋勫缓宸ュ簭鏁版嵁瀵硅薄
+                    Map<String, Object> processMap = new HashMap<>();
+                    processMap.put(process.getName(), processDefectRate);
+                    processesList.add(processMap);
+                }
+            }
+            
+            // 璁$畻姣忔棩骞冲潎涓嶈壇鐜�
+            double dailyAverageDefectRate = 0.0;
+            if (dailyTotalQuantity.compareTo(BigDecimal.ZERO) > 0) {
+                // 璁$畻涓嶈壇鐜囷紝淇濈暀涓や綅灏忔暟
+                BigDecimal defectRateDecimal = dailyDefectiveQuantity.divide(dailyTotalQuantity, 4, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
+                dailyAverageDefectRate = defectRateDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+            }
+            
+            // 娣诲姞骞冲潎涓嶈壇鐜囧拰宸ュ簭鏁版嵁鍒扮粨鏋滈」
+            item.put("averageDefectRate", dailyAverageDefectRate);
+            item.put("processes", processesList);
+            
+            result.add(item);
+        }
+        
+        return result;
+    }
+}
\ No newline at end of file

--
Gitblit v1.9.3