Commit 9890fa716e35507dda0221f95e05c6de0bdc62ac

Authored by YunaiV
1 parent 5a3967dd

✨ feat(mes): 新增设备台账导入功能及相关接口

新增设备台账导入功能,支持从 Excel 文件批量导入设备信息。实现了导入模板的生成和导入结果的反馈,包括成功创建和更新的设备编码,以及导入失败的原因提示。同时,更新了设备类型和车间的校验逻辑,确保数据的有效性和完整性。
Showing 25 changed files with 378 additions and 19 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/MesDvMachineryController.java
... ... @@ -8,6 +8,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
8 8 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
9 9 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
10 10 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  11 +import cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.MesDvMachineryImportExcelVO;
  12 +import cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.MesDvMachineryImportRespVO;
11 13 import cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.MesDvMachineryPageReqVO;
12 14 import cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.MesDvMachineryRespVO;
13 15 import cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.MesDvMachinerySaveReqVO;
... ... @@ -19,6 +21,7 @@ import cn.iocoder.yudao.module.mes.service.dv.machinery.MesDvMachineryTypeServic
19 21 import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkshopService;
20 22 import io.swagger.v3.oas.annotations.Operation;
21 23 import io.swagger.v3.oas.annotations.Parameter;
  24 +import io.swagger.v3.oas.annotations.Parameters;
22 25 import io.swagger.v3.oas.annotations.tags.Tag;
23 26 import jakarta.annotation.Resource;
24 27 import jakarta.servlet.http.HttpServletResponse;
... ... @@ -26,6 +29,7 @@ import jakarta.validation.Valid;
26 29 import org.springframework.security.access.prepost.PreAuthorize;
27 30 import org.springframework.validation.annotation.Validated;
28 31 import org.springframework.web.bind.annotation.*;
  32 +import org.springframework.web.multipart.MultipartFile;
29 33  
30 34 import java.io.IOException;
31 35 import java.util.Collections;
... ... @@ -116,6 +120,33 @@ public class MesDvMachineryController {
116 120 return success(BeanUtils.toBean(list, MesDvMachineryRespVO.class));
117 121 }
118 122  
  123 + @GetMapping("/get-import-template")
  124 + @Operation(summary = "获得设备导入模板")
  125 + public void importTemplate(HttpServletResponse response) throws IOException {
  126 + // 手动创建导出 demo
  127 + List<MesDvMachineryImportExcelVO> list = Collections.singletonList(
  128 + MesDvMachineryImportExcelVO.builder().code("EQ-001").name("示例设备")
  129 + .brand("示例品牌").spec("型号A").machineryTypeCode("MT-001")
  130 + .workshopCode("WS-001").status(0).build()
  131 + );
  132 + // 输出
  133 + ExcelUtils.write(response, "设备导入模板.xls", "设备列表", MesDvMachineryImportExcelVO.class, list);
  134 + }
  135 +
  136 + @PostMapping("/import")
  137 + @Operation(summary = "导入设备")
  138 + @Parameters({
  139 + @Parameter(name = "file", description = "Excel 文件", required = true),
  140 + @Parameter(name = "updateSupport", description = "是否支持更新,默认为 false", example = "true")
  141 + })
  142 + @PreAuthorize("@ss.hasPermission('mes:dv-machinery:import')")
  143 + public CommonResult<MesDvMachineryImportRespVO> importExcel(@RequestParam("file") MultipartFile file,
  144 + @RequestParam(value = "updateSupport", required = false,
  145 + defaultValue = "false") Boolean updateSupport) throws Exception {
  146 + List<MesDvMachineryImportExcelVO> list = ExcelUtils.read(file, MesDvMachineryImportExcelVO.class);
  147 + return success(machineryService.importMachineryList(list, updateSupport));
  148 + }
  149 +
