已添加4个文件
已修改14个文件
685 ■■■■■ 文件已修改
src/main/java/com/ruoyi/home/annotation/DefaultType.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/aspectj/DefaultTypeAspect.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/controller/HomeController.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/processDataProductionStatisticsDto.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/service/HomeService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java 172 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductionProductMainDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductProcessMapper.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductionProductMainMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionProductMainService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-kthg.yml 248 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductProcessMapper.xml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionProductMainMapper.xml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/annotation/DefaultType.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,22 @@
package com.ruoyi.home.annotation;
import java.lang.annotation.*;
/**
 * <br>
 * ç»Ÿè®¡ç±»åž‹é»˜è®¤å€¼æ³¨è§£
 * é»˜è®¤ type = 1
 * </br>
 *
 * @author deslrey
 * @version 1.0
 * @since 2026/2/5
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DefaultType {
    String value() default "1";
}
src/main/java/com/ruoyi/home/aspectj/DefaultTypeAspect.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
package com.ruoyi.home.aspectj;
import com.ruoyi.home.annotation.DefaultType;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Parameter;
/**
 * <br>
 * ç»Ÿè®¡ç±»åž‹é»˜è®¤å€¼æ³¨è§£åˆ‡é¢
 * </br>
 *
 * @author deslrey
 * @version 1.0
 * @since 2026/2/5
 */
