huminmin
2026-07-10 2ee9e158e3129070f6b1fd953da1540f05d4f2b0
修改报工
已添加1个文件
已修改22个文件
673 ■■■■■ 文件已修改
doc/sql/天津玮苓乐器.sql 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/ApprovalTemplateService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/enums/TypeEnums.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductionAccountDto.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductionProductMainDto.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/vo/ProductionAccountVo.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionAccountController.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductionAccount.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductionProductMain.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionAccountService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionProductMainService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionAccountServiceImpl.java 135 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java 207 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionAccountMapper.xml 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionProductMainMapper.xml 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockInventoryMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/sql/Ìì½òçâÜßÀÖÆ÷.sql
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,15 @@
ALTER TABLE `production_product_main`
    ADD COLUMN `report_type` int NULL DEFAULT 0 COMMENT '报工结果类型:0合格,1轻微返工,2严重返工,3报废' AFTER `status`,
ADD COLUMN `audit_status` int NULL DEFAULT 0 COMMENT '审核状态:0待审核,1审核通过,2审核不通过' AFTER `report_type`,
ADD COLUMN `audit_remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '审核意见' AFTER `audit_status`;
ALTER TABLE `production_account`
    ADD COLUMN `adjust_amount` decimal(18,2) NULL DEFAULT NULL COMMENT '工资修正金额' AFTER `technology_operation_name`,
  ADD COLUMN `adjust_remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '工资修正说明' AFTER `adjust_amount`,
  ADD COLUMN `adjust_user` bigint NULL DEFAULT NULL COMMENT '修正人' AFTER `adjust_remark`,
  ADD COLUMN `adjust_time` datetime NULL DEFAULT NULL COMMENT '修正时间' AFTER `adjust_user`,
  ADD COLUMN `accounting_batch_no` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL COMMENT '核算批次号' AFTER `adjust_time`;
ALTER TABLE `quality_unqualified`
    ADD COLUMN `photo_urls` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL COMMENT '不合格图片' AFTER `deal_result`;
src/main/java/com/ruoyi/approve/service/ApprovalTemplateService.java
@@ -31,4 +31,6 @@
    ApprovalTemplateVo getApprovalTemplateVoById(Long id);
    ApprovalTemplateVo getEnabledTemplateByBusinessType(Long businessType);
}
src/main/java/com/ruoyi/approve/service/impl/ApprovalInstanceServiceImpl.java
@@ -31,6 +31,8 @@
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import com.ruoyi.production.pojo.ProductionProductMain;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysDeptMapper;
@@ -94,6 +96,7 @@
    private final EnterpriseNewsMapper enterpriseNewsMapper;
    private final EnterpriseNewsScopeDeptMapper enterpriseNewsScopeDeptMapper;
    private final ApprovalTemplateNodeApproverMapper approvalTemplateNodeApproverMapper;
    private final ProductionProductMainMapper productionProductMainMapper;
    @Override
    public R listPage(Page<ApprovalInstanceVo> page, ApprovalInstanceDto approvalInstanceDto) {
@@ -550,6 +553,10 @@
        }
        if (TypeEnums.ENTERPRISE_NEWS_APPROVAL.getCode().equals(businessType)) {
            handleNewsApprovalFinished(instance, status);
            return;
        }
        if (TypeEnums.PRODUCTION_REPORT_APPROVAL.getCode().equals(businessType)) {
            handleProductionReportApprovalFinished(instance, status);
        }
    }