119 150 // ==================== 拼接 VO ====================
120 151  
121 152 private List<MesDvMachineryRespVO> buildMachineryRespVOList(List<MesDvMachineryDO> list) {
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryImportExcelVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo;
  2 +
  3 +import cn.idev.excel.annotation.ExcelProperty;
  4 +import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
  5 +import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
  6 +import cn.iocoder.yudao.module.mes.enums.DictTypeConstants;
  7 +import lombok.AllArgsConstructor;
  8 +import lombok.Builder;
  9 +import lombok.Data;
  10 +import lombok.NoArgsConstructor;
  11 +
  12 +/**
  13 + * 设备台账 Excel 导入 VO
  14 + */
  15 +@Data
  16 +@Builder
  17 +@AllArgsConstructor
  18 +@NoArgsConstructor
  19 +public class MesDvMachineryImportExcelVO {
  20 +
  21 + @ExcelProperty("设备编码")
  22 + private String code;
  23 +
  24 + @ExcelProperty("设备名称")
  25 + private String name;
  26 +
  27 + @ExcelProperty("品牌")
  28 + private String brand;
  29 +
  30 + @ExcelProperty("规格型号")
  31 + private String spec;
  32 +
  33 + @ExcelProperty("设备类型编码")
  34 + private String machineryTypeCode;
  35 +
  36 + @ExcelProperty("所属车间编码")
  37 + private String workshopCode;
  38 +
  39 + @ExcelProperty(value = "设备状态", converter = DictConvert.class)
  40 + @DictFormat(DictTypeConstants.MES_DV_MACHINERY_STATUS)
  41 + private Integer status;
  42 +
  43 + @ExcelProperty("备注")
  44 + private String remark;
  45 +
  46 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryImportRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Builder;
  5 +import lombok.Data;
  6 +
  7 +import java.util.List;
  8 +import java.util.Map;
  9 +
  10 +@Schema(description = "管理后台 - MES 设备台账导入 Response VO")
  11 +@Data
  12 +@Builder
  13 +public class MesDvMachineryImportRespVO {
  14 +
  15 + @Schema(description = "创建成功的设备编码数组", requiredMode = Schema.RequiredMode.REQUIRED)
  16 + private List<String> createCodes;
  17 +
  18 + @Schema(description = "更新成功的设备编码数组", requiredMode = Schema.RequiredMode.REQUIRED)
  19 + private List<String> updateCodes;
  20 +
  21 + @Schema(description = "导入失败的设备集合,key 为设备编码,value 为失败原因", requiredMode = Schema.RequiredMode.REQUIRED)
  22 + private Map<String, String> failureCodes;
  23 +
  24 +}
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/dv/machinery/vo/MesDvMachineryPageReqVO.java
... ... @@ -6,6 +6,8 @@ import lombok.Data;
6 6 import lombok.EqualsAndHashCode;
7 7 import lombok.ToString;
8 8  
  9 +import java.util.Set;
  10 +
9 11 @Schema(description = "管理后台 - MES 设备台账分页 Request VO")
10 12 @Data
11 13 @EqualsAndHashCode(callSuper = true)
... ... @@ -24,6 +26,9 @@ public class MesDvMachineryPageReqVO extends PageParam {
24 26 @Schema(description = "设备类型编号", example = "100")
25 27 private Long machineryTypeId;
26 28  
  29 + @Schema(description = "设备类型编号列表(含子类型,由后端自动填充)", hidden = true)
  30 + private Set<Long> machineryTypeIds;
  31 +
27 32 @Schema(description = "所属车间编号", example = "200")
28 33 private Long workshopId;
29 34  
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/dv/checkplan/MesDvCheckPlanMachineryMapper.java
... ... @@ -28,4 +28,8 @@ public interface MesDvCheckPlanMachineryMapper extends BaseMapperX&lt;MesDvCheckPla
28 28 .eq(MesDvCheckPlanMachineryDO::getPlanId, planId));
29 29 }
30 30  
  31 + default Long selectCountByMachineryId(Long machineryId) {
  32 + return selectCount(MesDvCheckPlanMachineryDO::getMachineryId, machineryId);
  33 + }
  34 +
31 35 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/dv/checkplan/MesDvCheckPlanSubjectMapper.java
... ... @@ -28,4 +28,8 @@ public interface MesDvCheckPlanSubjectMapper extends BaseMapperX&lt;MesDvCheckPlanS
28 28 .eq(MesDvCheckPlanSubjectDO::getPlanId, planId));
29 29 }
30 30  
  31 + default Long selectCountBySubjectId(Long subjectId) {
  32 + return selectCount(MesDvCheckPlanSubjectDO::getSubjectId, subjectId);
  33 + }
  34 +
31 35 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/dv/checkrecord/MesDvCheckRecordMapper.java
... ... @@ -25,4 +25,8 @@ public interface MesDvCheckRecordMapper extends BaseMapperX&lt;MesDvCheckRecordDO&gt;
25 25 .orderByDesc(MesDvCheckRecordDO::getId));
26 26 }
27 27  
  28 + default Long selectCountByMachineryId(Long machineryId) {
  29 + return selectCount(MesDvCheckRecordDO::getMachineryId, machineryId);
  30 + }
  31 +
