From 7d45f862fcf531b85fbce7f8717dea3d58b8d309 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Wed, 25 Feb 2026 19:24:47 +0800 Subject: [PATCH] refactor(mes): 优化 RQC 模块,添加主表缺陷统计 --- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/MesQcRqcLineController.java | 7 ------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcPageReqVO.java | 11 ++--------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcRespVO.java | 25 +++++++++++++++++++++---- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcSaveReqVO.java | 44 ++++++++++++++++++++++++++++++-------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/line/MesQcRqcLineRespVO.java | 7 ++----- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/rqc/MesQcRqcDO.java | 33 ++++++++++++++++++++++++++++----- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/rqc/MesQcRqcLineDO.java | 7 +++---- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcMapper.java | 2 -- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/rqc/MesQcRqcMapper.java | 4 +--- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcLineServiceImpl.java | 31 +++++++++++++++++++++++-------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImpl.java | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateDetailService.java | 26 +------------------------- yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateDetailServiceImpl.java | 19 ------------------- 13 files changed, 172 insertions(+), 119 deletions(-) diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/MesQcRqcLineController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/MesQcRqcLineController.java index f28c372..ca965d1 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/MesQcRqcLineController.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/MesQcRqcLineController.java @@ -85,13 +85,6 @@ public class MesQcRqcLineController { .setIndicatorType(indicator.getType())); findAndThen(unitMeasureMap, vo.getUnitMeasureId(), unit -> vo.setUnitMeasureName(unit.getName())); - // 逐个查询工具名称(工具数量通常较少) - if (vo.getToolId() != null) { - MesTmToolDO tool = toolService.getTool(vo.getToolId()); - if (tool != null) { - vo.setToolName(tool.getName()); - } - } }); } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcPageReqVO.java index df9143b..c8368e2 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcPageReqVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcPageReqVO.java @@ -23,14 +23,11 @@ public class MesQcRqcPageReqVO extends PageParam { @Schema(description = "来源单据类型", example = "RTISSUE") private String sourceDocType; - @Schema(description = "来源单据编号", example = "RT2025") - private String sourceDocCode; - @Schema(description = "产品物料 ID", example = "20") private Long itemId; - @Schema(description = "检验类型", example = "1") - private Integer rqcType; + @Schema(description = "批次号", example = "BATCH001") + private String batchCode; @Schema(description = "检测结果", example = "1") private Integer checkResult; @@ -41,8 +38,4 @@ public class MesQcRqcPageReqVO extends PageParam { @Schema(description = "检测人员用户 ID", example = "1") private Long inspectorUserId; - @Schema(description = "检测日期") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] inspectDate; - } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcRespVO.java index f5ddce4..ef727e5 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcRespVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcRespVO.java @@ -36,9 +36,6 @@ public class MesQcRqcRespVO { @Schema(description = "来源单据类型", example = "RTISSUE") private String sourceDocType; - @Schema(description = "来源单据编号", example = "RT20250101001") - private String sourceDocCode; - @Schema(description = "来源单据行 ID", example = "300") private Long sourceLineId; @@ -46,7 +43,7 @@ public class MesQcRqcRespVO { @Schema(description = "检验类型", example = "1") @ExcelProperty("检验类型") - private Integer rqcType; + private Integer type; // ========== 物料 ========== @@ -110,6 +107,26 @@ public class MesQcRqcRespVO { @ExcelProperty("备注") private String remark; + // ========== 缺陷统计 ========== + + @Schema(description = "致命缺陷数量", example = "5") + private Integer criticalQuantity; + + @Schema(description = "严重缺陷数量", example = "10") + private Integer majorQuantity; + + @Schema(description = "轻微缺陷数量", example = "15") + private Integer minorQuantity; + + @Schema(description = "致命缺陷率(%)", example = "5.00") + private BigDecimal criticalRate; + + @Schema(description = "严重缺陷率(%)", example = "10.00") + private BigDecimal majorRate; + + @Schema(description = "轻微缺陷率(%)", example = "15.00") + private BigDecimal minorRate; + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) @ExcelProperty("创建时间") private LocalDateTime createTime; diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcSaveReqVO.java index 4db5ec2..d875b39 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcSaveReqVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/MesQcRqcSaveReqVO.java @@ -1,6 +1,10 @@ package cn.iocoder.yudao.module.mes.controller.admin.qc.rqc.vo; +import cn.hutool.core.util.ObjUtil; +import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.AssertTrue; +import jakarta.validation.constraints.DecimalMin; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; import lombok.Data; @@ -23,8 +27,7 @@ public class MesQcRqcSaveReqVO { @NotEmpty(message = "检验单名称不能为空") private String name; - @Schema(description = "检验模板 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") - @NotNull(message = "检验模板不能为空") + @Schema(description = "检验模板 ID", example = "100") private Long templateId; // ========== 来源单据 ========== @@ -35,16 +38,14 @@ public class MesQcRqcSaveReqVO { @Schema(description = "来源单据类型", example = "RTISSUE") private String sourceDocType; - @Schema(description = "来源单据编号", example = "RT20250101001") - private String sourceDocCode; - @Schema(description = "来源单据行 ID", example = "300") private Long sourceLineId; // ========== 检验类型 ========== - @Schema(description = "检验类型", example = "1") - private Integer rqcType; + @Schema(description = "检验类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "检验类型不能为空") + private Integer type; // ========== 物料 ========== @@ -57,15 +58,19 @@ public class MesQcRqcSaveReqVO { // ========== 数量 ========== - // TODO @AI:参考 iqc 的参数校验; - - @Schema(description = "检测数量", example = "100") + @Schema(description = "检测数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100") + @NotNull(message = "检测数量不能为空") + @DecimalMin(value = "0", message = "检测数量不能小于 0") private BigDecimal checkQuantity; - @Schema(description = "合格品数量", example = "90") + @Schema(description = "合格品数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "90") + @NotNull(message = "合格品数量不能为空") + @DecimalMin(value = "0", message = "合格品数量不能小于 0") private BigDecimal qualifiedQuantity; - @Schema(description = "不合格数量", example = "10") + @Schema(description = "不合格数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10") + @NotNull(message = "不合格数量不能为空") + @DecimalMin(value = "0", message = "不合格数量不能小于 0") private BigDecimal unqualifiedQuantity; // ========== 检验 ========== @@ -73,13 +78,24 @@ public class MesQcRqcSaveReqVO { @Schema(description = "检测结果", example = "1") private Integer checkResult; - @Schema(description = "检测日期") + @Schema(description = "检测日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "检测日期不能为空") private LocalDateTime inspectDate; - @Schema(description = "检测人员用户 ID", example = "1") + @Schema(description = "检测人员用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "检测人员不能为空") private Long inspectorUserId; @Schema(description = "备注", example = "备注") private String remark; + @AssertTrue(message = "检测数量必须等于合格品数量与不合格品数量之和") + @JsonIgnore + public boolean isQuantityValid() { + if (ObjUtil.hasNull(checkQuantity, qualifiedQuantity, unqualifiedQuantity)) { + return true; // @NotNull 会处理 null + } + return checkQuantity.compareTo(qualifiedQuantity.add(unqualifiedQuantity)) == 0; + } + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/line/MesQcRqcLineRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/line/MesQcRqcLineRespVO.java index c680aeb..da38747 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/line/MesQcRqcLineRespVO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/rqc/vo/line/MesQcRqcLineRespVO.java @@ -30,11 +30,8 @@ public class MesQcRqcLineRespVO { @Schema(description = "检测指标类型", example = "QUANTITATIVE") private String indicatorType; - @Schema(description = "检测工具 ID", example = "5") - private Long toolId; - - @Schema(description = "检测工具名称", example = "卡尺") - private String toolName; + @Schema(description = "检测工具", example = "卡尺") + private String tool; @Schema(description = "检测方法", example = "目测") private String checkMethod; diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/rqc/MesQcRqcDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/rqc/MesQcRqcDO.java index 3f8d6d3..a305546 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/rqc/MesQcRqcDO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/rqc/MesQcRqcDO.java @@ -58,10 +58,6 @@ public class MesQcRqcDO extends BaseDO { */ private String sourceDocType; /** - * 来源单据编号 - */ - private String sourceDocCode; - /** * 来源单据行 ID */ private Long sourceLineId; @@ -73,7 +69,7 @@ public class MesQcRqcDO extends BaseDO { * * 字典 mes_rqc_type */ - private Integer rqcType; + private Integer type; // ========== 物料 ========== @@ -133,6 +129,33 @@ public class MesQcRqcDO extends BaseDO { */ private String remark; + // ========== 缺陷统计 ========== + + /** + * 致命缺陷数量 + */ + private Integer criticalQuantity; + /** + * 严重缺陷数量 + */ + private Integer majorQuantity; + /** + * 轻微缺陷数量 + */ + private Integer minorQuantity; + /** + * 致命缺陷率(%) + */ + private BigDecimal criticalRate; + /** + * 严重缺陷率(%) + */ + private BigDecimal majorRate; + /** + * 轻微缺陷率(%) + */ + private BigDecimal minorRate; + // ========== 预留字段 ========== /** diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/rqc/MesQcRqcLineDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/rqc/MesQcRqcLineDO.java index 322e8a6..9bcc17f 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/rqc/MesQcRqcLineDO.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/rqc/MesQcRqcLineDO.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.tm.tool.MesTmToolDO; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; @@ -44,11 +43,11 @@ public class MesQcRqcLineDO extends BaseDO { */ private Long indicatorId; /** - * 检测工具 ID + * 检测工具 * - * 关联 {@link MesTmToolDO#getId()} + * 冗余 {@link MesQcIndicatorDO#getTool()} */ - private Long toolId; + private String tool; /** * 检测方法 */ diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcMapper.java index d938559..6219e60 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcMapper.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/oqc/MesQcOqcMapper.java @@ -23,8 +23,6 @@ public interface MesQcOqcMapper extends BaseMapperX { .eqIfPresent(MesQcOqcDO::getItemId, reqVO.getItemId()) .eqIfPresent(MesQcOqcDO::getCheckResult, reqVO.getCheckResult()) .eqIfPresent(MesQcOqcDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(MesQcOqcDO::getOutDate, reqVO.getOutDate()) - .betweenIfPresent(MesQcOqcDO::getInspectDate, reqVO.getInspectDate()) .eqIfPresent(MesQcOqcDO::getInspectorUserId, reqVO.getInspectorUserId()) .orderByDesc(MesQcOqcDO::getId)); } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/rqc/MesQcRqcMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/rqc/MesQcRqcMapper.java index 49f649f..efd1db9 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/rqc/MesQcRqcMapper.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/rqc/MesQcRqcMapper.java @@ -19,12 +19,10 @@ public interface MesQcRqcMapper extends BaseMapperX { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(MesQcRqcDO::getCode, reqVO.getCode()) .eqIfPresent(MesQcRqcDO::getSourceDocType, reqVO.getSourceDocType()) - .likeIfPresent(MesQcRqcDO::getSourceDocCode, reqVO.getSourceDocCode()) .eqIfPresent(MesQcRqcDO::getItemId, reqVO.getItemId()) - .eqIfPresent(MesQcRqcDO::getRqcType, reqVO.getRqcType()) + .likeIfPresent(MesQcRqcDO::getBatchCode, reqVO.getBatchCode()) .eqIfPresent(MesQcRqcDO::getCheckResult, reqVO.getCheckResult()) .eqIfPresent(MesQcRqcDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(MesQcRqcDO::getInspectDate, reqVO.getInspectDate()) .eqIfPresent(MesQcRqcDO::getInspectorUserId, reqVO.getInspectorUserId()) .orderByDesc(MesQcRqcDO::getId)); } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcLineServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcLineServiceImpl.java index b251e52..f4351f2 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcLineServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcLineServiceImpl.java @@ -5,21 +5,25 @@ import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.mes.controller.admin.qc.rqc.vo.line.MesQcRqcLinePageReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.indicator.MesQcIndicatorDO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcLineDO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateIndicatorDO; import cn.iocoder.yudao.module.mes.dal.mysql.qc.rqc.MesQcRqcLineMapper; import cn.iocoder.yudao.module.mes.dal.mysql.qc.template.MesQcTemplateIndicatorMapper; import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum; +import cn.iocoder.yudao.module.mes.service.qc.indicator.MesQcIndicatorService; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; /** @@ -36,6 +40,9 @@ public class MesQcRqcLineServiceImpl implements MesQcRqcLineService { @Resource private MesQcTemplateIndicatorMapper templateIndicatorMapper; + @Resource + private MesQcIndicatorService indicatorService; + @Override public MesQcRqcLineDO validateRqcLineExists(Long id) { MesQcRqcLineDO line = rqcLineMapper.selectById(id); @@ -57,14 +64,22 @@ public class MesQcRqcLineServiceImpl implements MesQcRqcLineService { @Override public void createLinesFromTemplate(Long rqcId, Long templateId) { - List indicators = templateIndicatorMapper.selectListByTemplateId(templateId); - List lines = convertList(indicators, indicator -> new MesQcRqcLineDO() - .setRqcId(rqcId).setIndicatorId(indicator.getIndicatorId()) - .setToolId(null) // TODO @芋艿:模板指标暂无 toolId,后续可扩展;todo @AI:改成 tool;参考 iqc - .setCheckMethod(indicator.getCheckMethod()) - .setStandardValue(indicator.getStandardValue()).setUnitMeasureId(indicator.getUnitMeasureId()) - .setMaxThreshold(indicator.getThresholdMax()).setMinThreshold(indicator.getThresholdMin()) - .setCriticalQuantity(0).setMajorQuantity(0).setMinorQuantity(0)); + List templateIndicators = templateIndicatorMapper.selectListByTemplateId(templateId); + if (CollUtil.isEmpty(templateIndicators)) { + return; + } + Map indicatorMap = indicatorService.getIndicatorMap( + convertSet(templateIndicators, MesQcTemplateIndicatorDO::getIndicatorId)); + List lines = convertList(templateIndicators, templateIndicator -> { + MesQcIndicatorDO indicator = indicatorMap.get(templateIndicator.getIndicatorId()); + return new MesQcRqcLineDO() + .setRqcId(rqcId).setIndicatorId(templateIndicator.getIndicatorId()) + .setTool(indicator != null ? indicator.getTool() : null) + .setCheckMethod(templateIndicator.getCheckMethod()) + .setStandardValue(templateIndicator.getStandardValue()).setUnitMeasureId(templateIndicator.getUnitMeasureId()) + .setMaxThreshold(templateIndicator.getThresholdMax()).setMinThreshold(templateIndicator.getThresholdMin()) + .setCriticalQuantity(0).setMajorQuantity(0).setMinorQuantity(0); + }); rqcLineMapper.insertBatch(lines); } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImpl.java index ce20f02..1bbe567 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/rqc/MesQcRqcServiceImpl.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.mes.service.qc.rqc; -import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -8,12 +7,15 @@ import cn.iocoder.yudao.module.mes.controller.admin.qc.rqc.vo.MesQcRqcPageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.qc.rqc.vo.MesQcRqcSaveReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.defectrecord.MesQcDefectRecordDO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.rqc.MesQcRqcDO; -import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO; import cn.iocoder.yudao.module.mes.dal.mysql.qc.rqc.MesQcRqcMapper; import cn.iocoder.yudao.module.mes.enums.MesOrderStatusEnum; +import cn.iocoder.yudao.module.mes.enums.qc.MesQcDefectLevelEnum; import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; import cn.iocoder.yudao.module.mes.service.qc.defectrecord.MesQcDefectRecordService; -import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateService; +import cn.iocoder.yudao.module.mes.service.qc.template.MesQcTemplateDetailService; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; @@ -21,7 +23,9 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.List; +import java.util.Objects; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; @@ -38,29 +42,35 @@ public class MesQcRqcServiceImpl implements MesQcRqcService { @Resource private MesQcRqcMapper rqcMapper; @Resource - private MesQcTemplateService templateService; + private MesQcTemplateDetailService templateDetailService; @Resource private MesQcRqcLineService rqcLineService; @Resource @Lazy + private MesMdItemService itemService; + @Resource + @Lazy private MesQcDefectRecordService defectRecordService; + @Resource + private AdminUserApi adminUserApi; + @Override @Transactional(rollbackFor = Exception.class) public Long createRqc(MesQcRqcSaveReqVO createReqVO) { // 1.1 校验编号唯一 validateRqcCodeUnique(null, createReqVO.getCode()); - // TODO @AI:关联的物资等存在的校验; - // 1.2 校验检验模板存在且支持 RQC 类型 - Long templateId = createReqVO.getTemplateId(); - // TODO @AI:参考 iqc 获取 templateId;不在依赖前端传递; - MesQcTemplateDO template = templateService.validateTemplateExists(templateId); - if (!CollUtil.contains(template.getTypes(), MesQcTypeEnum.RQC.getType())) { - throw exception(QC_RQC_NO_TEMPLATE); - } + // 1.2 校验物料、检测人员存在 + itemService.validateItemExists(createReqVO.getItemId()); + adminUserApi.validateUser(createReqVO.getInspectorUserId()); + // 1.3 根据物料 + 检验类型自动匹配模板 + MesQcTemplateItemDO templateItem = templateDetailService.getRequiredTemplateByItemIdAndType( + createReqVO.getItemId(), createReqVO.getType()); + Long templateId = templateItem.getTemplateId(); // 2. 插入主表 MesQcRqcDO rqc = BeanUtils.toBean(createReqVO, MesQcRqcDO.class) + .setTemplateId(templateId) .setStatus(MesOrderStatusEnum.DRAFT.getType()); rqcMapper.insert(rqc); @@ -75,6 +85,9 @@ public class MesQcRqcServiceImpl implements MesQcRqcService { validateRqcStatusPrepare(updateReqVO.getId()); // 1.2 校验编号唯一 validateRqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode()); + // 1.3 校验物料、检测人员存在 + itemService.validateItemExists(updateReqVO.getItemId()); + adminUserApi.validateUser(updateReqVO.getInspectorUserId()); // 2. 更新 MesQcRqcDO updateObj = BeanUtils.toBean(updateReqVO, MesQcRqcDO.class); @@ -160,10 +173,44 @@ public class MesQcRqcServiceImpl implements MesQcRqcService { @Override public void recalculateDefectStats(Long rqcId, List records) { - // RQC 只更新行级缺陷统计,主表不存储缺陷统计字段 + MesQcRqcDO rqc = validateRqcExists(rqcId); + // 1. 行级缺陷统计 rqcLineService.recalculateLineDefectStats(rqcId, records); - // TODO @AI:还是对齐其他的 + // 2.1 汇总主表的缺陷数量 + int totalCritical = 0; + int totalMajor = 0; + int totalMinor = 0; + for (MesQcDefectRecordDO record : records) { + int quantity = ObjUtil.defaultIfNull(record.getQuantity(), 1); + if (Objects.equals(record.getLevel(), MesQcDefectLevelEnum.CRITICAL.getType())) { + totalCritical += quantity; + } else if (Objects.equals(record.getLevel(), MesQcDefectLevelEnum.MAJOR.getType())) { + totalMajor += quantity; + } else if (Objects.equals(record.getLevel(), MesQcDefectLevelEnum.MINOR.getType())) { + totalMinor += quantity; + } else { + throw exception(QC_DEFECT_RECORD_LEVEL_UNKNOWN); + } + } + // 2.2 计算缺陷率 + BigDecimal criticalRate = BigDecimal.ZERO; + BigDecimal majorRate = BigDecimal.ZERO; + BigDecimal minorRate = BigDecimal.ZERO; + if (rqc.getCheckQuantity() != null && rqc.getCheckQuantity().compareTo(BigDecimal.ZERO) > 0) { + BigDecimal checkQty = rqc.getCheckQuantity(); + criticalRate = BigDecimal.valueOf(totalCritical).multiply(BigDecimal.valueOf(100)) + .divide(checkQty, 2, RoundingMode.HALF_UP); + majorRate = BigDecimal.valueOf(totalMajor).multiply(BigDecimal.valueOf(100)) + .divide(checkQty, 2, RoundingMode.HALF_UP); + minorRate = BigDecimal.valueOf(totalMinor).multiply(BigDecimal.valueOf(100)) + .divide(checkQty, 2, RoundingMode.HALF_UP); + } + // 2.3 更新主表 + MesQcRqcDO updateRqc = new MesQcRqcDO().setId(rqcId) + .setCriticalQuantity(totalCritical).setMajorQuantity(totalMajor).setMinorQuantity(totalMinor) + .setCriticalRate(criticalRate).setMajorRate(majorRate).setMinorRate(minorRate); + rqcMapper.updateById(updateRqc); } } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateDetailService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateDetailService.java index ed73fac..9eeefb0 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateDetailService.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateDetailService.java @@ -5,13 +5,12 @@ import cn.iocoder.yudao.module.mes.controller.admin.qc.template.vo.indicator.Mes import cn.iocoder.yudao.module.mes.controller.admin.qc.template.vo.indicator.MesQcTemplateIndicatorSaveReqVO; import cn.iocoder.yudao.module.mes.controller.admin.qc.template.vo.item.MesQcTemplateItemPageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.qc.template.vo.item.MesQcTemplateItemSaveReqVO; -import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateDO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateIndicatorDO; import cn.iocoder.yudao.module.mes.dal.dataobject.qc.template.MesQcTemplateItemDO; import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum; import jakarta.validation.Valid; -// TODO @AI:还是按照表,拆分。而不是 detail; +// TODO @AI:还是按照表,拆分。一个 MesQcTemplateIndicatorDO、MesQcTemplateItemDO; /** * MES 质检方案明细 Service 接口 * @@ -99,29 +98,6 @@ public interface MesQcTemplateDetailService { */ PageResult getTemplateItemPage(MesQcTemplateItemPageReqVO pageReqVO); - // ========== 复杂查询 ========== - - /** - * 根据方案 ID + 产品 ID 获取产品关联 - * - * @param templateId 方案 ID - * @param itemId 产品 ID - * @return 产品关联 - */ - MesQcTemplateItemDO getTemplateItemByTemplateIdAndItemId(Long templateId, Long itemId); - - // TODO @芋艿:【不要删除】后续这个方法,会慢慢被替代掉; - /** - * 根据产品物料 ID 和 QC 类型查找检验模板 - * - * 查找逻辑:在 template_item 中找到匹配 itemId 的模板,再校验该模板的 types 包含给定的 qcType - * - * @param itemId 产品物料 ID - * @param qcType 检测种类(枚举 {@link MesQcTypeEnum}) - * @return 匹配的检验模板(可能为 null) - */ - MesQcTemplateDO getTemplateByItemIdAndType(Long itemId, Integer qcType); - /** * 根据产品物料 ID 和 QC 类型查找检验模板的产品关联(必须存在,否则抛异常) * diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateDetailServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateDetailServiceImpl.java index 4a94bc7..721240d 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateDetailServiceImpl.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/template/MesQcTemplateDetailServiceImpl.java @@ -159,25 +159,6 @@ public class MesQcTemplateDetailServiceImpl implements MesQcTemplateDetailServic // ========== 复杂查询 ========== @Override - public MesQcTemplateItemDO getTemplateItemByTemplateIdAndItemId(Long templateId, Long itemId) { - return templateItemMapper.selectByTemplateIdAndItemId(templateId, itemId); - } - - @Override - public MesQcTemplateDO getTemplateByItemIdAndType(Long itemId, Integer qcType) { - // 1.1 查出 itemId 关联的所有 templateId - List templateItems = templateItemMapper.selectListByItemId(itemId); - if (CollUtil.isEmpty(templateItems)) { - return null; - } - // 1.2 批量查模板,筛选 types 包含给定 qcType 的第一个 - List templates = templateMapper.selectByIds( - convertSet(templateItems, MesQcTemplateItemDO::getTemplateId)); - // 2. 筛选 types 包含给定 qcType 的第一个 - return findFirst(templates, template -> CollUtil.contains(template.getTypes(), qcType)); - } - - @Override public MesQcTemplateItemDO getRequiredTemplateByItemIdAndType(Long itemId, Integer qcType) { // 1. 查出 itemId 关联的所有 templateId List templateItems = templateItemMapper.selectListByItemId(itemId); -- libgit2 0.21.4