src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -1721,14 +1721,15 @@
        LocalDate endDate = range[1];
        String startStr = startDate.toString();
        String endStr = endDate.toString();
        // 使用区间右开(< endDate + 1 天)保证检测时间含时分秒时也能覆盖到 endDate 当天
        String endExclusiveStr = endDate.plusDays(1).toString();
        List<QualityInspect> list = qualityInspectMapper.selectList(
                new LambdaQueryWrapper<QualityInspect>()
                        .eq(QualityInspect::getInspectType, inspectType)
                        .eq(QualityInspect::getInspectState, 1)
                        .ge(QualityInspect::getCheckTime, startStr)
                        .le(QualityInspect::getCheckTime, endStr));
                        .lt(QualityInspect::getCheckTime, endExclusiveStr));
        return buildQualifiedAnalysis(list);
    }
@@ -1767,8 +1768,8 @@
        QualityQualifiedAnalysisDto dto = new QualityQualifiedAnalysisDto();
        if (CollectionUtils.isEmpty(list)) {
            dto.setQualifiedCount(0);
            dto.setUnqualifiedCount(0);
            dto.setQualifiedCount(BigDecimal.valueOf(0));
            dto.setUnqualifiedCount(BigDecimal.valueOf(0));
            dto.setQualifiedRate(BigDecimal.ZERO.setScale(2));
            dto.setUnqualifiedRate(BigDecimal.ZERO.setScale(2));
            return dto;
@@ -1784,8 +1785,8 @@
        BigDecimal totalCount = qualifiedCount.add(unqualifiedCount);
        dto.setQualifiedCount(qualifiedCount.intValue());
        dto.setUnqualifiedCount(unqualifiedCount.intValue());
        dto.setQualifiedCount(qualifiedCount);
        dto.setUnqualifiedCount(unqualifiedCount);
        if (totalCount.compareTo(BigDecimal.ZERO) == 0) {
            dto.setQualifiedRate(BigDecimal.ZERO.setScale(2));
@@ -1808,74 +1809,64 @@
    @Override
    public QualityInspectionCountDto qualityInspectionCount() {
        String todayStr = LocalDate.now().toString();
        String prevDayStr = LocalDate.now().minusDays(1).toString();
        // 查询出截止今日的总检验数
        List<QualityInspect> todayList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
                .le(QualityInspect::getCheckTime, todayStr));
        // 查询出截止前一天的总检验数
        List<QualityInspect> prevList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
                .le(QualityInspect::getCheckTime, prevDayStr));
        // 计算今日的总检验数
        BigDecimal todayCount = todayList.stream()
                .map(QualityInspect::getQuantity)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // 计算前一天的总检验数
        BigDecimal prevCount = prevList.stream()
                .map(QualityInspect::getQuantity)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        LocalDate today = LocalDate.now();
        String todayStartStr = today.toString();
        String tomorrowStartStr = today.plusDays(1).toString();
        String yesterdayStartStr = today.minusDays(1).toString();
        // 计算今日相对昨天的一个总比增长
        BigDecimal growthRate = calcGrowthRate(todayCount, prevCount);
        // 累计总检验数(截止今日 24:00 之前的所有记录)
        BigDecimal totalCount = sumInspectQuantity(null, tomorrowStartStr, null);
        // 今日单日检验数
        BigDecimal todayCount = sumInspectQuantity(todayStartStr, tomorrowStartStr, null);
        // 昨日单日检验数
        BigDecimal yesterdayCount = sumInspectQuantity(yesterdayStartStr, todayStartStr, null);
        // 总检验数同比增长 = (今日单日 - 昨日单日) / 昨日单日 × 100%
        BigDecimal growthRate = calcGrowthRate(todayCount, yesterdayCount);
        // 计算今天的待完成数量
        List<QualityInspect> todayPendingList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
                .eq(QualityInspect::getInspectState, 0)
                .eq(QualityInspect::getCheckTime, todayStr));
        // 今日待完成(inspectState=0)
        BigDecimal todayPendingCount = sumInspectQuantity(todayStartStr, tomorrowStartStr, 0);
        BigDecimal yesterdayPendingCount = sumInspectQuantity(yesterdayStartStr, todayStartStr, 0);
        BigDecimal todayPendingCountGrowthRate = calcGrowthRate(todayPendingCount, yesterdayPendingCount);
        // 计算前一天的待完成数量
        List<QualityInspect> prevPendingList = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
                .eq(QualityInspect::getInspectState, 0)
                .eq(QualityInspect::getCheckTime, prevDayStr));
        // 计算今天的待完成数量
        BigDecimal todayPendingCount = todayPendingList.stream()
                .map(QualityInspect::getQuantity)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // 今日已完成(inspectState=1)
        BigDecimal todayCompletedCount = sumInspectQuantity(todayStartStr, tomorrowStartStr, 1);
        BigDecimal yesterdayCompletedCount = sumInspectQuantity(yesterdayStartStr, todayStartStr, 1);
        BigDecimal todayCompletedCountGrowthRate = calcGrowthRate(todayCompletedCount, yesterdayCompletedCount);
        // 计算前一天的待完成数量
        BigDecimal prevPendingCount = prevPendingList.stream()
                .map(QualityInspect::getQuantity)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // 计算今天的待完成数量相对昨天的一个同比增长
        BigDecimal todayPendingCountGrowthRate = calcGrowthRate(todayPendingCount, prevPendingCount);
        // 计算今天的已完成数量
        List<QualityInspect> todayCompletedList = qualityInspectMapper
                .selectList(new LambdaQueryWrapper<QualityInspect>()
                        .eq(QualityInspect::getInspectState, 1)
                        .eq(QualityInspect::getCheckTime, todayStr));
        // 计算前一天的已完成数量
        List<QualityInspect> prevCompletedList = qualityInspectMapper
                .selectList(new LambdaQueryWrapper<QualityInspect>()
                        .eq(QualityInspect::getInspectState, 1)
                        .eq(QualityInspect::getCheckTime, prevDayStr));
        // 计算今天的已完成数量
        BigDecimal todayCompletedCount = todayCompletedList.stream()
                .map(QualityInspect::getQuantity)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // 计算前一天的已完成数量
        BigDecimal prevCompletedCount = prevCompletedList.stream()
                .map(QualityInspect::getQuantity)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
        // 计算今天的已完成数量相对昨天的一个同比增长
        BigDecimal todayCompletedCountGrowthRate = calcGrowthRate(todayCompletedCount, prevCompletedCount);
        QualityInspectionCountDto dto = new QualityInspectionCountDto();
        dto.setTotalCount(todayCount);
        dto.setTotalCount(totalCount);
        dto.setTotalCountGrowthRate(growthRate);
        dto.setTodayPendingCount(todayPendingCount);
        dto.setTodayPendingCountGrowthRate(todayPendingCountGrowthRate);
        dto.setTodayCompletedCount(todayCompletedCount);
        dto.setTodayCompletedCountGrowthRate(todayCompletedCountGrowthRate);
        return dto;
    }
    /**
     * 通过 SQL SUM 聚合 quality_inspect.quantity,避免把全表加载到内存
     */
    private BigDecimal sumInspectQuantity(String startInclusive, String endExclusive, Integer inspectState) {
        QueryWrapper<QualityInspect> wrapper = new QueryWrapper<>();
        wrapper.select("COALESCE(SUM(quantity), 0) AS total");
        if (startInclusive != null) {
            wrapper.ge("check_time", startInclusive);
        }
        if (endExclusive != null) {
            wrapper.lt("check_time", endExclusive);
        }
        if (inspectState != null) {
            wrapper.eq("inspect_state", inspectState);
        }
        List<Map<String, Object>> rows = qualityInspectMapper.selectMaps(wrapper);
        if (rows == null || rows.isEmpty()) {
            return BigDecimal.ZERO;
        }
        Object total = rows.get(0).get("total");
        if (total == null) {
            return BigDecimal.ZERO;
        }
        return total instanceof BigDecimal ? (BigDecimal) total : new BigDecimal(total.toString());
    }
    private BigDecimal calcGrowthRate(BigDecimal today, BigDecimal prev) {
@@ -1892,14 +1883,14 @@
    public NonComplianceWarningDto nonComplianceWarning() {
        String[] range = lastSevenDaysDateRange();
        String startStr = range[0];
        String endStr = range[1];
        String endExclusiveStr = range[1];
        // 查询近七天已处理不合格数据
        List<QualityUnqualified> list = qualityUnqualifiedMapper.selectList(
                new LambdaQueryWrapper<QualityUnqualified>()
                        .eq(QualityUnqualified::getInspectState, 1)
                        .ge(QualityUnqualified::getCheckTime, startStr)
                        .le(QualityUnqualified::getCheckTime, endStr));
                        .lt(QualityUnqualified::getCheckTime, endExclusiveStr));
        NonComplianceWarningDto dto = new NonComplianceWarningDto();
@@ -1998,24 +1989,24 @@
    }
    /**
     * 获取近七天的日期区间(仅含年月日)
     * 获取近七天的日期区间(仅含年月日):返回 [start, endExclusive] —— endExclusive 是今天 + 1 天,便于使用 lt 包含今天全部
     */
    public static String[] lastSevenDaysDateRange() {
        LocalDate today = LocalDate.now();
        return new String[]{today.minusDays(6).toString(), today.toString()};
        return new String[]{today.minusDays(6).toString(), today.plusDays(1).toString()};
    }
    @Override
    public List<CompletedInspectionCountDto> completedInspectionCount() {
        String[] range = lastSevenDaysDateRange();
        String startStr = range[0];
        String endStr = range[1];
        String endExclusiveStr = range[1];
        // 查询近七天已完成的检验数据
        List<QualityInspect> list = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
                .eq(QualityInspect::getInspectState, 1)
                .ge(QualityInspect::getCheckTime, startStr)
                .le(QualityInspect::getCheckTime, endStr));
                .lt(QualityInspect::getCheckTime, endExclusiveStr));
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM-dd");
@@ -2067,8 +2058,15 @@
    @Override
    public List<UnqualifiedProductRankDto> unqualifiedProductRanking() {
        // 限定近 30 天,避免全表加载
        LocalDate today = LocalDate.now();
        String startStr = today.minusDays(29).toString();
        String endExclusiveStr = today.plusDays(1).toString();
        List<QualityInspect> list = qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
                .eq(QualityInspect::getInspectState, 1));
                .eq(QualityInspect::getInspectState, 1)
                .ge(QualityInspect::getCheckTime, startStr)
                .lt(QualityInspect::getCheckTime, endExclusiveStr));
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
@@ -2219,7 +2217,7 @@
        List<QualityInspect> qualityInspectList = qualityInspectMapper
                .selectList(new LambdaQueryWrapper<QualityInspect>()
                        .ge(QualityInspect::getCheckTime, startDate.toString())
                        .le(QualityInspect::getCheckTime, endDate.toString())
                        .lt(QualityInspect::getCheckTime, endDate.plusDays(1).toString())
                        .eq(QualityInspect::getInspectState, 1));
        QualityStatisticsDto dto = new QualityStatisticsDto();
@@ -2294,15 +2292,15 @@
        // 统计每种检验类型的不合格数量
        item.setSupplierNum(list.stream()
                .filter(i -> i.getInspectType() == 0)
                .filter(i -> Objects.equals(i.getInspectType(), 0))
                .map(i -> i.getUnqualifiedQuantity() != null ? i.getUnqualifiedQuantity() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        item.setProcessNum(list.stream()
                .filter(i -> i.getInspectType() == 1)
                .filter(i -> Objects.equals(i.getInspectType(), 1))
                .map(i -> i.getUnqualifiedQuantity() != null ? i.getUnqualifiedQuantity() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        item.setFactoryNum(list.stream()
                .filter(i -> i.getInspectType() == 2)
                .filter(i -> Objects.equals(i.getInspectType(), 2))
                .map(i -> i.getUnqualifiedQuantity() != null ? i.getUnqualifiedQuantity() : BigDecimal.ZERO)
                .reduce(BigDecimal.ZERO, BigDecimal::add));