28 32 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/dv/machinery/MesDvMachineryMapper.java
1 1 package cn.iocoder.yudao.module.mes.dal.mysql.dv.machinery;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 6 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
... ... @@ -21,6 +22,7 @@ public interface MesDvMachineryMapper extends BaseMapperX&lt;MesDvMachineryDO&gt; {
21 22 .likeIfPresent(MesDvMachineryDO::getName, reqVO.getName())
22 23 .likeIfPresent(MesDvMachineryDO::getBrand, reqVO.getBrand())
23 24 .eqIfPresent(MesDvMachineryDO::getMachineryTypeId, reqVO.getMachineryTypeId())
  25 + .inIfPresent(MesDvMachineryDO::getMachineryTypeId, reqVO.getMachineryTypeIds())
24 26 .eqIfPresent(MesDvMachineryDO::getWorkshopId, reqVO.getWorkshopId())
25 27 .eqIfPresent(MesDvMachineryDO::getStatus, reqVO.getStatus())
26 28 .orderByDesc(MesDvMachineryDO::getId));
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/dv/maintenrecord/MesDvMaintenRecordMapper.java
... ... @@ -5,7 +5,6 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
6 6 import cn.iocoder.yudao.module.mes.controller.admin.dv.maintenrecord.vo.MesDvMaintenRecordPageReqVO;
7 7 import cn.iocoder.yudao.module.mes.dal.dataobject.dv.maintenrecord.MesDvMaintenRecordDO;
8   -import cn.hutool.core.util.StrUtil;
9 8 import org.apache.ibatis.annotations.Mapper;
10 9  
11 10 /**
... ... @@ -18,6 +17,7 @@ public interface MesDvMaintenRecordMapper extends BaseMapperX&lt;MesDvMaintenRecord
18 17  
19 18 default PageResult<MesDvMaintenRecordDO> selectPage(MesDvMaintenRecordPageReqVO reqVO) {
20 19 return selectPage(reqVO, new LambdaQueryWrapperX<MesDvMaintenRecordDO>()
  20 + // TODO @AI:对齐分析下,哪里有问题!
21 21 // .apply(StrUtil.isNotBlank(reqVO.getPlanName()),
22 22 // "plan_id IN (SELECT id FROM mes_dv_check_plan WHERE name LIKE CONCAT('%', {0}, '%') AND deleted = 0)",
23 23 // reqVO.getPlanName())
... ... @@ -34,4 +34,8 @@ public interface MesDvMaintenRecordMapper extends BaseMapperX&lt;MesDvMaintenRecord
34 34 .orderByDesc(MesDvMaintenRecordDO::getId));
35 35 }
36 36  
  37 + default Long selectCountByMachineryId(Long machineryId) {
  38 + return selectCount(MesDvMaintenRecordDO::getMachineryId, machineryId);
  39 + }
  40 +
37 41 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/dv/repair/MesDvRepairMapper.java
... ... @@ -25,4 +25,8 @@ public interface MesDvRepairMapper extends BaseMapperX&lt;MesDvRepairDO&gt; {
25 25 .orderByDesc(MesDvRepairDO::getId));
26 26 }
27 27  
  28 + default Long selectCountByMachineryId(Long machineryId) {
  29 + return selectCount(MesDvRepairDO::getMachineryId, machineryId);
  30 + }
  31 +
28 32 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
... ... @@ -149,10 +149,16 @@ public interface ErrorCodeConstants {
149 149 // ========== MES 设备管理-设备台账(1-040-301-000) ==========
150 150 ErrorCode DV_MACHINERY_NOT_EXISTS = new ErrorCode(1_040_301_000, "设备不存在");
151 151 ErrorCode DV_MACHINERY_CODE_DUPLICATE = new ErrorCode(1_040_301_001, "设备编码已存在");
  152 + ErrorCode DV_MACHINERY_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_040_301_002, "导入设备数据不能为空");
  153 + ErrorCode DV_MACHINERY_HAS_CHECK_PLAN = new ErrorCode(1_040_301_003, "设备已关联点检计划,无法删除");
  154 + ErrorCode DV_MACHINERY_HAS_CHECK_RECORD = new ErrorCode(1_040_301_004, "设备已关联点检记录,无法删除");
  155 + ErrorCode DV_MACHINERY_HAS_MAINTEN_RECORD = new ErrorCode(1_040_301_005, "设备已关联保养记录,无法删除");
  156 + ErrorCode DV_MACHINERY_HAS_REPAIR = new ErrorCode(1_040_301_006, "设备已关联维修工单,无法删除");
152 157  
153 158 // ========== MES 设备管理-点检保养项目(1-040-304-000) ==========
154 159 ErrorCode DV_SUBJECT_NOT_EXISTS = new ErrorCode(1_040_304_000, "点检保养项目不存在");
155 160 ErrorCode DV_SUBJECT_CODE_DUPLICATE = new ErrorCode(1_040_304_001, "项目编码已存在");
  161 + ErrorCode DV_SUBJECT_USED_BY_CHECK_PLAN = new ErrorCode(1_040_304_002, "点检保养项目已被点检保养方案使用,无法删除");
156 162  
157 163 // ========== MES 设备管理-点检计划(1-040-302-000) ==========
158 164 ErrorCode DV_CHECK_PLAN_NOT_EXISTS = new ErrorCode(1_040_302_000, "点检计划不存在");
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/checkplan/MesDvCheckPlanMachineryService.java
... ... @@ -51,4 +51,12 @@ public interface MesDvCheckPlanMachineryService {
51 51 */
52 52 void deleteByPlanId(Long planId);
53 53  
  54 + /**
  55 + * 获得指定设备关联的方案设备数量
  56 + *
  57 + * @param machineryId 设备编号
  58 + * @return 方案设备数量
  59 + */
  60 + Long getCheckPlanMachineryCountByMachineryId(Long machineryId);
  61 +
