Просмотр исходного кода

perf: 【IoT 物联网】场景联动类型归纳优化,移除多余文件

puhui999 7 месяцев назад
Родитель
Сommit
a8adda7dc5

+ 42 - 1
src/api/iot/rule/scene/index.ts

@@ -1,5 +1,46 @@
 import request from '@/config/axios'
-import { IotSceneRule } from './scene.types'
+
+// 场景联动
+export interface IotSceneRule {
+  id?: number // 场景编号
+  name: string // 场景名称
+  description?: string // 场景描述
+  status: number // 场景状态:0-开启,1-关闭
+  triggers: Trigger[] // 触发器数组
+  actions: Action[] // 执行器数组
+}
+
+// 触发器结构
+export interface Trigger {
+  type: number // 触发类型
+  productId?: number // 产品编号
+  deviceId?: number // 设备编号
+  identifier?: string // 物模型标识符
+  operator?: string // 操作符
+  value?: string // 参数值
+  cronExpression?: string // CRON 表达式
+  conditionGroups?: TriggerCondition[][] // 条件组(二维数组)
+}
+
+// 触发条件结构
+export interface TriggerCondition {
+  type: number // 条件类型:1-设备状态,2-设备属性,3-当前时间
+  productId?: number // 产品编号
+  deviceId?: number // 设备编号
+  identifier?: string // 标识符
+  operator: string // 操作符
+  param: string // 参数
+}
+
+// 执行器结构
+export interface Action {
+  type: number // 执行类型
+  productId?: number // 产品编号
+  deviceId?: number // 设备编号
+  identifier?: string // 物模型标识符(服务调用时使用)
+  params?: string // 请求参数
+  alertConfigId?: number // 告警配置编号
+}
 
 // IoT 场景联动 API
 export const RuleSceneApi = {

+ 0 - 202
src/api/iot/rule/scene/scene.types.ts

@@ -1,202 +0,0 @@
-/**
- * IoT 场景联动接口定义
- */
-
-// ========== IoT物模型TSL数据类型定义 ==========
-
-// TODO @puhui999:看看有些是不是在别的模块已经定义了。物模型的
-
-/** 物模型TSL响应数据结构 */
-export interface IotThingModelTSLRespVO {
-  productId: number
-  productKey: string
-  properties: ThingModelProperty[]
-  events: ThingModelEvent[]
-  services: ThingModelService[]
-}
-
-/** 物模型属性 */
-export interface ThingModelProperty {
-  identifier: string
-  name: string
-  accessMode: string
-  required?: boolean
-  dataType: string
-  description?: string
-  dataSpecs?: ThingModelDataSpecs
-  dataSpecsList?: ThingModelDataSpecs[]
-}
-
-/** 物模型事件 */
-export interface ThingModelEvent {
-  identifier: string
-  name: string
-  required?: boolean
-  type: string
-  description?: string
-  outputParams?: ThingModelParam[]
-  method?: string
-}
-
-/** 物模型服务 */
-export interface ThingModelService {
-  identifier: string
-  name: string
-  required?: boolean
-  callType: string
-  description?: string
-  inputParams?: ThingModelParam[]
-  outputParams?: ThingModelParam[]
-  method?: string
-}
-
-/** 物模型参数 */
-export interface ThingModelParam {
-  identifier: string
-  name: string
-  direction: string
-  paraOrder?: number
-  dataType: string
-  dataSpecs?: ThingModelDataSpecs
-  dataSpecsList?: ThingModelDataSpecs[]
-}
-
-/** 数值型数据规范 */
-export interface ThingModelNumericDataSpec {
-  dataType: 'int' | 'float' | 'double'
-  max: string
-  min: string
-  step: string
-  precise?: string
-  defaultValue?: string
-  unit?: string
-  unitName?: string
-}
-
-/** 布尔/枚举型数据规范 */
-export interface ThingModelBoolOrEnumDataSpecs {
-  dataType: 'bool' | 'enum'
-  name: string
-  value: number
-}
-
-/** 文本/时间型数据规范 */
-export interface ThingModelDateOrTextDataSpecs {
-  dataType: 'text' | 'date'
-  length?: number
-  defaultValue?: string
-}
-
-/** 数组型数据规范 */
-export interface ThingModelArrayDataSpecs {
-  dataType: 'array'
-  size: number
-  childDataType: string
-  dataSpecsList?: ThingModelDataSpecs[]
-}
-
-/** 结构体型数据规范 */
-export interface ThingModelStructDataSpecs {
-  dataType: 'struct'
-  identifier: string
-  name: string
-  accessMode: string
-  required?: boolean
-  childDataType: string
-  dataSpecs?: ThingModelDataSpecs
-  dataSpecsList?: ThingModelDataSpecs[]
-}
-
-/** 数据规范联合类型 */
-export type ThingModelDataSpecs =
-  | ThingModelNumericDataSpec
-  | ThingModelBoolOrEnumDataSpecs
-  | ThingModelDateOrTextDataSpecs
-  | ThingModelArrayDataSpecs
-  | ThingModelStructDataSpecs
-
-/** 属性选择器内部使用的统一数据结构 */
-export interface PropertySelectorItem {
-  identifier: string
-  name: string
-  description?: string
-  dataType: string
-  type: number // IoTThingModelTypeEnum
-  accessMode?: string
-  required?: boolean
-  unit?: string
-  range?: string
-  eventType?: string
-  callType?: string
-  inputParams?: ThingModelParam[]
-  outputParams?: ThingModelParam[]
-  property?: ThingModelProperty
-  event?: ThingModelEvent
-  service?: ThingModelService
-}
-
-// ========== 场景联动规则相关接口定义 ==========
-
-// 后端 DO 接口 - 匹配后端数据结构
-interface IotSceneRule {
-  id?: number // 场景编号
-  name: string // 场景名称
-  description?: string // 场景描述
-  status: number // 场景状态:0-开启,1-关闭
-  triggers: Trigger[] // 触发器数组
-  actions: Action[] // 执行器数组
-}
-
-// 触发器 DO 结构
-interface Trigger {
-  type: number // 触发类型
-  productId?: number // 产品编号
-  deviceId?: number // 设备编号
-  identifier?: string // 物模型标识符
-  operator?: string // 操作符
-  value?: string // 参数值
-  cronExpression?: string // CRON 表达式
-  conditionGroups?: TriggerCondition[][] // 条件组(二维数组)
-}
-
-// 触发条件 DO 结构
-interface TriggerCondition {
-  type: number // 条件类型:1-设备状态,2-设备属性,3-当前时间
-  productId?: number // 产品编号
-  deviceId?: number // 设备编号
-  identifier?: string // 标识符
-  operator: string // 操作符
-  param: string // 参数
-}
-
-// 执行器 DO 结构
-interface Action {
-  type: number // 执行类型
-  productId?: number // 产品编号
-  deviceId?: number // 设备编号
-  identifier?: string // 物模型标识符(服务调用时使用)
-  params?: string // 请求参数
-  alertConfigId?: number // 告警配置编号
-}
-
-// 表单验证规则类型
-interface ValidationRule {
-  required?: boolean
-  message?: string
-  trigger?: string | string[]
-  type?: string
-  min?: number
-  max?: number
-  enum?: any[]
-}
-
-interface FormValidationRules {
-  [key: string]: ValidationRule[]
-}
-
-// 表单数据类型别名
-export type TriggerFormData = Trigger
-
-// TODO @puhui999:这个文件,目标最终没有哈,和别的模块一致;
-
-export { IotSceneRule, Trigger, TriggerCondition, Action, ValidationRule, FormValidationRules }

+ 103 - 2
src/api/iot/thingmodel/index.ts

@@ -40,7 +40,7 @@ export interface ThingModelService {
 }
 
 /** dataSpecs 数值型数据结构 */
-export interface DataSpecsNumberDataVO {
+export interface DataSpecsNumberData {
   dataType: 'int' | 'float' | 'double' // 数据类型,取值为 INT、FLOAT 或 DOUBLE
   max: string // 最大值,必须与 dataType 设置一致,且为 STRING 类型
   min: string // 最小值,必须与 dataType 设置一致,且为 STRING 类型
@@ -52,13 +52,114 @@ export interface DataSpecsNumberDataVO {
 }
 
 /** dataSpecs 枚举型数据结构 */
-export interface DataSpecsEnumOrBoolDataVO {
+export interface DataSpecsEnumOrBoolData {
   dataType: 'enum' | 'bool'
   defaultValue?: string // 默认值,可选
   name: string // 枚举项的名称
   value: number | undefined // 枚举值
 }
 
+/** 物模型TSL响应数据结构 */
+export interface IotThingModelTSLResp {
+  productId: number
+  productKey: string
+  properties: ThingModelProperty[]
+  events: ThingModelEvent[]
+  services: ThingModelService[]
+}
+
+/** 物模型属性 */
+export interface ThingModelProperty {
+  identifier: string
+  name: string
+  accessMode: string
+  required?: boolean
+  dataType: string
+  description?: string
+  dataSpecs?: ThingModelProperty
+  dataSpecsList?: ThingModelProperty[]
+}
+
+/** 物模型事件 */
+export interface ThingModelEvent {
+  identifier: string
+  name: string
+  required?: boolean
+  type: string
+  description?: string
+  outputParams?: ThingModelParam[]
+  method?: string
+}
+
+/** 物模型服务 */
+export interface ThingModelService {
+  identifier: string
+  name: string
+  required?: boolean
+  callType: string
+  description?: string
+  inputParams?: ThingModelParam[]
+  outputParams?: ThingModelParam[]
+  method?: string
+}
+
+/** 物模型参数 */
+export interface ThingModelParam {
+  identifier: string
+  name: string
+  direction: string
+  paraOrder?: number
+  dataType: string
+  dataSpecs?: ThingModelProperty
+  dataSpecsList?: ThingModelProperty[]
+}
+
+/** 数值型数据规范 */
+export interface ThingModelNumericDataSpec {
+  dataType: 'int' | 'float' | 'double'
+  max: string
+  min: string
+  step: string
+  precise?: string
+  defaultValue?: string
+  unit?: string
+  unitName?: string
+}
+
+/** 布尔/枚举型数据规范 */
+export interface ThingModelBoolOrEnumDataSpecs {
+  dataType: 'bool' | 'enum'
+  name: string
+  value: number
+}
+
+/** 文本/时间型数据规范 */
+export interface ThingModelDateOrTextDataSpecs {
+  dataType: 'text' | 'date'
+  length?: number
+  defaultValue?: string
+}
+
+/** 数组型数据规范 */
+export interface ThingModelArrayDataSpecs {
+  dataType: 'array'
+  size: number
+  childDataType: string
+  dataSpecsList?: ThingModelProperty[]
+}
+
+/** 结构体型数据规范 */
+export interface ThingModelStructDataSpecs {
+  dataType: 'struct'
+  identifier: string
+  name: string
+  accessMode: string
+  required?: boolean
+  childDataType: string
+  dataSpecs?: ThingModelProperty
+  dataSpecsList?: ThingModelProperty[]
+}
+
 // IoT 产品物模型 API
 export const ThingModelApi = {
   // 查询产品物模型分页

+ 1 - 1
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 { IotSceneRule } from '@/api/iot/rule/scene/scene.types'
+import { IotSceneRule } from '@/api/iot/rule/scene'
 import { RuleSceneApi } from '@/api/iot/rule/scene'
 import {
   IotRuleSceneTriggerTypeEnum,

+ 1 - 1
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 { TriggerCondition } from '@/api/iot/rule/scene/scene.types'
+import type { TriggerCondition } from '@/api/iot/rule/scene'
 import {
   IotRuleSceneTriggerConditionTypeEnum,
   IotRuleSceneTriggerConditionParameterOperatorEnum

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

@@ -94,17 +94,18 @@
 
 <script setup lang="ts">
 import { useVModel } from '@vueuse/core'
-import { ConditionFormData, IotRuleSceneTriggerTimeOperatorEnum } from '@/views/iot/utils/constants'
+import { IotRuleSceneTriggerTimeOperatorEnum } from '@/views/iot/utils/constants'
+import type { TriggerCondition } from '@/api/iot/rule/scene'
 
 /** 当前时间条件配置组件 */
 defineOptions({ name: 'CurrentTimeConditionConfig' })
 
 const props = defineProps<{
-  modelValue: ConditionFormData
+  modelValue: TriggerCondition
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: ConditionFormData): void
+  (e: 'update:modelValue', value: TriggerCondition): void
   (e: 'validate', result: { valid: boolean; message: string }): void
 }>()
 
@@ -178,7 +179,7 @@ const needsSecondTimeInput = computed(() => {
 })
 
 // 事件处理
-const updateConditionField = (field: keyof ConditionFormData, value: any) => {
+const updateConditionField = (field: keyof TriggerCondition, value: any) => {
   condition.value[field] = value
   updateValidationResult()
 }

+ 2 - 1
src/views/iot/rule/scene/form/configs/DeviceControlConfig.vue

@@ -82,7 +82,8 @@ import { useVModel } from '@vueuse/core'
 import ProductSelector from '../selectors/ProductSelector.vue'
 import DeviceSelector from '../selectors/DeviceSelector.vue'
 import JsonParamsInput from '../inputs/JsonParamsInput.vue'
-import { Action, ThingModelProperty, ThingModelService } from '@/api/iot/rule/scene/scene.types'
+import type { Action } from '@/api/iot/rule/scene'
+import type { ThingModelProperty, ThingModelService } from '@/api/iot/thingmodel'
 import {
   IotRuleSceneActionTypeEnum,
   IoTThingModelAccessModeEnum

+ 1 - 1
src/views/iot/rule/scene/form/configs/DeviceStatusConditionConfig.vue

@@ -84,7 +84,7 @@
 import { useVModel } from '@vueuse/core'
 import ProductSelector from '../selectors/ProductSelector.vue'
 import DeviceSelector from '../selectors/DeviceSelector.vue'
-import { TriggerCondition } from '@/api/iot/rule/scene/scene.types'
+import type { TriggerCondition } from '@/api/iot/rule/scene'
 
 /** 设备状态条件配置组件 */
 defineOptions({ name: 'DeviceStatusConditionConfig' })

+ 3 - 28
src/views/iot/rule/scene/form/configs/DeviceTriggerConfig.vue

@@ -27,49 +27,24 @@ import { useVModel } from '@vueuse/core'
 
 import MainConditionConfig from './MainConditionConfig.vue'
 import ConditionGroupContainerConfig from './ConditionGroupContainerConfig.vue'
-import { TriggerFormData } from '@/api/iot/rule/scene/scene.types'
-import { IotRuleSceneTriggerTypeEnum as TriggerTypeEnum } from '@/views/iot/utils/constants'
+import type { Trigger } from '@/api/iot/rule/scene'
 
 /** 设备触发配置组件 */
 defineOptions({ name: 'DeviceTriggerConfig' })
 
 const props = defineProps<{
-  modelValue: TriggerFormData
+  modelValue: Trigger
   index: number
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: TriggerFormData): void
+  (e: 'update:modelValue', value: Trigger): void
   (e: 'validate', value: { valid: boolean; message: string }): void
   (e: 'trigger-type-change', type: number): void
 }>()
 
 const trigger = useVModel(props, 'modelValue', emit)
 
-// 初始化主条件
-const initMainCondition = () => {
-  // TODO @puhui999: 等到编辑回显时联调
-  // if (!trigger.value.mainCondition) {
-  //   trigger.value = {
-  //     type: trigger.value.type, // 使用触发事件类型作为条件类型
-  //     productId: undefined,
-  //     deviceId: undefined,
-  //     identifier: '',
-  //     operator: '=',
-  //     param: ''
-  //   }
-  // }
-}
-
-// 监听触发器类型变化,自动初始化主条件
-watch(
-  () => trigger.value.type,
-  () => {
-    initMainCondition()
-  },
-  { immediate: true }
-)
-
 const handleTriggerTypeChange = (type: number) => {
   trigger.value.type = type
   emit('trigger-type-change', type)

+ 6 - 6
src/views/iot/rule/scene/form/configs/MainConditionConfig.vue

@@ -35,24 +35,24 @@
 
 <script setup lang="ts">
 import MainConditionInnerConfig from './MainConditionInnerConfig.vue'
-import { TriggerFormData } from '@/api/iot/rule/scene/scene.types'
-import { IotRuleSceneTriggerConditionTypeEnum } from '@/views/iot/utils/constants'
+import { Trigger } from '@/api/iot/rule/scene'
+
 /** 主条件配置组件 */
 defineOptions({ name: 'MainConditionConfig' })
 
-const props = defineProps<{
-  modelValue: TriggerFormData
+defineProps<{
+  modelValue: Trigger
   triggerType: number
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: TriggerFormData): void
+  (e: 'update:modelValue', value: Trigger): void
   (e: 'validate', result: { valid: boolean; message: string }): void
   (e: 'trigger-type-change', type: number): void
 }>()
 
 // 事件处理
-const updateCondition = (condition: TriggerFormData) => {
+const updateCondition = (condition: Trigger) => {
   emit('update:modelValue', condition)
 }
 

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

@@ -1,7 +1,6 @@
 <template>
   <div class="space-y-16px">
     <!-- 触发事件类型选择 -->
-    <!-- TODO @puhui999:事件上报时,应该也是 json? -->
     <el-form-item label="触发事件类型" required>
       <el-select
         :model-value="triggerType"
@@ -189,7 +188,7 @@ import OperatorSelector from '../selectors/OperatorSelector.vue'
 import ValueInput from '../inputs/ValueInput.vue'
 import JsonParamsInput from '../inputs/JsonParamsInput.vue'
 
-import { TriggerFormData } from '@/api/iot/rule/scene/scene.types'
+import type { Trigger } from '@/api/iot/rule/scene'
 import { IotRuleSceneTriggerTypeEnum, getTriggerTypeOptions } from '@/views/iot/utils/constants'
 import { useVModel } from '@vueuse/core'
 
@@ -197,12 +196,12 @@ import { useVModel } from '@vueuse/core'
 defineOptions({ name: 'MainConditionInnerConfig' })
 
 const props = defineProps<{
-  modelValue: TriggerFormData
+  modelValue: Trigger
   triggerType: number
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: TriggerFormData): void
+  (e: 'update:modelValue', value: Trigger): void
   (e: 'validate', result: { valid: boolean; message: string }): void
   (e: 'trigger-type-change', value: number): void
 }>()
@@ -278,7 +277,7 @@ const getTriggerTypeText = (type: number) => {
 const triggerTypeOptions = getTriggerTypeOptions()
 
 // 事件处理
-const updateConditionField = (field: keyof TriggerFormData, value: any) => {
+const updateConditionField = (field: keyof Trigger, value: any) => {
   ;(condition.value as any)[field] = value
   updateValidationResult()
 }

+ 1 - 1
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 { TriggerCondition } from '@/api/iot/rule/scene/scene.types'
+import type { TriggerCondition } from '@/api/iot/rule/scene'
 import {
   IotRuleSceneTriggerConditionTypeEnum,
   IotRuleSceneTriggerConditionParameterOperatorEnum

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

@@ -122,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 { Action } from '@/api/iot/rule/scene/scene.types'
+import type { Action } from '@/api/iot/rule/scene'
 import {
   IotRuleSceneActionTypeEnum as ActionTypeEnum,
   isDeviceAction,

+ 1 - 1
src/views/iot/rule/scene/form/sections/BasicInfoSection.vue

@@ -58,7 +58,7 @@
 <script setup lang="ts">
 import { useVModel } from '@vueuse/core'
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import { IotSceneRule } from '@/api/iot/rule/scene/scene.types'
+import type { IotSceneRule } from '@/api/iot/rule/scene'
 
 /** 基础信息配置组件 */
 defineOptions({ name: 'BasicInfoSection' })

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

@@ -96,7 +96,7 @@
 import { useVModel } from '@vueuse/core'
 import DeviceTriggerConfig from '../configs/DeviceTriggerConfig.vue'
 import TimerTriggerConfig from '../configs/TimerTriggerConfig.vue'
-import { TriggerFormData } from '@/api/iot/rule/scene/scene.types'
+import type { Trigger } from '@/api/iot/rule/scene'
 import {
   getTriggerTypeOptions,
   IotRuleSceneTriggerTypeEnum as TriggerTypeEnum,
@@ -108,11 +108,11 @@ import {
 defineOptions({ name: 'TriggerSection' })
 
 const props = defineProps<{
-  triggers: TriggerFormData[]
+  triggers: Trigger[]
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:triggers', value: TriggerFormData[]): void
+  (e: 'update:triggers', value: Trigger[]): void
 }>()
 
 const triggers = useVModel(props, 'triggers', emit)
@@ -136,7 +136,7 @@ const getTriggerTagType = (type: number): string => {
 
 // 事件处理函数
 const addTrigger = () => {
-  const newTrigger: TriggerFormData = {
+  const newTrigger: Trigger = {
     type: TriggerTypeEnum.DEVICE_STATE_UPDATE,
     productId: undefined,
     deviceId: undefined,
@@ -160,7 +160,7 @@ const updateTriggerType = (index: number, type: number) => {
   onTriggerTypeChange(index, type)
 }
 
-const updateTriggerDeviceConfig = (index: number, newTrigger: TriggerFormData) => {
+const updateTriggerDeviceConfig = (index: number, newTrigger: Trigger) => {
   triggers.value[index] = newTrigger
 }
 

+ 0 - 317
src/views/iot/rule/scene/form/selectors/ProductDeviceSelector.vue

@@ -1,317 +0,0 @@
-<!-- 产品设备选择器组件 -->
-<template>
-  <div class="product-device-selector">
-    <el-row :gutter="16">
-      <!-- 产品选择 -->
-      <el-col :span="12">
-        <el-form-item label="选择产品" required>
-          <el-select
-            v-model="localProductId"
-            placeholder="请选择产品"
-            filterable
-            clearable
-            @change="handleProductChange"
-            class="w-full"
-            :loading="productLoading"
-          >
-            <el-option
-              v-for="product in productList"
-              :key="product.id"
-              :label="product.name"
-              :value="product.id"
-            >
-              <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">
-                    {{ product.name }}
-                  </div>
-                  <div class="text-12px text-[var(--el-text-color-secondary)]">
-                    {{ product.productKey }}
-                  </div>
-                </div>
-                <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="product.status" />
-              </div>
-            </el-option>
-          </el-select>
-        </el-form-item>
-      </el-col>
-
-      <!-- 设备选择模式 -->
-      <el-col :span="12">
-        <el-form-item label="设备选择模式" required>
-          <el-radio-group
-            v-model="deviceSelectionMode"
-            @change="handleDeviceSelectionModeChange"
-            :disabled="!localProductId"
-          >
-            <el-radio value="all">全部设备</el-radio>
-            <el-radio value="specific">选择设备</el-radio>
-          </el-radio-group>
-          <div
-            v-if="!localProductId"
-            class="text-12px text-[var(--el-text-color-placeholder)] mt-4px"
-          >
-            请先选择产品
-          </div>
-        </el-form-item>
-      </el-col>
-    </el-row>
-
-    <!-- 具体设备选择 -->
-    <el-row v-if="deviceSelectionMode === 'specific'" :gutter="16">
-      <el-col :span="24">
-        <el-form-item label="选择设备" required>
-          <el-select
-            v-model="localDeviceId"
-            :placeholder="localProductId ? '请选择设备' : '请先选择产品'"
-            filterable
-            clearable
-            @change="handleDeviceChange"
-            class="w-full"
-            :loading="deviceLoading"
-            :disabled="!localProductId"
-          >
-            <el-option
-              v-for="device in deviceList"
-              :key="device.id"
-              :label="device.deviceName"
-              :value="device.id"
-            >
-              <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">
-                    {{ device.deviceName }}
-                  </div>
-                  <div class="text-12px text-[var(--el-text-color-secondary)]">
-                    {{ device.nickname || '无备注' }}
-                  </div>
-                </div>
-                <el-tag size="small" :type="getDeviceStatusTag(device.state)">
-                  {{ getDeviceStatusText(device.state) }}
-                </el-tag>
-              </div>
-            </el-option>
-          </el-select>
-        </el-form-item>
-      </el-col>
-    </el-row>
-
-    <!-- 选择结果展示 -->
-    <div
-      v-if="localProductId && localDeviceId !== undefined"
-      class="mt-16px p-12px bg-[var(--el-fill-color-light)] rounded-6px border border-[var(--el-border-color-lighter)]"
-    >
-      <div class="flex items-center gap-6px mb-8px">
-        <Icon icon="ep:check" class="text-[var(--el-color-success)] text-16px" />
-        <span class="text-14px font-500 text-[var(--el-text-color-primary)]">已选择设备</span>
-      </div>
-      <div class="flex flex-col gap-6px ml-22px">
-        <div class="flex items-center gap-8px">
-          <span class="text-12px text-[var(--el-text-color-secondary)] min-w-40px">产品:</span>
-          <span class="text-12px text-[var(--el-text-color-primary)] font-500">
-            {{ selectedProduct?.name }}
-          </span>
-          <el-tag size="small" type="primary">{{ selectedProduct?.productKey }}</el-tag>
-        </div>
-        <div class="flex items-center gap-8px">
-          <span class="text-12px text-[var(--el-text-color-secondary)] min-w-40px">设备:</span>
-          <span
-            v-if="deviceSelectionMode === 'all'"
-            class="text-12px text-[var(--el-text-color-primary)] font-500"
-            >全部设备</span
-          >
-          <span v-else class="text-12px text-[var(--el-text-color-primary)] font-500">
-            {{ selectedDevice?.deviceName }}
-          </span>
-          <el-tag v-if="deviceSelectionMode === 'all'" size="small" type="warning"> 全部</el-tag>
-          <el-tag v-else size="small" :type="getDeviceStatusTag(selectedDevice?.state)">
-            {{ getDeviceStatusText(selectedDevice?.state) }}
-          </el-tag>
-        </div>
-      </div>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { useVModel } from '@vueuse/core'
-import { ProductApi } from '@/api/iot/product/product'
-import { DeviceApi } from '@/api/iot/device/device'
-import { DICT_TYPE } from '@/utils/dict'
-
-/** 产品设备选择器组件 */
-defineOptions({ name: 'ProductDeviceSelector' })
-
-interface Props {
-  productId?: number
-  deviceId?: number
-}
-
-interface Emits {
-  (e: 'update:productId', value?: number): void
-  (e: 'update:deviceId', value?: number): void
-  (e: 'change', value: { productId?: number; deviceId?: number }): void
-}
-
-const props = defineProps<Props>()
-const emit = defineEmits<Emits>()
-
-const localProductId = useVModel(props, 'productId', emit)
-const localDeviceId = useVModel(props, 'deviceId', emit)
-
-// 设备选择模式
-// 默认选择具体设备,这样用户可以看到设备选择器
-const deviceSelectionMode = ref<'specific' | 'all'>('specific')
-
-// 数据状态
-const productLoading = ref(false)
-const deviceLoading = ref(false)
-const productList = ref<any[]>([])
-const deviceList = ref<any[]>([])
-
-// 计算属性
-const selectedProduct = computed(() => {
-  return productList.value.find((p) => p.id === localProductId.value)
-})
-
-const selectedDevice = computed(() => {
-  return deviceList.value.find((d) => d.id === localDeviceId.value)
-})
-
-// TODO @puhui999:字典下;
-// 设备状态映射
-const getDeviceStatusText = (state?: number) => {
-  switch (state) {
-    case 0:
-      return '未激活'
-    case 1:
-      return '在线'
-    case 2:
-      return '离线'
-    default:
-      return '未知'
-  }
-}
-
-const getDeviceStatusTag = (state?: number) => {
-  switch (state) {
-    case 0:
-      return 'info'
-    case 1:
-      return 'success'
-    case 2:
-      return 'danger'
-    default:
-      return 'info'
-  }
-}
-
-// TODO @puhui999:注释风格哈
-// 事件处理
-const handleProductChange = async (productId?: number) => {
-  localProductId.value = productId
-  localDeviceId.value = undefined
-  deviceList.value = []
-  if (productId) {
-    await getDeviceList(productId)
-  }
-  emitChange()
-}
-
-const handleDeviceChange = (deviceId?: number) => {
-  localDeviceId.value = deviceId
-  emitChange()
-}
-
-const handleDeviceSelectionModeChange = (mode: 'specific' | 'all') => {
-  deviceSelectionMode.value = mode
-  if (mode === 'all') {
-    // 全部设备时,设备 ID 设为 0
-    localDeviceId.value = 0
-  } else {
-    // 选择设备时,清空设备 ID
-    localDeviceId.value = undefined
-  }
-  emitChange()
-}
-
-const emitChange = () => {
-  emit('change', {
-    productId: localProductId.value,
-    deviceId: localDeviceId.value
-  })
-}
-
-// API 调用
-const getProductList = async () => {
-  productLoading.value = true
-  try {
-    const data = await ProductApi.getSimpleProductList()
-    productList.value = data || []
-  } catch (error) {
-    console.error('获取产品列表失败:', error)
-    // 模拟数据
-    // TODO @puhui999:移除下,不太合理
-    productList.value = [
-      { id: 1, name: '智能温度传感器', productKey: 'temp_sensor_001', status: 0 },
-      { id: 2, name: '智能空调控制器', productKey: 'ac_controller_001', status: 0 },
-      { id: 3, name: '智能门锁', productKey: 'smart_lock_001', status: 0 }
-    ]
-  } finally {
-    productLoading.value = false
-  }
-}
-
-const getDeviceList = async (productId: number) => {
-  deviceLoading.value = true
-  try {
-    const data = await DeviceApi.getSimpleDeviceList(undefined, productId)
-    deviceList.value = data || []
-  } catch (error) {
-    console.error('获取设备列表失败:', error)
-    // 模拟数据
-    // TODO @puhui999:移除下,不太合理
-    deviceList.value = [
-      { id: 1, deviceName: 'sensor_001', nickname: '客厅温度传感器', state: 1, productId },
-      { id: 2, deviceName: 'sensor_002', nickname: '卧室温度传感器', state: 2, productId },
-      { id: 3, deviceName: 'sensor_003', nickname: '厨房温度传感器', state: 1, productId }
-    ]
-  } finally {
-    deviceLoading.value = false
-  }
-}
-
-// 初始化
-onMounted(async () => {
-  await getProductList()
-
-  // 根据初始设备 ID 设置选择模式
-  if (localDeviceId.value === 0) {
-    deviceSelectionMode.value = 'all'
-  } else if (localDeviceId.value) {
-    deviceSelectionMode.value = 'specific'
-  }
-
-  if (localProductId.value) {
-    await getDeviceList(localProductId.value)
-  }
-})
-
-// 监听产品变化
-watch(
-  () => localProductId.value,
-  async (newProductId) => {
-    if (newProductId && deviceList.value.length === 0) {
-      await getDeviceList(newProductId)
-    }
-  }
-)
-// TODO @puhui999:是不是 unocss
-</script>
-
-<style scoped>
-:deep(.el-select-dropdown__item) {
-  height: auto;
-  padding: 8px 20px;
-}
-</style>

+ 28 - 2
src/views/iot/rule/scene/form/selectors/PropertySelector.vue

@@ -160,12 +160,38 @@
 import { useVModel } from '@vueuse/core'
 import { InfoFilled } from '@element-plus/icons-vue'
 import { IotRuleSceneTriggerTypeEnum, IoTThingModelTypeEnum } from '@/views/iot/utils/constants'
+import type {
+  IotThingModelTSLResp,
+  ThingModelEvent,
+  ThingModelParam,
+  ThingModelProperty,
+  ThingModelService
+} from '@/api/iot/thingmodel'
 import { ThingModelApi } from '@/api/iot/thingmodel'
-import type { IotThingModelTSLRespVO, PropertySelectorItem } from '@/api/iot/rule/scene/scene.types'
 
 /** 属性选择器组件 */
 defineOptions({ name: 'PropertySelector' })
 
+/** 属性选择器内部使用的统一数据结构 */
+export interface PropertySelectorItem {
+  identifier: string
+  name: string
+  description?: string
+  dataType: string
+  type: number // IoTThingModelTypeEnum
+  accessMode?: string
+  required?: boolean
+  unit?: string
+  range?: string
+  eventType?: string
+  callType?: string
+  inputParams?: ThingModelParam[]
+  outputParams?: ThingModelParam[]
+  property?: ThingModelProperty
+  event?: ThingModelEvent
+  service?: ThingModelService
+}
+
 const props = defineProps<{
   modelValue?: string
   triggerType: number
@@ -183,7 +209,7 @@ const localValue = useVModel(props, 'modelValue', emit)
 // 状态
 const loading = ref(false)
 const propertyList = ref<PropertySelectorItem[]>([])
-const thingModelTSL = ref<IotThingModelTSLRespVO | null>(null)
+const thingModelTSL = ref<IotThingModelTSLResp | null>(null)
 
 // 计算属性
 const propertyGroups = computed(() => {

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

@@ -239,7 +239,7 @@
 import { DICT_TYPE, getIntDictOptions, getDictLabel } from '@/utils/dict'
 import { ContentWrap } from '@/components/ContentWrap'
 import RuleSceneForm from './form/RuleSceneForm.vue'
-import { IotSceneRule } from '@/api/iot/rule/scene/scene.types'
+import { IotSceneRule } from '@/api/iot/rule/scene'
 import { RuleSceneApi } from '@/api/iot/rule/scene'
 import {
   IotRuleSceneTriggerTypeEnum,

+ 2 - 2
src/views/iot/thingmodel/dataSpecs/ThingModelEnumDataSpecs.vue

@@ -46,14 +46,14 @@
 import { useVModel } from '@vueuse/core'
 import { isEmpty } from '@/utils/is'
 import { IoTDataSpecsDataTypeEnum } from '@/views/iot/utils/constants'
-import { DataSpecsEnumOrBoolDataVO } from '@/api/iot/thingmodel'
+import { DataSpecsEnumOrBoolData } from '@/api/iot/thingmodel'
 
 /** 枚举型的 dataSpecs 配置组件 */
 defineOptions({ name: 'ThingModelEnumDataSpecs' })
 
 const props = defineProps<{ modelValue: any }>()
 const emits = defineEmits(['update:modelValue'])
-const dataSpecsList = useVModel(props, 'modelValue', emits) as Ref<DataSpecsEnumOrBoolDataVO[]>
+const dataSpecsList = useVModel(props, 'modelValue', emits) as Ref<DataSpecsEnumOrBoolData[]>
 const message = useMessage()
 
 /** 添加枚举项 */

+ 2 - 2
src/views/iot/thingmodel/dataSpecs/ThingModelNumberDataSpecs.vue

@@ -60,14 +60,14 @@
 <script lang="ts" setup>
 import { useVModel } from '@vueuse/core'
 import { DICT_TYPE, getStrDictOptions } from '@/utils/dict'
-import { DataSpecsNumberDataVO } from '@/api/iot/thingmodel'
+import { DataSpecsNumberData } from '@/api/iot/thingmodel'
 
 /** 数值型的 dataSpecs 配置组件 */
 defineOptions({ name: 'ThingModelNumberDataSpecs' })
 
 const props = defineProps<{ modelValue: any }>()
 const emits = defineEmits(['update:modelValue'])
-const dataSpecs = useVModel(props, 'modelValue', emits) as Ref<DataSpecsNumberDataVO>
+const dataSpecs = useVModel(props, 'modelValue', emits) as Ref<DataSpecsNumberData>
 
 /** 单位发生变化时触发 */
 const unitChange = (UnitSpecs: string) => {