diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java index 109f4b2..cdc25d8 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java @@ -96,35 +96,20 @@ public class IotDeviceController { })); } - // TODO @AI:希望改成“未绑定的”。需要剔除已经绑定,包括自己的; - // TODO @AI:不需要传递 gatewayId; - // TODO @AI:需要分页; - @GetMapping("/bindable-sub-device-list") - @Operation(summary = "获取可绑定到网关的子设备列表") - @Parameter(name = "gatewayId", description = "网关设备编号(可选)", example = "1") + @GetMapping("/unbound-sub-device-page") + @Operation(summary = "获取未绑定网关的子设备分页") @PreAuthorize("@ss.hasPermission('iot:device:query')") - public CommonResult> getBindableSubDeviceList( - @RequestParam(value = "gatewayId", required = false) Long gatewayId) { - List list = deviceService.getBindableSubDeviceList(gatewayId); - if (CollUtil.isEmpty(list)) { - return success(Collections.emptyList()); + public CommonResult> getUnboundSubDevicePage(@Valid IotDevicePageReqVO pageReqVO) { + PageResult pageResult = deviceService.getUnboundSubDevicePage(pageReqVO); + if (CollUtil.isEmpty(pageResult.getList())) { + return success(PageResult.empty()); } // 补充产品名称 Map productMap = convertMap(productService.getProductList(), IotProductDO::getId); - return success(convertList(list, device -> { - // TODO @AI:可以 beanutils 转换么? - IotDeviceRespVO respVO = new IotDeviceRespVO() - .setId(device.getId()) - .setDeviceName(device.getDeviceName()) - .setNickname(device.getNickname()) - .setProductId(device.getProductId()) - .setState(device.getState()) - .setGatewayId(device.getGatewayId()); - MapUtils.findAndThen(productMap, device.getProductId(), - product -> respVO.setProductName(product.getName())); - return respVO; - })); + PageResult result = BeanUtils.toBean(pageResult, IotDeviceRespVO.class, device -> + MapUtils.findAndThen(productMap, device.getProductId(), product -> device.setProductName(product.getName()))); + return success(result); } @PutMapping("/update-group") diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java index 3f9c740..043f487 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java @@ -143,11 +143,13 @@ public class IotProductController { @GetMapping("/simple-list") @Operation(summary = "获取产品的精简信息列表", description = "主要用于前端的下拉选项") - public CommonResult> getProductSimpleList() { - List list = productService.getProductList(); - return success(convertList(list, product -> // 只返回 id、name 字段 + @Parameter(name = "deviceType", description = "设备类型", example = "1") + public CommonResult> getProductSimpleList( + @RequestParam(value = "deviceType", required = false) Integer deviceType) { + List list = productService.getProductList(deviceType); + return success(convertList(list, product -> // 只返回 id、name、productKey 字段 new IotProductRespVO().setId(product.getId()).setName(product.getName()).setStatus(product.getStatus()) - .setDeviceType(product.getDeviceType()))); + .setDeviceType(product.getDeviceType()).setProductKey(product.getProductKey()))); } } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java index da1f5dd..c61acf9 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.iot.controller.admin.device.vo.device.IotDevicePageReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO; +import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import jakarta.annotation.Nullable; import org.apache.ibatis.annotations.Mapper; @@ -142,20 +143,20 @@ public interface IotDeviceMapper extends BaseMapperX { } /** - * 查询可绑定到网关的子设备列表 - *

