zss
7 天以前 7df528176008256c3b177526274f89d391c61526
Merge branch 'dev_New' into pcdz
已添加3个文件
已修改13个文件
392 ■■■■■ 文件已修改
src/main/java/com/ruoyi/common/enums/StockInQualifiedRecordTypeEnum.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/enums/StockInUnQualifiedRecordTypeEnum.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
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 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductProcessMapper.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/project/system/domain/SysMenu.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-dev.yml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductProcessMapper.xml 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/InvoiceRegistrationProductMapper.xml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/system/SysMenuMapper.xml 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/enums/StockInQualifiedRecordTypeEnum.java
@@ -10,7 +10,7 @@
    CUSTOMIZATION_STOCK_IN("0", "合格自定义入库"),
    PRODUCTION_REPORT_STOCK_IN("2", "生产报工-入库"),
    PURCHASE_STOCK_IN("7", "采购-入库"),
    QUALITYINSPECT_STOCK_IN("11", "质检-合格入库"),
    QUALITYINSPECT_STOCK_IN("6", "质检-合格入库"),
    DEFECTIVE_PASS("11", "不合格-让步放行");
src/main/java/com/ruoyi/common/enums/StockInUnQualifiedRecordTypeEnum.java
@@ -7,7 +7,7 @@
public enum StockInUnQualifiedRecordTypeEnum implements BaseEnum<String> {
    DEFECTIVE_SCRAP("5", "不合格处理-报废"),
    DEFECTIVE_SCRAP("4", "不合格处理-报废"),
    PRODUCTION_SCRAP("5", "生产报工-报废"),
    CUSTOMIZATION_UNSTOCK_IN("9", "不合格自定义入库"),
    QUALITYINSPECT_UNSTOCK_IN("12", "质检-不合格入库");
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() {
@@ -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);
                }
            }
