From 4c051620b14a7f9fe4649059516abea91330aafc Mon Sep 17 00:00:00 2001 From: puhui999 Date: Mon, 11 Aug 2025 11:53:35 +0800 Subject: [PATCH] refactor:【IoT 物联网】重命名 RuleScene => SceneRule --- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java | 94 ---------------------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotSceneRuleController.java | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleScenePageReqVO.java | 36 ------------------------------------ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneRespVO.java | 35 ----------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneSaveReqVO.java | 40 ---------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneUpdateStatusReqVO.java | 22 ---------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRulePageReqVO.java | 36 ++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleRespVO.java | 35 +++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleSaveReqVO.java | 40 ++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleUpdateStatusReqVO.java | 22 ++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotSceneRuleDO.java | 48 ++++++++++++++++++++++++------------------------ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java | 33 --------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotSceneRuleMapper.java | 33 +++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java | 52 ---------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionOperatorEnum.java | 80 -------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java | 35 ----------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java | 66 ------------------------------------------------------------------ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleActionTypeEnum.java | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleConditionOperatorEnum.java | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleConditionTypeEnum.java | 35 +++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleTriggerTypeEnum.java | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java | 58 ---------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotSceneRuleJob.java | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java | 52 ---------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotSceneRuleMessageHandler.java | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java | 8 ++++---- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java | 106 ---------------------------------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java | 552 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleService.java | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceImpl.java | 552 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java | 6 +++--- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java | 6 +++--- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java | 55 ------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlSceneRuleAction.java | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java | 4 ++-- yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceSimpleTest.java | 211 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceSimpleTest.java | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 37 files changed, 1562 insertions(+), 1563 deletions(-) delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotSceneRuleController.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleScenePageReqVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneRespVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneSaveReqVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneUpdateStatusReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRulePageReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleRespVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleSaveReqVO.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleUpdateStatusReqVO.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotSceneRuleMapper.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionOperatorEnum.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleActionTypeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleConditionOperatorEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleConditionTypeEnum.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleTriggerTypeEnum.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotSceneRuleJob.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotSceneRuleMessageHandler.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleService.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceImpl.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlSceneRuleAction.java delete mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceSimpleTest.java create mode 100644 yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceSimpleTest.java diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java deleted file mode 100644 index fee12bb..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotRuleSceneController.java +++ /dev/null @@ -1,94 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule; - -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.rule.vo.scene.IotRuleScenePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneRespVO; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneUpdateStatusReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; -import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService; -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; - -// TODO @puhui999:SceneRule 方法名,类名等; -@Tag(name = "管理后台 - IoT 场景联动") -@RestController -@RequestMapping("/iot/rule-scene") -@Validated -public class IotRuleSceneController { - - @Resource - private IotRuleSceneService ruleSceneService; - - @PostMapping("/create") - @Operation(summary = "创建场景联动") - @PreAuthorize("@ss.hasPermission('iot:rule-scene:create')") - public CommonResult createRuleScene(@Valid @RequestBody IotRuleSceneSaveReqVO createReqVO) { - return success(ruleSceneService.createRuleScene(createReqVO)); - } - - @PutMapping("/update") - @Operation(summary = "更新场景联动") - @PreAuthorize("@ss.hasPermission('iot:rule-scene:update')") - public CommonResult updateRuleScene(@Valid @RequestBody IotRuleSceneSaveReqVO updateReqVO) { - ruleSceneService.updateRuleScene(updateReqVO); - return success(true); - } - - @PutMapping("/update-status") - @Operation(summary = "更新场景联动状态") - @PreAuthorize("@ss.hasPermission('iot:rule-scene:update')") - public CommonResult updateRuleSceneStatus(@Valid @RequestBody IotRuleSceneUpdateStatusReqVO updateReqVO) { - ruleSceneService.updateRuleSceneStatus(updateReqVO.getId(), updateReqVO.getStatus()); - return success(true); - } - - @DeleteMapping("/delete") - @Operation(summary = "删除场景联动") - @Parameter(name = "id", description = "编号", required = true) - @PreAuthorize("@ss.hasPermission('iot:rule-scene:delete')") - public CommonResult deleteRuleScene(@RequestParam("id") Long id) { - ruleSceneService.deleteRuleScene(id); - return success(true); - } - - @GetMapping("/get") - @Operation(summary = "获得场景联动") - @Parameter(name = "id", description = "编号", required = true, example = "1024") - @PreAuthorize("@ss.hasPermission('iot:rule-scene:query')") - public CommonResult getRuleScene(@RequestParam("id") Long id) { - IotSceneRuleDO ruleScene = ruleSceneService.getRuleScene(id); - return success(BeanUtils.toBean(ruleScene, IotRuleSceneRespVO.class)); - } - - @GetMapping("/page") - @Operation(summary = "获得场景联动分页") - @PreAuthorize("@ss.hasPermission('iot:rule-scene:query')") - public CommonResult> getRuleScenePage(@Valid IotRuleScenePageReqVO pageReqVO) { - PageResult pageResult = ruleSceneService.getRuleScenePage(pageReqVO); - return success(BeanUtils.toBean(pageResult, IotRuleSceneRespVO.class)); - } - - @GetMapping("/simple-list") - @Operation(summary = "获取场景联动的精简信息列表", description = "主要用于前端的下拉选项") - public CommonResult> getRuleSceneSimpleList() { - List list = ruleSceneService.getRuleSceneListByStatus(CommonStatusEnum.ENABLE.getStatus()); - return success(convertList(list, scene -> // 只返回 id、name 字段 - new IotRuleSceneRespVO().setId(scene.getId()).setName(scene.getName()))); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotSceneRuleController.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotSceneRuleController.java new file mode 100644 index 0000000..57d71be --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/IotSceneRuleController.java @@ -0,0 +1,93 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule; + +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.rule.vo.scene.IotSceneRulePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotSceneRuleRespVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotSceneRuleSaveReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotSceneRuleUpdateStatusReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; +import cn.iocoder.yudao.module.iot.service.rule.scene.IotSceneRuleService; +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/scene-rule") +@Validated +public class IotSceneRuleController { + + @Resource + private IotSceneRuleService sceneRuleService; + + @PostMapping("/create") + @Operation(summary = "创建场景联动") + @PreAuthorize("@ss.hasPermission('iot:scene-rule:create')") + public CommonResult createSceneRule(@Valid @RequestBody IotSceneRuleSaveReqVO createReqVO) { + return success(sceneRuleService.createSceneRule(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新场景联动") + @PreAuthorize("@ss.hasPermission('iot:scene-rule:update')") + public CommonResult updateSceneRule(@Valid @RequestBody IotSceneRuleSaveReqVO updateReqVO) { + sceneRuleService.updateSceneRule(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新场景联动状态") + @PreAuthorize("@ss.hasPermission('iot:scene-rule:update')") + public CommonResult updateSceneRuleStatus(@Valid @RequestBody IotSceneRuleUpdateStatusReqVO updateReqVO) { + sceneRuleService.updateSceneRuleStatus(updateReqVO.getId(), updateReqVO.getStatus()); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除场景联动") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('iot:scene-rule:delete')") + public CommonResult deleteSceneRule(@RequestParam("id") Long id) { + sceneRuleService.deleteSceneRule(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得场景联动") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('iot:scene-rule:query')") + public CommonResult getSceneRule(@RequestParam("id") Long id) { + IotSceneRuleDO sceneRule = sceneRuleService.getSceneRule(id); + return success(BeanUtils.toBean(sceneRule, IotSceneRuleRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得场景联动分页") + @PreAuthorize("@ss.hasPermission('iot:scene-rule:query')") + public CommonResult> getSceneRulePage(@Valid IotSceneRulePageReqVO pageReqVO) { + PageResult pageResult = sceneRuleService.getSceneRulePage(pageReqVO); + return success(BeanUtils.toBean(pageResult, IotSceneRuleRespVO.class)); + } + + @GetMapping("/simple-list") + @Operation(summary = "获取场景联动的精简信息列表", description = "主要用于前端的下拉选项") + public CommonResult> getSceneRuleSimpleList() { + List list = sceneRuleService.getSceneRuleListByStatus(CommonStatusEnum.ENABLE.getStatus()); + return success(convertList(list, scene -> // 只返回 id、name 字段 + new IotSceneRuleRespVO().setId(scene.getId()).setName(scene.getName()))); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleScenePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleScenePageReqVO.java deleted file mode 100644 index 66e75b4..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleScenePageReqVO.java +++ /dev/null @@ -1,36 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.pojo.PageParam; -import cn.iocoder.yudao.framework.common.validation.InEnum; -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 = "管理后台 - IoT 场景联动分页 Request VO") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -public class IotRuleScenePageReqVO extends PageParam { - - @Schema(description = "场景名称", example = "赵六") - private String name; - - @Schema(description = "场景描述", example = "你猜") - private String description; - - @Schema(description = "场景状态", example = "1") - @InEnum(CommonStatusEnum.class) - private Integer status; - - @Schema(description = "创建时间") - @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) - private LocalDateTime[] 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/controller/admin/rule/vo/scene/IotRuleSceneRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneRespVO.java deleted file mode 100644 index c42d9ff..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneRespVO.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene; - -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; -import io.swagger.v3.oas.annotations.media.Schema; -import lombok.Data; - -import java.time.LocalDateTime; -import java.util.List; - -@Schema(description = "管理后台 - IoT 场景联动 Response VO") -@Data -public class IotRuleSceneRespVO { - - @Schema(description = "场景编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15865") - private Long id; - - @Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") - private String name; - - @Schema(description = "场景描述", example = "你猜") - private String description; - - @Schema(description = "场景状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") - private Integer status; - - @Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED) - private List triggers; - - @Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED) - private List actions; - - @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDateTime 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/controller/admin/rule/vo/scene/IotRuleSceneSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneSaveReqVO.java deleted file mode 100644 index e6d9c06..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneSaveReqVO.java +++ /dev/null @@ -1,40 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.validation.InEnum; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotEmpty; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -import java.util.List; - -@Schema(description = "管理后台 - IoT 场景联动新增/修改 Request VO") -@Data -public class IotRuleSceneSaveReqVO { - - @Schema(description = "场景编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15865") - private Long id; - - @Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") - @NotEmpty(message = "场景名称不能为空") - private String name; - - @Schema(description = "场景描述", example = "你猜") - private String description; - - @Schema(description = "场景状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") - @NotNull(message = "场景状态不能为空") - @InEnum(CommonStatusEnum.class) - private Integer status; - - @Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED) - @NotEmpty(message = "触发器数组不能为空") - private List triggers; - - @Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED) - @NotEmpty(message = "执行器数组不能为空") - private List actions; - -} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneUpdateStatusReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneUpdateStatusReqVO.java deleted file mode 100644 index 9c98fa0..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotRuleSceneUpdateStatusReqVO.java +++ /dev/null @@ -1,22 +0,0 @@ -package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.validation.InEnum; -import io.swagger.v3.oas.annotations.media.Schema; -import jakarta.validation.constraints.NotNull; -import lombok.Data; - -@Schema(description = "管理后台 - IoT 场景联动更新状态 Request VO") -@Data -public class IotRuleSceneUpdateStatusReqVO { - - @Schema(description = "场景联动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") - @NotNull(message = "场景联动编号不能为空") - private Long id; - - @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") - @NotNull(message = "状态不能为空") - @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") - private Integer status; - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRulePageReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRulePageReqVO.java new file mode 100644 index 0000000..8345004 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRulePageReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.validation.InEnum; +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 = "管理后台 - IoT 场景联动分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class IotSceneRulePageReqVO extends PageParam { + + @Schema(description = "场景名称", example = "赵六") + private String name; + + @Schema(description = "场景描述", example = "你猜") + private String description; + + @Schema(description = "场景状态", example = "1") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] 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/controller/admin/rule/vo/scene/IotSceneRuleRespVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleRespVO.java new file mode 100644 index 0000000..835ef62 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleRespVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene; + +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - IoT 场景联动 Response VO") +@Data +public class IotSceneRuleRespVO { + + @Schema(description = "场景编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15865") + private Long id; + + @Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + private String name; + + @Schema(description = "场景描述", example = "你猜") + private String description; + + @Schema(description = "场景状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List triggers; + + @Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED) + private List actions; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime 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/controller/admin/rule/vo/scene/IotSceneRuleSaveReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleSaveReqVO.java new file mode 100644 index 0000000..4a5f1ed --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleSaveReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; + +@Schema(description = "管理后台 - IoT 场景联动新增/修改 Request VO") +@Data +public class IotSceneRuleSaveReqVO { + + @Schema(description = "场景编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15865") + private Long id; + + @Schema(description = "场景名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @NotEmpty(message = "场景名称不能为空") + private String name; + + @Schema(description = "场景描述", example = "你猜") + private String description; + + @Schema(description = "场景状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2") + @NotNull(message = "场景状态不能为空") + @InEnum(CommonStatusEnum.class) + private Integer status; + + @Schema(description = "触发器数组", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "触发器数组不能为空") + private List triggers; + + @Schema(description = "执行器数组", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "执行器数组不能为空") + private List actions; + +} \ No newline at end of file diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleUpdateStatusReqVO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleUpdateStatusReqVO.java new file mode 100644 index 0000000..ea3721f --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/rule/vo/scene/IotSceneRuleUpdateStatusReqVO.java @@ -0,0 +1,22 @@ +package cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.validation.InEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Schema(description = "管理后台 - IoT 场景联动更新状态 Request VO") +@Data +public class IotSceneRuleUpdateStatusReqVO { + + @Schema(description = "场景联动编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + @NotNull(message = "场景联动编号不能为空") + private Long id; + + @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0") + @NotNull(message = "状态不能为空") + @InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") + private Integer status; + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotSceneRuleDO.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotSceneRuleDO.java index d1bce72..94aa1eb 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotSceneRuleDO.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/rule/IotSceneRuleDO.java @@ -7,10 +7,10 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; 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.dataobject.thingmodel.IotThingModelDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionTypeEnum; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleActionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -79,13 +79,13 @@ public class IotSceneRuleDO extends TenantBaseDO { /** * 场景事件类型 * - * 枚举 {@link IotRuleSceneTriggerTypeEnum} - * 1. {@link IotRuleSceneTriggerTypeEnum#DEVICE_STATE_UPDATE} 时,operator 非空,并且 value 为在线状态 - * 2. {@link IotRuleSceneTriggerTypeEnum#DEVICE_PROPERTY_POST} - * {@link IotRuleSceneTriggerTypeEnum#DEVICE_EVENT_POST} 时,identifier、operator 非空,并且 value 为属性值 - * 3. {@link IotRuleSceneTriggerTypeEnum#DEVICE_EVENT_POST} - * {@link IotRuleSceneTriggerTypeEnum#DEVICE_SERVICE_INVOKE} 时,identifier 非空,但是 operator、value 为空 - * 4. {@link IotRuleSceneTriggerTypeEnum#TIMER} 时,conditions 非空,并且设备无关(无需 productId、deviceId 字段) + * 枚举 {@link IotSceneRuleTriggerTypeEnum} + * 1. {@link IotSceneRuleTriggerTypeEnum#DEVICE_STATE_UPDATE} 时,operator 非空,并且 value 为在线状态 + * 2. {@link IotSceneRuleTriggerTypeEnum#DEVICE_PROPERTY_POST} + * {@link IotSceneRuleTriggerTypeEnum#DEVICE_EVENT_POST} 时,identifier、operator 非空,并且 value 为属性值 + * 3. {@link IotSceneRuleTriggerTypeEnum#DEVICE_EVENT_POST} + * {@link IotSceneRuleTriggerTypeEnum#DEVICE_SERVICE_INVOKE} 时,identifier 非空,但是 operator、value 为空 + * 4. {@link IotSceneRuleTriggerTypeEnum#TIMER} 时,conditions 非空,并且设备无关(无需 productId、deviceId 字段) */ private Integer type; @@ -111,14 +111,14 @@ public class IotSceneRuleDO extends TenantBaseDO { /** * 操作符 * - * 枚举 {@link IotRuleSceneConditionOperatorEnum} + * 枚举 {@link IotSceneRuleConditionOperatorEnum} */ private String operator; /** * 参数(属性值、在线状态) *