@Aspect
@Component
public class DefaultTypeAspect {
    @Around("execution(* com.ruoyi.home.controller.*.*(.., @com.ruoyi.home.annotation.DefaultType (*), ..))")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object[] args = joinPoint.getArgs();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Parameter[] parameters = signature.getMethod().getParameters();
        for (int i = 0; i < parameters.length; i++) {
            DefaultType annotation = parameters[i].getAnnotation(DefaultType.class);
            if (annotation != null && args[i] == null) {
                args[i] = Integer.parseInt(annotation.value());
            }
        }
        return joinPoint.proceed(args);
    }
}
src/main/java/com/ruoyi/home/controller/HomeController.java
@@ -5,6 +5,7 @@
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.home.annotation.DefaultType;
import com.ruoyi.home.dto.*;
import com.ruoyi.home.service.HomeService;
import com.ruoyi.dto.MapDto;
@@ -72,21 +73,21 @@
    /********************************************************营销采购类**************************************************/
    @GetMapping("/supplierPurchaseRanking")
    @ApiOperation("供应商采购排名")
    public AjaxResult supplierPurchaseRanking(@RequestParam(value = "type", defaultValue = "1") Integer type) {
    public AjaxResult supplierPurchaseRanking(@DefaultType Integer type) {
        List<SupplierPurchaseRankingDto> list = homeService.supplierPurchaseRanking(type);
        return AjaxResult.success(list);
    }
    @GetMapping("/customerRevenueAnalysis")
    @ApiOperation("客户营收贡献数值分析")
    public AjaxResult customerRevenueAnalysis(@RequestParam("customerId") Long customerId, @RequestParam(value = "type", defaultValue = "1") Integer type) {
    public AjaxResult customerRevenueAnalysis(Long customerId, @DefaultType Integer type) {
        CustomerRevenueAnalysisDto dto = homeService.customerRevenueAnalysis(customerId, type);
        return AjaxResult.success(dto);
    }
    @GetMapping("/customerContributionRanking")
    @ApiOperation("客户金额贡献排名")
    public AjaxResult customerContributionRanking(@RequestParam(value = "type", defaultValue = "1") Integer type) {
    public AjaxResult customerContributionRanking(@DefaultType Integer type) {
        List<CustomerContributionRankingDto> list = homeService.customerContributionRanking(type);
        return AjaxResult.success(list);
    }
@@ -124,28 +125,28 @@
    /********************************************************生产类*****************************************************/
    @GetMapping("/inputOutputAnalysis")
    @ApiOperation("投入产出分析")
    public AjaxResult inputOutputAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
    public AjaxResult inputOutputAnalysis(@DefaultType Integer type){
      List<InputOutputAnalysisDto> list = homeService.inputOutputAnalysis(type);
        return AjaxResult.success(list);
    }
    @GetMapping("/processOutputAnalysis")
    @ApiOperation("工序产出分析")
    public AjaxResult processOutputAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
    public AjaxResult processOutputAnalysis(@DefaultType Integer type){
        List<MapDto> list = homeService.processOutputAnalysis(type);
        return AjaxResult.success(list);
    }
    @GetMapping("/workOrderEfficiencyAnalysis")
    @ApiOperation("工单执行效率分析")
    public AjaxResult workOrderEfficiencyAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
    public AjaxResult workOrderEfficiencyAnalysis(@DefaultType Integer type){
        List<WorkOrderEfficiencyDto> list = homeService.workOrderEfficiencyAnalysis(type);
        return AjaxResult.success(list);
    }
    @GetMapping("/productionAccountingAnalysis")
    @ApiOperation("生产核算分析")
    public AjaxResult productionAccountingAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
    public AjaxResult productionAccountingAnalysis(@DefaultType Integer type){
        List<ProductionAccountingDto> list   = homeService.productionAccountingAnalysis(type);
        return AjaxResult.success(list);
    }
@@ -170,22 +171,29 @@
        return AjaxResult.success(productionTurnoverDto);
    }
    @GetMapping("/processDataProductionStatistics")
    @ApiOperation("工序数据生产统计数据")
    public AjaxResult processDataProductionStatistics(@DefaultType Integer type,@RequestParam(required = false) List<Long> processIds) {
        List<processDataProductionStatisticsDto> list = homeService.processDataProductionStatistics(type, processIds);
        return AjaxResult.success(list);
    }
    /********************************************************质量类*****************************************************/
    @GetMapping("/rawMaterialDetection")
    @ApiOperation("原材料检测")
    public AjaxResult rawMaterialDetection(@RequestParam(value = "type", defaultValue = "1") Integer type){
    public AjaxResult rawMaterialDetection(@DefaultType Integer type){
        return AjaxResult.success(homeService.rawMaterialDetection(type));
    }
    @GetMapping("/processDetection")
    @ApiOperation("过程检测")
    public AjaxResult processDetection(@RequestParam(value = "type", defaultValue = "1") Integer type){
    public AjaxResult processDetection(@DefaultType Integer type){
        return AjaxResult.success(homeService.processDetection(type));
    }
    @GetMapping("/factoryDetection")
    @ApiOperation("成品出厂检测")
    public AjaxResult factoryDetection(@RequestParam(value = "type", defaultValue = "1") Integer type){
    public AjaxResult factoryDetection(@DefaultType Integer type){
        return AjaxResult.success(homeService.factoryDetection(type));
    }
@@ -232,10 +240,17 @@
        return AjaxResult.success(qualityStatisticsDto);
    }
    @GetMapping("/qualityInspectionStatistics")
    @ApiOperation("质量统计")
    public AjaxResult qualityInspectionStatistics(@DefaultType Integer type) {
       QualityStatisticsDto  dto = homeService.qualityInspectionStatistics(type);
        return AjaxResult.success(dto);
    }
    /********************************************************财务类*****************************************************/
    @GetMapping("/incomeExpenseAnalysis")
    @ApiOperation("支收对比分析")
    public AjaxResult incomeExpenseAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type) {
    public AjaxResult incomeExpenseAnalysis(@DefaultType Integer type) {
        List<Map<String, Object>> result = homeService.incomeExpenseAnalysis(type);
        return AjaxResult.success(result);
    }
@@ -249,7 +264,7 @@
    @GetMapping("/expenseCompositionAnalysis")
    @ApiOperation("构成分析")
    public AjaxResult expenseCompositionAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type) {
    public AjaxResult expenseCompositionAnalysis(@DefaultType Integer type) {
        List<MapDto> list = homeService.expenseCompositionAnalysis(type);
        return AjaxResult.success(list);
    }
@@ -271,7 +286,7 @@
    @GetMapping("/statisticsReceivablePayable")
    @Log(title = "应收应付统计", businessType = BusinessType.OTHER)
    @ApiOperation("应收应付统计")
    public AjaxResult statisticsReceivablePayable(StatisticsReceivablePayableDto req, @RequestParam(value = "type", defaultValue = "1") Integer type ) {
    public AjaxResult statisticsReceivablePayable(StatisticsReceivablePayableDto req, @DefaultType Integer type ) {
        StatisticsReceivablePayableDto statisticsReceivablePayable = homeService.statisticsReceivablePayable(type);
        return AjaxResult.success(statisticsReceivablePayable);
    }
@@ -294,7 +309,7 @@
    @GetMapping("/productInOutAnalysis")
    @ApiOperation("产品出入库分析")
    public AjaxResult productInOutAnalysis(@RequestParam(value = "type", defaultValue = "1") Integer type){
    public AjaxResult productInOutAnalysis(@DefaultType Integer type){
        List<Map<String, Object>> result = homeService.productInOutAnalysis(type);
        return AjaxResult.success(result);
    }
src/main/java/com/ruoyi/home/dto/processDataProductionStatisticsDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,40 @@
package com.ruoyi.home.dto;
import lombok.Data;
import java.math.BigDecimal;
/**
 * <br>
 * å·¥åºæ•°æ®ç”Ÿäº§ç»Ÿè®¡æ˜Žç»†Dto
 * </br>
 *
 * @author deslrey
 * @version 1.0
 * @since 2026/2/5
 */
@Data
public class processDataProductionStatisticsDto {
    /**
     * å·¥åºåç§°
     */
    private String processName;
    /**
     * ç´¯è®¡æ€»æŠ•å…¥
     */
    private BigDecimal totalInput;
    /**
     * ç´¯åŠ æ€»æŠ¥åºŸ
     */
    private BigDecimal totalScrap;
    /**
     * ç´¯åŠ æ€»äº§å‡º
     */
    private BigDecimal totalOutput;
}
src/main/java/com/ruoyi/home/service/HomeService.java
@@ -91,4 +91,8 @@
    List<UnqualifiedProductRankDto> unqualifiedProductRanking();
    List<MapDto> unqualifiedProductProcessingAnalysis();
    QualityStatisticsDto qualityInspectionStatistics(Integer type);
    List<processDataProductionStatisticsDto> processDataProductionStatistics(Integer type, List<Long> processIds);
}
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -33,17 +33,15 @@
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.dto.ProductWorkOrderDto;
import com.ruoyi.production.mapper.ProductOrderMapper;
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.mapper.SalesLedgerProductionAccountingMapper;
import com.ruoyi.production.pojo.ProductProcess;
import com.ruoyi.production.pojo.ProductWorkOrder;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.domain.SysUserDept;
import com.ruoyi.project.system.mapper.SysDeptMapper;
import com.ruoyi.project.system.mapper.SysUserDeptMapper;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.purchase.mapper.PaymentRegistrationMapper;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PaymentRegistration;
@@ -143,6 +141,9 @@
    @Autowired
    private QualityUnqualifiedMapper qualityUnqualifiedMapper;
    @Autowired
    private ProductProcessMapper productProcessMapper;
    @Override
    public HomeBusinessDto business() {
@@ -463,8 +464,8 @@
        }
        // åº”æ”¶
        List<SalesLedger> salesLedgers = salesLedgerMapper.selectList(new LambdaQueryWrapper<SalesLedger>()
                // .ge(SalesLedger::getEntryDate, startDate)
                // .lt(SalesLedger::getEntryDate, endDate)
        // .ge(SalesLedger::getEntryDate, startDate)
        // .lt(SalesLedger::getEntryDate, endDate)
        );
        // BigDecimal receivableMoney =
        // salesLedgers.stream().map(SalesLedger::getContractAmount).reduce(BigDecimal.ZERO,
@@ -473,8 +474,8 @@
        // åº”付
        List<PurchaseLedger> procurementRecords = purchaseLedgerMapper
                .selectList(new LambdaQueryWrapper<PurchaseLedger>()
                        // .ge(PurchaseLedger::getEntryDate, startDate)
                        // .lt(PurchaseLedger::getEntryDate, endDate)
                // .ge(PurchaseLedger::getEntryDate, startDate)
                // .lt(PurchaseLedger::getEntryDate, endDate)
                );
        // BigDecimal payableMoney =
        // procurementRecords.stream().map(PurchaseLedger::getContractAmount).reduce(BigDecimal.ZERO,
@@ -482,8 +483,8 @@
        BigDecimal payableMoney = sumAmount(procurementRecords, PurchaseLedger::getContractAmount);
        // é¢„æ”¶
        List<ReceiptPayment> receiptPayments = receiptPaymentMapper.selectList(new LambdaQueryWrapper<ReceiptPayment>()
                // .ge(ReceiptPayment::getReceiptPaymentDate, startDate)
                // .lt(ReceiptPayment::getReceiptPaymentDate, endDate)
        // .ge(ReceiptPayment::getReceiptPaymentDate, startDate)
        // .lt(ReceiptPayment::getReceiptPaymentDate, endDate)
        );
        // BigDecimal advanceMoney =
        // receiptPayments.stream().map(ReceiptPayment::getReceiptPaymentAmount).reduce(BigDecimal.ZERO,
@@ -492,8 +493,8 @@
        // é¢„付
        List<PaymentRegistration> paymentRegistrations = paymentRegistrationMapper
                .selectList(new LambdaQueryWrapper<PaymentRegistration>()
                        // .ge(PaymentRegistration::getPaymentDate, startDate)
                        // .lt(PaymentRegistration::getPaymentDate, endDate)
                // .ge(PaymentRegistration::getPaymentDate, startDate)
                // .lt(PaymentRegistration::getPaymentDate, endDate)
                );
        // BigDecimal prepayMoney =
        // paymentRegistrations.stream().map(PaymentRegistration::getCurrentPaymentAmount).reduce(BigDecimal.ZERO,
@@ -557,7 +558,7 @@
        productionProgressDto.setCompletedOrderDetails(productOrderDtos);
        long totalCount = productOrderDtos.size();
        long count = productOrderDtos.stream().filter(
                        productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(productOrderDto.getQuantity()) >= 0)
                productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(productOrderDto.getQuantity()) >= 0)
                .count();
        long count2 = productOrderDtos.stream()
                .filter(productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(BigDecimal.ZERO) == 0)
@@ -1729,7 +1730,8 @@
                    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);
                    dto.setFinishQuantity(
                            dto.getFinishQuantity() != null ? dto.getFinishQuantity().add(finishQty) : finishQty);
                }
            }
@@ -1893,7 +1895,6 @@
        return dto;
    }
    @Override
    public QualityQualifiedAnalysisDto rawMaterialDetection(Integer type) {
        return commonDetection(type, 0);
@@ -1956,7 +1957,7 @@
                endDate = today.with(DayOfWeek.SUNDAY);
        }
        return new LocalDate[]{startDate, endDate};
        return new LocalDate[] { startDate, endDate };
    }
    private QualityQualifiedAnalysisDto buildQualifiedAnalysis(List<QualityInspect> list) {
@@ -2218,7 +2219,7 @@
        LocalDateTime startTime = today.minusDays(6).atStartOfDay();
        LocalDateTime endTime = today.atTime(23, 59, 59);
        return new LocalDateTime[]{startTime, endTime};
        return new LocalDateTime[] { startTime, endTime };
    }
    @Override