- * 条件:设备类型为 GATEWAY_SUB 且未绑定任何网关,或已绑定到指定网关 + * 分页查询未绑定网关的子设备 * - * @param gatewayId 网关设备编号(可选,用于包含已绑定到该网关的设备) - * @return 子设备列表 + * @param reqVO 分页查询参数 + * @return 子设备分页 */ - default List selectBindableSubDeviceList(@Nullable Long gatewayId) { - return selectList(new LambdaQueryWrapperX() - .eq(IotDeviceDO::getDeviceType, cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum.GATEWAY_SUB.getType()) - .and(wrapper -> wrapper - .isNull(IotDeviceDO::getGatewayId))); -// .or() -// .eqIfPresent(IotDeviceDO::getGatewayId, gatewayId))) + default PageResult selectUnboundSubDevicePage(IotDevicePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotDeviceDO::getDeviceName, reqVO.getDeviceName()) + .likeIfPresent(IotDeviceDO::getNickname, reqVO.getNickname()) + .eqIfPresent(IotDeviceDO::getProductId, reqVO.getProductId()) + // 仅查询子设备 + 未绑定网关 + .eq(IotDeviceDO::getDeviceType, IotProductDeviceTypeEnum.GATEWAY_SUB.getType()) + .isNull(IotDeviceDO::getGatewayId) + .orderByDesc(IotDeviceDO::getId)); } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java index 5ba4a81..2ed27db 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java @@ -27,6 +27,12 @@ public interface IotProductMapper extends BaseMapperX { .orderByDesc(IotProductDO::getId)); } + default List selectList(Integer deviceType) { + return selectList(new LambdaQueryWrapperX() + .eqIfPresent(IotProductDO::getDeviceType, deviceType) + .orderByDesc(IotProductDO::getId)); + } + default IotProductDO selectByProductKey(String productKey) { return selectOne(new LambdaQueryWrapper() .apply("LOWER(product_key) = {0}", productKey.toLowerCase())); @@ -37,5 +43,4 @@ public interface IotProductMapper extends BaseMapperX { .geIfPresent(IotProductDO::getCreateTime, createTime)); } - } \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java index f94ce9a..8c5345d 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/ErrorCodeConstants.java @@ -26,19 +26,15 @@ public interface ErrorCodeConstants { // ========== 设备 1-050-003-000 ============ ErrorCode DEVICE_NOT_EXISTS = new ErrorCode(1_050_003_000, "设备不存在"); ErrorCode DEVICE_NAME_EXISTS = new ErrorCode(1_050_003_001, "设备名称在同一产品下必须唯一"); - ErrorCode DEVICE_HAS_CHILDREN = new ErrorCode(1_050_003_002, "有子设备,不允许删除"); + ErrorCode DEVICE_GATEWAY_HAS_SUB = new ErrorCode(1_050_003_002, "网关设备存在已绑定的子设备,不允许删除"); ErrorCode DEVICE_KEY_EXISTS = new ErrorCode(1_050_003_003, "设备标识已经存在"); ErrorCode DEVICE_GATEWAY_NOT_EXISTS = new ErrorCode(1_050_003_004, "网关设备不存在"); ErrorCode DEVICE_NOT_GATEWAY = new ErrorCode(1_050_003_005, "设备不是网关设备"); ErrorCode DEVICE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_050_003_006, "导入设备数据不能为空!"); ErrorCode DEVICE_DOWNSTREAM_FAILED_SERVER_ID_NULL = new ErrorCode(1_050_003_007, "下行设备消息失败,原因:设备未连接网关"); ErrorCode DEVICE_SERIAL_NUMBER_EXISTS = new ErrorCode(1_050_003_008, "设备序列号已存在,序列号必须全局唯一"); - // TODO @AI:1_050_003_009 需要提示具体的哪个设备。产品/设备,标识下 - ErrorCode DEVICE_NOT_GATEWAY_SUB = new ErrorCode(1_050_003_009, "设备不是网关子设备类型,无法绑定到网关"); - // TODO @AI:1_050_003_009 需要提示具体的哪个设备。产品/设备,标识下 - ErrorCode DEVICE_GATEWAY_BINDTO_EXISTS = new ErrorCode(1_050_003_010, "设备已绑定到其他网关,请先解绑"); - // TODO @AI:是不是可以删除,DEVICE_GATEWAY_BINDTO_NOT_EXISTS - ErrorCode DEVICE_GATEWAY_BINDTO_NOT_EXISTS = new ErrorCode(1_050_003_011, "设备未绑定到任何网关"); + ErrorCode DEVICE_NOT_GATEWAY_SUB = new ErrorCode(1_050_003_009, "设备【{}/{}】不是网关子设备类型,无法绑定到网关"); + ErrorCode DEVICE_GATEWAY_BINDTO_EXISTS = new ErrorCode(1_050_003_010, "设备【{}/{}】已绑定到其他网关,请先解绑"); // ========== 产品分类 1-050-004-000 ========== ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_050_004_000, "产品分类不存在"); diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java index 84bdf8e..5ddc973 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java @@ -73,7 +73,6 @@ public interface IotDeviceService { */ void updateDeviceGroup(@Valid IotDeviceUpdateGroupReqVO updateReqVO); - // TODO @AI:网关设备被删除时,需要查看是否有子设备绑定。如果有,则不允许删除。 /** * 删除单个设备 * @@ -307,14 +306,12 @@ public interface IotDeviceService { void unbindDeviceGateway(Collection ids); /** - * 获取可绑定到网关的子设备列表 - *

- * 条件:设备类型为 GATEWAY_SUB 且未绑定任何网关 + * 获取未绑定网关的子设备分页 * - * @param gatewayId 网关设备编号(可选,用于包含已绑定到该网关的设备) - * @return 子设备列表 + * @param pageReqVO 分页查询参数(仅使用 productId、deviceName、nickname) + * @return 子设备分页 */ - List getBindableSubDeviceList(@Nullable Long gatewayId); + PageResult getUnboundSubDevicePage(IotDevicePageReqVO pageReqVO); /** * 根据网关编号获取子设备列表 @@ -324,13 +321,4 @@ public interface IotDeviceService { */ List getDeviceListByGatewayId(Long gatewayId); - // TODO @AI:暂时用不到,可以删除。 - /** - * 根据网关编号获取子设备数量 - * - * @param gatewayId 网关设备编号 - * @return 子设备数量 - */ - Long getDeviceCountByGatewayId(Long gatewayId); - } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java index f5b0784..b7ca507 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceServiceImpl.java @@ -170,9 +170,10 @@ public class IotDeviceServiceImpl implements IotDeviceService { public void deleteDevice(Long id) { // 1.1 校验存在 IotDeviceDO device = validateDeviceExists(id); - // 1.2 如果是网关设备,检查是否有子设备 - if (device.getGatewayId() != null && deviceMapper.selectCountByGatewayId(id) > 0) { - throw exception(DEVICE_HAS_CHILDREN); + // 1.2 如果是网关设备,检查是否有子设备绑定 + if (IotProductDeviceTypeEnum.isGateway(device.getDeviceType()) + && deviceMapper.selectCountByGatewayId(id) > 0) { + throw exception(DEVICE_GATEWAY_HAS_SUB); } // 2. 删除设备 @@ -193,10 +194,11 @@ public class IotDeviceServiceImpl implements IotDeviceService { if (CollUtil.isEmpty(devices)) { return; } - // 1.2 校验网关设备是否存在 + // 1.2 如果是网关设备,检查是否有子设备绑定 for (IotDeviceDO device : devices) { - if (device.getGatewayId() != null && deviceMapper.selectCountByGatewayId(device.getId()) > 0) { - throw exception(DEVICE_HAS_CHILDREN); + if (IotProductDeviceTypeEnum.isGateway(device.getDeviceType()) + && deviceMapper.selectCountByGatewayId(device.getId()) > 0) { + throw exception(DEVICE_GATEWAY_HAS_SUB); } } @@ -522,34 +524,29 @@ public class IotDeviceServiceImpl implements IotDeviceService { if (CollUtil.isEmpty(ids)) { return; } - // TODO @AI:校验应该是 1.1、1.2 统一风格; - // 1. 校验网关设备存在且类型正确 + // 1.1 校验网关设备存在且类型正确 validateGatewayDeviceExists(gatewayId); - - // 2. 校验并绑定每个子设备 + // 1.2 校验子设备存在 List devices = deviceMapper.selectByIds(ids); if (devices.size() != ids.size()) { throw exception(DEVICE_NOT_EXISTS); } - - List updateList = new ArrayList<>(); + // 1.3 校验每个设备是否可绑定 for (IotDeviceDO device : devices) { - // 2.1 校验是否为子设备类型 if (!IotProductDeviceTypeEnum.isGatewaySub(device.getDeviceType())) { - throw exception(DEVICE_NOT_GATEWAY_SUB); + throw exception(DEVICE_NOT_GATEWAY_SUB, device.getProductKey(), device.getDeviceName()); } - // 2.2 校验是否已绑定其他网关 if (device.getGatewayId() != null && !device.getGatewayId().equals(gatewayId)) { - throw exception(DEVICE_GATEWAY_BINDTO_EXISTS); + throw exception(DEVICE_GATEWAY_BINDTO_EXISTS, device.getProductKey(), device.getDeviceName()); } - updateList.add(new IotDeviceDO().setId(device.getId()).setGatewayId(gatewayId)); } - // 3. 批量更新数据库 - // TODO @AI:List updateList 直接 convertList,不用上面 for 里面搞;校验是校验,插入是插入; + // 2. 批量更新数据库 + List updateList = convertList(devices, device -> + new IotDeviceDO().setId(device.getId()).setGatewayId(gatewayId)); deviceMapper.updateBatch(updateList); - // 4. 清空对应缓存 + // 3. 清空对应缓存 deleteDeviceCache(devices); } @@ -579,8 +576,8 @@ public class IotDeviceServiceImpl implements IotDeviceService { } @Override - public List getBindableSubDeviceList(@Nullable Long gatewayId) { - return deviceMapper.selectBindableSubDeviceList(gatewayId); + public PageResult getUnboundSubDevicePage(IotDevicePageReqVO pageReqVO) { + return deviceMapper.selectUnboundSubDevicePage(pageReqVO); } @Override @@ -588,11 +585,6 @@ public class IotDeviceServiceImpl implements IotDeviceService { return deviceMapper.selectListByGatewayId(gatewayId); } - @Override - public Long getDeviceCountByGatewayId(Long gatewayId) { - return deviceMapper.selectCountByGatewayId(gatewayId); - } - private IotDeviceServiceImpl getSelf() { return SpringUtil.getBean(getClass()); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java index 70e6afd..d4292ef 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java @@ -106,6 +106,14 @@ public interface IotProductService { List getProductList(); /** + * 根据设备类型获得产品列表 + * + * @param deviceType 设备类型(可选) + * @return 产品列表 + */ + List getProductList(@Nullable Integer deviceType); + + /** * 获得产品数量 * * @param createTime 创建时间,如果为空,则统计所有产品数量 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java index 151590a..a07d027 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java @@ -158,6 +158,11 @@ public class IotProductServiceImpl implements IotProductService { } @Override + public List getProductList(Integer deviceType) { + return productMapper.selectList(deviceType); + } + + @Override public Long getProductCount(LocalDateTime createTime) { return productMapper.selectCountByCreateTime(createTime); }