Commit 9fc804293cb46086d79b7c5b16134842d35f98c6

Authored by YunaiV
1 parent c3826a2b

feat(mes): 新增产品 BOM、SOP、SIP 子表全链路(MD 主数据)

新增 md_product_bom / md_product_sop / md_product_sip 三张子表的完整后端:
- DO / Mapper / VO / Service / Controller 共 24 个文件
- BOM 支持自引用校验和 DFS 闭环检测
- SOP / SIP 支持排序号唯一校验和图片管理
- 不冗余物料字段,仅存 ID,Controller 层 JOIN 组装展示
- ErrorCodeConstants 新增 6 个错误码
- MesMdItemServiceImpl 增加级联删除
Showing 24 changed files with 1548 additions and 0 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdProductBomController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.md.item;
  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.collection.MapUtils;
  7 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  8 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomPageReqVO;
  9 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomRespVO;
  10 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomSaveReqVO;
  11 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  12 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO;
  13 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO;
  14 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
  15 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  16 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService;
  17 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductBomService;
  18 +import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
  19 +import io.swagger.v3.oas.annotations.Operation;
  20 +import io.swagger.v3.oas.annotations.Parameter;
  21 +import io.swagger.v3.oas.annotations.tags.Tag;
  22 +import jakarta.annotation.Resource;
  23 +import jakarta.validation.Valid;
  24 +import org.springframework.security.access.prepost.PreAuthorize;
  25 +import org.springframework.validation.annotation.Validated;
  26 +import org.springframework.web.bind.annotation.*;
  27 +
  28 +import java.util.Collections;
  29 +import java.util.List;
  30 +import java.util.Map;
  31 +
  32 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  33 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  34 +
  35 +@Tag(name = "管理后台 - MES 产品BOM")
  36 +@RestController
  37 +@RequestMapping("/mes/md/product-bom")
  38 +@Validated
  39 +public class MesMdProductBomController {
  40 +
  41 + @Resource
  42 + private MesMdProductBomService productBomService;
  43 +
  44 + @Resource
  45 + private MesMdItemService itemService;
  46 +
  47 + @Resource
  48 + private MesMdItemTypeService itemTypeService;
  49 +
  50 + @Resource
  51 + private MesMdUnitMeasureService unitMeasureService;
  52 +
  53 + @PostMapping("/create")
  54 + @Operation(summary = "创建产品BOM")
  55 + @PreAuthorize("@ss.hasPermission('mes:md-item:create')")
  56 + public CommonResult<Long> createProductBom(@Valid @RequestBody MesMdProductBomSaveReqVO createReqVO) {
  57 + return success(productBomService.createProductBom(createReqVO));
  58 + }
  59 +
  60 + @PutMapping("/update")
  61 + @Operation(summary = "更新产品BOM")
  62 + @PreAuthorize("@ss.hasPermission('mes:md-item:update')")
  63 + public CommonResult<Boolean> updateProductBom(@Valid @RequestBody MesMdProductBomSaveReqVO updateReqVO) {
  64 + productBomService.updateProductBom(updateReqVO);
  65 + return success(true);
  66 + }
  67 +
  68 + @DeleteMapping("/delete")
  69 + @Operation(summary = "删除产品BOM")
  70 + @Parameter(name = "id", description = "编号", required = true)
  71 + @PreAuthorize("@ss.hasPermission('mes:md-item:delete')")
  72 + public CommonResult<Boolean> deleteProductBom(@RequestParam("id") Long id) {
  73 + productBomService.deleteProductBom(id);
  74 + return success(true);
  75 + }
  76 +
  77 + @GetMapping("/get")
  78 + @Operation(summary = "获得产品BOM")
  79 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  80 + @PreAuthorize("@ss.hasPermission('mes:md-item:query')")
  81 + public CommonResult<MesMdProductBomRespVO> getProductBom(@RequestParam("id") Long id) {
  82 + MesMdProductBomDO productBom = productBomService.getProductBom(id);
  83 + return success(BeanUtils.toBean(productBom, MesMdProductBomRespVO.class));
  84 + }
  85 +
  86 + @GetMapping("/page")
  87 + @Operation(summary = "获得产品BOM分页")
  88 + @PreAuthorize("@ss.hasPermission('mes:md-item:query')")
  89 + public CommonResult<PageResult<MesMdProductBomRespVO>> getProductBomPage(@Valid MesMdProductBomPageReqVO pageReqVO) {
  90 + PageResult<MesMdProductBomDO> pageResult = productBomService.getProductBomPage(pageReqVO);
  91 + List<MesMdProductBomRespVO> voList = buildProductBomRespVOList(pageResult.getList());
  92 + return success(new PageResult<>(voList, pageResult.getTotal()));
  93 + }
  94 +
  95 + @GetMapping("/list-by-item-id")
  96 + @Operation(summary = "根据物料产品编号获得产品BOM列表")
  97 + @Parameter(name = "itemId", description = "物料产品编号", required = true, example = "1")
  98 + @PreAuthorize("@ss.hasPermission('mes:md-item:query')")
  99 + public CommonResult<List<MesMdProductBomRespVO>> getProductBomListByItemId(
  100 + @RequestParam("itemId") Long itemId) {
  101 + List<MesMdProductBomDO> list = productBomService.getProductBomListByItemId(itemId);
  102 + return success(buildProductBomRespVOList(list));
  103 + }
  104 +
  105 + // ==================== 拼接 VO ====================
  106 +
  107 + private List<MesMdProductBomRespVO> buildProductBomRespVOList(List<MesMdProductBomDO> list) {
  108 + if (CollUtil.isEmpty(list)) {
  109 + return Collections.emptyList();
  110 + }
  111 + // 1. 批量获取 BOM 物料信息
  112 + Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(
  113 + convertSet(list, MesMdProductBomDO::getBomItemId));
  114 + // 2. 批量获取计量单位信息
  115 + Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
  116 + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId));
  117 + // 3. 批量获取物料分类信息(用于 itemOrProduct)
  118 + Map<Long, MesMdItemTypeDO> itemTypeMap = itemTypeService.getItemTypeMap(
  119 + convertSet(itemMap.values(), MesMdItemDO::getItemTypeId));
  120 + // 4. 拼接 VO
  121 + return BeanUtils.toBean(list, MesMdProductBomRespVO.class, vo -> {
  122 + MapUtils.findAndThen(itemMap, vo.getBomItemId(), item -> {
  123 + vo.setBomItemCode(item.getCode());
  124 + vo.setBomItemName(item.getName());
  125 + vo.setBomItemSpecification(item.getSpecification());
  126 + MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(),
  127 + unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName()));
  128 + MapUtils.findAndThen(itemTypeMap, item.getItemTypeId(),
  129 + itemType -> vo.setItemOrProduct(itemType.getItemOrProduct()));
  130 + });
  131 + });
  132 + }
  133 +
  134 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdProductSipController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.md.item;
  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.md.item.vo.sip.MesMdProductSipPageReqVO;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipRespVO;
  8 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipSaveReqVO;
  9 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSipDO;
  10 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductSipService;
  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 java.util.List;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +
  24 +@Tag(name = "管理后台 - MES 产品SIP")
  25 +@RestController
  26 +@RequestMapping("/mes/md/product-sip")
  27 +@Validated
  28 +public class MesMdProductSipController {
  29 +
  30 + @Resource
  31 + private MesMdProductSipService productSipService;
  32 +
  33 + @PostMapping("/create")
  34 + @Operation(summary = "创建产品SIP")
  35 + @PreAuthorize("@ss.hasPermission('mes:md-item:create')")
  36 + public CommonResult<Long> createProductSip(@Valid @RequestBody MesMdProductSipSaveReqVO createReqVO) {
  37 + return success(productSipService.createProductSip(createReqVO));
  38 + }
  39 +
  40 + @PutMapping("/update")
  41 + @Operation(summary = "更新产品SIP")
  42 + @PreAuthorize("@ss.hasPermission('mes:md-item:update')")
  43 + public CommonResult<Boolean> updateProductSip(@Valid @RequestBody MesMdProductSipSaveReqVO updateReqVO) {
  44 + productSipService.updateProductSip(updateReqVO);
  45 + return success(true);
  46 + }
  47 +
  48 + @DeleteMapping("/delete")
  49 + @Operation(summary = "删除产品SIP")
  50 + @Parameter(name = "id", description = "编号", required = true)
  51 + @PreAuthorize("@ss.hasPermission('mes:md-item:delete')")
  52 + public CommonResult<Boolean> deleteProductSip(@RequestParam("id") Long id) {
  53 + productSipService.deleteProductSip(id);
  54 + return success(true);
  55 + }
  56 +
  57 + @GetMapping("/get")
  58 + @Operation(summary = "获得产品SIP")
  59 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  60 + @PreAuthorize("@ss.hasPermission('mes:md-item:query')")
  61 + public CommonResult<MesMdProductSipRespVO> getProductSip(@RequestParam("id") Long id) {
  62 + MesMdProductSipDO sip = productSipService.getProductSip(id);
  63 + return success(BeanUtils.toBean(sip, MesMdProductSipRespVO.class));
  64 + }
  65 +
  66 + @GetMapping("/page")
  67 + @Operation(summary = "获得产品SIP分页")
  68 + @PreAuthorize("@ss.hasPermission('mes:md-item:query')")
  69 + public CommonResult<PageResult<MesMdProductSipRespVO>> getProductSipPage(@Valid MesMdProductSipPageReqVO pageReqVO) {
  70 + PageResult<MesMdProductSipDO> pageResult = productSipService.getProductSipPage(pageReqVO);
  71 + // TODO @芋艿:工序模块实现后,补充 processCode/processName 的 JOIN 逻辑
  72 + return success(BeanUtils.toBean(pageResult, MesMdProductSipRespVO.class));
  73 + }
  74 +
  75 + @GetMapping("/list-by-item-id")
  76 + @Operation(summary = "根据物料产品编号,获得产品SIP列表")
  77 + @Parameter(name = "itemId", description = "物料产品编号", required = true, example = "69")
  78 + @PreAuthorize("@ss.hasPermission('mes:md-item:query')")
  79 + public CommonResult<List<MesMdProductSipRespVO>> getProductSipListByItemId(
  80 + @RequestParam("itemId") Long itemId) {
  81 + List<MesMdProductSipDO> list = productSipService.getProductSipListByItemId(itemId);
  82 + // TODO @芋艿:工序模块实现后,补充 processCode/processName 的 JOIN 逻辑
  83 + return success(BeanUtils.toBean(list, MesMdProductSipRespVO.class));
  84 + }
  85 +
  86 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdProductSopController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.md.item;
  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.md.item.vo.sop.MesMdProductSopPageReqVO;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopRespVO;
  8 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopSaveReqVO;
  9 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSopDO;
  10 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductSopService;
  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 java.util.List;
  21 +
  22 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  23 +
  24 +@Tag(name = "管理后台 - MES 产品SOP")
  25 +@RestController
  26 +@RequestMapping("/mes/md/product-sop")
  27 +@Validated
  28 +public class MesMdProductSopController {
  29 +
  30 + @Resource
  31 + private MesMdProductSopService productSopService;
  32 +
  33 + @PostMapping("/create")
  34 + @Operation(summary = "创建产品SOP")
  35 + @PreAuthorize("@ss.hasPermission('mes:md-item:create')")
  36 + public CommonResult<Long> createProductSop(@Valid @RequestBody MesMdProductSopSaveReqVO createReqVO) {
  37 + return success(productSopService.createProductSop(createReqVO));
  38 + }
  39 +
  40 + @PutMapping("/update")
  41 + @Operation(summary = "更新产品SOP")
  42 + @PreAuthorize("@ss.hasPermission('mes:md-item:update')")
  43 + public CommonResult<Boolean> updateProductSop(@Valid @RequestBody MesMdProductSopSaveReqVO updateReqVO) {
  44 + productSopService.updateProductSop(updateReqVO);
  45 + return success(true);
  46 + }
  47 +
  48 + @DeleteMapping("/delete")
  49 + @Operation(summary = "删除产品SOP")
  50 + @Parameter(name = "id", description = "编号", required = true)
  51 + @PreAuthorize("@ss.hasPermission('mes:md-item:delete')")
  52 + public CommonResult<Boolean> deleteProductSop(@RequestParam("id") Long id) {
  53 + productSopService.deleteProductSop(id);
  54 + return success(true);
  55 + }
  56 +
  57 + @GetMapping("/get")
  58 + @Operation(summary = "获得产品SOP")
  59 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  60 + @PreAuthorize("@ss.hasPermission('mes:md-item:query')")
  61 + public CommonResult<MesMdProductSopRespVO> getProductSop(@RequestParam("id") Long id) {
  62 + MesMdProductSopDO sop = productSopService.getProductSop(id);
  63 + return success(BeanUtils.toBean(sop, MesMdProductSopRespVO.class));
  64 + }
  65 +
  66 + @GetMapping("/page")
  67 + @Operation(summary = "获得产品SOP分页")
  68 + @PreAuthorize("@ss.hasPermission('mes:md-item:query')")
  69 + public CommonResult<PageResult<MesMdProductSopRespVO>> getProductSopPage(@Valid MesMdProductSopPageReqVO pageReqVO) {
  70 + PageResult<MesMdProductSopDO> pageResult = productSopService.getProductSopPage(pageReqVO);
  71 + // TODO @芋艿:工序模块实现后,补充 processCode/processName 的 JOIN 逻辑
  72 + return success(BeanUtils.toBean(pageResult, MesMdProductSopRespVO.class));
  73 + }
  74 +
  75 + @GetMapping("/list-by-item-id")
  76 + @Operation(summary = "根据物料产品编号,获得产品SOP列表")
  77 + @Parameter(name = "itemId", description = "物料产品编号", required = true, example = "69")
  78 + @PreAuthorize("@ss.hasPermission('mes:md-item:query')")
  79 + public CommonResult<List<MesMdProductSopRespVO>> getProductSopListByItemId(
  80 + @RequestParam("itemId") Long itemId) {
  81 + List<MesMdProductSopDO> list = productSopService.getProductSopListByItemId(itemId);
  82 + // TODO @芋艿:工序模块实现后,补充 processCode/processName 的 JOIN 逻辑
  83 + return success(BeanUtils.toBean(list, MesMdProductSopRespVO.class));
  84 + }
  85 +
  86 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/bom/MesMdProductBomPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom;
  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 产品BOM分页 Request VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class MesMdProductBomPageReqVO extends PageParam {
  15 +
  16 + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  17 + @NotNull(message = "物料产品ID不能为空")
  18 + private Long itemId;
  19 +
  20 + @Schema(description = "是否启用", example = "0")
  21 + private Integer status;
  22 +
  23 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/bom/MesMdProductBomRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.math.BigDecimal;
  7 +import java.time.LocalDateTime;
  8 +
  9 +@Schema(description = "管理后台 - MES 产品BOM Response VO")
  10 +@Data
  11 +public class MesMdProductBomRespVO {
  12 +
  13 + @Schema(description = "BOM编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  14 + private Long id;
  15 +
  16 + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  17 + private Long itemId;
  18 +
  19 + @Schema(description = "BOM物料ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  20 + private Long bomItemId;
  21 +
  22 + @Schema(description = "物料使用比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.5")
  23 + private BigDecimal quantity;
  24 +
  25 + @Schema(description = "是否启用", example = "0")
  26 + private Integer status;
  27 +
  28 + @Schema(description = "备注", example = "备注")
  29 + private String remark;
  30 +
  31 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  32 + private LocalDateTime createTime;
  33 +
  34 + // ========== 关联展示字段 ==========
  35 +
  36 + @Schema(description = "BOM物料编码", example = "ITEM001")
  37 + private String bomItemCode;
  38 +
  39 + @Schema(description = "BOM物料名称", example = "螺丝")
  40 + private String bomItemName;
  41 +
  42 + @Schema(description = "BOM物料规格", example = "M6*20")
  43 + private String bomItemSpecification;
  44 +
  45 + @Schema(description = "计量单位名称", example = "个")
  46 + private String unitMeasureName;
  47 +
  48 + @Schema(description = "产品物料标识", example = "ITEM")
  49 + private String itemOrProduct;
  50 +
  51 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/bom/MesMdProductBomSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.NotNull;
  5 +import lombok.Data;
  6 +
  7 +import java.math.BigDecimal;
  8 +
  9 +@Schema(description = "管理后台 - MES 产品BOM新增/修改 Request VO")
  10 +@Data
  11 +public class MesMdProductBomSaveReqVO {
  12 +
  13 + @Schema(description = "BOM编号", example = "1024")
  14 + private Long id;
  15 +
  16 + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  17 + @NotNull(message = "物料产品ID不能为空")
  18 + private Long itemId;
  19 +
  20 + @Schema(description = "BOM物料ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
  21 + @NotNull(message = "BOM物料ID不能为空")
  22 + private Long bomItemId;
  23 +
  24 + @Schema(description = "物料使用比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.5")
  25 + @NotNull(message = "物料使用比例不能为空")
  26 + private BigDecimal quantity;
  27 +
  28 + @Schema(description = "是否启用", example = "0")
  29 + private Integer status;
  30 +
  31 + @Schema(description = "备注", example = "备注")
  32 + private String remark;
  33 +
  34 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sip/MesMdProductSipPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip;
  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 产品SIP分页 Request VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class MesMdProductSipPageReqVO extends PageParam {
  15 +
  16 + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "69")
  17 + @NotNull(message = "物料产品ID不能为空")
  18 + private Long itemId;
  19 +
  20 + @Schema(description = "标题", example = "步骤一")
  21 + private String title;
  22 +
  23 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sip/MesMdProductSipRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip;
  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 产品SIP Response VO")
  9 +@Data
  10 +public class MesMdProductSipRespVO {
  11 +
  12 + @Schema(description = "SIP编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  13 + private Long id;
  14 +
  15 + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "69")
  16 + private Long itemId;
  17 +
  18 + @Schema(description = "排列顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  19 + private Integer orderNum;
  20 +
  21 + @Schema(description = "工序ID", example = "100")
  22 + private Long processId;
  23 +
  24 + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "步骤一")
  25 + private String title;
  26 +
  27 + @Schema(description = "详细描述", example = "操作说明")
  28 + private String description;
  29 +
  30 + @Schema(description = "图片地址", example = "https://www.example.com/sip.png")
  31 + private String url;
  32 +
  33 + @Schema(description = "备注", example = "备注信息")
  34 + private String remark;
  35 +
  36 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  37 + private LocalDateTime createTime;
  38 +
  39 + @Schema(description = "工序编号", example = "PROC001")
  40 + private String processCode;
  41 +
  42 + @Schema(description = "工序名称", example = "焊接工序")
  43 + private String processName;
  44 +
  45 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sip/MesMdProductSipSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip;
  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 产品SIP新增/修改 Request VO")
  9 +@Data
  10 +public class MesMdProductSipSaveReqVO {
  11 +
  12 + @Schema(description = "SIP编号", example = "1024")
  13 + private Long id;
  14 +
  15 + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "69")
  16 + @NotNull(message = "物料产品ID不能为空")
  17 + private Long itemId;
  18 +
  19 + @Schema(description = "排列顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  20 + @NotNull(message = "排列顺序不能为空")
  21 + private Integer orderNum;
  22 +
  23 + @Schema(description = "工序ID", example = "100")
  24 + private Long processId;
  25 +
  26 + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "步骤一")
  27 + @NotEmpty(message = "标题不能为空")
  28 + private String title;
  29 +
  30 + @Schema(description = "详细描述", example = "操作说明")
  31 + private String description;
  32 +
  33 + @Schema(description = "图片地址", example = "https://www.example.com/sip.png")
  34 + private String url;
  35 +
  36 + @Schema(description = "备注", example = "备注信息")
  37 + private String remark;
  38 +
  39 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sop/MesMdProductSopPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop;
  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 产品SOP分页 Request VO")
  11 +@Data
  12 +@EqualsAndHashCode(callSuper = true)
  13 +@ToString(callSuper = true)
  14 +public class MesMdProductSopPageReqVO extends PageParam {
  15 +
  16 + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "69")
  17 + @NotNull(message = "物料产品ID不能为空")
  18 + private Long itemId;
  19 +
  20 + @Schema(description = "标题", example = "步骤一")
  21 + private String title;
  22 +
  23 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sop/MesMdProductSopRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop;
  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 产品SOP Response VO")
  9 +@Data
  10 +public class MesMdProductSopRespVO {
  11 +
  12 + @Schema(description = "SOP编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  13 + private Long id;
  14 +
  15 + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "69")
  16 + private Long itemId;
  17 +
  18 + @Schema(description = "排列顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  19 + private Integer orderNum;
  20 +
  21 + @Schema(description = "工序ID", example = "100")
  22 + private Long processId;
  23 +
  24 + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "步骤一")
  25 + private String title;
  26 +
  27 + @Schema(description = "详细描述", example = "操作说明")
  28 + private String description;
  29 +
  30 + @Schema(description = "图片地址", example = "https://www.example.com/sop.png")
  31 + private String url;
  32 +
  33 + @Schema(description = "备注", example = "备注信息")
  34 + private String remark;
  35 +
  36 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  37 + private LocalDateTime createTime;
  38 +
  39 + @Schema(description = "工序编号", example = "PROC001")
  40 + private String processCode;
  41 +
  42 + @Schema(description = "工序名称", example = "焊接工序")
  43 + private String processName;
  44 +
  45 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sop/MesMdProductSopSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop;
  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 产品SOP新增/修改 Request VO")
  9 +@Data
  10 +public class MesMdProductSopSaveReqVO {
  11 +
  12 + @Schema(description = "SOP编号", example = "1024")
  13 + private Long id;
  14 +
  15 + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "69")
  16 + @NotNull(message = "物料产品ID不能为空")
  17 + private Long itemId;
  18 +
  19 + // TODO @AI:orderNumber;包括前端、后端、数据库的字典,都要变更;注意 sql 也去执行下变更;
  20 + @Schema(description = "排列顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  21 + @NotNull(message = "排列顺序不能为空")
  22 + private Integer orderNum;
  23 +
  24 + @Schema(description = "工序ID", example = "100")
  25 + private Long processId;
  26 +
  27 + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "步骤一")
  28 + @NotEmpty(message = "标题不能为空")
  29 + private String title;
  30 +
  31 + @Schema(description = "详细描述", example = "操作说明")
  32 + private String description;
  33 +
  34 + @Schema(description = "图片地址", example = "https://www.example.com/sop.png")
  35 + private String url;
  36 +
  37 + @Schema(description = "备注", example = "备注信息")
  38 + private String remark;
  39 +
  40 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdProductBomDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.dataobject.md.item;
  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 +import java.math.BigDecimal;
  10 +
  11 +/**
  12 + * MES 产品BOM DO
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@TableName("mes_md_product_bom")
  17 +@KeySequence("mes_md_product_bom_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  18 +@Data
  19 +@EqualsAndHashCode(callSuper = true)
  20 +@ToString(callSuper = true)
  21 +@Builder
  22 +@NoArgsConstructor
  23 +@AllArgsConstructor
  24 +public class MesMdProductBomDO extends BaseDO {
  25 +
  26 + /**
  27 + * BOM编号
  28 + */
  29 + @TableId
  30 + private Long id;
  31 + /**
  32 + * 物料产品编号
  33 + *
  34 + * 关联 {@link MesMdItemDO#getId()}
  35 + */
  36 + private Long itemId;
  37 + /**
  38 + * BOM物料编号
  39 + *
  40 + * 关联 {@link MesMdItemDO#getId()}
  41 + */
  42 + private Long bomItemId;
  43 + /**
  44 + * 物料使用比例
  45 + */
  46 + private BigDecimal quantity;
  47 + /**
  48 + * 是否启用
  49 + *
  50 + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum}
  51 + */
  52 + private Integer status;
  53 + /**
  54 + * 备注
  55 + */
  56 + private String remark;
  57 + /**
  58 + * 预留字段1
  59 + */
  60 + private String attribute1;
  61 + /**
  62 + * 预留字段2
  63 + */
  64 + private String attribute2;
  65 + /**
  66 + * 预留字段3
  67 + */
  68 + private Integer attribute3;
  69 + /**
  70 + * 预留字段4
  71 + */
  72 + private Integer attribute4;
  73 +
  74 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdProductSipDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.dataobject.md.item;
  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 产品SIP DO
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@TableName("mes_md_product_sip")
  15 +@KeySequence("mes_md_product_sip_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +@Builder
  20 +@NoArgsConstructor
  21 +@AllArgsConstructor
  22 +public class MesMdProductSipDO extends BaseDO {
  23 +
  24 + /**
  25 + * 编号
  26 + */
  27 + @TableId
  28 + private Long id;
  29 + /**
  30 + * 物料产品编号
  31 + *
  32 + * 关联 {@link MesMdItemDO#getId()}
  33 + */
  34 + private Long itemId;
  35 + /**
  36 + * 排列顺序
  37 + */
  38 + private Integer orderNum;
  39 + /**
  40 + * 工序编号
  41 + */
  42 + // TODO @AI:关联 {@link MesMdProcessDO#getId()},但是目前还没有实现工序模块,所以先不写;后续工序模块实现后,再补上关联关系;
  43 + private Long processId;
  44 + /**
  45 + * 标题
  46 + */
  47 + private String title;
  48 + /**
  49 + * 详细描述
  50 + */
  51 + private String description;
  52 + /**
  53 + * 图片地址
  54 + */
  55 + private String url;
  56 + /**
  57 + * 备注
  58 + */
  59 + private String remark;
  60 + /**
  61 + * 预留字段1
  62 + */
  63 + private String attribute1;
  64 + /**
  65 + * 预留字段2
  66 + */
  67 + private String attribute2;
  68 + /**
  69 + * 预留字段3
  70 + */
  71 + private Integer attribute3;
  72 + /**
  73 + * 预留字段4
  74 + */
  75 + private Integer attribute4;
  76 +
  77 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdProductSopDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.dataobject.md.item;
  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 产品SOP DO
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@TableName("mes_md_product_sop")
  15 +@KeySequence("mes_md_product_sop_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +@Builder
  20 +@NoArgsConstructor
  21 +@AllArgsConstructor
  22 +public class MesMdProductSopDO extends BaseDO {
  23 +
  24 + /**
  25 + * 编号
  26 + */
  27 + @TableId
  28 + private Long id;
  29 + /**
  30 + * 物料产品编号
  31 + *
  32 + * 关联 {@link MesMdItemDO#getId()}
  33 + */
  34 + private Long itemId;
  35 + /**
  36 + * 排列顺序
  37 + */
  38 + private Integer orderNum;
  39 + /**
  40 + * 工序编号
  41 + */
  42 + private Long processId;
  43 + /**
  44 + * 标题
  45 + */
  46 + private String title;
  47 + /**
  48 + * 详细描述
  49 + */
  50 + private String description;
  51 + /**
  52 + * 图片地址
  53 + */
  54 + private String url;
  55 + /**
  56 + * 备注
  57 + */
  58 + private String remark;
  59 + /**
  60 + * 预留字段1
  61 + */
  62 + private String attribute1;
  63 + /**
  64 + * 预留字段2
  65 + */
  66 + private String attribute2;
  67 + /**
  68 + * 预留字段3
  69 + */
  70 + private Integer attribute3;
  71 + /**
  72 + * 预留字段4
  73 + */
  74 + private Integer attribute4;
  75 +
  76 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductBomMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.mysql.md.item;
  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.md.item.vo.bom.MesMdProductBomPageReqVO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * MES 产品BOM Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface MesMdProductBomMapper extends BaseMapperX<MesMdProductBomDO> {
  19 +
  20 + default PageResult<MesMdProductBomDO> selectPage(MesMdProductBomPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<MesMdProductBomDO>()
  22 + .eq(MesMdProductBomDO::getItemId, reqVO.getItemId())
  23 + .eqIfPresent(MesMdProductBomDO::getStatus, reqVO.getStatus())
  24 + .orderByDesc(MesMdProductBomDO::getId));
  25 + }
  26 +
  27 + default List<MesMdProductBomDO> selectByItemId(Long itemId) {
  28 + return selectList(MesMdProductBomDO::getItemId, itemId);
  29 + }
  30 +
  31 + default List<MesMdProductBomDO> selectAll() {
  32 + return selectList();
  33 + }
  34 +
  35 + default void deleteByItemId(Long itemId) {
  36 + delete(MesMdProductBomDO::getItemId, itemId);
  37 + }
  38 +
  39 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductSipMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.mysql.md.item;
  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.md.item.vo.sip.MesMdProductSipPageReqVO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSipDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * MES 产品SIP Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface MesMdProductSipMapper extends BaseMapperX<MesMdProductSipDO> {
  19 +
  20 + default PageResult<MesMdProductSipDO> selectPage(MesMdProductSipPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<MesMdProductSipDO>()
  22 + .eq(MesMdProductSipDO::getItemId, reqVO.getItemId())
  23 + .likeIfPresent(MesMdProductSipDO::getTitle, reqVO.getTitle())
  24 + .orderByAsc(MesMdProductSipDO::getOrderNum));
  25 + }
  26 +
  27 + default List<MesMdProductSipDO> selectByItemId(Long itemId) {
  28 + return selectList(new LambdaQueryWrapperX<MesMdProductSipDO>()
  29 + .eq(MesMdProductSipDO::getItemId, itemId)
  30 + .orderByAsc(MesMdProductSipDO::getOrderNum));
  31 + }
  32 +
  33 + default Long selectCountByItemIdAndOrderNum(Long itemId, Integer orderNum, Long excludeId) {
  34 + return selectCount(new LambdaQueryWrapperX<MesMdProductSipDO>()
  35 + .eq(MesMdProductSipDO::getItemId, itemId)
  36 + .eq(MesMdProductSipDO::getOrderNum, orderNum)
  37 + .neIfPresent(MesMdProductSipDO::getId, excludeId));
  38 + }
  39 +
  40 + default void deleteByItemId(Long itemId) {
  41 + delete(MesMdProductSipDO::getItemId, itemId);
  42 + }
  43 +
  44 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductSopMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.mysql.md.item;
  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.md.item.vo.sop.MesMdProductSopPageReqVO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSopDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +import java.util.List;
  11 +
  12 +/**
  13 + * MES 产品SOP Mapper
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Mapper
  18 +public interface MesMdProductSopMapper extends BaseMapperX<MesMdProductSopDO> {
  19 +
  20 + default PageResult<MesMdProductSopDO> selectPage(MesMdProductSopPageReqVO reqVO) {
  21 + return selectPage(reqVO, new LambdaQueryWrapperX<MesMdProductSopDO>()
  22 + .eq(MesMdProductSopDO::getItemId, reqVO.getItemId())
  23 + .likeIfPresent(MesMdProductSopDO::getTitle, reqVO.getTitle())
  24 + .orderByAsc(MesMdProductSopDO::getOrderNum));
  25 + }
  26 +
  27 + default List<MesMdProductSopDO> selectByItemId(Long itemId) {
  28 + return selectList(new LambdaQueryWrapperX<MesMdProductSopDO>()
  29 + .eq(MesMdProductSopDO::getItemId, itemId)
  30 + .orderByAsc(MesMdProductSopDO::getOrderNum));
  31 + }
  32 +
  33 + default Long selectCountByItemIdAndOrderNum(Long itemId, Integer orderNum, Long excludeId) {
  34 + return selectCount(new LambdaQueryWrapperX<MesMdProductSopDO>()
  35 + .eq(MesMdProductSopDO::getItemId, itemId)
  36 + .eq(MesMdProductSopDO::getOrderNum, orderNum)
  37 + .neIfPresent(MesMdProductSopDO::getId, excludeId));
  38 + }
  39 +
  40 + default void deleteByItemId(Long itemId) {
  41 + delete(MesMdProductSopDO::getItemId, itemId);
  42 + }
  43 +
  44 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductBomService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.md.item;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomPageReqVO;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomSaveReqVO;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO;
  7 +import jakarta.validation.Valid;
  8 +
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * MES 产品BOM Service 接口
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public interface MesMdProductBomService {
  17 +
  18 + /**
  19 + * 创建产品BOM
  20 + *
  21 + * @param createReqVO 创建信息
  22 + * @return 编号
  23 + */
  24 + Long createProductBom(@Valid MesMdProductBomSaveReqVO createReqVO);
  25 +
  26 + /**
  27 + * 更新产品BOM
  28 + *
  29 + * @param updateReqVO 更新信息
  30 + */
  31 + void updateProductBom(@Valid MesMdProductBomSaveReqVO updateReqVO);
  32 +
  33 + /**
  34 + * 删除产品BOM
  35 + *
  36 + * @param id 编号
  37 + */
  38 + void deleteProductBom(Long id);
  39 +
  40 + /**
  41 + * 获得产品BOM
  42 + *
  43 + * @param id 编号
  44 + * @return 产品BOM
  45 + */
  46 + MesMdProductBomDO getProductBom(Long id);
  47 +
  48 + /**
  49 + * 获得产品BOM分页
  50 + *
  51 + * @param pageReqVO 分页查询
  52 + * @return 产品BOM分页
  53 + */
  54 + PageResult<MesMdProductBomDO> getProductBomPage(MesMdProductBomPageReqVO pageReqVO);
  55 +
  56 + /**
  57 + * 根据物料产品编号获得产品BOM列表
  58 + *
  59 + * @param itemId 物料产品编号
  60 + * @return 产品BOM列表
  61 + */
  62 + List<MesMdProductBomDO> getProductBomListByItemId(Long itemId);
  63 +
  64 + /**
  65 + * 根据物料产品编号删除产品BOM
  66 + *
  67 + * @param itemId 物料产品编号
  68 + */
  69 + void deleteProductBomByItemId(Long itemId);
  70 +
  71 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductBomServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.md.item;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomPageReqVO;
  6 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomSaveReqVO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO;
  8 +import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdProductBomMapper;
  9 +import jakarta.annotation.Resource;
  10 +import org.springframework.context.annotation.Lazy;
  11 +import org.springframework.stereotype.Service;
  12 +import org.springframework.validation.annotation.Validated;
  13 +
  14 +import java.util.*;
  15 +
  16 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  17 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
  18 +
  19 +/**
  20 + * MES 产品BOM Service 实现类
  21 + *
  22 + * @author 芋道源码
  23 + */
  24 +@Service
  25 +@Validated
  26 +public class MesMdProductBomServiceImpl implements MesMdProductBomService {
  27 +
  28 + @Resource
  29 + private MesMdProductBomMapper productBomMapper;
  30 +
  31 + @Resource
  32 + @Lazy // 避免循环依赖
  33 + private MesMdItemService itemService;
  34 +
  35 + // TODO @AI:1.1 1.2 1.3 如果都是校验;
  36 + @Override
  37 + public Long createProductBom(MesMdProductBomSaveReqVO createReqVO) {
  38 + // 1. 校验物料产品存在
  39 + validateItemExists(createReqVO.getItemId());
  40 + // 2. 校验BOM物料存在
  41 + validateItemExists(createReqVO.getBomItemId());
  42 + // 3. 校验不能自引用
  43 + if (createReqVO.getItemId().equals(createReqVO.getBomItemId())) {
  44 + throw exception(MD_PRODUCT_BOM_SELF_REFERENCE);
  45 + }
  46 + // 4. 校验不能形成闭环
  47 + if (hasCycle(createReqVO.getItemId(), createReqVO.getBomItemId())) {
  48 + throw exception(MD_PRODUCT_BOM_CIRCULAR);
  49 + }
  50 +
  51 + // 插入
  52 + MesMdProductBomDO productBom = BeanUtils.toBean(createReqVO, MesMdProductBomDO.class);
  53 + productBomMapper.insert(productBom);
  54 + return productBom.getId();
  55 + }
  56 +
  57 + // TODO @AI:1.1 1.2 1.3 如果都是校验;
  58 + @Override
  59 + public void updateProductBom(MesMdProductBomSaveReqVO updateReqVO) {
  60 + // 1. 校验存在
  61 + validateProductBomExists(updateReqVO.getId());
  62 + // 2. 校验物料产品存在
  63 + validateItemExists(updateReqVO.getItemId());
  64 + // 3. 校验BOM物料存在
  65 + validateItemExists(updateReqVO.getBomItemId());
  66 + // 4. 校验不能自引用
  67 + if (updateReqVO.getItemId().equals(updateReqVO.getBomItemId())) {
  68 + throw exception(MD_PRODUCT_BOM_SELF_REFERENCE);
  69 + }
  70 +
  71 + // 更新
  72 + MesMdProductBomDO updateObj = BeanUtils.toBean(updateReqVO, MesMdProductBomDO.class);
  73 + productBomMapper.updateById(updateObj);
  74 + }
  75 +
  76 + @Override
  77 + public void deleteProductBom(Long id) {
  78 + // 校验存在
  79 + validateProductBomExists(id);
  80 + // 删除
  81 + productBomMapper.deleteById(id);
  82 + }
  83 +
  84 + private void validateProductBomExists(Long id) {
  85 + if (productBomMapper.selectById(id) == null) {
  86 + throw exception(MD_PRODUCT_BOM_NOT_EXISTS);
  87 + }
  88 + }
  89 +
  90 + private void validateItemExists(Long itemId) {
  91 + if (itemService.getItem(itemId) == null) {
  92 + throw exception(MD_ITEM_NOT_EXISTS);
  93 + }
  94 + }
  95 +
  96 + // TODO @AI:看看有没 hutool 工具类里,有没 dfs 检测的?
  97 + /**
  98 + * 检测新增边 (itemId -> bomItemId) 后,BOM 图是否存在闭环
  99 + *
  100 + * @param itemId 父物料编号
  101 + * @param bomItemId BOM子物料编号
  102 + * @return 是否存在闭环
  103 + */
  104 + private boolean hasCycle(Long itemId, Long bomItemId) {
  105 + // 获取所有已有的 BOM 记录
  106 + List<MesMdProductBomDO> allBoms = productBomMapper.selectAll();
  107 + // 构建邻接表:parent -> Set<child>
  108 + Map<Long, Set<Long>> graph = new HashMap<>();
  109 + for (MesMdProductBomDO bom : allBoms) {
  110 + graph.computeIfAbsent(bom.getItemId(), k -> new HashSet<>()).add(bom.getBomItemId());
  111 + }
  112 + // 添加待新增的边
  113 + graph.computeIfAbsent(itemId, k -> new HashSet<>()).add(bomItemId);
  114 + // DFS 检测环
  115 + Set<Long> visited = new HashSet<>();
  116 + Set<Long> inStack = new HashSet<>();
  117 + for (Long node : graph.keySet()) {
  118 + if (dfs(node, graph, visited, inStack)) {
  119 + return true;
  120 + }
  121 + }
  122 + return false;
  123 + }
  124 +
  125 + private boolean dfs(Long node, Map<Long, Set<Long>> graph, Set<Long> visited, Set<Long> inStack) {
  126 + if (inStack.contains(node)) {
  127 + return true;
  128 + }
  129 + if (visited.contains(node)) {
  130 + return false;
  131 + }
  132 + visited.add(node);
  133 + inStack.add(node);
  134 + Set<Long> neighbors = graph.getOrDefault(node, Collections.emptySet());
  135 + for (Long neighbor : neighbors) {
  136 + if (dfs(neighbor, graph, visited, inStack)) {
  137 + return true;
  138 + }
  139 + }
  140 + inStack.remove(node);
  141 + return false;
  142 + }
  143 +
  144 + @Override
  145 + public MesMdProductBomDO getProductBom(Long id) {
  146 + return productBomMapper.selectById(id);
  147 + }
  148 +
  149 + @Override
  150 + public PageResult<MesMdProductBomDO> getProductBomPage(MesMdProductBomPageReqVO pageReqVO) {
  151 + return productBomMapper.selectPage(pageReqVO);
  152 + }
  153 +
  154 + @Override
  155 + public List<MesMdProductBomDO> getProductBomListByItemId(Long itemId) {
  156 + return productBomMapper.selectByItemId(itemId);
  157 + }
  158 +
  159 + @Override
  160 + public void deleteProductBomByItemId(Long itemId) {
  161 + productBomMapper.deleteByItemId(itemId);
  162 + }
  163 +
  164 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSipService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.md.item;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipPageReqVO;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipSaveReqVO;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSipDO;
  7 +import jakarta.validation.Valid;
  8 +
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * MES 产品SIP Service 接口
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public interface MesMdProductSipService {
  17 +
  18 + /**
  19 + * 创建产品SIP
  20 + *
  21 + * @param createReqVO 创建信息
  22 + * @return 编号
  23 + */
  24 + Long createProductSip(@Valid MesMdProductSipSaveReqVO createReqVO);
  25 +
  26 + /**
  27 + * 更新产品SIP
  28 + *
  29 + * @param updateReqVO 更新信息
  30 + */
  31 + void updateProductSip(@Valid MesMdProductSipSaveReqVO updateReqVO);
  32 +
  33 + /**
  34 + * 删除产品SIP
  35 + *
  36 + * @param id 编号
  37 + */
  38 + void deleteProductSip(Long id);
  39 +
  40 + /**
  41 + * 获得产品SIP
  42 + *
  43 + * @param id 编号
  44 + * @return 产品SIP
  45 + */
  46 + MesMdProductSipDO getProductSip(Long id);
  47 +
  48 + /**
  49 + * 获得产品SIP分页
  50 + *
  51 + * @param pageReqVO 分页查询
  52 + * @return 产品SIP分页
  53 + */
  54 + PageResult<MesMdProductSipDO> getProductSipPage(MesMdProductSipPageReqVO pageReqVO);
  55 +
  56 + /**
  57 + * 根据物料产品编号,获得产品SIP列表
  58 + *
  59 + * @param itemId 物料产品编号
  60 + * @return 产品SIP列表
  61 + */
  62 + List<MesMdProductSipDO> getProductSipListByItemId(Long itemId);
  63 +
  64 + /**
  65 + * 根据物料产品编号,删除产品SIP
  66 + *
  67 + * @param itemId 物料产品编号
  68 + */
  69 + void deleteProductSipByItemId(Long itemId);
  70 +
  71 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSipServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.md.item;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipPageReqVO;
  6 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipSaveReqVO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSipDO;
  8 +import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdProductSipMapper;
  9 +import jakarta.annotation.Resource;
  10 +import org.springframework.stereotype.Service;
  11 +import org.springframework.validation.annotation.Validated;
  12 +
  13 +import java.util.List;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  16 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
  17 +
  18 +/**
  19 + * MES 产品SIP Service 实现类
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +@Service
  24 +@Validated
  25 +public class MesMdProductSipServiceImpl implements MesMdProductSipService {
  26 +
  27 + @Resource
  28 + private MesMdProductSipMapper productSipMapper;
  29 +
  30 + @Override
  31 + public Long createProductSip(MesMdProductSipSaveReqVO createReqVO) {
  32 + // 校验排列顺序的唯一性
  33 + validateOrderNumUnique(createReqVO.getItemId(), createReqVO.getOrderNum(), null);
  34 +
  35 + // 插入
  36 + MesMdProductSipDO sip = BeanUtils.toBean(createReqVO, MesMdProductSipDO.class);
  37 + productSipMapper.insert(sip);
  38 + return sip.getId();
  39 + }
  40 +
  41 + @Override
  42 + public void updateProductSip(MesMdProductSipSaveReqVO updateReqVO) {
  43 + // 校验存在
  44 + validateProductSipExists(updateReqVO.getId());
  45 + // 校验排列顺序的唯一性
  46 + validateOrderNumUnique(updateReqVO.getItemId(), updateReqVO.getOrderNum(), updateReqVO.getId());
  47 +
  48 + // 更新
  49 + MesMdProductSipDO updateObj = BeanUtils.toBean(updateReqVO, MesMdProductSipDO.class);
  50 + productSipMapper.updateById(updateObj);
  51 + }
  52 +
  53 + @Override
  54 + public void deleteProductSip(Long id) {
  55 + // 校验存在
  56 + validateProductSipExists(id);
  57 + // 删除
  58 + productSipMapper.deleteById(id);
  59 + }
  60 +
  61 + private void validateProductSipExists(Long id) {
  62 + if (productSipMapper.selectById(id) == null) {
  63 + throw exception(MD_PRODUCT_SIP_NOT_EXISTS);
  64 + }
  65 + }
  66 +
  67 + private void validateOrderNumUnique(Long itemId, Integer orderNum, Long excludeId) {
  68 + Long count = productSipMapper.selectCountByItemIdAndOrderNum(itemId, orderNum, excludeId);
  69 + if (count > 0) {
  70 + throw exception(MD_PRODUCT_SIP_ORDER_NUM_DUPLICATE);
  71 + }
  72 + }
  73 +
  74 + @Override
  75 + public MesMdProductSipDO getProductSip(Long id) {
  76 + return productSipMapper.selectById(id);
  77 + }
  78 +
  79 + @Override
  80 + public PageResult<MesMdProductSipDO> getProductSipPage(MesMdProductSipPageReqVO pageReqVO) {
  81 + return productSipMapper.selectPage(pageReqVO);
  82 + }
  83 +
  84 + @Override
  85 + public List<MesMdProductSipDO> getProductSipListByItemId(Long itemId) {
  86 + return productSipMapper.selectByItemId(itemId);
  87 + }
  88 +
  89 + @Override
  90 + public void deleteProductSipByItemId(Long itemId) {
  91 + productSipMapper.deleteByItemId(itemId);
  92 + }
  93 +
  94 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSopService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.md.item;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopPageReqVO;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopSaveReqVO;
  6 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSopDO;
  7 +import jakarta.validation.Valid;
  8 +
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * MES 产品SOP Service 接口
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public interface MesMdProductSopService {
  17 +
  18 + /**
  19 + * 创建产品SOP
  20 + *
  21 + * @param createReqVO 创建信息
  22 + * @return 编号
  23 + */
  24 + Long createProductSop(@Valid MesMdProductSopSaveReqVO createReqVO);
  25 +
  26 + /**
  27 + * 更新产品SOP
  28 + *
  29 + * @param updateReqVO 更新信息
  30 + */
  31 + void updateProductSop(@Valid MesMdProductSopSaveReqVO updateReqVO);
  32 +
  33 + /**
  34 + * 删除产品SOP
  35 + *
  36 + * @param id 编号
  37 + */
  38 + void deleteProductSop(Long id);
  39 +
  40 + /**
  41 + * 获得产品SOP
  42 + *
  43 + * @param id 编号
  44 + * @return 产品SOP
  45 + */
  46 + MesMdProductSopDO getProductSop(Long id);
  47 +
  48 + /**
  49 + * 获得产品SOP分页
  50 + *
  51 + * @param pageReqVO 分页查询
  52 + * @return 产品SOP分页
  53 + */
  54 + PageResult<MesMdProductSopDO> getProductSopPage(MesMdProductSopPageReqVO pageReqVO);
  55 +
  56 + /**
  57 + * 根据物料产品编号,获得产品SOP列表
  58 + *
  59 + * @param itemId 物料产品编号
  60 + * @return 产品SOP列表
  61 + */
  62 + List<MesMdProductSopDO> getProductSopListByItemId(Long itemId);
  63 +
  64 + /**
  65 + * 根据物料产品编号,删除产品SOP
  66 + *
  67 + * @param itemId 物料产品编号
  68 + */
  69 + void deleteProductSopByItemId(Long itemId);
  70 +
  71 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSopServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.md.item;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopPageReqVO;
  6 +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopSaveReqVO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSopDO;
  8 +import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdProductSopMapper;
  9 +import jakarta.annotation.Resource;
  10 +import org.springframework.stereotype.Service;
  11 +import org.springframework.validation.annotation.Validated;
  12 +
  13 +import java.util.List;
  14 +
  15 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  16 +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
  17 +
  18 +/**
  19 + * MES 产品SOP Service 实现类
  20 + *
  21 + * @author 芋道源码
  22 + */
  23 +@Service
  24 +@Validated
  25 +public class MesMdProductSopServiceImpl implements MesMdProductSopService {
  26 +
  27 + @Resource
  28 + private MesMdProductSopMapper productSopMapper;
  29 +
  30 + @Override
  31 + public Long createProductSop(MesMdProductSopSaveReqVO createReqVO) {
  32 + // 校验排列顺序的唯一性
  33 + validateOrderNumUnique(createReqVO.getItemId(), createReqVO.getOrderNum(), null);
  34 +
  35 + // 插入
  36 + MesMdProductSopDO sop = BeanUtils.toBean(createReqVO, MesMdProductSopDO.class);
  37 + productSopMapper.insert(sop);
  38 + return sop.getId();
  39 + }
  40 +
  41 + @Override
  42 + public void updateProductSop(MesMdProductSopSaveReqVO updateReqVO) {
  43 + // 校验存在
  44 + validateProductSopExists(updateReqVO.getId());
  45 + // 校验排列顺序的唯一性
  46 + validateOrderNumUnique(updateReqVO.getItemId(), updateReqVO.getOrderNum(), updateReqVO.getId());
  47 +
  48 + // 更新
  49 + MesMdProductSopDO updateObj = BeanUtils.toBean(updateReqVO, MesMdProductSopDO.class);
  50 + productSopMapper.updateById(updateObj);
  51 + }
  52 +
  53 + @Override
  54 + public void deleteProductSop(Long id) {
  55 + // 校验存在
  56 + validateProductSopExists(id);
  57 + // 删除
  58 + productSopMapper.deleteById(id);
  59 + }
  60 +
  61 + private void validateProductSopExists(Long id) {
  62 + if (productSopMapper.selectById(id) == null) {
  63 + throw exception(MD_PRODUCT_SOP_NOT_EXISTS);
  64 + }
  65 + }
  66 +
  67 + private void validateOrderNumUnique(Long itemId, Integer orderNum, Long excludeId) {
  68 + Long count = productSopMapper.selectCountByItemIdAndOrderNum(itemId, orderNum, excludeId);
  69 + if (count > 0) {
  70 + throw exception(MD_PRODUCT_SOP_ORDER_NUM_DUPLICATE);
  71 + }
  72 + }
  73 +
  74 + @Override
  75 + public MesMdProductSopDO getProductSop(Long id) {
  76 + return productSopMapper.selectById(id);
  77 + }
  78 +
  79 + @Override
  80 + public PageResult<MesMdProductSopDO> getProductSopPage(MesMdProductSopPageReqVO pageReqVO) {
  81 + return productSopMapper.selectPage(pageReqVO);
  82 + }
  83 +
  84 + @Override
  85 + public List<MesMdProductSopDO> getProductSopListByItemId(Long itemId) {
  86 + return productSopMapper.selectByItemId(itemId);
  87 + }
  88 +
  89 + @Override
  90 + public void deleteProductSopByItemId(Long itemId) {
  91 + productSopMapper.deleteByItemId(itemId);
  92 + }
  93 +
  94 +}