@@ -2353,7 +2354,7 @@
            return new ArrayList<>();
        }
        //  ç»Ÿè®¡æ¯ç§å¤„理结果的数量
        // ç»Ÿè®¡æ¯ç§å¤„理结果的数量
        Map<String, BigDecimal> countMap = new HashMap<>();
        for (QualityUnqualified item : list) {
            if (StringUtils.isEmpty(item.getDealResult()) || item.getQuantity() == null) {
@@ -2366,7 +2367,7 @@
            return new ArrayList<>();
        }
        //  è®¡ç®—总数
        // è®¡ç®—总数
        BigDecimal totalCount = countMap.values()
                .stream()
                .reduce(BigDecimal.ZERO, BigDecimal::add);
@@ -2375,7 +2376,7 @@
            return new ArrayList<>();
        }
        //  æŒ‰æ•°é‡å€’序排序
        // æŒ‰æ•°é‡å€’序排序
        List<Map.Entry<String, BigDecimal>> sortedList = countMap.entrySet()
                .stream()
                .sorted((a, b) -> b.getValue().compareTo(a.getValue()))
@@ -2411,4 +2412,135 @@
        return result;
    }
    @Override
    public QualityStatisticsDto qualityInspectionStatistics(Integer type) {
        LocalDate today = LocalDate.now();
        LocalDate startDate;
        LocalDate endDate;
        switch (type) {
            case 1: // æœ¬å‘¨
                startDate = today.with(DayOfWeek.MONDAY);
                endDate = today.with(DayOfWeek.SUNDAY);
                break;
            case 2: // æœ¬æœˆ
                startDate = today.with(TemporalAdjusters.firstDayOfMonth());
                endDate = today.with(TemporalAdjusters.lastDayOfMonth());
                break;
            case 3: // æœ¬å­£åº¦
                int currentMonth = today.getMonthValue();
                int startMonth = ((currentMonth - 1) / 3) * 3 + 1;
                startDate = LocalDate.of(today.getYear(), startMonth, 1);
                endDate = startDate.plusMonths(2).with(TemporalAdjusters.lastDayOfMonth());
                break;
            default:
                startDate = today.with(DayOfWeek.MONDAY);
                endDate = today.with(DayOfWeek.SUNDAY);
        }
        List<QualityInspect> qualityInspectList = qualityInspectMapper
                .selectList(new LambdaQueryWrapper<QualityInspect>()
                        .ge(QualityInspect::getCheckTime, startDate)
                        .le(QualityInspect::getCheckTime, endDate)
                        .eq(QualityInspect::getInspectState, 1));
        QualityStatisticsDto dto = new QualityStatisticsDto();
        dto.setSupplierNum(sumQuantity(qualityInspectList, 0)); // åŽŸææ–™
        dto.setProcessNum(sumQuantity(qualityInspectList, 1)); // è¿‡ç¨‹
        dto.setFactoryNum(sumQuantity(qualityInspectList, 2)); // å‡ºåŽ‚
        // 4. å¤„理图表项 (Item)
        List<QualityStatisticsItem> itemList = new ArrayList<>();
        Map<QualityInspect, LocalDate> dateMap = qualityInspectList.stream()
                .collect(Collectors.toMap(
                        i -> i,
                        i -> i.getCheckTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDate()));
        if (type == 3) {
            // å­£åº¦æ¨¡å¼ï¼šæŒ‰æœˆåˆ†ç»„
            Map<String, List<QualityInspect>> groupByMonth = qualityInspectList.stream()
                    .collect(Collectors.groupingBy(i -> {
                        LocalDate ld = dateMap.get(i);
                        return ld.format(DateTimeFormatter.ofPattern("yyyy-MM"));
                    }));
            for (int i = 0; i < 3; i++) {
                LocalDate monthDate = startDate.plusMonths(i);
                String monthStr = monthDate.format(DateTimeFormatter.ofPattern("yyyy-MM"));
                itemList.add(buildItem(monthStr, groupByMonth.getOrDefault(monthStr, new ArrayList<>())));
            }
        } else {
            // å‘¨æˆ–月模式:按天分组
            Map<String, List<QualityInspect>> groupByDay = qualityInspectList.stream()
                    .collect(Collectors.groupingBy(i -> {
                        LocalDate ld = dateMap.get(i);
                        return ld.format(DateTimeFormatter.ofPattern("MM/dd"));
                    }));
            long days = ChronoUnit.DAYS.between(startDate, endDate);
            for (int i = 0; i <= days; i++) {
                LocalDate tempDay = startDate.plusDays(i);
                String dayStr = tempDay.format(DateTimeFormatter.ofPattern("MM/dd"));
                itemList.add(buildItem(dayStr, groupByDay.getOrDefault(dayStr, new ArrayList<>())));
            }
        }
        dto.setItem(itemList);
        return dto;
    }
    private BigDecimal sumQuantity(List<QualityInspect> list, Integer type) {
        return list.stream()
                .filter(i -> i.getInspectType().equals(type))
                .map(QualityInspect::getQuantity)
                .filter(Objects::nonNull)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    private QualityStatisticsItem buildItem(String dateLabel, List<QualityInspect> list) {
        QualityStatisticsItem item = new QualityStatisticsItem();
        item.setDate(dateLabel);
        item.setSupplierNum(list.stream().filter(i -> i.getInspectType() == 0).map(QualityInspect::getQuantity)
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        item.setProcessNum(list.stream().filter(i -> i.getInspectType() == 1).map(QualityInspect::getQuantity)
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        item.setFactoryNum(list.stream().filter(i -> i.getInspectType() == 2).map(QualityInspect::getQuantity)
                .reduce(BigDecimal.ZERO, BigDecimal::add));
        return item;
    }
    @Override
    public List<processDataProductionStatisticsDto> processDataProductionStatistics(Integer type,
            List<Long> processIds) {
        LoginUser loginUser = SecurityUtils.getLoginUser();
        Long userId = SecurityUtils.isAdmin(loginUser.getUserId()) ? null : loginUser.getUserId();
        LocalDate today = LocalDate.now();
        LocalDate startDate;
        LocalDate endDate;
        switch (type) {
            case 1:
                startDate = today;
                endDate = today;
                break;
            case 2:
                startDate = today.with(DayOfWeek.MONDAY);
                endDate = today.with(DayOfWeek.SUNDAY);
                break;
            case 3:
                startDate = today.with(TemporalAdjusters.firstDayOfMonth());
                endDate = today.with(TemporalAdjusters.lastDayOfMonth());
                break;
            default:
                startDate = today;
                endDate = today;
        }
        LocalDateTime startDateTime = startDate.atStartOfDay();
        LocalDateTime endDateTime = endDate.atTime(LocalTime.MAX);
        return productProcessMapper.calculateProductionStatistics(startDateTime, endDateTime, userId, processIds);
    }
}
src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java
@@ -3,9 +3,7 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProductProcessRouteItemDto;
import com.ruoyi.production.dto.ProductionProductMainDto;
import com.ruoyi.production.dto.SalesLedgerProductionAccountingDto;
import com.ruoyi.production.service.ProductionProductMainService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -14,7 +12,6 @@
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.List;
@RequestMapping("productionProductMain")
@@ -54,7 +51,6 @@
        return R.ok(productionProductMainService.removeProductMain(productionProductMainDto.getId()));
    }
    /**
     * å¯¼å‡º
     */
@@ -65,4 +61,9 @@
        ExcelUtil<ProductionProductMainDto> util = new ExcelUtil<ProductionProductMainDto>(ProductionProductMainDto.class);
        util.exportExcel(response, list, "生产报工数据");
    }
    @GetMapping("/queryProductInputAndOutput")
    public R queryProductInputAndOutput(Page page, ProductionProductMainDto productionProductMainDto) {
        return R.ok(productionProductMainService.queryProductInputAndOutput(page, productionProductMainDto));
    }
}
src/main/java/com/ruoyi/production/dto/ProductionProductMainDto.java
@@ -10,7 +10,6 @@
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
@ExcelIgnoreUnannotated
@@ -59,5 +58,6 @@
    private BigDecimal workHours;
    private BigDecimal wages;
    private String startTime;
    private String endTime;
}
src/main/java/com/ruoyi/production/mapper/ProductProcessMapper.java
@@ -3,12 +3,18 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.home.dto.processDataProductionStatisticsDto;
import com.ruoyi.production.dto.ProductProcessDto;
import com.ruoyi.production.pojo.ProductProcess;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.List;
@Mapper
public interface ProductProcessMapper extends BaseMapper<ProductProcess> {
    IPage<ProductProcessDto> listPage(Page page,@Param("productProcessDto") ProductProcessDto productProcessDto);
    List<processDataProductionStatisticsDto> calculateProductionStatistics(LocalDateTime startDateTime, LocalDateTime endDateTime, Long userId, List<Long> processIds);
}
src/main/java/com/ruoyi/production/mapper/ProductionProductMainMapper.java
@@ -11,6 +11,7 @@
import org.apache.ibatis.annotations.Param;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@Mapper
@@ -33,4 +34,6 @@
    IPage<ProductionProductMainDto> listProductionDetails(@Param("ew") SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto, Page page);
    ArrayList<Long> listMain(List<Long> idList);
    IPage<HashMap<String, Object>> queryProductInputAndOutput(Page page, @Param("ew") ProductionProductMainDto productionProductMainDto);
}
src/main/java/com/ruoyi/production/service/ProductionProductMainService.java
@@ -7,6 +7,7 @@
import com.ruoyi.production.pojo.ProductionProductMain;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public interface ProductionProductMainService extends IService<ProductionProductMain> {
@@ -17,4 +18,12 @@
    Boolean removeProductMain(Long id);
    ArrayList<Long> listMain(List<Long> idList);
    /**
     * æŒ‰å¤©æŸ¥è¯¢äº§å“çš„æŠ•入和产出
     * @param page
     * @param productionProductMainDto
     * @return
     */
    IPage<HashMap<String, Object>> queryProductInputAndOutput(Page page, ProductionProductMainDto productionProductMainDto);
}
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -37,6 +37,7 @@
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -207,7 +208,7 @@
                }
            }else {
                //直接入库
                stockUtils.addStock(productProcessRouteItem.getProductModelId(), productionProductOutput.getQuantity(), StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId());
                stockUtils.addStock(productProcessRouteItem.getProductModelId(), productQty, StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId());
            }
            /*更新工单和生产订单*/
            ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId());
