Commit b26ff0d722445a4fdfbb747ba7675f102b6518f3

Authored by YunaiV
1 parent c093da8c

feat(mes): 重构 IQC 缺陷记录为通用质检缺陷记录表,支持多模块复用

将 mes_qc_iqc_defect 重构为通用 mes_qc_defect_record 表,通过 qcType 区分 IQC/IPQC/OQC/RQC,实现多质检模块缺陷记录复用。

主要变更:
1. 新增 MesQcDefectRecordDO、Mapper、Service、Controller 及 VO
2. 删除旧 IQC 独享的缺陷表相关代码(DO/Mapper/Service/Controller/VO 共 8 个文件)
3. 更新 MesQcIqcServiceImpl,替换为通用 MesQcDefectRecordService
4. 新增错误码 QC_DEFECT_RECORD_NOT_EXISTS/LEVEL_UNKNOWN/QC_TYPE_UNSUPPORTED
5. 新增 SQL 建表脚本 mes_qc_defect_record_migration.sql 及测试数据
Showing 17 changed files with 506 additions and 384 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/defect/MesQcDefectRecordController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.qc.defect;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.mes.controller.admin.qc.defect.vo.MesQcDefectRecordPageReqVO;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.qc.defect.vo.MesQcDefectRecordRespVO;
  8 +import cn.iocoder.yudao.module.mes.controller.admin.qc.defect.vo.MesQcDefectRecordSaveReqVO;
  9 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defect.MesQcDefectRecordDO;
  10 +import cn.iocoder.yudao.module.mes.service.qc.defect.MesQcDefectRecordService;
  11 +import io.swagger.v3.oas.annotations.Operation;
  12 +import io.swagger.v3.oas.annotations.Parameter;
  13 +import io.swagger.v3.oas.annotations.tags.Tag;
  14 +import jakarta.annotation.Resource;
  15 +import jakarta.validation.Valid;
  16 +import org.springframework.security.access.prepost.PreAuthorize;
  17 +import org.springframework.validation.annotation.Validated;
  18 +import org.springframework.web.bind.annotation.*;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  21 +
  22 +@Tag(name = "管理后台 - MES 质检缺陷记录")
  23 +@RestController
  24 +@RequestMapping("/mes/qc/defect-record")
  25 +@Validated
  26 +public class MesQcDefectRecordController {
  27 +
  28 + @Resource
  29 + private MesQcDefectRecordService defectRecordService;
  30 +
  31 + // TODO @AI:使用 mes:qc-record:create 权限标识先;不要搞太复杂;当然,也写个 todo @芋艿:说下这个情况
  32 + @PostMapping("/create")
  33 + @Operation(summary = "创建质检缺陷记录")
  34 + @PreAuthorize("@ss.hasPermission('mes:qc-defect-record:create')")
  35 + public CommonResult<Long> createDefectRecord(@Valid @RequestBody MesQcDefectRecordSaveReqVO createReqVO) {
  36 + return success(defectRecordService.createDefectRecord(createReqVO));
  37 + }
  38 +
  39 + @PutMapping("/update")
  40 + @Operation(summary = "更新质检缺陷记录")
  41 + @PreAuthorize("@ss.hasPermission('mes:qc-defect-record:update')")
  42 + public CommonResult<Boolean> updateDefectRecord(@Valid @RequestBody MesQcDefectRecordSaveReqVO updateReqVO) {
  43 + defectRecordService.updateDefectRecord(updateReqVO);
  44 + return success(true);
  45 + }
  46 +
  47 + @DeleteMapping("/delete")
  48 + @Operation(summary = "删除质检缺陷记录")
  49 + @Parameter(name = "id", description = "编号", required = true)
  50 + @PreAuthorize("@ss.hasPermission('mes:qc-defect-record:update')")
  51 + public CommonResult<Boolean> deleteDefectRecord(@RequestParam("id") Long id) {
  52 + defectRecordService.deleteDefectRecord(id);
  53 + return success(true);
  54 + }
  55 +
  56 + @GetMapping("/page")
  57 + @Operation(summary = "获得质检缺陷记录分页")
  58 + @PreAuthorize("@ss.hasPermission('mes:qc-defect-record:query')")
  59 + public CommonResult<PageResult<MesQcDefectRecordRespVO>> getDefectRecordPage(@Valid MesQcDefectRecordPageReqVO pageReqVO) {
  60 + PageResult<MesQcDefectRecordDO> pageResult = defectRecordService.getDefectRecordPage(pageReqVO);
  61 + return success(BeanUtils.toBean(pageResult, MesQcDefectRecordRespVO.class));
  62 + }
  63 +
  64 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/defect/MesQcIqcDefectPageReqVO.java renamed to yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/defect/vo/MesQcDefectRecordPageReqVO.java
1   -package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect;
  1 +package cn.iocoder.yudao.module.mes.controller.admin.qc.defect.vo;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 4 import io.swagger.v3.oas.annotations.media.Schema;
... ... @@ -7,17 +7,21 @@ import lombok.Data;
7 7 import lombok.EqualsAndHashCode;
8 8 import lombok.ToString;
9 9  
10   -@Schema(description = "管理后台 - MES 来料检验缺陷记录分页 Request VO")
  10 +@Schema(description = "管理后台 - MES 质检缺陷记录分页 Request VO")
11 11 @Data
12 12 @EqualsAndHashCode(callSuper = true)
13 13 @ToString(callSuper = true)
14   -public class MesQcIqcDefectPageReqVO extends PageParam {
  14 +public class MesQcDefectRecordPageReqVO extends PageParam {
15 15  
16   - @Schema(description = "来料检验单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
17   - @NotNull(message = "来料检验单 ID 不能为空")
18   - private Long iqcId;
  16 + @Schema(description = "检验类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  17 + @NotNull(message = "检验类型不能为空")
  18 + private Integer qcType;
19 19  
20   - @Schema(description = "来料检验行 ID", example = "200")
  20 + @Schema(description = "检验单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  21 + @NotNull(message = "检验单 ID 不能为空")
  22 + private Long qcId;
  23 +
  24 + @Schema(description = "检验行 ID", example = "200")
21 25 private Long lineId;
22 26  
23 27 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/defect/MesQcIqcDefectRespVO.java renamed to yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/defect/vo/MesQcDefectRecordRespVO.java
1   -package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect;
  1 +package cn.iocoder.yudao.module.mes.controller.admin.qc.defect.vo;
2 2  
3 3 import io.swagger.v3.oas.annotations.media.Schema;
4 4 import lombok.Data;
5 5  
6 6 import java.time.LocalDateTime;
7 7  
8   -@Schema(description = "管理后台 - MES 来料检验缺陷记录 Response VO")
  8 +@Schema(description = "管理后台 - MES 质检缺陷记录 Response VO")
9 9 @Data
10   -public class MesQcIqcDefectRespVO {
  10 +public class MesQcDefectRecordRespVO {
11 11  
12 12 @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
13 13 private Long id;
14 14  
15   - @Schema(description = "来料检验单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
16   - private Long iqcId;
  15 + @Schema(description = "检验类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  16 + private Integer qcType;
17 17  
18   - @Schema(description = "来料检验行 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
  18 + @Schema(description = "检验单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  19 + private Long qcId;
  20 +
  21 + @Schema(description = "检验行 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
19 22 private Long lineId;
20 23  
21 24 @Schema(description = "缺陷描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "表面划伤")
22   - private String defectName;
  25 + private String name;
23 26  
24 27 @Schema(description = "缺陷等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
25   - private Integer defectLevel;
  28 + private Integer level;
26 29  
27 30 @Schema(description = "缺陷数量", example = "1")
28   - private Integer defectQuantity;
  31 + private Integer quantity;
29 32  
30 33 @Schema(description = "备注", example = "备注")
31 34 private String remark;
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/defect/vo/MesQcDefectRecordSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.qc.defect.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.validation.InEnum;
  4 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
  5 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
  6 +import io.swagger.v3.oas.annotations.media.Schema;
  7 +import jakarta.validation.constraints.NotEmpty;
  8 +import jakarta.validation.constraints.NotNull;
  9 +import lombok.Data;
  10 +
  11 +@Schema(description = "管理后台 - MES 质检缺陷记录新增/修改 Request VO")
  12 +@Data
  13 +public class MesQcDefectRecordSaveReqVO {
  14 +
  15 + @Schema(description = "编号", example = "1024")
  16 + private Long id;
  17 +
  18 + @Schema(description = "检验类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  19 + @NotNull(message = "检验类型不能为空")
  20 + @InEnum(MesQcTypeEnum.class)
  21 + private Integer qcType;
  22 +
  23 + @Schema(description = "检验单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  24 + @NotNull(message = "检验单 ID 不能为空")
  25 + private Long qcId;
  26 +
  27 + @Schema(description = "检验行 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
  28 + @NotNull(message = "检验行 ID 不能为空")
  29 + private Long lineId;
  30 +
  31 + @Schema(description = "缺陷描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "表面划伤")
  32 + @NotEmpty(message = "缺陷描述不能为空")
  33 + private String name;
  34 +
  35 + @Schema(description = "缺陷等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  36 + @NotNull(message = "缺陷等级不能为空")
  37 + @InEnum(MesQcDefectLevelEnum.class)
  38 + private Integer level;
  39 +
  40 + @Schema(description = "缺陷数量", example = "1")
  41 + private Integer quantity;
  42 +
  43 + @Schema(description = "备注", example = "备注")
  44 + private String remark;
  45 +
  46 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/MesQcIqcDefectController.java deleted
1   -package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc;
2   -
3   -import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6   -import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect.MesQcIqcDefectPageReqVO;
7   -import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect.MesQcIqcDefectRespVO;
8   -import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect.MesQcIqcDefectSaveReqVO;
9   -import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcDefectDO;
10   -import cn.iocoder.yudao.module.mes.service.qc.lqc.MesQcIqcDefectService;
11   -import io.swagger.v3.oas.annotations.Operation;
12   -import io.swagger.v3.oas.annotations.Parameter;
13   -import io.swagger.v3.oas.annotations.tags.Tag;
14   -import jakarta.annotation.Resource;
15   -import jakarta.validation.Valid;
16   -import org.springframework.security.access.prepost.PreAuthorize;
17   -import org.springframework.validation.annotation.Validated;
18   -import org.springframework.web.bind.annotation.*;
19   -
20   -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
21   -
22   -@Tag(name = "管理后台 - MES 来料检验缺陷记录")
23   -@RestController
24   -@RequestMapping("/mes/qc/iqc/defect")
25   -@Validated
26   -public class MesQcIqcDefectController {
27   -
28   - @Resource
29   - private MesQcIqcDefectService iqcDefectService;
30   -
31   - @PostMapping("/create")
32   - @Operation(summary = "创建来料检验缺陷记录")
33   - @PreAuthorize("@ss.hasPermission('mes:qc-iqc:create')")
34   - public CommonResult<Long> createIqcDefect(@Valid @RequestBody MesQcIqcDefectSaveReqVO createReqVO) {
35   - return success(iqcDefectService.createIqcDefect(createReqVO));
36   - }
37   -
38   - @PutMapping("/update")
39   - @Operation(summary = "更新来料检验缺陷记录")
40   - @PreAuthorize("@ss.hasPermission('mes:qc-iqc:update')")
41   - public CommonResult<Boolean> updateIqcDefect(@Valid @RequestBody MesQcIqcDefectSaveReqVO updateReqVO) {
42   - iqcDefectService.updateIqcDefect(updateReqVO);
43   - return success(true);
44   - }
45   -
46   - @DeleteMapping("/delete")
47   - @Operation(summary = "删除来料检验缺陷记录")
48   - @Parameter(name = "id", description = "编号", required = true)
49   - @PreAuthorize("@ss.hasPermission('mes:qc-iqc:update')")
50   - public CommonResult<Boolean> deleteIqcDefect(@RequestParam("id") Long id) {
51   - iqcDefectService.deleteIqcDefect(id);
52   - return success(true);
53   - }
54   -
55   - @GetMapping("/page")
56   - @Operation(summary = "获得来料检验缺陷记录分页")
57   - @PreAuthorize("@ss.hasPermission('mes:qc-iqc:query')")
58   - public CommonResult<PageResult<MesQcIqcDefectRespVO>> getIqcDefectPage(@Valid MesQcIqcDefectPageReqVO pageReqVO) {
59   - PageResult<MesQcIqcDefectDO> pageResult = iqcDefectService.getIqcDefectPage(pageReqVO);
60   - return success(BeanUtils.toBean(pageResult, MesQcIqcDefectRespVO.class));
61   - }
62   -
63   -}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/defect/MesQcIqcDefectSaveReqVO.java deleted
1   -package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect;
2   -
3   -import io.swagger.v3.oas.annotations.media.Schema;
4   -import jakarta.validation.constraints.NotEmpty;
5   -import jakarta.validation.constraints.NotNull;
6   -import lombok.Data;
7   -
8   -@Schema(description = "管理后台 - MES 来料检验缺陷记录新增/修改 Request VO")
9   -@Data
10   -public class MesQcIqcDefectSaveReqVO {
11   -
12   - @Schema(description = "编号", example = "1024")
13   - private Long id;
14   -
15   - @Schema(description = "来料检验单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
16   - @NotNull(message = "来料检验单 ID 不能为空")
17   - private Long iqcId;
18   -
19   - @Schema(description = "来料检验行 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
20   - @NotNull(message = "来料检验行 ID 不能为空")
21   - private Long lineId;
22   -
23   - @Schema(description = "缺陷描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "表面划伤")
24   - @NotEmpty(message = "缺陷描述不能为空")
25   - private String defectName;
26   -
27   - @Schema(description = "缺陷等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
28   - @NotNull(message = "缺陷等级不能为空")
29   - private Integer defectLevel;
30   -
31   - @Schema(description = "缺陷数量", example = "1")
32   - private Integer defectQuantity;
33   -
34   - @Schema(description = "备注", example = "备注")
35   - private String remark;
36   -
37   -}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/defect/MesQcDefectDO.java
... ... @@ -34,12 +34,16 @@ public class MesQcDefectDO extends BaseDO {
34 34 * 缺陷描述
35 35 */
36 36 private String name;
  37 + // TODO @AI:改成 mes_defect_type;字典 sql 变更;另外,dict constants 里也写下
  38 + // TODO @AI:枚举类;
37 39 /**
38 40 * 检测项类型
39 41 *
40 42 * 字典类型 mes_index_type
41 43 */
42 44 private String type;
  45 + // TODO @AI:改成 mes_defect_level;另外,dict constants 里也写下
  46 + // TODO @AI:枚举类;
43 47 /**
44 48 * 缺陷等级
45 49 *
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/lqc/MesQcIqcDefectDO.java renamed to yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/defect/MesQcDefectRecordDO.java
1   -package cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc;
  1 +package cn.iocoder.yudao.module.mes.dal.dataobject.qc.defect;
2 2  
3 3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcDO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.ipqc.MesQcIpqcLineDO;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcDO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcLineDO;
  8 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
  9 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
4 10 import com.baomidou.mybatisplus.annotation.KeySequence;
5 11 import com.baomidou.mybatisplus.annotation.TableId;
6 12 import com.baomidou.mybatisplus.annotation.TableName;
7 13 import lombok.*;
8 14  
9 15 /**
10   - * MES 来料检验缺陷记录 DO
  16 + * MES 质检缺陷记录 DO
  17 + *
  18 + * 通用缺陷记录表,通过 {@link #qcType} 区分检验类型(IQC、IPQC、OQC、RQC),多模块复用
11 19 *
12 20 * @author 芋道源码
13 21 */
14   -@TableName("mes_qc_iqc_defect")
15   -@KeySequence("mes_qc_iqc_defect_seq")
  22 +@TableName("mes_qc_defect_record")
  23 +@KeySequence("mes_qc_defect_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
16 24 @Data
17 25 @EqualsAndHashCode(callSuper = true)
18 26 @ToString(callSuper = true)
19 27 @Builder
20 28 @NoArgsConstructor
21 29 @AllArgsConstructor
22   -public class MesQcIqcDefectDO extends BaseDO {
  30 +public class MesQcDefectRecordDO extends BaseDO {
23 31  
24 32 /**
25 33 * 编号
... ... @@ -27,31 +35,39 @@ public class MesQcIqcDefectDO extends BaseDO {
27 35 @TableId
28 36 private Long id;
29 37 /**
30   - * 来料检验单 ID
  38 + * 检验类型
  39 + *
  40 + * 枚举 {@link MesQcTypeEnum}
  41 + */
  42 + private Integer qcType;
  43 + /**
  44 + * 检验单 ID
31 45 *
32 46 * 关联 {@link MesQcIqcDO#getId()}
  47 + * 关联 {@link MesQcIpqcDO#getId()}
33 48 */
34   - private Long iqcId;
  49 + private Long qcId;
35 50 /**
36   - * 来料检验行 ID
  51 + * 检验行 ID
37 52 *
38 53 * 关联 {@link MesQcIqcLineDO#getId()}
  54 + * 关联 {@link MesQcIpqcLineDO#getId()}
39 55 */
40 56 private Long lineId;
41 57 /**
42 58 * 缺陷描述
43 59 */
44   - private String defectName;
  60 + private String name;
45 61 /**
46 62 * 缺陷等级
47 63 *
48   - * 枚举 {@link cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum}
  64 + * 枚举 {@link MesQcDefectLevelEnum}
49 65 */
50   - private Integer defectLevel;
  66 + private Integer level;
51 67 /**
52 68 * 缺陷数量
53 69 */
54   - private Integer defectQuantity;
  70 + private Integer quantity;
55 71 /**
56 72 * 备注
57 73 */
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/defect/MesQcDefectRecordMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.mysql.qc.defect;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.mes.controller.admin.qc.defect.vo.MesQcDefectRecordPageReqVO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defect.MesQcDefectRecordDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * MES 质检缺陷记录 Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface MesQcDefectRecordMapper extends BaseMapperX<MesQcDefectRecordDO> {
  19 +
  20 + default PageResult<MesQcDefectRecordDO> selectPage(MesQcDefectRecordPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<MesQcDefectRecordDO>()
  22 + .eqIfPresent(MesQcDefectRecordDO::getQcType, reqVO.getQcType())
  23 + .eqIfPresent(MesQcDefectRecordDO::getQcId, reqVO.getQcId())
  24 + .eqIfPresent(MesQcDefectRecordDO::getLineId, reqVO.getLineId())
  25 + .orderByDesc(MesQcDefectRecordDO::getId));
  26 + }
  27 +
  28 + default List<MesQcDefectRecordDO> selectListByQcTypeAndQcId(Integer qcType, Long qcId) {
  29 + return selectList(new LambdaQueryWrapperX<MesQcDefectRecordDO>()
  30 + .eq(MesQcDefectRecordDO::getQcType, qcType)
  31 + .eq(MesQcDefectRecordDO::getQcId, qcId));
  32 + }
  33 +
  34 + default List<MesQcDefectRecordDO> selectListByQcTypeAndQcIdAndLineId(Integer qcType, Long qcId, Long lineId) {
  35 + return selectList(new LambdaQueryWrapperX<MesQcDefectRecordDO>()
  36 + .eq(MesQcDefectRecordDO::getQcType, qcType)
  37 + .eq(MesQcDefectRecordDO::getQcId, qcId)
  38 + .eq(MesQcDefectRecordDO::getLineId, lineId));
  39 + }
  40 +
  41 + default void deleteByQcTypeAndQcId(Integer qcType, Long qcId) {
  42 + delete(new LambdaQueryWrapperX<MesQcDefectRecordDO>()
  43 + .eq(MesQcDefectRecordDO::getQcType, qcType)
  44 + .eq(MesQcDefectRecordDO::getQcId, qcId));
  45 + }
  46 +
  47 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/lqc/MesQcIqcDefectMapper.java deleted
1   -package cn.iocoder.yudao.module.mes.dal.mysql.qc.lqc;
2   -
3   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5   -import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6   -import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect.MesQcIqcDefectPageReqVO;
7   -import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcDefectDO;
8   -import org.apache.ibatis.annotations.Mapper;
9   -
10   -import java.util.List;
11   -
12   -/**
13   - * MES 来料检验缺陷记录 Mapper
14   - *
15   - * @author 芋道源码
16   - */
17   -@Mapper
18   -public interface MesQcIqcDefectMapper extends BaseMapperX<MesQcIqcDefectDO> {
19   -
20   - default PageResult<MesQcIqcDefectDO> selectPage(MesQcIqcDefectPageReqVO reqVO) {
21   - return selectPage(reqVO, new LambdaQueryWrapperX<MesQcIqcDefectDO>()
22   - .eqIfPresent(MesQcIqcDefectDO::getIqcId, reqVO.getIqcId())
23   - .eqIfPresent(MesQcIqcDefectDO::getLineId, reqVO.getLineId())
24   - .orderByDesc(MesQcIqcDefectDO::getId));
25   - }
26   -
27   - default List<MesQcIqcDefectDO> selectListByIqcId(Long iqcId) {
28   - return selectList(MesQcIqcDefectDO::getIqcId, iqcId);
29   - }
30   -
31   - default List<MesQcIqcDefectDO> selectListByIqcIdAndLineId(Long iqcId, Long lineId) {
32   - return selectList(new LambdaQueryWrapperX<MesQcIqcDefectDO>()
33   - .eq(MesQcIqcDefectDO::getIqcId, iqcId)
34   - .eq(MesQcIqcDefectDO::getLineId, lineId));
35   - }
36   -
37   - default void deleteByIqcId(Long iqcId) {
38   - delete(new LambdaQueryWrapperX<MesQcIqcDefectDO>()
39   - .eq(MesQcIqcDefectDO::getIqcId, iqcId));
40   - }
41   -
42   -}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
... ... @@ -252,9 +252,20 @@ public interface ErrorCodeConstants {
252 252 ErrorCode QC_IQC_NO_TEMPLATE = new ErrorCode(1_040_603_005, "当前产品未配置 IQC 检测模板");
253 253 // ========== MES 质量管理-来料检验行(1-040-603-100) ==========
254 254 ErrorCode QC_IQC_LINE_NOT_EXISTS = new ErrorCode(1_040_603_100, "来料检验行不存在");
255   - // ========== MES 质量管理-来料检验缺陷(1-040-603-200) ==========
256   - ErrorCode QC_IQC_DEFECT_NOT_EXISTS = new ErrorCode(1_040_603_200, "来料检验缺陷记录不存在");
257   - ErrorCode QC_IQC_DEFECT_LEVEL_UNKNOWN = new ErrorCode(1_040_603_201, "未知的缺陷等级");
  255 +
  256 + // ========== MES 质量管理-过程检验 IPQC(1-040-604-000) ==========
  257 + ErrorCode QC_IPQC_NOT_EXISTS = new ErrorCode(1_040_604_000, "过程检验单不存在");
  258 + ErrorCode QC_IPQC_CODE_DUPLICATE = new ErrorCode(1_040_604_001, "过程检验单编号已存在");
  259 + ErrorCode QC_IPQC_NOT_PREPARE = new ErrorCode(1_040_604_002, "只有草稿状态的检验单才可操作");
  260 + ErrorCode QC_IPQC_QUANTITY_MISMATCH = new ErrorCode(1_040_604_004, "合格品与不合格品数量之和须等于检测数量");
  261 + ErrorCode QC_IPQC_NO_TEMPLATE = new ErrorCode(1_040_604_005, "当前产品未配置 IPQC 检测模板");
  262 + // ========== MES 质量管理-过程检验行(1-040-604-100) ==========
  263 + ErrorCode QC_IPQC_LINE_NOT_EXISTS = new ErrorCode(1_040_604_100, "过程检验行不存在");
  264 +
  265 + // ========== MES 质量管理-质检缺陷记录(通用)(1-040-605-000) ==========
  266 + ErrorCode QC_DEFECT_RECORD_NOT_EXISTS = new ErrorCode(1_040_605_000, "缺陷记录不存在");
  267 + ErrorCode QC_DEFECT_RECORD_LEVEL_UNKNOWN = new ErrorCode(1_040_605_001, "未知的缺陷等级");
  268 + ErrorCode QC_DEFECT_RECORD_QC_TYPE_UNSUPPORTED = new ErrorCode(1_040_605_002, "不支持的检验类型");
258 269  
259 270 // ========== MES 仓库管理-仓库(1-040-700-000) ==========
260 271 ErrorCode WM_WAREHOUSE_NOT_EXISTS = new ErrorCode(1_040_700_000, "仓库不存在");
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/lqc/MesQcIqcDefectService.java renamed to yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/defect/MesQcDefectRecordService.java
1   -package cn.iocoder.yudao.module.mes.service.qc.lqc;
  1 +package cn.iocoder.yudao.module.mes.service.qc.defect;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4   -import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect.MesQcIqcDefectPageReqVO;
5   -import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect.MesQcIqcDefectSaveReqVO;
6   -import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcDefectDO;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.qc.defect.vo.MesQcDefectRecordPageReqVO;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.qc.defect.vo.MesQcDefectRecordSaveReqVO;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defect.MesQcDefectRecordDO;
7 7 import jakarta.validation.Valid;
8 8  
9 9 /**
10   - * MES 来料检验缺陷记录 Service 接口
  10 + * MES 质检缺陷记录 Service 接口
11 11 *
12 12 * @author 芋道源码
13 13 */
14   -public interface MesQcIqcDefectService {
  14 +public interface MesQcDefectRecordService {
15 15  
16 16 /**
17   - * 创建来料检验缺陷记录
  17 + * 创建质检缺陷记录
18 18 *
19 19 * @param createReqVO 创建信息
20 20 * @return 编号
21 21 */
22   - Long createIqcDefect(@Valid MesQcIqcDefectSaveReqVO createReqVO);
  22 + Long createDefectRecord(@Valid MesQcDefectRecordSaveReqVO createReqVO);
23 23  
24 24 /**
25   - * 更新来料检验缺陷记录
  25 + * 更新质检缺陷记录
26 26 *
27 27 * @param updateReqVO 更新信息
28 28 */
29   - void updateIqcDefect(@Valid MesQcIqcDefectSaveReqVO updateReqVO);
  29 + void updateDefectRecord(@Valid MesQcDefectRecordSaveReqVO updateReqVO);
30 30  
31 31 /**
32   - * 删除来料检验缺陷记录
  32 + * 删除质检缺陷记录
33 33 *
34 34 * @param id 编号
35 35 */
36   - void deleteIqcDefect(Long id);
  36 + void deleteDefectRecord(Long id);
37 37  
38 38 /**
39   - * 获得来料检验缺陷记录分页
  39 + * 获得质检缺陷记录分页
40 40 *
41 41 * @param pageReqVO 分页查询
42   - * @return 来料检验缺陷记录分页
  42 + * @return 质检缺陷记录分页
43 43 */
44   - PageResult<MesQcIqcDefectDO> getIqcDefectPage(MesQcIqcDefectPageReqVO pageReqVO);
  44 + PageResult<MesQcDefectRecordDO> getDefectRecordPage(MesQcDefectRecordPageReqVO pageReqVO);
45 45  
46 46 /**
47   - * 根据来料检验单 ID 级联删除所有缺陷记录
  47 + * 根据检验类型和检验单 ID 级联删除所有缺陷记录
48 48 *
49   - * @param iqcId 来料检验单 ID
  49 + * @param qcType 检验类型
  50 + * @param qcId 检验单 ID
50 51 */
51   - void deleteByIqcId(Long iqcId);
  52 + void deleteByQcTypeAndQcId(Integer qcType, Long qcId);
52 53  
53 54 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/defect/MesQcDefectRecordServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.qc.defect;
  2 +
  3 +import cn.hutool.core.util.ObjUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.mes.controller.admin.qc.defect.vo.MesQcDefectRecordPageReqVO;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.qc.defect.vo.MesQcDefectRecordSaveReqVO;
  8 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defect.MesQcDefectRecordDO;
  9 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcDO;
  10 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcLineDO;
  11 +import cn.iocoder.yudao.module.mes.dal.mysql.qc.defect.MesQcDefectRecordMapper;
  12 +import cn.iocoder.yudao.module.mes.dal.mysql.qc.lqc.MesQcIqcMapper;
  13 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
  14 +import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
  15 +import cn.iocoder.yudao.module.mes.service.qc.lqc.MesQcIqcLineService;
  16 +import jakarta.annotation.Resource;
  17 +import org.springframework.context.annotation.Lazy;
  18 +import org.springframework.stereotype.Service;
  19 +import org.springframework.transaction.annotation.Transactional;
  20 +import org.springframework.validation.annotation.Validated;
  21 +
  22 +import java.math.BigDecimal;
  23 +import java.math.RoundingMode;
  24 +import java.util.ArrayList;
  25 +import java.util.List;
  26 +import java.util.Objects;
  27 +
  28 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  29 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
  30 +
  31 +/**
  32 + * MES 质检缺陷记录 Service 实现类
  33 + *
  34 + * @author 芋道源码
  35 + */
  36 +@Service
  37 +@Validated
  38 +public class MesQcDefectRecordServiceImpl implements MesQcDefectRecordService {
  39 +
  40 + @Resource
  41 + private MesQcDefectRecordMapper defectRecordMapper;
  42 +
  43 + // TODO @AI:不要调用 mapper,调用对方的 service;
  44 + @Resource
  45 + private MesQcIqcMapper iqcMapper;
  46 + @Resource
  47 + @Lazy
  48 + private MesQcIqcLineService iqcLineService;
  49 +
  50 + @Override
  51 + @Transactional(rollbackFor = Exception.class)
  52 + public Long createDefectRecord(MesQcDefectRecordSaveReqVO createReqVO) {
  53 + // 1. 校验主表和行表存在
  54 + validateQcExists(createReqVO.getQcType(), createReqVO.getQcId());
  55 + validateQcLineExists(createReqVO.getQcType(), createReqVO.getLineId());
  56 +
  57 + // 2. 插入
  58 + MesQcDefectRecordDO record = BeanUtils.toBean(createReqVO, MesQcDefectRecordDO.class);
  59 + defectRecordMapper.insert(record);
  60 +
  61 + // 3. 重新计算缺陷统计
  62 + recalculateDefectStats(createReqVO.getQcType(), createReqVO.getQcId());
  63 + return record.getId();
  64 + }
  65 +
  66 + @Override
  67 + @Transactional(rollbackFor = Exception.class)
  68 + public void updateDefectRecord(MesQcDefectRecordSaveReqVO updateReqVO) {
  69 + // 1. 校验存在
  70 + validateDefectRecordExists(updateReqVO.getId());
  71 +
  72 + // 2. 更新
  73 + MesQcDefectRecordDO updateObj = BeanUtils.toBean(updateReqVO, MesQcDefectRecordDO.class);
  74 + defectRecordMapper.updateById(updateObj);
  75 +
  76 + // 3. 重新计算缺陷统计
  77 + recalculateDefectStats(updateReqVO.getQcType(), updateReqVO.getQcId());
  78 + }
  79 +
  80 + @Override
  81 + @Transactional(rollbackFor = Exception.class)
  82 + public void deleteDefectRecord(Long id) {
  83 + // 1. 校验存在
  84 + MesQcDefectRecordDO record = validateDefectRecordExists(id);
  85 +
  86 + // 2. 删除
  87 + defectRecordMapper.deleteById(id);
  88 +
  89 + // 3. 重新计算缺陷统计
  90 + recalculateDefectStats(record.getQcType(), record.getQcId());
  91 + }
  92 +
  93 + @Override
  94 + public PageResult<MesQcDefectRecordDO> getDefectRecordPage(MesQcDefectRecordPageReqVO pageReqVO) {
  95 + return defectRecordMapper.selectPage(pageReqVO);
  96 + }
  97 +
  98 + @Override
  99 + public void deleteByQcTypeAndQcId(Integer qcType, Long qcId) {
  100 + defectRecordMapper.deleteByQcTypeAndQcId(qcType, qcId);
  101 + }
  102 +
  103 + // ==================== 校验方法 ====================
  104 +
  105 + // TODO @AI:validateQcExists、validateQcLineExists 合并成一个方法;然后调用对应的 service 方法;
  106 + private void validateQcExists(Integer qcType, Long qcId) {
  107 + if (Objects.equals(qcType, MesQcTypeEnum.IQC.getType())) {
  108 + if (iqcMapper.selectById(qcId) == null) {
  109 + throw exception(QC_IQC_NOT_EXISTS);
  110 + }
  111 + } else {
  112 + // 后续扩展:IPQC、OQC、RQC
  113 + throw exception(QC_DEFECT_RECORD_QC_TYPE_UNSUPPORTED);
  114 + }
  115 + }
  116 +
  117 + // TODO @AI:去掉这个,相信调用方
  118 + private void validateQcLineExists(Integer qcType, Long lineId) {
  119 + if (Objects.equals(qcType, MesQcTypeEnum.IQC.getType())) {
  120 + MesQcIqcLineDO line = iqcLineService.getIqcLine(lineId);
  121 + if (line == null) {
  122 + throw exception(QC_IQC_LINE_NOT_EXISTS);
  123 + }
  124 + } else {
  125 + // 后续扩展:IPQC、OQC、RQC
  126 + throw exception(QC_DEFECT_RECORD_QC_TYPE_UNSUPPORTED);
  127 + }
  128 + }
  129 +
  130 + private MesQcDefectRecordDO validateDefectRecordExists(Long id) {
  131 + MesQcDefectRecordDO record = defectRecordMapper.selectById(id);
  132 + if (record == null) {
  133 + throw exception(QC_DEFECT_RECORD_NOT_EXISTS);
  134 + }
  135 + return record;
  136 + }
  137 +
  138 + // ==================== 缺陷统计 ====================
  139 +
  140 + /**
  141 + * 重新计算缺陷统计(行级 + 主表级)
  142 + *
  143 + * @param qcType 检验类型
  144 + * @param qcId 检验单 ID
  145 + */
  146 + @SuppressWarnings("DuplicatedCode")
  147 + private void recalculateDefectStats(Integer qcType, Long qcId) {
  148 + // 1. 查询所有缺陷记录
  149 + List<MesQcDefectRecordDO> records = defectRecordMapper.selectListByQcTypeAndQcId(qcType, qcId);
  150 +
  151 + if (Objects.equals(qcType, MesQcTypeEnum.IQC.getType())) {
  152 + // TODO @AI:直接调用 iqcservice 方法;qcId、records
  153 + recalculateIqcDefectStats(qcId, records);
  154 + } else {
  155 + // 后续扩展:IPQC、OQC、RQC
  156 + throw exception(QC_DEFECT_RECORD_QC_TYPE_UNSUPPORTED);
  157 + }
  158 + }
  159 +
  160 + /**
  161 + * IQC 缺陷统计重算
  162 + */
  163 + private void recalculateIqcDefectStats(Long qcId, List<MesQcDefectRecordDO> records) {
  164 + // 1. 按行汇总缺陷数量,批量更新
  165 + // TODO @AI:1 这块的逻辑,放到 iqcLineService 里,使用 qcId、records;
  166 + List<MesQcIqcLineDO> lines = iqcLineService.selectListByIqcId(qcId);
  167 + List<MesQcIqcLineDO> updateLines = new ArrayList<>();
  168 + for (MesQcIqcLineDO line : lines) {
  169 + int critical = 0, major = 0, minor = 0;
  170 + for (MesQcDefectRecordDO record : records) {
  171 + if (ObjUtil.notEqual(record.getLineId(), line.getId())) {
  172 + continue;
  173 + }
  174 + int quantity = ObjUtil.defaultIfNull(record.getQuantity(), 1);
  175 + if (Objects.equals(record.getLevel(), MesQcDefectLevelEnum.CRITICAL.getType())) {
  176 + critical += quantity;
  177 + } else if (Objects.equals(record.getLevel(), MesQcDefectLevelEnum.MAJOR.getType())) {
  178 + major += quantity;
  179 + } else if (Objects.equals(record.getLevel(), MesQcDefectLevelEnum.MINOR.getType())) {
  180 + minor += quantity;
  181 + } else {
  182 + throw exception(QC_DEFECT_RECORD_LEVEL_UNKNOWN);
  183 + }
  184 + }
  185 + updateLines.add(new MesQcIqcLineDO().setId(line.getId())
  186 + .setCriticalQuantity(critical).setMajorQuantity(major).setMinorQuantity(minor));
  187 + }
  188 + iqcLineService.batchUpdateDefectStats(updateLines);
  189 +
  190 + // 2. 汇总主表的缺陷数量
  191 + // TODO @AI:2-4 这块的逻辑,放到 iqcService 里,使用 qcId、records;
  192 + int totalCritical = 0, totalMajor = 0, totalMinor = 0;
  193 + for (MesQcDefectRecordDO record : records) {
  194 + int quantity = ObjUtil.defaultIfNull(record.getQuantity(), 1);
  195 + if (Objects.equals(record.getLevel(), MesQcDefectLevelEnum.CRITICAL.getType())) {
  196 + totalCritical += quantity;
  197 + } else if (Objects.equals(record.getLevel(), MesQcDefectLevelEnum.MAJOR.getType())) {
  198 + totalMajor += quantity;
  199 + } else if (Objects.equals(record.getLevel(), MesQcDefectLevelEnum.MINOR.getType())) {
  200 + totalMinor += quantity;
  201 + } else {
  202 + throw exception(QC_DEFECT_RECORD_LEVEL_UNKNOWN);
  203 + }
  204 + }
  205 +
  206 + // 3. 计算缺陷率
  207 + MesQcIqcDO iqc = iqcMapper.selectById(qcId);
  208 + BigDecimal criticalRate = BigDecimal.ZERO;
  209 + BigDecimal majorRate = BigDecimal.ZERO;
  210 + BigDecimal minorRate = BigDecimal.ZERO;
  211 + if (iqc != null && iqc.getCheckQuantity() != null && iqc.getCheckQuantity() > 0) {
  212 + BigDecimal checkQty = BigDecimal.valueOf(iqc.getCheckQuantity());
  213 + criticalRate = BigDecimal.valueOf(totalCritical).multiply(BigDecimal.valueOf(100))
  214 + .divide(checkQty, 2, RoundingMode.HALF_UP);
  215 + majorRate = BigDecimal.valueOf(totalMajor).multiply(BigDecimal.valueOf(100))
  216 + .divide(checkQty, 2, RoundingMode.HALF_UP);
  217 + minorRate = BigDecimal.valueOf(totalMinor).multiply(BigDecimal.valueOf(100))
  218 + .divide(checkQty, 2, RoundingMode.HALF_UP);
  219 + }
  220 +
  221 + // 4. 更新主表
  222 + MesQcIqcDO updateIqc = new MesQcIqcDO().setId(qcId)
  223 + .setCriticalQuantity(totalCritical).setMajorQuantity(totalMajor).setMinorQuantity(totalMinor)
  224 + .setCriticalRate(criticalRate).setMajorRate(majorRate).setMinorRate(minorRate);
  225 + iqcMapper.updateById(updateIqc);
  226 + }
  227 +
  228 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/lqc/MesQcIqcDefectServiceImpl.java deleted
1   -package cn.iocoder.yudao.module.mes.service.qc.lqc;
2   -
3   -import cn.hutool.core.util.ObjUtil;
4   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
5   -import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6   -import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect.MesQcIqcDefectPageReqVO;
7   -import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect.MesQcIqcDefectSaveReqVO;
8   -import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcDO;
9   -import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcDefectDO;
10   -import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcLineDO;
11   -import cn.iocoder.yudao.module.mes.dal.mysql.qc.lqc.MesQcIqcDefectMapper;
12   -import cn.iocoder.yudao.module.mes.dal.mysql.qc.lqc.MesQcIqcMapper;
13   -import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum;
14   -import jakarta.annotation.Resource;
15   -import org.springframework.context.annotation.Lazy;
16   -import org.springframework.stereotype.Service;
17   -import org.springframework.transaction.annotation.Transactional;
18   -import org.springframework.validation.annotation.Validated;
19   -
20   -import java.math.BigDecimal;
21   -import java.math.RoundingMode;
22   -import java.util.ArrayList;
23   -import java.util.List;
24   -import java.util.Objects;
25   -
26   -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
27   -import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
28   -
29   -/**
30   - * MES 来料检验缺陷记录 Service 实现类
31   - *
32   - * @author 芋道源码
33   - */
34   -@Service
35   -@Validated
36   -public class MesQcIqcDefectServiceImpl implements MesQcIqcDefectService {
37   -
38   - @Resource
39   - private MesQcIqcDefectMapper iqcDefectMapper;
40   - @Resource
41   - private MesQcIqcMapper iqcMapper;
42   - @Resource
43   - @Lazy
44   - private MesQcIqcLineService iqcLineService;
45   -
46   - @Override
47   - @Transactional(rollbackFor = Exception.class)
48   - public Long createIqcDefect(MesQcIqcDefectSaveReqVO createReqVO) {
49   - // 1.1 校验 IQC 存在
50   - validateIqcExists(createReqVO.getIqcId());
51   - // 1.2 校验行存在
52   - validateIqcLineExists(createReqVO.getLineId());
53   -
54   - // 2. 插入
55   - MesQcIqcDefectDO defect = BeanUtils.toBean(createReqVO, MesQcIqcDefectDO.class);
56   - iqcDefectMapper.insert(defect);
57   -
58   - // 3. 重新计算缺陷统计
59   - recalculateDefectStats(createReqVO.getIqcId());
60   - return defect.getId();
61   - }
62   -
63   - @Override
64   - @Transactional(rollbackFor = Exception.class)
65   - public void updateIqcDefect(MesQcIqcDefectSaveReqVO updateReqVO) {
66   - // 1. 校验存在
67   - validateIqcDefectExists(updateReqVO.getId());
68   -
69   - // 2. 更新
70   - MesQcIqcDefectDO updateObj = BeanUtils.toBean(updateReqVO, MesQcIqcDefectDO.class);
71   - iqcDefectMapper.updateById(updateObj);
72   -
73   - // 3. 重新计算缺陷统计
74   - recalculateDefectStats(updateReqVO.getIqcId());
75   - }
76   -
77   - @Override
78   - @Transactional(rollbackFor = Exception.class)
79   - public void deleteIqcDefect(Long id) {
80   - // 1. 校验存在
81   - MesQcIqcDefectDO defect = validateIqcDefectExists(id);
82   -
83   - // 2. 删除
84   - iqcDefectMapper.deleteById(id);
85   -
86   - // 3. 重新计算缺陷统计
87   - recalculateDefectStats(defect.getIqcId());
88   - }
89   -
90   - @Override
91   - public PageResult<MesQcIqcDefectDO> getIqcDefectPage(MesQcIqcDefectPageReqVO pageReqVO) {
92   - return iqcDefectMapper.selectPage(pageReqVO);
93   - }
94   -
95   - @Override
96   - public void deleteByIqcId(Long iqcId) {
97   - iqcDefectMapper.deleteByIqcId(iqcId);
98   - }
99   -
100   - private void validateIqcExists(Long iqcId) {
101   - if (iqcMapper.selectById(iqcId) == null) {
102   - throw exception(QC_IQC_NOT_EXISTS);
103   - }
104   - }
105   -
106   - private void validateIqcLineExists(Long lineId) {
107   - MesQcIqcLineDO line = iqcLineService.getIqcLine(lineId);
108   - if (line == null) {
109   - throw exception(QC_IQC_LINE_NOT_EXISTS);
110   - }
111   - }
112   -
113   - private MesQcIqcDefectDO validateIqcDefectExists(Long id) {
114   - MesQcIqcDefectDO defect = iqcDefectMapper.selectById(id);
115   - if (defect == null) {
116   - throw exception(QC_IQC_DEFECT_NOT_EXISTS);
117   - }
118   - return defect;
119   - }
120   -
121   - /**
122   - * 重新计算缺陷统计(行级 + 主表级)
123   - *
124   - * @param iqcId 来料检验单 ID
125   - */
126   - @SuppressWarnings("DuplicatedCode")
127   - private void recalculateDefectStats(Long iqcId) {
128   - // 1. 查询所有缺陷记录
129   - List<MesQcIqcDefectDO> defects = iqcDefectMapper.selectListByIqcId(iqcId);
130   -
131   - // 2. 按行汇总缺陷数量,批量更新
132   - List<MesQcIqcLineDO> lines = iqcLineService.selectListByIqcId(iqcId);
133   - List<MesQcIqcLineDO> updateLines = new ArrayList<>();
134   - for (MesQcIqcLineDO line : lines) {
135   - int critical = 0, major = 0, minor = 0;
136   - for (MesQcIqcDefectDO defect : defects) {
137   - if (ObjUtil.notEqual(defect.getLineId(), line.getId())) {
138   - continue;
139   - }
140   - int quantity = ObjUtil.defaultIfNull(defect.getDefectQuantity(), 1);
141   - if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.CRITICAL.getType())) {
142   - critical += quantity;
143   - } else if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.MAJOR.getType())) {
144   - major += quantity;
145   - } else if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.MINOR.getType())) {
146   - minor += quantity;
147   - } else {
148   - throw exception(QC_IQC_DEFECT_LEVEL_UNKNOWN);
149   - }
150   - }
151   - updateLines.add(new MesQcIqcLineDO().setId(line.getId())
152   - .setCriticalQuantity(critical).setMajorQuantity(major).setMinorQuantity(minor));
153   - }
154   - iqcLineService.batchUpdateDefectStats(updateLines);
155   -
156   - // 3.1 汇总主表的缺陷数量
157   - int totalCritical = 0, totalMajor = 0, totalMinor = 0;
158   - for (MesQcIqcDefectDO defect : defects) {
159   - int quantity = ObjUtil.defaultIfNull(defect.getDefectQuantity(), 1);
160   - if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.CRITICAL.getType())) {
161   - totalCritical += quantity;
162   - } else if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.MAJOR.getType())) {
163   - totalMajor += quantity;
164   - } else if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.MINOR.getType())) {
165   - totalMinor += quantity;
166   - } else {
167   - throw exception(QC_IQC_DEFECT_LEVEL_UNKNOWN);
168   - }
169   - }
170   - // 3.2 计算缺陷率
171   - MesQcIqcDO iqc = iqcMapper.selectById(iqcId);
172   - BigDecimal criticalRate = BigDecimal.ZERO;
173   - BigDecimal majorRate = BigDecimal.ZERO;
174   - BigDecimal minorRate = BigDecimal.ZERO;
175   - if (iqc != null && iqc.getCheckQuantity() != null && iqc.getCheckQuantity() > 0) {
176   - BigDecimal checkQty = BigDecimal.valueOf(iqc.getCheckQuantity());
177   - criticalRate = BigDecimal.valueOf(totalCritical).multiply(BigDecimal.valueOf(100))
178   - .divide(checkQty, 2, RoundingMode.HALF_UP);
179   - majorRate = BigDecimal.valueOf(totalMajor).multiply(BigDecimal.valueOf(100))
180   - .divide(checkQty, 2, RoundingMode.HALF_UP);
181   - minorRate = BigDecimal.valueOf(totalMinor).multiply(BigDecimal.valueOf(100))
182   - .divide(checkQty, 2, RoundingMode.HALF_UP);
183   - }
184   - // 3.3 更新主表
185   - MesQcIqcDO updateIqc = new MesQcIqcDO().setId(iqcId)
186   - .setCriticalQuantity(totalCritical).setMajorQuantity(totalMajor).setMinorQuantity(totalMinor)
187   - .setCriticalRate(criticalRate).setMajorRate(majorRate).setMinorRate(minorRate);
188   - iqcMapper.updateById(updateIqc);
189   - }
190   -
191   -}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/lqc/MesQcIqcServiceImpl.java
... ... @@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemD
12 12 import cn.iocoder.yudao.module.mes.dal.mysql.qc.lqc.MesQcIqcMapper;
13 13 import cn.iocoder.yudao.module.mes.enums.qc.MesQcIqcStatusEnum;
14 14 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
  15 +import cn.iocoder.yudao.module.mes.service.qc.defect.MesQcDefectRecordService;
15 16 import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateService;
16 17 import jakarta.annotation.Resource;
17 18 import org.springframework.stereotype.Service;
... ... @@ -38,7 +39,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
38 39 @Resource
39 40 private MesQcIqcLineService iqcLineService;
40 41 @Resource
41   - private MesQcIqcDefectService iqcDefectService;
  42 + private MesQcDefectRecordService defectRecordService;
42 43  
43 44 @Override
44 45 @Transactional(rollbackFor = Exception.class)
... ... @@ -117,7 +118,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
117 118 // 2.2 级联删除行
118 119 iqcLineService.deleteByIqcId(id);
119 120 // 2.3 级联删除缺陷记录
120   - iqcDefectService.deleteByIqcId(id);
  121 + defectRecordService.deleteByQcTypeAndQcId(MesQcTypeEnum.IQC.getType(), id);
121 122 }
122 123  
123 124 /**
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateService.java
... ... @@ -107,6 +107,17 @@ public interface MesQcTemplateService {
107 107 */
108 108 MesQcTemplateItemDO getTemplateItemByTemplateIdAndItemId(Long templateId, Long itemId);
109 109  
  110 + /**
  111 + * 根据产品物料 ID 和 QC 类型查找检验模板
  112 + *
  113 + * 查找逻辑:在 template_item 中找到匹配 itemId 的模板,再校验该模板的 types 包含给定的 qcType
  114 + *
  115 + * @param itemId 产品物料 ID
  116 + * @param qcType 检测种类(枚举 {@link cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum})
  117 + * @return 匹配的检验模板(可能为 null)
  118 + */
  119 + MesQcTemplateDO getTemplateByItemIdAndType(Long itemId, Integer qcType);
  120 +
110 121 // ========== 质检方案-检测指标项 ==========
111 122  
112 123 /**
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateServiceImpl.java
... ... @@ -109,6 +109,25 @@ public class MesQcTemplateServiceImpl implements MesQcTemplateService {
109 109 }
110 110  
111 111 @Override
  112 + public MesQcTemplateDO getTemplateByItemIdAndType(Long itemId, Integer qcType) {
  113 + // 1.1 查出 itemId 关联的所有 templateId
  114 + List<MesQcTemplateItemDO> templateItems = templateItemMapper.selectListByItemId(itemId);
  115 + if (CollUtil.isEmpty(templateItems)) {
  116 + return null;
  117 + }
  118 + // 1.2 批量查模板,筛选 types 包含给定 qcType 的第一个
  119 + // TODO @AI:convertSet;
  120 + List<Long> templateIds = templateItems.stream()
  121 + .map(MesQcTemplateItemDO::getTemplateId).distinct().toList();
  122 + List<MesQcTemplateDO> templates = templateMapper.selectByIds(templateIds);
  123 +
  124 + // 2. 筛选 types 包含给定 qcType 的第一个 TODO @AI:findOne;
  125 + return templates.stream()
  126 + .filter(t -> CollUtil.contains(t.getTypes(), qcType))
  127 + .findFirst().orElse(null);
  128 + }
  129 +
  130 + @Override
112 131 public MesQcTemplateDO getTemplate(Long id) {
113 132 return templateMapper.selectById(id);
114 133 }
... ...