Commit a347943b68595902809f67578fdf5cca84b7f8af

Authored by YunaiV
1 parent 015eab68

feat(mes): 优化缺陷统计计算逻辑,重构模板校验方法,增强代码可读性

yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/lqc/MesQcIqcDefectServiceImpl.java
1 package cn.iocoder.yudao.module.mes.service.qc.lqc; 1 package cn.iocoder.yudao.module.mes.service.qc.lqc;
2 2
  3 +import cn.hutool.core.util.ObjUtil;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect.MesQcIqcDefectPageReqVO; 6 import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect.MesQcIqcDefectPageReqVO;
@@ -124,6 +125,7 @@ public class MesQcIqcDefectServiceImpl implements MesQcIqcDefectService { @@ -124,6 +125,7 @@ public class MesQcIqcDefectServiceImpl implements MesQcIqcDefectService {
124 * 125 *
125 * @param iqcId 来料检验单 ID 126 * @param iqcId 来料检验单 ID
126 */ 127 */
  128 + @SuppressWarnings("DuplicatedCode")
127 private void recalculateDefectStats(Long iqcId) { 129 private void recalculateDefectStats(Long iqcId) {
128 // 1. 查询所有缺陷记录 130 // 1. 查询所有缺陷记录
129 List<MesQcIqcDefectDO> defects = iqcDefectMapper.selectListByIqcId(iqcId); 131 List<MesQcIqcDefectDO> defects = iqcDefectMapper.selectListByIqcId(iqcId);
@@ -131,44 +133,38 @@ public class MesQcIqcDefectServiceImpl implements MesQcIqcDefectService { @@ -131,44 +133,38 @@ public class MesQcIqcDefectServiceImpl implements MesQcIqcDefectService {
131 // 2. 更新每行的缺陷数量 133 // 2. 更新每行的缺陷数量
132 List<MesQcIqcLineDO> lines = iqcLineService.selectListByIqcId(iqcId); 134 List<MesQcIqcLineDO> lines = iqcLineService.selectListByIqcId(iqcId);
133 for (MesQcIqcLineDO line : lines) { 135 for (MesQcIqcLineDO line : lines) {
134 - int critical = 0;  
135 - int major = 0;  
136 - int minor = 0; 136 + int critical = 0, major = 0, minor = 0;
137 for (MesQcIqcDefectDO defect : defects) { 137 for (MesQcIqcDefectDO defect : defects) {
138 - // TODO @AI:notEquals continue;减少括号层级;  
139 - if (Objects.equals(defect.getLineId(), line.getId())) {  
140 - // TODO @AI:defaultIfNull;变量改成 quantity  
141 - int qty = defect.getDefectQuantity() != null ? defect.getDefectQuantity() : 1;  
142 - if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.CRITICAL.getType())) {  
143 - critical += qty;  
144 - } else if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.MAJOR.getType())) {  
145 - major += qty;  
146 - } else if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.MINOR.getType())) {  
147 - minor += qty;  
148 - }  
149 - // TODO @AI:抛出异常;未知的缺陷等级 138 + if (ObjUtil.notEqual(defect.getLineId(), line.getId())) {
  139 + continue;
  140 + }
  141 + int quantity = ObjUtil.defaultIfNull(defect.getDefectQuantity(), 1);
  142 + if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.CRITICAL.getType())) {
  143 + critical += quantity;
  144 + } else if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.MAJOR.getType())) {
  145 + major += quantity;
  146 + } else if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.MINOR.getType())) {
  147 + minor += quantity;
  148 + } else {
  149 + throw exception(QC_IQC_DEFECT_LEVEL_UNKNOWN);
150 } 150 }
151 } 151 }
152 - MesQcIqcLineDO updateLine = new MesQcIqcLineDO().setId(line.getId())  
153 - .setCriticalQuantity(critical).setMajorQuantity(major).setMinorQuantity(minor);  
154 - // 直接通过 lineService 内部更新(避免循环依赖,使用 mapper)  
155 - // TODO @AI:单独搞个 updateLineDefectStats 方法;减少 updateLine 变量的作用域;  
156 - iqcLineMapper.updateById(updateLine); 152 + updateLineDefectStats(line.getId(), critical, major, minor);
157 } 153 }
158 154
159 // 3.1 汇总主表的缺陷数量 155 // 3.1 汇总主表的缺陷数量
160 int totalCritical = 0, totalMajor = 0, totalMinor = 0; 156 int totalCritical = 0, totalMajor = 0, totalMinor = 0;
161 for (MesQcIqcDefectDO defect : defects) { 157 for (MesQcIqcDefectDO defect : defects) {
162 - // TODO @AI:defaultIfNull;变量改成 quantity  
163 - int qty = defect.getDefectQuantity() != null ? defect.getDefectQuantity() : 1; 158 + int quantity = ObjUtil.defaultIfNull(defect.getDefectQuantity(), 1);
164 if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.CRITICAL.getType())) { 159 if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.CRITICAL.getType())) {
165 - totalCritical += qty; 160 + totalCritical += quantity;
166 } else if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.MAJOR.getType())) { 161 } else if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.MAJOR.getType())) {
167 - totalMajor += qty; 162 + totalMajor += quantity;
168 } else if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.MINOR.getType())) { 163 } else if (Objects.equals(defect.getDefectLevel(), MesQcDefectLevelEnum.MINOR.getType())) {
169 - totalMinor += qty; 164 + totalMinor += quantity;
  165 + } else {
  166 + throw exception(QC_IQC_DEFECT_LEVEL_UNKNOWN);
170 } 167 }
171 - // TODO @AI:抛出异常;未知的缺陷等级  
172 } 168 }
173 // 3.2 计算缺陷率 169 // 3.2 计算缺陷率
174 MesQcIqcDO iqc = iqcMapper.selectById(iqcId); 170 MesQcIqcDO iqc = iqcMapper.selectById(iqcId);
@@ -191,4 +187,14 @@ public class MesQcIqcDefectServiceImpl implements MesQcIqcDefectService { @@ -191,4 +187,14 @@ public class MesQcIqcDefectServiceImpl implements MesQcIqcDefectService {
191 iqcMapper.updateById(updateIqc); 187 iqcMapper.updateById(updateIqc);
192 } 188 }
193 189
  190 + // TODO @AI:在 iqclineservice 里,提供一个方法,直接根据行 ID 列表,批量更新缺陷统计数量。然后这里直接调用即可,避免循环更新数据库。
  191 + /**
  192 + * 更新检验行的缺陷统计数量
  193 + */
  194 + private void updateLineDefectStats(Long lineId, int critical, int major, int minor) {
  195 + MesQcIqcLineDO updateLine = new MesQcIqcLineDO().setId(lineId)
  196 + .setCriticalQuantity(critical).setMajorQuantity(major).setMinorQuantity(minor);
  197 + iqcLineMapper.updateById(updateLine);
  198 + }
  199 +
