From fe299d792e3610742147cd2b48f6b1a869286084 Mon Sep 17 00:00:00 2001 From: puhui999 Date: Mon, 4 Aug 2025 15:49:53 +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=E8=A7=A6?= =?UTF-8?q?=E5=8F=91=E5=99=A8=E6=9C=8D=E5=8A=A1=E8=B0=83=E7=94=A8=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E8=BE=93=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../iot/rule/scene/form/RuleSceneForm.vue | 199 ++----- .../form/configs/MainConditionInnerConfig.vue | 41 +- .../scene/form/inputs/ServiceParamsInput.vue | 490 ++++++++++++++++++ 3 files changed, 552 insertions(+), 178 deletions(-) create mode 100644 src/views/iot/rule/scene/form/inputs/ServiceParamsInput.vue diff --git a/src/views/iot/rule/scene/form/RuleSceneForm.vue b/src/views/iot/rule/scene/form/RuleSceneForm.vue index e2f155a80..b70071270 100644 --- a/src/views/iot/rule/scene/form/RuleSceneForm.vue +++ b/src/views/iot/rule/scene/form/RuleSceneForm.vue @@ -36,74 +36,15 @@ import { useVModel } from '@vueuse/core' import BasicInfoSection from './sections/BasicInfoSection.vue' import TriggerSection from './sections/TriggerSection.vue' import ActionSection from './sections/ActionSection.vue' -import { IotRuleScene, IotRuleSceneDO, RuleSceneFormData } from '@/api/iot/rule/scene/scene.types' +import { IotRuleSceneDO, RuleSceneFormData } from '@/api/iot/rule/scene/scene.types' import { RuleSceneApi } from '@/api/iot/rule/scene' import { IotRuleSceneTriggerTypeEnum, IotRuleSceneActionTypeEnum, - IotDeviceMessageTypeEnum, isDeviceTrigger } from '@/views/iot/utils/constants' import { ElMessage } from 'element-plus' -import { generateUUID } from '@/utils' - -// 导入全局的 CommonStatusEnum -// TODO @puhui999:这里直接复用全局的哈; -const CommonStatusEnum = { - ENABLE: 0, // 开启 - DISABLE: 1 // 关闭 -} as const - -// 工具函数:根据触发器类型获取消息类型 -const getMessageTypeByTriggerType = (triggerType: number): string => { - switch (triggerType) { - case IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST: - return IotDeviceMessageTypeEnum.PROPERTY - case IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST: - return IotDeviceMessageTypeEnum.EVENT - case IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE: - return IotDeviceMessageTypeEnum.SERVICE - default: - return IotDeviceMessageTypeEnum.PROPERTY - } -} - -// 工具函数:根据执行器类型获取消息类型 -const getMessageTypeByActionType = (actionType: number): string => { - switch (actionType) { - case IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET: - return IotDeviceMessageTypeEnum.PROPERTY - case IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE: - return IotDeviceMessageTypeEnum.SERVICE - default: - return IotDeviceMessageTypeEnum.PROPERTY - } -} - -// 工具函数:根据执行器类型和参数获取标识符 -const getIdentifierByActionType = (actionType: number, params?: Record): string => { - if (!params) return '' - - switch (actionType) { - case IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET: - // 属性设置:取第一个属性名作为标识符 - return Object.keys(params)[0] || '' - case IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE: - // 服务调用:取 method 字段作为标识符 - return params.method || '' - default: - return '' - } -} - -// 工具函数:判断是否为设备执行器 -const isDeviceAction = (type: number): boolean => { - const deviceActionTypes = [ - IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET, - IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE - ] as number[] - return deviceActionTypes.includes(type) -} +import { CommonStatusEnum } from '@/utils/constants' /** IoT 场景联动规则表单 - 主表单组件 */ defineOptions({ name: 'RuleSceneForm' }) @@ -146,111 +87,11 @@ const createDefaultFormData = (): RuleSceneFormData => { } } -/** - * 将表单数据转换为后端 API 格式 - * 转换为 IotRuleScene 格式,与后端 API 接口对齐 - */ -const convertFormToVO = (formData: RuleSceneFormData): IotRuleScene => { - return { - id: formData.id, - name: formData.name, - description: formData.description, - status: Number(formData.status), - triggers: formData.triggers.map((trigger) => ({ - key: generateUUID(), // 为每个触发器生成唯一标识 - type: trigger.type, - productKey: trigger.productId ? `product_${trigger.productId}` : undefined, // 转换为产品标识 - deviceNames: trigger.deviceId ? [`device_${trigger.deviceId}`] : undefined, // 转换为设备名称数组 - conditions: trigger.identifier - ? [ - { - type: getMessageTypeByTriggerType(trigger.type), - identifier: trigger.identifier, - parameters: [ - { - identifier: trigger.identifier, - operator: trigger.operator || '=', - value: trigger.value || '' - } - ] - } - ] - : undefined, - cronExpression: trigger.cronExpression - })), - actions: - formData.actions?.map((action) => ({ - key: generateUUID(), // 为每个执行器生成唯一标识 - type: action.type, - deviceControl: isDeviceAction(action.type) - ? { - productKey: action.productId ? `product_${action.productId}` : '', - deviceNames: action.deviceId ? [`device_${action.deviceId}`] : [], - type: getMessageTypeByActionType(action.type), - identifier: getIdentifierByActionType(action.type, action.params), - params: action.params || {} - } - : undefined, - alertConfigId: action.alertConfigId - })) || [] - } -} - -// TODO @puhui999:下面好像没用到? -/** - * 将后端 DO 数据转换为表单格式 - * 由于数据结构已对齐,转换变得非常简单 - */ -const convertVOToForm = (apiData: IotRuleSceneDO): RuleSceneFormData => { - // 转换所有触发器 - const triggers = apiData.triggers?.length - ? apiData.triggers.map((trigger: any) => ({ - type: Number(trigger.type), - productId: trigger.productId, - deviceId: trigger.deviceId, - identifier: trigger.identifier, - operator: trigger.operator, - value: trigger.value, - cronExpression: trigger.cronExpression, - conditionGroups: trigger.conditionGroups || [] - })) - : [ - { - type: IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST, - productId: undefined, - deviceId: undefined, - identifier: undefined, - operator: undefined, - value: undefined, - cronExpression: undefined, - conditionGroups: [] - } - ] - - return { - id: apiData.id, - name: apiData.name, - description: apiData.description, - status: Number(apiData.status), - triggers, - actions: - apiData.actions?.map((action: any) => ({ - type: Number(action.type), - productId: action.productId, - deviceId: action.deviceId, - params: action.params || {}, - alertConfigId: action.alertConfigId, - // 为每个执行器添加唯一标识符,解决组件索引重用问题 - key: generateUUID() - })) || [] - } -} - // 表单数据和状态 const formRef = ref() const formData = ref(createDefaultFormData()) // 自定义校验器 -const validateTriggers = (rule: any, value: any, callback: any) => { +const validateTriggers = (_rule: any, value: any, callback: any) => { if (!value || !Array.isArray(value) || value.length === 0) { callback(new Error('至少需要一个触发器')) return @@ -301,7 +142,7 @@ const validateTriggers = (rule: any, value: any, callback: any) => { callback() } -const validateActions = (rule: any, value: any, callback: any) => { +const validateActions = (_rule: any, value: any, callback: any) => { if (!value || !Array.isArray(value) || value.length === 0) { callback(new Error('至少需要一个执行器')) return @@ -387,18 +228,17 @@ const handleSubmit = async () => { // 提交请求 submitLoading.value = true try { - // 转换数据格式 - const apiData = convertFormToVO(formData.value) - console.log('提交数据:', apiData) + // 数据结构已对齐,直接使用表单数据 + console.log('提交数据:', formData.value) // 调用API保存数据 if (isEdit.value) { // 更新场景联动规则 - await RuleSceneApi.updateRuleScene(apiData) + await RuleSceneApi.updateRuleScene(formData.value) ElMessage.success('更新成功') } else { // 创建场景联动规则 - await RuleSceneApi.createRuleScene(apiData) + await RuleSceneApi.createRuleScene(formData.value) ElMessage.success('创建成功') } @@ -420,9 +260,28 @@ const handleClose = () => { /** 初始化表单数据 */ const initFormData = () => { if (props.ruleScene) { - // 编辑模式:转换后端数据为表单格式 + // 编辑模式:数据结构已对齐,直接使用后端数据 isEdit.value = true - formData.value = convertVOToForm(props.ruleScene) + formData.value = { + ...props.ruleScene, + // 确保触发器数组不为空 + triggers: props.ruleScene.triggers?.length + ? props.ruleScene.triggers + : [ + { + type: IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST, + productId: undefined, + deviceId: undefined, + identifier: undefined, + operator: undefined, + value: undefined, + cronExpression: undefined, + conditionGroups: [] + } + ], + // 确保执行器数组不为空 + actions: props.ruleScene.actions || [] + } } else { // 新增模式:使用默认数据 isEdit.value = false diff --git a/src/views/iot/rule/scene/form/configs/MainConditionInnerConfig.vue b/src/views/iot/rule/scene/form/configs/MainConditionInnerConfig.vue index 301fc7b50..07feb1d51 100644 --- a/src/views/iot/rule/scene/form/configs/MainConditionInnerConfig.vue +++ b/src/views/iot/rule/scene/form/configs/MainConditionInnerConfig.vue @@ -59,8 +59,8 @@ - - + + - - + + + + + { - condition.value[field] = value + ;(condition.value as any)[field] = value updateValidationResult() } @@ -214,7 +232,7 @@ const handleOperatorChange = () => { updateValidationResult() } -const handleValueValidate = (result: { valid: boolean; message: string }) => { +const handleValueValidate = (_result: { valid: boolean; message: string }) => { updateValidationResult() } @@ -250,7 +268,11 @@ const updateValidationResult = () => { return } - if (!condition.value.operator) { + // 服务调用不需要操作符 + if ( + props.triggerType !== IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE && + !condition.value.operator + ) { isValid.value = false validationMessage.value = '请选择操作符' emit('validate', { valid: false, message: validationMessage.value }) @@ -276,7 +298,10 @@ watch( condition.value.productId, condition.value.deviceId, condition.value.identifier, - condition.value.operator, + // 服务调用不需要监听操作符 + props.triggerType !== IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE + ? condition.value.operator + : null, condition.value.value ], () => { diff --git a/src/views/iot/rule/scene/form/inputs/ServiceParamsInput.vue b/src/views/iot/rule/scene/form/inputs/ServiceParamsInput.vue new file mode 100644 index 000000000..00d8b6eb3 --- /dev/null +++ b/src/views/iot/rule/scene/form/inputs/ServiceParamsInput.vue @@ -0,0 +1,490 @@ + + + + + +