Bläddra i källkod

perf:【IoT 物联网】场景联动优化数据结构对齐后端

puhui999 8 månader sedan
förälder
incheckning
d06835ae7f

+ 26 - 38
src/views/iot/rule/scene/form/RuleSceneForm.vue

@@ -39,14 +39,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 {
-  IotRuleScene,
-  IotRuleSceneDO,
-  IotRuleSceneActionTypeEnum,
-  RuleSceneFormData,
-  TriggerFormData,
-  TriggerConditionFormData
-} from '@/api/iot/rule/scene/scene.types'
+import { IotRuleSceneDO, RuleSceneFormData } from '@/api/iot/rule/scene/scene.types'
 import { IotRuleSceneTriggerTypeEnum } from '@/views/iot/utils/constants'
 import { ElMessage } from 'element-plus'
 import { generateUUID } from '@/utils'
@@ -64,16 +57,12 @@ defineOptions({ name: 'RuleSceneForm' })
 const props = defineProps<{
   /** 抽屉显示状态 */
   modelValue: boolean
-  /** 编辑的规则数据(新增时为空) */
-  ruleScene?: IotRuleScene
 }>()
 
 /** 组件事件定义 */
 const emit = defineEmits<{
-  /** 更新抽屉显示状态 */
-  'update:modelValue': [value: boolean]
-  /** 操作成功事件 */
-  success: []
+  (e: 'update:modelValue', value: boolean): void
+  (e: 'success'): void
 }>()
 
 const drawerVisible = useVModel(props, 'modelValue', emit) // 是否可见
@@ -120,13 +109,14 @@ const convertFormToVO = (formData: RuleSceneFormData): IotRuleSceneDO => {
       cronExpression: trigger.cronExpression,
       conditionGroups: trigger.conditionGroups || []
     })),
-    actions: formData.actions?.map((action) => ({
-      type: action.type,
-      productId: action.productId,
-      deviceId: action.deviceId,
-      params: action.params,
-      alertConfigId: action.alertConfigId
-    })) || []
+    actions:
+      formData.actions?.map((action) => ({
+        type: action.type,
+        productId: action.productId,
+        deviceId: action.deviceId,
+        params: action.params,
+        alertConfigId: action.alertConfigId
+      })) || []
   }
 }
 
@@ -216,7 +206,7 @@ const triggerValidation = ref({ valid: true, message: '' })
 const actionValidation = ref({ valid: true, message: '' })
 
 // 计算属性
-const isEdit = computed(() => !!props.ruleScene?.id)
+const isEdit = ref(false)
 const drawerTitle = computed(() => (isEdit.value ? '编辑场景联动规则' : '新增场景联动规则'))
 
 // 事件处理
