Bläddra i källkod

【功能新增】IoT:设备管理界面增加设备分组选择功能

YunaiV 8 månader sedan
förälder
incheckning
b5ac526139
12 ändrade filer med 198 tillägg och 12 borttagningar
  1. 1 1
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java
  2. 88 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceGroupController.java
  3. 4 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java
  4. 5 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java
  5. 3 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupRespVO.java
  6. 1 1
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
  7. 6 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java
  8. 6 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
  9. 41 7
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java
  10. 22 3
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java
  11. 8 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
  12. 13 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java

+ 1 - 1
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java

@@ -35,5 +35,5 @@ public interface ErrorCodeConstants {
 
     // ========== 设备分组 1-050-005-000 ==========
     ErrorCode DEVICE_GROUP_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备分组不存在");
-
+    ErrorCode DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS = new ErrorCode(1_050_005_001, "设备分组下存在设备,不允许删除");
 }

+ 88 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceGroupController.java

@@ -0,0 +1,88 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupPageReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupRespVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupSaveReqVO;
+import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO;
+import cn.iocoder.yudao.module.iot.service.device.IotDeviceGroupService;
+import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+
+@Tag(name = "管理后台 - IoT 设备分组")
+@RestController
+@RequestMapping("/iot/device-group")
+@Validated
+public class IotDeviceGroupController {
+
+    @Resource
+    private IotDeviceGroupService deviceGroupService;
+    @Resource
+    private IotDeviceService deviceService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建设备分组")
+    @PreAuthorize("@ss.hasPermission('iot:device-group:create')")
+    public CommonResult<Long> createDeviceGroup(@Valid @RequestBody IotDeviceGroupSaveReqVO createReqVO) {
+        return success(deviceGroupService.createDeviceGroup(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新设备分组")
+    @PreAuthorize("@ss.hasPermission('iot:device-group:update')")
+    public CommonResult<Boolean> updateDeviceGroup(@Valid @RequestBody IotDeviceGroupSaveReqVO updateReqVO) {
+        deviceGroupService.updateDeviceGroup(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除设备分组")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('iot:device-group:delete')")
+    public CommonResult<Boolean> deleteDeviceGroup(@RequestParam("id") Long id) {
+        deviceGroupService.deleteDeviceGroup(id);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得设备分组")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('iot:device-group:query')")
+    public CommonResult<IotDeviceGroupRespVO> getDeviceGroup(@RequestParam("id") Long id) {
+        IotDeviceGroupDO deviceGroup = deviceGroupService.getDeviceGroup(id);
+        return success(BeanUtils.toBean(deviceGroup, IotDeviceGroupRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得设备分组分页")
+    @PreAuthorize("@ss.hasPermission('iot:device-group:query')")
+    public CommonResult<PageResult<IotDeviceGroupRespVO>> getDeviceGroupPage(@Valid IotDeviceGroupPageReqVO pageReqVO) {
+        PageResult<IotDeviceGroupDO> pageResult = deviceGroupService.getDeviceGroupPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, IotDeviceGroupRespVO.class,
+                group -> group.setDeviceCount(deviceService.getDeviceCountByGroupId(group.getId()))));
+    }
+
+    @GetMapping("/simple-list")
+    @Operation(summary = "获取设备分组的精简信息列表", description = "只包含被开启的分组,主要用于前端的下拉选项")
+    public CommonResult<List<IotDeviceGroupRespVO>> getSimpleDeviceGroupList() {
+        List<IotDeviceGroupDO> list = deviceGroupService.getDeviceGroupListByStatus(CommonStatusEnum.ENABLE.getStatus());
+        return success(convertList(list, group -> // 只返回 id、name 字段
+                new IotDeviceGroupRespVO().setId(group.getId()).setName(group.getName())));
+    }
+
+}

+ 4 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceRespVO.java

@@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
 import java.time.LocalDateTime;
+import java.util.Set;
 
 @Schema(description = "管理后台 - IoT 设备 Response VO")
 @Data
@@ -23,6 +24,9 @@ public class IotDeviceRespVO {
     @ExcelProperty("设备名称备")
     private String deviceName;
 
+    @Schema(description = "设备分组编号数组", example = "1,2")
+    private Set<Long> groupIds;
+
     @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
     @ExcelProperty("产品编号")
     private Long productId;

+ 5 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/device/IotDeviceSaveReqVO.java

@@ -3,6 +3,8 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo.device;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
+import java.util.Set;
+
 @Schema(description = "管理后台 - IoT 设备新增/修改 Request VO")
 @Data
 public class IotDeviceSaveReqVO {
@@ -25,6 +27,9 @@ public class IotDeviceSaveReqVO {
     @Schema(description = "设备图片", example = "https://iocoder.cn/1.png")
     private String picUrl;
 
+    @Schema(description = "设备分组编号数组", example = "1,2")
+    private Set<Long> groupIds;
+
     @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
     private Long productId;
 

+ 3 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/group/IotDeviceGroupRespVO.java

@@ -24,4 +24,7 @@ public class IotDeviceGroupRespVO {
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
     private LocalDateTime createTime;
 
+    @Schema(description = "设备数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+    private Long deviceCount;
+
 }

+ 1 - 1
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java

@@ -57,7 +57,7 @@ public class IotDeviceDO extends BaseDO {
     /**
      * 设备分组编号集合
      *
-     * 关联 TODO 芋艿:
+     * 关联 {@link IotDeviceGroupDO#getId()}
      */
     @TableField(typeHandler = LongSetTypeHandler.class)
     private Set<Long> groupIds;

+ 6 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceGroupMapper.java

@@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGro
 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 /**
  * IoT 设备分组 Mapper
  *
@@ -22,4 +24,8 @@ public interface IotDeviceGroupMapper extends BaseMapperX<IotDeviceGroupDO> {
                 .orderByDesc(IotDeviceGroupDO::getId));
     }
 
+    default List<IotDeviceGroupDO> selectListByStatus(Integer status) {
+        return selectList(IotDeviceGroupDO::getStatus, status);
+    }
+
 }

+ 6 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java

@@ -50,4 +50,10 @@ public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> {
         return selectList(IotDeviceDO::getDeviceType, deviceType);
     }
 
+    default Long selectCountByGroupId(Long groupId) {
+        return selectCount(new LambdaQueryWrapperX<IotDeviceDO>()
+                .apply("FIND_IN_SET(" + groupId + ",group_ids) > 0")
+                .orderByDesc(IotDeviceDO::getId));
+    }
+
 }

+ 41 - 7
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupService.java

@@ -1,11 +1,17 @@
 package cn.iocoder.yudao.module.iot.service.device;
 
+import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupPageReqVO;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.group.IotDeviceGroupSaveReqVO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceGroupDO;
 import jakarta.validation.Valid;
 
+import java.util.Collection;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+
 /**
  * IoT 设备分组 Service 接口
  *
@@ -14,7 +20,7 @@ import jakarta.validation.Valid;
 public interface IotDeviceGroupService {
 
     /**
-     * 创建IoT 设备分组
+     * 创建设备分组
      *
      * @param createReqVO 创建信息
      * @return 编号
@@ -22,33 +28,61 @@ public interface IotDeviceGroupService {
     Long createDeviceGroup(@Valid IotDeviceGroupSaveReqVO createReqVO);
 
     /**
-     * 更新IoT 设备分组
+     * 更新设备分组
      *
      * @param updateReqVO 更新信息
      */
     void updateDeviceGroup(@Valid IotDeviceGroupSaveReqVO updateReqVO);
 
     /**
-     * 删除IoT 设备分组
+     * 删除设备分组
      *
      * @param id 编号
      */
     void deleteDeviceGroup(Long id);
 
     /**
-     * 获得IoT 设备分组
+     * 校验设备分组是否存在
+     *
+     * @param ids 设备分组 ID 数组
+     */
+    default List<IotDeviceGroupDO> validateDeviceGroupExists(Collection<Long> ids) {
+        if (CollUtil.isEmpty(ids)) {
+            return List.of();
+        }
+        return convertList(ids, this::validateDeviceGroupExists);
+    }
+
+    /**
+     * 校验设备分组是否存在
+     *
+     * @param id 设备分组 ID
+     * @return 设备分组
+     */
+    IotDeviceGroupDO validateDeviceGroupExists(Long id);
+
+    /**
+     * 获得设备分组
      *
      * @param id 编号
-     * @return IoT 设备分组
+     * @return 设备分组
      */
     IotDeviceGroupDO getDeviceGroup(Long id);
 
     /**
-     * 获得IoT 设备分组分页
+     * 获得设备分组分页
      *
      * @param pageReqVO 分页查询
-     * @return IoT 设备分组分页
+     * @return 设备分组分页
      */
     PageResult<IotDeviceGroupDO> getDeviceGroupPage(IotDeviceGroupPageReqVO pageReqVO);
 
+    /**
+     * 获得设备分组列表
+     *
+     * @param status 状态
+     * @return 设备分组列表
+     */
+    List<IotDeviceGroupDO> getDeviceGroupListByStatus(Integer status);
+
 }

+ 22 - 3
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceGroupServiceImpl.java

@@ -10,7 +10,10 @@ import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
+import java.util.List;
+
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS;
 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_GROUP_NOT_EXISTS;
 
 /**
@@ -25,6 +28,9 @@ public class IotDeviceGroupServiceImpl implements IotDeviceGroupService {
     @Resource
     private IotDeviceGroupMapper deviceGroupMapper;
 
+    @Resource
+    private IotDeviceService deviceService;
+
     @Override
     public Long createDeviceGroup(IotDeviceGroupSaveReqVO createReqVO) {
         // 插入
@@ -45,16 +51,24 @@ public class IotDeviceGroupServiceImpl implements IotDeviceGroupService {
 
     @Override
     public void deleteDeviceGroup(Long id) {
-        // 校验存在
+        // 1.1 校验存在
         validateDeviceGroupExists(id);
+        // 1.2 校验是否存在设备
+        if (deviceService.getDeviceCountByGroupId(id) > 0) {
+            throw exception(DEVICE_GROUP_DELETE_FAIL_DEVICE_EXISTS);
+        }
+
         // 删除
         deviceGroupMapper.deleteById(id);
     }
 
-    private void validateDeviceGroupExists(Long id) {
-        if (deviceGroupMapper.selectById(id) == null) {
+    @Override
+    public IotDeviceGroupDO validateDeviceGroupExists(Long id) {
+        IotDeviceGroupDO group = deviceGroupMapper.selectById(id);
+        if (group == null) {
             throw exception(DEVICE_GROUP_NOT_EXISTS);
         }
+        return group;
     }
 
     @Override
@@ -67,4 +81,9 @@ public class IotDeviceGroupServiceImpl implements IotDeviceGroupService {
         return deviceGroupMapper.selectPage(pageReqVO);
     }
 
+    @Override
+    public List<IotDeviceGroupDO> getDeviceGroupListByStatus(Integer status) {
+        return deviceGroupMapper.selectListByStatus(status);
+    }
+
 }

+ 8 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java

@@ -78,6 +78,14 @@ public interface IotDeviceService {
      */
     Long getDeviceCountByProductId(Long productId);
 
+    /**
+     * 获得设备数量
+     *
+     * @param groupId 分组编号
+     * @return 设备数量
+     */
+    Long getDeviceCountByGroupId(Long groupId);
+
     /**
      * 根据产品 key 和设备名称,获得设备信息
      *

+ 13 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java

@@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
 import cn.iocoder.yudao.module.iot.service.product.IotProductService;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
@@ -42,6 +43,9 @@ public class IotDeviceServiceImpl implements IotDeviceService {
 
     @Resource
     private IotProductService productService;
+    @Resource
+    @Lazy // 延迟加载,解决循环依赖
+    private IotDeviceGroupService deviceGroupService;
 
     @Override
     public Long createDevice(IotDeviceSaveReqVO createReqVO) {
@@ -63,6 +67,8 @@ public class IotDeviceServiceImpl implements IotDeviceService {
             && createReqVO.getGatewayId() != null) {
             validateGatewayDeviceExists(createReqVO.getGatewayId());
         }
+        // 1.5 校验分组存在
+        deviceGroupService.validateDeviceGroupExists(createReqVO.getGroupIds());
 
         // 2.1 转换 VO 为 DO
         IotDeviceDO device = BeanUtils.toBean(createReqVO, IotDeviceDO.class, o -> {
@@ -90,6 +96,8 @@ public class IotDeviceServiceImpl implements IotDeviceService {
                 && updateReqVO.getGatewayId() != null) {
             validateGatewayDeviceExists(updateReqVO.getGatewayId());
         }
+        // 1.3 校验分组存在
+        deviceGroupService.validateDeviceGroupExists(updateReqVO.getGroupIds());
 
         // 2. 更新到数据库
         IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class);
@@ -182,6 +190,11 @@ public class IotDeviceServiceImpl implements IotDeviceService {
         return deviceMapper.selectCountByProductId(productId);
     }
 
+    @Override
+    public Long getDeviceCountByGroupId(Long groupId) {
+        return deviceMapper.selectCountByGroupId(groupId);
+    }
+
     @Override
     @TenantIgnore
     public IotDeviceDO getDeviceByProductKeyAndDeviceName(String productKey, String deviceName) {