Browse Source

【优化】IOT 设备管理

安浩浩 11 months ago
parent
commit
643e289384
14 changed files with 110 additions and 120 deletions
  1. 3 18
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java
  2. 5 25
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDevicePageReqVO.java
  3. 1 31
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceRespVO.java
  4. 21 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/IotDeviceStatusUpdateReqVO.java
  5. 11 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java
  6. 16 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSimpleRespVO.java
  7. 7 7
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
  8. 0 7
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceMapper.java
  9. 1 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java
  10. 11 25
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java
  11. 2 3
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceService.java
  12. 10 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java
  13. 6 0
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java
  14. 16 4
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java

+ 3 - 18
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceController.java

@@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDevicePageReqVO;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceRespVO;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
 import cn.iocoder.yudao.module.iot.service.device.IotDeviceService;
 import io.swagger.v3.oas.annotations.Operation;
@@ -45,12 +46,9 @@ public class IotDeviceController {
 
     @PutMapping("/update-status")
     @Operation(summary = "更新设备状态")
-    @Parameter(name = "id", description = "编号", required = true)
-    @Parameter(name = "status", description = "状态", required = true, example = "1")
     @PreAuthorize("@ss.hasPermission('iot:device:update')")
-    public CommonResult<Boolean> updateDeviceStatus(@RequestParam("id") Long id,
-                                                    @RequestParam("status") Integer status) {
-        deviceService.updateDeviceStatus(id, status);
+    public CommonResult<Boolean> updateDeviceStatus(@Valid @RequestBody IotDeviceStatusUpdateReqVO updateReqVO) {
+        deviceService.updateDeviceStatus(updateReqVO);
         return success(true);
     }
 
@@ -88,17 +86,4 @@ public class IotDeviceController {
         return success(BeanUtils.toBean(pageResult, IotDeviceRespVO.class));
     }
 
-    @GetMapping("/export-excel")
-    @Operation(summary = "导出设备 Excel")
-    @PreAuthorize("@ss.hasPermission('iot:device:export')")
-    @ApiAccessLog(operateType = EXPORT)
-    public void exportDeviceExcel(@Valid IotDevicePageReqVO pageReqVO,
-                                  HttpServletResponse response) throws IOException {
-        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
-        List<IotDeviceDO> list = deviceService.getDevicePage(pageReqVO).getList();
-        // 导出 Excel
-        ExcelUtils.write(response, "IoT 设备.xls", "数据", IotDeviceRespVO.class,
-                BeanUtils.toBean(list, IotDeviceRespVO.class));
-    }
-
 }

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

@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.validation.InEnum;
 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
+import cn.iocoder.yudao.module.iot.enums.product.IotProductDeviceTypeEnum;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 import lombok.EqualsAndHashCode;
@@ -28,6 +29,9 @@ public class IotDevicePageReqVO extends PageParam {
     @Schema(description = "设备名称", example = "王五")
     private String deviceName;
 
+    @Schema(description = "备注名称", example = "张三")
+    private String nickname;
+
     @Schema(description = "产品编号", example = "26202")
     private Long productId;
 
@@ -35,12 +39,9 @@ public class IotDevicePageReqVO extends PageParam {
     private String productKey;
 
     @Schema(description = "设备类型", example = "1")
-    // TODO @haohao:需要有个设备类型的枚举
+    @InEnum(IotProductDeviceTypeEnum.class)
     private Integer deviceType;
 
-    @Schema(description = "备注名称", example = "张三")
-    private String nickname;
-
     @Schema(description = "网关设备 ID", example = "16380")
     private Long gatewayId;
 
@@ -64,12 +65,6 @@ public class IotDevicePageReqVO extends PageParam {
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] activeTime;
 
-    @Schema(description = "设备的 IP 地址")
-    private String ip;
-
-    @Schema(description = "设备的固件版本")
-    private String firmwareVersion;
-
     @Schema(description = "设备密钥,用于设备认证,需安全存储")
     private String deviceSecret;
 
@@ -85,21 +80,6 @@ public class IotDevicePageReqVO extends PageParam {
     @Schema(description = "认证类型(如一机一密、动态注册)", example = "2")
     private String authType;
 
-    @Schema(description = "设备位置的纬度,范围 -90.000000 ~ 90.000000")
-    private BigDecimal latitude;
-
-    @Schema(description = "设备位置的经度,范围 -180.000000 ~ 180.000000")
-    private BigDecimal longitude;
-
-    @Schema(description = "地区编码,符合国家地区编码标准,关联地区表", example = "16995")
-    private Integer areaId;
-
-    @Schema(description = "设备详细地址")
-    private String address;
-
-    @Schema(description = "设备序列号")
-    private String serialNumber;
-
     @Schema(description = "创建时间")
     @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
     private LocalDateTime[] createTime;

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

@@ -25,7 +25,7 @@ public class IotDeviceRespVO {
     private String deviceName;
 
     @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26202")
-    @ExcelProperty("产品 ID")
+    @ExcelProperty("产品编号")
     private Long productId;
 
     @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
@@ -41,7 +41,6 @@ public class IotDeviceRespVO {
     private String nickname;
 
     @Schema(description = "网关设备 ID", example = "16380")
-    @ExcelProperty("网关设备 ID")
     private Long gatewayId;
 
     @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@@ -64,14 +63,6 @@ public class IotDeviceRespVO {
     @ExcelProperty("设备激活时间")
     private LocalDateTime activeTime;
 
-    @Schema(description = "设备的 IP 地址")
-    @ExcelProperty("设备的 IP 地址")
-    private String ip;
-
-    @Schema(description = "设备的固件版本")
-    @ExcelProperty("设备的固件版本")
-    private String firmwareVersion;
-
     @Schema(description = "设备密钥,用于设备认证")
     @ExcelProperty("设备密钥")
     private String deviceSecret;
@@ -92,27 +83,6 @@ public class IotDeviceRespVO {
     @ExcelProperty("认证类型(如一机一密、动态注册)")
     private String authType;
 
-    // TODO @haohao:经纬度:可能 double 就够啦
-    @Schema(description = "设备位置的纬度,范围")
-    @ExcelProperty("设备位置的纬度")
-    private BigDecimal latitude;
-
-    @Schema(description = "设备位置的经度")
-    @ExcelProperty("设备位置的经度")
-    private BigDecimal longitude;
-
-    @Schema(description = "地区编码", example = "16995")
-    @ExcelProperty("地区编码")
-    private Integer areaId;
-
-    @Schema(description = "设备详细地址")
-    @ExcelProperty("设备详细地址")
-    private String address;
-
-    @Schema(description = "设备序列号")
-    @ExcelProperty("设备序列号")
-    private String serialNumber;
-
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
     @ExcelProperty("创建时间")
     private LocalDateTime createTime;

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

@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.iot.controller.admin.device.vo;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "管理后台 - IoT 设备状态更新 Request VO")
+@Data
+public class IotDeviceStatusUpdateReqVO {
+
+    @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotNull(message = "设备编号不能为空")
+    private Long id;
+
+    @Schema(description = "设备状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    @NotNull(message = "设备状态不能为空")
+    @InEnum(IotDeviceStatusEnum.class)
+    private Integer status;
+}

+ 11 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/IotProductController.java

@@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductPageReqVO;
 import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductRespVO;
 import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSimpleRespVO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
 import cn.iocoder.yudao.module.iot.service.product.IotProductService;
 import io.swagger.v3.oas.annotations.Operation;
@@ -17,6 +18,8 @@ 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;
 
 @Tag(name = "管理后台 - IoT 产品")
@@ -80,4 +83,12 @@ public class IotProductController {
         return success(BeanUtils.toBean(pageResult, IotProductRespVO.class));
     }
 
+    @GetMapping("/list-all-simple")
+    @Operation(summary = "获得所有产品列表")
+    @PreAuthorize("@ss.hasPermission('iot:product:query')")
+    public CommonResult<List<IotProductSimpleRespVO>> listAllSimpleProducts() {
+        List<IotProductDO> list = productService.listAllProducts();
+        return success(BeanUtils.toBean(list, IotProductSimpleRespVO.class));
+    }
+
 }

+ 16 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/product/vo/IotProductSimpleRespVO.java

@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.iot.controller.admin.product.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - IoT 产品 Response VO")
+@Data
+public class IotProductSimpleRespVO {
+
+    @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "26087")
+    private Long id;
+
+    @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+    private String name;
+
+}

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

@@ -50,34 +50,34 @@ public class IotDeviceDO extends BaseDO {
 
     /**
      * 产品编号
-     *
+     * <p>
      * 关联 {@link IotProductDO#getId()}
      */
     private Long productId;
     /**
      * 产品标识
-     *
+     * <p>
      * 冗余 {@link IotProductDO#getProductKey()}
      */
     private String productKey;
     /**
      * 设备类型
-     *
+     * <p>
      * 冗余 {@link IotProductDO#getDeviceType()}
      */
     private Integer deviceType;
 
     /**
      * 设备状态
-     *
+     * <p>
      * 枚举 {@link IotDeviceStatusEnum}
      */
     private Integer status;
     /**
      * 网关设备编号
-     *
+     * <p>
      * 子设备需要关联的网关设备 ID
-     *
+     * <p>
      * 关联 {@link IotDeviceDO#getId()}
      */
     private Long gatewayId;
@@ -140,7 +140,7 @@ public class IotDeviceDO extends BaseDO {
     private BigDecimal longitude;
     /**
      * 地区编码
-     *
+     * <p>
      * 关联 Area 的 id
      */
     private Integer areaId;

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

@@ -29,18 +29,11 @@ public interface IotDeviceMapper extends BaseMapperX<IotDeviceDO> {
                 .betweenIfPresent(IotDeviceDO::getLastOnlineTime, reqVO.getLastOnlineTime())
                 .betweenIfPresent(IotDeviceDO::getLastOfflineTime, reqVO.getLastOfflineTime())
                 .betweenIfPresent(IotDeviceDO::getActiveTime, reqVO.getActiveTime())
-                .eqIfPresent(IotDeviceDO::getIp, reqVO.getIp())
-                .eqIfPresent(IotDeviceDO::getFirmwareVersion, reqVO.getFirmwareVersion())
                 .eqIfPresent(IotDeviceDO::getDeviceSecret, reqVO.getDeviceSecret())
                 .eqIfPresent(IotDeviceDO::getMqttClientId, reqVO.getMqttClientId())
                 .likeIfPresent(IotDeviceDO::getMqttUsername, reqVO.getMqttUsername())
                 .eqIfPresent(IotDeviceDO::getMqttPassword, reqVO.getMqttPassword())
                 .eqIfPresent(IotDeviceDO::getAuthType, reqVO.getAuthType())
-                .eqIfPresent(IotDeviceDO::getLatitude, reqVO.getLatitude())
-                .eqIfPresent(IotDeviceDO::getLongitude, reqVO.getLongitude())
-                .eqIfPresent(IotDeviceDO::getAreaId, reqVO.getAreaId())
-                .eqIfPresent(IotDeviceDO::getAddress, reqVO.getAddress())
-                .eqIfPresent(IotDeviceDO::getSerialNumber, reqVO.getSerialNumber())
                 .betweenIfPresent(IotDeviceDO::getCreateTime, reqVO.getCreateTime())
                 .orderByDesc(IotDeviceDO::getId));
     }

+ 1 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/product/IotProductMapper.java

@@ -25,4 +25,5 @@ public interface IotProductMapper extends BaseMapperX<IotProductDO> {
     default IotProductDO selectByProductKey(String productKey) {
         return selectOne(new LambdaQueryWrapperX<IotProductDO>().eq(IotProductDO::getProductKey, productKey));
     }
+
 }

+ 11 - 25
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/DeviceServiceImpl.java

@@ -6,11 +6,12 @@ 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.IotDevicePageReqVO;
 import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceSaveReqVO;
+import cn.iocoder.yudao.module.iot.controller.admin.device.vo.IotDeviceStatusUpdateReqVO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceDO;
 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
 import cn.iocoder.yudao.module.iot.dal.mysql.device.IotDeviceMapper;
-import cn.iocoder.yudao.module.iot.dal.mysql.product.IotProductMapper;
 import cn.iocoder.yudao.module.iot.enums.device.IotDeviceStatusEnum;
+import cn.iocoder.yudao.module.iot.service.product.IotProductService;
 import jakarta.annotation.Resource;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
@@ -35,9 +36,8 @@ public class DeviceServiceImpl implements IotDeviceService {
 
     @Resource
     private IotDeviceMapper deviceMapper;
-    // TODO @haohao:不直接调用 productmapper,通过 productservice;每一个模型,不直接使用对方的
     @Resource
-    private IotProductMapper productMapper;
+    private IotProductService productService;
 
     /**
      * 创建 IoT 设备
@@ -49,7 +49,7 @@ public class DeviceServiceImpl implements IotDeviceService {
     @Transactional(rollbackFor = Exception.class)
     public Long createDevice(IotDeviceSaveReqVO createReqVO) {
         // 1.1 校验产品是否存在
-        IotProductDO product = productMapper.selectById(createReqVO.getProductId());
+        IotProductDO product = productService.getProduct(createReqVO.getProductId());
         if (product == null) {
             throw exception(PRODUCT_NOT_EXISTS);
         }
@@ -106,8 +106,7 @@ public class DeviceServiceImpl implements IotDeviceService {
      * @return 生成的 deviceSecret
      */
     private String generateDeviceSecret() {
-        // TODO @haohao:return IdUtil.fastSimpleUUID()
-        return UUID.randomUUID().toString().replace("-", "");
+        return IdUtil.fastSimpleUUID();
     }
 
     /**
@@ -147,7 +146,6 @@ public class DeviceServiceImpl implements IotDeviceService {
      * @return 生成的唯一 DeviceName
      */
     private String generateUniqueDeviceName(String productKey) {
-        // TODO @haohao:业务逻辑里,尽量避免 while true。万一 bug = =;虽然这个不会哈。我先改了下
         for (int i = 0; i < Short.MAX_VALUE; i++) {
             String deviceName = IdUtil.fastSimpleUUID().substring(0, 20);
             if (deviceMapper.selectByProductKeyAndDeviceName(productKey, deviceName) != null) {
@@ -161,16 +159,11 @@ public class DeviceServiceImpl implements IotDeviceService {
     @Transactional(rollbackFor = Exception.class)
     public void updateDevice(IotDeviceSaveReqVO updateReqVO) {
         // 校验存在
-        IotDeviceDO existingDevice = validateDeviceExists(updateReqVO.getId());
+        validateDeviceExists(updateReqVO.getId());
 
         // 设备名称 和 产品 ID 不能修改
-        // TODO @haohao:这种,直接设置为 null 就不会更新了。忽略前端的传参
-        if (updateReqVO.getDeviceName() != null && !updateReqVO.getDeviceName().equals(existingDevice.getDeviceName())) {
-            throw exception(DEVICE_NAME_CANNOT_BE_MODIFIED);
-        }
-        if (updateReqVO.getProductId() != null && !updateReqVO.getProductId().equals(existingDevice.getProductId())) {
-            throw exception(DEVICE_PRODUCT_CANNOT_BE_MODIFIED);
-        }
+        updateReqVO.setDeviceName(null);
+        updateReqVO.setProductId(null);
 
         // 更新 DO 对象
         IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class);
@@ -222,19 +215,12 @@ public class DeviceServiceImpl implements IotDeviceService {
     }
 
     @Override
-    public void updateDeviceStatus(Long id, Integer status) {
+    public void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO) {
         // 校验存在
-        validateDeviceExists(id);
-
-        // TODO @haohao:这个可以直接用 swagger 注解哈
-        // 校验状态是否合法
-        if (!IotDeviceStatusEnum.isValidStatus(status)) {
-            throw exception(DEVICE_INVALID_DEVICE_STATUS);
-        }
+        validateDeviceExists(updateReqVO.getId());
 
         // 更新状态和更新时间
-        IotDeviceDO updateObj = new IotDeviceDO().setId(id).setStatus(status)
-                .setStatusLastUpdateTime(LocalDateTime.now());
+        IotDeviceDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceDO.class);
         deviceMapper.updateById(updateObj);
     }
 

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

@@ -53,9 +53,8 @@ public interface IotDeviceService {
     /**
      * 更新设备状态
      *
-     * @param id 编号
-     * @param status 状态
+     * @param updateReqVO 更新信息
      */
-    void updateDeviceStatus(Long id, Integer status);
+    void updateDeviceStatus(IotDeviceStatusUpdateReqVO updateReqVO);
 
 }

+ 10 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductService.java

@@ -6,6 +6,8 @@ import cn.iocoder.yudao.module.iot.controller.admin.product.vo.IotProductSaveReq
 import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;
 import jakarta.validation.Valid;
 
+import java.util.List;
+
 /**
  * IoT 产品 Service 接口
  *
@@ -58,4 +60,12 @@ public interface IotProductService {
      * @param status 状态
      */
     void updateProductStatus(Long id, Integer status);
+
+    /**
+     * 获得所有产品
+     *
+     * @return 产品列表
+     */
+    List<IotProductDO> listAllProducts();
+
 }

+ 6 - 0
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/product/IotProductServiceImpl.java

@@ -12,6 +12,7 @@ import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
+import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
 
@@ -113,4 +114,9 @@ public class IotProductServiceImpl implements IotProductService {
         productMapper.updateById(updateObj);
     }
 
+    @Override
+    public List<IotProductDO> listAllProducts() {
+        return productMapper.selectList();
+    }
+
 }

+ 16 - 4
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java

@@ -24,6 +24,7 @@ import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 
 import java.util.*;
+import java.util.stream.Collectors;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.diffList;
@@ -176,22 +177,33 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe
         List<IotThinkModelFunctionDO> createList = diffResult.get(0); // 需要新增的
         List<IotThinkModelFunctionDO> updateList = diffResult.get(1); // 需要更新的
         List<IotThinkModelFunctionDO> deleteList = diffResult.get(2); // 需要删除的
+
         // 3.2 批量执行数据库操作
+        // 新增数据库中的新事件和服务列表
         if (CollUtil.isNotEmpty(createList)) {
             thinkModelFunctionMapper.insertBatch(createList);
         }
+        // 更新数据库中的事件和服务列表
         if (CollUtil.isNotEmpty(updateList)) {
-            for (IotThinkModelFunctionDO updateFunc : updateList) {
-                // 设置 ID,以便更新
+            // 首先,为每个需要更新的对象设置其对应的 ID
+            updateList.forEach(updateFunc -> {
                 IotThinkModelFunctionDO oldFunc = findFunctionByIdentifierAndType(
                         oldFunctionList, updateFunc.getIdentifier(), updateFunc.getType());
                 if (oldFunc != null) {
                     updateFunc.setId(oldFunc.getId());
-                    thinkModelFunctionMapper.updateById(updateFunc);
                 }
+            });
+            // 过滤掉没有设置 ID 的对象
+            List<IotThinkModelFunctionDO> validUpdateList = updateList.stream()
+                    .filter(func -> func.getId() != null)
+                    .collect(Collectors.toList());
+            // 执行批量更新
+            if (CollUtil.isNotEmpty(validUpdateList)) {
+                thinkModelFunctionMapper.updateBatch(validUpdateList);
             }
-            // TODO @haohao:seckillProductMapper.updateBatch(diffList.get(1)); 可以直接类似这么操作哇?
         }
+
+        // 删除数据库中的旧事件和服务列表
         if (CollUtil.isNotEmpty(deleteList)) {
             Set<Long> idsToDelete = CollectionUtils.convertSet(deleteList, IotThinkModelFunctionDO::getId);
             thinkModelFunctionMapper.deleteByIds(idsToDelete);