Commit ff1d20f4efc692b398ed7f8ed69d9bc413baa8a2

Authored by YunaiV
1 parent 2fcfebc7

feat(mes): 新增来料检验单及缺陷记录相关功能,包括请求和响应 VO、Mapper、Controller 及 API 接口

Showing 21 changed files with 1761 additions and 0 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/MesQcIqcController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  5 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  9 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  10 +import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcPageReqVO;
  11 +import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcRespVO;
  12 +import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.MesQcIqcSaveReqVO;
  13 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  14 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
  15 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO;
  16 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.MesQcIqcDO;
  17 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  18 +import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
  19 +import cn.iocoder.yudao.module.mes.service.md.vendor.MesMdVendorService;
  20 +import cn.iocoder.yudao.module.mes.service.qc.MesQcIqcService;
  21 +import io.swagger.v3.oas.annotations.Operation;
  22 +import io.swagger.v3.oas.annotations.Parameter;
  23 +import io.swagger.v3.oas.annotations.tags.Tag;
  24 +import jakarta.annotation.Resource;
  25 +import jakarta.servlet.http.HttpServletResponse;
  26 +import jakarta.validation.Valid;
  27 +import org.springframework.security.access.prepost.PreAuthorize;
  28 +import org.springframework.validation.annotation.Validated;
  29 +import org.springframework.web.bind.annotation.*;
  30 +
  31 +import java.io.IOException;
  32 +import java.util.Collections;
  33 +import java.util.List;
  34 +import java.util.Map;
  35 +
  36 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
  37 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  38 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  39 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
  40 +
  41 +@Tag(name = "管理后台 - MES 来料检验单(IQC)")
  42 +@RestController
  43 +@RequestMapping("/mes/qc/iqc")
  44 +@Validated
  45 +public class MesQcIqcController {
  46 +
  47 + @Resource
  48 + private MesQcIqcService iqcService;
  49 + @Resource
  50 + private MesMdVendorService vendorService;
  51 + @Resource
  52 + private MesMdItemService itemService;
  53 + @Resource
  54 + private MesMdUnitMeasureService unitMeasureService;
  55 +
  56 + @PostMapping("/create")
  57 + @Operation(summary = "创建来料检验单")
  58 + @PreAuthorize("@ss.hasPermission('mes:qc-iqc:create')")
  59 + public CommonResult<Long> createIqc(@Valid @RequestBody MesQcIqcSaveReqVO createReqVO) {
  60 + return success(iqcService.createIqc(createReqVO));
  61 + }
  62 +
  63 + @PutMapping("/update")
  64 + @Operation(summary = "更新来料检验单")
  65 + @PreAuthorize("@ss.hasPermission('mes:qc-iqc:update')")
  66 + public CommonResult<Boolean> updateIqc(@Valid @RequestBody MesQcIqcSaveReqVO updateReqVO) {
  67 + iqcService.updateIqc(updateReqVO);
  68 + return success(true);
  69 + }
  70 +
  71 + @PutMapping("/complete")
  72 + @Operation(summary = "完成来料检验单")
  73 + @Parameter(name = "id", description = "编号", required = true)
  74 + @PreAuthorize("@ss.hasPermission('mes:qc-iqc:update')")
  75 + public CommonResult<Boolean> completeIqc(@RequestParam("id") Long id) {
  76 + iqcService.completeIqc(id);
  77 + return success(true);
  78 + }
  79 +
  80 + @DeleteMapping("/delete")
  81 + @Operation(summary = "删除来料检验单")
  82 + @Parameter(name = "id", description = "编号", required = true)
  83 + @PreAuthorize("@ss.hasPermission('mes:qc-iqc:delete')")
  84 + public CommonResult<Boolean> deleteIqc(@RequestParam("id") Long id) {
  85 + iqcService.deleteIqc(id);
  86 + return success(true);
  87 + }
  88 +
  89 + @GetMapping("/get")
  90 + @Operation(summary = "获得来料检验单")
  91 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  92 + @PreAuthorize("@ss.hasPermission('mes:qc-iqc:query')")
  93 + public CommonResult<MesQcIqcRespVO> getIqc(@RequestParam("id") Long id) {
  94 + MesQcIqcDO iqc = iqcService.getIqc(id);
  95 + return success(buildIqcRespVOList(Collections.singletonList(iqc)).get(0));
  96 + }
  97 +
  98 + @GetMapping("/page")
  99 + @Operation(summary = "获得来料检验单分页")
  100 + @PreAuthorize("@ss.hasPermission('mes:qc-iqc:query')")
  101 + public CommonResult<PageResult<MesQcIqcRespVO>> getIqcPage(@Valid MesQcIqcPageReqVO pageReqVO) {
  102 + PageResult<MesQcIqcDO> pageResult = iqcService.getIqcPage(pageReqVO);
  103 + return success(new PageResult<>(buildIqcRespVOList(pageResult.getList()), pageResult.getTotal()));
  104 + }
  105 +
  106 + @GetMapping("/export-excel")
  107 + @Operation(summary = "导出来料检验单 Excel")
  108 + @PreAuthorize("@ss.hasPermission('mes:qc-iqc:export')")
  109 + @ApiAccessLog(operateType = EXPORT)
  110 + public void exportIqcExcel(@Valid MesQcIqcPageReqVO pageReqVO,
  111 + HttpServletResponse response) throws IOException {
  112 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  113 + List<MesQcIqcDO> list = iqcService.getIqcPage(pageReqVO).getList();
  114 + List<MesQcIqcRespVO> voList = buildIqcRespVOList(list);
  115 + ExcelUtils.write(response, "来料检验单.xls", "数据", MesQcIqcRespVO.class, voList);
  116 + }
  117 +
  118 + // ==================== 拼接 VO ====================
  119 +
  120 + private List<MesQcIqcRespVO> buildIqcRespVOList(List<MesQcIqcDO> list) {
  121 + if (CollUtil.isEmpty(list)) {
  122 + return Collections.emptyList();
  123 + }
  124 + // 批量查询供应商
  125 + Map<Long, MesMdVendorDO> vendorMap = vendorService.getVendorMap(
  126 + convertSet(list, MesQcIqcDO::getVendorId));
  127 + // 批量查询物料
  128 + Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(
  129 + convertSet(list, MesQcIqcDO::getItemId));
  130 + // 批量查询计量单位(通过物料的 unitMeasureId)
  131 + Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
  132 + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId));
  133 + // 拼装 VO
  134 + return BeanUtils.toBean(list, MesQcIqcRespVO.class, vo -> {
  135 + findAndThen(vendorMap, vo.getVendorId(),
  136 + vendor -> vo.setVendorNickname(vendor.getNickname()));
  137 + findAndThen(itemMap, vo.getItemId(), item -> {
  138 + vo.setItemCode(item.getCode());
  139 + vo.setItemName(item.getName());
  140 + vo.setItemSpecification(item.getSpecification());
  141 + findAndThen(unitMeasureMap, item.getUnitMeasureId(),
  142 + unit -> vo.setUnitName(unit.getName()));
  143 + });
  144 + });
  145 + }
  146 +
  147 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/MesQcIqcDefectController.java 0 → 100644
  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.MesQcIqcDefectDO;
  10 +import cn.iocoder.yudao.module.mes.service.qc.MesQcIqcService;
  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 MesQcIqcService iqcService;
  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(iqcService.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 + iqcService.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 + iqcService.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 = iqcService.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/MesQcIqcLineController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.line.MesQcIqcLinePageReqVO;
  8 +import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.line.MesQcIqcLineRespVO;
  9 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
  10 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.MesQcIqcLineDO;
  11 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.MesQcIndicatorDO;
  12 +import cn.iocoder.yudao.module.mes.dal.dataobject.tm.tool.MesTmToolDO;
  13 +import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
  14 +import cn.iocoder.yudao.module.mes.service.qc.MesQcIqcService;
  15 +import cn.iocoder.yudao.module.mes.service.qc.MesQcIndicatorService;
  16 +import cn.iocoder.yudao.module.mes.service.tm.tool.MesTmToolService;
  17 +import io.swagger.v3.oas.annotations.Operation;
  18 +import io.swagger.v3.oas.annotations.Parameter;
  19 +import io.swagger.v3.oas.annotations.tags.Tag;
  20 +import jakarta.annotation.Resource;
  21 +import jakarta.validation.Valid;
  22 +import org.springframework.security.access.prepost.PreAuthorize;
  23 +import org.springframework.validation.annotation.Validated;
  24 +import org.springframework.web.bind.annotation.GetMapping;
  25 +import org.springframework.web.bind.annotation.RequestMapping;
  26 +import org.springframework.web.bind.annotation.RequestParam;
  27 +import org.springframework.web.bind.annotation.RestController;
  28 +
  29 +import java.util.Collections;
  30 +import java.util.List;
  31 +import java.util.Map;
  32 +
  33 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  34 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.MapUtils.findAndThen;
  36 +
  37 +@Tag(name = "管理后台 - MES 来料检验单行")
  38 +@RestController
  39 +@RequestMapping("/mes/qc/iqc/line")
  40 +@Validated
  41 +public class MesQcIqcLineController {
  42 +
  43 + @Resource
  44 + private MesQcIqcService iqcService;
  45 + @Resource
  46 + private MesQcIndicatorService indicatorService;
  47 + @Resource
  48 + private MesMdUnitMeasureService unitMeasureService;
  49 + @Resource
  50 + private MesTmToolService toolService;
  51 +
  52 + @GetMapping("/get")
  53 + @Operation(summary = "获得来料检验单行")
  54 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  55 + @PreAuthorize("@ss.hasPermission('mes:qc-iqc:query')")
  56 + public CommonResult<MesQcIqcLineRespVO> getIqcLine(@RequestParam("id") Long id) {
  57 + MesQcIqcLineDO line = iqcService.getIqcLine(id);
  58 + return success(buildLineRespVOList(Collections.singletonList(line)).get(0));
  59 + }
  60 +
  61 + @GetMapping("/page")
  62 + @Operation(summary = "获得来料检验单行分页")
  63 + @PreAuthorize("@ss.hasPermission('mes:qc-iqc:query')")
  64 + public CommonResult<PageResult<MesQcIqcLineRespVO>> getIqcLinePage(@Valid MesQcIqcLinePageReqVO pageReqVO) {
  65 + PageResult<MesQcIqcLineDO> pageResult = iqcService.getIqcLinePage(pageReqVO);
  66 + return success(new PageResult<>(buildLineRespVOList(pageResult.getList()), pageResult.getTotal()));
  67 + }
  68 +
  69 + // ==================== 拼接 VO ====================
  70 +
  71 + private List<MesQcIqcLineRespVO> buildLineRespVOList(List<MesQcIqcLineDO> list) {
  72 + if (CollUtil.isEmpty(list)) {
  73 + return Collections.emptyList();
  74 + }
  75 + // 批量查询检测指标
  76 + Map<Long, MesQcIndicatorDO> indicatorMap = indicatorService.getIndicatorMap(
  77 + convertSet(list, MesQcIqcLineDO::getIndicatorId));
  78 + // 批量查询计量单位
  79 + Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
  80 + convertSet(list, MesQcIqcLineDO::getUnitMeasureId));
  81 + // 拼装 VO
  82 + return BeanUtils.toBean(list, MesQcIqcLineRespVO.class, vo -> {
  83 + findAndThen(indicatorMap, vo.getIndicatorId(), indicator ->
  84 + vo.setIndicatorCode(indicator.getCode()).setIndicatorName(indicator.getName())
  85 + .setIndicatorType(indicator.getType()));
  86 + findAndThen(unitMeasureMap, vo.getUnitMeasureId(),
  87 + unit -> vo.setUnitMeasureName(unit.getName()));
  88 + // 逐个查询工具名称(工具数量通常较少)
  89 + if (vo.getToolId() != null) {
  90 + MesTmToolDO tool = toolService.getTool(vo.getToolId());
  91 + if (tool != null) {
  92 + vo.setToolName(tool.getName());
  93 + }
  94 + }
  95 + });
  96 + }
  97 +
  98 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/MesQcIqcPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  13 +
  14 +@Schema(description = "管理后台 - MES 来料检验单分页 Request VO")
  15 +@Data
  16 +@EqualsAndHashCode(callSuper = true)
  17 +@ToString(callSuper = true)
  18 +public class MesQcIqcPageReqVO extends PageParam {
  19 +
  20 + @Schema(description = "检验单编号", example = "IQC2025")
  21 + private String code;
  22 +
  23 + @Schema(description = "供应商 ID", example = "10")
  24 + private Long vendorId;
  25 +
  26 + @Schema(description = "供应商批次号", example = "VB2025")
  27 + private String vendorBatch;
  28 +
  29 + @Schema(description = "产品物料 ID", example = "20")
  30 + private Long itemId;
  31 +
  32 + @Schema(description = "检测结果", example = "PASS")
  33 + private String checkResult;
  34 +
  35 + @Schema(description = "状态", example = "0")
  36 + private Integer status;
  37 +
  38 + @Schema(description = "来料日期")
  39 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  40 + private LocalDateTime[] receiveDate;
  41 +
  42 + @Schema(description = "检测日期")
  43 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  44 + private LocalDateTime[] inspectDate;
  45 +
  46 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/MesQcIqcRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo;
  2 +
  3 +import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
  4 +import cn.idev.excel.annotation.ExcelProperty;
  5 +import io.swagger.v3.oas.annotations.media.Schema;
  6 +import lombok.Data;
  7 +
  8 +import java.math.BigDecimal;
  9 +import java.time.LocalDateTime;
  10 +
  11 +@Schema(description = "管理后台 - MES 来料检验单 Response VO")
  12 +@Data
  13 +@ExcelIgnoreUnannotated
  14 +public class MesQcIqcRespVO {
  15 +
  16 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  17 + @ExcelProperty("编号")
  18 + private Long id;
  19 +
  20 + @Schema(description = "检验单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "IQC20250101001")
  21 + @ExcelProperty("检验单编号")
  22 + private String code;
  23 +
  24 + @Schema(description = "检验单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "物料A来料检验")
  25 + @ExcelProperty("检验单名称")
  26 + private String name;
  27 +
  28 + @Schema(description = "检验模板 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  29 + private Long templateId;
  30 +
  31 + // ========== 来源单据 ==========
  32 +
  33 + @Schema(description = "来源单据 ID", example = "200")
  34 + private Long sourceDocId;
  35 +
  36 + @Schema(description = "来源单据类型", example = "ARRIVAL")
  37 + private String sourceDocType;
  38 +
  39 + @Schema(description = "来源单据编号", example = "ARV20250101001")
  40 + private String sourceDocCode;
  41 +
  42 + @Schema(description = "来源单据行 ID", example = "300")
  43 + private Long sourceLineId;
  44 +
  45 + // ========== 供应商 ==========
  46 +
  47 + @Schema(description = "供应商 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  48 + private Long vendorId;
  49 +
  50 + @Schema(description = "供应商简称", example = "供应商A")
  51 + private String vendorNickname;
  52 +
  53 + @Schema(description = "供应商批次号", example = "VB20250101")
  54 + @ExcelProperty("供应商批次号")
  55 + private String vendorBatch;
  56 +
  57 + // ========== 物料 ==========
  58 +
  59 + @Schema(description = "产品物料 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
  60 + private Long itemId;
  61 +
  62 + @Schema(description = "产品物料编码", example = "ITEM001")
  63 + @ExcelProperty("产品物料编码")
  64 + private String itemCode;
  65 +
  66 + @Schema(description = "产品物料名称", example = "物料A")
  67 + @ExcelProperty("产品物料名称")
  68 + private String itemName;
  69 +
  70 + @Schema(description = "规格型号", example = "100mm*50mm")
  71 + private String itemSpecification;
  72 +
  73 + @Schema(description = "单位名称", example = "个")
  74 + private String unitName;
  75 +
  76 + // ========== 数量 ==========
  77 +
  78 + @Schema(description = "最低检测数", example = "5")
  79 + private Integer minCheckQuantity;
  80 +
  81 + @Schema(description = "最大不合格数", example = "0")
  82 + private Integer maxUnqualifiedQuantity;
  83 +
  84 + @Schema(description = "本次接收数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  85 + @ExcelProperty("接收数量")
  86 + private BigDecimal receivedQuantity;
  87 +
  88 + @Schema(description = "本次检测数量", example = "10")
  89 + @ExcelProperty("检测数量")
  90 + private Integer checkQuantity;
  91 +
  92 + @Schema(description = "合格品数量", example = "9")
  93 + @ExcelProperty("合格品数量")
  94 + private Integer qualifiedQuantity;
  95 +
  96 + @Schema(description = "不合格品数量", example = "1")
  97 + @ExcelProperty("不合格品数量")
  98 + private Integer unqualifiedQuantity;
  99 +
  100 + // ========== 缺陷统计 ==========
  101 +
  102 + @Schema(description = "致命缺陷率(%)", example = "0.00")
  103 + private BigDecimal criticalRate;
  104 +
  105 + @Schema(description = "严重缺陷率(%)", example = "0.00")
  106 + private BigDecimal majorRate;
  107 +
  108 + @Schema(description = "轻微缺陷率(%)", example = "10.00")
  109 + private BigDecimal minorRate;
  110 +
  111 + @Schema(description = "致命缺陷数量", example = "0")
  112 + private Integer criticalQuantity;
  113 +
  114 + @Schema(description = "严重缺陷数量", example = "0")
  115 + private Integer majorQuantity;
  116 +
  117 + @Schema(description = "轻微缺陷数量", example = "1")
  118 + private Integer minorQuantity;
  119 +
  120 + // ========== 检验 ==========
  121 +
  122 + @Schema(description = "检测结果", example = "PASS")
  123 + @ExcelProperty("检测结果")
  124 + private String checkResult;
  125 +
  126 + @Schema(description = "来料日期")
  127 + @ExcelProperty("来料日期")
  128 + private LocalDateTime receiveDate;
  129 +
  130 + @Schema(description = "检测日期")
  131 + @ExcelProperty("检测日期")
  132 + private LocalDateTime inspectDate;
  133 +
  134 + @Schema(description = "检测人员", example = "张三")
  135 + @ExcelProperty("检测人员")
  136 + private String inspector;
  137 +
  138 + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
  139 + @ExcelProperty("状态")
  140 + private Integer status;
  141 +
  142 + @Schema(description = "备注", example = "备注")
  143 + @ExcelProperty("备注")
  144 + private String remark;
  145 +
  146 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  147 + @ExcelProperty("创建时间")
  148 + private LocalDateTime createTime;
  149 +
  150 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/MesQcIqcSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo;
  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 +import java.math.BigDecimal;
  9 +import java.time.LocalDateTime;
  10 +
  11 +@Schema(description = "管理后台 - MES 来料检验单新增/修改 Request VO")
  12 +@Data
  13 +public class MesQcIqcSaveReqVO {
  14 +
  15 + @Schema(description = "编号", example = "1024")
  16 + private Long id;
  17 +
  18 + @Schema(description = "检验单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "IQC20250101001")
  19 + @NotEmpty(message = "检验单编号不能为空")
  20 + private String code;
  21 +
  22 + @Schema(description = "检验单名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "物料A来料检验")
  23 + @NotEmpty(message = "检验单名称不能为空")
  24 + private String name;
  25 +
  26 + @Schema(description = "检验模板 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  27 + @NotNull(message = "检验模板不能为空")
  28 + private Long templateId;
  29 +
  30 + // ========== 来源单据 ==========
  31 +
  32 + @Schema(description = "来源单据 ID", example = "200")
  33 + private Long sourceDocId;
  34 +
  35 + @Schema(description = "来源单据类型", example = "ARRIVAL")
  36 + private String sourceDocType;
  37 +
  38 + @Schema(description = "来源单据编号", example = "ARV20250101001")
  39 + private String sourceDocCode;
  40 +
  41 + @Schema(description = "来源单据行 ID", example = "300")
  42 + private Long sourceLineId;
  43 +
  44 + // ========== 供应商 ==========
  45 +
  46 + @Schema(description = "供应商 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  47 + @NotNull(message = "供应商不能为空")
  48 + private Long vendorId;
  49 +
  50 + @Schema(description = "供应商批次号", example = "VB20250101")
  51 + private String vendorBatch;
  52 +
  53 + // ========== 物料 ==========
  54 +
  55 + @Schema(description = "产品物料 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
  56 + @NotNull(message = "产品物料不能为空")
  57 + private Long itemId;
  58 +
  59 + // ========== 数量 ==========
  60 +
  61 + @Schema(description = "最低检测数", example = "5")
  62 + private Integer minCheckQuantity;
  63 +
  64 + @Schema(description = "最大不合格数", example = "0")
  65 + private Integer maxUnqualifiedQuantity;
  66 +
  67 + @Schema(description = "本次接收数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  68 + @NotNull(message = "本次接收数量不能为空")
  69 + private BigDecimal receivedQuantity;
  70 +
  71 + @Schema(description = "本次检测数量", example = "10")
  72 + private Integer checkQuantity;
  73 +
  74 + @Schema(description = "合格品数量", example = "9")
  75 + private Integer qualifiedQuantity;
  76 +
  77 + @Schema(description = "不合格品数量", example = "1")
  78 + private Integer unqualifiedQuantity;
  79 +
  80 + // ========== 检验 ==========
  81 +
  82 + @Schema(description = "检测结果", example = "PASS")
  83 + private String checkResult;
  84 +
  85 + @Schema(description = "来料日期")
  86 + private LocalDateTime receiveDate;
  87 +
  88 + @Schema(description = "检测日期")
  89 + private LocalDateTime inspectDate;
  90 +
  91 + @Schema(description = "检测人员", example = "张三")
  92 + private String inspector;
  93 +
  94 + @Schema(description = "备注", example = "备注")
  95 + private String remark;
  96 +
  97 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/defect/MesQcIqcDefectPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +
  10 +@Schema(description = "管理后台 - MES 来料检验缺陷记录分页 Request VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class MesQcIqcDefectPageReqVO extends PageParam {
  15 +
  16 + @Schema(description = "来料检验单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  17 + @NotNull(message = "来料检验单 ID 不能为空")
  18 + private Long iqcId;
  19 +
  20 + @Schema(description = "来料检验行 ID", example = "200")
  21 + private Long lineId;
  22 +
  23 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/defect/MesQcIqcDefectRespVO.java 0 → 100644
  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 lombok.Data;
  5 +
  6 +import java.time.LocalDateTime;
  7 +
  8 +@Schema(description = "管理后台 - MES 来料检验缺陷记录 Response VO")
  9 +@Data
  10 +public class MesQcIqcDefectRespVO {
  11 +
  12 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  13 + private Long id;
  14 +
  15 + @Schema(description = "来料检验单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  16 + private Long iqcId;
  17 +
  18 + @Schema(description = "来料检验行 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "200")
  19 + private Long lineId;
  20 +
  21 + @Schema(description = "缺陷描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "表面划伤")
  22 + private String defectName;
  23 +
  24 + @Schema(description = "缺陷等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "CRITICAL")
  25 + private String defectLevel;
  26 +
  27 + @Schema(description = "缺陷数量", example = "1")
  28 + private Integer defectQuantity;
  29 +
  30 + @Schema(description = "备注", example = "备注")
  31 + private String remark;
  32 +
  33 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  34 + private LocalDateTime createTime;
  35 +
  36 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/defect/MesQcIqcDefectSaveReqVO.java 0 → 100644
  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 = "CRITICAL")
  28 + @NotEmpty(message = "缺陷等级不能为空")
  29 + private String 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/controller/admin/qc/iqc/vo/line/MesQcIqcLinePageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.line;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import jakarta.validation.constraints.NotNull;
  6 +import lombok.Data;
  7 +import lombok.EqualsAndHashCode;
  8 +import lombok.ToString;
  9 +
  10 +@Schema(description = "管理后台 - MES 来料检验单行分页 Request VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class MesQcIqcLinePageReqVO extends PageParam {
  15 +
  16 + @Schema(description = "来料检验单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  17 + @NotNull(message = "来料检验单 ID 不能为空")
  18 + private Long iqcId;
  19 +
  20 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/iqc/vo/line/MesQcIqcLineRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.line;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +import lombok.experimental.Accessors;
  6 +
  7 +import java.math.BigDecimal;
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - MES 来料检验单行 Response VO")
  11 +@Data
  12 +@Accessors(chain = true)
  13 +public class MesQcIqcLineRespVO {
  14 +
  15 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  16 + private Long id;
  17 +
  18 + @Schema(description = "来料检验单 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  19 + private Long iqcId;
  20 +
  21 + @Schema(description = "检测指标 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
  22 + private Long indicatorId;
  23 +
  24 + @Schema(description = "检测指标编码", example = "IND001")
  25 + private String indicatorCode;
  26 +
  27 + @Schema(description = "检测指标名称", example = "外观")
  28 + private String indicatorName;
  29 +
  30 + @Schema(description = "检测指标类型", example = "QUANTITATIVE")
  31 + private String indicatorType;
  32 +
  33 + @Schema(description = "检测工具 ID", example = "5")
  34 + private Long toolId;
  35 +
  36 + @Schema(description = "检测工具名称", example = "卡尺")
  37 + private String toolName;
  38 +
  39 + @Schema(description = "检测方法", example = "目测")
  40 + private String checkMethod;
  41 +
  42 + @Schema(description = "标准值", example = "10.5000")
  43 + private BigDecimal standardValue;
  44 +
  45 + @Schema(description = "计量单位 ID", example = "3")
  46 + private Long unitMeasureId;
  47 +
  48 + @Schema(description = "计量单位名称", example = "毫米")
  49 + private String unitMeasureName;
  50 +
  51 + @Schema(description = "误差上限", example = "11.0000")
  52 + private BigDecimal maxThreshold;
  53 +
  54 + @Schema(description = "误差下限", example = "10.0000")
  55 + private BigDecimal minThreshold;
  56 +
  57 + @Schema(description = "致命缺陷数量", example = "0")
  58 + private Integer criticalQuantity;
  59 +
  60 + @Schema(description = "严重缺陷数量", example = "0")
  61 + private Integer majorQuantity;
  62 +
  63 + @Schema(description = "轻微缺陷数量", example = "1")
  64 + private Integer minorQuantity;
  65 +
  66 + @Schema(description = "备注", example = "备注")
  67 + private String remark;
  68 +
  69 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  70 + private LocalDateTime createTime;
  71 +
  72 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/MesQcIqcDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.dataobject.qc;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO;
  6 +import com.baomidou.mybatisplus.annotation.KeySequence;
  7 +import com.baomidou.mybatisplus.annotation.TableId;
  8 +import com.baomidou.mybatisplus.annotation.TableName;
  9 +import lombok.*;
  10 +
  11 +import java.math.BigDecimal;
  12 +import java.time.LocalDateTime;
  13 +
  14 +// TODO @AI:IQC 完整的拼写,也加下;
  15 +/**
  16 + * MES 来料检验单(IQC) DO
  17 + *
  18 + * @author 芋道源码
  19 + */
  20 +@TableName("mes_qc_iqc")
  21 +@KeySequence("mes_qc_iqc_seq")
  22 +@Data
  23 +@EqualsAndHashCode(callSuper = true)
  24 +@ToString(callSuper = true)
  25 +@Builder
  26 +@NoArgsConstructor
  27 +@AllArgsConstructor
  28 +public class MesQcIqcDO extends BaseDO {
  29 +
  30 + /**
  31 + * 编号
  32 + */
  33 + @TableId
  34 + private Long id;
  35 + /**
  36 + * 检验单编号
  37 + */
  38 + private String code;
  39 + /**
  40 + * 检验单名称
  41 + */
  42 + private String name;
  43 + /**
  44 + * 检验模板 ID
  45 + *
  46 + * 关联 {@link MesQcTemplateDO#getId()}
  47 + */
  48 + private Long templateId;
  49 +
  50 + // ========== 来源单据(TODO @芋艿:WM 模块迁移后接入) ==========
  51 +
  52 + /**
  53 + * 来源单据 ID
  54 + */
  55 + private Long sourceDocId;
  56 + /**
  57 + * 来源单据类型
  58 + *
  59 + * 字典 mes_qc_source_doc_type
  60 + */
  61 + private String sourceDocType;
  62 + /**
  63 + * 来源单据编号
  64 + */
  65 + private String sourceDocCode;
  66 + /**
  67 + * 来源单据行 ID
  68 + */
  69 + private Long sourceLineId;
  70 +
  71 + // ========== 供应商 ==========
  72 +
  73 + /**
  74 + * 供应商 ID
  75 + *
  76 + * 关联 {@link MesMdVendorDO#getId()}
  77 + */
  78 + private Long vendorId;
  79 + /**
  80 + * 供应商批次号
  81 + */
  82 + private String vendorBatch;
  83 +
  84 + // ========== 物料 ==========
  85 +
  86 + /**
  87 + * 产品物料 ID
  88 + *
  89 + * 关联 {@link MesMdItemDO#getId()}
  90 + */
  91 + private Long itemId;
  92 +
  93 + // ========== 数量 ==========
  94 +
  95 + /**
  96 + * 最低检测数
  97 + */
  98 + private Integer minCheckQuantity;
  99 + /**
  100 + * 最大不合格数
  101 + */
  102 + private Integer maxUnqualifiedQuantity;
  103 + /**
  104 + * 本次接收数量
  105 + */
  106 + private BigDecimal receivedQuantity;
  107 + /**
  108 + * 本次检测数量
  109 + */
  110 + private Integer checkQuantity;
  111 + /**
  112 + * 合格品数量
  113 + */
  114 + private Integer qualifiedQuantity;
  115 + /**
  116 + * 不合格品数量
  117 + */
  118 + private Integer unqualifiedQuantity;
  119 +
  120 + // ========== 缺陷统计 ==========
  121 +
  122 + /**
  123 + * 致命缺陷率(%)
  124 + */
  125 + private BigDecimal criticalRate;
  126 + /**
  127 + * 严重缺陷率(%)
  128 + */
  129 + private BigDecimal majorRate;
  130 + /**
  131 + * 轻微缺陷率(%)
  132 + */
  133 + private BigDecimal minorRate;
  134 + /**
  135 + * 致命缺陷数量
  136 + */
  137 + private Integer criticalQuantity;
  138 + /**
  139 + * 严重缺陷数量
  140 + */
  141 + private Integer majorQuantity;
  142 + /**
  143 + * 轻微缺陷数量
  144 + */
  145 + private Integer minorQuantity;
  146 +
  147 + // ========== 检验 ==========
  148 +
  149 + // TODO @AI:需要搞个枚举么?使用 int 把。现在就搞了;
  150 + /**
  151 + * 检测结果
  152 + *
  153 + * 字典 mes_qc_check_result
  154 + */
  155 + private String checkResult;
  156 + /**
  157 + * 来料日期
  158 + */
  159 + private LocalDateTime receiveDate;
  160 + /**
  161 + * 检测日期
  162 + */
  163 + private LocalDateTime inspectDate;
  164 + /**
  165 + * 检测人员
  166 + */
  167 + // TODO @AI:改成 inspectorUserId;
  168 + private String inspector;
  169 + // TODO @AI:需要搞个枚举么?使用 int 把。现在就搞了;
  170 + /**
  171 + * 状态(0=草稿 1=已完成)
  172 + *
  173 + * 字典 mes_qc_iqc_status
  174 + */
  175 + private Integer status;
  176 + /**
  177 + * 备注
  178 + */
  179 + private String remark;
  180 +
  181 + // ========== 预留字段 ==========
  182 +
  183 + /**
  184 + * 预留字段 1
  185 + */
  186 + private String attribute1;
  187 + /**
  188 + * 预留字段 2
  189 + */
  190 + private String attribute2;
  191 + /**
  192 + * 预留字段 3
  193 + */
  194 + private Integer attribute3;
  195 + /**
  196 + * 预留字段 4
  197 + */
  198 + private Integer attribute4;
  199 +
  200 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/MesQcIqcDefectDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.dataobject.qc;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
  5 +import com.baomidou.mybatisplus.annotation.TableId;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.*;
  8 +
  9 +/**
  10 + * MES 来料检验缺陷记录 DO
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@TableName("mes_qc_iqc_defect")
  15 +@KeySequence("mes_qc_iqc_defect_seq")
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +@Builder
  20 +@NoArgsConstructor
  21 +@AllArgsConstructor
  22 +public class MesQcIqcDefectDO extends BaseDO {
  23 +
  24 + /**
  25 + * 编号
  26 + */
  27 + @TableId
  28 + private Long id;
  29 + /**
  30 + * 来料检验单 ID
  31 + *
  32 + * 关联 {@link MesQcIqcDO#getId()}
  33 + */
  34 + private Long iqcId;
  35 + /**
  36 + * 来料检验行 ID
  37 + *
  38 + * 关联 {@link MesQcIqcLineDO#getId()}
  39 + */
  40 + private Long lineId;
  41 + /**
  42 + * 缺陷描述
  43 + */
  44 + private String defectName;
  45 + // TODO @AI:要不枚举值也加下,也改成 int;
  46 + /**
  47 + * 缺陷等级
  48 + *
  49 + * 字典 mes_defect_level
  50 + */
  51 + private String defectLevel;
  52 + /**
  53 + * 缺陷数量
  54 + */
  55 + private Integer defectQuantity;
  56 + /**
  57 + * 备注
  58 + */
  59 + private String remark;
  60 +
  61 + // ========== 预留字段 ==========
  62 +
  63 + /**
  64 + * 预留字段 1
  65 + */
  66 + private String attribute1;
  67 + /**
  68 + * 预留字段 2
  69 + */
  70 + private String attribute2;
  71 + /**
  72 + * 预留字段 3
  73 + */
  74 + private Integer attribute3;
  75 + /**
  76 + * 预留字段 4
  77 + */
  78 + private Integer attribute4;
  79 +
  80 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/qc/MesQcIqcLineDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.dataobject.qc;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.tm.tool.MesTmToolDO;
  6 +import com.baomidou.mybatisplus.annotation.KeySequence;
  7 +import com.baomidou.mybatisplus.annotation.TableId;
  8 +import com.baomidou.mybatisplus.annotation.TableName;
  9 +import lombok.*;
  10 +
  11 +import java.math.BigDecimal;
  12 +
  13 +/**
  14 + * MES 来料检验单行 DO
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@TableName("mes_qc_iqc_line")
  19 +@KeySequence("mes_qc_iqc_line_seq")
  20 +@Data
  21 +@EqualsAndHashCode(callSuper = true)
  22 +@ToString(callSuper = true)
  23 +@Builder
  24 +@NoArgsConstructor
  25 +@AllArgsConstructor
  26 +public class MesQcIqcLineDO extends BaseDO {
  27 +
  28 + /**
  29 + * 编号
  30 + */
  31 + @TableId
  32 + private Long id;
  33 + /**
  34 + * 来料检验单 ID
  35 + *
  36 + * 关联 {@link MesQcIqcDO#getId()}
  37 + */
  38 + private Long iqcId;
  39 + /**
  40 + * 检测指标 ID
  41 + *
  42 + * 关联 {@link MesQcIndicatorDO#getId()}
  43 + */
  44 + private Long indicatorId;
  45 + /**
  46 + * 检测工具 ID
  47 + *
  48 + * 关联 {@link MesTmToolDO#getId()}
  49 + */
  50 + private Long toolId;
  51 + /**
  52 + * 检测方法
  53 + */
  54 + private String checkMethod;
  55 + /**
  56 + * 标准值
  57 + */
  58 + private BigDecimal standardValue;
  59 + /**
  60 + * 计量单位 ID
  61 + *
  62 + * 关联 {@link MesMdUnitMeasureDO#getId()}
  63 + */
  64 + private Long unitMeasureId;
  65 + /**
  66 + * 误差上限
  67 + */
  68 + private BigDecimal maxThreshold;
  69 + /**
  70 + * 误差下限
  71 + */
  72 + private BigDecimal minThreshold;
  73 + /**
  74 + * 致命缺陷数量
  75 + */
  76 + private Integer criticalQuantity;
  77 + /**
  78 + * 严重缺陷数量
  79 + */
  80 + private Integer majorQuantity;
  81 + /**
  82 + * 轻微缺陷数量
  83 + */
  84 + private Integer minorQuantity;
  85 + /**
  86 + * 备注
  87 + */
  88 + private String remark;
  89 +
  90 + // ========== 预留字段 ==========
  91 +
  92 + /**
  93 + * 预留字段 1
  94 + */
  95 + private String attribute1;
  96 + /**
  97 + * 预留字段 2
  98 + */
  99 + private String attribute2;
  100 + /**
  101 + * 预留字段 3
  102 + */
  103 + private Integer attribute3;
  104 + /**
  105 + * 预留字段 4
  106 + */
  107 + private Integer attribute4;
  108 +
  109 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/MesQcIqcDefectMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.mysql.qc;
  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.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/dal/mysql/qc/MesQcIqcLineMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.mysql.qc;
  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.line.MesQcIqcLinePageReqVO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.MesQcIqcLineDO;
  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 MesQcIqcLineMapper extends BaseMapperX<MesQcIqcLineDO> {
  19 +
  20 + default PageResult<MesQcIqcLineDO> selectPage(MesQcIqcLinePageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<MesQcIqcLineDO>()
  22 + .eqIfPresent(MesQcIqcLineDO::getIqcId, reqVO.getIqcId())
  23 + .orderByAsc(MesQcIqcLineDO::getId));
  24 + }
  25 +
  26 + default List<MesQcIqcLineDO> selectListByIqcId(Long iqcId) {
  27 + return selectList(MesQcIqcLineDO::getIqcId, iqcId);
  28 + }
  29 +
  30 + default void deleteByIqcId(Long iqcId) {
  31 + delete(new LambdaQueryWrapperX<MesQcIqcLineDO>()
  32 + .eq(MesQcIqcLineDO::getIqcId, iqcId));
  33 + }
  34 +
  35 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/qc/MesQcIqcMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.mysql.qc;
  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.MesQcIqcPageReqVO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.MesQcIqcDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +/**
  11 + * MES 来料检验单(IQC) Mapper
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@Mapper
  16 +public interface MesQcIqcMapper extends BaseMapperX<MesQcIqcDO> {
  17 +
  18 + default PageResult<MesQcIqcDO> selectPage(MesQcIqcPageReqVO reqVO) {
  19 + return selectPage(reqVO, new LambdaQueryWrapperX<MesQcIqcDO>()
  20 + .likeIfPresent(MesQcIqcDO::getCode, reqVO.getCode())
  21 + .eqIfPresent(MesQcIqcDO::getVendorId, reqVO.getVendorId())
  22 + .likeIfPresent(MesQcIqcDO::getVendorBatch, reqVO.getVendorBatch())
  23 + .eqIfPresent(MesQcIqcDO::getItemId, reqVO.getItemId())
  24 + .eqIfPresent(MesQcIqcDO::getCheckResult, reqVO.getCheckResult())
  25 + .eqIfPresent(MesQcIqcDO::getStatus, reqVO.getStatus())
  26 + .betweenIfPresent(MesQcIqcDO::getReceiveDate, reqVO.getReceiveDate())
  27 + .betweenIfPresent(MesQcIqcDO::getInspectDate, reqVO.getInspectDate())
  28 + .orderByDesc(MesQcIqcDO::getId));
  29 + }
  30 +
  31 + default MesQcIqcDO selectByCode(String code) {
  32 + return selectOne(MesQcIqcDO::getCode, code);
  33 + }
  34 +
  35 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/DictTypeConstants.java
@@ -17,6 +17,7 @@ public interface DictTypeConstants { @@ -17,6 +17,7 @@ public interface DictTypeConstants {
17 String MES_CAL_CALENDAR_TYPE = "mes_cal_calendar_type"; // MES 班组类型 17 String MES_CAL_CALENDAR_TYPE = "mes_cal_calendar_type"; // MES 班组类型
18 String MES_CAL_PLAN_STATUS = "mes_cal_plan_status"; // MES 排班计划状态 18 String MES_CAL_PLAN_STATUS = "mes_cal_plan_status"; // MES 排班计划状态
19 String MES_DV_MACHINERY_STATUS = "mes_dv_machinery_status"; // MES 设备状态 19 String MES_DV_MACHINERY_STATUS = "mes_dv_machinery_status"; // MES 设备状态
  20 + String MES_DV_SUBJECT_TYPE = "mes_dv_subject_type"; // MES 点检保养项目类型
20 String MES_INDEX_TYPE = "mes_index_type"; // MES 检测项类型 21 String MES_INDEX_TYPE = "mes_index_type"; // MES 检测项类型
21 String MES_QC_RESULT_TYPE = "mes_qc_result_type"; // MES 质检结果值类型 22 String MES_QC_RESULT_TYPE = "mes_qc_result_type"; // MES 质检结果值类型
22 String MES_DEFECT_LEVEL = "mes_defect_level"; // MES 缺陷等级 23 String MES_DEFECT_LEVEL = "mes_defect_level"; // MES 缺陷等级
@@ -26,5 +27,8 @@ public interface DictTypeConstants { @@ -26,5 +27,8 @@ public interface DictTypeConstants {
26 String MES_QC_TYPE = "mes_qc_type"; // MES 检测种类(IQC/IPQC/OQC/RQC) 27 String MES_QC_TYPE = "mes_qc_type"; // MES 检测种类(IQC/IPQC/OQC/RQC)
27 String MES_PRO_LINK_TYPE = "mes_pro_link_type"; // MES 工序关系类型 28 String MES_PRO_LINK_TYPE = "mes_pro_link_type"; // MES 工序关系类型
28 String MES_TIME_UNIT_TYPE = "mes_time_unit_type"; // MES 时间单位 29 String MES_TIME_UNIT_TYPE = "mes_time_unit_type"; // MES 时间单位
  30 + String MES_QC_IQC_STATUS = "mes_qc_iqc_status"; // MES 检验单状态
  31 + String MES_QC_CHECK_RESULT = "mes_qc_check_result"; // MES 检测结果
  32 + String MES_QC_SOURCE_DOC_TYPE = "mes_qc_source_doc_type"; // MES 来源单据类型
29 33
30 } 34 }
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
@@ -120,6 +120,10 @@ public interface ErrorCodeConstants { @@ -120,6 +120,10 @@ public interface ErrorCodeConstants {
120 ErrorCode DV_MACHINERY_NOT_EXISTS = new ErrorCode(1_040_301_000, "设备不存在"); 120 ErrorCode DV_MACHINERY_NOT_EXISTS = new ErrorCode(1_040_301_000, "设备不存在");
121 ErrorCode DV_MACHINERY_CODE_DUPLICATE = new ErrorCode(1_040_301_001, "设备编码已存在"); 121 ErrorCode DV_MACHINERY_CODE_DUPLICATE = new ErrorCode(1_040_301_001, "设备编码已存在");
122 122
  123 + // ========== MES 设备管理-点检保养项目(1-040-304-000) ==========
  124 + ErrorCode DV_SUBJECT_NOT_EXISTS = new ErrorCode(1_040_304_000, "点检保养项目不存在");
  125 + ErrorCode DV_SUBJECT_CODE_DUPLICATE = new ErrorCode(1_040_304_001, "项目编码已存在");
  126 +
123 // ========== MES 设备管理-点检计划(1-040-302-000) ========== 127 // ========== MES 设备管理-点检计划(1-040-302-000) ==========
124 ErrorCode DV_CHECK_PLAN_NOT_EXISTS = new ErrorCode(1_040_302_000, "点检计划不存在"); 128 ErrorCode DV_CHECK_PLAN_NOT_EXISTS = new ErrorCode(1_040_302_000, "点检计划不存在");
125 129
@@ -192,6 +196,18 @@ public interface ErrorCodeConstants { @@ -192,6 +196,18 @@ public interface ErrorCodeConstants {
192 ErrorCode QC_DEFECT_CODE_DUPLICATE = new ErrorCode(1_040_602_001, "缺陷类型编码已存在"); 196 ErrorCode QC_DEFECT_CODE_DUPLICATE = new ErrorCode(1_040_602_001, "缺陷类型编码已存在");
193 ErrorCode QC_DEFECT_NAME_DUPLICATE = new ErrorCode(1_040_602_002, "缺陷类型名称已存在"); 197 ErrorCode QC_DEFECT_NAME_DUPLICATE = new ErrorCode(1_040_602_002, "缺陷类型名称已存在");
194 198
  199 + // ========== MES 质量管理-来料检验 IQC(1-040-603-000) ==========
  200 + ErrorCode QC_IQC_NOT_EXISTS = new ErrorCode(1_040_603_000, "来料检验单不存在");
  201 + ErrorCode QC_IQC_CODE_DUPLICATE = new ErrorCode(1_040_603_001, "来料检验单编号已存在");
  202 + ErrorCode QC_IQC_ONLY_PREPARE_CAN_DELETE = new ErrorCode(1_040_603_002, "只能删除草稿状态的检验单");
  203 + ErrorCode QC_IQC_ONLY_PREPARE_CAN_COMPLETE = new ErrorCode(1_040_603_003, "只能完成草稿状态的检验单");
  204 + ErrorCode QC_IQC_QUANTITY_MISMATCH = new ErrorCode(1_040_603_004, "合格品与不合格品数量之和须等于检测数量");
  205 + ErrorCode QC_IQC_NO_TEMPLATE = new ErrorCode(1_040_603_005, "当前产品未配置 IQC 检测模板");
  206 + // ========== MES 质量管理-来料检验行(1-040-603-100) ==========
  207 + ErrorCode QC_IQC_LINE_NOT_EXISTS = new ErrorCode(1_040_603_100, "来料检验行不存在");
  208 + // ========== MES 质量管理-来料检验缺陷(1-040-603-200) ==========
  209 + ErrorCode QC_IQC_DEFECT_NOT_EXISTS = new ErrorCode(1_040_603_200, "来料检验缺陷记录不存在");
  210 +
195 // ========== MES 仓库管理-仓库(1-040-700-000) ========== 211 // ========== MES 仓库管理-仓库(1-040-700-000) ==========
196 ErrorCode WM_WAREHOUSE_NOT_EXISTS = new ErrorCode(1_040_700_000, "仓库不存在"); 212 ErrorCode WM_WAREHOUSE_NOT_EXISTS = new ErrorCode(1_040_700_000, "仓库不存在");
197 ErrorCode WM_WAREHOUSE_CODE_DUPLICATE = new ErrorCode(1_040_700_001, "仓库编码已存在"); 213 ErrorCode WM_WAREHOUSE_CODE_DUPLICATE = new ErrorCode(1_040_700_001, "仓库编码已存在");
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/MesQcIqcService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.qc;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.*;
  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.MesQcIqcDefectSaveReqVO;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.line.MesQcIqcLinePageReqVO;
  8 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.MesQcIqcDO;
  9 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.MesQcIqcDefectDO;
  10 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.MesQcIqcLineDO;
  11 +import jakarta.validation.Valid;
  12 +
  13 +// TODO @AI:和别的模块一样,拆分成多个 service
  14 +/**
  15 + * MES 来料检验单(IQC) Service 接口
  16 + *
  17 + * @author 芋道源码
  18 + */
  19 +public interface MesQcIqcService {
  20 +
  21 + // ========== 来料检验主表 ==========
  22 +
  23 + /**
  24 + * 创建来料检验单
  25 + *
  26 + * @param createReqVO 创建信息
  27 + * @return 编号
  28 + */
  29 + Long createIqc(@Valid MesQcIqcSaveReqVO createReqVO);
  30 +
  31 + /**
  32 + * 更新来料检验单
  33 + *
  34 + * @param updateReqVO 更新信息
  35 + */
  36 + void updateIqc(@Valid MesQcIqcSaveReqVO updateReqVO);
  37 +
  38 + /**
  39 + * 完成来料检验单
  40 + *
  41 + * @param id 编号
  42 + */
  43 + void completeIqc(Long id);
  44 +
  45 + /**
  46 + * 删除来料检验单
  47 + *
  48 + * @param id 编号
  49 + */
  50 + void deleteIqc(Long id);
  51 +
  52 + /**
  53 + * 获得来料检验单
  54 + *
  55 + * @param id 编号
  56 + * @return 来料检验单
  57 + */
  58 + MesQcIqcDO getIqc(Long id);
  59 +
  60 + /**
  61 + * 获得来料检验单分页
  62 + *
  63 + * @param pageReqVO 分页查询
  64 + * @return 来料检验单分页
  65 + */
  66 + PageResult<MesQcIqcDO> getIqcPage(MesQcIqcPageReqVO pageReqVO);
  67 +
  68 + // ========== 来料检验行(只读) ==========
  69 +
  70 + /**
  71 + * 获得来料检验行
  72 + *
  73 + * @param id 编号
  74 + * @return 来料检验行
  75 + */
  76 + MesQcIqcLineDO getIqcLine(Long id);
  77 +
  78 + /**
  79 + * 获得来料检验行分页
  80 + *
  81 + * @param pageReqVO 分页查询
  82 + * @return 来料检验行分页
  83 + */
  84 + PageResult<MesQcIqcLineDO> getIqcLinePage(MesQcIqcLinePageReqVO pageReqVO);
  85 +
  86 + // ========== 来料检验缺陷记录 ==========
  87 +
  88 + /**
  89 + * 创建来料检验缺陷记录
  90 + *
  91 + * @param createReqVO 创建信息
  92 + * @return 编号
  93 + */
  94 + Long createIqcDefect(@Valid MesQcIqcDefectSaveReqVO createReqVO);
  95 +
  96 + /**
  97 + * 更新来料检验缺陷记录
  98 + *
  99 + * @param updateReqVO 更新信息
  100 + */
  101 + void updateIqcDefect(@Valid MesQcIqcDefectSaveReqVO updateReqVO);
  102 +
  103 + /**
  104 + * 删除来料检验缺陷记录
  105 + *
  106 + * @param id 编号
  107 + */
  108 + void deleteIqcDefect(Long id);
  109 +
  110 + /**
  111 + * 获得来料检验缺陷记录分页
  112 + *
  113 + * @param pageReqVO 分页查询
  114 + * @return 来料检验缺陷记录分页
  115 + */
  116 + PageResult<MesQcIqcDefectDO> getIqcDefectPage(MesQcIqcDefectPageReqVO pageReqVO);
  117 +
  118 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/MesQcIqcServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.qc;
  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.*;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect.MesQcIqcDefectPageReqVO;
  8 +import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.defect.MesQcIqcDefectSaveReqVO;
  9 +import cn.iocoder.yudao.module.mes.controller.admin.qc.iqc.vo.line.MesQcIqcLinePageReqVO;
  10 +import cn.iocoder.yudao.module.mes.dal.dataobject.qc.*;
  11 +import cn.iocoder.yudao.module.mes.dal.mysql.qc.*;
  12 +import jakarta.annotation.Resource;
  13 +import org.springframework.stereotype.Service;
  14 +import org.springframework.transaction.annotation.Transactional;
  15 +import org.springframework.validation.annotation.Validated;
  16 +
  17 +import java.math.BigDecimal;
  18 +import java.math.RoundingMode;
  19 +import java.util.List;
  20 +import java.util.Objects;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  23 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
  24 +
  25 +// TODO @AI:和别的模块一样,拆分成多个 service
  26 +/**
  27 + * MES 来料检验单(IQC) Service 实现类
  28 + *
  29 + * @author 芋道源码
  30 + */
  31 +@Service
  32 +@Validated
  33 +public class MesQcIqcServiceImpl implements MesQcIqcService {
  34 +
  35 + // TODO @AI:搞个枚举类;
  36 + /**
  37 + * IQC 检测种类值(对应 mes_qc_type 字典 value=1)
  38 + */
  39 + private static final int QC_TYPE_IQC = 1;
  40 +
  41 + @Resource
  42 + private MesQcIqcMapper iqcMapper;
  43 + @Resource
  44 + private MesQcIqcLineMapper iqcLineMapper;
  45 + @Resource
  46 + private MesQcIqcDefectMapper iqcDefectMapper;
  47 + @Resource
  48 + private MesQcTemplateMapper templateMapper;
  49 + @Resource
  50 + private MesQcTemplateIndicatorMapper templateIndicatorMapper;
  51 + @Resource
  52 + private MesQcTemplateItemMapper templateItemMapper;
  53 +
  54 + // ========== 来料检验主表 ==========
  55 +
  56 + @Override
  57 + @Transactional(rollbackFor = Exception.class)
  58 + public Long createIqc(MesQcIqcSaveReqVO createReqVO) {
  59 + // 1. 校验编号唯一
  60 + validateIqcCodeUnique(null, createReqVO.getCode());
  61 +
  62 + // 2. 查找物料关联的 IQC 检测模板
  63 + Long templateId = createReqVO.getTemplateId();
  64 + MesQcTemplateDO template = templateMapper.selectById(templateId);
  65 + if (template == null || template.getTypes() == null || !template.getTypes().contains(QC_TYPE_IQC)) {
  66 + throw exception(QC_IQC_NO_TEMPLATE);
  67 + }
  68 +
  69 + // 3. 从模板的产品关联中获取检测参数(min_check_quantity、max_unqualified_quantity)
  70 + MesQcTemplateItemDO templateItem = templateItemMapper.selectByTemplateIdAndItemId(
  71 + templateId, createReqVO.getItemId());
  72 + if (templateItem != null) {
  73 + if (createReqVO.getMinCheckQuantity() == null) {
  74 + createReqVO.setMinCheckQuantity(templateItem.getQuantityCheck());
  75 + }
  76 + if (createReqVO.getMaxUnqualifiedQuantity() == null) {
  77 + createReqVO.setMaxUnqualifiedQuantity(templateItem.getQuantityUnqualified());
  78 + }
  79 + }
  80 +
  81 + // 4. 插入主表
  82 + MesQcIqcDO iqc = BeanUtils.toBean(createReqVO, MesQcIqcDO.class);
  83 + iqc.setStatus(0); // 草稿
  84 + iqcMapper.insert(iqc);
  85 +
  86 + // 5. 从模板指标自动生成检验行
  87 + List<MesQcTemplateIndicatorDO> indicators = templateIndicatorMapper.selectListByTemplateId(templateId);
  88 + for (MesQcTemplateIndicatorDO indicator : indicators) {
  89 + MesQcIqcLineDO line = new MesQcIqcLineDO();
  90 + line.setIqcId(iqc.getId());
  91 + line.setIndicatorId(indicator.getIndicatorId());
  92 + line.setToolId(null); // TODO @芋艿:模板指标暂无 toolId,后续可扩展
  93 + line.setCheckMethod(indicator.getCheckMethod());
  94 + line.setStandardValue(indicator.getStandardValue());
  95 + line.setUnitMeasureId(indicator.getUnitMeasureId());
  96 + line.setMaxThreshold(indicator.getThresholdMax());
  97 + line.setMinThreshold(indicator.getThresholdMin());
  98 + line.setCriticalQuantity(0);
  99 + line.setMajorQuantity(0);
  100 + line.setMinorQuantity(0);
  101 + iqcLineMapper.insert(line);
  102 + }
  103 +
  104 + return iqc.getId();
  105 + }
  106 +
  107 + @Override
  108 + public void updateIqc(MesQcIqcSaveReqVO updateReqVO) {
  109 + // 1. 校验存在
  110 + MesQcIqcDO iqc = validateIqcExists(updateReqVO.getId());
  111 + // 2. 校验状态为草稿
  112 + if (!Objects.equals(iqc.getStatus(), 0)) {
  113 + throw exception(QC_IQC_ONLY_PREPARE_CAN_COMPLETE);
  114 + }
  115 + // 3. 校验编号唯一
  116 + validateIqcCodeUnique(updateReqVO.getId(), updateReqVO.getCode());
  117 + // 4. 更新
  118 + MesQcIqcDO updateObj = BeanUtils.toBean(updateReqVO, MesQcIqcDO.class);
  119 + iqcMapper.updateById(updateObj);
  120 + }
  121 +
  122 + @Override
  123 + public void completeIqc(Long id) {
  124 + // 1. 校验存在
  125 + MesQcIqcDO iqc = validateIqcExists(id);
  126 + // 2. 校验状态为草稿
  127 + if (!Objects.equals(iqc.getStatus(), 0)) {
  128 + throw exception(QC_IQC_ONLY_PREPARE_CAN_COMPLETE);
  129 + }
  130 + // 3. 校验合格品 + 不合格品 = 检测数量
  131 + if (iqc.getCheckQuantity() != null && iqc.getCheckQuantity() > 0) {
  132 + int total = (iqc.getQualifiedQuantity() != null ? iqc.getQualifiedQuantity() : 0)
  133 + + (iqc.getUnqualifiedQuantity() != null ? iqc.getUnqualifiedQuantity() : 0);
  134 + if (total != iqc.getCheckQuantity()) {
  135 + throw exception(QC_IQC_QUANTITY_MISMATCH);
  136 + }
  137 + }
  138 + // 4. 更新状态为已完成
  139 + MesQcIqcDO updateObj = new MesQcIqcDO();
  140 + updateObj.setId(id);
  141 + updateObj.setStatus(1);
  142 + iqcMapper.updateById(updateObj);
  143 + // TODO @芋艿:WM 模块迁移后,更新到货通知单行/外协入库单行的检验结果
  144 + }
  145 +
  146 + @Override
  147 + @Transactional(rollbackFor = Exception.class)
  148 + public void deleteIqc(Long id) {
  149 + // 1. 校验存在
  150 + MesQcIqcDO iqc = validateIqcExists(id);
  151 + // 2. 仅草稿可删
  152 + if (!Objects.equals(iqc.getStatus(), 0)) {
  153 + throw exception(QC_IQC_ONLY_PREPARE_CAN_DELETE);
  154 + }
  155 + // 3. 删除主表
  156 + iqcMapper.deleteById(id);
  157 + // 4. 级联删除行
  158 + iqcLineMapper.deleteByIqcId(id);
  159 + // 5. 级联删除缺陷记录
  160 + iqcDefectMapper.deleteByIqcId(id);
  161 + }
  162 +
  163 + private MesQcIqcDO validateIqcExists(Long id) {
  164 + MesQcIqcDO iqc = iqcMapper.selectById(id);
  165 + if (iqc == null) {
  166 + throw exception(QC_IQC_NOT_EXISTS);
  167 + }
  168 + return iqc;
  169 + }
  170 +
  171 + private void validateIqcCodeUnique(Long id, String code) {
  172 + MesQcIqcDO iqc = iqcMapper.selectByCode(code);
  173 + if (iqc == null) {
  174 + return;
  175 + }
  176 + if (ObjUtil.notEqual(iqc.getId(), id)) {
  177 + throw exception(QC_IQC_CODE_DUPLICATE);
  178 + }
  179 + }
  180 +
  181 + @Override
  182 + public MesQcIqcDO getIqc(Long id) {
  183 + return iqcMapper.selectById(id);
  184 + }
  185 +
  186 + @Override
  187 + public PageResult<MesQcIqcDO> getIqcPage(MesQcIqcPageReqVO pageReqVO) {
  188 + return iqcMapper.selectPage(pageReqVO);
  189 + }
  190 +
  191 + // ========== 来料检验行(只读) ==========
  192 +
  193 + @Override
  194 + public MesQcIqcLineDO getIqcLine(Long id) {
  195 + return iqcLineMapper.selectById(id);
  196 + }
  197 +
  198 + @Override
  199 + public PageResult<MesQcIqcLineDO> getIqcLinePage(MesQcIqcLinePageReqVO pageReqVO) {
  200 + return iqcLineMapper.selectPage(pageReqVO);
  201 + }
  202 +
  203 + // ========== 来料检验缺陷记录 ==========
  204 +
  205 + @Override
  206 + @Transactional(rollbackFor = Exception.class)
  207 + public Long createIqcDefect(MesQcIqcDefectSaveReqVO createReqVO) {
  208 + // 1. 校验 IQC 存在
  209 + validateIqcExists(createReqVO.getIqcId());
  210 + // 2. 校验行存在
  211 + validateIqcLineExists(createReqVO.getLineId());
  212 + // 3. 插入
  213 + MesQcIqcDefectDO defect = BeanUtils.toBean(createReqVO, MesQcIqcDefectDO.class);
  214 + iqcDefectMapper.insert(defect);
  215 + // 4. 重新计算缺陷统计
  216 + recalculateDefectStats(createReqVO.getIqcId());
  217 + return defect.getId();
  218 + }
  219 +
  220 + @Override
  221 + @Transactional(rollbackFor = Exception.class)
  222 + public void updateIqcDefect(MesQcIqcDefectSaveReqVO updateReqVO) {
  223 + // 1. 校验存在
  224 + validateIqcDefectExists(updateReqVO.getId());
  225 + // 2. 更新
  226 + MesQcIqcDefectDO updateObj = BeanUtils.toBean(updateReqVO, MesQcIqcDefectDO.class);
  227 + iqcDefectMapper.updateById(updateObj);
  228 + // 3. 重新计算缺陷统计
  229 + recalculateDefectStats(updateReqVO.getIqcId());
  230 + }
  231 +
  232 + @Override
  233 + @Transactional(rollbackFor = Exception.class)
  234 + public void deleteIqcDefect(Long id) {
  235 + // 1. 校验存在
  236 + MesQcIqcDefectDO defect = validateIqcDefectExists(id);
  237 + // 2. 删除
  238 + iqcDefectMapper.deleteById(id);
  239 + // 3. 重新计算缺陷统计
  240 + recalculateDefectStats(defect.getIqcId());
  241 + }
  242 +
  243 + private void validateIqcLineExists(Long id) {
  244 + if (iqcLineMapper.selectById(id) == null) {
  245 + throw exception(QC_IQC_LINE_NOT_EXISTS);
  246 + }
  247 + }
  248 +
  249 + private MesQcIqcDefectDO validateIqcDefectExists(Long id) {
  250 + MesQcIqcDefectDO defect = iqcDefectMapper.selectById(id);
  251 + if (defect == null) {
  252 + throw exception(QC_IQC_DEFECT_NOT_EXISTS);
  253 + }
  254 + return defect;
  255 + }
  256 +
  257 + @Override
  258 + public PageResult<MesQcIqcDefectDO> getIqcDefectPage(MesQcIqcDefectPageReqVO pageReqVO) {
  259 + return iqcDefectMapper.selectPage(pageReqVO);
  260 + }
  261 +
  262 + // ========== 内部方法 ==========
  263 +
  264 + /**
  265 + * 重新计算缺陷统计(行级 + 主表级)
  266 + *
  267 + * @param iqcId 来料检验单 ID
  268 + */
  269 + private void recalculateDefectStats(Long iqcId) {
  270 + // 1. 查询所有缺陷记录
  271 + List<MesQcIqcDefectDO> defects = iqcDefectMapper.selectListByIqcId(iqcId);
  272 +
  273 + // 2. 更新每行的缺陷数量
  274 + List<MesQcIqcLineDO> lines = iqcLineMapper.selectListByIqcId(iqcId);
  275 + for (MesQcIqcLineDO line : lines) {
  276 + int critical = 0, major = 0, minor = 0;
  277 + for (MesQcIqcDefectDO defect : defects) {
  278 + if (Objects.equals(defect.getLineId(), line.getId())) {
  279 + int qty = defect.getDefectQuantity() != null ? defect.getDefectQuantity() : 1;
  280 + switch (defect.getDefectLevel()) {
  281 + case "CRITICAL": critical += qty; break;
  282 + case "MAJOR": major += qty; break;
  283 + case "MINOR": minor += qty; break;
  284 + }
  285 + }
  286 + }
  287 + MesQcIqcLineDO updateLine = new MesQcIqcLineDO();
  288 + updateLine.setId(line.getId());
  289 + updateLine.setCriticalQuantity(critical);
  290 + updateLine.setMajorQuantity(major);
  291 + updateLine.setMinorQuantity(minor);
  292 + iqcLineMapper.updateById(updateLine);
  293 + }
  294 +
  295 + // 3. 汇总主表的缺陷数量
  296 + int totalCritical = 0, totalMajor = 0, totalMinor = 0;
  297 + for (MesQcIqcDefectDO defect : defects) {
  298 + int qty = defect.getDefectQuantity() != null ? defect.getDefectQuantity() : 1;
  299 + switch (defect.getDefectLevel()) {
  300 + case "CRITICAL": totalCritical += qty; break;
  301 + case "MAJOR": totalMajor += qty; break;
  302 + case "MINOR": totalMinor += qty; break;
  303 + }
  304 + }
  305 +
  306 + // 4. 计算缺陷率
  307 + MesQcIqcDO iqc = iqcMapper.selectById(iqcId);
  308 + BigDecimal criticalRate = BigDecimal.ZERO;
  309 + BigDecimal majorRate = BigDecimal.ZERO;
  310 + BigDecimal minorRate = BigDecimal.ZERO;
  311 + if (iqc != null && iqc.getCheckQuantity() != null && iqc.getCheckQuantity() > 0) {
  312 + BigDecimal checkQty = BigDecimal.valueOf(iqc.getCheckQuantity());
  313 + criticalRate = BigDecimal.valueOf(totalCritical).multiply(BigDecimal.valueOf(100))
  314 + .divide(checkQty, 2, RoundingMode.HALF_UP);
  315 + majorRate = BigDecimal.valueOf(totalMajor).multiply(BigDecimal.valueOf(100))
  316 + .divide(checkQty, 2, RoundingMode.HALF_UP);
  317 + minorRate = BigDecimal.valueOf(totalMinor).multiply(BigDecimal.valueOf(100))
  318 + .divide(checkQty, 2, RoundingMode.HALF_UP);
  319 + }
  320 +
  321 + // 5. 更新主表
  322 + MesQcIqcDO updateIqc = new MesQcIqcDO();
  323 + updateIqc.setId(iqcId);
  324 + updateIqc.setCriticalQuantity(totalCritical);
  325 + updateIqc.setMajorQuantity(totalMajor);
  326 + updateIqc.setMinorQuantity(totalMinor);
  327 + updateIqc.setCriticalRate(criticalRate);
  328 + updateIqc.setMajorRate(majorRate);
  329 + updateIqc.setMinorRate(minorRate);
  330 + iqcMapper.updateById(updateIqc);
  331 + }
  332 +
  333 +}