From 6c954c4ff123623117e3e81aa4287a520574151e Mon Sep 17 00:00:00 2001 From: puhui999 Date: Tue, 5 Aug 2025 11:59:46 +0800 Subject: [PATCH] =?UTF-8?q?perf=EF=BC=9A=E3=80=90IoT=20=E7=89=A9=E8=81=94?= =?UTF-8?q?=E7=BD=91=E3=80=91=E5=9C=BA=E6=99=AF=E8=81=94=E5=8A=A8=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E7=BB=9F=E4=B8=80=E7=B1=BB=E5=9E=8B=E5=AE=9A=E4=B9=89?= =?UTF-8?q?=EF=BC=8C=E7=AE=80=E5=8C=96=E5=91=8A=E8=AD=A6=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/iot/rule/scene/index.ts | 17 +- src/api/iot/rule/scene/scene.types.ts | 139 +-------- .../iot/rule/scene/form/RuleSceneForm.vue | 8 +- .../rule/scene/form/configs/AlertConfig.vue | 275 +++--------------- .../scene/form/configs/ConditionConfig.vue | 10 +- .../form/configs/DeviceControlConfig.vue | 6 +- .../configs/DeviceStatusConditionConfig.vue | 6 +- .../form/configs/SubConditionGroupConfig.vue | 10 +- .../scene/form/sections/ActionSection.vue | 60 ++-- .../scene/form/sections/BasicInfoSection.vue | 6 +- src/views/iot/rule/scene/index.vue | 20 +- 11 files changed, 134 insertions(+), 423 deletions(-) diff --git a/src/api/iot/rule/scene/index.ts b/src/api/iot/rule/scene/index.ts index 75b121544..9bbf8db6a 100644 --- a/src/api/iot/rule/scene/index.ts +++ b/src/api/iot/rule/scene/index.ts @@ -1,5 +1,5 @@ import request from '@/config/axios' -import { IotRuleScene } from './scene.types' +import { IotSceneRule } from './scene.types' // IoT 场景联动 API export const RuleSceneApi = { @@ -14,21 +14,24 @@ export const RuleSceneApi = { }, // 新增场景联动 - createRuleScene: async (data: IotRuleScene) => { + createRuleScene: async (data: IotSceneRule) => { return await request.post({ url: `/iot/rule-scene/create`, data }) }, // 修改场景联动 - updateRuleScene: async (data: IotRuleScene) => { + updateRuleScene: async (data: IotSceneRule) => { return await request.put({ url: `/iot/rule-scene/update`, data }) }, // 修改场景联动 updateRuleSceneStatus: async (id: number, status: number) => { - return await request.put({ url: `/iot/rule-scene/update-status`, data: { - id, - status - }}) + return await request.put({ + url: `/iot/rule-scene/update-status`, + data: { + id, + status + } + }) }, // 删除场景联动 diff --git a/src/api/iot/rule/scene/scene.types.ts b/src/api/iot/rule/scene/scene.types.ts index 577786502..dc9342ca4 100644 --- a/src/api/iot/rule/scene/scene.types.ts +++ b/src/api/iot/rule/scene/scene.types.ts @@ -137,122 +137,18 @@ export interface PropertySelectorItem { // ========== 场景联动规则相关接口定义 ========== -// 基础接口(如果项目中有全局的 BaseDO,可以使用全局的) -interface TenantBaseDO { - createTime?: Date // 创建时间 - updateTime?: Date // 更新时间 - creator?: string // 创建者 - updater?: string // 更新者 - deleted?: boolean // 是否删除 - tenantId?: number // 租户编号 -} - -// 触发条件参数 -interface TriggerConditionParameter { - identifier0?: string // 标识符(事件、服务) - identifier?: string // 标识符(属性) - operator: string // 操作符(必填) - value: string // 比较值(必填,多值用逗号分隔) -} - -// 触发条件 -interface TriggerCondition { - type: string // 消息类型 - identifier: string // 消息标识符 - parameters: TriggerConditionParameter[] // 参数数组 -} - -// 触发器配置 -interface TriggerConfig { - key?: string // 组件唯一标识符,用于解决索引重用问题 - type: number // 触发类型(必填) - productKey?: string // 产品标识(设备触发时必填) - deviceNames?: string[] // 设备名称数组(设备触发时必填) - conditions?: TriggerCondition[] // 触发条件数组(设备触发时必填) - cronExpression?: string // CRON表达式(定时触发时必填) -} - -// 执行设备控制 -interface ActionDeviceControl { - productKey: string // 产品标识(必填) - deviceNames: string[] // 设备名称数组(必填) - type: string // 消息类型(必填) - identifier: string // 消息标识符(必填) - params: Record // 参数对象(必填)- 统一使用 params 字段 -} - -// 执行器配置 -interface ActionConfig { - key?: string // 组件唯一标识符,用于解决索引重用问题 - type: number // 执行类型(必填) - deviceControl?: ActionDeviceControl // 设备控制(设备控制时必填) - alertConfigId?: number // 告警配置ID(告警恢复时必填) -} - -// 表单数据接口 - 直接对应后端 DO 结构 -interface RuleSceneFormData { - id?: number - name: string - description?: string - status: number - triggers: TriggerFormData[] // 支持多个触发器 - actions: ActionFormData[] -} - -// 触发器表单数据 - 直接对应 TriggerDO -interface TriggerFormData { - type: number // 触发类型 - productId?: number // 产品编号 - deviceId?: number // 设备编号 - identifier?: string // 物模型标识符 - operator?: string // 操作符 - value?: string // 参数值 - cronExpression?: string // CRON 表达式 - conditionGroups?: TriggerConditionFormData[][] // 条件组(二维数组) -} - -// 触发条件表单数据 - 直接对应 TriggerConditionDO -interface TriggerConditionFormData { - type: number // 条件类型:1-设备状态,2-设备属性,3-当前时间 - productId?: number // 产品编号 - deviceId?: number // 设备编号 - identifier?: string // 标识符 - operator: string // 操作符 - param: string // 参数值 -} - -// 执行器表单数据 - 直接对应 ActionDO -interface ActionFormData { - type: number // 执行类型 - productId?: number // 产品编号 - deviceId?: number // 设备编号 - identifier?: string // 物模型标识符(服务调用时使用) - params?: Record // 请求参数 - alertConfigId?: number // 告警配置编号 -} - -// 主接口 - 原有的 API 接口格式(保持兼容性) -interface IotRuleScene extends TenantBaseDO { - id?: number // 场景编号(新增时为空) - name: string // 场景名称(必填) - description?: string // 场景描述(可选) - status: number // 场景状态:0-开启,1-关闭 - triggers: TriggerConfig[] // 触发器数组(必填,至少一个) - actions: ActionConfig[] // 执行器数组(必填,至少一个) -} - // 后端 DO 接口 - 匹配后端数据结构 -interface IotRuleSceneDO { +interface IotSceneRule { id?: number // 场景编号 name: string // 场景名称 description?: string // 场景描述 status: number // 场景状态:0-开启,1-关闭 - triggers: TriggerDO[] // 触发器数组 - actions: ActionDO[] // 执行器数组 + triggers: Trigger[] // 触发器数组 + actions: Action[] // 执行器数组 } // 触发器 DO 结构 -interface TriggerDO { +interface Trigger { type: number // 触发类型 productId?: number // 产品编号 deviceId?: number // 设备编号 @@ -260,12 +156,12 @@ interface TriggerDO { operator?: string // 操作符 value?: string // 参数值 cronExpression?: string // CRON 表达式 - conditionGroups?: TriggerConditionDO[][] // 条件组(二维数组) + conditionGroups?: TriggerCondition[][] // 条件组(二维数组) } // 触发条件 DO 结构 -interface TriggerConditionDO { - type: number // 条件类型 +interface TriggerCondition { + type: number // 条件类型:1-设备状态,2-设备属性,3-当前时间 productId?: number // 产品编号 deviceId?: number // 设备编号 identifier?: string // 标识符 @@ -274,7 +170,7 @@ interface TriggerConditionDO { } // 执行器 DO 结构 -interface ActionDO { +interface Action { type: number // 执行类型 productId?: number // 产品编号 deviceId?: number // 设备编号 @@ -300,21 +196,4 @@ interface FormValidationRules { // TODO @puhui999:这个文件,目标最终没有哈,和别的模块一致; -export { - IotRuleScene, - IotRuleSceneDO, - TriggerDO, - TriggerConditionDO, - ActionDO, - TriggerConfig, - TriggerCondition, - TriggerConditionParameter, - ActionConfig, - ActionDeviceControl, - RuleSceneFormData, - TriggerFormData, - TriggerConditionFormData, - ActionFormData, - ValidationRule, - FormValidationRules -} +export { IotSceneRule, Trigger, TriggerCondition, Action, ValidationRule, FormValidationRules } diff --git a/src/views/iot/rule/scene/form/RuleSceneForm.vue b/src/views/iot/rule/scene/form/RuleSceneForm.vue index 94c94579b..0362bc4bf 100644 --- a/src/views/iot/rule/scene/form/RuleSceneForm.vue +++ b/src/views/iot/rule/scene/form/RuleSceneForm.vue @@ -36,7 +36,7 @@ import { useVModel } from '@vueuse/core' import BasicInfoSection from './sections/BasicInfoSection.vue' import TriggerSection from './sections/TriggerSection.vue' import ActionSection from './sections/ActionSection.vue' -import { IotRuleSceneDO, RuleSceneFormData } from '@/api/iot/rule/scene/scene.types' +import { IotSceneRule } from '@/api/iot/rule/scene/scene.types' import { RuleSceneApi } from '@/api/iot/rule/scene' import { IotRuleSceneTriggerTypeEnum, @@ -54,7 +54,7 @@ const props = defineProps<{ /** 抽屉显示状态 */ modelValue: boolean /** 编辑的场景联动规则数据 */ - ruleScene?: IotRuleSceneDO + ruleScene?: IotSceneRule }>() /** 组件事件定义 */ @@ -66,7 +66,7 @@ const emit = defineEmits<{ const drawerVisible = useVModel(props, 'modelValue', emit) // 是否可见 /** 创建默认的表单数据 */ -const createDefaultFormData = (): RuleSceneFormData => { +const createDefaultFormData = (): IotSceneRule => { return { name: '', description: '', @@ -89,7 +89,7 @@ const createDefaultFormData = (): RuleSceneFormData => { // 表单数据和状态 const formRef = ref() -const formData = ref(createDefaultFormData()) +const formData = ref(createDefaultFormData()) // 自定义校验器 const validateTriggers = (_rule: any, value: any, callback: any) => { if (!value || !Array.isArray(value) || value.length === 0) { diff --git a/src/views/iot/rule/scene/form/configs/AlertConfig.vue b/src/views/iot/rule/scene/form/configs/AlertConfig.vue index bffe9d578..8073c351a 100644 --- a/src/views/iot/rule/scene/form/configs/AlertConfig.vue +++ b/src/views/iot/rule/scene/form/configs/AlertConfig.vue @@ -1,262 +1,81 @@ - - diff --git a/src/views/iot/rule/scene/form/configs/ConditionConfig.vue b/src/views/iot/rule/scene/form/configs/ConditionConfig.vue index 3eeed5143..9574c58ce 100644 --- a/src/views/iot/rule/scene/form/configs/ConditionConfig.vue +++ b/src/views/iot/rule/scene/form/configs/ConditionConfig.vue @@ -123,7 +123,7 @@ import DeviceSelector from '../selectors/DeviceSelector.vue' import PropertySelector from '../selectors/PropertySelector.vue' import OperatorSelector from '../selectors/OperatorSelector.vue' import ValueInput from '../inputs/ValueInput.vue' -import { TriggerConditionFormData } from '@/api/iot/rule/scene/scene.types' +import { TriggerCondition } from '@/api/iot/rule/scene/scene.types' import { IotRuleSceneTriggerConditionTypeEnum, IotRuleSceneTriggerConditionParameterOperatorEnum @@ -133,12 +133,12 @@ import { defineOptions({ name: 'ConditionConfig' }) const props = defineProps<{ - modelValue: TriggerConditionFormData + modelValue: TriggerCondition triggerType: number }>() const emit = defineEmits<{ - (e: 'update:modelValue', value: TriggerConditionFormData): void + (e: 'update:modelValue', value: TriggerCondition): void (e: 'validate', result: { valid: boolean; message: string }): void }>() @@ -155,12 +155,12 @@ const isValid = ref(true) const valueValidation = ref({ valid: true, message: '' }) // 事件处理 -const updateConditionField = (field: keyof TriggerConditionFormData, value: any) => { +const updateConditionField = (field: keyof TriggerCondition, value: any) => { ;(condition.value as any)[field] = value emit('update:modelValue', condition.value) } -const updateCondition = (newCondition: TriggerConditionFormData) => { +const updateCondition = (newCondition: TriggerCondition) => { condition.value = newCondition emit('update:modelValue', condition.value) } diff --git a/src/views/iot/rule/scene/form/configs/DeviceControlConfig.vue b/src/views/iot/rule/scene/form/configs/DeviceControlConfig.vue index 7bf056bdf..e8ea5f1ba 100644 --- a/src/views/iot/rule/scene/form/configs/DeviceControlConfig.vue +++ b/src/views/iot/rule/scene/form/configs/DeviceControlConfig.vue @@ -320,18 +320,18 @@ import { useVModel } from '@vueuse/core' import { InfoFilled } from '@element-plus/icons-vue' import ProductSelector from '../selectors/ProductSelector.vue' import DeviceSelector from '../selectors/DeviceSelector.vue' -import { ActionFormData, ThingModelService } from '@/api/iot/rule/scene/scene.types' +import { Action, ThingModelService } from '@/api/iot/rule/scene/scene.types' import { IotRuleSceneActionTypeEnum } from '@/views/iot/utils/constants' /** 设备控制配置组件 */ defineOptions({ name: 'DeviceControlConfig' }) const props = defineProps<{ - modelValue: ActionFormData + modelValue: Action }>() const emit = defineEmits<{ - (e: 'update:modelValue', value: ActionFormData): void + (e: 'update:modelValue', value: Action): void }>() const action = useVModel(props, 'modelValue', emit) diff --git a/src/views/iot/rule/scene/form/configs/DeviceStatusConditionConfig.vue b/src/views/iot/rule/scene/form/configs/DeviceStatusConditionConfig.vue index 0f77124ec..a380192ab 100644 --- a/src/views/iot/rule/scene/form/configs/DeviceStatusConditionConfig.vue +++ b/src/views/iot/rule/scene/form/configs/DeviceStatusConditionConfig.vue @@ -84,17 +84,17 @@ import { useVModel } from '@vueuse/core' import ProductSelector from '../selectors/ProductSelector.vue' import DeviceSelector from '../selectors/DeviceSelector.vue' -import { TriggerConditionFormData } from '@/api/iot/rule/scene/scene.types' +import { TriggerCondition } from '@/api/iot/rule/scene/scene.types' /** 设备状态条件配置组件 */ defineOptions({ name: 'DeviceStatusConditionConfig' }) const props = defineProps<{ - modelValue: TriggerConditionFormData + modelValue: TriggerCondition }>() const emit = defineEmits<{ - (e: 'update:modelValue', value: TriggerConditionFormData): void + (e: 'update:modelValue', value: TriggerCondition): void (e: 'validate', result: { valid: boolean; message: string }): void }>() diff --git a/src/views/iot/rule/scene/form/configs/SubConditionGroupConfig.vue b/src/views/iot/rule/scene/form/configs/SubConditionGroupConfig.vue index d89e4c4de..1e86d301d 100644 --- a/src/views/iot/rule/scene/form/configs/SubConditionGroupConfig.vue +++ b/src/views/iot/rule/scene/form/configs/SubConditionGroupConfig.vue @@ -83,7 +83,7 @@ import { nextTick } from 'vue' import { useVModel } from '@vueuse/core' import ConditionConfig from './ConditionConfig.vue' -import { TriggerConditionFormData } from '@/api/iot/rule/scene/scene.types' +import { TriggerCondition } from '@/api/iot/rule/scene/scene.types' import { IotRuleSceneTriggerConditionTypeEnum, IotRuleSceneTriggerConditionParameterOperatorEnum @@ -93,13 +93,13 @@ import { defineOptions({ name: 'SubConditionGroupConfig' }) const props = defineProps<{ - modelValue: TriggerConditionFormData[] + modelValue: TriggerCondition[] triggerType: number maxConditions?: number }>() const emit = defineEmits<{ - (e: 'update:modelValue', value: TriggerConditionFormData[]): void + (e: 'update:modelValue', value: TriggerCondition[]): void (e: 'validate', result: { valid: boolean; message: string }): void }>() @@ -123,7 +123,7 @@ const addCondition = () => { return } - const newCondition: TriggerConditionFormData = { + const newCondition: TriggerCondition = { type: IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY, // 默认为设备属性 productId: undefined, deviceId: undefined, @@ -161,7 +161,7 @@ const removeCondition = (index: number) => { } } -const updateCondition = (index: number, condition: TriggerConditionFormData) => { +const updateCondition = (index: number, condition: TriggerCondition) => { if (subGroup.value) { subGroup.value[index] = condition } diff --git a/src/views/iot/rule/scene/form/sections/ActionSection.vue b/src/views/iot/rule/scene/form/sections/ActionSection.vue index 344030745..c181e5e68 100644 --- a/src/views/iot/rule/scene/form/sections/ActionSection.vue +++ b/src/views/iot/rule/scene/form/sections/ActionSection.vue @@ -78,12 +78,27 @@ @update:model-value="(value) => updateAction(index, value)" /> - + + + +
+
+ + 触发告警 + 自动执行 +
+
+ 当触发条件满足时,系统将自动发送告警通知,无需额外配置。 +
+
@@ -107,7 +122,7 @@ import { useVModel } from '@vueuse/core' import ActionTypeSelector from '../selectors/ActionTypeSelector.vue' import DeviceControlConfig from '../configs/DeviceControlConfig.vue' import AlertConfig from '../configs/AlertConfig.vue' -import { ActionFormData } from '@/api/iot/rule/scene/scene.types' +import { Action } from '@/api/iot/rule/scene/scene.types' import { IotRuleSceneActionTypeEnum as ActionTypeEnum, isDeviceAction, @@ -118,23 +133,20 @@ import { /** 执行器配置组件 */ defineOptions({ name: 'ActionSection' }) -interface Props { - actions: ActionFormData[] -} +const props = defineProps<{ + actions: Action[] +}>() -interface Emits { - (e: 'update:actions', value: ActionFormData[]): void -} - -const props = defineProps() -const emit = defineEmits() +const emit = defineEmits<{ + (e: 'update:actions', value: Action[]): void +}>() const actions = useVModel(props, 'actions', emit) /** * 创建默认的执行器数据 */ -const createDefaultActionData = (): ActionFormData => { +const createDefaultActionData = (): Action => { return { type: ActionTypeEnum.DEVICE_PROPERTY_SET, // 默认为设备属性设置 productId: undefined, @@ -145,9 +157,7 @@ const createDefaultActionData = (): ActionFormData => { } } -// 配置常量 -// TODO @puhui999:去掉最大;注释风格改下; -const maxActions = 5 +const maxActions = 5 // 最大执行器数量 // 工具函数 const getActionTypeName = (type: number) => { @@ -164,7 +174,7 @@ const getActionTypeTag = (type: number) => { return actionTypeTags[type] || 'info' } -// 事件处理 +/** 添加执行器 */ const addAction = () => { if (actions.value.length >= maxActions) { return @@ -174,24 +184,29 @@ const addAction = () => { actions.value.push(newAction) } +/** 删除执行器 */ const removeAction = (index: number) => { actions.value.splice(index, 1) } +/** 更新执行器类型 */ const updateActionType = (index: number, type: number) => { actions.value[index].type = type onActionTypeChange(actions.value[index], type) } -const updateAction = (index: number, action: ActionFormData) => { +/** 更新执行器 */ +const updateAction = (index: number, action: Action) => { actions.value[index] = action } +/** 更新告警配置 */ const updateActionAlertConfig = (index: number, alertConfigId?: number) => { actions.value[index].alertConfigId = alertConfigId } -const onActionTypeChange = (action: ActionFormData, type: number) => { +/** 监听执行器类型变化 */ +const onActionTypeChange = (action: Action, type: number) => { // 清理不相关的配置,确保数据结构干净 if (isDeviceAction(type)) { // 设备控制类型:清理告警配置,确保设备参数存在 @@ -204,16 +219,11 @@ const onActionTypeChange = (action: ActionFormData, type: number) => { action.identifier = undefined } } else if (isAlertAction(type)) { - // 告警类型:清理设备配置 action.productId = undefined action.deviceId = undefined action.identifier = undefined // 清理服务标识符 action.params = undefined + action.alertConfigId = undefined } - - // 触发重新校验 - nextTick(() => { - // 这里可以添加校验逻辑 - }) } diff --git a/src/views/iot/rule/scene/form/sections/BasicInfoSection.vue b/src/views/iot/rule/scene/form/sections/BasicInfoSection.vue index 786731765..fd27cd35c 100644 --- a/src/views/iot/rule/scene/form/sections/BasicInfoSection.vue +++ b/src/views/iot/rule/scene/form/sections/BasicInfoSection.vue @@ -58,17 +58,17 @@