@@ -691,6 +698,27 @@
        shippingInfoMapper.updateById(shippingInfo);
    }
    private void handleProductionReportApprovalFinished(ApprovalInstance instance, String status) {
        if (instance == null || instance.getBusinessId() == null) {
            return;
        }
        ProductionProductMain productionProductMain = productionProductMainMapper.selectById(instance.getBusinessId());
        if (productionProductMain == null) {
            return;
        }
        if ("APPROVED".equals(status)) {
            productionProductMain.setAuditStatus(1);
        } else if ("REJECTED".equals(status)) {
            productionProductMain.setAuditStatus(2);
        } else if ("PENDING".equals(status)) {
            productionProductMain.setAuditStatus(0);
        } else {
            return;
        }
        productionProductMainMapper.updateById(productionProductMain);
    }
    private List<ApprovalTask> createNodeAndTasks(ApprovalInstance instance, ApprovalTemplateNode templateNode) {
        List<ApprovalTemplateNodeApprover> approvers = approvalTemplateNodeApproverMapper.selectList(
                new LambdaQueryWrapper<ApprovalTemplateNodeApprover>()
src/main/java/com/ruoyi/approve/service/impl/ApprovalTemplateServiceImpl.java
@@ -183,6 +183,25 @@
        return buildTemplateVo(template, nodeMap, approverMap);
    }
    @Override
    public ApprovalTemplateVo getEnabledTemplateByBusinessType(Long businessType) {
        if (businessType == null) {
            return null;
        }
        ApprovalTemplate template = this.getOne(
                new LambdaQueryWrapper<ApprovalTemplate>()
                        .eq(ApprovalTemplate::getDeleted, 0)
                        .eq(ApprovalTemplate::getEnabled, 1)
                        .eq(ApprovalTemplate::getBusinessType, businessType)
                        .orderByDesc(ApprovalTemplate::getId)
                        .last("limit 1")
        );
        if (template == null) {
            return null;
        }
        return getApprovalTemplateVoById(template.getId());
    }
    /**
     * æ‰¹é‡å¡«å……模板节点及节点审批人,避免循环查库。
     */
src/main/java/com/ruoyi/common/enums/TypeEnums.java
@@ -24,7 +24,8 @@
    OVERTIME_APPROVAL(15L, "加班审批"),
    TRAVEL_REIMBURSEMENT_APPROVAL(16L, "出差报销审批"),
    EXPENSE_APPROVAL(17L, "费用审批"),
    ENTERPRISE_NEWS_APPROVAL(18L, "企业新闻审批");
    ENTERPRISE_NEWS_APPROVAL(18L, "企业新闻审批"),
    PRODUCTION_REPORT_APPROVAL(19L, "报工审批");
src/main/java/com/ruoyi/production/bean/dto/ProductionAccountDto.java
@@ -6,6 +6,7 @@
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDate;
@Data
@@ -39,6 +40,21 @@
    @Schema(description = "工序")
    private String process;
    @Schema(description = "工资修正金额")
    private BigDecimal adjustAmount;
    @Schema(description = "工资修正说明")
    private String adjustRemark;
    @Schema(description = "修正人")
    private Long adjustUser;
    @Schema(description = "报工结果类型:0合格,1轻微返工,2严重返工,3报废")
    private Integer reportType;
    @Schema(description = "审核状态:0待审核,1审核通过,2审核不通过")
    private Integer auditStatus;
    @Schema(description = "日期类型(按天/按月)")
    private String dateType;
src/main/java/com/ruoyi/production/bean/dto/ProductionProductMainDto.java
@@ -21,6 +21,15 @@
    @Schema(description = "报工ID")
    private Long productMainId;
    @Schema(description = "报工结果类型:0合格,1轻微返工,2严重返工,3报废")
    private Integer reportType;
    @Schema(description = "审核状态:0待审核,1审核通过,2审核不通过")
    private Integer auditStatus;
    @Schema(description = "审核意见")
    private String auditRemark;
    @Schema(description = "租户ID")
    private Long tenantId;
src/main/java/com/ruoyi/production/bean/vo/ProductionAccountVo.java
@@ -11,6 +11,15 @@
@Schema(name = "ProductionAccountVo", description = "生产核算分页结果")
public class ProductionAccountVo {
    @Schema(description = "报工单号")
    private String reportNo;
    @Schema(description = "审核状态")
    private String auditStatusName;
    @Schema(description = "报工类型")
    private String reportTypeName;
    @Schema(description = "客户合同号")
    private String customerContractNo;
@@ -35,6 +44,9 @@
    @Schema(description = "排产人员名称")
    private String schedulingUserName;
    @Schema(description = "工单编号")
    private String workOrderNo;
    @Schema(description = "工资")
    private BigDecimal wages;
@@ -44,6 +56,12 @@
    @Schema(description = "工资定额")
    private BigDecimal workHours;
    @Schema(description = "工资修正金额")
    private BigDecimal adjustAmount;
    @Schema(description = "工资修正说明")
    private String adjustRemark;
    @Schema(description = "工时")
    private BigDecimal workHour;
src/main/java/com/ruoyi/production/controller/ProductionAccountController.java
@@ -10,9 +10,11 @@
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestBody;
/**
 * <p>
@@ -38,4 +40,16 @@
    public R<IPage<ProductionProductMainDto>> listProductionDetails(ProductionAccountDto productionAccountDto, Page page) {
        return R.ok(productionAccountService.listProductionDetails(productionAccountDto,page));
    }
    @PostMapping("/batchAccounting")
    @Operation(summary = "批量核算")
    public R<Boolean> batchAccounting(@RequestBody ProductionAccountDto dto) {
        return R.ok(productionAccountService.batchAccounting(dto));
    }
    @PostMapping("/singleAdjust")
    @Operation(summary = "单个修正")
    public R<Boolean> singleAdjust(@RequestBody ProductionAccountDto dto) {
        return R.ok(productionAccountService.singleAdjust(dto));
    }
}
src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java
@@ -80,6 +80,13 @@
        return R.ok(productionProductMainService.removeProductMain(id));
    }
    @PostMapping("/audit")
    @Operation(summary = "审核生产报工")
    @PreAuthorize("@ss.hasPermi('productionProductMain:audit')")
    public R audit(@RequestBody ProductionProductMainDto productionProductMainDto) {
        return R.ok(productionProductMainService.auditProductMain(productionProductMainDto));
    }
    /**
     * å¯¼å‡º
src/main/java/com/ruoyi/production/pojo/ProductionAccount.java
@@ -45,6 +45,21 @@
    @Schema(description = "工序名称")
    private String technologyOperationName;
    @Schema(description = "工资修正金额")
    private BigDecimal adjustAmount;
    @Schema(description = "工资修正说明")
    private String adjustRemark;
    @Schema(description = "修正人")
    private Long adjustUser;
    @Schema(description = "修正时间")
    private LocalDateTime adjustTime;
    @Schema(description = "核算批次号")
    private String accountingBatchNo;
    @Schema(description = "生产日期")
    private LocalDateTime schedulingDate;
src/main/java/com/ruoyi/production/pojo/ProductionProductMain.java
@@ -33,6 +33,18 @@
    @Schema(description = "报工状态")
    private Integer status;
    @Schema(description = "报工结果类型:0合格,1轻微返工,2严重返工,3报废")
    @TableField("report_type")
    private Integer reportType;
    @Schema(description = "审核状态:0待审核,1审核通过,2审核不通过")
    @TableField("audit_status")
    private Integer auditStatus;
    @Schema(description = "审核意见")
    @TableField("audit_remark")
    private String auditRemark;
    @Schema(description = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
src/main/java/com/ruoyi/production/service/ProductionAccountService.java
@@ -20,4 +20,8 @@
    IPage<ProductionAccountVo> listPage(Page<ProductionAccountDto> page, ProductionAccountDto dto);
    IPage<ProductionProductMainDto> listProductionDetails(ProductionAccountDto productionAccountDto, Page page);
    Boolean batchAccounting(ProductionAccountDto dto);
    Boolean singleAdjust(ProductionAccountDto dto);
}
src/main/java/com/ruoyi/production/service/ProductionProductMainService.java
@@ -22,5 +22,7 @@
    Boolean removeProductMain(Long id);
    Boolean auditProductMain(ProductionProductMainDto productionProductMainDto);
    ArrayList<Long> listMain(List<Long> idList);
}
src/main/java/com/ruoyi/production/service/impl/ProductionAccountServiceImpl.java
@@ -1,19 +1,39 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.production.bean.dto.ProductionAccountDto;
import com.ruoyi.production.bean.dto.ProductionProductMainDto;
import com.ruoyi.production.bean.vo.ProductionAccountVo;
import com.ruoyi.production.mapper.ProductionAccountMapper;
import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import com.ruoyi.production.mapper.ProductionProductOutputMapper;
import com.ruoyi.production.pojo.ProductionAccount;
import com.ruoyi.production.pojo.ProductionOperationTask;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
import com.ruoyi.production.pojo.ProductionProductMain;
import com.ruoyi.production.pojo.ProductionProductOutput;
import com.ruoyi.technology.mapper.TechnologyOperationMapper;
import com.ruoyi.technology.mapper.TechnologyRoutingOperationMapper;
import com.ruoyi.technology.pojo.TechnologyOperation;
import com.ruoyi.technology.pojo.TechnologyRoutingOperation;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.production.service.ProductionAccountService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.exception.ServiceException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
@Service
@RequiredArgsConstructor
@@ -21,6 +41,12 @@
    private final ProductionProductMainMapper productionProductMainMapper;
    private final ProductionProductOutputMapper productionProductOutputMapper;
    private final ProductionOperationTaskMapper productionOperationTaskMapper;
    private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
    private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
    private final TechnologyOperationMapper technologyOperationMapper;
    private final SysUserMapper sysUserMapper;
    @Override
    public IPage<ProductionAccountVo> listPage(Page<ProductionAccountDto> page, ProductionAccountDto dto) {
@@ -32,7 +58,114 @@
    @Override
    public IPage<ProductionProductMainDto> listProductionDetails(ProductionAccountDto dto, Page page) {
        // æŸ¥è¯¢ç”Ÿäº§æ ¸ç®—明细
        return productionProductMainMapper.listProductionDetails(normalizeDateQuery(dto), page);
        ProductionAccountDto queryDto = normalizeDateQuery(dto);
        if (queryDto.getAuditStatus() == null) {
            queryDto.setAuditStatus(1);
        }
        if (queryDto.getReportType() == null) {
            queryDto.setReportType(0);
        }
        return productionProductMainMapper.listProductionDetails(queryDto, page);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchAccounting(ProductionAccountDto dto) {
        ProductionAccountDto queryDto = normalizeDateQuery(dto);
        LambdaQueryWrapper<ProductionProductMain> queryWrapper = Wrappers.<ProductionProductMain>lambdaQuery()
                .eq(ProductionProductMain::getAuditStatus, 1)
                .eq(ProductionProductMain::getReportType, 0);
        if (queryDto.getSchedulingUserId() != null) {
            queryWrapper.eq(ProductionProductMain::getUserId, queryDto.getSchedulingUserId());
        }
        if (queryDto.getSchedulingUserName() != null && !queryDto.getSchedulingUserName().isEmpty()) {
            queryWrapper.like(ProductionProductMain::getUserName, queryDto.getSchedulingUserName());
        }
        if (queryDto.getEntryDate() != null) {
            queryWrapper.apply("date(create_time) = {0}", queryDto.getEntryDate());
        }
        if (queryDto.getEntryDateStart() != null) {
            queryWrapper.ge(ProductionProductMain::getCreateTime, queryDto.getEntryDateStart().atStartOfDay());
        }
        if (queryDto.getEntryDateEnd() != null) {
            queryWrapper.le(ProductionProductMain::getCreateTime, queryDto.getEntryDateEnd().atTime(23, 59, 59));
        }
        List<ProductionProductMain> reportList = productionProductMainMapper.selectList(queryWrapper);
        for (ProductionProductMain report : reportList) {
            rebuildAccount(report);
        }
        return Boolean.TRUE;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean singleAdjust(ProductionAccountDto dto) {
        if (dto == null || dto.getSchedulingUserId() == null) {
            throw new ServiceException("请选择需要修正的人员");
        }
        BigDecimal adjustAmount = dto.getAdjustAmount();
        if (adjustAmount == null || adjustAmount.compareTo(BigDecimal.ZERO) == 0) {
            throw new ServiceException("修正金额不能为空");
        }
        ProductionAccount account = new ProductionAccount();
        account.setSchedulingUserId(dto.getSchedulingUserId());
        account.setSchedulingUserName(dto.getSchedulingUserName());
        account.setTechnologyOperationName("工资修正");
        account.setAdjustAmount(adjustAmount);
        account.setAdjustRemark(dto.getAdjustRemark());
        account.setAdjustUser(dto.getAdjustUser());
        account.setAdjustTime(LocalDateTime.now());
        account.setSchedulingDate(LocalDateTime.now());
        account.setWorkHours(BigDecimal.ZERO);
        account.setFinishedNum(BigDecimal.ZERO);
        account.setAccountingBatchNo("ADJ-" + LocalDate.now());
        baseMapper.insert(account);
        return Boolean.TRUE;
    }
    private void rebuildAccount(ProductionProductMain productionProductMain) {
        if (productionProductMain == null || productionProductMain.getId() == null) {
            return;
        }
        productionAccountDelete(productionProductMain.getId());
        ProductionProductOutput output = productionProductOutputMapper.selectOne(
                Wrappers.<ProductionProductOutput>lambdaQuery()
                        .eq(ProductionProductOutput::getProductionProductMainId, productionProductMain.getId())
                        .last("limit 1"));
        if (output == null || output.getQuantity() == null || output.getQuantity().compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        ProductionOperationTask task = productionOperationTaskMapper.selectById(productionProductMain.getProductionOperationTaskId());
        if (task == null) {
            return;
        }
        ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(task.getProductionOrderRoutingOperationId());
        if (routingOperation == null) {
            return;
        }
        TechnologyRoutingOperation technologyRoutingOperation = technologyRoutingOperationMapper.selectById(routingOperation.getTechnologyRoutingOperationId());
        TechnologyOperation technologyOperation = technologyRoutingOperation == null ? null
                : technologyOperationMapper.selectById(technologyRoutingOperation.getTechnologyOperationId());
        SysUser user = sysUserMapper.selectUserById(productionProductMain.getUserId());
        ProductionAccount account = new ProductionAccount();
        account.setProductionProductMainId(productionProductMain.getId());
        account.setSchedulingUserId(user == null ? productionProductMain.getUserId() : user.getUserId());
        account.setSchedulingUserName(user == null ? productionProductMain.getUserName() : user.getNickName());
        account.setFinishedNum(output.getQuantity());
        account.setWorkHours(technologyOperation == null ? null : technologyOperation.getSalaryQuota());
        account.setTechnologyOperationName(technologyOperation == null ? null : technologyOperation.getName());
        account.setSchedulingDate(LocalDateTime.now());
        account.setAccountingBatchNo("BATCH-" + LocalDate.now());
        baseMapper.insert(account);
    }
    private void productionAccountDelete(Long productionProductMainId) {
        if (productionProductMainId == null) {
            return;
        }
        baseMapper.delete(new LambdaQueryWrapper<ProductionAccount>()
                .eq(ProductionAccount::getProductionProductMainId, productionProductMainId));
    }
    private ProductionAccountDto normalizeDateQuery(ProductionAccountDto dto) {
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -7,10 +7,16 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.alibaba.fastjson2.JSON;
import com.ruoyi.approve.bean.dto.ApprovalInstanceDto;
import com.ruoyi.approve.bean.vo.ApprovalTemplateVo;
import com.ruoyi.approve.service.ApprovalInstanceService;
import com.ruoyi.approve.service.ApprovalTemplateService;
import com.ruoyi.basic.mapper.ProductMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.Product;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.common.enums.TypeEnums;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.exception.ServiceException;
@@ -78,6 +84,8 @@
    private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
    private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
    private final TechnologyOperationMapper technologyOperationMapper;
    private final ApprovalTemplateService approvalTemplateService;
    private final ApprovalInstanceService approvalInstanceService;
    private final StockUtils stockUtils;
    private final StockInRecordService stockInRecordService;
    private final StockInventoryService stockInventoryService;
@@ -277,9 +285,13 @@
        productionProductMain.setUserName(user == null ? dto.getUserName() : user.getNickName());
        productionProductMain.setProductionOperationTaskId(taskId);
        productionProductMain.setStatus(0);
        productionProductMain.setReportType(dto.getReportType() == null ? 0 : dto.getReportType());
        productionProductMain.setAuditStatus(dto.getAuditStatus() == null ? 0 : dto.getAuditStatus());
        productionProductMain.setAuditRemark(dto.getAuditRemark());
        productionProductMain.setWorkHour(dto.getWorkHour());
        productionProductMainMapper.insert(productionProductMain);
        syncOperationParamInputValue(dto, routingOperation.getId(), productionProductMain.getId());
        createReportApprovalInstance(productionProductMain);
        List<ProductStructureDto> productStructureDtos = resolveInputStructures(
                productionOrder.getId(), routingOperation, productModel.getId());
@@ -406,7 +418,6 @@
            productionAccount.setWorkHours(technologyOperation != null ? technologyOperation.getSalaryQuota() : null);
            productionAccount.setTechnologyOperationName(technologyOperation == null ? null : technologyOperation.getName());
            productionAccount.setSchedulingDate(LocalDateTime.now());
            productionAccountMapper.insert(productionAccount);
        }
        if (scrapQty.compareTo(BigDecimal.ZERO) > 0) {
            stockUtils.addUnStockWithBatchNo(
@@ -417,6 +428,120 @@
                    qualifiedBatchNo);
        }
        return true;
    }
    private void createReportApprovalInstance(ProductionProductMain productionProductMain) {
        if (productionProductMain == null || productionProductMain.getId() == null) {
            return;
        }
        ApprovalTemplateVo templateVo = approvalTemplateService.getEnabledTemplateByBusinessType(
                TypeEnums.PRODUCTION_REPORT_APPROVAL.getCode()
        );
        if (templateVo == null) {
            throw new ServiceException("请先配置报工审批模板");
        }
        ApprovalInstanceDto approvalInstanceDto = new ApprovalInstanceDto();
        approvalInstanceDto.setTemplateId(templateVo.getId());
        approvalInstanceDto.setTemplateName(templateVo.getTemplateName());
        approvalInstanceDto.setBusinessId(productionProductMain.getId());
        approvalInstanceDto.setBusinessType(TypeEnums.PRODUCTION_REPORT_APPROVAL.getCode());
        approvalInstanceDto.setTitle(productionProductMain.getProductNo());
        approvalInstanceDto.setApplicantId(productionProductMain.getUserId());
        approvalInstanceDto.setApplicantName(productionProductMain.getUserName());
        approvalInstanceDto.setApplyTime(LocalDateTime.now());
        approvalInstanceDto.setStatus("PENDING");
        approvalInstanceDto.setFormConfig(JSON.toJSONString(buildReportApprovalFormConfig(productionProductMain)));
        approvalInstanceService.add(approvalInstanceDto);
    }
    private Map<String, Object> buildReportApprovalFormConfig(ProductionProductMain productionProductMain) {
        Map<String, Object> formConfig = new LinkedHashMap<>();
        formConfig.put("summaryPlaceholder", "报工审批");
        formConfig.put("approvalType", "production_report");
        List<Map<String, Object>> fields = new ArrayList<>();
        fields.add(buildReportField("productNo", "报工单号", "text", productionProductMain.getProductNo()));
        fields.add(buildReportField("userName", "报工人员", "text", productionProductMain.getUserName()));
        fields.add(buildReportField("workOrderNo", "工单编号", "text", resolveWorkOrderNo(productionProductMain.getProductionOperationTaskId())));
        fields.add(buildReportField("reportType", "报工结果", "select", resolveReportTypeLabel(productionProductMain.getReportType())));
        fields.add(buildReportField("workHour", "工时", "number", productionProductMain.getWorkHour()));
        fields.add(buildReportField("auditStatus", "审核状态", "select", resolveAuditStatusLabel(productionProductMain.getAuditStatus())));
        fields.add(buildReportField("auditRemark", "审核意见", "textarea", productionProductMain.getAuditRemark()));
        formConfig.put("fields", fields);
        Map<String, Object> formPayload = new LinkedHashMap<>();
        formPayload.put("productNo", productionProductMain.getProductNo());
        formPayload.put("userName", productionProductMain.getUserName());
        formPayload.put("workOrderNo", resolveWorkOrderNo(productionProductMain.getProductionOperationTaskId()));
        formPayload.put("reportType", resolveReportTypeLabel(productionProductMain.getReportType()));
        formPayload.put("workHour", productionProductMain.getWorkHour());
        formPayload.put("auditStatus", resolveAuditStatusLabel(productionProductMain.getAuditStatus()));
        formPayload.put("auditRemark", productionProductMain.getAuditRemark());
        formConfig.put("formPayload", formPayload);
        return formConfig;
    }
    private Map<String, Object> buildReportField(String key, String label, String type, Object defaultValue) {
        Map<String, Object> field = new LinkedHashMap<>();
        field.put("key", key);
        field.put("label", label);
        field.put("type", type);
        field.put("required", Boolean.FALSE);
        field.put("defaultValue", defaultValue);
        return field;
    }
    private String resolveWorkOrderNo(Long productionOperationTaskId) {
        if (productionOperationTaskId == null) {
            return null;
        }
        ProductionOperationTask task = productionOperationTaskMapper.selectById(productionOperationTaskId);
        if (task != null && task.getWorkOrderNo() != null) {
            return task.getWorkOrderNo();
        }
        if (task == null || task.getProductionOrderRoutingOperationId() == null) {
            return null;
        }
        ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(task.getProductionOrderRoutingOperationId());
        if (routingOperation == null || routingOperation.getProductionOrderId() == null) {
            return null;
        }
        ProductionOrder productionOrder = productionOrderMapper.selectById(routingOperation.getProductionOrderId());
        return productionOrder == null ? null : productionOrder.getNpsNo();
    }
    private String resolveReportTypeLabel(Integer reportType) {
        if (reportType == null) {
            return "—";
        }
        switch (reportType) {
            case 0:
                return "合格";
            case 1:
                return "轻微返工";
            case 2:
                return "严重返工";
            case 3:
                return "报废";
            default:
                return "—";
        }
    }
    private String resolveAuditStatusLabel(Integer auditStatus) {
        if (auditStatus == null) {
            return "待审核";
        }
        switch (auditStatus) {
            case 0:
                return "待审核";
            case 1:
                return "审核通过";
            case 2:
                return "审核不通过";
            default:
                return "—";
        }
    }
    private String resolveLatestStockInBatchNo(Long recordId,
@@ -681,6 +806,86 @@
        return dto.getProductionOperationTaskId();
    }
    private boolean isCountingWageReport(ProductionProductMain productionProductMain) {
        return productionProductMain != null
                && productionProductMain.getAuditStatus() != null
                && productionProductMain.getAuditStatus() == 1
                && productionProductMain.getReportType() != null
                && productionProductMain.getReportType() == 0;
    }
    private boolean isExcludedFromWage(ProductionProductMain productionProductMain) {
        return productionProductMain != null
                && productionProductMain.getReportType() != null
                && productionProductMain.getReportType() != 0;
    }
    @Override
    public Boolean auditProductMain(ProductionProductMainDto productionProductMainDto) {
        if (productionProductMainDto == null || productionProductMainDto.getId() == null) {
            throw new ServiceException("参数错误");
        }
        ProductionProductMain productionProductMain = productionProductMainMapper.selectById(productionProductMainDto.getId());
        if (productionProductMain == null) {
            throw new ServiceException("报工不存在");
        }
        Integer auditStatus = productionProductMainDto.getAuditStatus();
        if (auditStatus == null) {
            throw new ServiceException("审核状态不能为空");
        }
        productionProductMain.setAuditStatus(auditStatus);
        productionProductMain.setAuditRemark(productionProductMainDto.getAuditRemark());
        productionProductMainMapper.updateById(productionProductMain);
        productionAccountMapper.delete(new LambdaQueryWrapper<ProductionAccount>()
                .eq(ProductionAccount::getProductionProductMainId, productionProductMain.getId()));
        if (auditStatus == 1 && !isExcludedFromWage(productionProductMain)) {
            rebuildProductionAccount(productionProductMain);
        }
        return true;
    }
    private void rebuildProductionAccount(ProductionProductMain productionProductMain) {
        if (productionProductMain == null || productionProductMain.getId() == null) {
            return;
        }
        ProductionProductOutput output = productionProductOutputMapper.selectOne(
                Wrappers.<ProductionProductOutput>lambdaQuery()
                        .eq(ProductionProductOutput::getProductionProductMainId, productionProductMain.getId())
                        .last("limit 1"));
        if (output == null) {
            return;
        }
        ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectById(productionProductMain.getProductionOperationTaskId());
        if (productionOperationTask == null) {
            return;
        }
        ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(productionOperationTask.getProductionOrderRoutingOperationId());
        if (routingOperation == null) {
            return;
        }
        ProductionOrder productionOrder = productionOrderMapper.selectById(productionOperationTask.getProductionOrderId());
        if (productionOrder == null) {
            return;
        }
        TechnologyRoutingOperation technologyRoutingOperation = technologyRoutingOperationMapper.selectById(routingOperation.getTechnologyRoutingOperationId());
        TechnologyOperation technologyOperation = technologyRoutingOperation == null ? null
                : technologyOperationMapper.selectById(technologyRoutingOperation.getTechnologyOperationId());
        SysUser user = userMapper.selectUserById(productionProductMain.getUserId());
        BigDecimal productQty = defaultDecimal(output.getQuantity());
        if (productQty.compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        ProductionAccount productionAccount = new ProductionAccount();
        productionAccount.setProductionProductMainId(productionProductMain.getId());
        productionAccount.setSchedulingUserId(user == null ? productionProductMain.getUserId() : user.getUserId());
        productionAccount.setSchedulingUserName(user == null ? productionProductMain.getUserName() : user.getNickName());
        productionAccount.setFinishedNum(productQty);
        productionAccount.setWorkHours(technologyOperation != null ? technologyOperation.getSalaryQuota() : null);
        productionAccount.setTechnologyOperationName(technologyOperation == null ? null : technologyOperation.getName());
        productionAccount.setSchedulingDate(LocalDateTime.now());
        productionAccountMapper.insert(productionAccount);
    }
    @Override
    public ArrayList<Long> listMain(List<Long> idList) {
        // æŸ¥è¯¢ä¸»è¡¨ID集合
src/main/java/com/ruoyi/quality/controller/QualityUnqualifiedController.java
@@ -4,6 +4,7 @@
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.quality.pojo.QualityUnqualified;
import com.ruoyi.quality.service.IQualityUnqualifiedService;
import io.swagger.v3.oas.annotations.Operation;
@@ -37,6 +38,10 @@
    @Log(title = "新增不合格管理", businessType = BusinessType.INSERT)
    public R<?> add(@RequestBody QualityUnqualified qualityUnqualified) {
        qualityUnqualified.setInspectState(0);
        if (qualityUnqualified.getDealType() != null) {
            qualityUnqualified.setDealResult(resolveDealResult(qualityUnqualified.getDealType()));
        }
        normalizeRepairWorkHour(qualityUnqualified);
        return R.ok(qualityUnqualifiedService.save(qualityUnqualified));
    }
@@ -78,6 +83,10 @@
    @Operation(summary = "不合格管理修改")
    @Log(title = "不合格管理修改", businessType = BusinessType.UPDATE)
    public R<?> update(@RequestBody QualityUnqualified qualityUnqualified) {
        if (qualityUnqualified.getDealType() != null) {
            qualityUnqualified.setDealResult(resolveDealResult(qualityUnqualified.getDealType()));
        }
        normalizeRepairWorkHour(qualityUnqualified);
        return R.ok(qualityUnqualifiedService.updateById(qualityUnqualified));
    }
@@ -115,8 +124,38 @@
    @Operation(summary = "不合格管理处理")
    @Log(title = "不合格管理处理", businessType = BusinessType.OTHER)
    public R<?> deal(@RequestBody QualityUnqualified qualityUnqualified) {
        if (qualityUnqualified.getDealType() != null) {
            qualityUnqualified.setDealResult(resolveDealResult(qualityUnqualified.getDealType()));
        }
        normalizeRepairWorkHour(qualityUnqualified);
        return R.ok(qualityUnqualifiedService.deal(qualityUnqualified));
    }
    private String resolveDealResult(Integer dealType) {
        if (dealType == null) {
            return null;
        }
        return switch (dealType) {
            case 0 -> "轻微返工";
            case 1 -> "严重返工";
            case 2 -> "报废";
            default -> null;
        };
    }
    private void normalizeRepairWorkHour(QualityUnqualified qualityUnqualified) {
        if (qualityUnqualified == null || qualityUnqualified.getDealType() == null) {
            return;
        }
        if (qualityUnqualified.getDealType() == 0) {
            if (qualityUnqualified.getRepairWorkHour() == null
                    || qualityUnqualified.getRepairWorkHour().compareTo(java.math.BigDecimal.ZERO) <= 0) {
                throw new ServiceException("轻微返工必须填写大于0的修理工时");
            }
        } else {
            qualityUnqualified.setRepairWorkHour(java.math.BigDecimal.ZERO);
        }
    }
}
src/main/java/com/ruoyi/quality/pojo/QualityUnqualified.java
@@ -99,6 +99,24 @@
    private String dealResult;
    /**
     * ä¸åˆæ ¼å›¾ç‰‡
     */
    @Excel(name = "不合格图片")
    private String photoUrls;
    @Schema(description = "不合格处理类型:0轻微返工,1严重返工,2报废")
    @Excel(name = "不合格处理类型", readConverterExp = "0=轻微返工,1=严重返工,2=报废")
    private Integer dealType;
    @Schema(description = "修理工时")
    @Excel(name = "修理工时")
    private BigDecimal repairWorkHour;
    @Schema(description = "是否重新生成新单:0否,1是")
    @Excel(name = "是否重新生成新单", readConverterExp = "0=否,1=是")
    private Integer regenerateNewOrder;
    /**
     * å¤„理人
     */
    @Excel(name = "处理人")
src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
@@ -73,14 +73,29 @@
        QualityInspect qualityInspect = qualityInspectService.getById(unqualified.getInspectId());
        String batchNo = qualityInspect == null ? null
                : resolveProductionBatchNo(qualityInspect.getProductMainId(), qualityInspect.getId(), qualityInspect.getProductModelId());
        if (qualityUnqualified.getDealType() != null) {
            switch (qualityUnqualified.getDealType()) {
                case 0:
                    qualityUnqualified.setDealResult("轻微返工");
                    break;
                case 1:
                    qualityUnqualified.setDealResult("严重返工");
                    break;
                case 2:
                    qualityUnqualified.setDealResult("报废");
                    break;
                default:
                    break;
            }
        }
        if (ObjectUtils.isNotNull(qualityInspect) && qualityInspect.getInspectType() != 0) {
            switch (qualityUnqualified.getDealResult()) {
                case "返修":
                case "返工":
                case "严重返工":
                case "轻微返工":
                    if (ObjectUtils.isNotNull(qualityInspect.getProductMainId())) {
                        ProductionProductMain sourceMain = productionProductMainMapper.selectById(qualityInspect.getProductMainId());
                        if (sourceMain == null || sourceMain.getProductionOperationTaskId() == null) {
                            throw new ServiceException("历史报工未绑定生产工单,无法按新模型返修/返工");
                            throw new ServiceException("历史报工未绑定生产工单,无法按新模型返工");
                        }
                        createReworkProductionByNewModel(sourceMain, unqualified.getQuantity());
                    }
@@ -88,6 +103,7 @@
                case "报废":
                    stockUtils.addUnStockWithBatchNo(qualityInspect.getProductModelId(), unqualified.getQuantity(),
                            StockInQualifiedRecordTypeEnum.DEFECTIVE_SCRAP.getCode(), unqualified.getId(), batchNo);
                    qualityUnqualified.setRegenerateNewOrder(1);
                    break;
                case "让步放行":
                    stockUtils.addStockWithBatchNo(qualityInspect.getProductModelId(), unqualified.getQuantity(),
src/main/resources/mapper/production/ProductionAccountMapper.xml
@@ -13,6 +13,11 @@
        <result column="finished_num" property="finishedNum" />
        <result column="work_hours" property="workHours" />
        <result column="technology_operation_name" property="technologyOperationName" />
        <result column="adjust_amount" property="adjustAmount" />
        <result column="adjust_remark" property="adjustRemark" />
        <result column="adjust_user" property="adjustUser" />
        <result column="adjust_time" property="adjustTime" />
        <result column="accounting_batch_no" property="accountingBatchNo" />
        <result column="scheduling_date" property="schedulingDate" />
        <result column="create_user" property="createUser" />
        <result column="create_time" property="createTime" />
@@ -23,13 +28,27 @@
    <select id="listPage" resultType="com.ruoyi.production.bean.vo.ProductionAccountVo">
        select
        group_concat(distinct ppm.product_no order by ppm.product_no separator ',') as reportNo,
        case
            when sum(case when ppm.audit_status = 0 then 1 else 0 end) > 0 then '待审核'
            when sum(case when ppm.audit_status = 2 then 1 else 0 end) > 0 then '审核不通过'
            else '审核通过'
        end as auditStatusName,
        case
            when sum(case when ppm.report_type = 1 then 1 else 0 end) > 0 then '轻微返工'
            when sum(case when ppm.report_type = 2 then 1 else 0 end) > 0 then '严重返工'
            when sum(case when ppm.report_type = 3 then 1 else 0 end) > 0 then '报废'
            else '合格'
        end as reportTypeName,
        group_concat(distinct p_parent.product_name order by p_parent.product_name separator ',') as productCategory,
        group_concat(distinct pm.model order by pm.model separator ',') as specificationModel,
        group_concat(distinct pm.unit order by pm.unit separator ',') as unit,
        pa.scheduling_user_id as schedulingUserId,
        pa.scheduling_user_name as schedulingUserName,
        group_concat(distinct pot.work_order_no order by pot.work_order_no separator ',') as workOrderNo,
        cast(sum(
            case
                when pa.adjust_amount is not null then ifnull(pa.adjust_amount, 0)
                when poro.type = 0 then ifnull(pa.work_hours, 0) * ifnull(ppm.work_hour, 0)
                else ifnull(pa.work_hours, 0) * ifnull(pa.finished_num, 0) *
                     case
@@ -41,6 +60,7 @@
        ) as decimal(18,4)) as wages,
        cast(sum(ifnull(pa.finished_num, 0)) as decimal(18,4)) as finishedNum,
        cast(sum(ifnull(pa.work_hours, 0)) as decimal(18,4)) as workHours,
        cast(sum(ifnull(pa.adjust_amount, 0)) as decimal(18,4)) as adjustAmount,
        cast(sum(ifnull(ppm.work_hour, 0)) as decimal(18,4)) as workHour,
        case
            when sum(ifnull(ppo.quantity, 0) + ifnull(ppo.scrapQty, 0)) = 0 then '0%'
@@ -55,6 +75,7 @@
            )
        end as outputRate,
        group_concat(distinct pa.technology_operation_name order by pa.technology_operation_name separator ',') as process,
        group_concat(distinct pa.adjust_remark order by pa.adjust_time desc separator ',') as adjustRemark,
        case
            when count(distinct date(pa.scheduling_date)) = 1 then min(date(pa.scheduling_date))
            else null
@@ -79,6 +100,8 @@
            group by production_product_main_id
        ) ppo on ppo.production_product_main_id = ppm.id
        <where>
            and ppm.audit_status = 1
            and ppm.report_type = 0
            <if test="c != null">
                <if test="c.productCategory != null and c.productCategory != ''">
                    and p_parent.product_name like concat('%', #{c.productCategory}, '%')
@@ -115,9 +138,12 @@
    <select id="selectUserAccount" resultType="com.ruoyi.production.bean.dto.UserAccountDto">
        select ifnull(sum(finished_num), 0) as accountBalance,
               ifnull(sum(work_hours), 0) as account
        from production_account
        where scheduling_user_id = #{userId}
          and date_format(scheduling_date, '%Y-%m') = #{date}
        from production_account pa
                 inner join production_product_main ppm on ppm.id = pa.production_product_main_id
        where pa.scheduling_user_id = #{userId}
          and date_format(pa.scheduling_date, '%Y-%m') = #{date}
          and ppm.audit_status = 1
          and ppm.report_type = 0
    </select>
    <select id="selectDailyWagesStats" resultType="java.util.Map">
@@ -125,9 +151,12 @@
               cast(ifnull(sum(finished_num), 0) as decimal(18,2)) as numberOfCompleted,
               cast(ifnull(sum(work_hours), 0) as decimal(18,2)) as amount,
               cast(0 as decimal(18,2)) as passRate
        from production_account
        where scheduling_date &gt;= #{startDate}
          and scheduling_date &lt;= #{endDate}
        from production_account pa
                 inner join production_product_main ppm on ppm.id = pa.production_product_main_id
        where pa.scheduling_date &gt;= #{startDate}
          and pa.scheduling_date &lt;= #{endDate}
          and ppm.audit_status = 1
          and ppm.report_type = 0
        group by date_format(scheduling_date, '%m-%d')
        order by date_format(scheduling_date, '%m-%d')
    </select>
src/main/resources/mapper/production/ProductionProductMainMapper.xml
@@ -7,6 +7,9 @@
        <id column="id" property="id" />
        <result column="product_no" property="productNo" />
        <result column="production_operation_task_id" property="productionOperationTaskId" />
        <result column="report_type" property="reportType" />
        <result column="audit_status" property="auditStatus" />
        <result column="audit_remark" property="auditRemark" />
        <result column="dept_id" property="deptId" />
        <result column="update_time" property="updateTime" />
        <result column="create_user" property="createUser" />
@@ -16,6 +19,20 @@
    <select id="listPageProductionProductMainDto" resultType="com.ruoyi.production.bean.dto.ProductionProductMainDto">
        select ppm.*,
               ppm.product_no as reportNo,
               case ppm.report_type
                   when 0 then '合格'
                   when 1 then '轻微返工'
                   when 2 then '严重返工'
                   when 3 then '报废'
                   else '未知'
                   end as reportTypeName,
               case ppm.audit_status
                   when 0 then '待审核'
                   when 1 then '审核通过'
                   when 2 then '审核不通过'
                   else '未知'
                   end as auditStatusName,
               pot.work_order_no as workOrderNo,
               case pot.status
                   when 1 then '待确认'
@@ -57,6 +74,12 @@
            <if test="c.productNo != null and c.productNo != ''">
                and ppm.product_no like concat('%', #{c.productNo}, '%')
            </if>
            <if test="c.auditStatus != null">
                and ppm.audit_status = #{c.auditStatus}
            </if>
            <if test="c.reportType != null">
                and ppm.report_type = #{c.reportType}
            </if>
            <if test="c.workOrderNo != null and c.workOrderNo != ''">
                and pot.work_order_no like concat('%', #{c.workOrderNo}, '%')
            </if>
@@ -91,6 +114,20 @@
    <select id="listProductionDetails" resultType="com.ruoyi.production.bean.dto.ProductionProductMainDto">
        select ppm.*,
               ppm.product_no as reportNo,
               case ppm.report_type
                   when 0 then '合格'
                   when 1 then '轻微返工'
                   when 2 then '严重返工'
                   when 3 then '报废'
                   else '未知'
                   end as reportTypeName,
               case ppm.audit_status
                   when 0 then '待审核'
                   when 1 then '审核通过'
                   when 2 then '审核不通过'
                   else '未知'
                   end as auditStatusName,
               pot.work_order_no as workOrderNo,
               p.product_name as productName,
               pm.model as productModelName,
@@ -125,6 +162,12 @@
                 left join production_product_output ppo on ppo.production_product_main_id = ppm.id
        <where>
            <if test="c != null">
                <if test="c.auditStatus != null">
                    and ppm.audit_status = #{c.auditStatus}
                </if>
                <if test="c.reportType != null">
                    and ppm.report_type = #{c.reportType}
                </if>
                <if test="c.productCategory != null and c.productCategory != ''">
                    and p_parent.product_name like concat('%', #{c.productCategory}, '%')
                </if>
src/main/resources/mapper/quality/QualityUnqualifiedMapper.xml
@@ -14,6 +14,7 @@
        qu.quantity,
        qu.defective_phenomena,
        qu.deal_result,
        qu.photo_urls,
        qu.deal_name,
        qu.deal_time,
        CASE
@@ -74,6 +75,7 @@
            qu.quantity,
            qu.defective_phenomena,
            qu.deal_result,
        qu.photo_urls,
            qu.deal_name,
            qu.deal_time,
            CASE
src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -222,7 +222,7 @@
        unit,
        product_name,
        product_id
        order by combined.create_time desc
        order by MAX(create_time) desc
    </select>
    <select id="listStockInventoryExportData" resultType="com.ruoyi.stock.execl.StockInventoryExportData">