54 62 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/checkplan/MesDvCheckPlanMachineryServiceImpl.java
... ... @@ -74,4 +74,9 @@ public class MesDvCheckPlanMachineryServiceImpl implements MesDvCheckPlanMachine
74 74 checkPlanMachineryMapper.deleteByPlanId(planId);
75 75 }
76 76  
  77 + @Override
  78 + public Long getCheckPlanMachineryCountByMachineryId(Long machineryId) {
  79 + return checkPlanMachineryMapper.selectCountByMachineryId(machineryId);
  80 + }
  81 +
77 82 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/checkplan/MesDvCheckPlanSubjectService.java
... ... @@ -51,4 +51,12 @@ public interface MesDvCheckPlanSubjectService {
51 51 */
52 52 void deleteByPlanId(Long planId);
53 53  
  54 + /**
  55 + * 获得指定项目的方案项目关联数量
  56 + *
  57 + * @param subjectId 项目编号
  58 + * @return 项目关联数量
  59 + */
  60 + Long getCheckPlanSubjectCountBySubjectId(Long subjectId);
  61 +
54 62 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/checkplan/MesDvCheckPlanSubjectServiceImpl.java
... ... @@ -74,4 +74,9 @@ public class MesDvCheckPlanSubjectServiceImpl implements MesDvCheckPlanSubjectSe
74 74 checkPlanSubjectMapper.deleteByPlanId(planId);
75 75 }
76 76  
  77 + @Override
  78 + public Long getCheckPlanSubjectCountBySubjectId(Long subjectId) {
  79 + return checkPlanSubjectMapper.selectCountBySubjectId(subjectId);
  80 + }
  81 +