* 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。 - * 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN} + * 例如说,{@link IotSceneRuleConditionOperatorEnum#IN}、{@link IotSceneRuleConditionOperatorEnum#BETWEEN} */ private String value; @@ -148,10 +148,10 @@ public class IotSceneRuleDO extends TenantBaseDO { /** * 触发条件类型 * - * 枚举 {@link IotRuleSceneConditionTypeEnum} - * 1. {@link IotRuleSceneConditionTypeEnum#DEVICE_STATE} 时,operator 非空,并且 value 为在线状态 - * 2. {@link IotRuleSceneConditionTypeEnum#DEVICE_PROPERTY} 时,identifier、operator 非空,并且 value 为属性值 - * 3. {@link IotRuleSceneConditionTypeEnum#CURRENT_TIME} 时,operator 非空(使用 DATE_TIME_ 和 TIME_ 部分),并且 value 非空 + * 枚举 {@link IotSceneRuleConditionTypeEnum} + * 1. {@link IotSceneRuleConditionTypeEnum#DEVICE_STATE} 时,operator 非空,并且 value 为在线状态 + * 2. {@link IotSceneRuleConditionTypeEnum#DEVICE_PROPERTY} 时,identifier、operator 非空,并且 value 为属性值 + * 3. {@link IotSceneRuleConditionTypeEnum#CURRENT_TIME} 时,operator 非空(使用 DATE_TIME_ 和 TIME_ 部分),并且 value 非空 */ private Integer type; @@ -176,14 +176,14 @@ public class IotSceneRuleDO extends TenantBaseDO { /** * 操作符 * - * 枚举 {@link IotRuleSceneConditionOperatorEnum} + * 枚举 {@link IotSceneRuleConditionOperatorEnum} */ private String operator; /** * 参数 * * 如果有多个值,则使用 "," 分隔,类似 "1,2,3"。 - * 例如说,{@link IotRuleSceneConditionOperatorEnum#IN}、{@link IotRuleSceneConditionOperatorEnum#BETWEEN} + * 例如说,{@link IotSceneRuleConditionOperatorEnum#IN}、{@link IotSceneRuleConditionOperatorEnum#BETWEEN} */ private String param; @@ -198,11 +198,11 @@ public class IotSceneRuleDO extends TenantBaseDO { /** * 执行类型 * - * 枚举 {@link IotRuleSceneActionTypeEnum} - * 1. {@link IotRuleSceneActionTypeEnum#DEVICE_PROPERTY_SET} 时,params 非空 - * {@link IotRuleSceneActionTypeEnum#DEVICE_SERVICE_INVOKE} 时,params 非空 - * 2. {@link IotRuleSceneActionTypeEnum#ALERT_TRIGGER} 时,alertConfigId 为空,因为是 {@link IotAlertConfigDO} 里面关联它 - * 3. {@link IotRuleSceneActionTypeEnum#ALERT_RECOVER} 时,alertConfigId 非空 + * 枚举 {@link IotSceneRuleActionTypeEnum} + * 1. {@link IotSceneRuleActionTypeEnum#DEVICE_PROPERTY_SET} 时,params 非空 + * {@link IotSceneRuleActionTypeEnum#DEVICE_SERVICE_INVOKE} 时,params 非空 + * 2. {@link IotSceneRuleActionTypeEnum#ALERT_TRIGGER} 时,alertConfigId 为空,因为是 {@link IotAlertConfigDO} 里面关联它 + * 3. {@link IotSceneRuleActionTypeEnum#ALERT_RECOVER} 时,alertConfigId 非空 */ private Integer type; diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java deleted file mode 100644 index 9294366..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotRuleSceneMapper.java +++ /dev/null @@ -1,33 +0,0 @@ -package cn.iocoder.yudao.module.iot.dal.mysql.rule; - -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.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; -import org.apache.ibatis.annotations.Mapper; - -import java.util.List; - -/** - * IoT 场景联动 Mapper - * - * @author HUIHUI - */ -@Mapper -public interface IotRuleSceneMapper extends BaseMapperX { - - default PageResult selectPage(IotRuleScenePageReqVO reqVO) { - return selectPage(reqVO, new LambdaQueryWrapperX() - .likeIfPresent(IotSceneRuleDO::getName, reqVO.getName()) - .likeIfPresent(IotSceneRuleDO::getDescription, reqVO.getDescription()) - .eqIfPresent(IotSceneRuleDO::getStatus, reqVO.getStatus()) - .betweenIfPresent(IotSceneRuleDO::getCreateTime, reqVO.getCreateTime()) - .orderByDesc(IotSceneRuleDO::getId)); - } - - default List selectListByStatus(Integer status) { - return selectList(IotSceneRuleDO::getStatus, status); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotSceneRuleMapper.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotSceneRuleMapper.java new file mode 100644 index 0000000..4fd6490 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/rule/IotSceneRuleMapper.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.iot.dal.mysql.rule; + +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.iot.controller.admin.rule.vo.scene.IotSceneRulePageReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * IoT 场景联动 Mapper + * + * @author HUIHUI + */ +@Mapper +public interface IotSceneRuleMapper extends BaseMapperX { + + default PageResult selectPage(IotSceneRulePageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(IotSceneRuleDO::getName, reqVO.getName()) + .likeIfPresent(IotSceneRuleDO::getDescription, reqVO.getDescription()) + .eqIfPresent(IotSceneRuleDO::getStatus, reqVO.getStatus()) + .betweenIfPresent(IotSceneRuleDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(IotSceneRuleDO::getId)); + } + + default List selectListByStatus(Integer status) { + return selectList(IotSceneRuleDO::getStatus, status); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java deleted file mode 100644 index 323592b..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneActionTypeEnum.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.iocoder.yudao.module.iot.enums.rule; - -import cn.iocoder.yudao.framework.common.core.ArrayValuable; -import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.util.Arrays; - -/** - * IoT 规则场景的触发类型枚举 - * - * 设备触发,定时触发 - */ -@RequiredArgsConstructor -@Getter -public enum IotRuleSceneActionTypeEnum implements ArrayValuable { - - /** - * 设备属性设置 - * - * 对应 {@link IotDeviceMessageMethodEnum#PROPERTY_SET} - */ - DEVICE_PROPERTY_SET(1), - /** - * 设备服务调用 - * - * 对应 {@link IotDeviceMessageMethodEnum#SERVICE_INVOKE} - */ - DEVICE_SERVICE_INVOKE(2), - - /** - * 告警触发 - */ - ALERT_TRIGGER(100), - /** - * 告警恢复 - */ - ALERT_RECOVER(101), - - ; - - private final Integer type; - - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneActionTypeEnum::getType).toArray(Integer[]::new); - - @Override - public Integer[] array() { - return ARRAYS; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionOperatorEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionOperatorEnum.java deleted file mode 100644 index f9debc9..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionOperatorEnum.java +++ /dev/null @@ -1,80 +0,0 @@ -package cn.iocoder.yudao.module.iot.enums.rule; - -import cn.hutool.core.util.ArrayUtil; -import cn.iocoder.yudao.framework.common.core.ArrayValuable; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.util.Arrays; - -/** - * IoT 场景触发条件的操作符枚举 - * - * @author 芋道源码 - */ -@RequiredArgsConstructor -@Getter -public enum IotRuleSceneConditionOperatorEnum implements ArrayValuable { - - EQUALS("=", "#source == #value"), - NOT_EQUALS("!=", "!(#source == #value)"), - - GREATER_THAN(">", "#source > #value"), - GREATER_THAN_OR_EQUALS(">=", "#source >= #value"), - - LESS_THAN("<", "#source < #value"), - LESS_THAN_OR_EQUALS("<=", "#source <= #value"), - - IN("in", "#values.contains(#source)"), - NOT_IN("not in", "!(#values.contains(#source))"), - - BETWEEN("between", "(#source >= #values.get(0)) && (#source <= #values.get(1))"), - NOT_BETWEEN("not between", "(#source < #values.get(0)) || (#source > #values.get(1))"), - - LIKE("like", "#source.contains(#value)"), // 字符串匹配 - NOT_NULL("not null", "#source != null && #source.length() > 0"), // 非空 - - // ========== 特殊:不放在字典里 ========== - - // TODO @puhui999:@芋艿:需要测试下 - DATE_TIME_GREATER_THAN("date_time_>", "#source > #value"), // 在时间之后:时间戳 - DATE_TIME_LESS_THAN("date_time_<", "#source < #value"), // 在时间之前:时间戳 - DATE_TIME_BETWEEN("date_time_between", // 在时间之间:时间戳 - "(#source >= #values.get(0)) && (#source <= #values.get(1))"), - - // TODO @puhui999:@芋艿:需要测试下 - TIME_GREATER_THAN("time_>", "#source.isAfter(#value)"), // 在当日时间之后:HH:mm:ss - TIME_LESS_THAN("time_<", "#source.isBefore(#value)"), // 在当日时间之前:HH:mm:ss - TIME_BETWEEN("time_between", // 在当日时间之间:HH:mm:ss - "(#source >= #values.get(0)) && (#source <= #values.get(1))"), - - ; - - private final String operator; - private final String springExpression; - - public static final String[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneConditionOperatorEnum::getOperator).toArray(String[]::new); - - /** - * Spring 表达式 - 原始值 - */ - public static final String SPRING_EXPRESSION_SOURCE = "source"; - /** - * Spring 表达式 - 目标值 - */ - public static final String SPRING_EXPRESSION_VALUE = "value"; - /** - * Spring 表达式 - 目标值数组 - */ - public static final String SPRING_EXPRESSION_VALUE_LIST = "values"; - - public static IotRuleSceneConditionOperatorEnum operatorOf(String operator) { - return ArrayUtil.firstMatch(item -> item.getOperator().equals(operator), values()); - } - - @Override - public String[] array() { - return ARRAYS; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java deleted file mode 100644 index 031976d..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneConditionTypeEnum.java +++ /dev/null @@ -1,35 +0,0 @@ -package cn.iocoder.yudao.module.iot.enums.rule; - -import cn.iocoder.yudao.framework.common.core.ArrayValuable; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.util.Arrays; - -/** - * IoT 条件类型枚举 - * - * @author 芋道源码 - */ -@RequiredArgsConstructor -@Getter -public enum IotRuleSceneConditionTypeEnum implements ArrayValuable { - - DEVICE_STATE(1, "设备状态"), - DEVICE_PROPERTY(2, "设备属性"), - - CURRENT_TIME(100, "当前时间"), - - ; - - private final Integer type; - private final String name; - - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneConditionTypeEnum::getType).toArray(Integer[]::new); - - @Override - public Integer[] array() { - return ARRAYS; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java deleted file mode 100644 index 565ac40..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotRuleSceneTriggerTypeEnum.java +++ /dev/null @@ -1,66 +0,0 @@ -package cn.iocoder.yudao.module.iot.enums.rule; - -import cn.iocoder.yudao.framework.common.core.ArrayValuable; -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -import java.util.Arrays; - -/** - * IoT 场景流转的触发类型枚举 - * - * 为什么不直接使用 IotDeviceMessageMethodEnum 呢? - * 原因是,物模型属性上报,存在批量上报的情况,不只对应一个 method!!! - * - * @author 芋道源码 - */ -@RequiredArgsConstructor -@Getter -public enum IotRuleSceneTriggerTypeEnum implements ArrayValuable { - - @Deprecated - DEVICE(1), // 设备触发 // TODO @puhui999:@芋艿:这个可以作废 - - // TODO @芋艿:后续“对应”部分,要 @下,等包结构梳理完; - /** - * 设备上下线变更 - * - * 对应 IotDeviceMessageMethodEnum.STATE_UPDATE - */ - DEVICE_STATE_UPDATE(1), - /** - * 物模型属性上报 - * - * 对应 IotDeviceMessageMethodEnum.DEVICE_PROPERTY_POST - */ - DEVICE_PROPERTY_POST(2), - /** - * 设备事件上报 - * - * 对应 IotDeviceMessageMethodEnum.DEVICE_EVENT_POST - */ - DEVICE_EVENT_POST(3), - /** - * 设备服务调用 - * - * 对应 IotDeviceMessageMethodEnum.DEVICE_SERVICE_INVOKE - */ - DEVICE_SERVICE_INVOKE(4), - - /** - * 定时触发 - */ - TIMER(100) - - ; - - private final Integer type; - - public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotRuleSceneTriggerTypeEnum::getType).toArray(Integer[]::new); - - @Override - public Integer[] array() { - return ARRAYS; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleActionTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleActionTypeEnum.java new file mode 100644 index 0000000..7e9e4de --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleActionTypeEnum.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.iot.enums.rule; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * IoT 规则场景的触发类型枚举 + * + * 设备触发,定时触发 + */ +@RequiredArgsConstructor +@Getter +public enum IotSceneRuleActionTypeEnum implements ArrayValuable { + + /** + * 设备属性设置 + * + * 对应 {@link IotDeviceMessageMethodEnum#PROPERTY_SET} + */ + DEVICE_PROPERTY_SET(1), + /** + * 设备服务调用 + * + * 对应 {@link IotDeviceMessageMethodEnum#SERVICE_INVOKE} + */ + DEVICE_SERVICE_INVOKE(2), + + /** + * 告警触发 + */ + ALERT_TRIGGER(100), + /** + * 告警恢复 + */ + ALERT_RECOVER(101), + + ; + + private final Integer type; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotSceneRuleActionTypeEnum::getType).toArray(Integer[]::new); + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleConditionOperatorEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleConditionOperatorEnum.java new file mode 100644 index 0000000..9bf90cf --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleConditionOperatorEnum.java @@ -0,0 +1,80 @@ +package cn.iocoder.yudao.module.iot.enums.rule; + +import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * IoT 场景触发条件的操作符枚举 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum IotSceneRuleConditionOperatorEnum implements ArrayValuable { + + EQUALS("=", "#source == #value"), + NOT_EQUALS("!=", "!(#source == #value)"), + + GREATER_THAN(">", "#source > #value"), + GREATER_THAN_OR_EQUALS(">=", "#source >= #value"), + + LESS_THAN("<", "#source < #value"), + LESS_THAN_OR_EQUALS("<=", "#source <= #value"), + + IN("in", "#values.contains(#source)"), + NOT_IN("not in", "!(#values.contains(#source))"), + + BETWEEN("between", "(#source >= #values.get(0)) && (#source <= #values.get(1))"), + NOT_BETWEEN("not between", "(#source < #values.get(0)) || (#source > #values.get(1))"), + + LIKE("like", "#source.contains(#value)"), // 字符串匹配 + NOT_NULL("not null", "#source != null && #source.length() > 0"), // 非空 + + // ========== 特殊:不放在字典里 ========== + + // TODO @puhui999:@芋艿:需要测试下 + DATE_TIME_GREATER_THAN("date_time_>", "#source > #value"), // 在时间之后:时间戳 + DATE_TIME_LESS_THAN("date_time_<", "#source < #value"), // 在时间之前:时间戳 + DATE_TIME_BETWEEN("date_time_between", // 在时间之间:时间戳 + "(#source >= #values.get(0)) && (#source <= #values.get(1))"), + + // TODO @puhui999:@芋艿:需要测试下 + TIME_GREATER_THAN("time_>", "#source.isAfter(#value)"), // 在当日时间之后:HH:mm:ss + TIME_LESS_THAN("time_<", "#source.isBefore(#value)"), // 在当日时间之前:HH:mm:ss + TIME_BETWEEN("time_between", // 在当日时间之间:HH:mm:ss + "(#source >= #values.get(0)) && (#source <= #values.get(1))"), + + ; + + private final String operator; + private final String springExpression; + + public static final String[] ARRAYS = Arrays.stream(values()).map(IotSceneRuleConditionOperatorEnum::getOperator).toArray(String[]::new); + + /** + * Spring 表达式 - 原始值 + */ + public static final String SPRING_EXPRESSION_SOURCE = "source"; + /** + * Spring 表达式 - 目标值 + */ + public static final String SPRING_EXPRESSION_VALUE = "value"; + /** + * Spring 表达式 - 目标值数组 + */ + public static final String SPRING_EXPRESSION_VALUE_LIST = "values"; + + public static IotSceneRuleConditionOperatorEnum operatorOf(String operator) { + return ArrayUtil.firstMatch(item -> item.getOperator().equals(operator), values()); + } + + @Override + public String[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleConditionTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleConditionTypeEnum.java new file mode 100644 index 0000000..69cd589 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleConditionTypeEnum.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.iot.enums.rule; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * IoT 条件类型枚举 + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum IotSceneRuleConditionTypeEnum implements ArrayValuable { + + DEVICE_STATE(1, "设备状态"), + DEVICE_PROPERTY(2, "设备属性"), + + CURRENT_TIME(100, "当前时间"), + + ; + + private final Integer type; + private final String name; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotSceneRuleConditionTypeEnum::getType).toArray(Integer[]::new); + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleTriggerTypeEnum.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleTriggerTypeEnum.java new file mode 100644 index 0000000..5e502b5 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/rule/IotSceneRuleTriggerTypeEnum.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.iot.enums.rule; + +import cn.iocoder.yudao.framework.common.core.ArrayValuable; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; + +/** + * IoT 场景流转的触发类型枚举 + * + * 为什么不直接使用 IotDeviceMessageMethodEnum 呢? + * 原因是,物模型属性上报,存在批量上报的情况,不只对应一个 method!!! + * + * @author 芋道源码 + */ +@RequiredArgsConstructor +@Getter +public enum IotSceneRuleTriggerTypeEnum implements ArrayValuable { + + @Deprecated + DEVICE(1), // 设备触发 // TODO @puhui999:@芋艿:这个可以作废 + + // TODO @芋艿:后续“对应”部分,要 @下,等包结构梳理完; + /** + * 设备上下线变更 + * + * 对应 IotDeviceMessageMethodEnum.STATE_UPDATE + */ + DEVICE_STATE_UPDATE(1), + /** + * 物模型属性上报 + * + * 对应 IotDeviceMessageMethodEnum.DEVICE_PROPERTY_POST + */ + DEVICE_PROPERTY_POST(2), + /** + * 设备事件上报 + * + * 对应 IotDeviceMessageMethodEnum.DEVICE_EVENT_POST + */ + DEVICE_EVENT_POST(3), + /** + * 设备服务调用 + * + * 对应 IotDeviceMessageMethodEnum.DEVICE_SERVICE_INVOKE + */ + DEVICE_SERVICE_INVOKE(4), + + /** + * 定时触发 + */ + TIMER(100) + + ; + + private final Integer type; + + public static final Integer[] ARRAYS = Arrays.stream(values()).map(IotSceneRuleTriggerTypeEnum::getType).toArray(Integer[]::new); + + @Override + public Integer[] array() { + return ARRAYS; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java deleted file mode 100644 index 352162e..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotRuleSceneJob.java +++ /dev/null @@ -1,58 +0,0 @@ -package cn.iocoder.yudao.module.iot.job.rule; - -import cn.hutool.core.map.MapUtil; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; -import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.quartz.JobExecutionContext; -import org.springframework.scheduling.quartz.QuartzJobBean; - -import java.util.Map; - -/** - * IoT 规则场景 Job,用于执行 {@link IotRuleSceneTriggerTypeEnum#TIMER} 类型的规则场景 - * - * @author 芋道源码 - */ -@Slf4j -public class IotRuleSceneJob extends QuartzJobBean { - - /** - * JobData Key - 规则场景编号 - */ - public static final String JOB_DATA_KEY_RULE_SCENE_ID = "ruleSceneId"; - - @Resource - private IotRuleSceneService ruleSceneService; - - @Override - protected void executeInternal(JobExecutionContext context) { - // 获得规则场景编号 - Long ruleSceneId = context.getMergedJobDataMap().getLong(JOB_DATA_KEY_RULE_SCENE_ID); - - // 执行规则场景 - ruleSceneService.executeRuleSceneByTimer(ruleSceneId); - } - - /** - * 创建 JobData Map - * - * @param ruleSceneId 规则场景编号 - * @return JobData Map - */ - public static Map buildJobDataMap(Long ruleSceneId) { - return MapUtil.of(JOB_DATA_KEY_RULE_SCENE_ID, ruleSceneId); - } - - /** - * 创建 Job 名字 - * - * @param ruleSceneId 规则场景编号 - * @return Job 名字 - */ - public static String buildJobName(Long ruleSceneId) { - return String.format("%s_%d", IotRuleSceneJob.class.getSimpleName(), ruleSceneId); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotSceneRuleJob.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotSceneRuleJob.java new file mode 100644 index 0000000..9967ccc --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/job/rule/IotSceneRuleJob.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.iot.job.rule; + +import cn.hutool.core.map.MapUtil; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; +import cn.iocoder.yudao.module.iot.service.rule.scene.IotSceneRuleService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.quartz.JobExecutionContext; +import org.springframework.scheduling.quartz.QuartzJobBean; + +import java.util.Map; + +/** + * IoT 规则场景 Job,用于执行 {@link IotSceneRuleTriggerTypeEnum#TIMER} 类型的规则场景 + * + * @author 芋道源码 + */ +@Slf4j +public class IotSceneRuleJob extends QuartzJobBean { + + /** + * JobData Key - 规则场景编号 + */ + public static final String JOB_DATA_KEY_RULE_SCENE_ID = "sceneRuleId"; + + @Resource + private IotSceneRuleService sceneRuleService; + + @Override + protected void executeInternal(JobExecutionContext context) { + // 获得规则场景编号 + Long sceneRuleId = context.getMergedJobDataMap().getLong(JOB_DATA_KEY_RULE_SCENE_ID); + + // 执行规则场景 + sceneRuleService.executeSceneRuleByTimer(sceneRuleId); + } + + /** + * 创建 JobData Map + * + * @param sceneRuleId 规则场景编号 + * @return JobData Map + */ + public static Map buildJobDataMap(Long sceneRuleId) { + return MapUtil.of(JOB_DATA_KEY_RULE_SCENE_ID, sceneRuleId); + } + + /** + * 创建 Job 名字 + * + * @param sceneRuleId 规则场景编号 + * @return Job 名字 + */ + public static String buildJobName(Long sceneRuleId) { + return String.format("%s_%d", IotSceneRuleJob.class.getSimpleName(), sceneRuleId); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java deleted file mode 100644 index 4212a78..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotRuleSceneMessageHandler.java +++ /dev/null @@ -1,52 +0,0 @@ -package cn.iocoder.yudao.module.iot.mq.consumer.rule; - -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService; -import jakarta.annotation.PostConstruct; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -// TODO @puhui999:后面重构哈 -/** - * 针对 {@link IotDeviceMessage} 的消费者,处理规则场景 - * - * @author 芋道源码 - */ -@Component -@Slf4j -public class IotRuleSceneMessageHandler implements IotMessageSubscriber { - - @Resource - private IotRuleSceneService ruleSceneService; - - @Resource - private IotMessageBus messageBus; - - @PostConstruct - public void init() { - messageBus.register(this); - } - - @Override - public String getTopic() { - return IotDeviceMessage.MESSAGE_BUS_DEVICE_MESSAGE_TOPIC; - } - - @Override - public String getGroup() { - return "iot_rule_consumer"; - } - - @Override - public void onMessage(IotDeviceMessage message) { - if (true) { - return; - } - log.info("[onMessage][消息内容({})]", message); - ruleSceneService.executeRuleSceneByDevice(message); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotSceneRuleMessageHandler.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotSceneRuleMessageHandler.java new file mode 100644 index 0000000..c39cefe --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/rule/IotSceneRuleMessageHandler.java @@ -0,0 +1,52 @@ +package cn.iocoder.yudao.module.iot.mq.consumer.rule; + +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus; +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.service.rule.scene.IotSceneRuleService; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +// TODO @puhui999:后面重构哈 +/** + * 针对 {@link IotDeviceMessage} 的消费者,处理规则场景 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class IotSceneRuleMessageHandler implements IotMessageSubscriber { + + @Resource + private IotSceneRuleService sceneRuleService; + + @Resource + private IotMessageBus messageBus; + + @PostConstruct + public void init() { + messageBus.register(this); + } + + @Override + public String getTopic() { + return IotDeviceMessage.MESSAGE_BUS_DEVICE_MESSAGE_TOPIC; + } + + @Override + public String getGroup() { + return "iot_rule_consumer"; + } + + @Override + public void onMessage(IotDeviceMessage message) { + if (true) { + return; + } + log.info("[onMessage][消息内容({})]", message); + sceneRuleService.executeSceneRuleByDevice(message); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java index e03af2f..aa93787 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/alert/IotAlertConfigServiceImpl.java @@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConf import cn.iocoder.yudao.module.iot.controller.admin.alert.vo.config.IotAlertConfigSaveReqVO; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import cn.iocoder.yudao.module.iot.dal.mysql.alert.IotAlertConfigMapper; -import cn.iocoder.yudao.module.iot.service.rule.scene.IotRuleSceneService; +import cn.iocoder.yudao.module.iot.service.rule.scene.IotSceneRuleService; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import jakarta.annotation.Resource; import org.springframework.context.annotation.Lazy; @@ -32,7 +32,7 @@ public class IotAlertConfigServiceImpl implements IotAlertConfigService { @Resource @Lazy // 延迟,避免循环依赖报错 - private IotRuleSceneService ruleSceneService; + private IotSceneRuleService sceneRuleService; @Resource private AdminUserApi adminUserApi; @@ -40,7 +40,7 @@ public class IotAlertConfigServiceImpl implements IotAlertConfigService { @Override public Long createAlertConfig(IotAlertConfigSaveReqVO createReqVO) { // 校验关联数据是否存在 - ruleSceneService.validateRuleSceneList(createReqVO.getSceneRuleIds()); + sceneRuleService.validateSceneRuleList(createReqVO.getSceneRuleIds()); adminUserApi.validateUserList(createReqVO.getReceiveUserIds()); // 插入 @@ -54,7 +54,7 @@ public class IotAlertConfigServiceImpl implements IotAlertConfigService { // 校验存在 validateAlertConfigExists(updateReqVO.getId()); // 校验关联数据是否存在 - ruleSceneService.validateRuleSceneList(updateReqVO.getSceneRuleIds()); + sceneRuleService.validateSceneRuleList(updateReqVO.getSceneRuleIds()); adminUserApi.validateUserList(updateReqVO.getReceiveUserIds()); // 更新 diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java deleted file mode 100644 index 62225e6..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneService.java +++ /dev/null @@ -1,106 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.rule.scene; - -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO; -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; -import jakarta.validation.Valid; - -import java.util.Collection; -import java.util.List; - -/** - * IoT 规则场景规则 Service 接口 - * - * @author 芋道源码 - */ -public interface IotRuleSceneService { - - /** - * 创建场景联动 - * - * @param createReqVO 创建信息 - * @return 编号 - */ - Long createRuleScene(@Valid IotRuleSceneSaveReqVO createReqVO); - - /** - * 更新场景联动 - * - * @param updateReqVO 更新信息 - */ - void updateRuleScene(@Valid IotRuleSceneSaveReqVO updateReqVO); - - /** - * 更新场景联动状态 - * - * @param id 场景联动编号 - * @param status 状态 - */ - void updateRuleSceneStatus(Long id, Integer status); - - /** - * 删除场景联动 - * - * @param id 编号 - */ - void deleteRuleScene(Long id); - - /** - * 获得场景联动 - * - * @param id 编号 - * @return 场景联动 - */ - IotSceneRuleDO getRuleScene(Long id); - - /** - * 获得场景联动分页 - * - * @param pageReqVO 分页查询 - * @return 场景联动分页 - */ - PageResult getRuleScenePage(IotRuleScenePageReqVO pageReqVO); - - /** - * 校验规则场景联动规则编号们是否存在。如下情况,视为无效: - * 1. 规则场景联动规则编号不存在 - * - * @param ids 场景联动规则编号数组 - */ - void validateRuleSceneList(Collection ids); - - /** - * 获得指定状态的场景联动列表 - * - * @param status 状态 - * @return 场景联动列表 - */ - List getRuleSceneListByStatus(Integer status); - - /** - * 【缓存】获得指定设备的场景列表 - * - * @param productKey 产品 Key - * @param deviceName 设备名称 - * @return 场景列表 - */ - List getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName); - - /** - * 基于 {@link IotRuleSceneTriggerTypeEnum#DEVICE} 场景,执行规则场景 - * - * @param message 消息 - */ - void executeRuleSceneByDevice(IotDeviceMessage message); - - /** - * 基于 {@link IotRuleSceneTriggerTypeEnum#TIMER} 场景,执行规则场景 - * - * @param id 场景联动规则编号 - */ - void executeRuleSceneByTimer(Long id); - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java deleted file mode 100644 index 8a03e58..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceImpl.java +++ /dev/null @@ -1,552 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.rule.scene; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.collection.ListUtil; -import cn.hutool.core.map.MapUtil; -import cn.hutool.core.text.CharPool; -import cn.hutool.core.util.NumberUtil; -import cn.hutool.core.util.ObjUtil; -import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.number.NumberUtils; -import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; -import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; -import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; -import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleScenePageReqVO; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO; -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; -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.dataobject.rule.IotSceneRuleDO; -import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotRuleSceneMapper; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionOperatorEnum; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneConditionTypeEnum; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneTriggerTypeEnum; -import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; -import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.product.IotProductService; -import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.validation.annotation.Validated; - -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.RULE_SCENE_NOT_EXISTS; - -/** - * IoT 规则场景 Service 实现类 - * - * @author 芋道源码 - */ -@Service -@Validated -@Slf4j -public class IotRuleSceneServiceImpl implements IotRuleSceneService { - - @Resource - private IotRuleSceneMapper ruleSceneMapper; - - @Resource - private List ruleSceneActions; - - @Resource(name = "iotSchedulerManager") - private IotSchedulerManager schedulerManager; - - @Resource - private IotProductService productService; - - @Resource - private IotDeviceService deviceService; - - @Override - public Long createRuleScene(IotRuleSceneSaveReqVO createReqVO) { - IotSceneRuleDO ruleScene = BeanUtils.toBean(createReqVO, IotSceneRuleDO.class); - ruleSceneMapper.insert(ruleScene); - return ruleScene.getId(); - } - - @Override - public void updateRuleScene(IotRuleSceneSaveReqVO updateReqVO) { - // 校验存在 - validateRuleSceneExists(updateReqVO.getId()); - // 更新 - IotSceneRuleDO updateObj = BeanUtils.toBean(updateReqVO, IotSceneRuleDO.class); - ruleSceneMapper.updateById(updateObj); - } - - @Override - public void updateRuleSceneStatus(Long id, Integer status) { - // 校验存在 - validateRuleSceneExists(id); - // 更新状态 - IotSceneRuleDO updateObj = new IotSceneRuleDO().setId(id).setStatus(status); - ruleSceneMapper.updateById(updateObj); - } - - @Override - public void deleteRuleScene(Long id) { - // 校验存在 - validateRuleSceneExists(id); - // 删除 - ruleSceneMapper.deleteById(id); - } - - private void validateRuleSceneExists(Long id) { - if (ruleSceneMapper.selectById(id) == null) { - throw exception(RULE_SCENE_NOT_EXISTS); - } - } - - @Override - public IotSceneRuleDO getRuleScene(Long id) { - return ruleSceneMapper.selectById(id); - } - - @Override - public PageResult getRuleScenePage(IotRuleScenePageReqVO pageReqVO) { - return ruleSceneMapper.selectPage(pageReqVO); - } - - @Override - public void validateRuleSceneList(Collection ids) { - if (CollUtil.isEmpty(ids)) { - return; - } - // 批量查询存在的规则场景 - List existingScenes = ruleSceneMapper.selectByIds(ids); - if (existingScenes.size() != ids.size()) { - throw exception(RULE_SCENE_NOT_EXISTS); - } - } - - @Override - public List getRuleSceneListByStatus(Integer status) { - return ruleSceneMapper.selectListByStatus(status); - } - - // TODO 芋艿,缓存待实现 - @Override - @TenantIgnore // 忽略租户隔离:因为 IotRuleSceneMessageHandler 调用时,一般未传递租户,所以需要忽略 - public List getRuleSceneListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) { - // TODO @puhui999:一些注释,看看要不要优化下; - // 注意:旧的测试代码已删除,因为使用了废弃的数据结构 - // 如需测试,请使用上面的新结构测试代码示例 - List list = ruleSceneMapper.selectList(); - // 只返回启用状态的规则场景 - List enabledList = filterList(list, - ruleScene -> CommonStatusEnum.ENABLE.getStatus().equals(ruleScene.getStatus())); - - // 根据 productKey 和 deviceName 进行匹配 - return filterList(enabledList, ruleScene -> { - if (CollUtil.isEmpty(ruleScene.getTriggers())) { - return false; - } - - for (IotSceneRuleDO.Trigger trigger : ruleScene.getTriggers()) { - // 检查触发器是否匹配指定的产品和设备 - if (isMatchProductAndDevice(trigger, productKey, deviceName)) { - return true; - } - } - return false; - }); - } - - /** - * 检查触发器是否匹配指定的产品和设备 - * - * @param trigger 触发器 - * @param productKey 产品标识 - * @param deviceName 设备名称 - * @return 是否匹配 - */ - private boolean isMatchProductAndDevice(IotSceneRuleDO.Trigger trigger, String productKey, String deviceName) { - try { - // 1. 检查产品是否匹配 - if (trigger.getProductId() != null) { - // 通过 productKey 获取产品信息 - IotProductDO product = productService.getProductByProductKey(productKey); - if (product == null || !trigger.getProductId().equals(product.getId())) { - return false; - } - } - - // 2. 检查设备是否匹配 - if (trigger.getDeviceId() != null) { - // 通过 productKey 和 deviceName 获取设备信息 - IotDeviceDO device = deviceService.getDeviceFromCache(productKey, deviceName); - if (device == null) { - return false; - } - - // 检查是否是全部设备的特殊标识 - if (IotDeviceDO.DEVICE_ID_ALL.equals(trigger.getDeviceId())) { - return true; // 匹配所有设备 - } - - // 检查具体设备ID是否匹配 - if (!trigger.getDeviceId().equals(device.getId())) { - return false; - } - } - - return true; - } catch (Exception e) { - log.warn("[isMatchProductAndDevice][产品({}) 设备({}) 匹配触发器异常]", productKey, deviceName, e); - return false; - } - } - - @Override - public void executeRuleSceneByDevice(IotDeviceMessage message) { - // TODO @芋艿:这里的 tenantId,通过设备获取; - TenantUtils.execute(message.getTenantId(), () -> { - // 1. 获得设备匹配的规则场景 - List ruleScenes = getMatchedRuleSceneListByMessage(message); - if (CollUtil.isEmpty(ruleScenes)) { - return; - } - - // 2. 执行规则场景 - executeRuleSceneAction(message, ruleScenes); - }); - } - - @Override - public void executeRuleSceneByTimer(Long id) { - // 1.1 获得规则场景 - IotSceneRuleDO scene = TenantUtils.executeIgnore(() -> ruleSceneMapper.selectById(id)); - if (scene == null) { - log.error("[executeRuleSceneByTimer][规则场景({}) 不存在]", id); - return; - } - if (CommonStatusEnum.isDisable(scene.getStatus())) { - log.info("[executeRuleSceneByTimer][规则场景({}) 已被禁用]", id); - return; - } - // 1.2 判断是否有定时触发器,避免脏数据 - IotSceneRuleDO.Trigger config = CollUtil.findOne(scene.getTriggers(), - trigger -> ObjUtil.equals(trigger.getType(), IotRuleSceneTriggerTypeEnum.TIMER.getType())); - if (config == null) { - log.error("[executeRuleSceneByTimer][规则场景({}) 不存在定时触发器]", scene); - return; - } - - // 2. 执行规则场景 - TenantUtils.execute(scene.getTenantId(), - () -> executeRuleSceneAction(null, ListUtil.toList(scene))); - } - - /** - * 基于消息,获得匹配的规则场景列表 - * - * @param message 设备消息 - * @return 规则场景列表 - */ - private List getMatchedRuleSceneListByMessage(IotDeviceMessage message) { - // 1. 匹配设备 - // TODO @芋艿:可能需要 getSelf(); 缓存 - // 1.1 通过 deviceId 获取设备信息 - IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId()); - if (device == null) { - log.warn("[getMatchedRuleSceneListByMessage][设备({}) 不存在]", message.getDeviceId()); - return List.of(); - } - - // 1.2 通过 productId 获取产品信息 - IotProductDO product = productService.getProductFromCache(device.getProductId()); - if (product == null) { - log.warn("[getMatchedRuleSceneListByMessage][产品({}) 不存在]", device.getProductId()); - return List.of(); - } - - // 1.3 获取匹配的规则场景 - List ruleScenes = getRuleSceneListByProductKeyAndDeviceNameFromCache( - product.getProductKey(), device.getDeviceName()); - if (CollUtil.isEmpty(ruleScenes)) { - return ruleScenes; - } - - // 2. 匹配 trigger 触发器的条件 - return filterList(ruleScenes, ruleScene -> { - for (IotSceneRuleDO.Trigger trigger : ruleScene.getTriggers()) { - // 2.1 检查触发器类型,根据新的枚举值进行匹配 - // TODO @芋艿:需要根据新的触发器类型枚举进行适配 - // 原来使用 IotRuleSceneTriggerTypeEnum.DEVICE,新结构可能有不同的类型 - - // 2.2 条件分组为空,说明没有匹配的条件,因此不匹配 - if (CollUtil.isEmpty(trigger.getConditionGroups())) { - return false; - } - - // 2.3 检查条件分组:分组与分组之间是"或"的关系,条件与条件之间是"且"的关系 - boolean anyGroupMatched = false; - for (List conditionGroup : trigger.getConditionGroups()) { - if (CollUtil.isEmpty(conditionGroup)) { - continue; - } - - // 检查当前分组中的所有条件是否都匹配(且关系) - boolean allConditionsMatched = true; - for (IotSceneRuleDO.TriggerCondition condition : conditionGroup) { - // TODO @芋艿:这里需要实现具体的条件匹配逻辑 - // 根据新的 TriggerCondition 结构进行匹配 - if (!isTriggerConditionMatched(message, condition, ruleScene, trigger)) { - allConditionsMatched = false; - break; - } - } - - if (allConditionsMatched) { - anyGroupMatched = true; - break; // 有一个分组匹配即可 - } - } - - if (anyGroupMatched) { - log.info("[getMatchedRuleSceneList][消息({}) 匹配到规则场景编号({}) 的触发器({})]", message, ruleScene.getId(), trigger); - return true; - } - } - return false; - }); - } - - /** - * 基于消息,判断触发器的条件是否匹配 - * - * @param message 设备消息 - * @param condition 触发条件 - * @param ruleScene 规则场景(用于日志,无其它作用) - * @param trigger 触发器(用于日志,无其它作用) - * @return 是否匹配 - */ - private boolean isTriggerConditionMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition, - IotSceneRuleDO ruleScene, IotSceneRuleDO.Trigger trigger) { - try { - // 1. 根据条件类型进行匹配 - if (IotRuleSceneConditionTypeEnum.DEVICE_STATE.getType().equals(condition.getType())) { - // 设备状态条件匹配 - return matchDeviceStateCondition(message, condition); - } else if (IotRuleSceneConditionTypeEnum.DEVICE_PROPERTY.getType().equals(condition.getType())) { - // 设备属性条件匹配 - return matchDevicePropertyCondition(message, condition); - } else if (IotRuleSceneConditionTypeEnum.CURRENT_TIME.getType().equals(condition.getType())) { - // 当前时间条件匹配 - return matchCurrentTimeCondition(condition); - } else { - log.warn("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 存在未知的条件类型({})]", - ruleScene.getId(), trigger, condition.getType()); - return false; - } - } catch (Exception e) { - log.error("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 条件匹配异常]", - ruleScene.getId(), trigger, e); - return false; - } - } - - /** - * 匹配设备状态条件 - * - * @param message 设备消息 - * @param condition 触发条件 - * @return 是否匹配 - */ - private boolean matchDeviceStateCondition(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { - // TODO @芋艿:需要根据设备状态进行匹配 - // 这里需要检查消息中的设备状态是否符合条件中定义的状态 - log.debug("[matchDeviceStateCondition][设备状态条件匹配逻辑待实现] condition: {}", condition); - return false; - } - - /** - * 匹配设备属性条件 - * - * @param message 设备消息 - * @param condition 触发条件 - * @return 是否匹配 - */ - private boolean matchDevicePropertyCondition(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { - // 1. 检查标识符是否匹配 - String messageIdentifier = IotDeviceMessageUtils.getIdentifier(message); - if (StrUtil.isBlank(condition.getIdentifier()) || !condition.getIdentifier().equals(messageIdentifier)) { - return false; - } - - // 2. 获取消息中的属性值 - Object messageValue = message.getData(); - if (messageValue == null) { - return false; - } - - // 3. 根据操作符进行匹配 - return evaluateCondition(messageValue, condition.getOperator(), condition.getParam()); - } - - /** - * 匹配当前时间条件 - * - * @param condition 触发条件 - * @return 是否匹配 - */ - private boolean matchCurrentTimeCondition(IotSceneRuleDO.TriggerCondition condition) { - // TODO @芋艿:需要根据当前时间进行匹配 - // 这里需要检查当前时间是否符合条件中定义的时间范围 - log.debug("[matchCurrentTimeCondition][当前时间条件匹配逻辑待实现] condition: {}", condition); - return false; - } - - /** - * 评估条件是否匹配 - * - * @param sourceValue 源值(来自消息) - * @param operator 操作符 - * @param paramValue 参数值(来自条件配置) - * @return 是否匹配 - */ - private boolean evaluateCondition(Object sourceValue, String operator, String paramValue) { - try { - // 1. 校验操作符是否合法 - IotRuleSceneConditionOperatorEnum operatorEnum = IotRuleSceneConditionOperatorEnum.operatorOf(operator); - if (operatorEnum == null) { - log.warn("[evaluateCondition][存在错误的操作符({})]", operator); - return false; - } - - // 2.1 构建 Spring 表达式的变量 - Map springExpressionVariables = MapUtil.builder() - .put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, sourceValue) - .build(); - // 2.2 根据操作符类型处理参数值 - if (StrUtil.isNotBlank(paramValue)) { - // TODO @puhui999:这里是不是在 IotRuleSceneConditionOperatorEnum 加个属性; - if (operatorEnum == IotRuleSceneConditionOperatorEnum.IN - || operatorEnum == IotRuleSceneConditionOperatorEnum.NOT_IN - || operatorEnum == IotRuleSceneConditionOperatorEnum.BETWEEN - || operatorEnum == IotRuleSceneConditionOperatorEnum.NOT_BETWEEN) { - // 处理多值情况 - List paramValues = StrUtil.split(paramValue, CharPool.COMMA); - springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, - convertList(paramValues, NumberUtil::parseDouble)); - } else { - // 处理单值情况 - springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, - NumberUtil.parseDouble(paramValue)); - } - } - - // 3. 计算 Spring 表达式 - return (Boolean) SpringExpressionUtils.parseExpression(operatorEnum.getSpringExpression(), springExpressionVariables); - } catch (Exception e) { - log.error("[evaluateCondition][条件评估异常] sourceValue: {}, operator: {}, paramValue: {}", - sourceValue, operator, paramValue, e); - return false; - } - } - - // TODO @芋艿:【可优化】可以考虑增加下单测,边界太多了。 - - /** - * 判断触发器的条件参数是否匹配 - * - * @param message 设备消息 - * @param condition 触发条件 - * @param ruleScene 规则场景(用于日志,无其它作用) - * @param trigger 触发器(用于日志,无其它作用) - * @return 是否匹配 - */ - @SuppressWarnings({"unchecked", "DataFlowIssue"}) - private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition, - IotSceneRuleDO ruleScene, IotSceneRuleDO.Trigger trigger) { - // 1.1 校验操作符是否合法 - IotRuleSceneConditionOperatorEnum operator = - IotRuleSceneConditionOperatorEnum.operatorOf(condition.getOperator()); - if (operator == null) { - log.error("[isTriggerConditionParameterMatched][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]", - ruleScene.getId(), trigger, condition.getOperator()); - return false; - } - // 1.2 校验消息是否包含对应的值 - String messageValue = MapUtil.getStr((Map) message.getData(), condition.getIdentifier()); - if (messageValue == null) { - return false; - } - - // 2.1 构建 Spring 表达式的变量 - Map springExpressionVariables = new HashMap<>(); - try { - springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, messageValue); - springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, condition.getParam()); - List parameterValues = StrUtil.splitTrim(condition.getParam(), CharPool.COMMA); - springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, parameterValues); - // 特殊:解决数字的比较。因为 Spring 是基于它的 compareTo 方法,对数字的比较存在问题! - if (ObjectUtils.equalsAny(operator, IotRuleSceneConditionOperatorEnum.BETWEEN, - IotRuleSceneConditionOperatorEnum.NOT_BETWEEN, - IotRuleSceneConditionOperatorEnum.GREATER_THAN, - IotRuleSceneConditionOperatorEnum.GREATER_THAN_OR_EQUALS, - IotRuleSceneConditionOperatorEnum.LESS_THAN, - IotRuleSceneConditionOperatorEnum.LESS_THAN_OR_EQUALS) - && NumberUtil.isNumber(messageValue) - && NumberUtils.isAllNumber(parameterValues)) { - springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, - NumberUtil.parseDouble(messageValue)); - springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE, - NumberUtil.parseDouble(condition.getParam())); - springExpressionVariables.put(IotRuleSceneConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, - convertList(parameterValues, NumberUtil::parseDouble)); - } - // 2.2 计算 Spring 表达式 - return (Boolean) SpringExpressionUtils.parseExpression(operator.getSpringExpression(), springExpressionVariables); - } catch (Exception e) { - log.error("[isTriggerConditionParameterMatched][消息({}) 规则场景编号({}) 的触发器({}) 的匹配表达式({}/{}) 计算异常]", - message, ruleScene.getId(), trigger, operator, springExpressionVariables, e); - return false; - } - } - - /** - * 执行规则场景的动作 - * - * @param message 设备消息 - * @param ruleScenes 规则场景列表 - */ - private void executeRuleSceneAction(IotDeviceMessage message, List ruleScenes) { - // 1. 遍历规则场景 - ruleScenes.forEach(ruleScene -> { - // 2. 遍历规则场景的动作 - ruleScene.getActions().forEach(actionConfig -> { - // 3.1 获取对应的动作 Action 数组 - List actions = filterList(ruleSceneActions, - action -> action.getType().getType().equals(actionConfig.getType())); - if (CollUtil.isEmpty(actions)) { - return; - } - // 3.2 执行动作 - actions.forEach(action -> { - try { - action.execute(message, ruleScene, actionConfig); - log.info("[executeRuleSceneAction][消息({}) 规则场景编号({}) 的执行动作({}) 成功]", - message, ruleScene.getId(), actionConfig); - } catch (Exception e) { - log.error("[executeRuleSceneAction][消息({}) 规则场景编号({}) 的执行动作({}) 执行异常]", - message, ruleScene.getId(), actionConfig, e); - } - }); - }); - }); - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleService.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleService.java new file mode 100644 index 0000000..2916848 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleService.java @@ -0,0 +1,106 @@ +package cn.iocoder.yudao.module.iot.service.rule.scene; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotSceneRulePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotSceneRuleSaveReqVO; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; + +/** + * IoT 规则场景规则 Service 接口 + * + * @author 芋道源码 + */ +public interface IotSceneRuleService { + + /** + * 创建场景联动 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createSceneRule(@Valid IotSceneRuleSaveReqVO createReqVO); + + /** + * 更新场景联动 + * + * @param updateReqVO 更新信息 + */ + void updateSceneRule(@Valid IotSceneRuleSaveReqVO updateReqVO); + + /** + * 更新场景联动状态 + * + * @param id 场景联动编号 + * @param status 状态 + */ + void updateSceneRuleStatus(Long id, Integer status); + + /** + * 删除场景联动 + * + * @param id 编号 + */ + void deleteSceneRule(Long id); + + /** + * 获得场景联动 + * + * @param id 编号 + * @return 场景联动 + */ + IotSceneRuleDO getSceneRule(Long id); + + /** + * 获得场景联动分页 + * + * @param pageReqVO 分页查询 + * @return 场景联动分页 + */ + PageResult getSceneRulePage(IotSceneRulePageReqVO pageReqVO); + + /** + * 校验规则场景联动规则编号们是否存在。如下情况,视为无效: + * 1. 规则场景联动规则编号不存在 + * + * @param ids 场景联动规则编号数组 + */ + void validateSceneRuleList(Collection ids); + + /** + * 获得指定状态的场景联动列表 + * + * @param status 状态 + * @return 场景联动列表 + */ + List getSceneRuleListByStatus(Integer status); + + /** + * 【缓存】获得指定设备的场景列表 + * + * @param productKey 产品 Key + * @param deviceName 设备名称 + * @return 场景列表 + */ + List getSceneRuleListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName); + + /** + * 基于 {@link IotSceneRuleTriggerTypeEnum#DEVICE} 场景,执行规则场景 + * + * @param message 消息 + */ + void executeSceneRuleByDevice(IotDeviceMessage message); + + /** + * 基于 {@link IotSceneRuleTriggerTypeEnum#TIMER} 场景,执行规则场景 + * + * @param id 场景联动规则编号 + */ + void executeSceneRuleByTimer(Long id); + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceImpl.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceImpl.java new file mode 100644 index 0000000..39efa79 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceImpl.java @@ -0,0 +1,552 @@ +package cn.iocoder.yudao.module.iot.service.rule.scene; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.ListUtil; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.text.CharPool; +import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.ObjUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.number.NumberUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; +import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils; +import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotSceneRulePageReqVO; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotSceneRuleSaveReqVO; +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils; +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.dataobject.rule.IotSceneRuleDO; +import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotSceneRuleMapper; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionOperatorEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleConditionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleTriggerTypeEnum; +import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.service.product.IotProductService; +import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.filterList; +import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.RULE_SCENE_NOT_EXISTS; + +/** + * IoT 规则场景 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +@Slf4j +public class IotSceneRuleServiceImpl implements IotSceneRuleService { + + @Resource + private IotSceneRuleMapper sceneRuleMapper; + + @Resource + private List sceneRuleActions; + + @Resource(name = "iotSchedulerManager") + private IotSchedulerManager schedulerManager; + + @Resource + private IotProductService productService; + + @Resource + private IotDeviceService deviceService; + + @Override + public Long createSceneRule(IotSceneRuleSaveReqVO createReqVO) { + IotSceneRuleDO sceneRule = BeanUtils.toBean(createReqVO, IotSceneRuleDO.class); + sceneRuleMapper.insert(sceneRule); + return sceneRule.getId(); + } + + @Override + public void updateSceneRule(IotSceneRuleSaveReqVO updateReqVO) { + // 校验存在 + validateSceneRuleExists(updateReqVO.getId()); + // 更新 + IotSceneRuleDO updateObj = BeanUtils.toBean(updateReqVO, IotSceneRuleDO.class); + sceneRuleMapper.updateById(updateObj); + } + + @Override + public void updateSceneRuleStatus(Long id, Integer status) { + // 校验存在 + validateSceneRuleExists(id); + // 更新状态 + IotSceneRuleDO updateObj = new IotSceneRuleDO().setId(id).setStatus(status); + sceneRuleMapper.updateById(updateObj); + } + + @Override + public void deleteSceneRule(Long id) { + // 校验存在 + validateSceneRuleExists(id); + // 删除 + sceneRuleMapper.deleteById(id); + } + + private void validateSceneRuleExists(Long id) { + if (sceneRuleMapper.selectById(id) == null) { + throw exception(RULE_SCENE_NOT_EXISTS); + } + } + + @Override + public IotSceneRuleDO getSceneRule(Long id) { + return sceneRuleMapper.selectById(id); + } + + @Override + public PageResult getSceneRulePage(IotSceneRulePageReqVO pageReqVO) { + return sceneRuleMapper.selectPage(pageReqVO); + } + + @Override + public void validateSceneRuleList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return; + } + // 批量查询存在的规则场景 + List existingScenes = sceneRuleMapper.selectByIds(ids); + if (existingScenes.size() != ids.size()) { + throw exception(RULE_SCENE_NOT_EXISTS); + } + } + + @Override + public List getSceneRuleListByStatus(Integer status) { + return sceneRuleMapper.selectListByStatus(status); + } + + // TODO 芋艿,缓存待实现 + @Override + @TenantIgnore // 忽略租户隔离:因为 IotSceneRuleMessageHandler 调用时,一般未传递租户,所以需要忽略 + public List getSceneRuleListByProductKeyAndDeviceNameFromCache(String productKey, String deviceName) { + // TODO @puhui999:一些注释,看看要不要优化下; + // 注意:旧的测试代码已删除,因为使用了废弃的数据结构 + // 如需测试,请使用上面的新结构测试代码示例 + List list = sceneRuleMapper.selectList(); + // 只返回启用状态的规则场景 + List enabledList = filterList(list, + sceneRule -> CommonStatusEnum.ENABLE.getStatus().equals(sceneRule.getStatus())); + + // 根据 productKey 和 deviceName 进行匹配 + return filterList(enabledList, sceneRule -> { + if (CollUtil.isEmpty(sceneRule.getTriggers())) { + return false; + } + + for (IotSceneRuleDO.Trigger trigger : sceneRule.getTriggers()) { + // 检查触发器是否匹配指定的产品和设备 + if (isMatchProductAndDevice(trigger, productKey, deviceName)) { + return true; + } + } + return false; + }); + } + + /** + * 检查触发器是否匹配指定的产品和设备 + * + * @param trigger 触发器 + * @param productKey 产品标识 + * @param deviceName 设备名称 + * @return 是否匹配 + */ + private boolean isMatchProductAndDevice(IotSceneRuleDO.Trigger trigger, String productKey, String deviceName) { + try { + // 1. 检查产品是否匹配 + if (trigger.getProductId() != null) { + // 通过 productKey 获取产品信息 + IotProductDO product = productService.getProductByProductKey(productKey); + if (product == null || !trigger.getProductId().equals(product.getId())) { + return false; + } + } + + // 2. 检查设备是否匹配 + if (trigger.getDeviceId() != null) { + // 通过 productKey 和 deviceName 获取设备信息 + IotDeviceDO device = deviceService.getDeviceFromCache(productKey, deviceName); + if (device == null) { + return false; + } + + // 检查是否是全部设备的特殊标识 + if (IotDeviceDO.DEVICE_ID_ALL.equals(trigger.getDeviceId())) { + return true; // 匹配所有设备 + } + + // 检查具体设备ID是否匹配 + if (!trigger.getDeviceId().equals(device.getId())) { + return false; + } + } + + return true; + } catch (Exception e) { + log.warn("[isMatchProductAndDevice][产品({}) 设备({}) 匹配触发器异常]", productKey, deviceName, e); + return false; + } + } + + @Override + public void executeSceneRuleByDevice(IotDeviceMessage message) { + // TODO @芋艿:这里的 tenantId,通过设备获取; + TenantUtils.execute(message.getTenantId(), () -> { + // 1. 获得设备匹配的规则场景 + List sceneRules = getMatchedSceneRuleListByMessage(message); + if (CollUtil.isEmpty(sceneRules)) { + return; + } + + // 2. 执行规则场景 + executeSceneRuleAction(message, sceneRules); + }); + } + + @Override + public void executeSceneRuleByTimer(Long id) { + // 1.1 获得规则场景 + IotSceneRuleDO scene = TenantUtils.executeIgnore(() -> sceneRuleMapper.selectById(id)); + if (scene == null) { + log.error("[executeSceneRuleByTimer][规则场景({}) 不存在]", id); + return; + } + if (CommonStatusEnum.isDisable(scene.getStatus())) { + log.info("[executeSceneRuleByTimer][规则场景({}) 已被禁用]", id); + return; + } + // 1.2 判断是否有定时触发器,避免脏数据 + IotSceneRuleDO.Trigger config = CollUtil.findOne(scene.getTriggers(), + trigger -> ObjUtil.equals(trigger.getType(), IotSceneRuleTriggerTypeEnum.TIMER.getType())); + if (config == null) { + log.error("[executeSceneRuleByTimer][规则场景({}) 不存在定时触发器]", scene); + return; + } + + // 2. 执行规则场景 + TenantUtils.execute(scene.getTenantId(), + () -> executeSceneRuleAction(null, ListUtil.toList(scene))); + } + + /** + * 基于消息,获得匹配的规则场景列表 + * + * @param message 设备消息 + * @return 规则场景列表 + */ + private List getMatchedSceneRuleListByMessage(IotDeviceMessage message) { + // 1. 匹配设备 + // TODO @芋艿:可能需要 getSelf(); 缓存 + // 1.1 通过 deviceId 获取设备信息 + IotDeviceDO device = deviceService.getDeviceFromCache(message.getDeviceId()); + if (device == null) { + log.warn("[getMatchedSceneRuleListByMessage][设备({}) 不存在]", message.getDeviceId()); + return List.of(); + } + + // 1.2 通过 productId 获取产品信息 + IotProductDO product = productService.getProductFromCache(device.getProductId()); + if (product == null) { + log.warn("[getMatchedSceneRuleListByMessage][产品({}) 不存在]", device.getProductId()); + return List.of(); + } + + // 1.3 获取匹配的规则场景 + List sceneRules = getSceneRuleListByProductKeyAndDeviceNameFromCache( + product.getProductKey(), device.getDeviceName()); + if (CollUtil.isEmpty(sceneRules)) { + return sceneRules; + } + + // 2. 匹配 trigger 触发器的条件 + return filterList(sceneRules, sceneRule -> { + for (IotSceneRuleDO.Trigger trigger : sceneRule.getTriggers()) { + // 2.1 检查触发器类型,根据新的枚举值进行匹配 + // TODO @芋艿:需要根据新的触发器类型枚举进行适配 + // 原来使用 IotSceneRuleTriggerTypeEnum.DEVICE,新结构可能有不同的类型 + + // 2.2 条件分组为空,说明没有匹配的条件,因此不匹配 + if (CollUtil.isEmpty(trigger.getConditionGroups())) { + return false; + } + + // 2.3 检查条件分组:分组与分组之间是"或"的关系,条件与条件之间是"且"的关系 + boolean anyGroupMatched = false; + for (List conditionGroup : trigger.getConditionGroups()) { + if (CollUtil.isEmpty(conditionGroup)) { + continue; + } + + // 检查当前分组中的所有条件是否都匹配(且关系) + boolean allConditionsMatched = true; + for (IotSceneRuleDO.TriggerCondition condition : conditionGroup) { + // TODO @芋艿:这里需要实现具体的条件匹配逻辑 + // 根据新的 TriggerCondition 结构进行匹配 + if (!isTriggerConditionMatched(message, condition, sceneRule, trigger)) { + allConditionsMatched = false; + break; + } + } + + if (allConditionsMatched) { + anyGroupMatched = true; + break; // 有一个分组匹配即可 + } + } + + if (anyGroupMatched) { + log.info("[getMatchedSceneRuleList][消息({}) 匹配到规则场景编号({}) 的触发器({})]", message, sceneRule.getId(), trigger); + return true; + } + } + return false; + }); + } + + /** + * 基于消息,判断触发器的条件是否匹配 + * + * @param message 设备消息 + * @param condition 触发条件 + * @param sceneRule 规则场景(用于日志,无其它作用) + * @param trigger 触发器(用于日志,无其它作用) + * @return 是否匹配 + */ + private boolean isTriggerConditionMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition, + IotSceneRuleDO sceneRule, IotSceneRuleDO.Trigger trigger) { + try { + // 1. 根据条件类型进行匹配 + if (IotSceneRuleConditionTypeEnum.DEVICE_STATE.getType().equals(condition.getType())) { + // 设备状态条件匹配 + return matchDeviceStateCondition(message, condition); + } else if (IotSceneRuleConditionTypeEnum.DEVICE_PROPERTY.getType().equals(condition.getType())) { + // 设备属性条件匹配 + return matchDevicePropertyCondition(message, condition); + } else if (IotSceneRuleConditionTypeEnum.CURRENT_TIME.getType().equals(condition.getType())) { + // 当前时间条件匹配 + return matchCurrentTimeCondition(condition); + } else { + log.warn("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 存在未知的条件类型({})]", + sceneRule.getId(), trigger, condition.getType()); + return false; + } + } catch (Exception e) { + log.error("[isTriggerConditionMatched][规则场景编号({}) 的触发器({}) 条件匹配异常]", + sceneRule.getId(), trigger, e); + return false; + } + } + + /** + * 匹配设备状态条件 + * + * @param message 设备消息 + * @param condition 触发条件 + * @return 是否匹配 + */ + private boolean matchDeviceStateCondition(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { + // TODO @芋艿:需要根据设备状态进行匹配 + // 这里需要检查消息中的设备状态是否符合条件中定义的状态 + log.debug("[matchDeviceStateCondition][设备状态条件匹配逻辑待实现] condition: {}", condition); + return false; + } + + /** + * 匹配设备属性条件 + * + * @param message 设备消息 + * @param condition 触发条件 + * @return 是否匹配 + */ + private boolean matchDevicePropertyCondition(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition) { + // 1. 检查标识符是否匹配 + String messageIdentifier = IotDeviceMessageUtils.getIdentifier(message); + if (StrUtil.isBlank(condition.getIdentifier()) || !condition.getIdentifier().equals(messageIdentifier)) { + return false; + } + + // 2. 获取消息中的属性值 + Object messageValue = message.getData(); + if (messageValue == null) { + return false; + } + + // 3. 根据操作符进行匹配 + return evaluateCondition(messageValue, condition.getOperator(), condition.getParam()); + } + + /** + * 匹配当前时间条件 + * + * @param condition 触发条件 + * @return 是否匹配 + */ + private boolean matchCurrentTimeCondition(IotSceneRuleDO.TriggerCondition condition) { + // TODO @芋艿:需要根据当前时间进行匹配 + // 这里需要检查当前时间是否符合条件中定义的时间范围 + log.debug("[matchCurrentTimeCondition][当前时间条件匹配逻辑待实现] condition: {}", condition); + return false; + } + + /** + * 评估条件是否匹配 + * + * @param sourceValue 源值(来自消息) + * @param operator 操作符 + * @param paramValue 参数值(来自条件配置) + * @return 是否匹配 + */ + private boolean evaluateCondition(Object sourceValue, String operator, String paramValue) { + try { + // 1. 校验操作符是否合法 + IotSceneRuleConditionOperatorEnum operatorEnum = IotSceneRuleConditionOperatorEnum.operatorOf(operator); + if (operatorEnum == null) { + log.warn("[evaluateCondition][存在错误的操作符({})]", operator); + return false; + } + + // 2.1 构建 Spring 表达式的变量 + Map springExpressionVariables = MapUtil.builder() + .put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, sourceValue) + .build(); + // 2.2 根据操作符类型处理参数值 + if (StrUtil.isNotBlank(paramValue)) { + // TODO @puhui999:这里是不是在 IotSceneRuleConditionOperatorEnum 加个属性; + if (operatorEnum == IotSceneRuleConditionOperatorEnum.IN + || operatorEnum == IotSceneRuleConditionOperatorEnum.NOT_IN + || operatorEnum == IotSceneRuleConditionOperatorEnum.BETWEEN + || operatorEnum == IotSceneRuleConditionOperatorEnum.NOT_BETWEEN) { + // 处理多值情况 + List paramValues = StrUtil.split(paramValue, CharPool.COMMA); + springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, + convertList(paramValues, NumberUtil::parseDouble)); + } else { + // 处理单值情况 + springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE, + NumberUtil.parseDouble(paramValue)); + } + } + + // 3. 计算 Spring 表达式 + return (Boolean) SpringExpressionUtils.parseExpression(operatorEnum.getSpringExpression(), springExpressionVariables); + } catch (Exception e) { + log.error("[evaluateCondition][条件评估异常] sourceValue: {}, operator: {}, paramValue: {}", + sourceValue, operator, paramValue, e); + return false; + } + } + + // TODO @芋艿:【可优化】可以考虑增加下单测,边界太多了。 + + /** + * 判断触发器的条件参数是否匹配 + * + * @param message 设备消息 + * @param condition 触发条件 + * @param sceneRule 规则场景(用于日志,无其它作用) + * @param trigger 触发器(用于日志,无其它作用) + * @return 是否匹配 + */ + @SuppressWarnings({"unchecked", "DataFlowIssue"}) + private boolean isTriggerConditionParameterMatched(IotDeviceMessage message, IotSceneRuleDO.TriggerCondition condition, + IotSceneRuleDO sceneRule, IotSceneRuleDO.Trigger trigger) { + // 1.1 校验操作符是否合法 + IotSceneRuleConditionOperatorEnum operator = + IotSceneRuleConditionOperatorEnum.operatorOf(condition.getOperator()); + if (operator == null) { + log.error("[isTriggerConditionParameterMatched][规则场景编号({}) 的触发器({}) 存在错误的操作符({})]", + sceneRule.getId(), trigger, condition.getOperator()); + return false; + } + // 1.2 校验消息是否包含对应的值 + String messageValue = MapUtil.getStr((Map) message.getData(), condition.getIdentifier()); + if (messageValue == null) { + return false; + } + + // 2.1 构建 Spring 表达式的变量 + Map springExpressionVariables = new HashMap<>(); + try { + springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, messageValue); + springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE, condition.getParam()); + List parameterValues = StrUtil.splitTrim(condition.getParam(), CharPool.COMMA); + springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, parameterValues); + // 特殊:解决数字的比较。因为 Spring 是基于它的 compareTo 方法,对数字的比较存在问题! + if (ObjectUtils.equalsAny(operator, IotSceneRuleConditionOperatorEnum.BETWEEN, + IotSceneRuleConditionOperatorEnum.NOT_BETWEEN, + IotSceneRuleConditionOperatorEnum.GREATER_THAN, + IotSceneRuleConditionOperatorEnum.GREATER_THAN_OR_EQUALS, + IotSceneRuleConditionOperatorEnum.LESS_THAN, + IotSceneRuleConditionOperatorEnum.LESS_THAN_OR_EQUALS) + && NumberUtil.isNumber(messageValue) + && NumberUtils.isAllNumber(parameterValues)) { + springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_SOURCE, + NumberUtil.parseDouble(messageValue)); + springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE, + NumberUtil.parseDouble(condition.getParam())); + springExpressionVariables.put(IotSceneRuleConditionOperatorEnum.SPRING_EXPRESSION_VALUE_LIST, + convertList(parameterValues, NumberUtil::parseDouble)); + } + // 2.2 计算 Spring 表达式 + return (Boolean) SpringExpressionUtils.parseExpression(operator.getSpringExpression(), springExpressionVariables); + } catch (Exception e) { + log.error("[isTriggerConditionParameterMatched][消息({}) 规则场景编号({}) 的触发器({}) 的匹配表达式({}/{}) 计算异常]", + message, sceneRule.getId(), trigger, operator, springExpressionVariables, e); + return false; + } + } + + /** + * 执行规则场景的动作 + * + * @param message 设备消息 + * @param sceneRules 规则场景列表 + */ + private void executeSceneRuleAction(IotDeviceMessage message, List sceneRules) { + // 1. 遍历规则场景 + sceneRules.forEach(sceneRule -> { + // 2. 遍历规则场景的动作 + sceneRule.getActions().forEach(actionConfig -> { + // 3.1 获取对应的动作 Action 数组 + List actions = filterList(sceneRuleActions, + action -> action.getType().getType().equals(actionConfig.getType())); + if (CollUtil.isEmpty(actions)) { + return; + } + // 3.2 执行动作 + actions.forEach(action -> { + try { + action.execute(message, sceneRule, actionConfig); + log.info("[executeSceneRuleAction][消息({}) 规则场景编号({}) 的执行动作({}) 成功]", + message, sceneRule.getId(), actionConfig); + } catch (Exception e) { + log.error("[executeSceneRuleAction][消息({}) 规则场景编号({}) 的执行动作({}) 执行异常]", + message, sceneRule.getId(), actionConfig, e); + } + }); + }); + }); + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java index 10b93cf..851f381 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertRecoverSceneRuleAction.java @@ -5,7 +5,7 @@ import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertRecordDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleActionTypeEnum; import cn.iocoder.yudao.module.iot.service.alert.IotAlertRecordService; import jakarta.annotation.Resource; import org.springframework.stereotype.Component; @@ -42,8 +42,8 @@ public class IotAlertRecoverSceneRuleAction implements IotSceneRuleAction { } @Override - public IotRuleSceneActionTypeEnum getType() { - return IotRuleSceneActionTypeEnum.ALERT_RECOVER; + public IotSceneRuleActionTypeEnum getType() { + return IotSceneRuleActionTypeEnum.ALERT_RECOVER; } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java index a751315..28223db 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotAlertTriggerSceneRuleAction.java @@ -5,7 +5,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.alert.IotAlertConfigDO; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleActionTypeEnum; import cn.iocoder.yudao.module.iot.service.alert.IotAlertConfigService; import cn.iocoder.yudao.module.iot.service.alert.IotAlertRecordService; import cn.iocoder.yudao.module.system.api.mail.MailSendApi; @@ -62,8 +62,8 @@ public class IotAlertTriggerSceneRuleAction implements IotSceneRuleAction { } @Override - public IotRuleSceneActionTypeEnum getType() { - return IotRuleSceneActionTypeEnum.ALERT_TRIGGER; + public IotSceneRuleActionTypeEnum getType() { + return IotSceneRuleActionTypeEnum.ALERT_TRIGGER; } } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java deleted file mode 100644 index 19a7d3c..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlRuleSceneAction.java +++ /dev/null @@ -1,55 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.rule.scene.action; - -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; -import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService; -import jakarta.annotation.Resource; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Component; - -/** - * IoT 设备控制的 {@link IotSceneRuleAction} 实现类 - * - * @author 芋道源码 - */ -@Component -@Slf4j -public class IotDeviceControlRuleSceneAction implements IotSceneRuleAction { - - @Resource - private IotDeviceService deviceService; - @Resource - private IotDeviceMessageService deviceMessageService; - - // TODO @puhui999:这里 - @Override - public void execute(IotDeviceMessage message, - IotSceneRuleDO rule, IotSceneRuleDO.Action actionConfig) { - //IotSceneRuleDO.ActionDeviceControl control = actionConfig.getDeviceControl(); - //Assert.notNull(control, "设备控制配置不能为空"); - //// 遍历每个设备,下发消息 - //control.getDeviceNames().forEach(deviceName -> { - // IotDeviceDO device = deviceService.getDeviceFromCache(control.getProductKey(), deviceName); - // if (device == null) { - // log.error("[execute][message({}) actionConfig({}) 对应的设备不存在]", message, actionConfig); - // return; - // } - // try { - // // TODO @芋艿:@puhui999:这块可能要改,从 type => method - // IotDeviceMessage downstreamMessage = deviceMessageService.sendDeviceMessage(IotDeviceMessage.requestOf( - // control.getType() + control.getIdentifier(), control.getData()).setDeviceId(device.getId())); - // log.info("[execute][message({}) actionConfig({}) 下发消息({})成功]", message, actionConfig, downstreamMessage); - // } catch (Exception e) { - // log.error("[execute][message({}) actionConfig({}) 下发消息失败]", message, actionConfig, e); - // } - //}); - } - - @Override - public IotRuleSceneActionTypeEnum getType() { - return IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET; - } - -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlSceneRuleAction.java new file mode 100644 index 0000000..b71a920 --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotDeviceControlSceneRuleAction.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.iot.service.rule.scene.action; + +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleActionTypeEnum; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.service.device.message.IotDeviceMessageService; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** + * IoT 设备控制的 {@link IotSceneRuleAction} 实现类 + * + * @author 芋道源码 + */ +@Component +@Slf4j +public class IotDeviceControlSceneRuleAction implements IotSceneRuleAction { + + @Resource + private IotDeviceService deviceService; + @Resource + private IotDeviceMessageService deviceMessageService; + + // TODO @puhui999:这里 + @Override + public void execute(IotDeviceMessage message, + IotSceneRuleDO rule, IotSceneRuleDO.Action actionConfig) { + //IotSceneRuleDO.ActionDeviceControl control = actionConfig.getDeviceControl(); + //Assert.notNull(control, "设备控制配置不能为空"); + //// 遍历每个设备,下发消息 + //control.getDeviceNames().forEach(deviceName -> { + // IotDeviceDO device = deviceService.getDeviceFromCache(control.getProductKey(), deviceName); + // if (device == null) { + // log.error("[execute][message({}) actionConfig({}) 对应的设备不存在]", message, actionConfig); + // return; + // } + // try { + // // TODO @芋艿:@puhui999:这块可能要改,从 type => method + // IotDeviceMessage downstreamMessage = deviceMessageService.sendDeviceMessage(IotDeviceMessage.requestOf( + // control.getType() + control.getIdentifier(), control.getData()).setDeviceId(device.getId())); + // log.info("[execute][message({}) actionConfig({}) 下发消息({})成功]", message, actionConfig, downstreamMessage); + // } catch (Exception e) { + // log.error("[execute][message({}) actionConfig({}) 下发消息失败]", message, actionConfig, e); + // } + //}); + } + + @Override + public IotSceneRuleActionTypeEnum getType() { + return IotSceneRuleActionTypeEnum.DEVICE_PROPERTY_SET; + } + +} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java index 9b5baf6..c88a37f 100644 --- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java +++ b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/rule/scene/action/IotSceneRuleAction.java @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.service.rule.scene.action; import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; -import cn.iocoder.yudao.module.iot.enums.rule.IotRuleSceneActionTypeEnum; +import cn.iocoder.yudao.module.iot.enums.rule.IotSceneRuleActionTypeEnum; import javax.annotation.Nullable; @@ -31,6 +31,6 @@ public interface IotSceneRuleAction { * * @return 类型 */ - IotRuleSceneActionTypeEnum getType(); + IotSceneRuleActionTypeEnum getType(); } diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceSimpleTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceSimpleTest.java deleted file mode 100644 index e2735f5..0000000 --- a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotRuleSceneServiceSimpleTest.java +++ /dev/null @@ -1,211 +0,0 @@ -package cn.iocoder.yudao.module.iot.service.rule.scene; - -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; -import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; -import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotRuleSceneSaveReqVO; -import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; -import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotRuleSceneMapper; -import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; -import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; -import cn.iocoder.yudao.module.iot.service.product.IotProductService; -import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction; -import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; - -import java.util.Collections; -import java.util.List; - -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; - -/** - * {@link IotRuleSceneServiceImpl} 的简化单元测试类 - * 使用 Mockito 进行纯单元测试,不依赖 Spring 容器 - * - * @author 芋道源码 - */ -public class IotRuleSceneServiceSimpleTest extends BaseMockitoUnitTest { - - @InjectMocks - private IotRuleSceneServiceImpl ruleSceneService; - - @Mock - private IotRuleSceneMapper ruleSceneMapper; - - @Mock - private List ruleSceneActions; - - @Mock - private IotSchedulerManager schedulerManager; - - @Mock - private IotProductService productService; - - @Mock - private IotDeviceService deviceService; - - @Test - public void testCreateRuleScene_success() { - // 准备参数 - IotRuleSceneSaveReqVO createReqVO = randomPojo(IotRuleSceneSaveReqVO.class, o -> { - o.setId(null); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - o.setTriggers(Collections.singletonList(randomPojo(IotSceneRuleDO.Trigger.class))); - o.setActions(Collections.singletonList(randomPojo(IotSceneRuleDO.Action.class))); - }); - - // Mock 行为 - Long expectedId = randomLongId(); - when(ruleSceneMapper.insert(any(IotSceneRuleDO.class))).thenAnswer(invocation -> { - IotSceneRuleDO ruleScene = invocation.getArgument(0); - ruleScene.setId(expectedId); - return 1; - }); - - // 调用 - Long ruleSceneId = ruleSceneService.createRuleScene(createReqVO); - - // 断言 - assertEquals(expectedId, ruleSceneId); - verify(ruleSceneMapper, times(1)).insert(any(IotSceneRuleDO.class)); - } - - @Test - public void testUpdateRuleScene_success() { - // 准备参数 - Long id = randomLongId(); - IotRuleSceneSaveReqVO updateReqVO = randomPojo(IotRuleSceneSaveReqVO.class, o -> { - o.setId(id); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - o.setTriggers(Collections.singletonList(randomPojo(IotSceneRuleDO.Trigger.class))); - o.setActions(Collections.singletonList(randomPojo(IotSceneRuleDO.Action.class))); - }); - - // Mock 行为 - IotSceneRuleDO existingRuleScene = randomPojo(IotSceneRuleDO.class, o -> o.setId(id)); - when(ruleSceneMapper.selectById(id)).thenReturn(existingRuleScene); - when(ruleSceneMapper.updateById(any(IotSceneRuleDO.class))).thenReturn(1); - - // 调用 - assertDoesNotThrow(() -> ruleSceneService.updateRuleScene(updateReqVO)); - - // 验证 - verify(ruleSceneMapper, times(1)).selectById(id); - verify(ruleSceneMapper, times(1)).updateById(any(IotSceneRuleDO.class)); - } - - @Test - public void testDeleteRuleScene_success() { - // 准备参数 - Long id = randomLongId(); - - // Mock 行为 - IotSceneRuleDO existingRuleScene = randomPojo(IotSceneRuleDO.class, o -> o.setId(id)); - when(ruleSceneMapper.selectById(id)).thenReturn(existingRuleScene); - when(ruleSceneMapper.deleteById(id)).thenReturn(1); - - // 调用 - assertDoesNotThrow(() -> ruleSceneService.deleteRuleScene(id)); - - // 验证 - verify(ruleSceneMapper, times(1)).selectById(id); - verify(ruleSceneMapper, times(1)).deleteById(id); - } - - @Test - public void testGetRuleScene() { - // 准备参数 - Long id = randomLongId(); - IotSceneRuleDO expectedRuleScene = randomPojo(IotSceneRuleDO.class, o -> o.setId(id)); - - // Mock 行为 - when(ruleSceneMapper.selectById(id)).thenReturn(expectedRuleScene); - - // 调用 - IotSceneRuleDO result = ruleSceneService.getRuleScene(id); - - // 断言 - assertEquals(expectedRuleScene, result); - verify(ruleSceneMapper, times(1)).selectById(id); - } - - @Test - public void testUpdateRuleSceneStatus_success() { - // 准备参数 - Long id = randomLongId(); - Integer status = CommonStatusEnum.DISABLE.getStatus(); - - // Mock 行为 - IotSceneRuleDO existingRuleScene = randomPojo(IotSceneRuleDO.class, o -> { - o.setId(id); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - }); - when(ruleSceneMapper.selectById(id)).thenReturn(existingRuleScene); - when(ruleSceneMapper.updateById(any(IotSceneRuleDO.class))).thenReturn(1); - - // 调用 - assertDoesNotThrow(() -> ruleSceneService.updateRuleSceneStatus(id, status)); - - // 验证 - verify(ruleSceneMapper, times(1)).selectById(id); - verify(ruleSceneMapper, times(1)).updateById(any(IotSceneRuleDO.class)); - } - - @Test - public void testExecuteRuleSceneByTimer_success() { - // 准备参数 - Long id = randomLongId(); - - // Mock 行为 - IotSceneRuleDO ruleScene = randomPojo(IotSceneRuleDO.class, o -> { - o.setId(id); - o.setStatus(CommonStatusEnum.ENABLE.getStatus()); - }); - when(ruleSceneMapper.selectById(id)).thenReturn(ruleScene); - - // 调用 - assertDoesNotThrow(() -> ruleSceneService.executeRuleSceneByTimer(id)); - - // 验证 - verify(ruleSceneMapper, times(1)).selectById(id); - } - - @Test - public void testExecuteRuleSceneByTimer_notExists() { - // 准备参数 - Long id = randomLongId(); - - // Mock 行为 - when(ruleSceneMapper.selectById(id)).thenReturn(null); - - // 调用 - 不存在的场景规则应该不会抛异常,只是记录日志 - assertDoesNotThrow(() -> ruleSceneService.executeRuleSceneByTimer(id)); - - // 验证 - verify(ruleSceneMapper, times(1)).selectById(id); - } - - @Test - public void testExecuteRuleSceneByTimer_disabled() { - // 准备参数 - Long id = randomLongId(); - - // Mock 行为 - IotSceneRuleDO ruleScene = randomPojo(IotSceneRuleDO.class, o -> { - o.setId(id); - o.setStatus(CommonStatusEnum.DISABLE.getStatus()); - }); - when(ruleSceneMapper.selectById(id)).thenReturn(ruleScene); - - // 调用 - 禁用的场景规则应该不会执行,只是记录日志 - assertDoesNotThrow(() -> ruleSceneService.executeRuleSceneByTimer(id)); - - // 验证 - verify(ruleSceneMapper, times(1)).selectById(id); - } -} diff --git a/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceSimpleTest.java b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceSimpleTest.java new file mode 100644 index 0000000..056794b --- /dev/null +++ b/yudao-module-iot/yudao-module-iot-biz/src/test/java/cn/iocoder/yudao/module/iot/service/rule/scene/IotSceneRuleServiceSimpleTest.java @@ -0,0 +1,211 @@ +package cn.iocoder.yudao.module.iot.service.rule.scene; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest; +import cn.iocoder.yudao.module.iot.controller.admin.rule.vo.scene.IotSceneRuleSaveReqVO; +import cn.iocoder.yudao.module.iot.dal.dataobject.rule.IotSceneRuleDO; +import cn.iocoder.yudao.module.iot.dal.mysql.rule.IotSceneRuleMapper; +import cn.iocoder.yudao.module.iot.framework.job.core.IotSchedulerManager; +import cn.iocoder.yudao.module.iot.service.device.IotDeviceService; +import cn.iocoder.yudao.module.iot.service.product.IotProductService; +import cn.iocoder.yudao.module.iot.service.rule.scene.action.IotSceneRuleAction; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import java.util.Collections; +import java.util.List; + +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +/** + * {@link IotSceneRuleServiceImpl} 的简化单元测试类 + * 使用 Mockito 进行纯单元测试,不依赖 Spring 容器 + * + * @author 芋道源码 + */ +public class IotSceneRuleServiceSimpleTest extends BaseMockitoUnitTest { + + @InjectMocks + private IotSceneRuleServiceImpl sceneRuleService; + + @Mock + private IotSceneRuleMapper sceneRuleMapper; + + @Mock + private List sceneRuleActions; + + @Mock + private IotSchedulerManager schedulerManager; + + @Mock + private IotProductService productService; + + @Mock + private IotDeviceService deviceService; + + @Test + public void testCreateScene_Rule_success() { + // 准备参数 + IotSceneRuleSaveReqVO createReqVO = randomPojo(IotSceneRuleSaveReqVO.class, o -> { + o.setId(null); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setTriggers(Collections.singletonList(randomPojo(IotSceneRuleDO.Trigger.class))); + o.setActions(Collections.singletonList(randomPojo(IotSceneRuleDO.Action.class))); + }); + + // Mock 行为 + Long expectedId = randomLongId(); + when(sceneRuleMapper.insert(any(IotSceneRuleDO.class))).thenAnswer(invocation -> { + IotSceneRuleDO sceneRule = invocation.getArgument(0); + sceneRule.setId(expectedId); + return 1; + }); + + // 调用 + Long sceneRuleId = sceneRuleService.createSceneRule(createReqVO); + + // 断言 + assertEquals(expectedId, sceneRuleId); + verify(sceneRuleMapper, times(1)).insert(any(IotSceneRuleDO.class)); + } + + @Test + public void testUpdateScene_Rule_success() { + // 准备参数 + Long id = randomLongId(); + IotSceneRuleSaveReqVO updateReqVO = randomPojo(IotSceneRuleSaveReqVO.class, o -> { + o.setId(id); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + o.setTriggers(Collections.singletonList(randomPojo(IotSceneRuleDO.Trigger.class))); + o.setActions(Collections.singletonList(randomPojo(IotSceneRuleDO.Action.class))); + }); + + // Mock 行为 + IotSceneRuleDO existingSceneRule = randomPojo(IotSceneRuleDO.class, o -> o.setId(id)); + when(sceneRuleMapper.selectById(id)).thenReturn(existingSceneRule); + when(sceneRuleMapper.updateById(any(IotSceneRuleDO.class))).thenReturn(1); + + // 调用 + assertDoesNotThrow(() -> sceneRuleService.updateSceneRule(updateReqVO)); + + // 验证 + verify(sceneRuleMapper, times(1)).selectById(id); + verify(sceneRuleMapper, times(1)).updateById(any(IotSceneRuleDO.class)); + } + + @Test + public void testDeleteSceneRule_success() { + // 准备参数 + Long id = randomLongId(); + + // Mock 行为 + IotSceneRuleDO existingSceneRule = randomPojo(IotSceneRuleDO.class, o -> o.setId(id)); + when(sceneRuleMapper.selectById(id)).thenReturn(existingSceneRule); + when(sceneRuleMapper.deleteById(id)).thenReturn(1); + + // 调用 + assertDoesNotThrow(() -> sceneRuleService.deleteSceneRule(id)); + + // 验证 + verify(sceneRuleMapper, times(1)).selectById(id); + verify(sceneRuleMapper, times(1)).deleteById(id); + } + + @Test + public void testGetSceneRule() { + // 准备参数 + Long id = randomLongId(); + IotSceneRuleDO expectedSceneRule = randomPojo(IotSceneRuleDO.class, o -> o.setId(id)); + + // Mock 行为 + when(sceneRuleMapper.selectById(id)).thenReturn(expectedSceneRule); + + // 调用 + IotSceneRuleDO result = sceneRuleService.getSceneRule(id); + + // 断言 + assertEquals(expectedSceneRule, result); + verify(sceneRuleMapper, times(1)).selectById(id); + } + + @Test + public void testUpdateSceneRuleStatus_success() { + // 准备参数 + Long id = randomLongId(); + Integer status = CommonStatusEnum.DISABLE.getStatus(); + + // Mock 行为 + IotSceneRuleDO existingSceneRule = randomPojo(IotSceneRuleDO.class, o -> { + o.setId(id); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + when(sceneRuleMapper.selectById(id)).thenReturn(existingSceneRule); + when(sceneRuleMapper.updateById(any(IotSceneRuleDO.class))).thenReturn(1); + + // 调用 + assertDoesNotThrow(() -> sceneRuleService.updateSceneRuleStatus(id, status)); + + // 验证 + verify(sceneRuleMapper, times(1)).selectById(id); + verify(sceneRuleMapper, times(1)).updateById(any(IotSceneRuleDO.class)); + } + + @Test + public void testExecuteSceneRuleByTimer_success() { + // 准备参数 + Long id = randomLongId(); + + // Mock 行为 + IotSceneRuleDO sceneRule = randomPojo(IotSceneRuleDO.class, o -> { + o.setId(id); + o.setStatus(CommonStatusEnum.ENABLE.getStatus()); + }); + when(sceneRuleMapper.selectById(id)).thenReturn(sceneRule); + + // 调用 + assertDoesNotThrow(() -> sceneRuleService.executeSceneRuleByTimer(id)); + + // 验证 + verify(sceneRuleMapper, times(1)).selectById(id); + } + + @Test + public void testExecuteSceneRuleByTimer_notExists() { + // 准备参数 + Long id = randomLongId(); + + // Mock 行为 + when(sceneRuleMapper.selectById(id)).thenReturn(null); + + // 调用 - 不存在的场景规则应该不会抛异常,只是记录日志 + assertDoesNotThrow(() -> sceneRuleService.executeSceneRuleByTimer(id)); + + // 验证 + verify(sceneRuleMapper, times(1)).selectById(id); + } + + @Test + public void testExecuteSceneRuleByTimer_disabled() { + // 准备参数 + Long id = randomLongId(); + + // Mock 行为 + IotSceneRuleDO sceneRule = randomPojo(IotSceneRuleDO.class, o -> { + o.setId(id); + o.setStatus(CommonStatusEnum.DISABLE.getStatus()); + }); + when(sceneRuleMapper.selectById(id)).thenReturn(sceneRule); + + // 调用 - 禁用的场景规则应该不会执行,只是记录日志 + assertDoesNotThrow(() -> sceneRuleService.executeSceneRuleByTimer(id)); + + // 验证 + verify(sceneRuleMapper, times(1)).selectById(id); + } +} -- libgit2 0.21.4