@@ -288,11 +289,17 @@
            ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId());
            if (productOrder != null) {
                BigDecimal orderCompleteQty = productOrder.getCompleteQuantity() == null ? BigDecimal.ZERO : productOrder.getCompleteQuantity();
                BigDecimal outputQty = productionProductOutput.getQuantity() != null
                        ? productionProductOutput.getQuantity() : BigDecimal.ZERO;
                BigDecimal totalQty = productionProductOutput.getQuantity() != null ? productionProductOutput.getQuantity() : BigDecimal.ZERO;
                BigDecimal scrapQty = productionProductOutput.getScrapQty() != null ? productionProductOutput.getScrapQty() : BigDecimal.ZERO;
                productOrder.setCompleteQuantity(orderCompleteQty.subtract(outputQty));
                BigDecimal actualQualifiedQty = totalQty.subtract(scrapQty);
                BigDecimal newCompleteQty = orderCompleteQty.subtract(actualQualifiedQty);
                productOrder.setCompleteQuantity(newCompleteQty.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : newCompleteQty);
                productOrder.setEndTime(null);
                productOrderMapper.updateById(productOrder);
            } else {
                throw new ServiceException("关联的生产订单不存在");
@@ -331,4 +338,9 @@
    public ArrayList<Long> listMain(List<Long> idList) {
        return productionProductMainMapper.listMain(idList);
    }
    @Override
    public IPage<HashMap<String, Object>> queryProductInputAndOutput(Page page, ProductionProductMainDto productionProductMainDto) {
        return productionProductMainMapper.queryProductInputAndOutput(page, productionProductMainDto);
    }
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -445,7 +445,7 @@
        IPage<SalesLedgerProductDto> salesLedgerProductDtoIPage = salesLedgerProductMapper.listPagePurchaseLedger(page, salesLedgerProduct);
        salesLedgerProductDtoIPage.getRecords().forEach(item -> {
            // åˆ¤æ–­çŠ¶æ€
            if(item.getTaxInclusiveTotalPrice().compareTo(item.getInvoiceTotal()) == 0){
            if(item.getTaxInclusiveTotalPrice().compareTo(item.getTicketsTotal()) == 0){
                item.setStatusName("已完成付款");
            }else{
                item.setStatusName("未完成付款");
src/main/resources/application-kthg.yml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,248 @@
# é¡¹ç›®ç›¸å…³é…ç½®
ruoyi:
  # åç§°
  name: RuoYi
  # ç‰ˆæœ¬
  version: 3.8.9
  # ç‰ˆæƒå¹´ä»½
  copyrightYear: 2025
  # æ–‡ä»¶è·¯å¾„ ç¤ºä¾‹ï¼ˆ Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
  profile: D:/ruoyi/uploadPath
  # èŽ·å–ip地址开关
  addressEnabled: false
  # éªŒè¯ç ç±»åž‹ math æ•°å­—计算 char å­—符验证
  captchaType: math
  # ååŒå®¡æ‰¹ç¼–号前缀(配置文件后缀命名)
  approvalNumberPrefix: NEW
# å¼€å‘环境配置
server:
  # æœåŠ¡å™¨çš„HTTP端口,默认为8080
  port: 8888
  servlet:
    # åº”用的访问路径
    context-path: /
  tomcat:
    # tomcat的URI编码
    uri-encoding: UTF-8
    # è¿žæŽ¥æ•°æ»¡åŽçš„æŽ’队数,默认为100
    accept-count: 1000
    threads:
      # tomcat最大线程数,默认为200
      max: 800
      # Tomcat启动初始化的线程数,默认值10
      min-spare: 100
# æ—¥å¿—配置
logging:
  level:
    org.quartz: DEBUG
    com.ruoyi: warn
    org.springframework: warn
minio:
  endpoint: http://114.132.189.42/
  port: 7019
  secure: false
  accessKey: admin
  secretKey: 12345678
  preview-expiry: 24 # é¢„览地址默认24小时
  default-bucket: uploadPath
# ç”¨æˆ·é…ç½®
user:
  password:
    # å¯†ç æœ€å¤§é”™è¯¯æ¬¡æ•°
    maxRetryCount: 5
    # å¯†ç é”å®šæ—¶é—´ï¼ˆé»˜è®¤10分钟)
    lockTime: 10
# Spring配置
spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    druid:
      # ä¸»åº“数据源
      master:
#        url: jdbc:mysql://localhost:3306/product-inventory-management-new?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        url: jdbc:mysql://1.15.17.182:9999/product-inventory-management-kthg?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
        username: root
        password: xd@123456..
      # ä»Žåº“数据源
      slave:
        # ä»Žæ•°æ®æºå¼€å…³/默认关闭
        enabled: false
        url:
        username:
        password:
      # åˆå§‹è¿žæŽ¥æ•°
      initialSize: 5
      # æœ€å°è¿žæŽ¥æ± æ•°é‡
      minIdle: 10
      # æœ€å¤§è¿žæŽ¥æ± æ•°é‡
      maxActive: 20
      # é…ç½®èŽ·å–è¿žæŽ¥ç­‰å¾…è¶…æ—¶çš„æ—¶é—´
      maxWait: 60000
      # é…ç½®è¿žæŽ¥è¶…æ—¶æ—¶é—´
      connectTimeout: 30000
      # é…ç½®ç½‘络超时时间
      socketTimeout: 60000
      # é…ç½®é—´éš”多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # é…ç½®ä¸€ä¸ªè¿žæŽ¥åœ¨æ± ä¸­æœ€å°ç”Ÿå­˜çš„æ—¶é—´ï¼Œå•位是毫秒
      minEvictableIdleTimeMillis: 300000
      # é…ç½®ä¸€ä¸ªè¿žæŽ¥åœ¨æ± ä¸­æœ€å¤§ç”Ÿå­˜çš„æ—¶é—´ï¼Œå•位是毫秒
      maxEvictableIdleTimeMillis: 900000
      # é…ç½®æ£€æµ‹è¿žæŽ¥æ˜¯å¦æœ‰æ•ˆ
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false
      webStatFilter:
        enabled: true
      statViewServlet:
        enabled: true
        # è®¾ç½®ç™½åå•,不填则允许所有访问
        allow:
        url-pattern: /druid/*
        # æŽ§åˆ¶å°ç®¡ç†ç”¨æˆ·åå’Œå¯†ç 
        login-username: ruoyi
        login-password: 123456
      filter:
        stat:
          enabled: true
          # æ…¢SQL记录
          log-slow-sql: true
          slow-sql-millis: 1000
          merge-sql: true
        wall:
          config:
            multi-statement-allow: true
  # èµ„源信息
  messages:
    # å›½é™…化资源文件路径
    basename: i18n/messages
  # æ–‡ä»¶ä¸Šä¼ 
  servlet:
    multipart:
      # å•个文件大小
      max-file-size: 1GB
      # è®¾ç½®æ€»ä¸Šä¼ çš„æ–‡ä»¶å¤§å°
      max-request-size: 2GB
  # æœåŠ¡æ¨¡å—
  devtools:
    restart:
      # çƒ­éƒ¨ç½²å¼€å…³
      enabled: false
  # redis é…ç½®
  redis:
    # åœ°å€
    host: 127.0.0.1
    #    host: 172.17.0.1
    # ç«¯å£ï¼Œé»˜è®¤ä¸º6379
    port: 6379
    # æ•°æ®åº“索引
    database: 0
    # å¯†ç 
    #    password: root2022!
    password:
    # è¿žæŽ¥è¶…æ—¶æ—¶é—´
    timeout: 10s
    lettuce:
      pool:
        # è¿žæŽ¥æ± ä¸­çš„æœ€å°ç©ºé—²è¿žæŽ¥
        min-idle: 0
        # è¿žæŽ¥æ± ä¸­çš„æœ€å¤§ç©ºé—²è¿žæŽ¥
        max-idle: 8
        # è¿žæŽ¥æ± çš„æœ€å¤§æ•°æ®åº“连接数
        max-active: 8
        # #连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: -1ms
  # Quartz定时任务配置(新增部分)
  quartz:
    job-store-type: jdbc  # ä½¿ç”¨æ•°æ®åº“存储
    jdbc:
      initialize-schema: never  # é¦–次运行时自动创建表结构,成功后改为never
      schema: classpath:org/quartz/impl/jdbcjobstore/tables_mysql_innodb.sql  # MySQL表结构脚本
    properties:
      org:
        quartz:
          scheduler:
            instanceName: RuoYiScheduler
            instanceId: AUTO
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate  # MySQL适配
            tablePrefix: qrtz_  # è¡¨åå‰ç¼€ï¼Œä¸Žè„šæœ¬ä¸€è‡´
            isClustered: false  # å•节点模式(集群需改为true)
            clusterCheckinInterval: 10000
            txIsolationLevelSerializable: true
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 10  # çº¿ç¨‹æ± å¤§å°
            threadPriority: 5
            makeThreadsDaemons: true
          updateCheck: false  # å…³é—­ç‰ˆæœ¬æ£€æŸ¥
# token配置
token:
  # ä»¤ç‰Œè‡ªå®šä¹‰æ ‡è¯†
  header: Authorization
  # ä»¤ç‰Œå¯†é’¥
  secret: abcdefghijklmnopqrstuvwxyz
  # ä»¤ç‰Œæœ‰æ•ˆæœŸï¼ˆé»˜è®¤30分钟)
  expireTime: 450
# MyBatis Plus配置
mybatis-plus:
  # æœç´¢æŒ‡å®šåŒ…别名   æ ¹æ®è‡ªå·±çš„项目来
  typeAliasesPackage: com.ruoyi.**.pojo
  # é…ç½®mapper的扫描,找到所有的mapper.xml映射文件
  mapperLocations: classpath*:mapper/**/*Mapper.xml
  # åŠ è½½å…¨å±€çš„é…ç½®æ–‡ä»¶
  configLocation: classpath:mybatis/mybatis-config.xml
  global-config:
    enable-sql-runner: true
    db-config:
      id-type: auto
# PageHelper分页插件
pagehelper:
  helperDialect: mysql
  supportMethodsArguments: true
  params: count=countSql
# Swagger配置
swagger:
  # æ˜¯å¦å¼€å¯swagger
  enabled: true
  # è¯·æ±‚前缀
  pathMapping: /dev-api
# é˜²æ­¢XSS攻击
xss:
  # è¿‡æ»¤å¼€å…³
  enabled: true
  # æŽ’除链接(多个用逗号分隔)
  excludes: /system/notice
  # åŒ¹é…é“¾æŽ¥
  urlPatterns: /system/*,/monitor/*,/tool/*
# ä»£ç ç”Ÿæˆ
gen:
  # ä½œè€…
  author: ruoyi
  # é»˜è®¤ç”ŸæˆåŒ…路径 system éœ€æ”¹æˆè‡ªå·±çš„æ¨¡å—名称 å¦‚ system monitor tool
  packageName: com.ruoyi.project.system
  # è‡ªåŠ¨åŽ»é™¤è¡¨å‰ç¼€ï¼Œé»˜è®¤æ˜¯true
  autoRemovePre: false
  # è¡¨å‰ç¼€ï¼ˆç”Ÿæˆç±»åä¸ä¼šåŒ…含表前缀,多个用逗号分隔)
  tablePrefix: sys_
  # æ˜¯å¦å…è®¸ç”Ÿæˆæ–‡ä»¶è¦†ç›–到本地(自定义路径),默认不允许
  allowOverwrite: false
file:
  temp-dir: D:/ruoyi/temp/uploads   # ä¸´æ—¶ç›®å½•
  upload-dir: D:/ruoyi/prod/uploads # æ­£å¼ç›®å½•
src/main/resources/application.yml
@@ -1,4 +1,4 @@
# Spring配置
spring:
  profiles:
    active: dev
    active: kthg
src/main/resources/mapper/production/ProductProcessMapper.xml
@@ -17,4 +17,37 @@
        </where>
        order by p.id asc
    </select>
    <select id="calculateProductionStatistics" resultType="com.ruoyi.home.dto.processDataProductionStatisticsDto">
        SELECT
        pp.name AS processName,
        SUM((ppo.quantity + ppo.scrap_qty) * pp.salary_quota) AS totalInput,
        SUM(ppo.scrap_qty * pp.salary_quota) AS totalScrap,
        SUM(ppo.quantity * pp.salary_quota) AS totalOutput
        FROM
        production_product_output ppo
        INNER JOIN production_product_main ppm ON ppo.product_main_id = ppm.id
        INNER JOIN product_process_route_item ppri ON ppm.product_process_route_item_id = ppri.id
        INNER JOIN product_process pp ON ppri.process_id = pp.id
        <where>
            <if test="startDateTime != null">
                AND ppo.create_time &gt;= #{startDateTime}
            </if>
            <if test="endDateTime != null">
                AND ppo.create_time &lt;= #{endDateTime}
            </if>
            <if test="userId != null">
                AND ppm.user_id = #{userId}
            </if>
            <if test="processIds != null and processIds.size() > 0">
                AND pp.id IN
                <foreach collection="processIds" item="id" open="(" separator="," close=")">
                    #{id}
                </foreach>
            </if>
        </where>
        GROUP BY
        pp.id,
        pp.name
    </select>
</mapper>
src/main/resources/mapper/production/ProductionProductMainMapper.xml
@@ -115,4 +115,30 @@
            #{id}
        </foreach>
    </delete>
    <select id="queryProductInputAndOutput" resultType="Hashmap">
        select *
        from (select p.product_name      as productName,
                     pm.model            as model,
                     pm.unit             as unit,
                     temp.inputQuantity  as inputQuantity,
                     temp.outputQuantity as outputQuantity
              from (select product_model_id,
                           coalesce(sum(inputQuantity), 0)  as inputQuantity,
                           coalesce(sum(outputQuantity), 0) as outputQuantity
                    from ((select product_model_id, coalesce(sum(quantity), 0) as inputQuantity, 0 as outputQuantity
                           from production_product_input
                           where create_time &gt;= #{ew.startTime}
                             and create_time &lt; #{ew.endTime}
                           group by product_model_id)
                          union all
                          (select product_model_id, 0 as inputQuantity, coalesce(sum(quantity), 0) as outputQuantity
                           from production_product_output
                           where create_time &gt;= #{ew.startTime}
                             and create_time &lt; #{ew.endTime}
                           group by product_model_id)) t
                    group by product_model_id) temp
                       left join product_model pm on temp.product_model_id = pm.id
                       left join product p on pm.product_id = p.id) tmp
    </select>
</mapper>
src/main/resources/mapper/sales/SalesLedgerProductMapper.xml
@@ -97,7 +97,7 @@
                AND slp.product_category like concat('%',#{req.productCategory},'%')
            </if>
            <if test="req.status != null and req.status ">
                AND slp.pending_invoice_total &gt; 0
                AND slp.pending_tickets_total &gt; 0
            </if>
        </where>
        order by slp.register_date desc