lipenghui hai 5 meses
pai
achega
9230775526
Modificáronse 14 ficheiros con 641 adicións e 9 borrados
  1. 2 4
      yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/enums/ErrorCodeConstant.java
  2. 84 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/IotProductClassifyController.java
  3. 16 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotProductClassifyListReqVO.java
  4. 37 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotProductClassifyPageReqVO.java
  5. 43 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotProductClassifyRespVO.java
  6. 32 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotProductClassifySaveReqVO.java
  7. 23 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotProductClassifySimpleRespVO.java
  8. 52 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/dataobject/IotProductClassifyDO.java
  9. 46 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/dal/mysql/IotProductClassifyMapper.java
  10. 119 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotProductClassifyService.java
  11. 180 0
      yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotProductClassifyServiceImpl.java
  12. 4 2
      yudao-server/src/main/resources/application-dev.yaml
  13. 1 1
      yudao-server/src/main/resources/application-local.yaml
  14. 2 2
      yudao-server/src/main/resources/application.yaml

+ 2 - 4
yudao-module-pms/yudao-module-pms-api/src/main/java/cn/iocoder/yudao/module/pms/enums/ErrorCodeConstant.java

@@ -1,9 +1,7 @@
-package cn.iocoder.yudao.module.supplier.enums;
+package cn.iocoder.yudao.module.pms.enums;
 
 import cn.iocoder.yudao.framework.common.exception.ErrorCode;
 
 public interface ErrorCodeConstant{
-    ErrorCode NOT_EXISTS = new ErrorCode( 122, "供应商主数据不存在");
-    ErrorCode SUPPLIER_UPDATE_AUDIT_STATUS_FAIL_NOT_PROCESS = new ErrorCode(1-060-000-002, "更新供应商审核状态失败,原因:供应商不是审核中状态");
-    ErrorCode NAME_EXISTED = new ErrorCode( 133, "名称重复");
+    ErrorCode IOT_PRODUCT_CLASSIFY_NOT_EXISTS = new ErrorCode(100, "设备分类不存在");
 }

