Browse Source

资料分类后台

lipenghui 5 tháng trước cách đây
mục cha
commit
9a30ea2ad2
11 tập tin đã thay đổi với 642 bổ sung5 xóa
  1. 84 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/IotInfoClassifyController.java
  2. 6 5
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotDevicePageReqVO.java
  3. 16 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotInfoClassifyListReqVO.java
  4. 39 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotInfoClassifyPageReqVO.java
  5. 43 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotInfoClassifyRespVO.java
  6. 34 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotInfoClassifySaveReqVO.java
  7. 23 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotInfoClassifySimpleRespVO.java
  8. 49 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/IotInfoClassifyDO.java
  9. 48 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/IotInfoClassifyMapper.java
  10. 120 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotInfoClassifyService.java
  11. 180 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotInfoClassifyServiceImpl.java

+ 84 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/IotInfoClassifyController.java

@@ -0,0 +1,84 @@
+package cn.iocoder.yudao.module.pms.controller.admin;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotInfoClassifyListReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotInfoClassifyRespVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotInfoClassifySaveReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotInfoClassifySimpleRespVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.IotInfoClassifyDO;
+import cn.iocoder.yudao.module.pms.service.IotInfoClassifyService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 资料分类")
+@RestController
+@RequestMapping("/rq/iot-info-classify")
+@Validated
+public class IotInfoClassifyController {
+
+    @Resource
+    private IotInfoClassifyService IotInfoClassifyService;
+
+    @PostMapping("create")
+    @Operation(summary = "创建资料分类")
+    @PreAuthorize("@ss.hasPermission('iot:info-classify:create')")
+    public CommonResult<Long> createIotInfoClassify(@Valid @RequestBody IotInfoClassifySaveReqVO createReqVO) {
+        Long deptId = IotInfoClassifyService.createIotInfoClassify(createReqVO);
+        return success(deptId);
+    }
+
+    @PutMapping("update")
+    @Operation(summary = "更新资料分类")
+    @PreAuthorize("@ss.hasPermission('iot:info-classify:update')")
+    public CommonResult<Boolean> updateIotInfoClassify(@Valid @RequestBody IotInfoClassifySaveReqVO updateReqVO) {
+        IotInfoClassifyService.updateIotInfoClassify(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("delete")
+    @Operation(summary = "删除资料分类")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('iot:info-classify:delete')")
+    public CommonResult<Boolean> deleteIotInfoClassify(@RequestParam("id") Long id) {
+        IotInfoClassifyService.deleteIotInfoClassify(id);
+        return success(true);
+    }
+
+    @GetMapping("/list")
+    @Operation(summary = "获取资料分类列表")
+    @PreAuthorize("@ss.hasPermission('iot:info-classify:query')")
+    public CommonResult<List<IotInfoClassifyRespVO>> getIotInfoClassifyList(IotInfoClassifyListReqVO reqVO) {
+        List<IotInfoClassifyDO> list = IotInfoClassifyService.getIotInfoClassifyList(reqVO);
+        return success(BeanUtils.toBean(list, IotInfoClassifyRespVO.class));
+    }
+
+    @GetMapping(value = {"/list-all-simple", "/simple-list"})
+    @Operation(summary = "获取资料分类精简信息列表", description = "只包含被开启的资料分类,主要用于前端的下拉选项")
+    public CommonResult<List<IotInfoClassifySimpleRespVO>> getSimpleIotInfoClassifyList() {
+        List<IotInfoClassifyDO> list = IotInfoClassifyService.getIotInfoClassifyList(
+                new IotInfoClassifyListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
+        return success(BeanUtils.toBean(list, IotInfoClassifySimpleRespVO.class));
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得资料分类信息")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('iot:info-classify:query')")
+    public CommonResult<IotInfoClassifyRespVO> getIotInfoClassify(@RequestParam("id") Long id) {
+        IotInfoClassifyDO dept = IotInfoClassifyService.getIotInfoClassify(id);
+        return success(BeanUtils.toBean(dept, IotInfoClassifyRespVO.class));
+    }
+
+}

+ 6 - 5
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotDevicePageReqVO.java

@@ -1,13 +1,14 @@
 package cn.iocoder.yudao.module.pms.controller.admin.vo;
 
-import lombok.*;
-
-import java.time.LocalDate;
-import java.util.*;
-import io.swagger.v3.oas.annotations.media.Schema;
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
 import org.springframework.format.annotation.DateTimeFormat;
 
+import java.time.LocalDate;
+
 import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
 
 @Schema(description = "管理后台 - 设备台账分页 Request VO")

+ 16 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotInfoClassifyListReqVO.java

@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.pms.controller.admin.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 产品分类列表 Request VO")
+@Data
+public class IotInfoClassifyListReqVO {
+
+    @Schema(description = "产品分类名称,模糊匹配", example = "芋道")
+    private String name;
+
+    @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
+    private Integer status;
+
+}

+ 39 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotInfoClassifyPageReqVO.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.pms.controller.admin.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 设备分类分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class IotInfoClassifyPageReqVO extends PageParam {
+
+    @Schema(description = "父分类id", example = "1691")
+    private Long parentId;
+
+    @Schema(description = "分类名称", example = "王五")
+    private String name;
+
+    @Schema(description = "分类编码")
+    private String code;
+
+    @Schema(description = "分类排序")
+    private Integer sort;
+
+    @Schema(description = "开启状态", example = "2")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+    private String remark;
+}

+ 43 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotInfoClassifyRespVO.java

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.pms.controller.admin.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 设备分类 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotInfoClassifyRespVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "28642")
+    @ExcelProperty("主键id")
+    private Long id;
+
+    @Schema(description = "父分类id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1691")
+    @ExcelProperty("父分类id")
+    private Long parentId;
+
+    @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
+    @ExcelProperty("分类名称")
+    private String name;
+
+    @Schema(description = "分类编码")
+    @ExcelProperty("分类编码")
+    private String code;
+
+    @Schema(description = "分类排序")
+    @ExcelProperty("分类排序")
+    private Integer sort;
+
+    @Schema(description = "开启状态", example = "2")
+    @ExcelProperty("开启状态")
+    private Integer status;
+
+    @Schema(description = "创建时间")
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+    private String remark;
+}

+ 34 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotInfoClassifySaveReqVO.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.pms.controller.admin.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 设备分类新增/修改 Request VO")
+@Data
+public class IotInfoClassifySaveReqVO {
+
+    @Schema(description = "主键id", requiredMode = Schema.RequiredMode.REQUIRED, example = "28642")
+    private Long id;
+
+    @Schema(description = "父分类id", requiredMode = Schema.RequiredMode.REQUIRED, example = "1691")
+    @NotNull(message = "父分类id不能为空")
+    private Long parentId;
+
+    @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
+    @NotEmpty(message = "分类名称不能为空")
+    private String name;
+
+    @Schema(description = "分类编码")
+    private String code;
+
+    @Schema(description = "分类排序")
+    private Integer sort;
+
+    @Schema(description = "开启状态", example = "2")
+    private Integer status;
+
+    private String remark;
+}

+ 23 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotInfoClassifySimpleRespVO.java

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.pms.controller.admin.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Schema(description = "管理后台 - 产品分类精简信息 Response VO")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class IotInfoClassifySimpleRespVO {
+
+    @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long id;
+
+    @Schema(description = "产品分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道")
+    private String name;
+
+    @Schema(description = "父产品分类 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+    private Long parentId;
+
+}

+ 49 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/IotInfoClassifyDO.java

@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.pms.dal.dataobject;
+
+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.*;
+
+/**
+ * 设备分类 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("rq_iot_product_classify")
+@KeySequence("rq_iot_product_classify_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class IotInfoClassifyDO extends BaseDO {
+    public static final Long PARENT_ID_ROOT = 0L;
+
+    /**
+     * 主键id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 父分类id
+     */
+    private Long parentId;
+    /**
+     * 分类名称
+     */
+    private String name;
+    /**
+     * 分类排序
+     */
+    private Integer sort;
+    /**
+     * 开启状态
+     */
+    private Integer status;
+
+    private String remark;
+
+}

+ 48 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/IotInfoClassifyMapper.java

@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.pms.dal.mysql;
+
+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.pms.controller.admin.vo.IotInfoClassifyListReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotInfoClassifyPageReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotProductClassifyListReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotProductClassifyPageReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.IotInfoClassifyDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 设备分类 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface IotInfoClassifyMapper extends BaseMapperX<IotInfoClassifyDO> {
+    default List<IotInfoClassifyDO> selectListByParentId(Collection<Long> parentIds) {
+        return selectList(IotInfoClassifyDO::getParentId, parentIds);
+    }
+    default IotInfoClassifyDO selectByParentIdAndName(Long parentId, String name) {
+        return selectOne(IotInfoClassifyDO::getParentId, parentId, IotInfoClassifyDO::getName, name);
+    }
+    default List<IotInfoClassifyDO> selectList(IotInfoClassifyListReqVO reqVO) {
+        return selectList(new LambdaQueryWrapperX<IotInfoClassifyDO>()
+                .likeIfPresent(IotInfoClassifyDO::getName, reqVO.getName())
+                .eqIfPresent(IotInfoClassifyDO::getStatus, reqVO.getStatus()));
+    }
+    default Long selectCountByParentId(Long parentId) {
+        return selectCount(IotInfoClassifyDO::getParentId, parentId);
+    }
+    default PageResult<IotInfoClassifyDO> selectPage(IotInfoClassifyPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<IotInfoClassifyDO>()
+                .eqIfPresent(IotInfoClassifyDO::getParentId, reqVO.getParentId())
+                .likeIfPresent(IotInfoClassifyDO::getName, reqVO.getName())
+                .eqIfPresent(IotInfoClassifyDO::getSort, reqVO.getSort())
+                .eqIfPresent(IotInfoClassifyDO::getStatus, reqVO.getStatus())
+                .eqIfPresent(IotInfoClassifyDO::getRemark, reqVO.getRemark())
+                .betweenIfPresent(IotInfoClassifyDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(IotInfoClassifyDO::getId));
+    }
+
+}

+ 120 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotInfoClassifyService.java

@@ -0,0 +1,120 @@
+package cn.iocoder.yudao.module.pms.service;
+
+import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotInfoClassifyListReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotInfoClassifySaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.IotInfoClassifyDO;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 产品分类 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface IotInfoClassifyService {
+
+    /**
+     * 创建产品分类
+     *
+     * @param createReqVO 产品分类信息
+     * @return 产品分类编号
+     */
+    Long createIotInfoClassify(IotInfoClassifySaveReqVO createReqVO);
+
+    /**
+     * 更新产品分类
+     *
+     * @param updateReqVO 产品分类信息
+     */
+    void updateIotInfoClassify(IotInfoClassifySaveReqVO updateReqVO);
+
+    /**
+     * 删除产品分类
+     *
+     * @param id 产品分类编号
+     */
+    void deleteIotInfoClassify(Long id);
+
+    /**
+     * 获得产品分类信息
+     *
+     * @param id 产品分类编号
+     * @return 产品分类信息
+     */
+    IotInfoClassifyDO getIotInfoClassify(Long id);
+
+    /**
+     * 获得产品分类信息数组
+     *
+     * @param ids 产品分类编号数组
+     * @return 产品分类信息数组
+     */
+    List<IotInfoClassifyDO> getIotInfoClassifyList(Collection<Long> ids);
+
+    /**
+     * 筛选产品分类列表
+     *
+     * @param reqVO 筛选条件请求 VO
+     * @return 产品分类列表
+     */
+    List<IotInfoClassifyDO> getIotInfoClassifyList(IotInfoClassifyListReqVO reqVO);
+
+    /**
+     * 获得指定编号的产品分类 Map
+     *
+     * @param ids 产品分类编号数组
+     * @return 产品分类 Map
+     */
+    default Map<Long, IotInfoClassifyDO> getIotInfoClassifyMap(Collection<Long> ids) {
+        List<IotInfoClassifyDO> list = getIotInfoClassifyList(ids);
+        return CollectionUtils.convertMap(list, IotInfoClassifyDO::getId);
+    }
+
+    /**
+     * 获得指定产品分类的所有子产品分类
+     *
+     * @param id 产品分类编号
+     * @return 子产品分类列表
+     */
+    default List<IotInfoClassifyDO> getChildIotInfoClassifyList(Long id) {
+        return getChildIotInfoClassifyList(Collections.singleton(id));
+    }
+
+    /**
+     * 获得指定产品分类的所有子产品分类
+     *
+     * @param ids 产品分类编号数组
+     * @return 子产品分类列表
+     */
+    List<IotInfoClassifyDO> getChildIotInfoClassifyList(Collection<Long> ids);
+
+//    /**
+//     * 获得指定领导者的产品分类列表
+//     *
+//     * @param id 领导者编号
+//     * @return 产品分类列表
+//     */
+//    List<IotInfoClassifyDO> getIotInfoClassifyListByLeaderUserId(Long id);
+//
+//    /**
+//     * 获得所有子产品分类,从缓存中
+//     *
+//     * @param id 父产品分类编号
+//     * @return 子产品分类列表
+//     */
+//    Set<Long> getChildIotInfoClassifyIdListFromCache(Long id);
+//
+//    /**
+//     * 校验产品分类们是否有效。如下情况,视为无效:
+//     * 1. 产品分类编号不存在
+//     * 2. 产品分类被禁用
+//     *
+//     * @param ids 角色编号数组
+//     */
+//    void validateIotInfoClassifyList(Collection<Long> ids);
+
+}

+ 180 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotInfoClassifyServiceImpl.java

@@ -0,0 +1,180 @@
+package cn.iocoder.yudao.module.pms.service;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotInfoClassifyListReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotInfoClassifySaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.IotInfoClassifyDO;
+import cn.iocoder.yudao.module.pms.dal.mysql.IotInfoClassifyMapper;
+import com.google.common.annotations.VisibleForTesting;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.*;
+
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
+
+/**
+ * 产品分类 Service 实现类
+ *
+ * @author 芋道源码
+ */
+@Service
+@Validated
+@Slf4j
+public class IotInfoClassifyServiceImpl implements IotInfoClassifyService {
+
+    @Resource
+    private IotInfoClassifyMapper iotInfoClassifyMapper;
+
+    @Override
+    public Long createIotInfoClassify(IotInfoClassifySaveReqVO createReqVO) {
+        if (createReqVO.getParentId() == null) {
+            createReqVO.setParentId(IotInfoClassifyDO.PARENT_ID_ROOT);
+        }
+        // 校验父产品分类的有效性
+        validateParentInfoClassify(null, createReqVO.getParentId());
+        // 校验产品分类名的唯一性
+        validateInfoClassifyNameUnique(null, createReqVO.getParentId(), createReqVO.getName());
+
+        // 插入产品分类
+        IotInfoClassifyDO dept = BeanUtils.toBean(createReqVO, IotInfoClassifyDO.class);
+        iotInfoClassifyMapper.insert(dept);
+        return dept.getId();
+    }
+
+    @Override
+    public void updateIotInfoClassify(IotInfoClassifySaveReqVO updateReqVO) {
+        if (updateReqVO.getParentId() == null) {
+            updateReqVO.setParentId(IotInfoClassifyDO.PARENT_ID_ROOT);
+        }
+        // 校验自己存在
+        validateIotInfoClassifyExists(updateReqVO.getId());
+        // 校验父产品分类的有效性
+        validateParentInfoClassify(updateReqVO.getId(), updateReqVO.getParentId());
+        // 校验产品分类名的唯一性
+        validateInfoClassifyNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());
+
+        // 更新产品分类
+        IotInfoClassifyDO updateObj = BeanUtils.toBean(updateReqVO, IotInfoClassifyDO.class);
+        iotInfoClassifyMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteIotInfoClassify(Long id) {
+        // 校验是否存在
+        validateIotInfoClassifyExists(id);
+        // 校验是否有子产品分类
+        if (iotInfoClassifyMapper.selectCountByParentId(id) > 0) {
+            throw exception(DEPT_EXITS_CHILDREN);
+        }
+        // 删除产品分类
+        iotInfoClassifyMapper.deleteById(id);
+    }
+
+    @VisibleForTesting
+    void validateIotInfoClassifyExists(Long id) {
+        if (id == null) {
+            return;
+        }
+        IotInfoClassifyDO dept = iotInfoClassifyMapper.selectById(id);
+        if (dept == null) {
+            throw exception(DEPT_NOT_FOUND);
+        }
+    }
+
+    @VisibleForTesting
+    void validateParentInfoClassify(Long id, Long parentId) {
+        if (parentId == null || IotInfoClassifyDO.PARENT_ID_ROOT.equals(parentId)) {
+            return;
+        }
+        // 1. 不能设置自己为父产品分类
+        if (Objects.equals(id, parentId)) {
+            throw exception(DEPT_PARENT_ERROR);
+        }
+        // 2. 父产品分类不存在
+        IotInfoClassifyDO parentDept = iotInfoClassifyMapper.selectById(parentId);
+        if (parentDept == null) {
+            throw exception(DEPT_PARENT_NOT_EXITS);
+        }
+        // 3. 递归校验父产品分类,如果父产品分类是自己的子产品分类,则报错,避免形成环路
+        if (id == null) { // id 为空,说明新增,不需要考虑环路
+            return;
+        }
+        for (int i = 0; i < Short.MAX_VALUE; i++) {
+            // 3.1 校验环路
+            parentId = parentDept.getParentId();
+            if (Objects.equals(id, parentId)) {
+                throw exception(DEPT_PARENT_IS_CHILD);
+            }
+            // 3.2 继续递归下一级父产品分类
+            if (parentId == null || IotInfoClassifyDO.PARENT_ID_ROOT.equals(parentId)) {
+                break;
+            }
+            parentDept = iotInfoClassifyMapper.selectById(parentId);
+            if (parentDept == null) {
+                break;
+            }
+        }
+    }
+
+    @VisibleForTesting
+    void validateInfoClassifyNameUnique(Long id, Long parentId, String name) {
+        IotInfoClassifyDO dept = iotInfoClassifyMapper.selectByParentIdAndName(parentId, name);
+        if (dept == null) {
+            return;
+        }
+        // 如果 id 为空,说明不用比较是否为相同 id 的产品分类
+        if (id == null) {
+            throw exception(DEPT_NAME_DUPLICATE);
+        }
+        if (ObjectUtil.notEqual(dept.getId(), id)) {
+            throw exception(DEPT_NAME_DUPLICATE);
+        }
+    }
+
+    @Override
+    public IotInfoClassifyDO getIotInfoClassify(Long id) {
+        return iotInfoClassifyMapper.selectById(id);
+    }
+
+    @Override
+    public List<IotInfoClassifyDO> getIotInfoClassifyList(Collection<Long> ids) {
+        if (CollUtil.isEmpty(ids)) {
+            return Collections.emptyList();
+        }
+        return iotInfoClassifyMapper.selectBatchIds(ids);
+    }
+
+    @Override
+    public List<IotInfoClassifyDO> getIotInfoClassifyList(IotInfoClassifyListReqVO reqVO) {
+        List<IotInfoClassifyDO> list = iotInfoClassifyMapper.selectList(reqVO);
+        list.sort(Comparator.comparing(IotInfoClassifyDO::getSort));
+        return list;
+    }
+
+    @Override
+    public List<IotInfoClassifyDO> getChildIotInfoClassifyList(Collection<Long> ids) {
+        List<IotInfoClassifyDO> children = new LinkedList<>();
+        // 遍历每一层
+        Collection<Long> parentIds = ids;
+        for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环
+            // 查询当前层,所有的子产品分类
+            List<IotInfoClassifyDO> depts = iotInfoClassifyMapper.selectListByParentId(parentIds);
+            // 1. 如果没有子产品分类,则结束遍历
+            if (CollUtil.isEmpty(depts)) {
+                break;
+            }
+            // 2. 如果有子产品分类,继续遍历
+            children.addAll(depts);
+            parentIds = convertSet(depts, IotInfoClassifyDO::getId);
+        }
+        return children;
+    }
+
+}