@@ -1892,7 +1894,6 @@
        }
        return dto;
    }
    @Override
    public QualityQualifiedAnalysisDto rawMaterialDetection(Integer type) {
@@ -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/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/service/impl/ProductionProductMainServiceImpl.java
@@ -207,7 +207,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 +288,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("关联的生产订单不存在");
src/main/java/com/ruoyi/project/system/domain/SysMenu.java
@@ -21,6 +21,14 @@
    /** èœå•ID */
    private Long menuId;
    public String getAppComponent() {
        return appComponent;
    }
    public void setAppComponent(String appComponent) {
        this.appComponent = appComponent;
    }
    /** èœå•名称 */
    private String menuName;
@@ -38,6 +46,9 @@
    /** ç»„件路径 */
    private String component;
    /** APP组件路径 */
    private String appComponent;
    /** è·¯ç”±å‚æ•° */
    private String query;
@@ -260,6 +271,7 @@
            .append("isFrame", getIsFrame())
            .append("IsCache", getIsCache())
            .append("menuType", getMenuType())
            .append("appComponent", getAppComponent())
            .append("visible", getVisible())
            .append("status ", getStatus())
            .append("perms", getPerms())
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-dev.yml
@@ -13,7 +13,8 @@
  addressEnabled: false
  # éªŒè¯ç ç±»åž‹ math æ•°å­—计算 char å­—符验证
  captchaType: math
  # ååŒå®¡æ‰¹ç¼–号前缀(配置文件后缀命名)
  approvalNumberPrefix: DEV
# å¼€å‘环境配置
server:
  # æœåŠ¡å™¨çš„HTTP端口,默认为8080
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/sales/InvoiceRegistrationProductMapper.xml
@@ -92,9 +92,11 @@
            T3.invoice_person,
            T3.invoice_date,
            T4.invoiceFileName,
            T2.project_name
        T2.project_name,
        u.nick_name as invoicePerson
        FROM invoice_registration_product T1
        LEFT JOIN sales_ledger T2 ON T1.sales_ledger_id = T2.id
        LEFT JOIN sys_user u ON u.user_id = T1.create_user
        RIGHT JOIN invoice_ledger T3 ON T1.id = T3.invoice_registration_product_id
        LEFT JOIN (
            SELECT
@@ -113,13 +115,16 @@
                AND T3.invoice_date &gt;= str_to_date(#{invoiceRegistrationProductDto.invoiceDateStart}, '%Y-%m-%d')
            </if>
            <if test="invoiceRegistrationProductDto.invoiceDateEnd != null and invoiceRegistrationProductDto.invoiceDateEnd != ''">
                AND T3.invoice_date &lt; date_add(str_to_date(#{invoiceRegistrationProductDto.invoiceDateEnd}, '%Y-%m-%d'), interval 1 day)
                AND T3.invoice_date &lt; date_add(str_to_date(#{invoiceRegistrationProductDto.invoiceDateEnd},
                '%Y-%m-%d'), interval 1 day)
            </if>
            <if test="invoiceRegistrationProductDto.createTimeStart != null ">
                AND T1.create_time &gt;= date_format(#{invoiceRegistrationProductDto.createTimeStart}, '%Y-%m-%d %H:%i:%s')
                AND T1.create_time &gt;= date_format(#{invoiceRegistrationProductDto.createTimeStart}, '%Y-%m-%d
                %H:%i:%s')
            </if>
            <if test="invoiceRegistrationProductDto.createTimeEnd != null ">
                AND T1.create_time &lt;= date_format(#{invoiceRegistrationProductDto.createTimeStart}, '%Y-%m-%d %H:%i:%s')+interval 1 day
                AND T1.create_time &lt;= date_format(#{invoiceRegistrationProductDto.createTimeStart}, '%Y-%m-%d
                %H:%i:%s')+interval 1 day
            </if>
        </where>
        ORDER BY T1.create_time DESC
src/main/resources/mapper/system/SysMenuMapper.xml
@@ -11,6 +11,7 @@
        <result property="parentId"       column="parent_id"      />
        <result property="orderNum"       column="order_num"      />
        <result property="path"           column="path"           />
        <result property="appComponent"   column="app_component"  />
        <result property="component"      column="component"      />
        <result property="query"          column="query"          />
        <result property="routeName"      column="route_name"     />
@@ -29,7 +30,7 @@
    </resultMap>
    <sql id="selectMenuVo">
        select menu_id, menu_name, parent_id, order_num, path, component, `query`, route_name, is_frame, is_cache, menu_type, visible, status, ifnull(perms,'') as perms, icon, create_time
        select menu_id, menu_name, parent_id, order_num, path,app_component, component, `query`, route_name, is_frame, is_cache, menu_type, visible, status, ifnull(perms,'') as perms, icon, create_time
        from sys_menu
    </sql>
    
@@ -50,13 +51,13 @@
    </select>
    
    <select id="selectMenuTreeAll" resultMap="SysMenuResult">
        select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
        select distinct m.menu_id, m.parent_id, m.menu_name, m.path,m.app_component, m.component, m.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
        from sys_menu m where m.menu_type in ('M', 'C') and m.status = 0
        order by m.parent_id, m.order_num
    </select>
    
    <select id="selectMenuListByUserId" parameterType="com.ruoyi.project.system.domain.SysMenu" resultMap="SysMenuResult">
        select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
        select distinct m.menu_id, m.parent_id, m.menu_name, m.path,m.app_component, m.component, m.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
        from sys_menu m
        left join sys_role_menu rm on m.menu_id = rm.menu_id
        left join sys_user_role ur on rm.role_id = ur.role_id
@@ -75,7 +76,7 @@
    </select>
    
    <select id="selectMenuTreeByUserId" parameterType="Long" resultMap="SysMenuResult">
        select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
        select distinct m.menu_id, m.parent_id, m.menu_name, m.path,m.app_component, m.component, m.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
        from sys_menu m
             left join sys_role_menu rm on m.menu_id = rm.menu_id
             left join sys_user_role ur on rm.role_id = ur.role_id
@@ -141,6 +142,7 @@
            <if test="orderNum != null">order_num = #{orderNum},</if>
            <if test="path != null and path != ''">path = #{path},</if>
            <if test="component != null">component = #{component},</if>
            <if test="appComponent != null">app_component = #{appComponent},</if>
            <if test="query != null">`query` = #{query},</if>
            <if test="routeName != null">route_name = #{routeName},</if>
            <if test="isFrame != null and isFrame != ''">is_frame = #{isFrame},</if>
@@ -164,6 +166,7 @@
        <if test="menuName != null and menuName != ''">menu_name,</if>
        <if test="orderNum != null">order_num,</if>
        <if test="path != null and path != ''">path,</if>
        <if test="appComponent != null and appComponent != ''">app_component,</if>
        <if test="component != null and component != ''">component,</if>
        <if test="query != null and query != ''">`query`,</if>
        <if test="routeName != null">route_name,</if>
@@ -183,6 +186,7 @@
        <if test="menuName != null and menuName != ''">#{menuName},</if>
        <if test="orderNum != null">#{orderNum},</if>
        <if test="path != null and path != ''">#{path},</if>
        <if test="appComponent != null and appComponent != ''">#{appComponent},</if>
        <if test="component != null and component != ''">#{component},</if>
        <if test="query != null and query != ''">#{query},</if>
        <if test="routeName != null">#{routeName},</if>