+ 84 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/IotProductClassifyController.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.IotProductClassifyListReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotProductClassifyRespVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotProductClassifySaveReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotProductClassifySimpleRespVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.IotProductClassifyDO;
+import cn.iocoder.yudao.module.pms.service.IotProductClassifyService;
+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-product-classify")
+@Validated
+public class IotProductClassifyController {
+
+    @Resource
+    private IotProductClassifyService iotProductClassifyService;
+
+    @PostMapping("create")
+    @Operation(summary = "创建产品分类")
+    @PreAuthorize("@ss.hasPermission('system:product-classify:create')")
+    public CommonResult<Long> createIotProductClassify(@Valid @RequestBody IotProductClassifySaveReqVO createReqVO) {
+        Long deptId = iotProductClassifyService.createIotProductClassify(createReqVO);
+        return success(deptId);
+    }
+
+    @PutMapping("update")
+    @Operation(summary = "更新产品分类")
+    @PreAuthorize("@ss.hasPermission('system:product-classify:update')")
+    public CommonResult<Boolean> updateIotProductClassify(@Valid @RequestBody IotProductClassifySaveReqVO updateReqVO) {
+        iotProductClassifyService.updateIotProductClassify(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("delete")
+    @Operation(summary = "删除产品分类")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('system:product-classify:delete')")
+    public CommonResult<Boolean> deleteIotProductClassify(@RequestParam("id") Long id) {
+        iotProductClassifyService.deleteIotProductClassify(id);
+        return success(true);
+    }
+
+    @GetMapping("/list")
+    @Operation(summary = "获取产品分类列表")
+    @PreAuthorize("@ss.hasPermission('system:product-classify:query')")
+    public CommonResult<List<IotProductClassifyRespVO>> getIotProductClassifyList(IotProductClassifyListReqVO reqVO) {
+        List<IotProductClassifyDO> list = iotProductClassifyService.getIotProductClassifyList(reqVO);
+        return success(BeanUtils.toBean(list, IotProductClassifyRespVO.class));
+    }
+
+    @GetMapping(value = {"/list-all-simple", "/simple-list"})
+    @Operation(summary = "获取产品分类精简信息列表", description = "只包含被开启的产品分类,主要用于前端的下拉选项")
+    public CommonResult<List<IotProductClassifySimpleRespVO>> getSimpleIotProductClassifyList() {
+        List<IotProductClassifyDO> list = iotProductClassifyService.getIotProductClassifyList(
+                new IotProductClassifyListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
+        return success(BeanUtils.toBean(list, IotProductClassifySimpleRespVO.class));
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得产品分类信息")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('system:product-classify:query')")
+    public CommonResult<IotProductClassifyRespVO> getIotProductClassify(@RequestParam("id") Long id) {
+        IotProductClassifyDO dept = iotProductClassifyService.getIotProductClassify(id);
+        return success(BeanUtils.toBean(dept, IotProductClassifyRespVO.class));
+    }
+
+}

+ 16 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotProductClassifyListReqVO.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 IotProductClassifyListReqVO {
+
+    @Schema(description = "产品分类名称,模糊匹配", example = "芋道")
+    private String name;
+
+    @Schema(description = "展示状态,参见 CommonStatusEnum 枚举类", example = "1")
+    private Integer status;
+
+}

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

@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.pms.controller.admin.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+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 IotProductClassifyPageReqVO 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;
+
+}

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

@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.pms.controller.admin.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+
+@Schema(description = "管理后台 - 设备分类 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class IotProductClassifyRespVO {
+
+    @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;
+
+}

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

@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.pms.controller.admin.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import javax.validation.constraints.*;
+
+@Schema(description = "管理后台 - 设备分类新增/修改 Request VO")
+@Data
+public class IotProductClassifySaveReqVO {
+
+    @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;
+
+}

+ 23 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/controller/admin/vo/IotProductClassifySimpleRespVO.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 IotProductClassifySimpleRespVO {
+
+    @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;
+
+}

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

@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.pms.dal.dataobject;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 设备分类 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 IotProductClassifyDO extends BaseDO {
+    public static final Long PARENT_ID_ROOT = 0L;
+
+    /**
+     * 主键id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 父分类id
+     */
+    private Long parentId;
+    /**
+     * 分类名称
+     */
+    private String name;
+    /**
+     * 分类编码
+     */
+    private String code;
+    /**
+     * 分类排序
+     */
+    private Integer sort;
+    /**
+     * 开启状态
+     */
+    private Integer status;
+
+}

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

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

+ 119 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotProductClassifyService.java

@@ -0,0 +1,119 @@
+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.IotProductClassifyListReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotProductClassifySaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.IotProductClassifyDO;
+import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
+import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
+
+import java.util.*;
+
+/**
+ * 产品分类 Service 接口
+ *
+ * @author 芋道源码
+ */
+public interface IotProductClassifyService {
+
+    /**
+     * 创建产品分类
+     *
+     * @param createReqVO 产品分类信息
+     * @return 产品分类编号
+     */
+    Long createIotProductClassify(IotProductClassifySaveReqVO createReqVO);
+
+    /**
+     * 更新产品分类
+     *
+     * @param updateReqVO 产品分类信息
+     */
+    void updateIotProductClassify(IotProductClassifySaveReqVO updateReqVO);
+
+    /**
+     * 删除产品分类
+     *
+     * @param id 产品分类编号
+     */
+    void deleteIotProductClassify(Long id);
+
+    /**
+     * 获得产品分类信息
+     *
+     * @param id 产品分类编号
+     * @return 产品分类信息
+     */
+    IotProductClassifyDO getIotProductClassify(Long id);
+
+    /**
+     * 获得产品分类信息数组
+     *
+     * @param ids 产品分类编号数组
+     * @return 产品分类信息数组
+     */
+    List<IotProductClassifyDO> getIotProductClassifyList(Collection<Long> ids);
+
+    /**
+     * 筛选产品分类列表
+     *
+     * @param reqVO 筛选条件请求 VO
+     * @return 产品分类列表
+     */
+    List<IotProductClassifyDO> getIotProductClassifyList(IotProductClassifyListReqVO reqVO);
+
+    /**
+     * 获得指定编号的产品分类 Map
+     *
+     * @param ids 产品分类编号数组
+     * @return 产品分类 Map
+     */
+    default Map<Long, IotProductClassifyDO> getIotProductClassifyMap(Collection<Long> ids) {
+        List<IotProductClassifyDO> list = getIotProductClassifyList(ids);
+        return CollectionUtils.convertMap(list, IotProductClassifyDO::getId);
+    }
+
+    /**
+     * 获得指定产品分类的所有子产品分类
+     *
+     * @param id 产品分类编号
+     * @return 子产品分类列表
+     */
+    default List<IotProductClassifyDO> getChildIotProductClassifyList(Long id) {
+        return getChildIotProductClassifyList(Collections.singleton(id));
+    }
+
+    /**
+     * 获得指定产品分类的所有子产品分类
+     *
+     * @param ids 产品分类编号数组
+     * @return 子产品分类列表
+     */
+    List<IotProductClassifyDO> getChildIotProductClassifyList(Collection<Long> ids);
+
+//    /**
+//     * 获得指定领导者的产品分类列表
+//     *
+//     * @param id 领导者编号
+//     * @return 产品分类列表
+//     */
+//    List<IotProductClassifyDO> getIotProductClassifyListByLeaderUserId(Long id);
+//
+//    /**
+//     * 获得所有子产品分类,从缓存中
+//     *
+//     * @param id 父产品分类编号
+//     * @return 子产品分类列表
+//     */
+//    Set<Long> getChildIotProductClassifyIdListFromCache(Long id);
+//
+//    /**
+//     * 校验产品分类们是否有效。如下情况,视为无效:
+//     * 1. 产品分类编号不存在
+//     * 2. 产品分类被禁用
+//     *
+//     * @param ids 角色编号数组
+//     */
+//    void validateIotProductClassifyList(Collection<Long> ids);
+
+}

+ 180 - 0
yudao-module-pms/yudao-module-pms-biz/src/main/java/cn/iocoder/yudao/module/pms/service/IotProductClassifyServiceImpl.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.IotProductClassifyListReqVO;
+import cn.iocoder.yudao.module.pms.controller.admin.vo.IotProductClassifySaveReqVO;
+import cn.iocoder.yudao.module.pms.dal.dataobject.IotProductClassifyDO;
+import cn.iocoder.yudao.module.pms.dal.mysql.IotProductClassifyMapper;
+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 IotProductClassifyServiceImpl implements IotProductClassifyService {
+
+    @Resource
+    private IotProductClassifyMapper iotProductClassifyMapper;
+
+    @Override
+    public Long createIotProductClassify(IotProductClassifySaveReqVO createReqVO) {
+        if (createReqVO.getParentId() == null) {
+            createReqVO.setParentId(IotProductClassifyDO.PARENT_ID_ROOT);
+        }
+        // 校验父产品分类的有效性
+        validateParentProductClassify(null, createReqVO.getParentId());
+        // 校验产品分类名的唯一性
+        validateProductClassifyNameUnique(null, createReqVO.getParentId(), createReqVO.getName());
+
+        // 插入产品分类
+        IotProductClassifyDO dept = BeanUtils.toBean(createReqVO, IotProductClassifyDO.class);
+        iotProductClassifyMapper.insert(dept);
+        return dept.getId();
+    }
+
+    @Override
+    public void updateIotProductClassify(IotProductClassifySaveReqVO updateReqVO) {
+        if (updateReqVO.getParentId() == null) {
+            updateReqVO.setParentId(IotProductClassifyDO.PARENT_ID_ROOT);
+        }
+        // 校验自己存在
+        validateIotProductClassifyExists(updateReqVO.getId());
+        // 校验父产品分类的有效性
+        validateParentProductClassify(updateReqVO.getId(), updateReqVO.getParentId());
+        // 校验产品分类名的唯一性
+        validateProductClassifyNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName());
+
+        // 更新产品分类
+        IotProductClassifyDO updateObj = BeanUtils.toBean(updateReqVO, IotProductClassifyDO.class);
+        iotProductClassifyMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteIotProductClassify(Long id) {
+        // 校验是否存在
+        validateIotProductClassifyExists(id);
+        // 校验是否有子产品分类
+        if (iotProductClassifyMapper.selectCountByParentId(id) > 0) {
+            throw exception(DEPT_EXITS_CHILDREN);
+        }
+        // 删除产品分类
+        iotProductClassifyMapper.deleteById(id);
+    }
+
+    @VisibleForTesting
+    void validateIotProductClassifyExists(Long id) {
+        if (id == null) {
+            return;
+        }
+        IotProductClassifyDO dept = iotProductClassifyMapper.selectById(id);
+        if (dept == null) {
+            throw exception(DEPT_NOT_FOUND);
+        }
+    }
+
+    @VisibleForTesting
+    void validateParentProductClassify(Long id, Long parentId) {
+        if (parentId == null || IotProductClassifyDO.PARENT_ID_ROOT.equals(parentId)) {
+            return;
+        }
+        // 1. 不能设置自己为父产品分类
+        if (Objects.equals(id, parentId)) {
+            throw exception(DEPT_PARENT_ERROR);
+        }
+        // 2. 父产品分类不存在
+        IotProductClassifyDO parentDept = iotProductClassifyMapper.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 || IotProductClassifyDO.PARENT_ID_ROOT.equals(parentId)) {
+                break;
+            }
+            parentDept = iotProductClassifyMapper.selectById(parentId);
+            if (parentDept == null) {
+                break;
+            }
+        }
+    }
+
+    @VisibleForTesting
+    void validateProductClassifyNameUnique(Long id, Long parentId, String name) {
+        IotProductClassifyDO dept = iotProductClassifyMapper.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 IotProductClassifyDO getIotProductClassify(Long id) {
+        return iotProductClassifyMapper.selectById(id);
+    }
+
+    @Override
+    public List<IotProductClassifyDO> getIotProductClassifyList(Collection<Long> ids) {
+        if (CollUtil.isEmpty(ids)) {
+            return Collections.emptyList();
+        }
+        return iotProductClassifyMapper.selectBatchIds(ids);
+    }
+
+    @Override
+    public List<IotProductClassifyDO> getIotProductClassifyList(IotProductClassifyListReqVO reqVO) {
+        List<IotProductClassifyDO> list = iotProductClassifyMapper.selectList(reqVO);
+        list.sort(Comparator.comparing(IotProductClassifyDO::getSort));
+        return list;
+    }
+
+    @Override
+    public List<IotProductClassifyDO> getChildIotProductClassifyList(Collection<Long> ids) {
+        List<IotProductClassifyDO> children = new LinkedList<>();
+        // 遍历每一层
+        Collection<Long> parentIds = ids;
+        for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环
+            // 查询当前层,所有的子产品分类
+            List<IotProductClassifyDO> depts = iotProductClassifyMapper.selectListByParentId(parentIds);
+            // 1. 如果没有子产品分类,则结束遍历
+            if (CollUtil.isEmpty(depts)) {
+                break;
+            }
+            // 2. 如果有子产品分类,继续遍历
+            children.addAll(depts);
+            parentIds = convertSet(depts, IotProductClassifyDO::getId);
+        }
+        return children;
+    }
+
+}