194 } 200 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/lqc/MesQcIqcServiceImpl.java
1 package cn.iocoder.yudao.module.mes.service.qc.lqc; 1 package cn.iocoder.yudao.module.mes.service.qc.lqc;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.hutool.core.util.ObjUtil; 4 import cn.hutool.core.util.ObjUtil;
  5 +import cn.iocoder.yudao.framework.common.exception.ErrorCode;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcPageReqVO; 8 import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcPageReqVO;
@@ -9,17 +11,14 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcDO; @@ -9,17 +11,14 @@ import cn.iocoder.yudao.module.mes.dal.dataobject.qc.lqc.MesQcIqcDO;
9 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateDO; 11 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateDO;
10 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO; 12 import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO;
11 import cn.iocoder.yudao.module.mes.dal.mysql.qc.lqc.MesQcIqcMapper; 13 import cn.iocoder.yudao.module.mes.dal.mysql.qc.lqc.MesQcIqcMapper;
12 -import cn.iocoder.yudao.module.mes.dal.mysql.qc.template.MesQcTemplateItemMapper;  
13 -import cn.iocoder.yudao.module.mes.dal.mysql.qc.template.MesQcTemplateMapper;  
14 import cn.iocoder.yudao.module.mes.enums.qc.MesQcIqcStatusEnum; 14 import cn.iocoder.yudao.module.mes.enums.qc.MesQcIqcStatusEnum;
15 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum; 15 import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum;
  16 +import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateService;
