diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdProductBomController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdProductBomController.java new file mode 100644 index 0000000..fc09974 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdProductBomController.java @@ -0,0 +1,134 @@ +package cn.iocoder.yudao.module.mes.controller.admin.md.item; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomRespVO; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemTypeDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemTypeService; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductBomService; +import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +@Tag(name = "管理后台 - MES 产品BOM") +@RestController +@RequestMapping("/mes/md/product-bom") +@Validated +public class MesMdProductBomController { + + @Resource + private MesMdProductBomService productBomService; + + @Resource + private MesMdItemService itemService; + + @Resource + private MesMdItemTypeService itemTypeService; + + @Resource + private MesMdUnitMeasureService unitMeasureService; + + @PostMapping("/create") + @Operation(summary = "创建产品BOM") + @PreAuthorize("@ss.hasPermission('mes:md-item:create')") + public CommonResult createProductBom(@Valid @RequestBody MesMdProductBomSaveReqVO createReqVO) { + return success(productBomService.createProductBom(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产品BOM") + @PreAuthorize("@ss.hasPermission('mes:md-item:update')") + public CommonResult updateProductBom(@Valid @RequestBody MesMdProductBomSaveReqVO updateReqVO) { + productBomService.updateProductBom(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产品BOM") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:md-item:delete')") + public CommonResult deleteProductBom(@RequestParam("id") Long id) { + productBomService.deleteProductBom(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产品BOM") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:md-item:query')") + public CommonResult getProductBom(@RequestParam("id") Long id) { + MesMdProductBomDO productBom = productBomService.getProductBom(id); + return success(BeanUtils.toBean(productBom, MesMdProductBomRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品BOM分页") + @PreAuthorize("@ss.hasPermission('mes:md-item:query')") + public CommonResult> getProductBomPage(@Valid MesMdProductBomPageReqVO pageReqVO) { + PageResult pageResult = productBomService.getProductBomPage(pageReqVO); + List voList = buildProductBomRespVOList(pageResult.getList()); + return success(new PageResult<>(voList, pageResult.getTotal())); + } + + @GetMapping("/list-by-item-id") + @Operation(summary = "根据物料产品编号获得产品BOM列表") + @Parameter(name = "itemId", description = "物料产品编号", required = true, example = "1") + @PreAuthorize("@ss.hasPermission('mes:md-item:query')") + public CommonResult> getProductBomListByItemId( + @RequestParam("itemId") Long itemId) { + List list = productBomService.getProductBomListByItemId(itemId); + return success(buildProductBomRespVOList(list)); + } + + // ==================== 拼接 VO ==================== + + private List buildProductBomRespVOList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + // 1. 批量获取 BOM 物料信息 + Map itemMap = itemService.getItemMap( + convertSet(list, MesMdProductBomDO::getBomItemId)); + // 2. 批量获取计量单位信息 + Map unitMeasureMap = unitMeasureService.getUnitMeasureMap( + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); + // 3. 批量获取物料分类信息(用于 itemOrProduct) + Map itemTypeMap = itemTypeService.getItemTypeMap( + convertSet(itemMap.values(), MesMdItemDO::getItemTypeId)); + // 4. 拼接 VO + return BeanUtils.toBean(list, MesMdProductBomRespVO.class, vo -> { + MapUtils.findAndThen(itemMap, vo.getBomItemId(), item -> { + vo.setBomItemCode(item.getCode()); + vo.setBomItemName(item.getName()); + vo.setBomItemSpecification(item.getSpecification()); + MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(), + unitMeasure -> vo.setUnitMeasureName(unitMeasure.getName())); + MapUtils.findAndThen(itemTypeMap, item.getItemTypeId(), + itemType -> vo.setItemOrProduct(itemType.getItemOrProduct())); + }); + }); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdProductSipController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdProductSipController.java new file mode 100644 index 0000000..f8b764c --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdProductSipController.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.mes.controller.admin.md.item; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipRespVO; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSipDO; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductSipService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - MES 产品SIP") +@RestController +@RequestMapping("/mes/md/product-sip") +@Validated +public class MesMdProductSipController { + + @Resource + private MesMdProductSipService productSipService; + + @PostMapping("/create") + @Operation(summary = "创建产品SIP") + @PreAuthorize("@ss.hasPermission('mes:md-item:create')") + public CommonResult createProductSip(@Valid @RequestBody MesMdProductSipSaveReqVO createReqVO) { + return success(productSipService.createProductSip(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产品SIP") + @PreAuthorize("@ss.hasPermission('mes:md-item:update')") + public CommonResult updateProductSip(@Valid @RequestBody MesMdProductSipSaveReqVO updateReqVO) { + productSipService.updateProductSip(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产品SIP") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:md-item:delete')") + public CommonResult deleteProductSip(@RequestParam("id") Long id) { + productSipService.deleteProductSip(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产品SIP") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:md-item:query')") + public CommonResult getProductSip(@RequestParam("id") Long id) { + MesMdProductSipDO sip = productSipService.getProductSip(id); + return success(BeanUtils.toBean(sip, MesMdProductSipRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品SIP分页") + @PreAuthorize("@ss.hasPermission('mes:md-item:query')") + public CommonResult> getProductSipPage(@Valid MesMdProductSipPageReqVO pageReqVO) { + PageResult pageResult = productSipService.getProductSipPage(pageReqVO); + // TODO @芋艿:工序模块实现后,补充 processCode/processName 的 JOIN 逻辑 + return success(BeanUtils.toBean(pageResult, MesMdProductSipRespVO.class)); + } + + @GetMapping("/list-by-item-id") + @Operation(summary = "根据物料产品编号,获得产品SIP列表") + @Parameter(name = "itemId", description = "物料产品编号", required = true, example = "69") + @PreAuthorize("@ss.hasPermission('mes:md-item:query')") + public CommonResult> getProductSipListByItemId( + @RequestParam("itemId") Long itemId) { + List list = productSipService.getProductSipListByItemId(itemId); + // TODO @芋艿:工序模块实现后,补充 processCode/processName 的 JOIN 逻辑 + return success(BeanUtils.toBean(list, MesMdProductSipRespVO.class)); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdProductSopController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdProductSopController.java new file mode 100644 index 0000000..10dd96b --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/MesMdProductSopController.java @@ -0,0 +1,86 @@ +package cn.iocoder.yudao.module.mes.controller.admin.md.item; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopRespVO; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSopDO; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdProductSopService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - MES 产品SOP") +@RestController +@RequestMapping("/mes/md/product-sop") +@Validated +public class MesMdProductSopController { + + @Resource + private MesMdProductSopService productSopService; + + @PostMapping("/create") + @Operation(summary = "创建产品SOP") + @PreAuthorize("@ss.hasPermission('mes:md-item:create')") + public CommonResult createProductSop(@Valid @RequestBody MesMdProductSopSaveReqVO createReqVO) { + return success(productSopService.createProductSop(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新产品SOP") + @PreAuthorize("@ss.hasPermission('mes:md-item:update')") + public CommonResult updateProductSop(@Valid @RequestBody MesMdProductSopSaveReqVO updateReqVO) { + productSopService.updateProductSop(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除产品SOP") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('mes:md-item:delete')") + public CommonResult deleteProductSop(@RequestParam("id") Long id) { + productSopService.deleteProductSop(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得产品SOP") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('mes:md-item:query')") + public CommonResult getProductSop(@RequestParam("id") Long id) { + MesMdProductSopDO sop = productSopService.getProductSop(id); + return success(BeanUtils.toBean(sop, MesMdProductSopRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得产品SOP分页") + @PreAuthorize("@ss.hasPermission('mes:md-item:query')") + public CommonResult> getProductSopPage(@Valid MesMdProductSopPageReqVO pageReqVO) { + PageResult pageResult = productSopService.getProductSopPage(pageReqVO); + // TODO @芋艿:工序模块实现后,补充 processCode/processName 的 JOIN 逻辑 + return success(BeanUtils.toBean(pageResult, MesMdProductSopRespVO.class)); + } + + @GetMapping("/list-by-item-id") + @Operation(summary = "根据物料产品编号,获得产品SOP列表") + @Parameter(name = "itemId", description = "物料产品编号", required = true, example = "69") + @PreAuthorize("@ss.hasPermission('mes:md-item:query')") + public CommonResult> getProductSopListByItemId( + @RequestParam("itemId") Long itemId) { + List list = productSopService.getProductSopListByItemId(itemId); + // TODO @芋艿:工序模块实现后,补充 processCode/processName 的 JOIN 逻辑 + return success(BeanUtils.toBean(list, MesMdProductSopRespVO.class)); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/bom/MesMdProductBomPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/bom/MesMdProductBomPageReqVO.java new file mode 100644 index 0000000..cdbcc33 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/bom/MesMdProductBomPageReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - MES 产品BOM分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MesMdProductBomPageReqVO extends PageParam { + + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "物料产品ID不能为空") + private Long itemId; + + @Schema(description = "是否启用", example = "0") + private Integer status; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/bom/MesMdProductBomRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/bom/MesMdProductBomRespVO.java new file mode 100644 index 0000000..805a86c --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/bom/MesMdProductBomRespVO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - MES 产品BOM Response VO") +@Data +public class MesMdProductBomRespVO { + + @Schema(description = "BOM编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long itemId; + + @Schema(description = "BOM物料ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + private Long bomItemId; + + @Schema(description = "物料使用比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.5") + private BigDecimal quantity; + + @Schema(description = "是否启用", example = "0") + private Integer status; + + @Schema(description = "备注", example = "备注") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + // ========== 关联展示字段 ========== + + @Schema(description = "BOM物料编码", example = "ITEM001") + private String bomItemCode; + + @Schema(description = "BOM物料名称", example = "螺丝") + private String bomItemName; + + @Schema(description = "BOM物料规格", example = "M6*20") + private String bomItemSpecification; + + @Schema(description = "计量单位名称", example = "个") + private String unitMeasureName; + + @Schema(description = "产品物料标识", example = "ITEM") + private String itemOrProduct; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/bom/MesMdProductBomSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/bom/MesMdProductBomSaveReqVO.java new file mode 100644 index 0000000..426427f --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/bom/MesMdProductBomSaveReqVO.java @@ -0,0 +1,34 @@ +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - MES 产品BOM新增/修改 Request VO") +@Data +public class MesMdProductBomSaveReqVO { + + @Schema(description = "BOM编号", example = "1024") + private Long id; + + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "物料产品ID不能为空") + private Long itemId; + + @Schema(description = "BOM物料ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "BOM物料ID不能为空") + private Long bomItemId; + + @Schema(description = "物料使用比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.5") + @NotNull(message = "物料使用比例不能为空") + private BigDecimal quantity; + + @Schema(description = "是否启用", example = "0") + private Integer status; + + @Schema(description = "备注", example = "备注") + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sip/MesMdProductSipPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sip/MesMdProductSipPageReqVO.java new file mode 100644 index 0000000..cf78d20 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sip/MesMdProductSipPageReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - MES 产品SIP分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MesMdProductSipPageReqVO extends PageParam { + + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "69") + @NotNull(message = "物料产品ID不能为空") + private Long itemId; + + @Schema(description = "标题", example = "步骤一") + private String title; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sip/MesMdProductSipRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sip/MesMdProductSipRespVO.java new file mode 100644 index 0000000..41f3875 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sip/MesMdProductSipRespVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - MES 产品SIP Response VO") +@Data +public class MesMdProductSipRespVO { + + @Schema(description = "SIP编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "69") + private Long itemId; + + @Schema(description = "排列顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer orderNum; + + @Schema(description = "工序ID", example = "100") + private Long processId; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "步骤一") + private String title; + + @Schema(description = "详细描述", example = "操作说明") + private String description; + + @Schema(description = "图片地址", example = "https://www.example.com/sip.png") + private String url; + + @Schema(description = "备注", example = "备注信息") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "工序编号", example = "PROC001") + private String processCode; + + @Schema(description = "工序名称", example = "焊接工序") + private String processName; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sip/MesMdProductSipSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sip/MesMdProductSipSaveReqVO.java new file mode 100644 index 0000000..e14f820 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sip/MesMdProductSipSaveReqVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - MES 产品SIP新增/修改 Request VO") +@Data +public class MesMdProductSipSaveReqVO { + + @Schema(description = "SIP编号", example = "1024") + private Long id; + + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "69") + @NotNull(message = "物料产品ID不能为空") + private Long itemId; + + @Schema(description = "排列顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "排列顺序不能为空") + private Integer orderNum; + + @Schema(description = "工序ID", example = "100") + private Long processId; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "步骤一") + @NotEmpty(message = "标题不能为空") + private String title; + + @Schema(description = "详细描述", example = "操作说明") + private String description; + + @Schema(description = "图片地址", example = "https://www.example.com/sip.png") + private String url; + + @Schema(description = "备注", example = "备注信息") + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sop/MesMdProductSopPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sop/MesMdProductSopPageReqVO.java new file mode 100644 index 0000000..4a90b62 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sop/MesMdProductSopPageReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - MES 产品SOP分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MesMdProductSopPageReqVO extends PageParam { + + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "69") + @NotNull(message = "物料产品ID不能为空") + private Long itemId; + + @Schema(description = "标题", example = "步骤一") + private String title; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sop/MesMdProductSopRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sop/MesMdProductSopRespVO.java new file mode 100644 index 0000000..76a45c7 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sop/MesMdProductSopRespVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - MES 产品SOP Response VO") +@Data +public class MesMdProductSopRespVO { + + @Schema(description = "SOP编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "69") + private Long itemId; + + @Schema(description = "排列顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer orderNum; + + @Schema(description = "工序ID", example = "100") + private Long processId; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "步骤一") + private String title; + + @Schema(description = "详细描述", example = "操作说明") + private String description; + + @Schema(description = "图片地址", example = "https://www.example.com/sop.png") + private String url; + + @Schema(description = "备注", example = "备注信息") + private String remark; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + + @Schema(description = "工序编号", example = "PROC001") + private String processCode; + + @Schema(description = "工序名称", example = "焊接工序") + private String processName; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sop/MesMdProductSopSaveReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sop/MesMdProductSopSaveReqVO.java new file mode 100644 index 0000000..027d1c7 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/sop/MesMdProductSopSaveReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - MES 产品SOP新增/修改 Request VO") +@Data +public class MesMdProductSopSaveReqVO { + + @Schema(description = "SOP编号", example = "1024") + private Long id; + + @Schema(description = "物料产品ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "69") + @NotNull(message = "物料产品ID不能为空") + private Long itemId; + + // TODO @AI:orderNumber;包括前端、后端、数据库的字典,都要变更;注意 sql 也去执行下变更; + @Schema(description = "排列顺序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "排列顺序不能为空") + private Integer orderNum; + + @Schema(description = "工序ID", example = "100") + private Long processId; + + @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "步骤一") + @NotEmpty(message = "标题不能为空") + private String title; + + @Schema(description = "详细描述", example = "操作说明") + private String description; + + @Schema(description = "图片地址", example = "https://www.example.com/sop.png") + private String url; + + @Schema(description = "备注", example = "备注信息") + private String remark; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdProductBomDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdProductBomDO.java new file mode 100644 index 0000000..bbfecb0 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdProductBomDO.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.md.item; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * MES 产品BOM DO + * + * @author 芋道源码 + */ +@TableName("mes_md_product_bom") +@KeySequence("mes_md_product_bom_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MesMdProductBomDO extends BaseDO { + + /** + * BOM编号 + */ + @TableId + private Long id; + /** + * 物料产品编号 + * + * 关联 {@link MesMdItemDO#getId()} + */ + private Long itemId; + /** + * BOM物料编号 + * + * 关联 {@link MesMdItemDO#getId()} + */ + private Long bomItemId; + /** + * 物料使用比例 + */ + private BigDecimal quantity; + /** + * 是否启用 + * + * 枚举 {@link cn.iocoder.yudao.framework.common.enums.CommonStatusEnum} + */ + private Integer status; + /** + * 备注 + */ + private String remark; + /** + * 预留字段1 + */ + private String attribute1; + /** + * 预留字段2 + */ + private String attribute2; + /** + * 预留字段3 + */ + private Integer attribute3; + /** + * 预留字段4 + */ + private Integer attribute4; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdProductSipDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdProductSipDO.java new file mode 100644 index 0000000..dea7866 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdProductSipDO.java @@ -0,0 +1,77 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.md.item; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * MES 产品SIP DO + * + * @author 芋道源码 + */ +@TableName("mes_md_product_sip") +@KeySequence("mes_md_product_sip_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MesMdProductSipDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 物料产品编号 + * + * 关联 {@link MesMdItemDO#getId()} + */ + private Long itemId; + /** + * 排列顺序 + */ + private Integer orderNum; + /** + * 工序编号 + */ + // TODO @AI:关联 {@link MesMdProcessDO#getId()},但是目前还没有实现工序模块,所以先不写;后续工序模块实现后,再补上关联关系; + private Long processId; + /** + * 标题 + */ + private String title; + /** + * 详细描述 + */ + private String description; + /** + * 图片地址 + */ + private String url; + /** + * 备注 + */ + private String remark; + /** + * 预留字段1 + */ + private String attribute1; + /** + * 预留字段2 + */ + private String attribute2; + /** + * 预留字段3 + */ + private Integer attribute3; + /** + * 预留字段4 + */ + private Integer attribute4; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdProductSopDO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdProductSopDO.java new file mode 100644 index 0000000..eee1914 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/md/item/MesMdProductSopDO.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.mes.dal.dataobject.md.item; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * MES 产品SOP DO + * + * @author 芋道源码 + */ +@TableName("mes_md_product_sop") +@KeySequence("mes_md_product_sop_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class MesMdProductSopDO extends BaseDO { + + /** + * 编号 + */ + @TableId + private Long id; + /** + * 物料产品编号 + * + * 关联 {@link MesMdItemDO#getId()} + */ + private Long itemId; + /** + * 排列顺序 + */ + private Integer orderNum; + /** + * 工序编号 + */ + private Long processId; + /** + * 标题 + */ + private String title; + /** + * 详细描述 + */ + private String description; + /** + * 图片地址 + */ + private String url; + /** + * 备注 + */ + private String remark; + /** + * 预留字段1 + */ + private String attribute1; + /** + * 预留字段2 + */ + private String attribute2; + /** + * 预留字段3 + */ + private Integer attribute3; + /** + * 预留字段4 + */ + private Integer attribute4; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductBomMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductBomMapper.java new file mode 100644 index 0000000..1528fb4 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductBomMapper.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.md.item; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomPageReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * MES 产品BOM Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MesMdProductBomMapper extends BaseMapperX { + + default PageResult selectPage(MesMdProductBomPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(MesMdProductBomDO::getItemId, reqVO.getItemId()) + .eqIfPresent(MesMdProductBomDO::getStatus, reqVO.getStatus()) + .orderByDesc(MesMdProductBomDO::getId)); + } + + default List selectByItemId(Long itemId) { + return selectList(MesMdProductBomDO::getItemId, itemId); + } + + default List selectAll() { + return selectList(); + } + + default void deleteByItemId(Long itemId) { + delete(MesMdProductBomDO::getItemId, itemId); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductSipMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductSipMapper.java new file mode 100644 index 0000000..6c8649d --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductSipMapper.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.md.item; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipPageReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSipDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * MES 产品SIP Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MesMdProductSipMapper extends BaseMapperX { + + default PageResult selectPage(MesMdProductSipPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(MesMdProductSipDO::getItemId, reqVO.getItemId()) + .likeIfPresent(MesMdProductSipDO::getTitle, reqVO.getTitle()) + .orderByAsc(MesMdProductSipDO::getOrderNum)); + } + + default List selectByItemId(Long itemId) { + return selectList(new LambdaQueryWrapperX() + .eq(MesMdProductSipDO::getItemId, itemId) + .orderByAsc(MesMdProductSipDO::getOrderNum)); + } + + default Long selectCountByItemIdAndOrderNum(Long itemId, Integer orderNum, Long excludeId) { + return selectCount(new LambdaQueryWrapperX() + .eq(MesMdProductSipDO::getItemId, itemId) + .eq(MesMdProductSipDO::getOrderNum, orderNum) + .neIfPresent(MesMdProductSipDO::getId, excludeId)); + } + + default void deleteByItemId(Long itemId) { + delete(MesMdProductSipDO::getItemId, itemId); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductSopMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductSopMapper.java new file mode 100644 index 0000000..d86d76f --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdProductSopMapper.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.mes.dal.mysql.md.item; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopPageReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSopDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * MES 产品SOP Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface MesMdProductSopMapper extends BaseMapperX { + + default PageResult selectPage(MesMdProductSopPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eq(MesMdProductSopDO::getItemId, reqVO.getItemId()) + .likeIfPresent(MesMdProductSopDO::getTitle, reqVO.getTitle()) + .orderByAsc(MesMdProductSopDO::getOrderNum)); + } + + default List selectByItemId(Long itemId) { + return selectList(new LambdaQueryWrapperX() + .eq(MesMdProductSopDO::getItemId, itemId) + .orderByAsc(MesMdProductSopDO::getOrderNum)); + } + + default Long selectCountByItemIdAndOrderNum(Long itemId, Integer orderNum, Long excludeId) { + return selectCount(new LambdaQueryWrapperX() + .eq(MesMdProductSopDO::getItemId, itemId) + .eq(MesMdProductSopDO::getOrderNum, orderNum) + .neIfPresent(MesMdProductSopDO::getId, excludeId)); + } + + default void deleteByItemId(Long itemId) { + delete(MesMdProductSopDO::getItemId, itemId); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductBomService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductBomService.java new file mode 100644 index 0000000..3de41fd --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductBomService.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.mes.service.md.item; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * MES 产品BOM Service 接口 + * + * @author 芋道源码 + */ +public interface MesMdProductBomService { + + /** + * 创建产品BOM + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProductBom(@Valid MesMdProductBomSaveReqVO createReqVO); + + /** + * 更新产品BOM + * + * @param updateReqVO 更新信息 + */ + void updateProductBom(@Valid MesMdProductBomSaveReqVO updateReqVO); + + /** + * 删除产品BOM + * + * @param id 编号 + */ + void deleteProductBom(Long id); + + /** + * 获得产品BOM + * + * @param id 编号 + * @return 产品BOM + */ + MesMdProductBomDO getProductBom(Long id); + + /** + * 获得产品BOM分页 + * + * @param pageReqVO 分页查询 + * @return 产品BOM分页 + */ + PageResult getProductBomPage(MesMdProductBomPageReqVO pageReqVO); + + /** + * 根据物料产品编号获得产品BOM列表 + * + * @param itemId 物料产品编号 + * @return 产品BOM列表 + */ + List getProductBomListByItemId(Long itemId); + + /** + * 根据物料产品编号删除产品BOM + * + * @param itemId 物料产品编号 + */ + void deleteProductBomByItemId(Long itemId); + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductBomServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductBomServiceImpl.java new file mode 100644 index 0000000..daa735c --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductBomServiceImpl.java @@ -0,0 +1,164 @@ +package cn.iocoder.yudao.module.mes.service.md.item; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.bom.MesMdProductBomSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductBomDO; +import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdProductBomMapper; +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.*; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; + +/** + * MES 产品BOM Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MesMdProductBomServiceImpl implements MesMdProductBomService { + + @Resource + private MesMdProductBomMapper productBomMapper; + + @Resource + @Lazy // 避免循环依赖 + private MesMdItemService itemService; + + // TODO @AI:1.1 1.2 1.3 如果都是校验; + @Override + public Long createProductBom(MesMdProductBomSaveReqVO createReqVO) { + // 1. 校验物料产品存在 + validateItemExists(createReqVO.getItemId()); + // 2. 校验BOM物料存在 + validateItemExists(createReqVO.getBomItemId()); + // 3. 校验不能自引用 + if (createReqVO.getItemId().equals(createReqVO.getBomItemId())) { + throw exception(MD_PRODUCT_BOM_SELF_REFERENCE); + } + // 4. 校验不能形成闭环 + if (hasCycle(createReqVO.getItemId(), createReqVO.getBomItemId())) { + throw exception(MD_PRODUCT_BOM_CIRCULAR); + } + + // 插入 + MesMdProductBomDO productBom = BeanUtils.toBean(createReqVO, MesMdProductBomDO.class); + productBomMapper.insert(productBom); + return productBom.getId(); + } + + // TODO @AI:1.1 1.2 1.3 如果都是校验; + @Override + public void updateProductBom(MesMdProductBomSaveReqVO updateReqVO) { + // 1. 校验存在 + validateProductBomExists(updateReqVO.getId()); + // 2. 校验物料产品存在 + validateItemExists(updateReqVO.getItemId()); + // 3. 校验BOM物料存在 + validateItemExists(updateReqVO.getBomItemId()); + // 4. 校验不能自引用 + if (updateReqVO.getItemId().equals(updateReqVO.getBomItemId())) { + throw exception(MD_PRODUCT_BOM_SELF_REFERENCE); + } + + // 更新 + MesMdProductBomDO updateObj = BeanUtils.toBean(updateReqVO, MesMdProductBomDO.class); + productBomMapper.updateById(updateObj); + } + + @Override + public void deleteProductBom(Long id) { + // 校验存在 + validateProductBomExists(id); + // 删除 + productBomMapper.deleteById(id); + } + + private void validateProductBomExists(Long id) { + if (productBomMapper.selectById(id) == null) { + throw exception(MD_PRODUCT_BOM_NOT_EXISTS); + } + } + + private void validateItemExists(Long itemId) { + if (itemService.getItem(itemId) == null) { + throw exception(MD_ITEM_NOT_EXISTS); + } + } + + // TODO @AI:看看有没 hutool 工具类里,有没 dfs 检测的? + /** + * 检测新增边 (itemId -> bomItemId) 后,BOM 图是否存在闭环 + * + * @param itemId 父物料编号 + * @param bomItemId BOM子物料编号 + * @return 是否存在闭环 + */ + private boolean hasCycle(Long itemId, Long bomItemId) { + // 获取所有已有的 BOM 记录 + List allBoms = productBomMapper.selectAll(); + // 构建邻接表:parent -> Set + Map> graph = new HashMap<>(); + for (MesMdProductBomDO bom : allBoms) { + graph.computeIfAbsent(bom.getItemId(), k -> new HashSet<>()).add(bom.getBomItemId()); + } + // 添加待新增的边 + graph.computeIfAbsent(itemId, k -> new HashSet<>()).add(bomItemId); + // DFS 检测环 + Set visited = new HashSet<>(); + Set inStack = new HashSet<>(); + for (Long node : graph.keySet()) { + if (dfs(node, graph, visited, inStack)) { + return true; + } + } + return false; + } + + private boolean dfs(Long node, Map> graph, Set visited, Set inStack) { + if (inStack.contains(node)) { + return true; + } + if (visited.contains(node)) { + return false; + } + visited.add(node); + inStack.add(node); + Set neighbors = graph.getOrDefault(node, Collections.emptySet()); + for (Long neighbor : neighbors) { + if (dfs(neighbor, graph, visited, inStack)) { + return true; + } + } + inStack.remove(node); + return false; + } + + @Override + public MesMdProductBomDO getProductBom(Long id) { + return productBomMapper.selectById(id); + } + + @Override + public PageResult getProductBomPage(MesMdProductBomPageReqVO pageReqVO) { + return productBomMapper.selectPage(pageReqVO); + } + + @Override + public List getProductBomListByItemId(Long itemId) { + return productBomMapper.selectByItemId(itemId); + } + + @Override + public void deleteProductBomByItemId(Long itemId) { + productBomMapper.deleteByItemId(itemId); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSipService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSipService.java new file mode 100644 index 0000000..322bec6 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSipService.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.mes.service.md.item; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSipDO; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * MES 产品SIP Service 接口 + * + * @author 芋道源码 + */ +public interface MesMdProductSipService { + + /** + * 创建产品SIP + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProductSip(@Valid MesMdProductSipSaveReqVO createReqVO); + + /** + * 更新产品SIP + * + * @param updateReqVO 更新信息 + */ + void updateProductSip(@Valid MesMdProductSipSaveReqVO updateReqVO); + + /** + * 删除产品SIP + * + * @param id 编号 + */ + void deleteProductSip(Long id); + + /** + * 获得产品SIP + * + * @param id 编号 + * @return 产品SIP + */ + MesMdProductSipDO getProductSip(Long id); + + /** + * 获得产品SIP分页 + * + * @param pageReqVO 分页查询 + * @return 产品SIP分页 + */ + PageResult getProductSipPage(MesMdProductSipPageReqVO pageReqVO); + + /** + * 根据物料产品编号,获得产品SIP列表 + * + * @param itemId 物料产品编号 + * @return 产品SIP列表 + */ + List getProductSipListByItemId(Long itemId); + + /** + * 根据物料产品编号,删除产品SIP + * + * @param itemId 物料产品编号 + */ + void deleteProductSipByItemId(Long itemId); + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSipServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSipServiceImpl.java new file mode 100644 index 0000000..07bb982 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSipServiceImpl.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.mes.service.md.item; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sip.MesMdProductSipSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSipDO; +import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdProductSipMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; + +/** + * MES 产品SIP Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MesMdProductSipServiceImpl implements MesMdProductSipService { + + @Resource + private MesMdProductSipMapper productSipMapper; + + @Override + public Long createProductSip(MesMdProductSipSaveReqVO createReqVO) { + // 校验排列顺序的唯一性 + validateOrderNumUnique(createReqVO.getItemId(), createReqVO.getOrderNum(), null); + + // 插入 + MesMdProductSipDO sip = BeanUtils.toBean(createReqVO, MesMdProductSipDO.class); + productSipMapper.insert(sip); + return sip.getId(); + } + + @Override + public void updateProductSip(MesMdProductSipSaveReqVO updateReqVO) { + // 校验存在 + validateProductSipExists(updateReqVO.getId()); + // 校验排列顺序的唯一性 + validateOrderNumUnique(updateReqVO.getItemId(), updateReqVO.getOrderNum(), updateReqVO.getId()); + + // 更新 + MesMdProductSipDO updateObj = BeanUtils.toBean(updateReqVO, MesMdProductSipDO.class); + productSipMapper.updateById(updateObj); + } + + @Override + public void deleteProductSip(Long id) { + // 校验存在 + validateProductSipExists(id); + // 删除 + productSipMapper.deleteById(id); + } + + private void validateProductSipExists(Long id) { + if (productSipMapper.selectById(id) == null) { + throw exception(MD_PRODUCT_SIP_NOT_EXISTS); + } + } + + private void validateOrderNumUnique(Long itemId, Integer orderNum, Long excludeId) { + Long count = productSipMapper.selectCountByItemIdAndOrderNum(itemId, orderNum, excludeId); + if (count > 0) { + throw exception(MD_PRODUCT_SIP_ORDER_NUM_DUPLICATE); + } + } + + @Override + public MesMdProductSipDO getProductSip(Long id) { + return productSipMapper.selectById(id); + } + + @Override + public PageResult getProductSipPage(MesMdProductSipPageReqVO pageReqVO) { + return productSipMapper.selectPage(pageReqVO); + } + + @Override + public List getProductSipListByItemId(Long itemId) { + return productSipMapper.selectByItemId(itemId); + } + + @Override + public void deleteProductSipByItemId(Long itemId) { + productSipMapper.deleteByItemId(itemId); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSopService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSopService.java new file mode 100644 index 0000000..32e46da --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSopService.java @@ -0,0 +1,71 @@ +package cn.iocoder.yudao.module.mes.service.md.item; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSopDO; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * MES 产品SOP Service 接口 + * + * @author 芋道源码 + */ +public interface MesMdProductSopService { + + /** + * 创建产品SOP + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProductSop(@Valid MesMdProductSopSaveReqVO createReqVO); + + /** + * 更新产品SOP + * + * @param updateReqVO 更新信息 + */ + void updateProductSop(@Valid MesMdProductSopSaveReqVO updateReqVO); + + /** + * 删除产品SOP + * + * @param id 编号 + */ + void deleteProductSop(Long id); + + /** + * 获得产品SOP + * + * @param id 编号 + * @return 产品SOP + */ + MesMdProductSopDO getProductSop(Long id); + + /** + * 获得产品SOP分页 + * + * @param pageReqVO 分页查询 + * @return 产品SOP分页 + */ + PageResult getProductSopPage(MesMdProductSopPageReqVO pageReqVO); + + /** + * 根据物料产品编号,获得产品SOP列表 + * + * @param itemId 物料产品编号 + * @return 产品SOP列表 + */ + List getProductSopListByItemId(Long itemId); + + /** + * 根据物料产品编号,删除产品SOP + * + * @param itemId 物料产品编号 + */ + void deleteProductSopByItemId(Long itemId); + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSopServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSopServiceImpl.java new file mode 100644 index 0000000..0b0151f --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/item/MesMdProductSopServiceImpl.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.mes.service.md.item; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.sop.MesMdProductSopSaveReqVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdProductSopDO; +import cn.iocoder.yudao.module.mes.dal.mysql.md.item.MesMdProductSopMapper; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; + +/** + * MES 产品SOP Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class MesMdProductSopServiceImpl implements MesMdProductSopService { + + @Resource + private MesMdProductSopMapper productSopMapper; + + @Override + public Long createProductSop(MesMdProductSopSaveReqVO createReqVO) { + // 校验排列顺序的唯一性 + validateOrderNumUnique(createReqVO.getItemId(), createReqVO.getOrderNum(), null); + + // 插入 + MesMdProductSopDO sop = BeanUtils.toBean(createReqVO, MesMdProductSopDO.class); + productSopMapper.insert(sop); + return sop.getId(); + } + + @Override + public void updateProductSop(MesMdProductSopSaveReqVO updateReqVO) { + // 校验存在 + validateProductSopExists(updateReqVO.getId()); + // 校验排列顺序的唯一性 + validateOrderNumUnique(updateReqVO.getItemId(), updateReqVO.getOrderNum(), updateReqVO.getId()); + + // 更新 + MesMdProductSopDO updateObj = BeanUtils.toBean(updateReqVO, MesMdProductSopDO.class); + productSopMapper.updateById(updateObj); + } + + @Override + public void deleteProductSop(Long id) { + // 校验存在 + validateProductSopExists(id); + // 删除 + productSopMapper.deleteById(id); + } + + private void validateProductSopExists(Long id) { + if (productSopMapper.selectById(id) == null) { + throw exception(MD_PRODUCT_SOP_NOT_EXISTS); + } + } + + private void validateOrderNumUnique(Long itemId, Integer orderNum, Long excludeId) { + Long count = productSopMapper.selectCountByItemIdAndOrderNum(itemId, orderNum, excludeId); + if (count > 0) { + throw exception(MD_PRODUCT_SOP_ORDER_NUM_DUPLICATE); + } + } + + @Override + public MesMdProductSopDO getProductSop(Long id) { + return productSopMapper.selectById(id); + } + + @Override + public PageResult getProductSopPage(MesMdProductSopPageReqVO pageReqVO) { + return productSopMapper.selectPage(pageReqVO); + } + + @Override + public List getProductSopListByItemId(Long itemId) { + return productSopMapper.selectByItemId(itemId); + } + + @Override + public void deleteProductSopByItemId(Long itemId) { + productSopMapper.deleteByItemId(itemId); + } + +}