+ 4 - 2
yudao-server/src/main/resources/application-dev.yaml

@@ -58,10 +58,10 @@ spring:
 
   # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
   redis:
-    host: 172.16.101.77 # 地址
+    host: localhost # 地址
     port: 6379 # 端口
     database: 1 # 数据库索引
-#    password: 123456 # 密码,建议生产环境开启
+    password: 123456 # 密码,建议生产环境开启
 
 --- #################### 定时任务相关配置 ####################
 
@@ -181,6 +181,8 @@ wx: # 参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-sta
 
 # 芋道配置项,设置当前项目所有自定义的配置
 yudao:
+  captcha:
+    enable: false
   pay:
     order-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/order # 支付渠道的【支付】回调地址
     refund-notify-url: http://yunai.natapp1.cc/admin-api/pay/notify/refund # 支付渠道的【退款】回调地址

+ 1 - 1
yudao-server/src/main/resources/application-local.yaml

@@ -284,4 +284,4 @@ justauth:
 --- #################### iot相关配置 TODO 芋艿【IOT】:再瞅瞅 ####################
 pf4j:
 #  pluginsDir: /tmp/
-  pluginsDir: ../plugins
+  pluginsDir: ../plugins

+ 2 - 2
yudao-server/src/main/resources/application.yaml

@@ -3,7 +3,7 @@ spring:
     name: yudao-server
 
   profiles:
-    active: local
+    active: dev
 
   main:
     allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
@@ -359,4 +359,4 @@ yudao:
 debug: false
 # 插件配置 TODO 芋艿:【IOT】需要处理下
 pf4j:
-  pluginsDir: /Users/anhaohao/code/gitee/ruoyi-vue-pro/plugins # 插件目录
+  pluginsDir: /Users/anhaohao/code/gitee/ruoyi-vue-pro/plugins # 插件目录