Commit fc2d27ba63f5c4b7bc9aab3b458735640f95e214

Authored by YunaiV
1 parent 3c9100d7

✨ feat(mes): 添加 SN 码生成、查询和导出功能

新增 SN 码生成、分页查询和批量删除的 API 接口,支持导出 SN 码分组和明细为 Excel 文件。实现了前端页面的搜索、生成和导出功能,提升了用户操作的便捷性。
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/sn/MesWmSnController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.wm.sn;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  5 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  9 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  10 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  11 +import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnGenerateReqVO;
  12 +import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnGroupRespVO;
  13 +import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnPageReqVO;
  14 +import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnRespVO;
  15 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  16 +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
  17 +import cn.iocoder.yudao.module.mes.service.wm.sn.MesWmSnService;
  18 +import io.swagger.v3.oas.annotations.Operation;
  19 +import io.swagger.v3.oas.annotations.Parameter;
  20 +import io.swagger.v3.oas.annotations.tags.Tag;
  21 +import jakarta.annotation.Resource;
  22 +import jakarta.servlet.http.HttpServletResponse;
  23 +import jakarta.validation.Valid;
  24 +import jakarta.validation.constraints.NotBlank;
  25 +import org.springframework.security.access.prepost.PreAuthorize;
  26 +import org.springframework.validation.annotation.Validated;
  27 +import org.springframework.web.bind.annotation.*;
  28 +
  29 +import java.io.IOException;
  30 +import java.util.List;
  31 +import java.util.Map;
  32 +
  33 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
  34 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  35 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
  36 +
  37 +@Tag(name = "管理后台 - MES SN 码")
  38 +@RestController
  39 +@RequestMapping("/mes/wm/sn")
  40 +@Validated
  41 +public class MesWmSnController {
  42 +
  43 + @Resource
  44 + private MesWmSnService snService;
  45 + @Resource
  46 + private MesMdItemService itemService;
  47 +
  48 + @PostMapping("/generate")
  49 + @Operation(summary = "生成 SN 码")
  50 + @PreAuthorize("@ss.hasPermission('mes:wm-sn:create')")
  51 + public CommonResult<Boolean> generateSnCodes(@Valid @RequestBody MesWmSnGenerateReqVO reqVO) {
  52 + snService.generateSnCodes(reqVO);
  53 + return success(true);
  54 + }
  55 +
  56 + @GetMapping("/group-page")
  57 + @Operation(summary = "获得 SN 码分组分页")
  58 + @PreAuthorize("@ss.hasPermission('mes:wm-sn:query')")
  59 + public CommonResult<PageResult<MesWmSnGroupRespVO>> getSnGroupPage(@Valid MesWmSnPageReqVO reqVO) {
  60 + PageResult<MesWmSnGroupRespVO> pageResult = snService.getSnGroupPage(reqVO);
  61 + if (CollUtil.isEmpty(pageResult.getList())) {
  62 + return success(PageResult.empty(pageResult.getTotal()));
  63 + }
  64 + buildGroupItemInfo(pageResult.getList());
  65 + return success(pageResult);
  66 + }
  67 +
  68 + @DeleteMapping("/delete-batch")
  69 + @Operation(summary = "批量删除 SN 码(按批次 UUID)")
  70 + @Parameter(name = "uuid", description = "批次 UUID", required = true)
  71 + @PreAuthorize("@ss.hasPermission('mes:wm-sn:delete')")
  72 + public CommonResult<Boolean> deleteSnBatch(@RequestParam("uuid") @NotBlank(message = "批次 UUID 不能为空") String uuid) {
  73 + snService.deleteSnByUuid(uuid);
  74 + return success(true);
  75 + }
  76 +
  77 + @GetMapping("/group-export-excel")
  78 + @Operation(summary = "导出 SN 码分组 Excel")
  79 + @PreAuthorize("@ss.hasPermission('mes:wm-sn:export')")
  80 + @ApiAccessLog(operateType = EXPORT)
  81 + public void exportSnGroupExcel(@Valid MesWmSnPageReqVO reqVO, HttpServletResponse response) throws IOException {
  82 + reqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  83 + List<MesWmSnGroupRespVO> list = snService.getSnGroupPage(reqVO).getList();
  84 + buildGroupItemInfo(list);
  85 + ExcelUtils.write(response, "SN码分组.xls", "数据", MesWmSnGroupRespVO.class, list);
  86 + }
  87 +
  88 + @GetMapping("/export-excel")
  89 + @Operation(summary = "导出批次 SN 码明细 Excel")
  90 + @Parameter(name = "uuid", description = "批次 UUID", required = true)
  91 + @PreAuthorize("@ss.hasPermission('mes:wm-sn:export')")
  92 + @ApiAccessLog(operateType = EXPORT)
  93 + public void exportSnExcel(@RequestParam("uuid") String uuid, HttpServletResponse response) throws IOException {
  94 + List<MesWmSnRespVO> list = BeanUtils.toBean(snService.getSnListByUuid(uuid), MesWmSnRespVO.class);
  95 + buildItemInfo(list);
  96 + ExcelUtils.write(response, "SN码明细.xls", "数据", MesWmSnRespVO.class, list);
  97 + }
  98 +
  99 + // ==================== 拼接 VO ====================
  100 +
  101 + private void buildGroupItemInfo(List<MesWmSnGroupRespVO> list) {
  102 + if (CollUtil.isEmpty(list)) {
  103 + return;
  104 + }
  105 + Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(convertSet(list, MesWmSnGroupRespVO::getItemId));
  106 + list.forEach(vo -> MapUtils.findAndThen(itemMap, vo.getItemId(), item ->
  107 + vo.setItemCode(item.getCode()).setItemName(item.getName()).setSpecification(item.getSpecification())));
  108 + }
  109 +
  110 + private void buildItemInfo(List<MesWmSnRespVO> list) {
  111 + if (CollUtil.isEmpty(list)) {
  112 + return;
  113 + }
  114 + Map<Long, MesMdItemDO> itemMap = itemService.getItemMap(convertSet(list, MesWmSnRespVO::getItemId));
  115 + list.forEach(vo -> MapUtils.findAndThen(itemMap, vo.getItemId(), item ->
  116 + vo.setItemCode(item.getCode()).setItemName(item.getName()).setSpecification(item.getSpecification())));
  117 + }
  118 +
  119 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/sn/vo/MesWmSnGenerateReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.Max;
  5 +import jakarta.validation.constraints.Min;
  6 +import jakarta.validation.constraints.NotNull;
  7 +import jakarta.validation.constraints.Size;
  8 +import lombok.Data;
  9 +
  10 +@Schema(description = "管理后台 - MES SN 码生成 Request VO")
  11 +@Data
  12 +public class MesWmSnGenerateReqVO {
  13 +
  14 + @Schema(description = "物料编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  15 + @NotNull(message = "物料编号不能为空")
  16 + private Long itemId;
  17 +
  18 + @Schema(description = "批次号", example = "BATCH001")
  19 + @Size(max = 100, message = "批次号长度不能超过 100 个字符")
  20 + private String batchCode;
  21 +
  22 + @Schema(description = "生产工单编号", example = "1")
  23 + private Long workOrderId;
  24 +
  25 + @Schema(description = "生成数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
  26 + @NotNull(message = "生成数量不能为空")
  27 + @Min(value = 1, message = "生成数量最小为 1")
  28 + @Max(value = 1000, message = "生成数量最大为 1000")
  29 + private Integer count;
  30 +
  31 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/sn/vo/MesWmSnGroupRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo;
  2 +
  3 +import cn.idev.excel.annotation.ExcelProperty;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.experimental.Accessors;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - MES SN 码分组 Response VO")
  11 +@Data
  12 +@Accessors(chain = true)
  13 +public class MesWmSnGroupRespVO {
  14 +
  15 + @Schema(description = "批次 UUID", example = "550e8400-e29b-41d4-a716-446655440000")
  16 + private String uuid;
  17 +
  18 + @Schema(description = "SN 码数量", example = "100")
  19 + @ExcelProperty("SN 码数量")
  20 + private Integer count;
  21 +
  22 + @Schema(description = "物料编号", example = "1")
  23 + private Long itemId;
  24 +
  25 + @Schema(description = "物料编码", example = "ITEM001")
  26 + @ExcelProperty("物料编码")
  27 + private String itemCode;
  28 +
  29 + @Schema(description = "物料名称", example = "物料A")
  30 + @ExcelProperty("物料名称")
  31 + private String itemName;
  32 +
  33 + @Schema(description = "规格型号", example = "100*200")
  34 + @ExcelProperty("规格型号")
  35 + private String specification;
  36 +
  37 + @Schema(description = "批次号", example = "BATCH001")
  38 + @ExcelProperty("批次号")
  39 + private String batchCode;
  40 +
  41 + @Schema(description = "生产工单编号", example = "1")
  42 + private Long workOrderId;
  43 +
  44 + @Schema(description = "创建时间")
  45 + @ExcelProperty("生成时间")
  46 + private LocalDateTime createTime;
  47 +
  48 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/sn/vo/MesWmSnPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  13 +
  14 +@Schema(description = "管理后台 - MES SN 码分页 Request VO")
  15 +@Data
  16 +@EqualsAndHashCode(callSuper = true)
  17 +@ToString(callSuper = true)
  18 +public class MesWmSnPageReqVO extends PageParam {
  19 +
  20 + @Schema(description = "批次 UUID", example = "550e8400-e29b-41d4-a716-446655440000")
  21 + private String uuid;
  22 +
  23 + @Schema(description = "SN 码", example = "SN20260305000001")
  24 + private String code;
  25 +
  26 + @Schema(description = "物料编号", example = "1")
  27 + private Long itemId;
  28 +
  29 + @Schema(description = "批次号", example = "BATCH001")
  30 + private String batchCode;
  31 +
  32 + @Schema(description = "创建时间")
  33 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  34 + private LocalDateTime[] createTime;
  35 +
  36 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/sn/vo/MesWmSnRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo;
  2 +
  3 +import cn.idev.excel.annotation.ExcelProperty;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.experimental.Accessors;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +@Schema(description = "管理后台 - MES SN 码 Response VO")
  11 +@Data
  12 +@Accessors(chain = true)
  13 +public class MesWmSnRespVO {
  14 +
  15 + @Schema(description = "编号", example = "1")
  16 + private Long id;
  17 +
  18 + @Schema(description = "批次 UUID", example = "550e8400-e29b-41d4-a716-446655440000")
  19 + private String uuid;
  20 +
  21 + @Schema(description = "SN 码", example = "SN20260305000001")
  22 + @ExcelProperty("SN 码")
  23 + private String code;
  24 +
  25 + @Schema(description = "物料编号", example = "1")
  26 + private Long itemId;
  27 +
  28 + @Schema(description = "物料编码", example = "ITEM001")
  29 + @ExcelProperty("物料编码")
  30 + private String itemCode;
  31 +
  32 + @Schema(description = "物料名称", example = "物料A")
  33 + @ExcelProperty("物料名称")
  34 + private String itemName;
  35 +
  36 + @Schema(description = "规格型号", example = "100*200")
  37 + @ExcelProperty("规格型号")
  38 + private String specification;
  39 +
  40 + @Schema(description = "批次号", example = "BATCH001")
  41 + @ExcelProperty("批次号")
  42 + private String batchCode;
  43 +
  44 + @Schema(description = "生产工单编号", example = "1")
  45 + private Long workOrderId;
  46 +
  47 + @Schema(description = "创建时间")
  48 + @ExcelProperty("生成时间")
  49 + private LocalDateTime createTime;
  50 +
  51 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/dataobject/wm/sn/MesWmSnDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.dataobject.wm.sn;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
  5 +import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderDO;
  6 +import com.baomidou.mybatisplus.annotation.KeySequence;
  7 +import com.baomidou.mybatisplus.annotation.TableId;
  8 +import com.baomidou.mybatisplus.annotation.TableName;
  9 +import lombok.*;
  10 +
  11 +/**
  12 + * MES SN 码 DO
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@TableName("mes_wm_sn")
  17 +@KeySequence("mes_wm_sn_seq")
  18 +@Data
  19 +@EqualsAndHashCode(callSuper = true)
  20 +@ToString(callSuper = true)
  21 +@Builder
  22 +@NoArgsConstructor
  23 +@AllArgsConstructor
  24 +public class MesWmSnDO extends BaseDO {
  25 +
  26 + /**
  27 + * 编号
  28 + */
  29 + @TableId
  30 + private Long id;
  31 + /**
  32 + * 批次 UUID(用于标记同一批次生成的 SN 码)
  33 + */
  34 + private String uuid;
  35 + /**
  36 + * SN 码(唯一)
  37 + */
  38 + private String code;
  39 + /**
  40 + * 物料编号
  41 + *
  42 + * 关联 {@link MesMdItemDO#getId()}
  43 + */
  44 + private Long itemId;
  45 + /**
  46 + * 批次号
  47 + */
  48 + private String batchCode;
  49 + // TODO @芋艿:【暂时不处理】看看后续要不要去掉这个字段。
  50 + /**
  51 + * 生产工单编号
  52 + *
  53 + * 关联 {@link MesProWorkOrderDO#getId()}
  54 + */
  55 + private Long workOrderId;
  56 +
  57 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/sn/MesWmSnMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.dal.mysql.wm.sn;
  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.framework.mybatis.core.query.MPJLambdaWrapperX;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnGroupRespVO;
  8 +import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnPageReqVO;
  9 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.sn.MesWmSnDO;
  10 +import org.apache.ibatis.annotations.Mapper;
  11 +
  12 +import java.util.List;
  13 +
  14 +/**
  15 + * MES SN 码 Mapper
  16 + *
  17 + * @author 芋道源码
  18 + */
  19 +@Mapper
  20 +public interface MesWmSnMapper extends BaseMapperX<MesWmSnDO> {
  21 +
  22 + /**
  23 + * 按 UUID 分组查询 SN 码分页(聚合查询)
  24 + */
  25 + default PageResult<MesWmSnGroupRespVO> selectPageGroupByUuid(MesWmSnPageReqVO reqVO) {
  26 + MPJLambdaWrapperX<MesWmSnDO> query = new MPJLambdaWrapperX<>();
  27 + query.eqIfPresent(MesWmSnDO::getUuid, reqVO.getUuid())
  28 + .likeIfPresent(MesWmSnDO::getCode, reqVO.getCode())
  29 + .eqIfPresent(MesWmSnDO::getItemId, reqVO.getItemId())
  30 + .likeIfPresent(MesWmSnDO::getBatchCode, reqVO.getBatchCode())
  31 + .betweenIfPresent(MesWmSnDO::getCreateTime, reqVO.getCreateTime());
  32 + query.selectAs(MesWmSnDO::getUuid, MesWmSnGroupRespVO::getUuid)
  33 + .selectMax(MesWmSnDO::getItemId, MesWmSnGroupRespVO::getItemId)
  34 + .selectMax(MesWmSnDO::getBatchCode, MesWmSnGroupRespVO::getBatchCode)
  35 + .selectMax(MesWmSnDO::getWorkOrderId, MesWmSnGroupRespVO::getWorkOrderId)
  36 + .selectMax(MesWmSnDO::getCreateTime, MesWmSnGroupRespVO::getCreateTime)
  37 + .selectAs("COUNT(*)", MesWmSnGroupRespVO::getCount)
  38 + .groupBy(MesWmSnDO::getUuid)
  39 + .last("ORDER BY MAX(t.create_time) DESC"); // 避免 this is incompatible with sql_mode=only_full_group_by 报错
  40 + return selectJoinPage(reqVO, MesWmSnGroupRespVO.class, query);
  41 + }
  42 +
  43 + default List<MesWmSnDO> selectListByUuid(String uuid) {
  44 + return selectList(new LambdaQueryWrapperX<MesWmSnDO>()
  45 + .eq(MesWmSnDO::getUuid, uuid)
  46 + .orderByAsc(MesWmSnDO::getId));
  47 + }
  48 +
  49 + default int deleteByUuid(String uuid) {
  50 + return delete(new LambdaQueryWrapperX<MesWmSnDO>()
  51 + .eq(MesWmSnDO::getUuid, uuid));
  52 + }
  53 +
  54 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/md/autocode/MesMdAutoCodeRuleCodeEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.enums.md.autocode;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * MES 编码规则代码枚举
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@Getter
  12 +@AllArgsConstructor
  13 +public enum MesMdAutoCodeRuleCodeEnum {
  14 +
  15 + SN_CODE("SN_CODE", "SN 码");
  16 +
  17 + /**
  18 + * 规则代码
  19 + */
  20 + private final String code;
  21 + /**
  22 + * 规则名称
  23 + */
  24 + private final String name;
  25 +
  26 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/md/autocode/MesMdAutoCodeRecordService.java
@@ -8,6 +8,16 @@ package cn.iocoder.yudao.module.mes.service.md.autocode; @@ -8,6 +8,16 @@ package cn.iocoder.yudao.module.mes.service.md.autocode;
8 public interface MesMdAutoCodeRecordService { 8 public interface MesMdAutoCodeRecordService {
9 9
10 /** 10 /**
  11 + * 生成编码(无输入字符)
  12 + *
  13 + * @param ruleCode 规则编码
  14 + * @return 生成的编码
  15 + */
  16 + default String generateAutoCode(String ruleCode) {
  17 + return generateAutoCode(ruleCode, null);
  18 + }
  19 +
  20 + /**
11 * 生成编码 21 * 生成编码
12 * 22 *
13 * @param ruleCode 规则编码 23 * @param ruleCode 规则编码
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/sn/MesWmSnService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.sn;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnGenerateReqVO;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnGroupRespVO;
  6 +import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnPageReqVO;
  7 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.sn.MesWmSnDO;
  8 +
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * MES SN 码 Service 接口
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public interface MesWmSnService {
  17 +
  18 + /**
  19 + * 批量生成 SN 码
  20 + *
  21 + * @param reqVO 生成请求
  22 + */
  23 + void generateSnCodes(MesWmSnGenerateReqVO reqVO);
  24 +
  25 + /**
  26 + * 获得 SN 码分组分页(按 UUID 聚合)
  27 + *
  28 + * @param reqVO 分页查询
  29 + * @return SN 码分组分页
  30 + */
  31 + PageResult<MesWmSnGroupRespVO> getSnGroupPage(MesWmSnPageReqVO reqVO);
  32 +
  33 + /**
  34 + * 获得批次 SN 码列表
  35 + *
  36 + * @param uuid 批次 UUID
  37 + * @return SN 码列表
  38 + */
  39 + List<MesWmSnDO> getSnListByUuid(String uuid);
  40 +
  41 + /**
  42 + * 批量删除 SN 码(按批次 UUID)
  43 + *
  44 + * @param uuid 批次 UUID
  45 + */
  46 + void deleteSnByUuid(String uuid);
  47 +
  48 +}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/sn/MesWmSnServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.service.wm.sn;
  2 +
  3 +import cn.hutool.core.util.IdUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnGenerateReqVO;
  6 +import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnGroupRespVO;
  7 +import cn.iocoder.yudao.module.mes.controller.admin.wm.sn.vo.MesWmSnPageReqVO;
  8 +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.sn.MesWmSnDO;
  9 +import cn.iocoder.yudao.module.mes.dal.mysql.wm.sn.MesWmSnMapper;
  10 +import cn.iocoder.yudao.module.mes.enums.md.autocode.MesMdAutoCodeRuleCodeEnum;
  11 +import cn.iocoder.yudao.module.mes.service.md.autocode.MesMdAutoCodeRecordService;
  12 +import jakarta.annotation.Resource;
  13 +import lombok.extern.slf4j.Slf4j;
  14 +import org.springframework.stereotype.Service;
  15 +import org.springframework.transaction.annotation.Transactional;
  16 +import org.springframework.validation.annotation.Validated;
  17 +
  18 +import java.util.ArrayList;
  19 +import java.util.List;
  20 +
  21 +/**
  22 + * MES SN 码 Service 实现类
  23 + *
  24 + * @author 芋道源码
  25 + */
  26 +@Service
  27 +@Validated
  28 +@Slf4j
  29 +public class MesWmSnServiceImpl implements MesWmSnService {
  30 +
  31 + @Resource
  32 + private MesWmSnMapper snMapper;
  33 + @Resource
  34 + private MesMdAutoCodeRecordService autoCodeRecordService;
  35 +
  36 + @Override
  37 + @Transactional(rollbackFor = Exception.class)
  38 + public void generateSnCodes(MesWmSnGenerateReqVO reqVO) {
  39 + List<MesWmSnDO> sns = new ArrayList<>(reqVO.getCount());
  40 + // 生成批次 UUID
  41 + String uuid = IdUtil.fastSimpleUUID();
  42 + // 批量生成 SN 码
  43 + for (int i = 0; i < reqVO.getCount(); i++) {
  44 + String snCode = autoCodeRecordService.generateAutoCode(MesMdAutoCodeRuleCodeEnum.SN_CODE.getCode());
  45 + sns.add(new MesWmSnDO().setUuid(uuid).setCode(snCode)
  46 + .setItemId(reqVO.getItemId()).setBatchCode(reqVO.getBatchCode())
  47 + .setWorkOrderId(reqVO.getWorkOrderId()));
  48 + }
  49 + // 批量插入
  50 + snMapper.insertBatch(sns);
  51 + }
  52 +
  53 + @Override
  54 + public PageResult<MesWmSnGroupRespVO> getSnGroupPage(MesWmSnPageReqVO reqVO) {
  55 + return snMapper.selectPageGroupByUuid(reqVO);
  56 + }
  57 +
  58 + @Override
  59 + public List<MesWmSnDO> getSnListByUuid(String uuid) {
  60 + return snMapper.selectListByUuid(uuid);
  61 + }
  62 +
  63 + @Override
  64 + @Transactional(rollbackFor = Exception.class)
  65 + public void deleteSnByUuid(String uuid) {
  66 + snMapper.deleteByUuid(uuid);
  67 + }
  68 +
  69 +}
yudao-ui/yudao-ui-admin-vue3/src/api/mes/wm/sn/index.ts 0 → 100644
  1 +import request from '@/config/axios'
  2 +
  3 +// MES SN 码 VO
  4 +export interface WmSnVO {
  5 + id: number
  6 + snCode: string
  7 + itemId: number
  8 + itemCode: string
  9 + itemName: string
  10 + specification: string
  11 + batchCode: string
  12 + workOrderId: number
  13 + createTime: string
  14 +}
  15 +
  16 +// MES SN 码生成 VO
  17 +export interface WmSnGenerateVO {
  18 + itemId: number
  19 + batchCode?: string
  20 + workOrderId?: number
  21 + snNum: number
  22 +}
  23 +
  24 +// MES SN 码 API
  25 +export const WmSnApi = {
  26 + // 生成 SN 码
  27 + generateSnCodes: async (data: WmSnGenerateVO) => {
  28 + return await request.post({ url: '/mes/wm/sn/generate', data })
  29 + },
  30 +
  31 + // 查询 SN 码分页
  32 + getSnPage: async (params: any) => {
  33 + return await request.get({ url: '/mes/wm/sn/page', params })
  34 + },
  35 +
  36 + // 批量删除 SN 码
  37 + deleteSnBatch: async (ids: string) => {
  38 + return await request.delete({ url: '/mes/wm/sn/delete-batch', params: { ids } })
  39 + },
  40 +
  41 + // 导出 SN 码 Excel
  42 + exportSnExcel: async (params: any) => {
  43 + return await request.download({ url: '/mes/wm/sn/export-excel', params })
  44 + }
  45 +}
yudao-ui/yudao-ui-admin-vue3/src/views/mes/wm/sn/index.vue 0 → 100644
  1 +<template>
  2 + <ContentWrap>
  3 + <!-- 搜索工作栏 -->
  4 + <el-form
  5 + class="-mb-15px"
  6 + :model="queryParams"
  7 + ref="queryFormRef"
  8 + :inline="true"
  9 + label-width="68px"
  10 + >
  11 + <el-form-item label="SN 码" prop="snCode">
  12 + <el-input
  13 + v-model="queryParams.snCode"
  14 + placeholder="请输入 SN 码"
  15 + clearable
  16 + @keyup.enter="handleQuery"
  17 + class="!w-240px"
  18 + />
  19 + </el-form-item>
  20 + <el-form-item label="物料ID" prop="itemId">
  21 + <el-input
  22 + v-model="queryParams.itemId"
  23 + placeholder="请输入物料ID"
  24 + clearable
  25 + @keyup.enter="handleQuery"
  26 + class="!w-240px"
  27 + />
  28 + </el-form-item>
  29 + <el-form-item label="批次号" prop="batchCode">
  30 + <el-input
  31 + v-model="queryParams.batchCode"
  32 + placeholder="请输入批次号"
  33 + clearable
  34 + @keyup.enter="handleQuery"
  35 + class="!w-240px"
  36 + />
  37 + </el-form-item>
  38 + <el-form-item label="创建时间" prop="createTime">
  39 + <el-date-picker
  40 + v-model="queryParams.createTime"
  41 + value-format="YYYY-MM-DD HH:mm:ss"
  42 + type="daterange"
  43 + start-placeholder="开始日期"
  44 + end-placeholder="结束日期"
  45 + :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
  46 + class="!w-240px"
  47 + />
  48 + </el-form-item>
  49 + <el-form-item>
  50 + <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
  51 + <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
  52 + <el-button
  53 + type="primary"
  54 + plain
  55 + @click="openForm()"
  56 + v-hasPermi="['mes:wm-sn:create']"
  57 + >
  58 + <Icon icon="ep:plus" class="mr-5px" /> 生成 SN 码
  59 + </el-button>
  60 + <el-button
  61 + type="success"
  62 + plain
  63 + @click="handleExport"
  64 + :loading="exportLoading"
  65 + v-hasPermi="['mes:wm-sn:export']"
  66 + >
  67 + <Icon icon="ep:download" class="mr-5px" /> 导出
  68 + </el-button>
  69 + </el-form-item>
  70 + </el-form>
  71 + </ContentWrap>
  72 +
  73 + <!-- 列表 -->
  74 + <ContentWrap>
  75 + <el-table v-loading="loading" :data="list" stripe>
  76 + <el-table-column label="SN 码" align="center" prop="snCode" min-width="180" />
  77 + <el-table-column label="物料编码" align="center" prop="itemCode" min-width="120" />
  78 + <el-table-column label="物料名称" align="center" prop="itemName" min-width="150" />
  79 + <el-table-column label="规格型号" align="center" prop="specification" min-width="120" />
  80 + <el-table-column label="批次号" align="center" prop="batchCode" min-width="120" />
  81 + <el-table-column
  82 + label="生成时间"
  83 + align="center"
  84 + prop="createTime"
  85 + :formatter="dateFormatter"
  86 + width="180px"
  87 + />
  88 + <el-table-column label="操作" align="center" width="120" fixed="right">
  89 + <template #default="scope">
  90 + <el-button
  91 + link
  92 + type="danger"
  93 + @click="handleDelete(scope.row.id)"
  94 + v-hasPermi="['mes:wm-sn:delete']"
  95 + >
  96 + 删除
  97 + </el-button>
  98 + </template>
  99 + </el-table-column>
  100 + </el-table>
  101 + <!-- 分页 -->
  102 + <Pagination
  103 + :total="total"
  104 + v-model:page="queryParams.pageNo"
  105 + v-model:limit="queryParams.pageSize"
  106 + @pagination="getList"
  107 + />
  108 + </ContentWrap>
  109 +
  110 + <!-- 生成对话框 -->
  111 + <el-dialog :title="'生成 SN 码'" v-model="dialogVisible" width="600px">
  112 + <el-form ref="formRef" :model="formData" :rules="formRules" label-width="100px">
  113 + <el-form-item label="物料ID" prop="itemId">
  114 + <el-input-number v-model="formData.itemId" :min="1" controls-position="right" class="!w-full" />
  115 + </el-form-item>
  116 + <el-form-item label="批次号" prop="batchCode">
  117 + <el-input v-model="formData.batchCode" placeholder="请输入批次号" maxlength="100" />
  118 + </el-form-item>
  119 + <el-form-item label="生成数量" prop="snNum">
  120 + <el-input-number v-model="formData.snNum" :min="1" :max="1000" />
  121 + </el-form-item>
  122 + </el-form>
  123 + <template #footer>
  124 + <el-button @click="dialogVisible = false">取消</el-button>
  125 + <el-button type="primary" @click="submitForm" :loading="formLoading">确定</el-button>
  126 + </template>
  127 + </el-dialog>
  128 +</template>
  129 +
  130 +<script setup lang="ts">
  131 +import { dateFormatter } from '@/utils/formatTime'
  132 +import { WmSnApi, WmSnVO, WmSnGenerateVO } from '@/api/mes/wm/sn'
  133 +
  134 +defineOptions({ name: 'MesWmSn' })
  135 +
  136 +const message = useMessage()
  137 +const { t } = useI18n()
  138 +
  139 +const loading = ref(true)
  140 +const list = ref<WmSnVO[]>([])
  141 +const total = ref(0)
  142 +const queryParams = reactive({
  143 + pageNo: 1,
  144 + pageSize: 10,
  145 + snCode: undefined,
  146 + itemId: undefined,
  147 + batchCode: undefined,
  148 + createTime: []
  149 +})
  150 +const queryFormRef = ref()
  151 +const exportLoading = ref(false)
  152 +
  153 +/** 查询列表 */
  154 +const getList = async () => {
  155 + loading.value = true
  156 + try {
  157 + const data = await WmSnApi.getSnPage(queryParams)
  158 + list.value = data.list
  159 + total.value = data.total
  160 + } finally {
  161 + loading.value = false
  162 + }
  163 +}
  164 +
  165 +/** 搜索按钮操作 */
  166 +const handleQuery = () => {
  167 + queryParams.pageNo = 1
  168 + getList()
  169 +}
  170 +
  171 +/** 重置按钮操作 */
  172 +const resetQuery = () => {
  173 + queryFormRef.value.resetFields()
  174 + handleQuery()
  175 +}
  176 +
  177 +/** 生成对话框 */
  178 +const dialogVisible = ref(false)
  179 +const formLoading = ref(false)
  180 +const formData = ref<WmSnGenerateVO>({
  181 + itemId: undefined,
  182 + batchCode: undefined,
  183 + workOrderId: undefined,
  184 + snNum: 100
  185 +})
  186 +const formRules = reactive({
  187 + itemId: [{ required: true, message: '物料不能为空', trigger: 'change' }],
  188 + snNum: [{ required: true, message: '生成数量不能为空', trigger: 'blur' }]
  189 +})
  190 +const formRef = ref()
  191 +
  192 +/** 打开生成对话框 */
  193 +const openForm = () => {
  194 + dialogVisible.value = true
  195 + resetForm()
  196 +}
  197 +
  198 +/** 重置表单 */
  199 +const resetForm = () => {
  200 + formData.value = {
  201 + itemId: undefined,
  202 + batchCode: undefined,
  203 + workOrderId: undefined,
  204 + snNum: 100
  205 + }
  206 + formRef.value?.resetFields()
  207 +}
  208 +
  209 +/** 提交表单 */
  210 +const submitForm = async () => {
  211 + await formRef.value.validate()
  212 + formLoading.value = true
  213 + try {
  214 + await WmSnApi.generateSnCodes(formData.value)
  215 + message.success('生成成功')
  216 + dialogVisible.value = false
  217 + await getList()
  218 + } finally {
  219 + formLoading.value = false
  220 + }
  221 +}
  222 +
  223 +/** 删除按钮操作 */
  224 +const handleDelete = async (id: number) => {
  225 + try {
  226 + await message.delConfirm()
  227 + await WmSnApi.deleteSnBatch(String(id))
  228 + message.success('删除成功')
  229 + await getList()
  230 + } catch {}
  231 +}
  232 +
  233 +/** 导出按钮操作 */
  234 +const handleExport = async () => {
  235 + try {
  236 + await message.exportConfirm()
  237 + exportLoading.value = true
  238 + await WmSnApi.exportSnExcel(queryParams)
  239 + } catch {
  240 + } finally {
  241 + exportLoading.value = false
  242 + }
  243 +}
  244 +
  245 +onMounted(() => {
  246 + getList()
  247 +})
  248 +</script>