77 82 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/checkrecord/MesDvCheckRecordService.java
... ... @@ -51,6 +51,14 @@ public interface MesDvCheckRecordService {
51 51 void validateCheckRecordExists(Long id);
52 52  
53 53 /**
  54 + * 获得指定设备的点检记录数量
  55 + *
  56 + * @param machineryId 设备编号
  57 + * @return 点检记录数量
  58 + */
  59 + Long getCheckRecordCountByMachineryId(Long machineryId);
  60 +
  61 + /**
54 62 * 获得设备点检记录
55 63 *
56 64 * @param id 编号
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/checkrecord/MesDvCheckRecordServiceImpl.java
... ... @@ -125,6 +125,11 @@ public class MesDvCheckRecordServiceImpl implements MesDvCheckRecordService {
125 125 }
126 126  
127 127 @Override
  128 + public Long getCheckRecordCountByMachineryId(Long machineryId) {
  129 + return checkRecordMapper.selectCountByMachineryId(machineryId);
  130 + }
  131 +
  132 + @Override
128 133 public MesDvCheckRecordDO getCheckRecord(Long id) {
129 134 return checkRecordMapper.selectById(id);
130 135 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/machinery/MesDvMachineryService.java
1 1 package cn.iocoder.yudao.module.mes.service.dv.machinery;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.MesDvMachineryImportExcelVO;
  5 +import cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.MesDvMachineryImportRespVO;
4 6 import cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.MesDvMachineryPageReqVO;
5 7 import cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.MesDvMachinerySaveReqVO;
6 8 import cn.iocoder.yudao.module.mes.dal.dataobject.dv.machinery.MesDvMachineryDO;
... ... @@ -97,4 +99,14 @@ public interface MesDvMachineryService {
97 99 return convertMap(getMachineryList(ids), MesDvMachineryDO::getId);
98 100 }
99 101  
  102 + /**
  103 + * 导入设备列表
  104 + *
  105 + * @param importMachineryList 导入设备列表
  106 + * @param updateSupport 是否支持更新
  107 + * @return 导入结果
  108 + */
  109 + MesDvMachineryImportRespVO importMachineryList(List<MesDvMachineryImportExcelVO> importMachineryList,
  110 + boolean updateSupport);
  111 +
100 112 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/machinery/MesDvMachineryServiceImpl.java
... ... @@ -2,23 +2,33 @@ package cn.iocoder.yudao.module.mes.service.dv.machinery;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.ObjUtil;
  5 +import cn.hutool.core.util.StrUtil;
5 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  8 +import cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.MesDvMachineryImportExcelVO;
  9 +import cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.MesDvMachineryImportRespVO;
7 10 import cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.MesDvMachineryPageReqVO;
8 11 import cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.MesDvMachinerySaveReqVO;
9 12 import cn.iocoder.yudao.module.mes.dal.dataobject.dv.machinery.MesDvMachineryDO;
  13 +import cn.iocoder.yudao.module.mes.dal.dataobject.dv.machinery.MesDvMachineryTypeDO;
  14 +import cn.iocoder.yudao.module.mes.dal.dataobject.md.workstation.MesMdWorkshopDO;
10 15 import cn.iocoder.yudao.module.mes.dal.mysql.dv.machinery.MesDvMachineryMapper;
11 16 import cn.iocoder.yudao.module.mes.enums.wm.BarcodeBizTypeEnum;
  17 +import cn.iocoder.yudao.module.mes.service.dv.checkplan.MesDvCheckPlanMachineryService;
  18 +import cn.iocoder.yudao.module.mes.service.dv.checkrecord.MesDvCheckRecordService;
  19 +import cn.iocoder.yudao.module.mes.service.dv.maintenrecord.MesDvMaintenRecordService;
  20 +import cn.iocoder.yudao.module.mes.service.dv.repair.MesDvRepairService;
12 21 import cn.iocoder.yudao.module.mes.service.md.workstation.MesMdWorkshopService;
13 22 import cn.iocoder.yudao.module.mes.service.wm.barcode.MesWmBarcodeService;
14 23 import jakarta.annotation.Resource;
15 24 import org.springframework.context.annotation.Lazy;
16 25 import org.springframework.stereotype.Service;
  26 +import org.springframework.transaction.annotation.Transactional;
17 27 import org.springframework.validation.annotation.Validated;
18 28  
19   -import java.util.Collection;
20   -import java.util.Collections;
21   -import java.util.List;
  29 +import java.util.*;
  30 +import java.util.concurrent.atomic.AtomicInteger;
  31 +import java.util.stream.Collectors;
22 32  
23 33 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24 34 import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
... ... @@ -46,6 +56,22 @@ public class MesDvMachineryServiceImpl implements MesDvMachineryService {
46 56 @Resource
47 57 private MesWmBarcodeService barcodeService;
48 58  
  59 + @Resource
  60 + @Lazy
  61 + private MesDvCheckPlanMachineryService checkPlanMachineryService;
  62 +
  63 + @Resource
  64 + @Lazy
  65 + private MesDvCheckRecordService checkRecordService;
  66 +
  67 + @Resource
  68 + @Lazy
  69 + private MesDvMaintenRecordService maintenRecordService;
  70 +
  71 + @Resource
  72 + @Lazy
  73 + private MesDvRepairService repairService;
  74 +
49 75 @Override
50 76 public Long createMachinery(MesDvMachinerySaveReqVO createReqVO) {
51 77 // 校验设备类型存在
... ... @@ -85,7 +111,19 @@ public class MesDvMachineryServiceImpl implements MesDvMachineryService {
85 111 public void deleteMachinery(Long id) {
86 112 // 校验存在
87 113 validateMachineryExists(id);
88   - // TODO @芋艿:后续补充点检计划、保养记录、维修工单等引用校验
  114 + // 校验关联数据
  115 + if (checkPlanMachineryService.getCheckPlanMachineryCountByMachineryId(id) > 0) {
  116 + throw exception(DV_MACHINERY_HAS_CHECK_PLAN);
  117 + }
  118 + if (checkRecordService.getCheckRecordCountByMachineryId(id) > 0) {
  119 + throw exception(DV_MACHINERY_HAS_CHECK_RECORD);
  120 + }
  121 + if (maintenRecordService.getMaintenRecordCountByMachineryId(id) > 0) {
  122 + throw exception(DV_MACHINERY_HAS_MAINTEN_RECORD);
  123 + }
  124 + if (repairService.getRepairCountByMachineryId(id) > 0) {
  125 + throw exception(DV_MACHINERY_HAS_REPAIR);
  126 + }
89 127  
90 128 // 删除
91 129 machineryMapper.deleteById(id);
... ... @@ -118,6 +156,15 @@ public class MesDvMachineryServiceImpl implements MesDvMachineryService {
118 156  
119 157 @Override
120 158 public PageResult<MesDvMachineryDO> getMachineryPage(MesDvMachineryPageReqVO pageReqVO) {
  159 + // 处理设备类型树形查询:选择父类型时,同时查询所有子类型下的设备
  160 + if (pageReqVO.getMachineryTypeId() != null) {
  161 + List<MesDvMachineryTypeDO> children = machineryTypeService.getMachineryTypeChildrenList(
  162 + pageReqVO.getMachineryTypeId());
  163 + Set<Long> typeIds = new HashSet<>();
  164 + typeIds.add(pageReqVO.getMachineryTypeId());
  165 + children.forEach(child -> typeIds.add(child.getId()));
  166 + pageReqVO.setMachineryTypeIds(typeIds);
  167 + }
121 168 return machineryMapper.selectPage(pageReqVO);
122 169 }
123 170  
... ... @@ -139,4 +186,89 @@ public class MesDvMachineryServiceImpl implements MesDvMachineryService {
139 186 return machineryMapper.selectByIds(ids);
140 187 }
141 188  
  189 + @Override
  190 + @Transactional(rollbackFor = Exception.class)
  191 + public MesDvMachineryImportRespVO importMachineryList(List<MesDvMachineryImportExcelVO> importMachineryList,
  192 + boolean updateSupport) {
  193 + // 1. 参数校验
  194 + if (CollUtil.isEmpty(importMachineryList)) {
  195 + throw exception(DV_MACHINERY_IMPORT_LIST_IS_EMPTY);
  196 + }
  197 +
  198 + // 2. 批量加载设备类型和车间,构建编码到实体的映射
  199 + List<MesDvMachineryTypeDO> allTypes = machineryTypeService.getMachineryTypeList(
  200 + new cn.iocoder.yudao.module.mes.controller.admin.dv.machinery.vo.type.MesDvMachineryTypeListReqVO());
  201 + Map<String, MesDvMachineryTypeDO> typeCodeMap = allTypes.stream()
  202 + .collect(Collectors.toMap(MesDvMachineryTypeDO::getCode, t -> t, (a, b) -> a));
  203 + List<MesMdWorkshopDO> allWorkshops = workshopService.getWorkshopListByStatus(
  204 + cn.iocoder.yudao.framework.common.enums.CommonStatusEnum.ENABLE.getStatus());
  205 + Map<String, MesMdWorkshopDO> workshopCodeMap = allWorkshops.stream()
  206 + .collect(Collectors.toMap(MesMdWorkshopDO::getCode, w -> w, (a, b) -> a));
  207 +
  208 + // 3. 遍历,逐个创建 or 更新
  209 + MesDvMachineryImportRespVO respVO = MesDvMachineryImportRespVO.builder()
  210 + .createCodes(new ArrayList<>()).updateCodes(new ArrayList<>())
  211 + .failureCodes(new LinkedHashMap<>()).build();
  212 + AtomicInteger index = new AtomicInteger(1);
  213 + importMachineryList.forEach(importItem -> {
  214 + int currentIndex = index.getAndIncrement();
  215 + // 3.1 校验必填字段
  216 + String key = StrUtil.blankToDefault(importItem.getCode(), "第 " + currentIndex + " 行");
  217 + if (StrUtil.isBlank(importItem.getCode())) {
  218 + respVO.getFailureCodes().put(key, "设备编码不能为空");
  219 + return;
  220 + }
  221 + if (StrUtil.isBlank(importItem.getName())) {
  222 + respVO.getFailureCodes().put(key, "设备名称不能为空");
  223 + return;
  224 + }
  225 + // 3.2 校验设备类型编码
  226 + if (StrUtil.isBlank(importItem.getMachineryTypeCode())) {
  227 + respVO.getFailureCodes().put(key, "设备类型编码不能为空");
  228 + return;
  229 + }
  230 + MesDvMachineryTypeDO machineryType = typeCodeMap.get(importItem.getMachineryTypeCode());
  231 + if (machineryType == null) {
  232 + respVO.getFailureCodes().put(key, "设备类型编码[" + importItem.getMachineryTypeCode() + "]不存在");
  233 + return;
  234 + }
  235 + // 3.3 校验车间编码
  236 + if (StrUtil.isBlank(importItem.getWorkshopCode())) {
  237 + respVO.getFailureCodes().put(key, "车间编码不能为空");
  238 + return;
  239 + }
  240 + MesMdWorkshopDO workshop = workshopCodeMap.get(importItem.getWorkshopCode());
  241 + if (workshop == null) {
  242 + respVO.getFailureCodes().put(key, "车间编码[" + importItem.getWorkshopCode() + "]不存在");
  243 + return;
  244 + }
  245 +
  246 + // 3.4 判断:创建 or 更新
  247 + MesDvMachineryDO existMachinery = machineryMapper.selectByCode(importItem.getCode());
  248 + if (existMachinery == null) {
  249 + // 3.4.1 创建
  250 + MesDvMachineryDO machinery = BeanUtils.toBean(importItem, MesDvMachineryDO.class);
  251 + machinery.setMachineryTypeId(machineryType.getId());
  252 + machinery.setWorkshopId(workshop.getId());
  253 + machineryMapper.insert(machinery);
  254 + // 自动生成条码
  255 + barcodeService.autoGenerateBarcode(BarcodeBizTypeEnum.MACHINERY.getValue(),
  256 + machinery.getId(), machinery.getCode(), machinery.getName());
  257 + respVO.getCreateCodes().add(importItem.getCode());
  258 + } else if (updateSupport) {
  259 + // 3.4.2 更新
  260 + MesDvMachineryDO updateObj = BeanUtils.toBean(importItem, MesDvMachineryDO.class);
  261 + updateObj.setId(existMachinery.getId());
  262 + updateObj.setMachineryTypeId(machineryType.getId());
  263 + updateObj.setWorkshopId(workshop.getId());
  264 + machineryMapper.updateById(updateObj);
  265 + respVO.getUpdateCodes().add(importItem.getCode());
  266 + } else {
  267 + // 不支持更新
  268 + respVO.getFailureCodes().put(key, "设备编码已存在");
  269 + }
  270 + });
  271 + return respVO;
  272 + }
  273 +
142 274 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/machinery/MesDvMachineryTypeServiceImpl.java
... ... @@ -164,23 +164,28 @@ public class MesDvMachineryTypeServiceImpl implements MesDvMachineryTypeService
164 164 @Override
165 165 public List<MesDvMachineryTypeDO> getMachineryTypeChildrenList(Long parentId) {
166 166 List<MesDvMachineryTypeDO> allList = machineryTypeMapper.selectList(); // 类型总量小,全量查
167   - // 递归收集所有子类型
  167 + // 1. 构建 parentId -> children 的 Map(类似 menu 的 treeNodeMap 思路)
  168 + Map<Long, List<MesDvMachineryTypeDO>> parentChildrenMap = new LinkedHashMap<>();
  169 + allList.forEach(type -> parentChildrenMap
  170 + .computeIfAbsent(type.getParentId(), k -> new ArrayList<>()).add(type));
  171 + // 2. 收集所有后代节点
168 172 List<MesDvMachineryTypeDO> result = new ArrayList<>();
169   - collectMachineryTypeChildren(result, parentId, allList);
170   - return result;
171   - }
172   -
173   - /**
174   - * 递归收集所有子类型
175   - */
176   - private void collectMachineryTypeChildren(List<MesDvMachineryTypeDO> result, Long parentId,
177   - List<MesDvMachineryTypeDO> allList) {
178   - for (MesDvMachineryTypeDO machineryType : allList) {
179   - if (Objects.equals(machineryType.getParentId(), parentId)) {
180   - result.add(machineryType);
181   - collectMachineryTypeChildren(result, machineryType.getId(), allList);
  173 + List<Long> parentIds = new ArrayList<>();
  174 + parentIds.add(parentId);
  175 + for (int i = 0; i < Short.MAX_VALUE; i++) {
  176 + if (i >= parentIds.size()) {
  177 + break;
  178 + }
  179 + List<MesDvMachineryTypeDO> children = parentChildrenMap.get(parentIds.get(i));
  180 + if (children == null) {
  181 + continue;
  182 + }
  183 + for (MesDvMachineryTypeDO child : children) {
  184 + result.add(child);
  185 + parentIds.add(child.getId());
182 186 }
183 187 }
  188 + return result;
184 189 }
185 190  
186 191 }
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/maintenrecord/MesDvMaintenRecordService.java
... ... @@ -51,6 +51,14 @@ public interface MesDvMaintenRecordService {
51 51 void validateMaintenRecordExists(Long id);
52 52  
53 53 /**
  54 + * 获得指定设备的保养记录数量
  55 + *
  56 + * @param machineryId 设备编号
  57 + * @return 保养记录数量
  58 + */
  59 + Long getMaintenRecordCountByMachineryId(Long machineryId);
  60 +
  61 + /**
54 62 * 获得设备保养记录
55 63 *
56 64 * @param id 编号
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/maintenrecord/MesDvMaintenRecordServiceImpl.java
... ... @@ -110,6 +110,11 @@ public class MesDvMaintenRecordServiceImpl implements MesDvMaintenRecordService
110 110 }
111 111 }
112 112  
  113 + @Override
  114 + public Long getMaintenRecordCountByMachineryId(Long machineryId) {
  115 + return maintenRecordMapper.selectCountByMachineryId(machineryId);
  116 + }
  117 +
113 118 /**
114 119 * 校验设备保养记录是否为草稿状态
115 120 *
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/repair/MesDvRepairService.java
... ... @@ -44,6 +44,14 @@ public interface MesDvRepairService {
44 44 void validateRepairExists(Long id);
45 45  
46 46 /**
  47 + * 获得指定设备的维修工单数量
  48 + *
  49 + * @param machineryId 设备编号
  50 + * @return 维修工单数量
  51 + */
  52 + Long getRepairCountByMachineryId(Long machineryId);
  53 +
  54 + /**
47 55 * 获得维修工单
48 56 *
49 57 * @param id 编号
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/repair/MesDvRepairServiceImpl.java
... ... @@ -83,6 +83,11 @@ public class MesDvRepairServiceImpl implements MesDvRepairService {
83 83 }
84 84 }
85 85  
  86 + @Override
  87 + public Long getRepairCountByMachineryId(Long machineryId) {
  88 + return repairMapper.selectCountByMachineryId(machineryId);
  89 + }
  90 +
86 91 /**
87 92 * 校验维修工单是否为草稿状态
88 93 *
... ...
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/dv/subject/MesDvSubjectServiceImpl.java
... ... @@ -8,7 +8,9 @@ import cn.iocoder.yudao.module.mes.controller.admin.dv.subject.vo.MesDvSubjectPa
8 8 import cn.iocoder.yudao.module.mes.controller.admin.dv.subject.vo.MesDvSubjectSaveReqVO;
9 9 import cn.iocoder.yudao.module.mes.dal.dataobject.dv.subject.MesDvSubjectDO;
10 10 import cn.iocoder.yudao.module.mes.dal.mysql.dv.subject.MesDvSubjectMapper;
  11 +import cn.iocoder.yudao.module.mes.service.dv.checkplan.MesDvCheckPlanSubjectService;
11 12 import jakarta.annotation.Resource;
  13 +import org.springframework.context.annotation.Lazy;
12 14 import org.springframework.stereotype.Service;
13 15 import org.springframework.validation.annotation.Validated;
14 16  
... ... @@ -30,6 +32,10 @@ public class MesDvSubjectServiceImpl implements MesDvSubjectService {
30 32  
31 33 @Resource
32 34 private MesDvSubjectMapper subjectMapper;
  35 + // DONE @AI:调用对方的 service
  36 + @Resource
  37 + @Lazy
  38 + private MesDvCheckPlanSubjectService checkPlanSubjectService;
33 39  
34 40 @Override
35 41 public Long createSubject(MesDvSubjectSaveReqVO createReqVO) {
... ... @@ -58,6 +64,11 @@ public class MesDvSubjectServiceImpl implements MesDvSubjectService {
58 64 public void deleteSubject(Long id) {
59 65 // 校验存在
60 66 validateSubjectExists(id);
  67 + // 校验是否被点检保养方案引用
  68 + if (checkPlanSubjectService.getCheckPlanSubjectCountBySubjectId(id) > 0) {
  69 + throw exception(DV_SUBJECT_USED_BY_CHECK_PLAN);
  70 + }
  71 +
61 72 // 删除
62 73 subjectMapper.deleteById(id);
63 74 }
... ...