@@ -284,30 +274,28 @@ const handleClose = () => {
 
 /** 初始化表单数据 */
 const initFormData = () => {
-  if (props.ruleScene) {
-    formData.value = convertVOToForm(props.ruleScene)
-  } else {
-    formData.value = createDefaultFormData()
-  }
+  // TODO @puhui999: 编辑的情况后面实现
+  formData.value = createDefaultFormData()
 }
 
 // 监听抽屉显示
 watch(drawerVisible, (visible) => {
   if (visible) {
     initFormData()
-    nextTick(() => {
-      formRef.value?.clearValidate()
-    })
+    // TODO @puhui999: 重置表单的情况
+    // nextTick(() => {
+    //   formRef.value?.clearValidate()
+    // })
   }
 })
 
 // 监听 props 变化
-watch(
-  () => props.ruleScene,
-  () => {
-    if (drawerVisible.value) {
-      initFormData()
-    }
-  }
-)
+// watch(
+//   () => props.ruleScene,
+//   () => {
+//     if (drawerVisible.value) {
+//       initFormData()
+//     }
+//   }
+// )
 </script>

+ 5 - 5
src/views/iot/rule/scene/form/configs/ConditionConfig.vue

@@ -122,7 +122,7 @@ import PropertySelector from '../selectors/PropertySelector.vue'
 import OperatorSelector from '../selectors/OperatorSelector.vue'
 import ValueInput from '../inputs/ValueInput.vue'
 import {
-  ConditionFormData,
+  TriggerConditionFormData,
   IotRuleSceneTriggerConditionTypeEnum
 } from '@/api/iot/rule/scene/scene.types'
 
@@ -130,12 +130,12 @@ import {
 defineOptions({ name: 'ConditionConfig' })
 
 const props = defineProps<{
-  modelValue: ConditionFormData
+  modelValue: TriggerConditionFormData
   triggerType: number
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: ConditionFormData): void
+  (e: 'update:modelValue', value: TriggerConditionFormData): void
   (e: 'validate', result: { valid: boolean; message: string }): void
 }>()
 
@@ -152,12 +152,12 @@ const isValid = ref(true)
 const valueValidation = ref({ valid: true, message: '' })
 
 // 事件处理
-const updateConditionField = (field: keyof ConditionFormData, value: any) => {
+const updateConditionField = (field: keyof TriggerConditionFormData, value: any) => {
   ;(condition.value as any)[field] = value
   emit('update:modelValue', condition.value)
 }
 
-const updateCondition = (newCondition: ConditionFormData) => {
+const updateCondition = (newCondition: TriggerConditionFormData) => {
   condition.value = newCondition
   emit('update:modelValue', condition.value)
 }

+ 18 - 28
src/views/iot/rule/scene/form/configs/ConditionGroupContainerConfig.vue

@@ -14,16 +14,14 @@
           <span>附加条件组</span>
         </div>
         <el-tag size="small" type="success">与主条件为且关系</el-tag>
-        <el-tag size="small" type="info">
-          {{ modelValue.subGroups?.length || 0 }}个子条件组
-        </el-tag>
+        <el-tag size="small" type="info"> {{ modelValue?.length || 0 }}个子条件组 </el-tag>
       </div>
       <div class="flex items-center gap-8px">
         <el-button
           type="primary"
           size="small"
           @click="addSubGroup"
-          :disabled="(modelValue.subGroups?.length || 0) >= maxSubGroups"
+          :disabled="(modelValue?.length || 0) >= maxSubGroups"
         >
           <Icon icon="ep:plus" />
           添加子条件组
@@ -36,11 +34,11 @@
     </div>
 
     <!-- 子条件组列表 -->
-    <div v-if="modelValue.subGroups && modelValue.subGroups.length > 0" class="space-y-16px">
+    <div v-if="modelValue && modelValue.length > 0" class="space-y-16px">
       <!-- 逻辑关系说明 -->
       <div class="relative">
         <div
-          v-for="(subGroup, subGroupIndex) in modelValue.subGroups"
+          v-for="(subGroup, subGroupIndex) in modelValue"
           :key="`sub-group-${subGroupIndex}`"
           class="relative"
         >
@@ -88,7 +86,7 @@
 
           <!-- 子条件组间的"或"连接符 -->
           <div
-            v-if="subGroupIndex < modelValue.subGroups!.length - 1"
+            v-if="subGroupIndex < modelValue!.length - 1"
             class="flex items-center justify-center py-12px"
           >
             <div class="flex items-center gap-8px">
@@ -125,21 +123,17 @@
 <script setup lang="ts">
 import { useVModel } from '@vueuse/core'
 import SubConditionGroupConfig from './SubConditionGroupConfig.vue'
-import {
-  ConditionGroupContainerFormData,
-  SubConditionGroupFormData
-} from '@/api/iot/rule/scene/scene.types'
 
 /** 条件组容器配置组件 */
 defineOptions({ name: 'ConditionGroupContainerConfig' })
 
 const props = defineProps<{
-  modelValue: ConditionGroupContainerFormData
+  modelValue: any
   triggerType: number
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: ConditionGroupContainerFormData): void
+  (e: 'update:modelValue', value: any): void
   (e: 'validate', result: { valid: boolean; message: string }): void
   (e: 'remove'): void
 }>()
@@ -155,24 +149,20 @@ const subGroupValidations = ref<{ [key: number]: { valid: boolean; message: stri
 
 // 事件处理
 const addSubGroup = () => {
-  if (!container.value.subGroups) {
-    container.value.subGroups = []
+  if (!container.value) {
+    container.value = []
   }
 
-  if (container.value.subGroups.length >= maxSubGroups) {
+  if (container.value.length >= maxSubGroups) {
     return
   }
 
-  const newSubGroup: SubConditionGroupFormData = {
-    conditions: []
-  }
-
-  container.value.subGroups.push(newSubGroup)
+  container.value.push([])
 }
 
 const removeSubGroup = (index: number) => {
-  if (container.value.subGroups) {
-    container.value.subGroups.splice(index, 1)
+  if (container.value) {
+    container.value.splice(index, 1)
     delete subGroupValidations.value[index]
 
     // 重新索引验证结果
@@ -191,9 +181,9 @@ const removeSubGroup = (index: number) => {
   }
 }
 
-const updateSubGroup = (index: number, subGroup: SubConditionGroupFormData) => {
-  if (container.value.subGroups) {
-    container.value.subGroups[index] = subGroup
+const updateSubGroup = (index: number, subGroup: any) => {
+  if (container.value) {
+    container.value[index] = subGroup
   }
 }
 
@@ -207,7 +197,7 @@ const handleSubGroupValidate = (index: number, result: { valid: boolean; message
 }
 
 const updateValidationResult = () => {
-  if (!container.value.subGroups || container.value.subGroups.length === 0) {
+  if (!container.value || container.value.length === 0) {
     emit('validate', { valid: true, message: '条件组容器为空,验证通过' })
     return
   }
@@ -225,7 +215,7 @@ const updateValidationResult = () => {
 
 // 监听变化
 watch(
-  () => container.value.subGroups,
+  () => container.value,
   () => {
     updateValidationResult()
   },

+ 6 - 6
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 { ConditionFormData } from '@/api/iot/rule/scene/scene.types'
+import { TriggerConditionFormData } from '@/api/iot/rule/scene/scene.types'
 
 /** 设备状态条件配置组件 */
 defineOptions({ name: 'DeviceStatusConditionConfig' })
 
 const props = defineProps<{
-  modelValue: ConditionFormData
+  modelValue: TriggerConditionFormData
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: ConditionFormData): void
+  (e: 'update:modelValue', value: TriggerConditionFormData): void
   (e: 'validate', result: { valid: boolean; message: string }): void
 }>()
 
@@ -139,18 +139,18 @@ const validationMessage = ref('')
 const isValid = ref(true)
 
 // 事件处理
-const updateConditionField = (field: keyof ConditionFormData, value: any) => {
+const updateConditionField = (field: any, value: any) => {
   condition.value[field] = value
   updateValidationResult()
 }
 
-const handleProductChange = (productId: number) => {
+const handleProductChange = (_: number) => {
   // 产品变化时清空设备
   condition.value.deviceId = undefined
   updateValidationResult()
 }
 
-const handleDeviceChange = (deviceId: number) => {
+const handleDeviceChange = (_: number) => {
   // 设备变化时可以进行其他处理
   updateValidationResult()
 }

+ 19 - 53
src/views/iot/rule/scene/form/configs/DeviceTriggerConfig.vue

@@ -11,48 +11,14 @@
     </div>
 
     <!-- 条件组配置 -->
-    <div v-if="trigger.mainCondition" class="space-y-16px">
-      <div v-if="!trigger.conditionGroup" class="flex items-center justify-between">
-        <div class="flex items-center gap-8px">
-          <span class="text-14px font-500 text-[var(--el-text-color-primary)]">附加条件组</span>
-          <el-tag size="small" type="success">与主条件为且关系</el-tag>
-          <el-tag size="small" type="info">
-            {{ trigger.conditionGroup?.subGroups?.length || 0 }} 个子条件组
-          </el-tag>
-        </div>
-        <el-button
-          type="primary"
-          size="small"
-          @click="addConditionGroup"
-          v-if="!trigger.conditionGroup"
-        >
-          <Icon icon="ep:plus" />
-          添加条件组
-        </el-button>
-      </div>
-
+    <div class="space-y-16px">
       <!-- 条件组配置 -->
       <ConditionGroupContainerConfig
-        v-if="trigger.conditionGroup"
-        v-model="trigger.conditionGroup"
+        v-model="trigger.conditionGroups"
         :trigger-type="trigger.type"
         @validate="handleConditionGroupValidate"
         @remove="removeConditionGroup"
       />
-
-      <!-- 空状态 -->
-      <div v-else class="py-40px text-center">
-        <el-empty description="暂无触发条件">
-          <template #description>
-            <div class="space-y-8px">
-              <p class="text-[var(--el-text-color-secondary)]">暂无触发条件</p>
-              <p class="text-12px text-[var(--el-text-color-placeholder)]">
-                请使用上方的"添加条件组"按钮来设置触发规则
-              </p>
-            </div>
-          </template>
-        </el-empty>
-      </div>
     </div>
   </div>
 </template>
@@ -70,6 +36,7 @@ defineOptions({ name: 'DeviceTriggerConfig' })
 
 const props = defineProps<{
   modelValue: TriggerFormData
+  index: number
 }>()
 
 const emit = defineEmits<{
@@ -89,16 +56,17 @@ const isValid = ref(true)
 
 // 初始化主条件
 const initMainCondition = () => {
-  if (!trigger.value.mainCondition) {
-    trigger.value.mainCondition = {
-      type: trigger.value.type, // 使用触发事件类型作为条件类型
-      productId: undefined,
-      deviceId: undefined,
-      identifier: '',
-      operator: '=',
-      param: ''
-    }
-  }
+  // TODO @puhui999: 等到编辑回显时联调
+  // if (!trigger.value.mainCondition) {
+  //   trigger.value = {
+  //     type: trigger.value.type, // 使用触发事件类型作为条件类型
+  //     productId: undefined,
+  //     deviceId: undefined,
+  //     identifier: '',
+  //     operator: '=',
+  //     param: ''
+  //   }
+  // }
 }
 
 // 监听触发器类型变化,自动初始化主条件
@@ -110,18 +78,16 @@ watch(
   { immediate: true }
 )
 
-// 新的事件处理函数
 const handleMainConditionValidate = (result: { valid: boolean; message: string }) => {
   mainConditionValidation.value = result
   updateValidationResult()
 }
 
 const addConditionGroup = () => {
-  if (!trigger.value.conditionGroup) {
-    trigger.value.conditionGroup = {
-      subGroups: []
-    }
+  if (!trigger.value.conditionGroups) {
+    trigger.value.conditionGroups = []
   }
+  trigger.value.conditionGroups.push([])
 }
 
 // 事件处理
@@ -130,7 +96,7 @@ const handleConditionGroupValidate = () => {
 }
 
 const removeConditionGroup = () => {
-  trigger.value.conditionGroup = undefined
+  trigger.value.conditionGroups = undefined
 }
 
 const updateValidationResult = () => {
@@ -151,7 +117,7 @@ const updateValidationResult = () => {
   }
 
   // 主条件验证
-  if (!trigger.value.mainCondition) {
+  if (!trigger.value.value) {
     isValid.value = false
     validationMessage.value = '请配置主条件'
     emit('validate', { valid: false, message: validationMessage.value })

+ 19 - 30
src/views/iot/rule/scene/form/configs/SubConditionGroupConfig.vue

@@ -1,10 +1,7 @@
 <template>
   <div class="p-16px">
     <!-- 空状态 -->
-    <div
-      v-if="!subGroup.conditions || subGroup.conditions.length === 0"
-      class="text-center py-24px"
-    >
+    <div v-if="!subGroup || subGroup.length === 0" class="text-center py-24px">
       <div class="flex flex-col items-center gap-12px">
         <Icon icon="ep:plus" class="text-32px text-[var(--el-text-color-placeholder)]" />
         <div class="text-[var(--el-text-color-secondary)]">
@@ -21,7 +18,7 @@
     <!-- 条件列表 -->
     <div v-else class="space-y-16px">
       <div
-        v-for="(condition, conditionIndex) in subGroup.conditions"
+        v-for="(condition, conditionIndex) in subGroup"
         :key="`condition-${conditionIndex}`"
         class="relative"
       >
@@ -47,7 +44,7 @@
               size="small"
               text
               @click="removeCondition(conditionIndex)"
-              v-if="subGroup.conditions!.length > 1"
+              v-if="subGroup!.length > 1"
               class="hover:bg-red-50"
             >
               <Icon icon="ep:delete" />
@@ -67,11 +64,7 @@
 
       <!-- 添加条件按钮 -->
       <div
-        v-if="
-          subGroup.conditions &&
-          subGroup.conditions.length > 0 &&
-          subGroup.conditions.length < maxConditions
-        "
+        v-if="subGroup && subGroup.length > 0 && subGroup.length < maxConditions"
         class="text-center py-16px"
       >
         <el-button type="primary" plain @click="addCondition">
@@ -90,22 +83,21 @@
 import { useVModel } from '@vueuse/core'
 import ConditionConfig from './ConditionConfig.vue'
 import {
-  ConditionFormData,
   IotRuleSceneTriggerConditionTypeEnum,
-  SubConditionGroupFormData
+  TriggerConditionFormData
 } from '@/api/iot/rule/scene/scene.types'
 
 /** 子条件组配置组件 */
 defineOptions({ name: 'SubConditionGroupConfig' })
 
 const props = defineProps<{
-  modelValue: SubConditionGroupFormData
+  modelValue: TriggerConditionFormData[]
   triggerType: number
   maxConditions?: number
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: SubConditionGroupFormData): void
+  (e: 'update:modelValue', value: TriggerConditionFormData[]): void
   (e: 'validate', result: { valid: boolean; message: string }): void
 }>()
 
@@ -119,15 +111,13 @@ const conditionValidations = ref<{ [key: number]: { valid: boolean; message: str
 
 // 事件处理
 const addCondition = () => {
-  if (!subGroup.value.conditions) {
-    subGroup.value.conditions = []
+  if (!subGroup.value) {
+    subGroup.value = []
   }
-
-  if (subGroup.value.conditions.length >= maxConditions.value) {
+  if (subGroup.value.length >= maxConditions.value) {
     return
   }
-
-  const newCondition: ConditionFormData = {
+  const newCondition: TriggerConditionFormData = {
     type: IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY, // 默认为设备属性
     productId: undefined,
     deviceId: undefined,
@@ -135,13 +125,12 @@ const addCondition = () => {
     operator: '=',
     param: ''
   }
-
-  subGroup.value.conditions.push(newCondition)
+  subGroup.value.push(newCondition)
 }
 
 const removeCondition = (index: number) => {
-  if (subGroup.value.conditions) {
-    subGroup.value.conditions.splice(index, 1)
+  if (subGroup.value) {
+    subGroup.value.splice(index, 1)
     delete conditionValidations.value[index]
 
     // 重新索引验证结果
@@ -160,9 +149,9 @@ const removeCondition = (index: number) => {
   }
 }
 
-const updateCondition = (index: number, condition: ConditionFormData) => {
-  if (subGroup.value.conditions) {
-    subGroup.value.conditions[index] = condition
+const updateCondition = (index: number, condition: TriggerConditionFormData) => {
+  if (subGroup.value) {
+    subGroup.value[index] = condition
   }
 }
 
@@ -172,7 +161,7 @@ const handleConditionValidate = (index: number, result: { valid: boolean; messag
 }
 
 const updateValidationResult = () => {
-  if (!subGroup.value.conditions || subGroup.value.conditions.length === 0) {
+  if (!subGroup.value || subGroup.value.length === 0) {
     emit('validate', { valid: false, message: '子条件组至少需要一个条件' })
     return
   }
@@ -190,7 +179,7 @@ const updateValidationResult = () => {
 
 // 监听变化
 watch(
-  () => subGroup.value.conditions,
+  () => subGroup.value,
   () => {
     updateValidationResult()
   },

+ 10 - 31
src/views/iot/rule/scene/form/sections/TriggerSection.vue

@@ -67,6 +67,7 @@
           <DeviceTriggerConfig
             v-if="isDeviceTrigger(triggerItem.type)"
             :model-value="triggerItem"
+            :index="index"
             @update:model-value="(value) => updateTriggerDeviceConfig(index, value)"
           />
 
@@ -111,13 +112,12 @@ import {
 /** 触发器配置组件 */
 defineOptions({ name: 'TriggerSection' })
 
-// Props 和 Emits 定义
 const props = defineProps<{
   triggers: TriggerFormData[]
 }>()
 
 const emit = defineEmits<{
-  'update:triggers': [value: TriggerFormData[]]
+  (e: 'update:triggers', value: TriggerFormData[]): void
 }>()
 
 const triggers = useVModel(props, 'triggers', emit)
@@ -172,36 +172,15 @@ const updateTriggerCronConfig = (index: number, cronExpression?: string) => {
   triggers.value[index].cronExpression = cronExpression
 }
 
-const onTriggerTypeChange = (index: number, type: number) => {
+const onTriggerTypeChange = (index: number, _: number) => {
   const triggerItem = triggers.value[index]
-
-  // 清理不相关的配置
-  if (type === TriggerTypeEnum.TIMER) {
-    triggerItem.productId = undefined
-    triggerItem.deviceId = undefined
-    triggerItem.identifier = undefined
-    triggerItem.operator = undefined
-    triggerItem.value = undefined
-    triggerItem.mainCondition = undefined
-    triggerItem.conditionGroup = undefined
-    if (!triggerItem.cronExpression) {
-      triggerItem.cronExpression = '0 0 12 * * ?'
-    }
-  } else {
-    triggerItem.cronExpression = undefined
-    if (type === TriggerTypeEnum.DEVICE_STATE_UPDATE) {
-      triggerItem.mainCondition = undefined
-      triggerItem.conditionGroup = undefined
-    } else {
-      // 设备属性、事件、服务触发需要条件配置
-      if (!triggerItem.mainCondition) {
-        triggerItem.mainCondition = undefined // 等待用户配置
-      }
-      if (!triggerItem.conditionGroup) {
-        triggerItem.conditionGroup = undefined // 可选的条件组
-      }
-    }
-  }
+  triggerItem.productId = undefined
+  triggerItem.deviceId = undefined
+  triggerItem.identifier = undefined
+  triggerItem.operator = undefined
+  triggerItem.value = undefined
+  triggerItem.cronExpression = undefined
+  triggerItem.conditionGroups = []
 }
 
 // 初始化:确保至少有一个触发器

+ 1 - 1
src/views/iot/rule/scene/index.vue

@@ -270,7 +270,7 @@
     </div>
 
     <!-- 表单对话框 -->
-    <RuleSceneForm v-model="formVisible" :rule-scene="currentRule" @success="getList" />
+    <RuleSceneForm v-model="formVisible" @success="getList" />
   </ContentWrap>
 </template>