Browse Source

perf: 【IoT 物联网】场景联动收拢常量定义

puhui999 9 months ago
parent
commit
93311f8bd7

+ 0 - 12
src/api/iot/device/device/index.ts

@@ -148,18 +148,6 @@ export const DeviceApi = {
     return await request.get({ url: `/iot/device/get-auth-info`, params: { id } })
     return await request.get({ url: `/iot/device/get-auth-info`, params: { id } })
   },
   },
 
 
-  // 根据 ProductKey 和 DeviceNames 获取设备列表
-  // TODO @puhui999:有没可能搞成基于 id 的查询哈?
-  getDevicesByProductKeyAndNames: async (productKey: string, deviceNames: string[]) => {
-    return await request.get({
-      url: `/iot/device/list-by-product-key-and-names`,
-      params: {
-        productKey,
-        deviceNames: deviceNames.join(',')
-      }
-    })
-  },
-
   // 查询设备消息分页
   // 查询设备消息分页
   getDeviceMessagePage: async (params: any) => {
   getDeviceMessagePage: async (params: any) => {
     return await request.get({ url: `/iot/device/message/page`, params })
     return await request.get({ url: `/iot/device/message/page`, params })

+ 0 - 1
src/views/iot/rule/data/sink/config/components/KeyValueEditor.vue

@@ -58,7 +58,6 @@ const updateModelValue = () => {
   emit('update:modelValue', result)
   emit('update:modelValue', result)
 }
 }
 
 
-// TODO @puhui999:有告警的地方,尽量用 cursor 处理下
 /** 监听项目变化 */
 /** 监听项目变化 */
 watch(items, updateModelValue, { deep: true })
 watch(items, updateModelValue, { deep: true })
 watch(
 watch(

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

@@ -13,7 +13,7 @@
             class="w-full"
             class="w-full"
           >
           >
             <el-option
             <el-option
-              v-for="option in conditionTypeOptions"
+              v-for="option in getConditionTypeOptions()"
               :key="option.value"
               :key="option.value"
               :label="option.label"
               :label="option.label"
               :value="option.value"
               :value="option.value"
@@ -47,7 +47,10 @@
     </el-row>
     </el-row>
 
 
     <!-- 设备状态条件配置 -->
     <!-- 设备状态条件配置 -->
-    <div v-if="condition.type === ConditionTypeEnum.DEVICE_STATUS" class="flex flex-col gap-16px">
+    <div
+      v-if="condition.type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_STATUS"
+      class="flex flex-col gap-16px"
+    >
       <!-- 状态和操作符选择 -->
       <!-- 状态和操作符选择 -->
       <el-row :gutter="16">
       <el-row :gutter="16">
         <!-- 操作符选择 -->
         <!-- 操作符选择 -->
@@ -60,7 +63,7 @@
               class="w-full"
               class="w-full"
             >
             >
               <el-option
               <el-option
-                v-for="option in statusOperatorOptions"
+                v-for="option in getStatusOperatorOptions()"
                 :key="option.value"
                 :key="option.value"
                 :label="option.label"
                 :label="option.label"
                 :value="option.value"
                 :value="option.value"
@@ -79,7 +82,7 @@
               class="w-full"
               class="w-full"
             >
             >
               <el-option
               <el-option
-                v-for="option in deviceStatusOptions"
+                v-for="option in getDeviceStatusOptions()"
                 :key="option.value"
                 :key="option.value"
                 :label="option.label"
                 :label="option.label"
                 :value="option.value"
                 :value="option.value"
@@ -91,13 +94,15 @@
     </div>
     </div>
 
 
     <!-- 设备属性条件配置 -->
     <!-- 设备属性条件配置 -->
-    <div v-else-if="condition.type === ConditionTypeEnum.DEVICE_PROPERTY" class="space-y-16px">
+    <div
+      v-else-if="condition.type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY"
+      class="space-y-16px"
+    >
       <!-- 属性配置 -->
       <!-- 属性配置 -->
       <el-row :gutter="16">
       <el-row :gutter="16">
         <!-- 属性/事件/服务选择 -->
         <!-- 属性/事件/服务选择 -->
         <el-col :span="6">
         <el-col :span="6">
           <el-form-item label="监控项" required>
           <el-form-item label="监控项" required>
-            <!-- TODO @puhui999:是不是不展示“整数”、“小数”这个类型,一行,只展示属性名 + 标识,更简洁一点;然后标识是 tag;因为已经有个 ? tip 了 -->
             <PropertySelector
             <PropertySelector
               :model-value="condition.identifier"
               :model-value="condition.identifier"
               @update:model-value="(value) => updateConditionField('identifier', value)"
               @update:model-value="(value) => updateConditionField('identifier', value)"
@@ -138,7 +143,7 @@
 
 
     <!-- 当前时间条件配置 -->
     <!-- 当前时间条件配置 -->
     <CurrentTimeConditionConfig
     <CurrentTimeConditionConfig
-      v-else-if="condition.type === ConditionTypeEnum.CURRENT_TIME"
+      v-else-if="condition.type === IotRuleSceneTriggerConditionTypeEnum.CURRENT_TIME"
       :model-value="condition"
       :model-value="condition"
       @update:model-value="updateCondition"
       @update:model-value="updateCondition"
     />
     />
@@ -156,7 +161,10 @@ import ValueInput from '../inputs/ValueInput.vue'
 import type { TriggerCondition } from '@/api/iot/rule/scene'
 import type { TriggerCondition } from '@/api/iot/rule/scene'
 import {
 import {
   IotRuleSceneTriggerConditionTypeEnum,
   IotRuleSceneTriggerConditionTypeEnum,
-  IotRuleSceneTriggerConditionParameterOperatorEnum
+  IotRuleSceneTriggerConditionParameterOperatorEnum,
+  getConditionTypeOptions,
+  getDeviceStatusOptions,
+  getStatusOperatorOptions
 } from '@/views/iot/utils/constants'
 } from '@/views/iot/utils/constants'
 
 
 /** 单个条件配置组件 */
 /** 单个条件配置组件 */
@@ -173,48 +181,6 @@ const emit = defineEmits<{
 
 
 const condition = useVModel(props, 'modelValue', emit)
 const condition = useVModel(props, 'modelValue', emit)
 
 
-// 常量定义
-const ConditionTypeEnum = IotRuleSceneTriggerConditionTypeEnum
-
-// 条件类型选项
-const conditionTypeOptions = [
-  {
-    value: IotRuleSceneTriggerConditionTypeEnum.DEVICE_STATUS,
-    label: '设备状态'
-  },
-  {
-    value: IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY,
-    label: '设备属性'
-  },
-  {
-    value: IotRuleSceneTriggerConditionTypeEnum.CURRENT_TIME,
-    label: '当前时间'
-  }
-]
-
-// 设备状态选项
-const deviceStatusOptions = [
-  {
-    value: 'online',
-    label: '在线'
-  },
-  {
-    value: 'offline',
-    label: '离线'
-  }
-]
-// 状态操作符选项
-const statusOperatorOptions = [
-  {
-    value: IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.value,
-    label: IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.name
-  },
-  {
-    value: IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS.value,
-    label: IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS.name
-  }
-]
-
 // 状态
 // 状态
 const propertyType = ref<string>('string')
 const propertyType = ref<string>('string')
 const propertyConfig = ref<any>(null)
 const propertyConfig = ref<any>(null)
@@ -222,8 +188,8 @@ const propertyConfig = ref<any>(null)
 // 计算属性:判断是否为设备相关条件
 // 计算属性:判断是否为设备相关条件
 const isDeviceCondition = computed(() => {
 const isDeviceCondition = computed(() => {
   return (
   return (
-    condition.value.type === ConditionTypeEnum.DEVICE_STATUS ||
-    condition.value.type === ConditionTypeEnum.DEVICE_PROPERTY
+    condition.value.type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_STATUS ||
+    condition.value.type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY
   )
   )
 })
 })
 
 
@@ -240,7 +206,7 @@ const updateCondition = (newCondition: TriggerCondition) => {
 
 
 const handleConditionTypeChange = (type: number) => {
 const handleConditionTypeChange = (type: number) => {
   // 清理不相关的字段
   // 清理不相关的字段
-  if (type === ConditionTypeEnum.DEVICE_STATUS) {
+  if (type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_STATUS) {
     condition.value.identifier = undefined
     condition.value.identifier = undefined
     // 清理时间相关字段(如果存在)
     // 清理时间相关字段(如果存在)
     if ('timeValue' in condition.value) {
     if ('timeValue' in condition.value) {
@@ -249,11 +215,11 @@ const handleConditionTypeChange = (type: number) => {
     if ('timeValue2' in condition.value) {
     if ('timeValue2' in condition.value) {
       delete (condition.value as any).timeValue2
       delete (condition.value as any).timeValue2
     }
     }
-  } else if (type === ConditionTypeEnum.CURRENT_TIME) {
+  } else if (type === IotRuleSceneTriggerConditionTypeEnum.CURRENT_TIME) {
     condition.value.identifier = undefined
     condition.value.identifier = undefined
     condition.value.productId = undefined
     condition.value.productId = undefined
     condition.value.deviceId = undefined
     condition.value.deviceId = undefined
-  } else if (type === ConditionTypeEnum.DEVICE_PROPERTY) {
+  } else if (type === IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY) {
     // 清理时间相关字段(如果存在)
     // 清理时间相关字段(如果存在)
     if ('timeValue' in condition.value) {
     if ('timeValue' in condition.value) {
       delete (condition.value as any).timeValue
       delete (condition.value as any).timeValue

+ 15 - 22
src/views/iot/rule/scene/form/configs/MainConditionInnerConfig.vue

@@ -157,8 +157,12 @@
               placeholder="请选择操作符"
               placeholder="请选择操作符"
               class="w-full"
               class="w-full"
             >
             >
-              <el-option label="变为在线" value="online" />
-              <el-option label="变为离线" value="offline" />
+              <el-option
+                v-for="option in deviceStatusChangeOptions"
+                :key="option.value"
+                :label="option.label"
+                :value="option.value"
+              />
             </el-select>
             </el-select>
           </el-form-item>
           </el-form-item>
         </el-col>
         </el-col>
@@ -168,7 +172,7 @@
     <!-- 其他触发类型的提示 -->
     <!-- 其他触发类型的提示 -->
     <div v-else class="text-center py-20px">
     <div v-else class="text-center py-20px">
       <p class="text-14px text-[var(--el-text-color-secondary)] mb-4px">
       <p class="text-14px text-[var(--el-text-color-secondary)] mb-4px">
-        当前触发事件类型:{{ getTriggerTypeText(triggerType) }}
+        当前触发事件类型:{{ getTriggerTypeLabel(triggerType) }}
       </p>
       </p>
       <p class="text-12px text-[var(--el-text-color-placeholder)]">
       <p class="text-12px text-[var(--el-text-color-placeholder)]">
         此触发类型暂不需要配置额外条件
         此触发类型暂不需要配置额外条件
@@ -186,7 +190,12 @@ import ValueInput from '../inputs/ValueInput.vue'
 import JsonParamsInput from '../inputs/JsonParamsInput.vue'
 import JsonParamsInput from '../inputs/JsonParamsInput.vue'
 
 
 import type { Trigger } from '@/api/iot/rule/scene'
 import type { Trigger } from '@/api/iot/rule/scene'
-import { IotRuleSceneTriggerTypeEnum, getTriggerTypeOptions } from '@/views/iot/utils/constants'
+import {
+  IotRuleSceneTriggerTypeEnum,
+  getTriggerTypeOptions,
+  getTriggerTypeLabel,
+  getDeviceStatusChangeOptions
+} from '@/views/iot/utils/constants'
 import { useVModel } from '@vueuse/core'
 import { useVModel } from '@vueuse/core'
 
 
 /** 主条件内部配置组件 */
 /** 主条件内部配置组件 */
@@ -249,25 +258,9 @@ const eventConfig = computed(() => {
   return undefined
   return undefined
 })
 })
 
 
-// 获取触发类型文本
-// TODO @puhui999:是不是有枚举可以服用哈;
-const getTriggerTypeText = (type: number) => {
-  switch (type) {
-    case IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST:
-      return '设备属性上报'
-    case IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST:
-      return '设备事件上报'
-    case IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE:
-      return '设备服务调用'
-    case IotRuleSceneTriggerTypeEnum.DEVICE_STATE_UPDATE:
-      return '设备状态变化'
-    default:
-      return '未知类型'
-  }
-}
-
-// 触发器类型选项
+// 使用标准化的选项获取函数
 const triggerTypeOptions = getTriggerTypeOptions()
 const triggerTypeOptions = getTriggerTypeOptions()
+const deviceStatusChangeOptions = getDeviceStatusChangeOptions()
 
 
 // 事件处理
 // 事件处理
 const updateConditionField = (field: keyof Trigger, value: any) => {
 const updateConditionField = (field: keyof Trigger, value: any) => {

+ 6 - 18
src/views/iot/rule/scene/form/sections/ActionSection.vue

@@ -45,7 +45,7 @@
               <Icon icon="ep:setting" class="text-[var(--el-color-success)] text-16px" />
               <Icon icon="ep:setting" class="text-[var(--el-color-success)] text-16px" />
               <span>执行器 {{ index + 1 }}</span>
               <span>执行器 {{ index + 1 }}</span>
               <el-tag :type="getActionTypeTag(action.type)" size="small">
               <el-tag :type="getActionTypeTag(action.type)" size="small">
-                {{ getActionTypeName(action.type) }}
+                {{ getActionTypeLabel(action.type) }}
               </el-tag>
               </el-tag>
             </div>
             </div>
             <div>
             <div>
@@ -139,7 +139,9 @@ import {
   isDeviceAction,
   isDeviceAction,
   isAlertAction,
   isAlertAction,
   getActionTypeLabel,
   getActionTypeLabel,
-  getActionTypeOptions
+  getActionTypeOptions,
+  getActionTypeTag,
+  SCENE_RULE_CONFIG
 } from '@/views/iot/utils/constants'
 } from '@/views/iot/utils/constants'
 
 
 /** 执行器配置组件 */
 /** 执行器配置组件 */
@@ -169,22 +171,8 @@ const createDefaultActionData = (): Action => {
   }
   }
 }
 }
 
 
-const maxActions = 5 // 最大执行器数量
-
-// 工具函数
-const getActionTypeName = (type: number) => {
-  return getActionTypeLabel(type)
-}
-
-const getActionTypeTag = (type: number) => {
-  const actionTypeTags = {
-    [ActionTypeEnum.DEVICE_PROPERTY_SET]: 'primary',
-    [ActionTypeEnum.DEVICE_SERVICE_INVOKE]: 'success',
-    [ActionTypeEnum.ALERT_TRIGGER]: 'danger',
-    [ActionTypeEnum.ALERT_RECOVER]: 'warning'
-  }
-  return actionTypeTags[type] || 'info'
-}
+// 使用标准化的常量和函数
+const maxActions = SCENE_RULE_CONFIG.MAX_ACTIONS
 
 
 /** 添加执行器 */
 /** 添加执行器 */
 const addAction = () => {
 const addAction = () => {

+ 2 - 19
src/views/iot/rule/scene/form/sections/TriggerSection.vue

@@ -118,9 +118,9 @@ import DeviceTriggerConfig from '../configs/DeviceTriggerConfig.vue'
 import { Crontab } from '@/components/Crontab'
 import { Crontab } from '@/components/Crontab'
 import type { Trigger } from '@/api/iot/rule/scene'
 import type { Trigger } from '@/api/iot/rule/scene'
 import {
 import {
-  getTriggerTypeOptions,
+  getTriggerTypeLabel,
+  getTriggerTagType,
   IotRuleSceneTriggerTypeEnum as TriggerTypeEnum,
   IotRuleSceneTriggerTypeEnum as TriggerTypeEnum,
-  IotRuleSceneTriggerTypeEnum,
   isDeviceTrigger
   isDeviceTrigger
 } from '@/views/iot/utils/constants'
 } from '@/views/iot/utils/constants'
 
 
@@ -137,23 +137,6 @@ const emit = defineEmits<{
 
 
 const triggers = useVModel(props, 'triggers', emit)
 const triggers = useVModel(props, 'triggers', emit)
 
 
-// 触发器类型选项(从 constants 中获取)
-const triggerTypeOptions = getTriggerTypeOptions()
-
-// 工具函数
-// TODO @puhui999:这里是不是重复了哈;
-const getTriggerTypeLabel = (type: number): string => {
-  const option = triggerTypeOptions.find((opt) => opt.value === type)
-  return option?.label || '未知类型'
-}
-
-const getTriggerTagType = (type: number): string => {
-  if (type === IotRuleSceneTriggerTypeEnum.TIMER) {
-    return 'warning'
-  }
-  return isDeviceTrigger(type) ? 'success' : 'info'
-}
-
 // 事件处理函数
 // 事件处理函数
 const addTrigger = () => {
 const addTrigger = () => {
   const newTrigger: Trigger = {
   const newTrigger: Trigger = {

+ 12 - 27
src/views/iot/rule/scene/form/selectors/DeviceSelector.vue

@@ -24,11 +24,11 @@
           <div class="text-12px text-[var(--el-text-color-secondary)]">{{ device.deviceKey }}</div>
           <div class="text-12px text-[var(--el-text-color-secondary)]">{{ device.deviceKey }}</div>
         </div>
         </div>
         <div class="flex items-center gap-4px">
         <div class="flex items-center gap-4px">
-          <el-tag size="small" :type="getStatusType(device.status)">
-            {{ getStatusText(device.status) }}
+          <el-tag size="small" :type="getDeviceEnableStatusTagType(device.status)">
+            {{ getDeviceEnableStatusText(device.status) }}
           </el-tag>
           </el-tag>
-          <el-tag size="small" :type="device.activeTime ? 'success' : 'info'">
-            {{ device.activeTime ? '已激活' : '未激活' }}
+          <el-tag size="small" :type="getDeviceActiveStatus(device.activeTime).tagType">
+            {{ getDeviceActiveStatus(device.activeTime).text }}
           </el-tag>
           </el-tag>
         </div>
         </div>
       </div>
       </div>
@@ -38,6 +38,12 @@
 
 
 <script setup lang="ts">
 <script setup lang="ts">
 import { DeviceApi } from '@/api/iot/device/device'
 import { DeviceApi } from '@/api/iot/device/device'
+import {
+  getDeviceEnableStatusText,
+  getDeviceEnableStatusTagType,
+  getDeviceActiveStatus,
+  DEVICE_SELECTOR_OPTIONS
+} from '@/views/iot/utils/constants'
 
 
 /** 设备选择器组件 */
 /** 设备选择器组件 */
 defineOptions({ name: 'DeviceSelector' })
 defineOptions({ name: 'DeviceSelector' })
@@ -77,33 +83,12 @@ const getDeviceList = async () => {
     console.error('获取设备列表失败:', error)
     console.error('获取设备列表失败:', error)
     deviceList.value = []
     deviceList.value = []
   } finally {
   } finally {
-    deviceList.value.push({ id: 0, deviceName: '全部设备' })
+    deviceList.value.push(DEVICE_SELECTOR_OPTIONS.ALL_DEVICES)
     deviceLoading.value = false
     deviceLoading.value = false
   }
   }
 }
 }
 
 
-// 设备状态映射
-const getStatusType = (status: number) => {
-  switch (status) {
-    case 0:
-      return 'success' // 正常
-    case 1:
-      return 'danger' // 禁用
-    default:
-      return 'info'
-  }
-}
-
-const getStatusText = (status: number) => {
-  switch (status) {
-    case 0:
-      return '正常'
-    case 1:
-      return '禁用'
-    default:
-      return '未知'
-  }
-}
+// 设备状态处理函数已从 constants.ts 中导入
 
 
 // 监听产品变化
 // 监听产品变化
 watch(
 watch(

+ 30 - 107
src/views/iot/rule/scene/form/selectors/PropertySelector.vue

@@ -18,20 +18,17 @@
           :label="property.name"
           :label="property.name"
           :value="property.identifier"
           :value="property.identifier"
         >
         >
-          <div class="flex items-center justify-between w-full py-4px">
-            <div class="flex-1">
-              <div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px">
-                {{ property.name }}
-              </div>
-              <div class="text-12px text-[var(--el-text-color-secondary)]">
-                {{ property.identifier }}
-              </div>
-            </div>
-            <div class="flex-shrink-0">
-              <el-tag :type="getPropertyTypeTag(property.dataType)" size="small">
-                {{ getPropertyTypeName(property.dataType) }}
-              </el-tag>
-            </div>
+          <div class="flex items-center justify-between w-full py-2px">
+            <span class="text-14px font-500 text-[var(--el-text-color-primary)] flex-1 truncate">
+              {{ property.name }}
+            </span>
+            <el-tag
+              :type="getDataTypeTagType(property.dataType)"
+              size="small"
+              class="ml-8px flex-shrink-0"
+            >
+              {{ property.identifier }}
+            </el-tag>
           </div>
           </div>
         </el-option>
         </el-option>
       </el-option-group>
       </el-option-group>
@@ -65,8 +62,8 @@
           <span class="text-14px font-500 text-[var(--el-text-color-primary)]">
           <span class="text-14px font-500 text-[var(--el-text-color-primary)]">
             {{ selectedProperty.name }}
             {{ selectedProperty.name }}
           </span>
           </span>
-          <el-tag :type="getPropertyTypeTag(selectedProperty.dataType)" size="small">
-            {{ getPropertyTypeName(selectedProperty.dataType) }}
+          <el-tag :type="getDataTypeTagType(selectedProperty.dataType)" size="small">
+            {{ getDataTypeName(selectedProperty.dataType) }}
           </el-tag>
           </el-tag>
         </div>
         </div>
 
 
@@ -119,7 +116,7 @@
               访问模式:
               访问模式:
             </span>
             </span>
             <span class="text-12px text-[var(--el-text-color-primary)] flex-1">
             <span class="text-12px text-[var(--el-text-color-primary)] flex-1">
-              {{ getAccessModeText(selectedProperty.accessMode) }}
+              {{ getAccessModeLabel(selectedProperty.accessMode) }}
             </span>
             </span>
           </div>
           </div>
 
 
@@ -133,7 +130,7 @@
               事件类型:
               事件类型:
             </span>
             </span>
             <span class="text-12px text-[var(--el-text-color-primary)] flex-1">
             <span class="text-12px text-[var(--el-text-color-primary)] flex-1">
-              {{ getEventTypeText(selectedProperty.eventType) }}
+              {{ getEventTypeLabel(selectedProperty.eventType) }}
             </span>
             </span>
           </div>
           </div>
 
 
@@ -147,7 +144,7 @@
               调用类型:
               调用类型:
             </span>
             </span>
             <span class="text-12px text-[var(--el-text-color-primary)] flex-1">
             <span class="text-12px text-[var(--el-text-color-primary)] flex-1">
-              {{ getCallTypeText(selectedProperty.callType) }}
+              {{ getThingModelServiceCallTypeLabel(selectedProperty.callType) }}
             </span>
             </span>
           </div>
           </div>
         </div>
         </div>
@@ -162,7 +159,12 @@ import { InfoFilled } from '@element-plus/icons-vue'
 import {
 import {
   IotRuleSceneTriggerTypeEnum,
   IotRuleSceneTriggerTypeEnum,
   IoTThingModelTypeEnum,
   IoTThingModelTypeEnum,
-  IoTDataSpecsDataTypeEnum
+  getAccessModeLabel,
+  getEventTypeLabel,
+  getThingModelServiceCallTypeLabel,
+  getDataTypeName,
+  getDataTypeTagType,
+  THING_MODEL_GROUP_LABELS
 } from '@/views/iot/utils/constants'
 } from '@/views/iot/utils/constants'
 import type {
 import type {
   IotThingModelTSLResp,
   IotThingModelTSLResp,
@@ -177,7 +179,7 @@ import { ThingModelApi } from '@/api/iot/thingmodel'
 defineOptions({ name: 'PropertySelector' })
 defineOptions({ name: 'PropertySelector' })
 
 
 /** 属性选择器内部使用的统一数据结构 */
 /** 属性选择器内部使用的统一数据结构 */
-export interface PropertySelectorItem {
+interface PropertySelectorItem {
   identifier: string
   identifier: string
   name: string
   name: string
   description?: string
   description?: string
@@ -221,21 +223,21 @@ const propertyGroups = computed(() => {
 
 
   if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST) {
   if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST) {
     groups.push({
     groups.push({
-      label: '设备属性',
+      label: THING_MODEL_GROUP_LABELS.PROPERTY,
       options: propertyList.value.filter((p) => p.type === IoTThingModelTypeEnum.PROPERTY)
       options: propertyList.value.filter((p) => p.type === IoTThingModelTypeEnum.PROPERTY)
     })
     })
   }
   }
 
 
   if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST) {
   if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST) {
     groups.push({
     groups.push({
-      label: '设备事件',
+      label: THING_MODEL_GROUP_LABELS.EVENT,
       options: propertyList.value.filter((p) => p.type === IoTThingModelTypeEnum.EVENT)
       options: propertyList.value.filter((p) => p.type === IoTThingModelTypeEnum.EVENT)
     })
     })
   }
   }
 
 
   if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE) {
   if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE) {
     groups.push({
     groups.push({
-      label: '设备服务',
+      label: THING_MODEL_GROUP_LABELS.SERVICE,
       options: propertyList.value.filter((p) => p.type === IoTThingModelTypeEnum.SERVICE)
       options: propertyList.value.filter((p) => p.type === IoTThingModelTypeEnum.SERVICE)
     })
     })
   }
   }
@@ -247,66 +249,6 @@ const selectedProperty = computed(() => {
   return propertyList.value.find((p) => p.identifier === localValue.value)
   return propertyList.value.find((p) => p.identifier === localValue.value)
 })
 })
 
 
-// 工具函数
-const getPropertyTypeName = (dataType: string) => {
-  const typeMap = {
-    [IoTDataSpecsDataTypeEnum.INT]: '整数',
-    [IoTDataSpecsDataTypeEnum.FLOAT]: '浮点数',
-    [IoTDataSpecsDataTypeEnum.DOUBLE]: '双精度',
-    [IoTDataSpecsDataTypeEnum.TEXT]: '字符串',
-    [IoTDataSpecsDataTypeEnum.BOOL]: '布尔值',
-    [IoTDataSpecsDataTypeEnum.ENUM]: '枚举',
-    [IoTDataSpecsDataTypeEnum.DATE]: '日期',
-    [IoTDataSpecsDataTypeEnum.STRUCT]: '结构体',
-    [IoTDataSpecsDataTypeEnum.ARRAY]: '数组'
-  }
-  return typeMap[dataType] || dataType
-}
-
-const getPropertyTypeTag = (dataType: string) => {
-  const tagMap = {
-    [IoTDataSpecsDataTypeEnum.INT]: 'primary',
-    [IoTDataSpecsDataTypeEnum.FLOAT]: 'success',
-    [IoTDataSpecsDataTypeEnum.DOUBLE]: 'success',
-    [IoTDataSpecsDataTypeEnum.TEXT]: 'info',
-    [IoTDataSpecsDataTypeEnum.BOOL]: 'warning',
-    [IoTDataSpecsDataTypeEnum.ENUM]: 'danger',
-    [IoTDataSpecsDataTypeEnum.DATE]: 'primary',
-    [IoTDataSpecsDataTypeEnum.STRUCT]: 'info',
-    [IoTDataSpecsDataTypeEnum.ARRAY]: 'warning'
-  }
-  return tagMap[dataType] || 'info'
-}
-
-// 工具函数 - 获取访问模式文本
-const getAccessModeText = (accessMode: string) => {
-  const modeMap = {
-    r: '只读',
-    w: '只写',
-    rw: '读写'
-  }
-  return modeMap[accessMode] || accessMode
-}
-
-// 工具函数 - 获取事件类型文本
-const getEventTypeText = (eventType: string) => {
-  const typeMap = {
-    info: '信息',
-    alert: '告警',
-    error: '故障'
-  }
-  return typeMap[eventType] || eventType
-}
-
-// 工具函数 - 获取调用类型文本
-const getCallTypeText = (callType: string) => {
-  const typeMap = {
-    sync: '同步',
-    async: '异步'
-  }
-  return typeMap[callType] || callType
-}
-
 // 事件处理
 // 事件处理
 const handleChange = (value: string) => {
 const handleChange = (value: string) => {
   const property = propertyList.value.find((p) => p.identifier === value)
   const property = propertyList.value.find((p) => p.identifier === value)
@@ -336,36 +278,17 @@ const getThingModelTSL = async () => {
       thingModelTSL.value = tslData
       thingModelTSL.value = tslData
       parseThingModelData()
       parseThingModelData()
     } else {
     } else {
-      // 如果TSL获取失败,尝试获取物模型列表
-      await getThingModelList()
+      console.error('获取物模型TSL失败: 返回数据为空')
+      propertyList.value = []
     }
     }
   } catch (error) {
   } catch (error) {
     console.error('获取物模型TSL失败:', error)
     console.error('获取物模型TSL失败:', error)
-    // 如果TSL获取失败,尝试获取物模型列表
-    await getThingModelList()
+    propertyList.value = []
   } finally {
   } finally {
     loading.value = false
     loading.value = false
   }
   }
 }
 }
 
 
-/**
- * 获取物模型列表(备用方案)
- */
-const getThingModelList = async () => {
-  if (!props.productId) {
-    propertyList.value = []
-    return
-  }
-
-  try {
-    const data = await ThingModelApi.getThingModelList({ productId: props.productId })
-    propertyList.value = data || []
-  } catch (error) {
-    console.error('获取物模型列表失败:', error)
-    propertyList.value = []
-  }
-}
-
 // 解析物模型TSL数据
 // 解析物模型TSL数据
 const parseThingModelData = () => {
 const parseThingModelData = () => {
   const tsl = thingModelTSL.value
   const tsl = thingModelTSL.value
@@ -484,7 +407,7 @@ watch(
 /* 下拉选项样式 */
 /* 下拉选项样式 */
 :deep(.el-select-dropdown__item) {
 :deep(.el-select-dropdown__item) {
   height: auto;
   height: auto;
-  padding: 8px 20px;
+  padding: 6px 20px;
 }
 }
 
 
 /* 弹出层内容样式 */
 /* 弹出层内容样式 */

+ 196 - 0
src/views/iot/utils/constants.ts

@@ -158,6 +158,47 @@ export const getDataTypeOptionsLabel = (value: string) => {
   return dataType && `${dataType.value}(${dataType.label})`
   return dataType && `${dataType.value}(${dataType.label})`
 }
 }
 
 
+/** 获取数据类型显示名称(用于属性选择器) */
+export const getDataTypeName = (dataType: string): string => {
+  const typeMap = {
+    [IoTDataSpecsDataTypeEnum.INT]: '整数',
+    [IoTDataSpecsDataTypeEnum.FLOAT]: '浮点数',
+    [IoTDataSpecsDataTypeEnum.DOUBLE]: '双精度',
+    [IoTDataSpecsDataTypeEnum.TEXT]: '字符串',
+    [IoTDataSpecsDataTypeEnum.BOOL]: '布尔值',
+    [IoTDataSpecsDataTypeEnum.ENUM]: '枚举',
+    [IoTDataSpecsDataTypeEnum.DATE]: '日期',
+    [IoTDataSpecsDataTypeEnum.STRUCT]: '结构体',
+    [IoTDataSpecsDataTypeEnum.ARRAY]: '数组'
+  }
+  return typeMap[dataType] || dataType
+}
+
+/** 获取数据类型标签类型(用于 el-tag 的 type 属性) */
+export const getDataTypeTagType = (
+  dataType: string
+): 'primary' | 'success' | 'info' | 'warning' | 'danger' => {
+  const tagMap = {
+    [IoTDataSpecsDataTypeEnum.INT]: 'primary',
+    [IoTDataSpecsDataTypeEnum.FLOAT]: 'success',
+    [IoTDataSpecsDataTypeEnum.DOUBLE]: 'success',
+    [IoTDataSpecsDataTypeEnum.TEXT]: 'info',
+    [IoTDataSpecsDataTypeEnum.BOOL]: 'warning',
+    [IoTDataSpecsDataTypeEnum.ENUM]: 'danger',
+    [IoTDataSpecsDataTypeEnum.DATE]: 'primary',
+    [IoTDataSpecsDataTypeEnum.STRUCT]: 'info',
+    [IoTDataSpecsDataTypeEnum.ARRAY]: 'warning'
+  } as const
+  return tagMap[dataType] || 'info'
+}
+
+/** 物模型组标签常量 */
+export const THING_MODEL_GROUP_LABELS = {
+  PROPERTY: '设备属性',
+  EVENT: '设备事件',
+  SERVICE: '设备服务'
+} as const
+
 // IoT OTA 任务设备范围枚举
 // IoT OTA 任务设备范围枚举
 export const IoTOtaTaskDeviceScopeEnum = {
 export const IoTOtaTaskDeviceScopeEnum = {
   ALL: {
   ALL: {
@@ -314,6 +355,26 @@ export const getActionTypeLabel = (type: number): string => {
   return option?.label || '未知类型'
   return option?.label || '未知类型'
 }
 }
 
 
+/** 获取执行器标签类型(用于 el-tag 的 type 属性) */
+export const getActionTypeTag = (
+  type: number
+): 'primary' | 'success' | 'info' | 'warning' | 'danger' => {
+  const actionTypeTags = {
+    [IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET]: 'primary',
+    [IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE]: 'success',
+    [IotRuleSceneActionTypeEnum.ALERT_TRIGGER]: 'danger',
+    [IotRuleSceneActionTypeEnum.ALERT_RECOVER]: 'warning'
+  } as const
+  return actionTypeTags[type] || 'info'
+}
+
+/** 场景联动规则配置常量 */
+export const SCENE_RULE_CONFIG = {
+  MAX_ACTIONS: 5, // 最大执行器数量
+  MAX_TRIGGERS: 10, // 最大触发器数量
+  MAX_CONDITIONS: 20 // 最大条件数量
+} as const
+
 /** IoT 设备消息类型枚举 */
 /** IoT 设备消息类型枚举 */
 export const IotDeviceMessageTypeEnum = {
 export const IotDeviceMessageTypeEnum = {
   PROPERTY: 'property', // 属性
   PROPERTY: 'property', // 属性
@@ -344,6 +405,131 @@ export const IotRuleSceneTriggerConditionTypeEnum = {
   CURRENT_TIME: 3 // 当前时间
   CURRENT_TIME: 3 // 当前时间
 } as const
 } as const
 
 
+/** 获取条件类型选项 */
+export const getConditionTypeOptions = () => [
+  {
+    value: IotRuleSceneTriggerConditionTypeEnum.DEVICE_STATUS,
+    label: '设备状态'
+  },
+  {
+    value: IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY,
+    label: '设备属性'
+  },
+  {
+    value: IotRuleSceneTriggerConditionTypeEnum.CURRENT_TIME,
+    label: '当前时间'
+  }
+]
+
+/** 设备状态枚举 */
+export const IoTDeviceStatusEnum = {
+  ONLINE: {
+    label: '在线',
+    value: 'online'
+  },
+  OFFLINE: {
+    label: '离线',
+    value: 'offline'
+  }
+} as const
+
+/** 设备启用状态枚举 */
+export const IoTDeviceEnableStatusEnum = {
+  ENABLED: {
+    label: '正常',
+    value: 0,
+    tagType: 'success'
+  },
+  DISABLED: {
+    label: '禁用',
+    value: 1,
+    tagType: 'danger'
+  }
+} as const
+
+/** 设备激活状态枚举 */
+export const IoTDeviceActiveStatusEnum = {
+  ACTIVATED: {
+    label: '已激活',
+    tagType: 'success'
+  },
+  NOT_ACTIVATED: {
+    label: '未激活',
+    tagType: 'info'
+  }
+} as const
+
+/** 设备选择器特殊选项 */
+export const DEVICE_SELECTOR_OPTIONS = {
+  ALL_DEVICES: {
+    id: 0,
+    deviceName: '全部设备'
+  }
+} as const
+
+/** 获取设备状态选项 */
+export const getDeviceStatusOptions = () => [
+  {
+    value: IoTDeviceStatusEnum.ONLINE.value,
+    label: IoTDeviceStatusEnum.ONLINE.label
+  },
+  {
+    value: IoTDeviceStatusEnum.OFFLINE.value,
+    label: IoTDeviceStatusEnum.OFFLINE.label
+  }
+]
+
+/** 获取状态操作符选项 */
+export const getStatusOperatorOptions = () => [
+  {
+    value: IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.value,
+    label: IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.name
+  },
+  {
+    value: IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS.value,
+    label: IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS.name
+  }
+]
+
+/** 获取设备状态变更选项(用于触发器配置) */
+export const getDeviceStatusChangeOptions = () => [
+  {
+    label: '变为在线',
+    value: IoTDeviceStatusEnum.ONLINE.value
+  },
+  {
+    label: '变为离线',
+    value: IoTDeviceStatusEnum.OFFLINE.value
+  }
+]
+
+/** 获取设备启用状态文本 */
+export const getDeviceEnableStatusText = (status: number): string => {
+  const statusItem = Object.values(IoTDeviceEnableStatusEnum).find((item) => item.value === status)
+  return statusItem?.label || '未知'
+}
+
+/** 获取设备启用状态标签类型 */
+export const getDeviceEnableStatusTagType = (
+  status: number
+): 'primary' | 'success' | 'info' | 'warning' | 'danger' => {
+  const statusItem = Object.values(IoTDeviceEnableStatusEnum).find((item) => item.value === status)
+  return statusItem?.tagType || 'info'
+}
+
+/** 获取设备激活状态文本和标签类型 */
+export const getDeviceActiveStatus = (activeTime?: string | null) => {
+  const isActivated = !!activeTime
+  return {
+    text: isActivated
+      ? IoTDeviceActiveStatusEnum.ACTIVATED.label
+      : IoTDeviceActiveStatusEnum.NOT_ACTIVATED.label,
+    tagType: isActivated
+      ? IoTDeviceActiveStatusEnum.ACTIVATED.tagType
+      : IoTDeviceActiveStatusEnum.NOT_ACTIVATED.tagType
+  }
+}
+
 /** IoT 场景联动触发时间操作符枚举 */
 /** IoT 场景联动触发时间操作符枚举 */
 export const IotRuleSceneTriggerTimeOperatorEnum = {
 export const IotRuleSceneTriggerTimeOperatorEnum = {
   BEFORE_TIME: { name: '在时间之前', value: 'before_time' }, // 在时间之前
   BEFORE_TIME: { name: '在时间之前', value: 'before_time' }, // 在时间之前
@@ -363,3 +549,13 @@ export const getTriggerTypeLabel = (type: number): string => {
   const option = options.find((item) => item.value === type)
   const option = options.find((item) => item.value === type)
   return option?.label || '未知类型'
   return option?.label || '未知类型'
 }
 }
+
+/** 获取触发器标签类型(用于 el-tag 的 type 属性) */
+export const getTriggerTagType = (
+  type: number
+): 'primary' | 'success' | 'info' | 'warning' | 'danger' => {
+  if (type === IotRuleSceneTriggerTypeEnum.TIMER) {
+    return 'warning'
+  }
+  return isDeviceTrigger(type) ? 'success' : 'info'
+}