16 import jakarta.annotation.Resource; 17 import jakarta.annotation.Resource;
17 import org.springframework.stereotype.Service; 18 import org.springframework.stereotype.Service;
18 import org.springframework.transaction.annotation.Transactional; 19 import org.springframework.transaction.annotation.Transactional;
19 import org.springframework.validation.annotation.Validated; 20 import org.springframework.validation.annotation.Validated;
20 21
21 -import java.util.Objects;  
22 -  
23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 22 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; 23 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
25 24
@@ -35,9 +34,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -35,9 +34,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
35 @Resource 34 @Resource
36 private MesQcIqcMapper iqcMapper; 35 private MesQcIqcMapper iqcMapper;
37 @Resource 36 @Resource
38 - private MesQcTemplateMapper templateMapper;  
39 - @Resource  
40 - private MesQcTemplateItemMapper templateItemMapper; 37 + private MesQcTemplateService templateService;
41 38
42 @Resource 39 @Resource
43 private MesQcIqcLineService iqcLineService; 40 private MesQcIqcLineService iqcLineService;
@@ -51,16 +48,13 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -51,16 +48,13 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
51 validateIqcCodeUnique(null, createReqVO.getCode()); 48 validateIqcCodeUnique(null, createReqVO.getCode());
52 // 1.2 查找物料关联的 IQC 检测模板 49 // 1.2 查找物料关联的 IQC 检测模板
53 Long templateId = createReqVO.getTemplateId(); 50 Long templateId = createReqVO.getTemplateId();
54 - // TODO @AI:直接使用 templateService 的 validateTemplateExists() 方法,后续如果有更多模板相关的校验,也可以放在该方法中  
55 - MesQcTemplateDO template = templateMapper.selectById(templateId);  
56 - // TODO @AI:CollUtil.contains 这样更合适;  
57 - if (template == null || template.getTypes() == null || !template.getTypes().contains(MesQcTypeEnum.IQC.getType())) { 51 + MesQcTemplateDO template = templateService.validateTemplateExists(templateId);
  52 + if (!CollUtil.contains(template.getTypes(), MesQcTypeEnum.IQC.getType())) {
58 throw exception(QC_IQC_NO_TEMPLATE); 53 throw exception(QC_IQC_NO_TEMPLATE);
59 } 54 }
60 55
61 // 3.1 从模板的产品关联中获取检测参数(min_check_quantity、max_unqualified_quantity) 56 // 3.1 从模板的产品关联中获取检测参数(min_check_quantity、max_unqualified_quantity)
62 - // TODO @AI:使用 templateItemService 方法,不要直接使用对方的 mapper;  
63 - MesQcTemplateItemDO templateItem = templateItemMapper.selectByTemplateIdAndItemId( 57 + MesQcTemplateItemDO templateItem = templateService.getTemplateItemByTemplateIdAndItemId(
64 templateId, createReqVO.getItemId()); 58 templateId, createReqVO.getItemId());
65 if (templateItem != null) { 59 if (templateItem != null) {
66 if (createReqVO.getMinCheckQuantity() == null) { 60 if (createReqVO.getMinCheckQuantity() == null) {
@@ -85,11 +79,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -85,11 +79,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
85 // 1.1 校验存在 79 // 1.1 校验存在
86 MesQcIqcDO iqc = validateIqcExists(updateReqVO.getId()); 80 MesQcIqcDO iqc = validateIqcExists(updateReqVO.getId());
87 // 1.2 校验状态为草稿 81 // 1.2 校验状态为草稿
88 - // TODO @AI:notEquals;  
89 - // TODO @AI:抽成一个方法,这样 completeIqc 和 deleteIqc 也可以复用,避免重复代码;  
90 - if (!Objects.equals(iqc.getStatus(), MesQcIqcStatusEnum.PREPARE.getType())) {  
91 - throw exception(QC_IQC_ONLY_PREPARE_CAN_COMPLETE);  
92 - } 82 + validatePrepareStatus(iqc, QC_IQC_ONLY_PREPARE_CAN_COMPLETE);
93 // 1.3 校验编号唯一 83 // 1.3 校验编号唯一
94 validateIqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); 84 validateIqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
95 85
@@ -103,9 +93,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -103,9 +93,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
103 // 1.1 校验存在 93 // 1.1 校验存在
104 MesQcIqcDO iqc = validateIqcExists(id); 94 MesQcIqcDO iqc = validateIqcExists(id);
105 // 1.2 校验状态为草稿 95 // 1.2 校验状态为草稿
106 - if (!Objects.equals(iqc.getStatus(), MesQcIqcStatusEnum.PREPARE.getType())) {  
107 - throw exception(QC_IQC_ONLY_PREPARE_CAN_COMPLETE);  
108 - } 96 + validatePrepareStatus(iqc, QC_IQC_ONLY_PREPARE_CAN_COMPLETE);
109 // 1.3 校验合格品 + 不合格品 = 检测数量 97 // 1.3 校验合格品 + 不合格品 = 检测数量
110 if (iqc.getCheckQuantity() != null && iqc.getCheckQuantity() > 0) { 98 if (iqc.getCheckQuantity() != null && iqc.getCheckQuantity() > 0) {
111 int total = (iqc.getQualifiedQuantity() != null ? iqc.getQualifiedQuantity() : 0) 99 int total = (iqc.getQualifiedQuantity() != null ? iqc.getQualifiedQuantity() : 0)
@@ -129,9 +117,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -129,9 +117,7 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
129 // 1.1 校验存在 117 // 1.1 校验存在
130 MesQcIqcDO iqc = validateIqcExists(id); 118 MesQcIqcDO iqc = validateIqcExists(id);
131 // 1.2 仅草稿可删 119 // 1.2 仅草稿可删
132 - if (!Objects.equals(iqc.getStatus(), MesQcIqcStatusEnum.PREPARE.getType())) {  
133 - throw exception(QC_IQC_ONLY_PREPARE_CAN_DELETE);  
134 - } 120 + validatePrepareStatus(iqc, QC_IQC_ONLY_PREPARE_CAN_DELETE);
135 121
136 // 2.1 删除主表 122 // 2.1 删除主表
137 iqcMapper.deleteById(id); 123 iqcMapper.deleteById(id);
@@ -149,6 +135,13 @@ public class MesQcIqcServiceImpl implements MesQcIqcService { @@ -149,6 +135,13 @@ public class MesQcIqcServiceImpl implements MesQcIqcService {
149 return iqc; 135 return iqc;
150 } 136 }
151 137
  138 + // TODO @AI:就搞个方法,传递 id 进去;抛出不为 草稿状态的异常;然后在 update/delete/complete 方法中调用这个方法(不用专门 errorCode)
  139 + private void validatePrepareStatus(MesQcIqcDO iqc, ErrorCode errorCode) {
  140 + if (ObjUtil.notEqual(iqc.getStatus(), MesQcIqcStatusEnum.PREPARE.getType())) {
  141 + throw exception(errorCode);
  142 + }
  143 + }
  144 +
152 private void validateIqcCodeUnique(Long id, String code) { 145 private void validateIqcCodeUnique(Long id, String code) {
153 MesQcIqcDO iqc = iqcMapper.selectByCode(code); 146 MesQcIqcDO iqc = iqcMapper.selectByCode(code);
154 if (iqc == null) { 147 if (iqc == null) {
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateService.java
@@ -90,6 +90,23 @@ public interface MesQcTemplateService { @@ -90,6 +90,23 @@ public interface MesQcTemplateService {
90 return convertMap(getTemplateList(ids), MesQcTemplateDO::getId); 90 return convertMap(getTemplateList(ids), MesQcTemplateDO::getId);
91 } 91 }
92 92
  93 + /**
  94 + * 校验质检方案存在
  95 + *
  96 + * @param id 编号
  97 + * @return 质检方案
  98 + */
  99 + MesQcTemplateDO validateTemplateExists(Long id);
  100 +
  101 + /**
  102 + * 根据方案 ID + 产品 ID 获取产品关联
  103 + *
  104 + * @param templateId 方案 ID
  105 + * @param itemId 产品 ID
  106 + * @return 产品关联(可能为 null)
  107 + */
  108 + MesQcTemplateItemDO getTemplateItemByTemplateIdAndItemId(Long templateId, Long itemId);
  109 +
93 // ========== 质检方案-检测指标项 ========== 110 // ========== 质检方案-检测指标项 ==========
94 111
95 /** 112 /**
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateServiceImpl.java
@@ -84,10 +84,13 @@ public class MesQcTemplateServiceImpl implements MesQcTemplateService { @@ -84,10 +84,13 @@ public class MesQcTemplateServiceImpl implements MesQcTemplateService {
84 templateItemMapper.deleteByTemplateId(id); 84 templateItemMapper.deleteByTemplateId(id);
85 } 85 }
86 86
87 - private void validateTemplateExists(Long id) {  
88 - if (templateMapper.selectById(id) == null) { 87 + @Override
  88 + public MesQcTemplateDO validateTemplateExists(Long id) {
  89 + MesQcTemplateDO template = templateMapper.selectById(id);
  90 + if (template == null) {
89 throw exception(QC_TEMPLATE_NOT_EXISTS); 91 throw exception(QC_TEMPLATE_NOT_EXISTS);
90 } 92 }
  93 + return template;
91 } 94 }
92 95
93 private void validateTemplateCodeUnique(Long id, String code) { 96 private void validateTemplateCodeUnique(Long id, String code) {
@@ -101,6 +104,11 @@ public class MesQcTemplateServiceImpl implements MesQcTemplateService { @@ -101,6 +104,11 @@ public class MesQcTemplateServiceImpl implements MesQcTemplateService {
101 } 104 }
102 105
103 @Override 106 @Override
  107 + public MesQcTemplateItemDO getTemplateItemByTemplateIdAndItemId(Long templateId, Long itemId) {
  108 + return templateItemMapper.selectByTemplateIdAndItemId(templateId, itemId);
  109 + }
  110 +
  111 + @Override
104 public MesQcTemplateDO getTemplate(Long id) { 112 public MesQcTemplateDO getTemplate(Long id) {
105 return templateMapper.selectById(id); 113 return templateMapper.selectById(id);
106 } 114 }