src/main/java/com/ruoyi/account/service/impl/AccountExpenseServiceImpl.java
@@ -24,8 +24,10 @@ import java.math.BigDecimal; import java.time.DayOfWeek; import java.time.LocalDate; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; @AllArgsConstructor @Service @@ -115,38 +117,87 @@ @Override public Map<String, List<String>> analysis() { // 获取本周的时间范围 LocalDate startOfWeek = LocalDate.now().with(DayOfWeek.MONDAY); LocalDate endOfWeek = LocalDate.now().with(DayOfWeek.SUNDAY); // 获取最近四个月(当前月 + 前3个月)的时间范围 LocalDate today = LocalDate.now(); DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM"); // 年月格式化器 Map<String, List<String>> result = new HashMap<>(); List<String> days = new ArrayList<>(); List<String> totalIncomeList = new ArrayList<>(); List<String> totalExpenseList = new ArrayList<>(); List<String> netIncomeList = new ArrayList<>(); // 根据时间范围循环查询每一天的总收入,总支出,净收入(总收入-总支出) for (LocalDate date = startOfWeek; date.isBefore(endOfWeek) || date.isEqual(endOfWeek); date = date.plusDays(1)) { BigDecimal totalIncome = accountIncomeMapper.selectList(Wrappers.<AccountIncome>lambdaQuery() .eq(AccountIncome::getInputTime, date.toString())) .stream() .map(AccountIncome::getIncomeMoney) .filter(Objects::nonNull) .reduce(BigDecimal.ZERO, BigDecimal::add); BigDecimal totalExpense = accountExpenseMapper.selectList(Wrappers.<AccountExpense>lambdaQuery() .eq(AccountExpense::getInputTime, date.toString())) .stream() .map(AccountExpense::getExpenseMoney) .filter(Objects::nonNull) .reduce(BigDecimal.ZERO, BigDecimal::add); List<String> months = new ArrayList<>(); // 存储年月(如 2025-12、2025-11) List<String> totalIncomeList = new ArrayList<>(); // 每月总收入 List<String> totalExpenseList = new ArrayList<>(); // 每月总支出 List<String> netIncomeList = new ArrayList<>(); // 每月净收入(收入-支出) // 步骤1:计算近4个月的年月列表(当前月、前1月、前2月、前3月) List<String> targetMonths = new ArrayList<>(); for (int i = 0; i < 4; i++) { LocalDate currentMonth = today.minusMonths(i); String monthStr = currentMonth.format(monthFormatter); targetMonths.add(monthStr); } // 反转列表,确保顺序为「前3月 → 当前月」(可选,按需求调整顺序) Collections.reverse(targetMonths); // 步骤2:一次性查询近4个月所有收入数据,按“年月”分组汇总 LocalDate fourMonthsAgo = today.minusMonths(3).withDayOfMonth(1); // 近4个月起始日(前3月1号) LocalDate currentMonthEnd = today.withDayOfMonth(today.lengthOfMonth()); // 当前月结束日 ZoneId zoneId = ZoneId.of("Asia/Shanghai"); // 查询近4个月所有收入 List<AccountIncome> allIncomes = accountIncomeMapper.selectList( Wrappers.<AccountIncome>lambdaQuery() .ge(AccountIncome::getIncomeDate, fourMonthsAgo.toString()) // 大于等于起始日 .le(AccountIncome::getIncomeDate, currentMonthEnd.toString()) // 小于等于结束日 ); // 收入按“年月”分组汇总(key:年月字符串,value:当月总收入) Map<String, BigDecimal> monthlyIncomeMap = allIncomes.stream() .filter(income -> income.getIncomeMoney() != null) // 过滤空金额 .collect(Collectors.groupingBy( income -> { // 将输入时间(字符串)转换为LocalDate,再格式化为年月 LocalDate inputDate = income.getIncomeDate().toInstant().atZone(zoneId).toLocalDate(); return inputDate.format(monthFormatter); }, Collectors.reducing(BigDecimal.ZERO, AccountIncome::getIncomeMoney, BigDecimal::add) )); // 步骤3:一次性查询近4个月所有支出数据,按“年月”分组汇总 List<AccountExpense> allExpenses = accountExpenseMapper.selectList( Wrappers.<AccountExpense>lambdaQuery() .ge(AccountExpense::getExpenseDate, fourMonthsAgo.toString()) .le(AccountExpense::getExpenseDate, currentMonthEnd.toString()) ); // 支出按“年月”分组汇总 Map<String, BigDecimal> monthlyExpenseMap = allExpenses.stream() .filter(expense -> expense.getExpenseMoney() != null) // 过滤空金额 .collect(Collectors.groupingBy( expense -> { LocalDate inputDate = expense.getExpenseDate().toInstant().atZone(zoneId).toLocalDate(); return inputDate.format(monthFormatter); }, Collectors.reducing(BigDecimal.ZERO, AccountExpense::getExpenseMoney, BigDecimal::add) )); // 步骤4:循环4个目标月份,填充统计数据(无数据时默认为0) for (String month : targetMonths) { // 当月总收入(无数据则为0) BigDecimal totalIncome = monthlyIncomeMap.getOrDefault(month, BigDecimal.ZERO); // 当月总支出(无数据则为0) BigDecimal totalExpense = monthlyExpenseMap.getOrDefault(month, BigDecimal.ZERO); // 当月净收入(收入 - 支出) BigDecimal netIncome = totalIncome.subtract(totalExpense); days.add(date.toString()); // 填充列表 months.add(month); totalIncomeList.add(totalIncome.toString()); totalExpenseList.add(totalExpense.toString()); netIncomeList.add(netIncome.toString()); } result.put("days", days); // 天 result.put("totalIncome", totalIncomeList); // 收入 result.put("totalExpense", totalExpenseList); // 支出 result.put("netIncome", netIncomeList); // 净收入 // 组装结果 result.put("days", months); // 年月(如 ["2025-09", "2025-10", "2025-11", "2025-12"]) result.put("totalIncome", totalIncomeList); // 对应月份总收入 result.put("totalExpense", totalExpenseList); // 对应月份总支出 result.put("netIncome", netIncomeList); // 对应月份净收入 return result; } src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -44,6 +44,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.*; import java.time.format.DateTimeFormatter; import java.time.temporal.TemporalAdjusters; import java.util.*; import java.util.concurrent.atomic.AtomicInteger; @@ -270,50 +271,83 @@ @Override public QualityStatisticsDto qualityStatistics() { // 获取一周数据 // 获取当前时间 // 获取近四个月数据(往前推三个月,共4个完整月份) LocalDate today = LocalDate.now(); // 获取本周周一 LocalDate startOfWeek = today.with(DayOfWeek.MONDAY); // 获取本周周日 LocalDate endOfWeek = today.with(DayOfWeek.SUNDAY); LambdaQueryWrapper<QualityInspect> qualityInspectLambdaQueryWrapper = new LambdaQueryWrapper<>(); qualityInspectLambdaQueryWrapper.ge(QualityInspect::getCheckTime, startOfWeek) .gt(QualityInspect::getCheckTime, endOfWeek); List<QualityInspect> qualityInspects = qualityStatisticsMapper.selectList(qualityInspectLambdaQueryWrapper); // 定义日期格式化器(用于显示“年月”格式) DateTimeFormatter monthFormatter = DateTimeFormatter.ofPattern("yyyy-MM"); QualityStatisticsDto qualityStatisticsDto = new QualityStatisticsDto(); qualityStatisticsDto.setSupplierNum(qualityInspects.stream().filter(item -> item.getInspectType().equals(0)).map(QualityInspect::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add)); qualityStatisticsDto.setProcessNum(qualityInspects.stream().filter(item -> item.getInspectType().equals(1)).map(QualityInspect::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add)); qualityStatisticsDto.setFactoryNum(qualityInspects.stream().filter(item -> item.getInspectType().equals(2)).map(QualityInspect::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add)); List<QualityStatisticsItem> qualityStatisticsItems = new ArrayList<>(); for (int j = 1; j < 8; j++) { LocalDate endTime = startOfWeek.plusDays(j); LocalDate startTime = endTime.minusDays(1); QualityStatisticsItem qualityStatisticsItem = new QualityStatisticsItem(); qualityStatisticsItem.setDate(startTime.toString()); qualityStatisticsItem.setSupplierNum(qualityInspects.stream() .filter(item -> item.getInspectType().equals(0) && "不合格".equals(item.getCheckResult()) && (startTime.isEqual(item.getCheckTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()) || startTime.isAfter(item.getCheckTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate())) && endTime.isBefore(item.getCheckTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate())) BigDecimal supplierNum = new BigDecimal(0); BigDecimal factoryNum = new BigDecimal(0); BigDecimal processNum = new BigDecimal(0); // 循环4次,分别统计近4个月的数据(当前月、前1个月、前2个月、前3个月) for (int i = 3; i >= 0; i--) { // 计算当前循环对应的月份(i=0:当前月,i=1:前1个月,以此类推) LocalDate currentMonth = today.minusMonths(i); // 当月的开始日期(每月1号) LocalDate monthStart = currentMonth.withDayOfMonth(1); // 当月的结束日期(每月最后一天) LocalDate monthEnd = currentMonth.withDayOfMonth(currentMonth.lengthOfMonth()); // 构建当月的查询条件(如果想一次性查全4个月数据再内存筛选,可优化为先查全再循环筛选) LambdaQueryWrapper<QualityInspect> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.ge(QualityInspect::getCheckTime, monthStart) .le(QualityInspect::getCheckTime, monthEnd); // 筛选当月数据 List<QualityInspect> monthInspects = qualityStatisticsMapper.selectList(queryWrapper); BigDecimal reduce = monthInspects.stream() .filter(inspect -> inspect.getInspectType().equals(0)) .map(QualityInspect::getQuantity) .reduce(BigDecimal.ZERO, BigDecimal::add) ); qualityStatisticsItem.setFactoryNum(qualityInspects.stream() .filter(item -> item.getInspectType().equals(1) && "不合格".equals(item.getCheckResult()) && (startTime.isEqual(item.getCheckTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()) || startTime.isAfter(item.getCheckTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate())) && endTime.isBefore(item.getCheckTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate())) .reduce(BigDecimal.ZERO, BigDecimal::add); supplierNum = supplierNum.add(reduce); BigDecimal reduce1 = monthInspects.stream() .filter(inspect -> inspect.getInspectType().equals(1)) .map(QualityInspect::getQuantity) .reduce(BigDecimal.ZERO, BigDecimal::add) ); qualityStatisticsItem.setProcessNum(qualityInspects.stream() .filter(item -> item.getInspectType().equals(2) && "不合格".equals(item.getCheckResult()) && (startTime.isEqual(item.getCheckTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()) || startTime.isAfter(item.getCheckTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate())) && endTime.isBefore(item.getCheckTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate())) .reduce(BigDecimal.ZERO, BigDecimal::add); processNum= processNum.add(reduce1); BigDecimal reduce2 = monthInspects.stream() .filter(inspect -> inspect.getInspectType().equals(2)) .map(QualityInspect::getQuantity) .reduce(BigDecimal.ZERO, BigDecimal::add)); qualityStatisticsItems.add(qualityStatisticsItem); .reduce(BigDecimal.ZERO, BigDecimal::add); factoryNum = factoryNum.add(reduce2); // 构建当月统计项 QualityStatisticsItem item = new QualityStatisticsItem(); item.setDate(monthStart.format(monthFormatter)); // 日期显示为“年月”(如 2025-10) // 1. 供应商检验(类型0)- 合格数量 BigDecimal supplierQualified = monthInspects.stream() .filter(inspect -> inspect.getInspectType().equals(0) && "合格".equals(inspect.getCheckResult())) .map(QualityInspect::getQuantity) .reduce(BigDecimal.ZERO, BigDecimal::add); item.setSupplierNum(supplierQualified); // 2. 工序检验(类型1)- 合格数量 BigDecimal processQualified = monthInspects.stream() .filter(inspect -> inspect.getInspectType().equals(1) && "合格".equals(inspect.getCheckResult())) .map(QualityInspect::getQuantity) .reduce(BigDecimal.ZERO, BigDecimal::add); item.setProcessNum(processQualified); // 3. 工厂检验(类型2)- 合格数量 BigDecimal factoryQualified = monthInspects.stream() .filter(inspect -> inspect.getInspectType().equals(2) && "合格".equals(inspect.getCheckResult())) .map(QualityInspect::getQuantity) .reduce(BigDecimal.ZERO, BigDecimal::add); item.setFactoryNum(factoryQualified); qualityStatisticsItems.add(item); } // 统计近4个月总数据(所有月份汇总) qualityStatisticsDto.setProcessNum(processNum); qualityStatisticsDto.setSupplierNum(supplierNum); qualityStatisticsDto.setFactoryNum(factoryNum); qualityStatisticsDto.setItem(qualityStatisticsItems); return qualityStatisticsDto; } src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java
@@ -467,6 +467,9 @@ if(customStorage.getTimeStr() != null){ customStorageLambdaQueryWrapper.eq(CustomStorage::getInboundDate, customStorage.getTimeStr()); } if(!StringUtils.isEmpty(customStorage.getProductCategory())){ customStorageLambdaQueryWrapper.like(CustomStorage::getProductCategory, customStorage.getProductCategory()); } } customStorageLambdaQueryWrapper.orderByDesc(CustomStorage::getInboundDate); IPage<CustomStorage> procurementPageDtoIPage = customStorageMapper.selectPage(page, customStorageLambdaQueryWrapper); @@ -561,6 +564,9 @@ if(customStorage.getInboundDate() != null){ customStorageLambdaQueryWrapper.eq(CustomStorage::getInboundDate, customStorage.getInboundDate()); } if(!StringUtils.isEmpty(customStorage.getProductCategory())){ customStorageLambdaQueryWrapper.like(CustomStorage::getProductCategory, customStorage.getProductCategory()); } } customStorageLambdaQueryWrapper.orderByDesc(CustomStorage::getInboundDate); IPage<CustomStorage> pageList = customStorageMapper.selectPage(page, customStorageLambdaQueryWrapper); src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml
@@ -57,6 +57,9 @@ <if test="req.supplierName != null and req.supplierName != ''"> and t3.supplier_name like concat('%',#{req.supplierName},'%') </if> <if test="req.productCategory != null and req.productCategory != ''"> and t2.product_category like concat('%',#{req.productCategory},'%') </if> <if test="req.timeStr != null and req.timeStr != ''"> and t1.create_time like concat('%',#{req.timeStr},'%') </if> @@ -142,6 +145,9 @@ t1.type = 1 <if test="req.supplierName != null and req.supplierName != ''"> and t3.supplier_name like concat('%',#{req.supplierName},'%') </if> <if test="req.productCategory != null and req.productCategory != ''"> and t2.product_category like concat('%',#{req.productCategory},'%') </if> <if test="req.timeStr != null and req.timeStr != ''"> and t1.create_time like concat('%',#{req.timeStr},'%') @@ -252,6 +258,9 @@ <if test="req.customerName != null and req.customerName != ''"> and t3.customer_name like concat('%',#{req.customerName},'%') </if> <if test="req.productCategory != null and req.productCategory != ''"> and t2.product_category like concat('%',#{req.productCategory},'%') </if> <if test="req.timeStr != null and req.timeStr != ''"> and t1.create_time like concat('%',#{req.timeStr},'%') </if> @@ -290,6 +299,9 @@ <if test="req.customerName != null and req.customerName != ''"> and t3.customer_name like concat('%',#{req.customerName},'%') </if> <if test="req.productCategory != null and req.productCategory != ''"> and t2.product_category like concat('%',#{req.productCategory},'%') </if> <if test="req.timeStr != null and req.timeStr != ''"> and t1.create_time like concat('%',#{req.timeStr},'%') </if> src/main/resources/mapper/procurementrecord/ProcurementRecordOutMapper.xml
@@ -26,6 +26,9 @@ <if test="req.supplierName != null and req.supplierName != ''"> and t3.supplier_name like concat('%',#{req.supplierName},'%') </if> <if test="req.productCategory != null and req.productCategory != ''"> and t2.product_category like concat('%',#{req.productCategory},'%') </if> <if test="req.timeStr != null and req.timeStr != ''"> and t1.create_time like concat('%',#{req.timeStr},'%') </if> @@ -119,6 +122,9 @@ <if test="req.customerName != null and req.customerName != ''"> and t3.customer_name like concat('%',#{req.customerName},'%') </if> <if test="req.productCategory != null and req.productCategory != ''"> and t2.product_category like concat('%',#{req.productCategory},'%') </if> <if test="req.timeStr != null and req.timeStr != ''"> and t1.create_time like concat('%',#{req.timeStr},'%') </if> @@ -147,6 +153,9 @@ <if test="req.supplierName != null and req.supplierName != ''"> and t2.supplier_name like concat('%',#{req.supplierName},'%') </if> <if test="req.productCategory != null and req.productCategory != ''"> and t2.product_category like concat('%',#{req.productCategory},'%') </if> <if test="req.timeStr != null and req.timeStr != ''"> and t1.create_time like concat('%',#{req.timeStr},'%') </if> src/main/resources/mapper/production/SalesLedgerProductionAccountingMapper.xml
@@ -48,6 +48,6 @@ </if> </where> group by t4.id order by t4.update_time desc order by t4.scheduling_date desc </select> </mapper> src/main/resources/mapper/production/SalesLedgerSchedulingMapper.xml
@@ -115,6 +115,6 @@ AND T2.scheduling_date <= DATE_FORMAT(#{salesLedgerDto.entryDateEnd},'%Y-%m-%d') </if> </where> order by T2.status asc order by T2.scheduling_date desc </select> </mapper> src/main/resources/mapper/production/SalesLedgerWorkMapper.xml
@@ -54,6 +54,6 @@ AND t4.scheduling_date <= DATE_FORMAT(#{salesLedgerDto.entryDateEnd},'%Y-%m-%d') </if> </where> order by t4.update_time desc order by t4.scheduling_date desc </select> </mapper>