Explorar o código

perf:【IoT 物联网】场景联动重构优化

puhui999 hai 10 meses
pai
achega
7f4d3d72f8

+ 0 - 192
src/views/iot/rule/scene/111index.vue

@@ -1,192 +0,0 @@
-<template>
-  <ContentWrap>
-    <!-- 搜索工作栏 -->
-    <el-form
-      class="-mb-15px"
-      :model="queryParams"
-      ref="queryFormRef"
-      :inline="true"
-      label-width="68px"
-    >
-      <el-form-item label="场景名称" prop="name">
-        <el-input
-          v-model="queryParams.name"
-          placeholder="请输入场景名称"
-          clearable
-          @keyup.enter="handleQuery"
-          class="!w-240px"
-        />
-      </el-form-item>
-      <el-form-item label="场景状态" prop="status">
-        <el-select
-          v-model="queryParams.status"
-          placeholder="请选择场景状态"
-          clearable
-          class="!w-240px"
-        >
-          <el-option
-            v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
-            :key="dict.value"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
-      </el-form-item>
-      <el-form-item label="创建时间" prop="createTime">
-        <el-date-picker
-          v-model="queryParams.createTime"
-          value-format="YYYY-MM-DD HH:mm:ss"
-          type="daterange"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
-          :default-time="[new Date('1 00:00:00'), new Date('1 23:59:59')]"
-          class="!w-220px"
-        />
-      </el-form-item>
-      <el-form-item>
-        <el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
-        <el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
-        <el-button
-          type="primary"
-          plain
-          @click="openForm('create')"
-          v-hasPermi="['iot:rule-scene:create']"
-        >
-          <Icon icon="ep:plus" class="mr-5px" /> 新增
-        </el-button>
-      </el-form-item>
-    </el-form>
-  </ContentWrap>
-
-  <!-- 列表 -->
-  <ContentWrap>
-    <el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
-      <el-table-column label="场景编号" align="center" prop="id" />
-      <el-table-column label="场景名称" align="center" prop="name" />
-      <el-table-column label="场景描述" align="center" prop="description" />
-      <el-table-column label="场景状态" align="center" prop="status">
-        <template #default="scope">
-          <dict-tag :type="DICT_TYPE.COMMON_STATUS" :value="scope.row.status" />
-        </template>
-      </el-table-column>
-      <el-table-column label="触发器" align="center" prop="triggers">
-        <template #default="{ row }"> {{ row.triggers?.length }}个 </template>
-      </el-table-column>
-      <el-table-column label="执行器" align="center" prop="actions">
-        <template #default="{ row }"> {{ row.actions?.length }}个 </template>
-      </el-table-column>
-      <el-table-column
-        label="创建时间"
-        align="center"
-        prop="createTime"
-        :formatter="dateFormatter"
-        width="180px"
-      />
-      <el-table-column label="操作" align="center" min-width="120px">
-        <template #default="scope">
-          <el-button
-            link
-            type="primary"
-            @click="openForm('update', scope.row.id)"
-            v-hasPermi="['iot:rule-scene:update']"
-          >
-            编辑
-          </el-button>
-          <el-button
-            link
-            type="danger"
-            @click="handleDelete(scope.row.id)"
-            v-hasPermi="['iot:rule-scene:delete']"
-          >
-            删除
-          </el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-    <!-- 分页 -->
-    <Pagination
-      :total="total"
-      v-model:page="queryParams.pageNo"
-      v-model:limit="queryParams.pageSize"
-      @pagination="getList"
-    />
-  </ContentWrap>
-
-  <!-- 表单弹窗:添加/修改 -->
-  <RuleSceneForm ref="formRef" @success="getList" />
-</template>
-
-<script setup lang="ts">
-import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import { dateFormatter } from '@/utils/formatTime'
-import { RuleSceneApi } from '@/api/iot/rule/scene'
-import RuleSceneForm from './RuleSceneForm.vue'
-import { IotRuleScene } from '@/api/iot/rule/scene/scene.types'
-
-/** IoT 场景联动 列表 */
-defineOptions({ name: 'IotRuleScene' })
-
-const message = useMessage() // 消息弹窗
-const { t } = useI18n() // 国际化
-
-const loading = ref(true) // 列表的加载中
-const list = ref<IotRuleScene[]>([]) // 列表的数据
-const total = ref(0) // 列表的总页数
-const queryParams = reactive({
-  pageNo: 1,
-  pageSize: 10,
-  name: undefined,
-  description: undefined,
-  status: undefined,
-  createTime: []
-})
-const queryFormRef = ref() // 搜索的表单
-
-/** 查询列表 */
-const getList = async () => {
-  loading.value = true
-  try {
-    const data = await RuleSceneApi.getRuleScenePage(queryParams)
-    list.value = data.list
-    total.value = data.total
-  } finally {
-    loading.value = false
-  }
-}
-
-/** 搜索按钮操作 */
-const handleQuery = () => {
-  queryParams.pageNo = 1
-  getList()
-}
-
-/** 重置按钮操作 */
-const resetQuery = () => {
-  queryFormRef.value.resetFields()
-  handleQuery()
-}
-
-/** 添加/修改操作 */
-const formRef = ref()
-const openForm = (type: string, id?: number) => {
-  formRef.value.open(type, id)
-}
-
-/** 删除按钮操作 */
-const handleDelete = async (id: number) => {
-  try {
-    // 删除的二次确认
-    await message.delConfirm()
-    // 发起删除
-    await RuleSceneApi.deleteRuleScene(id)
-    message.success(t('common.delSuccess'))
-    // 刷新列表
-    await getList()
-  } catch {}
-}
-
-/** 初始化 **/
-onMounted(() => {
-  getList()
-})
-</script>

+ 0 - 224
src/views/iot/rule/scene/RuleSceneForm.vue

@@ -1,224 +0,0 @@
-<template>
-  <Dialog :title="dialogTitle" v-model="dialogVisible" width="1080px">
-    <el-form
-      ref="formRef"
-      :model="formData"
-      :rules="formRules"
-      label-width="100px"
-      v-loading="formLoading"
-    >
-      <el-row>
-        <el-col :span="12">
-          <el-form-item label="场景名称" prop="name">
-            <el-input v-model="formData.name" placeholder="请输入场景名称" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="12">
-          <el-form-item label="场景状态" prop="status">
-            <el-radio-group v-model="formData.status">
-              <el-radio
-                v-for="dict in getIntDictOptions(DICT_TYPE.COMMON_STATUS)"
-                :key="dict.value"
-                :value="dict.value"
-              >
-                {{ dict.label }}
-              </el-radio>
-            </el-radio-group>
-          </el-form-item>
-        </el-col>
-        <el-col :span="24">
-          <el-form-item label="场景描述" prop="description">
-            <el-input v-model="formData.description" type="textarea" placeholder="请输入场景描述" />
-          </el-form-item>
-        </el-col>
-        <el-col :span="24">
-          <el-divider content-position="left">触发器配置</el-divider>
-          <!-- 根据触发类型选择不同的监听器组件 -->
-          <template v-for="(trigger, index) in formData.triggers" :key="trigger.key">
-            <!-- 设备状态变更和定时触发使用简化的监听器 -->
-            <device-state-listener
-              v-if="
-                trigger.type === IotRuleSceneTriggerTypeEnum.DEVICE_STATE_UPDATE ||
-                trigger.type === IotRuleSceneTriggerTypeEnum.TIMER
-              "
-              :model-value="trigger"
-              @update:model-value="(val) => (formData.triggers[index] = val)"
-              class="mb-10px"
-            >
-              <el-button type="danger" round size="small" @click="removeTrigger(index)">
-                <Icon icon="ep:delete" />
-              </el-button>
-            </device-state-listener>
-
-            <!-- 其他设备触发类型使用完整的监听器 -->
-            <device-listener
-              v-else
-              :model-value="trigger"
-              @update:model-value="(val) => (formData.triggers[index] = val)"
-              class="mb-10px"
-            >
-              <el-button type="danger" round size="small" @click="removeTrigger(index)">
-                <Icon icon="ep:delete" />
-              </el-button>
-            </device-listener>
-          </template>
-
-          <el-button class="ml-10px!" type="primary" size="small" @click="addTrigger">
-            添加触发器
-          </el-button>
-        </el-col>
-        <el-col :span="24">
-          <el-divider content-position="left">执行器配置</el-divider>
-          <action-executor
-            v-for="(action, index) in formData.actions"
-            :key="action.key"
-            :model-value="action"
-            @update:model-value="(val) => (formData.actions[index] = val)"
-            class="mb-10px"
-          >
-            <el-button type="danger" round size="small" @click="removeAction(index)">
-              <Icon icon="ep:delete" />
-            </el-button>
-          </action-executor>
-          <el-button class="ml-10px!" type="primary" size="small" @click="addAction">
-            添加执行器
-          </el-button>
-        </el-col>
-      </el-row>
-    </el-form>
-    <template #footer>
-      <el-button @click="submitForm" type="primary" :disabled="formLoading">确 定</el-button>
-      <el-button @click="dialogVisible = false">取 消</el-button>
-    </template>
-  </Dialog>
-</template>
-<script setup lang="ts">
-import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import { RuleSceneApi } from '@/api/iot/rule/scene'
-import DeviceListener from './components/listener/DeviceListener.vue'
-import DeviceStateListener from './components/listener/DeviceStateListener.vue'
-import { CommonStatusEnum } from '@/utils/constants'
-import {
-  ActionConfig,
-  IotDeviceMessageIdentifierEnum,
-  IotDeviceMessageTypeEnum,
-  IotRuleScene,
-  IotRuleSceneActionTypeEnum,
-  IotRuleSceneTriggerTypeEnum,
-  TriggerConfig
-} from '@/api/iot/rule/scene/scene.types'
-import ActionExecutor from './components/action/ActionExecutor.vue'
-import { generateUUID } from '@/utils'
-
-/** IoT 场景联动表单 */
-defineOptions({ name: 'IotRuleSceneForm' })
-
-const { t } = useI18n() // 国际化
-const message = useMessage() // 消息弹窗
-
-const dialogVisible = ref(false) // 弹窗的是否展示
-const dialogTitle = ref('') // 弹窗的标题
-const formLoading = ref(false) // 表单的加载中:1)修改时的数据加载;2)提交的按钮禁用
-const formType = ref('') // 表单的类型:create - 新增;update - 修改
-const formData = ref<IotRuleScene>({
-  status: CommonStatusEnum.ENABLE,
-  triggers: [] as TriggerConfig[],
-  actions: [] as ActionConfig[]
-} as IotRuleScene)
-const formRules = reactive({
-  name: [{ required: true, message: '场景名称不能为空', trigger: 'blur' }],
-  status: [{ required: true, message: '场景状态不能为空', trigger: 'blur' }],
-  triggers: [{ required: true, message: '触发器数组不能为空', trigger: 'blur' }],
-  actions: [{ required: true, message: '执行器数组不能为空', trigger: 'blur' }]
-})
-const formRef = ref() // 表单 Ref
-
-/** 添加触发器 */
-const addTrigger = () => {
-  formData.value.triggers.push({
-    key: generateUUID(), // 解决组件索引重用
-    type: IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST, // 默认为物模型属性上报
-    productKey: '',
-    deviceNames: [],
-    conditions: [
-      {
-        type: IotDeviceMessageTypeEnum.PROPERTY,
-        identifier: IotDeviceMessageIdentifierEnum.PROPERTY_SET,
-        parameters: []
-      }
-    ]
-  })
-}
-/** 移除触发器 */
-const removeTrigger = (index: number) => {
-  formData.value.triggers.splice(index, 1)
-}
-
-/** 添加执行器 */
-const addAction = () => {
-  formData.value.actions.push({
-    key: generateUUID(), // 解决组件索引重用
-    type: IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET
-  } as ActionConfig)
-}
-/** 移除执行器 */
-const removeAction = (index: number) => {
-  formData.value.actions.splice(index, 1)
-}
-
-/** 打开弹窗 */
-const open = async (type: string, id?: number) => {
-  dialogVisible.value = true
-  dialogTitle.value = t('action.' + type)
-  formType.value = type
-  resetForm()
-  // 修改时,设置数据
-  if (id) {
-    formLoading.value = true
-    try {
-      const data = (await RuleSceneApi.getRuleScene(id)) as IotRuleScene
-      // 解决组件索引重用
-      data.triggers?.forEach((item) => (item.key = generateUUID()))
-      data.actions?.forEach((item) => (item.key = generateUUID()))
-      formData.value = data
-    } finally {
-      formLoading.value = false
-    }
-  }
-}
-defineExpose({ open }) // 提供 open 方法,用于打开弹窗
-
-/** 提交表单 */
-const emit = defineEmits(['success']) // 定义 success 事件,用于操作成功后的回调
-const submitForm = async () => {
-  // 校验表单
-  await formRef.value.validate()
-  // 提交请求
-  formLoading.value = true
-  try {
-    const data = formData.value as unknown as IotRuleScene
-    if (formType.value === 'create') {
-      await RuleSceneApi.createRuleScene(data)
-      message.success(t('common.createSuccess'))
-    } else {
-      await RuleSceneApi.updateRuleScene(data)
-      message.success(t('common.updateSuccess'))
-    }
-    dialogVisible.value = false
-    // 发送操作成功的事件
-    emit('success')
-  } finally {
-    formLoading.value = false
-  }
-}
-
-/** 重置表单 */
-const resetForm = () => {
-  formData.value = {
-    status: CommonStatusEnum.ENABLE,
-    triggers: [] as TriggerConfig[],
-    actions: [] as ActionConfig[]
-  } as IotRuleScene
-  formRef.value?.resetFields()
-}
-</script>

+ 29 - 42
src/views/iot/rule/scene/components/RuleSceneForm.vue

@@ -19,22 +19,13 @@
         class="form-container"
       >
         <!-- 基础信息配置 -->
-        <BasicInfoSection
-          v-model="formData"
-          :rules="formRules"
-        />
+        <BasicInfoSection v-model="formData" :rules="formRules" />
 
         <!-- 触发器配置 -->
-        <TriggerSection
-          v-model:triggers="formData.triggers"
-          @validate="handleTriggerValidate"
-        />
+        <TriggerSection v-model:triggers="formData.triggers" @validate="handleTriggerValidate" />
 
         <!-- 执行器配置 -->
-        <ActionSection
-          v-model:actions="formData.actions"
-          @validate="handleActionValidate"
-        />
+        <ActionSection v-model:actions="formData.actions" @validate="handleActionValidate" />
 
         <!-- 预览区域 -->
         <PreviewSection
@@ -71,17 +62,8 @@ import ActionSection from './sections/ActionSection.vue'
 import PreviewSection from './sections/PreviewSection.vue'
 import { RuleSceneFormData, IotRuleScene } from '@/api/iot/rule/scene/scene.types'
 import { getBaseValidationRules } from '../utils/validation'
-import { 
-  transformFormToApi, 
-  transformApiToForm, 
-  createDefaultFormData 
-} from '../utils/transform'
-import { 
-  handleValidationError, 
-  handleNetworkError, 
-  showSuccess, 
-  withErrorHandling 
-} from '../utils/errorHandler'
+import { transformFormToApi, transformApiToForm, createDefaultFormData } from '../utils/transform'
+import { handleValidationError, showSuccess, withErrorHandling } from '../utils/errorHandler'
 
 /** IoT场景联动规则表单 - 主表单组件 */
 defineOptions({ name: 'RuleSceneForm' })
@@ -114,14 +96,16 @@ const actionValidation = ref({ valid: true, message: '' })
 
 // 计算属性
 const isEdit = computed(() => !!props.ruleScene?.id)
-const drawerTitle = computed(() => isEdit.value ? '编辑场景联动规则' : '新增场景联动规则')
+const drawerTitle = computed(() => (isEdit.value ? '编辑场景联动规则' : '新增场景联动规则'))
 
 const canSubmit = computed(() => {
-  return formData.value.name && 
-         formData.value.triggers.length > 0 && 
-         formData.value.actions.length > 0 &&
-         triggerValidation.value.valid &&
-         actionValidation.value.valid
+  return (
+    formData.value.name &&
+    formData.value.triggers.length > 0 &&
+    formData.value.actions.length > 0 &&
+    triggerValidation.value.valid &&
+    actionValidation.value.valid
+  )
 })
 
 // 事件处理
@@ -136,15 +120,15 @@ const handleActionValidate = (result: { valid: boolean; message: string }) => {
 const handleValidate = async () => {
   try {
     await formRef.value?.validate()
-    
+
     if (!triggerValidation.value.valid) {
       throw new Error(triggerValidation.value.message)
     }
-    
+
     if (!actionValidation.value.valid) {
       throw new Error(actionValidation.value.message)
     }
-    
+
     validationResult.value = { valid: true, message: '验证通过' }
     showSuccess('规则验证通过')
     return true
@@ -164,16 +148,16 @@ const handleSubmit = async () => {
       if (!isValid) {
         throw new Error('表单验证失败')
       }
-      
+
       // 转换数据格式
       const apiData = transformFormToApi(formData.value)
-      
+
       // 这里应该调用API保存数据
       console.log('提交数据:', apiData)
-      
+
       // 模拟API调用
-      await new Promise(resolve => setTimeout(resolve, 1000))
-      
+      await new Promise((resolve) => setTimeout(resolve, 1000))
+
       return apiData
     },
     {
@@ -184,7 +168,7 @@ const handleSubmit = async () => {
       successMessage: isEdit.value ? '更新成功' : '创建成功'
     }
   )
-  
+
   if (result) {
     emit('success')
     handleClose()
@@ -216,11 +200,14 @@ watch(drawerVisible, (visible) => {
 })
 
 // 监听props变化
-watch(() => props.ruleScene, () => {
-  if (drawerVisible.value) {
-    initFormData()
+watch(
+  () => props.ruleScene,
+  () => {
+    if (drawerVisible.value) {
+      initFormData()
+    }
   }
-})
+)
 </script>
 
 <style scoped>

+ 0 - 81
src/views/iot/rule/scene/components/ThingModelDualView.vue

@@ -1,81 +0,0 @@
-<template>
-  <Dialog v-model="dialogVisible" :title="dialogTitle" :appendToBody="true" v-loading="loading">
-    <div class="flex h-600px">
-      <!-- 左侧物模型属性(view 模式) -->
-      <div class="w-1/2 border-r border-gray-200 pr-2 overflow-auto">
-        <JsonEditor :model-value="thingModel" mode="view" height="600px" />
-      </div>
-
-      <!-- 右侧 JSON 编辑器(code 模式) -->
-      <div class="w-1/2 pl-2 overflow-auto">
-        <JsonEditor v-model="editableModelTSL" mode="code" height="600px" @error="handleError" />
-      </div>
-    </div>
-
-    <template #footer>
-      <el-button @click="dialogVisible = false">取消</el-button>
-      <el-button type="primary" @click="handleSave" :disabled="hasJsonError">保存</el-button>
-    </template>
-  </Dialog>
-</template>
-
-<script setup lang="ts">
-import { isEmpty } from '@/utils/is'
-
-defineOptions({ name: 'ThingModelDualView' })
-
-const props = defineProps<{
-  modelValue: any // 物模型的值
-  thingModel: any[] // 物模型
-}>()
-const emits = defineEmits(['update:modelValue', 'change'])
-
-const message = useMessage()
-const dialogVisible = ref(false) // 弹窗的是否展示
-const dialogTitle = ref('物模型编辑器') // 弹窗的标题
-const editableModelTSL = ref([
-  {
-    identifier: '对应左侧 identifier 属性值',
-    value: '如果 identifier 是 int 类型则输入数字,具体查看产品物模型定义'
-  }
-]) // 物模型数据
-const hasJsonError = ref(false) // 是否有 JSON 格式错误
-const loading = ref(false) // 加载状态
-
-/** 打开弹窗 */
-const open = () => {
-  try {
-    // 数据回显
-    if (props.modelValue) {
-      editableModelTSL.value = JSON.parse(props.modelValue)
-    }
-  } catch (e) {
-    message.error('物模型编辑器参数')
-    console.error(e)
-  } finally {
-    dialogVisible.value = true
-    // 重置状态
-    hasJsonError.value = false
-  }
-}
-defineExpose({ open }) // 暴露方法供父组件调用
-
-/** 保存修改 */
-const handleSave = async () => {
-  try {
-    await message.confirm('确定要保存物模型参数吗?')
-    emits('update:modelValue', JSON.stringify(editableModelTSL.value))
-    message.success('保存成功')
-    dialogVisible.value = false
-  } catch {}
-}
-
-/** 处理 JSON 编辑器错误的函数 */
-const handleError = (errors: any) => {
-  if (isEmpty(errors)) {
-    hasJsonError.value = false
-    return
-  }
-  hasJsonError.value = true
-}
-</script>

+ 0 - 142
src/views/iot/rule/scene/components/ThingModelParamInput.vue

@@ -1,142 +0,0 @@
-<template>
-  <div class="flex items-center">
-    <!-- 数值类型输入框 -->
-    <template v-if="isNumeric">
-      <el-input
-        v-model="value"
-        class="w-1/1!"
-        :placeholder="`请输入${dataSpecs.unitName ? dataSpecs.unitName : '数值'}`"
-      >
-        <template #append> {{ dataSpecs.unit }} </template>
-      </el-input>
-    </template>
-
-    <!-- 布尔类型使用开关 -->
-    <template v-else-if="isBool">
-      <el-switch
-        v-model="value"
-        size="large"
-        :active-text="dataSpecsList[1].name"
-        :active-value="dataSpecsList[1].value"
-        :inactive-text="dataSpecsList[0].name"
-        :inactive-value="dataSpecsList[0].value"
-      />
-    </template>
-
-    <!-- 枚举类型使用下拉选择 -->
-    <template v-else-if="isEnum">
-      <el-select class="w-1/1!" v-model="value">
-        <el-option
-          v-for="(item, index) in dataSpecsList"
-          :key="index"
-          :label="item.name"
-          :value="item.value"
-        />
-      </el-select>
-    </template>
-
-    <!-- 时间类型使用时间选择器 -->
-    <template v-else-if="isDate">
-      <el-date-picker
-        class="w-1/1!"
-        v-model="value"
-        type="datetime"
-        value-format="YYYY-MM-DD HH:mm:ss"
-        placeholder="选择日期时间"
-      />
-    </template>
-
-    <!-- 文本类型使用文本输入框 -->
-    <template v-else-if="isText">
-      <el-input
-        class="w-1/1!"
-        v-model="value"
-        :maxlength="dataSpecs?.length"
-        :show-word-limit="true"
-        placeholder="请输入文本"
-      />
-    </template>
-
-    <!-- array、struct 直接输入 -->
-    <template v-else>
-      <el-input class="w-1/1!" :model-value="value" disabled placeholder="请输入值">
-        <template #append>
-          <el-button type="primary" @click="openJsonEditor">编辑</el-button>
-        </template>
-      </el-input>
-      <!-- array、struct 类型数据编辑 -->
-      <ThingModelDualView
-        ref="thingModelDualViewRef"
-        v-model="value"
-        :thing-model="dataSpecsList"
-      />
-    </template>
-  </div>
-</template>
-
-<script lang="ts" setup>
-import { computed } from 'vue'
-import { useVModel } from '@vueuse/core'
-import ThingModelDualView from './ThingModelDualView.vue'
-import { IoTDataSpecsDataTypeEnum } from '@/views/iot/utils/constants'
-
-/** 物模型属性参数输入组件 */
-defineOptions({ name: 'ThingModelParamInput' })
-
-const props = defineProps<{
-  modelValue: any // 物模型的值
-  thingModel: any // 物模型
-}>()
-
-const emits = defineEmits(['update:modelValue', 'change'])
-const value = useVModel(props, 'modelValue', emits)
-
-const thingModelDualViewRef = ref<InstanceType<typeof ThingModelDualView>>()
-const openJsonEditor = () => {
-  thingModelDualViewRef.value?.open()
-}
-
-/** 计算属性:判断数据类型 */
-const isNumeric = computed(() =>
-  [
-    IoTDataSpecsDataTypeEnum.INT,
-    IoTDataSpecsDataTypeEnum.FLOAT,
-    IoTDataSpecsDataTypeEnum.DOUBLE
-  ].includes(props.thingModel?.dataType as any)
-)
-const isBool = computed(() => props.thingModel?.dataType === IoTDataSpecsDataTypeEnum.BOOL)
-const isEnum = computed(() => props.thingModel?.dataType === IoTDataSpecsDataTypeEnum.ENUM)
-const isDate = computed(() => props.thingModel?.dataType === IoTDataSpecsDataTypeEnum.DATE)
-const isText = computed(() => props.thingModel?.dataType === IoTDataSpecsDataTypeEnum.TEXT)
-/** 获取数据规格 */
-const dataSpecs = computed(() => {
-  if (isNumeric.value || isDate.value || isText.value) {
-    return props.thingModel?.dataSpecs || {}
-  }
-  return {}
-})
-const dataSpecsList = computed(() => {
-  if (
-    isBool.value ||
-    isEnum.value ||
-    [IoTDataSpecsDataTypeEnum.ARRAY, IoTDataSpecsDataTypeEnum.STRUCT].includes(
-      props.thingModel?.dataType
-    )
-  ) {
-    return props.thingModel?.dataSpecsList || []
-  }
-  return []
-})
-
-/** 物模型切换重置值 */
-watch(
-  () => props.thingModel?.dataType,
-  (_, oldValue) => {
-    if (!oldValue) {
-      return
-    }
-    value.value = undefined
-  },
-  { deep: true }
-)
-</script>

+ 0 - 307
src/views/iot/rule/scene/components/action/ActionExecutor.vue

@@ -1,307 +0,0 @@
-<template>
-  <div>
-    <div class="m-10px">
-      <!-- 产品设备回显区域 -->
-      <div class="relative bg-[#eff3f7] h-50px flex items-center px-10px">
-        <div class="flex items-center mr-60px">
-          <span class="mr-10px">执行动作</span>
-          <el-select
-            v-model="actionConfig.type"
-            class="!w-240px"
-            clearable
-            placeholder="请选择执行类型"
-          >
-            <el-option
-              v-for="dict in getIntDictOptions(DICT_TYPE.IOT_RULE_SCENE_ACTION_TYPE_ENUM)"
-              :key="dict.value"
-              :label="dict.label"
-              :value="dict.value"
-            />
-          </el-select>
-        </div>
-        <div v-if="isDeviceAction" class="flex items-center mr-60px">
-          <span class="mr-10px">产品</span>
-          <el-button type="primary" @click="handleSelectProduct" size="small" plain>
-            {{ product ? product.name : '选择产品' }}
-          </el-button>
-        </div>
-        <!-- TODO @puhui999:单选设备,默认不选就是全部设备 -->
-        <div v-if="isDeviceAction" class="flex items-center mr-60px">
-          <span class="mr-10px">设备</span>
-          <el-button type="primary" @click="handleSelectDevice" size="small" plain>
-            {{ isEmpty(deviceList) ? '选择设备' : deviceList.map((d) => d.deviceName).join(',') }}
-          </el-button>
-        </div>
-        <!-- 删除执行器 -->
-        <div class="absolute top-auto right-16px bottom-auto">
-          <el-tooltip content="删除执行器" placement="top">
-            <slot></slot>
-          </el-tooltip>
-        </div>
-      </div>
-
-      <!-- 设备控制执行器 -->
-      <!-- TODO @puhui999:服务调用时,选择好某个物模型,剩余直接填写一个 JSON 哈;不用逐个添加~可以试试【设备详情-设备调试】那,有服务调用的模拟 -->
-      <DeviceControlAction
-        v-if="isDeviceAction"
-        :action-type="actionConfig.type"
-        :model-value="actionConfig.deviceControl"
-        :product-id="product?.id"
-        :product-key="product?.productKey"
-        @update:model-value="(val) => (actionConfig.deviceControl = val)"
-      />
-
-      <!-- 告警执行器 -->
-      <div v-else-if="isAlertAction">
-        <!-- 告警触发 - 无需额外配置 -->
-        <div
-          v-if="actionConfig.type === IotRuleSceneActionTypeEnum.ALERT_TRIGGER"
-          class="bg-[#dbe5f6] flex items-center justify-center p-10px"
-        >
-          <el-icon class="mr-5px text-blue-500"><Icon icon="ep:info-filled" /></el-icon>
-          <span class="text-gray-600">触发告警通知,系统将自动发送告警信息</span>
-        </div>
-
-        <!-- 告警恢复 - 需要选择告警配置 -->
-        <div v-else-if="actionConfig.type === IotRuleSceneActionTypeEnum.ALERT_RECOVER">
-          <div class="bg-[#dbe5f6] flex items-center justify-center p-10px mb-10px">
-            <el-icon class="mr-5px text-blue-500"><Icon icon="ep:info-filled" /></el-icon>
-            <!-- TODO @puhui999:这种类型的提示,感觉放在 SELECT 那,后面有个所有的提示,会不会更好呀;因为可以少占用行呢; -->
-            <span class="text-gray-600">恢复指定的告警配置状态</span>
-          </div>
-          <div class="p-10px">
-            <el-form-item label="选择告警配置" required label-width="110">
-              <el-select
-                v-model="actionConfig.alertConfigId"
-                class="!w-240px"
-                clearable
-                placeholder="请选择要恢复的告警配置"
-                :loading="alertConfigLoading"
-              >
-                <el-option
-                  v-for="config in alertConfigList"
-                  :key="config.id"
-                  :label="config.name"
-                  :value="config.id"
-                />
-              </el-select>
-            </el-form-item>
-          </div>
-        </div>
-      </div>
-    </div>
-
-    <!-- 产品、设备的选择 -->
-    <ProductTableSelect ref="productTableSelectRef" @success="handleProductSelect" />
-    <DeviceTableSelect
-      ref="deviceTableSelectRef"
-      multiple
-      :product-id="product?.id"
-      @success="handleDeviceSelect"
-    />
-  </div>
-</template>
-
-<script setup lang="ts">
-import { useVModel } from '@vueuse/core'
-import { isEmpty } from '@/utils/is'
-import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import ProductTableSelect from '@/views/iot/product/product/components/ProductTableSelect.vue'
-import DeviceTableSelect from '@/views/iot/device/device/components/DeviceTableSelect.vue'
-import DeviceControlAction from './DeviceControlAction.vue'
-import { ProductApi, ProductVO } from '@/api/iot/product/product'
-import { DeviceApi, DeviceVO } from '@/api/iot/device/device'
-import { AlertConfigApi, AlertConfig } from '@/api/iot/alert/config'
-import {
-  ActionConfig,
-  ActionDeviceControl,
-  IotDeviceMessageIdentifierEnum,
-  IotDeviceMessageTypeEnum,
-  IotRuleSceneActionTypeEnum
-} from '@/api/iot/rule/scene/scene.types'
-
-/** 场景联动之执行器组件 */
-defineOptions({ name: 'ActionExecutor' })
-
-const props = defineProps<{ modelValue: any }>()
-const emits = defineEmits(['update:modelValue'])
-const actionConfig = useVModel(props, 'modelValue', emits) as Ref<ActionConfig>
-
-const message = useMessage()
-
-/** 计算属性:判断是否为设备相关执行类型 */
-const isDeviceAction = computed(() => {
-  return [
-    IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET,
-    IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE
-  ].includes(actionConfig.value.type as any)
-})
-
-/** 计算属性:判断是否为告警相关执行类型 */
-const isAlertAction = computed(() => {
-  return [
-    IotRuleSceneActionTypeEnum.ALERT_TRIGGER,
-    IotRuleSceneActionTypeEnum.ALERT_RECOVER
-  ].includes(actionConfig.value.type as any)
-})
-
-/** 初始化执行器结构 */
-const initActionConfig = () => {
-  if (!actionConfig.value) {
-    actionConfig.value = { type: IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET } as ActionConfig
-  }
-
-  // 设备控制执行器初始化
-  if (isDeviceAction.value && !actionConfig.value.deviceControl) {
-    actionConfig.value.deviceControl = {
-      productKey: '',
-      deviceNames: [],
-      type:
-        actionConfig.value.type === IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET
-          ? IotDeviceMessageTypeEnum.PROPERTY
-          : IotDeviceMessageTypeEnum.SERVICE,
-      identifier:
-        actionConfig.value.type === IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET
-          ? IotDeviceMessageIdentifierEnum.PROPERTY_SET
-          : IotDeviceMessageIdentifierEnum.SERVICE_INVOKE,
-      data: {}
-    } as ActionDeviceControl
-  }
-
-  // 告警执行器初始化
-  if (isAlertAction.value) {
-    if (actionConfig.value.type === IotRuleSceneActionTypeEnum.ALERT_TRIGGER) {
-      // 告警触发 - 无需额外配置
-      actionConfig.value.alertConfigId = undefined
-    } else if (actionConfig.value.type === IotRuleSceneActionTypeEnum.ALERT_RECOVER) {
-      // 告警恢复 - 需要选择告警配置
-      if (!actionConfig.value.alertConfigId) {
-        actionConfig.value.alertConfigId = undefined
-      }
-    }
-  }
-}
-
-/** 产品和设备选择 */
-const productTableSelectRef = ref<InstanceType<typeof ProductTableSelect>>()
-const deviceTableSelectRef = ref<InstanceType<typeof DeviceTableSelect>>()
-const product = ref<ProductVO>()
-const deviceList = ref<DeviceVO[]>([])
-
-/** 告警配置相关 */
-const alertConfigList = ref<AlertConfig[]>([])
-const alertConfigLoading = ref(false)
-
-/** 处理选择产品 */
-const handleSelectProduct = () => {
-  productTableSelectRef.value?.open()
-}
-
-/** 处理选择设备 */
-const handleSelectDevice = () => {
-  if (!product.value) {
-    message.warning('请先选择一个产品')
-    return
-  }
-  deviceTableSelectRef.value?.open()
-}
-
-/** 处理产品选择成功 */
-const handleProductSelect = (val: ProductVO) => {
-  product.value = val
-  if (actionConfig.value.deviceControl) {
-    actionConfig.value.deviceControl.productKey = val.productKey
-  }
-  // 重置设备选择
-  deviceList.value = []
-  if (actionConfig.value.deviceControl) {
-    actionConfig.value.deviceControl.deviceNames = []
-  }
-}
-
-/** 处理设备选择成功 */
-const handleDeviceSelect = (val: DeviceVO[]) => {
-  deviceList.value = val
-  if (actionConfig.value.deviceControl) {
-    actionConfig.value.deviceControl.deviceNames = val.map((item) => item.deviceName)
-  }
-}
-
-/** 获取告警配置列表 */
-const getAlertConfigList = async () => {
-  try {
-    alertConfigLoading.value = true
-    alertConfigList.value = await AlertConfigApi.getSimpleAlertConfigList()
-  } catch (error) {
-    console.error('获取告警配置列表失败:', error)
-  } finally {
-    alertConfigLoading.value = false
-  }
-}
-
-/** 监听执行类型变化,初始化对应配置 */
-watch(
-  () => actionConfig.value.type,
-  (newType) => {
-    initActionConfig()
-    // 如果是告警恢复类型,需要加载告警配置列表
-    if (newType === IotRuleSceneActionTypeEnum.ALERT_RECOVER) {
-      getAlertConfigList()
-    }
-  },
-  { immediate: true }
-)
-
-/** 初始化产品回显信息 */
-const initProductInfo = async () => {
-  if (!actionConfig.value.deviceControl?.productKey) {
-    return
-  }
-
-  try {
-    const productData = await ProductApi.getProductByKey(
-      actionConfig.value.deviceControl.productKey
-    )
-    if (productData) {
-      product.value = productData
-    }
-  } catch (error) {
-    console.error('获取产品信息失败:', error)
-  }
-}
-
-/**
- * 初始化设备回显信息
- */
-const initDeviceInfo = async () => {
-  if (
-    !actionConfig.value.deviceControl?.productKey ||
-    !actionConfig.value.deviceControl?.deviceNames?.length
-  ) {
-    return
-  }
-
-  try {
-    const deviceData = await DeviceApi.getDevicesByProductKeyAndNames(
-      actionConfig.value.deviceControl.productKey,
-      actionConfig.value.deviceControl.deviceNames
-    )
-    if (deviceData && deviceData.length > 0) {
-      deviceList.value = deviceData
-    }
-  } catch (error) {
-    console.error('获取设备信息失败:', error)
-  }
-}
-
-/** 初始化 */
-onMounted(async () => {
-  initActionConfig()
-
-  // 初始化产品和设备回显
-  if (actionConfig.value.deviceControl) {
-    await initProductInfo()
-    await initDeviceInfo()
-  }
-})
-</script>

+ 0 - 248
src/views/iot/rule/scene/components/action/DeviceControlAction.vue

@@ -1,248 +0,0 @@
-<template>
-  <div class="bg-[#dbe5f6] flex p-10px">
-    <div class="">
-      <div
-        class="flex items-center justify-around mb-10px last:mb-0"
-        v-for="(parameter, index) in parameters"
-        :key="index"
-      >
-        <!-- 选择服务 -->
-        <el-select
-          v-if="IotDeviceMessageTypeEnum.SERVICE === deviceControlConfig.type"
-          v-model="parameter.identifier0"
-          class="!w-240px mr-10px"
-          clearable
-          placeholder="请选择服务"
-        >
-          <el-option
-            v-for="thingModel in getThingModelTSLServices"
-            :key="thingModel.identifier"
-            :label="thingModel.name"
-            :value="thingModel.identifier"
-          />
-        </el-select>
-        <el-select
-          v-model="parameter.identifier"
-          class="!w-240px mr-10px"
-          clearable
-          placeholder="请选择物模型"
-        >
-          <el-option
-            v-for="thingModel in thingModels(parameter?.identifier0)"
-            :key="thingModel.identifier"
-            :label="thingModel.name"
-            :value="thingModel.identifier"
-          />
-        </el-select>
-        <ThingModelParamInput
-          class="!w-240px mr-10px"
-          v-model="parameter.value"
-          :thing-model="
-            thingModels(parameter?.identifier0)?.find(
-              (item) => item.identifier === parameter.identifier
-            )
-          "
-        />
-        <el-tooltip content="删除参数" placement="top">
-          <el-button type="danger" circle size="small" @click="removeParameter(index)">
-            <Icon icon="ep:delete" />
-          </el-button>
-        </el-tooltip>
-      </div>
-    </div>
-    <!-- 添加参数 -->
-    <div class="flex flex-1 flex-col items-center justify-center w-60px h-a">
-      <el-tooltip content="添加参数" placement="top">
-        <el-button type="primary" circle size="small" @click="addParameter">
-          <Icon icon="ep:plus" />
-        </el-button>
-      </el-tooltip>
-    </div>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { useVModel } from '@vueuse/core'
-import { isEmpty } from '@/utils/is'
-import { ThingModelApi } from '@/api/iot/thingmodel'
-import {
-  ActionDeviceControl,
-  IotDeviceMessageIdentifierEnum,
-  IotDeviceMessageTypeEnum,
-  IotRuleSceneActionTypeEnum
-} from '@/api/iot/rule/scene/scene.types'
-import ThingModelParamInput from '../ThingModelParamInput.vue'
-
-/** 设备控制执行器组件 */
-defineOptions({ name: 'DeviceControlAction' })
-
-const props = defineProps<{
-  modelValue: any
-  actionType: number
-  productId?: number
-  productKey?: string
-}>()
-const emits = defineEmits(['update:modelValue'])
-const deviceControlConfig = useVModel(props, 'modelValue', emits) as Ref<ActionDeviceControl>
-
-const message = useMessage()
-
-/** 执行器参数 */
-const parameters = ref<{ identifier: string; value: any; identifier0?: string }[]>([])
-const addParameter = () => {
-  if (!props.productId) {
-    message.warning('请先选择一个产品')
-    return
-  }
-  parameters.value.push({ identifier: '', value: undefined })
-}
-const removeParameter = (index: number) => {
-  parameters.value.splice(index, 1)
-}
-watch(
-  () => parameters.value,
-  (newVal) => {
-    if (isEmpty(newVal)) {
-      return
-    }
-    for (const parameter of newVal) {
-      if (isEmpty(parameter.identifier)) {
-        break
-      }
-      // 单独处理服务的情况
-      if (IotDeviceMessageTypeEnum.SERVICE === deviceControlConfig.value.type) {
-        if (!parameter.identifier0) {
-          continue
-        }
-        deviceControlConfig.value.data[parameter.identifier0] = {
-          identifier: parameter.identifier,
-          value: parameter.value
-        }
-        continue
-      }
-      deviceControlConfig.value.data[parameter.identifier] = parameter.value
-    }
-  },
-  { deep: true }
-)
-
-/** 初始化设备控制执行器结构 */
-const initDeviceControlConfig = () => {
-  if (!deviceControlConfig.value) {
-    deviceControlConfig.value = {
-      productKey: '',
-      deviceNames: [],
-      type:
-        props.actionType === IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET
-          ? IotDeviceMessageTypeEnum.PROPERTY
-          : IotDeviceMessageTypeEnum.SERVICE,
-      identifier:
-        props.actionType === IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET
-          ? IotDeviceMessageIdentifierEnum.PROPERTY_SET
-          : IotDeviceMessageIdentifierEnum.SERVICE_INVOKE,
-      data: {}
-    } as ActionDeviceControl
-  } else {
-    // 单独处理服务的情况
-    if (IotDeviceMessageTypeEnum.SERVICE === deviceControlConfig.value.type) {
-      // 参数回显
-      parameters.value = Object.entries(deviceControlConfig.value.data).map(([key, value]) => ({
-        identifier0: key,
-        identifier: value.identifier,
-        value: value.value
-      }))
-      return
-    }
-    // 参数回显
-    parameters.value = Object.entries(deviceControlConfig.value.data).map(([key, value]) => ({
-      identifier: key,
-      value: value
-    }))
-  }
-
-  // 确保 data 对象存在
-  if (!deviceControlConfig.value.data) {
-    deviceControlConfig.value.data = {}
-  }
-}
-
-/** 获取产品物模型 */
-const thingModelTSL = ref<any>()
-const getThingModelTSL = async () => {
-  if (!props.productId) {
-    return
-  }
-  thingModelTSL.value = await ThingModelApi.getThingModelTSLByProductId(props.productId)
-}
-const thingModels = computed(() => (identifier?: string): any[] => {
-  if (isEmpty(thingModelTSL.value)) {
-    return []
-  }
-  switch (deviceControlConfig.value.type) {
-    case IotDeviceMessageTypeEnum.PROPERTY:
-      return thingModelTSL.value?.properties || []
-    case IotDeviceMessageTypeEnum.SERVICE:
-      const service = thingModelTSL.value.services?.find(
-        (item: any) => item.identifier === identifier
-      )
-      return service?.inputParams || []
-  }
-  return []
-})
-/** 获取物模型服务 */
-const getThingModelTSLServices = computed(() => thingModelTSL.value?.services || [])
-
-/** 监听 productId 变化 */
-watch(
-  () => props.productId,
-  () => {
-    getThingModelTSL()
-    if (deviceControlConfig.value && deviceControlConfig.value.productKey === props.productKey) {
-      return
-    }
-    // 当产品ID变化时,清空原有数据
-    deviceControlConfig.value.data = {}
-    parameters.value = []
-  }
-)
-
-/** 监听执行类型变化 */
-watch(
-  () => props.actionType,
-  (val: any) => {
-    if (!val) {
-      return
-    }
-    // 切换执行类型时清空参数
-    deviceControlConfig.value.data = {}
-    parameters.value = []
-    if (val === IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET) {
-      deviceControlConfig.value.type = IotDeviceMessageTypeEnum.PROPERTY
-      deviceControlConfig.value.identifier = IotDeviceMessageIdentifierEnum.PROPERTY_SET
-    } else if (val === IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE) {
-      deviceControlConfig.value.type = IotDeviceMessageTypeEnum.SERVICE
-      deviceControlConfig.value.identifier = IotDeviceMessageIdentifierEnum.SERVICE_INVOKE
-    }
-  }
-)
-
-/** 监听消息类型变化 */
-watch(
-  () => deviceControlConfig.value.type,
-  () => {
-    // 切换消息类型时清空参数
-    deviceControlConfig.value.data = {}
-    parameters.value = []
-    if (deviceControlConfig.value.type === IotDeviceMessageTypeEnum.PROPERTY) {
-      deviceControlConfig.value.identifier = IotDeviceMessageIdentifierEnum.PROPERTY_SET
-    } else if (deviceControlConfig.value.type === IotDeviceMessageTypeEnum.SERVICE) {
-      deviceControlConfig.value.identifier = IotDeviceMessageIdentifierEnum.SERVICE_INVOKE
-    }
-  }
-)
-
-// 初始化
-onMounted(() => {
-  initDeviceControlConfig()
-})
-</script>

+ 0 - 106
src/views/iot/rule/scene/components/listener/ConditionSelector.vue

@@ -1,106 +0,0 @@
-<template>
-  <el-select v-model="selectedOperator" class="w-1/1" clearable :placeholder="placeholder">
-    <!-- 根据属性类型展示不同的可选条件 -->
-    <el-option
-      v-for="(item, key) in filteredOperators"
-      :key="key"
-      :label="item.name"
-      :value="item.value"
-    />
-  </el-select>
-</template>
-
-<script setup lang="ts">
-import { computed } from 'vue'
-import { IotRuleSceneTriggerConditionParameterOperatorEnum } from '@/api/iot/rule/scene/scene.types'
-
-/** 条件选择器 */
-defineOptions({ name: 'ConditionSelector' })
-const props = defineProps({
-  placeholder: {
-    type: String,
-    default: '请选择条件'
-  },
-  modelValue: {
-    type: String,
-    default: ''
-  },
-  dataType: {
-    type: String,
-    default: ''
-  }
-})
-
-const emit = defineEmits(['update:modelValue'])
-
-const selectedOperator = computed({
-  get: () => props.modelValue,
-  set: (value) => emit('update:modelValue', value)
-})
-
-// 根据数据类型过滤可用的操作符
-const filteredOperators = computed(() => {
-  // 如果没有指定数据类型,返回所有操作符
-  if (!props.dataType) {
-    return IotRuleSceneTriggerConditionParameterOperatorEnum
-  }
-
-  const operatorMap = new Map()
-  
-  // 添加通用的操作符(所有类型都有非空操作符)
-  operatorMap.set('NOT_NULL', IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_NULL)
-  
-  // 根据数据类型添加特定的操作符
-  switch (props.dataType) {
-    case 'int':
-    case 'float':
-    case 'double':
-      // 数值类型支持的所有操作符
-      operatorMap.set('EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS)
-      operatorMap.set('NOT_EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS)
-      operatorMap.set('GREATER_THAN', IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN)
-      operatorMap.set('GREATER_THAN_OR_EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN_OR_EQUALS)
-      operatorMap.set('LESS_THAN', IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN)
-      operatorMap.set('LESS_THAN_OR_EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN_OR_EQUALS)
-      operatorMap.set('IN', IotRuleSceneTriggerConditionParameterOperatorEnum.IN)
-      operatorMap.set('NOT_IN', IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_IN)
-      operatorMap.set('BETWEEN', IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN)
-      operatorMap.set('NOT_BETWEEN', IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN)
-      break
-    case 'enum':
-      // 枚举类型支持的操作符
-      operatorMap.set('EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS)
-      operatorMap.set('NOT_EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS)
-      operatorMap.set('IN', IotRuleSceneTriggerConditionParameterOperatorEnum.IN)
-      operatorMap.set('NOT_IN', IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_IN)
-      break
-    case 'bool':
-      // 布尔类型支持的操作符
-      operatorMap.set('EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS)
-      operatorMap.set('NOT_EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS)
-      break
-    case 'text':
-      // 文本类型支持的操作符
-      operatorMap.set('EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS)
-      operatorMap.set('NOT_EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS)
-      operatorMap.set('LIKE', IotRuleSceneTriggerConditionParameterOperatorEnum.LIKE)
-      break
-    case 'date':
-      // 日期类型支持的操作符
-      operatorMap.set('EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS)
-      operatorMap.set('NOT_EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS)
-      operatorMap.set('GREATER_THAN', IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN)
-      operatorMap.set('GREATER_THAN_OR_EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN_OR_EQUALS)
-      operatorMap.set('LESS_THAN', IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN)
-      operatorMap.set('LESS_THAN_OR_EQUALS', IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN_OR_EQUALS)
-      operatorMap.set('BETWEEN', IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN)
-      operatorMap.set('NOT_BETWEEN', IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN)
-      break
-    // struct 和 array 类型只支持非空操作符,已在通用部分添加
-    default:
-      return IotRuleSceneTriggerConditionParameterOperatorEnum
-  }
-  
-  return Object.fromEntries(operatorMap)
-})
-</script>

+ 0 - 367
src/views/iot/rule/scene/components/listener/DeviceListener.vue

@@ -1,367 +0,0 @@
-<template>
-  <div>
-    <div class="m-10px">
-      <div class="relative bg-[#eff3f7] h-50px flex items-center px-10px">
-        <div class="flex items-center mr-60px">
-          <span class="mr-10px">触发条件</span>
-          <el-select
-            v-model="triggerConfig.type"
-            class="!w-240px"
-            clearable
-            placeholder="请选择触发条件"
-          >
-            <el-option
-              v-for="dict in getIntDictOptions(DICT_TYPE.IOT_RULE_SCENE_TRIGGER_TYPE_ENUM)"
-              :key="dict.value"
-              :label="dict.label"
-              :value="dict.value"
-            />
-          </el-select>
-        </div>
-        <div v-if="isDeviceTrigger" class="flex items-center mr-60px">
-          <span class="mr-10px">产品</span>
-          <el-button type="primary" @click="productTableSelectRef?.open()" size="small" plain>
-            {{ product ? product.name : '选择产品' }}
-          </el-button>
-        </div>
-        <!-- TODO @puhui999:只允许选择一个,或者全部设备 -->
-        <div v-if="isDeviceTrigger" class="flex items-center mr-60px">
-          <span class="mr-10px">设备</span>
-          <el-button type="primary" @click="openDeviceSelect" size="small" plain>
-            {{ isEmpty(deviceList) ? '选择设备' : triggerConfig.deviceNames.join(',') }}
-          </el-button>
-        </div>
-        <!-- 删除触发器 -->
-        <div class="absolute top-auto right-16px bottom-auto">
-          <el-tooltip content="删除触发器" placement="top">
-            <slot></slot>
-          </el-tooltip>
-        </div>
-      </div>
-      <!-- 设备触发器条件 -->
-      <template v-if="isDeviceTrigger">
-        <!-- 设备上下线变更 - 无需额外配置 -->
-        <div
-          v-if="triggerConfig.type === IotRuleSceneTriggerTypeEnum.DEVICE_STATE_UPDATE"
-          class="bg-[#dbe5f6] flex items-center justify-center p-10px"
-        >
-          <span class="text-gray-600">设备上下线状态变更时触发,无需额外配置</span>
-        </div>
-
-        <!-- 物模型属性上报、设备事件上报、设备服务调用 - 需要配置条件 -->
-        <div
-          v-else
-          class="bg-[#dbe5f6] flex p-10px"
-          v-for="(condition, index) in triggerConfig.conditions"
-          :key="index"
-        >
-          <div class="w-70%">
-            <DeviceListenerCondition
-              v-for="(parameter, index2) in condition.parameters"
-              :key="index2"
-              :model-value="parameter"
-              :condition-type="condition.type"
-              :thingModels="thingModels(condition)"
-              @update:model-value="(val) => (condition.parameters[index2] = val)"
-              class="mb-10px last:mb-0"
-            >
-              <el-tooltip content="删除参数" placement="top">
-                <el-button
-                  type="danger"
-                  circle
-                  size="small"
-                  @click="removeConditionParameter(condition.parameters, index2)"
-                >
-                  <Icon icon="ep:delete" />
-                </el-button>
-              </el-tooltip>
-            </DeviceListenerCondition>
-          </div>
-          <!-- 添加参数 -->
-          <div class="flex flex-1 flex-col items-center justify-center w-60px h-a">
-            <el-tooltip content="添加参数" placement="top">
-              <el-button
-                type="primary"
-                circle
-                size="small"
-                @click="addConditionParameter(condition.parameters)"
-              >
-                <Icon icon="ep:plus" />
-              </el-button>
-            </el-tooltip>
-          </div>
-          <!-- 删除条件 -->
-          <div
-            class="device-listener-condition flex flex-1 flex-col items-center justify-center w-a h-a"
-          >
-            <el-tooltip content="删除条件" placement="top">
-              <el-button type="danger" size="small" @click="removeCondition(index)">
-                <Icon icon="ep:delete" />
-              </el-button>
-            </el-tooltip>
-          </div>
-        </div>
-      </template>
-      <!-- 定时触发 -->
-      <div
-        v-if="triggerConfig.type === IotRuleSceneTriggerTypeEnum.TIMER"
-        class="bg-[#dbe5f6] flex items-center justify-between p-10px"
-      >
-        <span class="w-120px">CRON 表达式</span>
-        <crontab v-model="triggerConfig.cronExpression" />
-      </div>
-      <!-- 除了设备上下线变更,其他设备触发类型都可以设置多个触发条件 -->
-      <!-- TODO @puhui999:触发有点不太对,可以在用下阿里云的呢~ -->
-      <el-text
-        v-if="
-          isDeviceTrigger && triggerConfig.type !== IotRuleSceneTriggerTypeEnum.DEVICE_STATE_UPDATE
-        "
-        class="ml-10px!"
-        type="primary"
-        @click="addCondition"
-      >
-        添加触发条件
-      </el-text>
-    </div>
-
-    <!-- 产品、设备的选择 -->
-    <ProductTableSelect ref="productTableSelectRef" @success="handleProductSelect" />
-    <DeviceTableSelect
-      ref="deviceTableSelectRef"
-      multiple
-      :product-id="product?.id"
-      @success="handleDeviceSelect"
-    />
-  </div>
-</template>
-
-<script setup lang="ts">
-import { useVModel } from '@vueuse/core'
-import { isEmpty } from '@/utils/is'
-import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import DeviceListenerCondition from './DeviceListenerCondition.vue'
-import ProductTableSelect from '@/views/iot/product/product/components/ProductTableSelect.vue'
-import DeviceTableSelect from '@/views/iot/device/device/components/DeviceTableSelect.vue'
-import { ProductApi, ProductVO } from '@/api/iot/product/product'
-import { DeviceApi, DeviceVO } from '@/api/iot/device/device'
-import { ThingModelApi } from '@/api/iot/thingmodel'
-import {
-  IotDeviceMessageIdentifierEnum,
-  IotDeviceMessageTypeEnum,
-  IotRuleSceneTriggerTypeEnum,
-  TriggerCondition,
-  TriggerConditionParameter,
-  TriggerConfig
-} from '@/api/iot/rule/scene/scene.types'
-import { Crontab } from '@/components/Crontab'
-
-/** 场景联动之监听器组件 */
-defineOptions({ name: 'DeviceListener' })
-
-const props = defineProps<{ modelValue: any }>()
-const emits = defineEmits(['update:modelValue'])
-const triggerConfig = useVModel(props, 'modelValue', emits) as Ref<TriggerConfig>
-
-const message = useMessage()
-
-/** 计算属性:判断是否为设备触发类型 */
-const isDeviceTrigger = computed(() => {
-  return [
-    IotRuleSceneTriggerTypeEnum.DEVICE_STATE_UPDATE,
-    IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST,
-    IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST,
-    IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE
-  ].includes(triggerConfig.value.type as any)
-})
-
-/** 添加触发条件 */
-const addCondition = () => {
-  // 根据触发类型设置默认的条件类型
-  let defaultConditionType: string = IotDeviceMessageTypeEnum.PROPERTY
-  switch (triggerConfig.value.type) {
-    case IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST:
-      defaultConditionType = IotDeviceMessageTypeEnum.PROPERTY
-      break
-    case IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST:
-      defaultConditionType = IotDeviceMessageTypeEnum.EVENT
-      break
-    case IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE:
-      defaultConditionType = IotDeviceMessageTypeEnum.SERVICE
-      break
-  }
-
-  // 添加触发条件
-  triggerConfig.value.conditions?.push({
-    type: defaultConditionType,
-    identifier: IotDeviceMessageIdentifierEnum.PROPERTY_SET,
-    parameters: []
-  })
-}
-/** 移除触发条件 */
-const removeCondition = (index: number) => {
-  triggerConfig.value.conditions?.splice(index, 1)
-}
-
-/** 添加参数 */
-const addConditionParameter = (conditionParameters: TriggerConditionParameter[]) => {
-  if (!product.value) {
-    message.warning('请先选择一个产品')
-    return
-  }
-  if (conditionParameters.length >= 1) {
-    message.warning('只允许添加一个参数')
-    return
-  }
-  conditionParameters.push({} as TriggerConditionParameter)
-}
-/** 移除参数 */
-const removeConditionParameter = (
-  conditionParameters: TriggerConditionParameter[],
-  index: number
-) => {
-  conditionParameters.splice(index, 1)
-}
-
-/** 产品和设备选择引用 */
-const productTableSelectRef = ref<InstanceType<typeof ProductTableSelect>>()
-const deviceTableSelectRef = ref<InstanceType<typeof DeviceTableSelect>>()
-const product = ref<ProductVO>()
-const deviceList = ref<DeviceVO[]>([])
-/** 处理产品选择 */
-const handleProductSelect = (val: ProductVO) => {
-  product.value = val
-  triggerConfig.value.productKey = val.productKey
-  deviceList.value = []
-  getThingModelTSL()
-}
-/** 处理设备选择 */
-const handleDeviceSelect = (val: DeviceVO[]) => {
-  deviceList.value = val
-  triggerConfig.value.deviceNames = val.map((item) => item.deviceName)
-}
-/** 打开设备选择器 */
-const openDeviceSelect = () => {
-  if (!product.value) {
-    message.warning('请先选择一个产品')
-    return
-  }
-  deviceTableSelectRef.value?.open()
-}
-
-/**
- * 初始化产品回显信息
- */
-const initProductInfo = async () => {
-  if (!triggerConfig.value.productKey) {
-    return
-  }
-
-  try {
-    // 使用新的API直接通过productKey获取产品信息
-    const productData = await ProductApi.getProductByKey(triggerConfig.value.productKey)
-    if (productData) {
-      product.value = productData
-      // 加载物模型数据
-      await getThingModelTSL()
-    }
-  } catch (error) {
-    console.error('获取产品信息失败:', error)
-  }
-}
-
-/**
- * 初始化设备回显信息
- */
-const initDeviceInfo = async () => {
-  if (!triggerConfig.value.productKey || !triggerConfig.value.deviceNames?.length) {
-    return
-  }
-
-  try {
-    // 使用新的API直接通过productKey和deviceNames获取设备列表
-    const deviceData = await DeviceApi.getDevicesByProductKeyAndNames(
-      triggerConfig.value.productKey,
-      triggerConfig.value.deviceNames
-    )
-
-    if (deviceData && deviceData.length > 0) {
-      deviceList.value = deviceData
-    }
-  } catch (error) {
-    console.error('获取设备信息失败:', error)
-  }
-}
-
-/** 获取产品物模型 */
-const thingModelTSL = ref<any>()
-const thingModels = computed(() => (condition: TriggerCondition) => {
-  if (isEmpty(thingModelTSL.value)) {
-    return []
-  }
-  switch (condition.type) {
-    case IotDeviceMessageTypeEnum.PROPERTY:
-      return thingModelTSL.value?.properties || []
-    case IotDeviceMessageTypeEnum.SERVICE:
-      return thingModelTSL.value?.services || []
-    case IotDeviceMessageTypeEnum.EVENT:
-      return thingModelTSL.value?.events || []
-  }
-  return []
-})
-const getThingModelTSL = async () => {
-  if (!product.value) {
-    return
-  }
-  thingModelTSL.value = await ThingModelApi.getThingModelTSLByProductId(product.value.id)
-}
-
-/** 监听触发类型变化,自动设置条件类型 */
-watch(
-  () => triggerConfig.value.type,
-  (newType) => {
-    if (!newType || newType === IotRuleSceneTriggerTypeEnum.TIMER) {
-      return
-    }
-
-    // 设备上下线变更不需要条件配置
-    if (newType === IotRuleSceneTriggerTypeEnum.DEVICE_STATE_UPDATE) {
-      triggerConfig.value.conditions = []
-      return
-    }
-
-    // 为其他设备触发类型设置默认条件
-    if (triggerConfig.value.conditions && triggerConfig.value.conditions.length > 0) {
-      triggerConfig.value.conditions.forEach((condition) => {
-        switch (newType) {
-          case IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST:
-            condition.type = IotDeviceMessageTypeEnum.PROPERTY
-            break
-          case IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST:
-            condition.type = IotDeviceMessageTypeEnum.EVENT
-            break
-          case IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE:
-            condition.type = IotDeviceMessageTypeEnum.SERVICE
-            break
-        }
-      })
-    }
-  }
-)
-
-/** 初始化 */
-onMounted(async () => {
-  // 初始化产品和设备回显
-  if (triggerConfig.value) {
-    // 初始化conditions数组,如果不存在且不是设备上下线变更类型
-    if (
-      !triggerConfig.value.conditions &&
-      triggerConfig.value.type !== IotRuleSceneTriggerTypeEnum.DEVICE_STATE_UPDATE
-    ) {
-      triggerConfig.value.conditions = []
-    }
-
-    await initProductInfo()
-    await initDeviceInfo()
-  }
-})
-</script>

+ 0 - 87
src/views/iot/rule/scene/components/listener/DeviceListenerCondition.vue

@@ -1,87 +0,0 @@
-<template>
-  <div class="flex items-center w-1/1">
-    <!-- 选择服务 -->
-    <el-select
-      v-if="
-        [IotDeviceMessageTypeEnum.SERVICE, IotDeviceMessageTypeEnum.EVENT].includes(conditionType)
-      "
-      v-model="conditionParameter.identifier0"
-      class="!w-150px mr-10px"
-      clearable
-      placeholder="请选择服务"
-    >
-      <el-option
-        v-for="thingModel in thingModels"
-        :key="thingModel.identifier"
-        :label="thingModel.name"
-        :value="thingModel.identifier"
-      />
-    </el-select>
-    <el-select
-      v-model="conditionParameter.identifier"
-      class="!w-150px mr-10px"
-      clearable
-      placeholder="请选择物模型"
-    >
-      <el-option
-        v-for="thingModel in getThingModels"
-        :key="thingModel.identifier"
-        :label="thingModel.name"
-        :value="thingModel.identifier"
-      />
-    </el-select>
-    <ConditionSelector
-      v-model="conditionParameter.operator"
-      :data-type="model?.dataType"
-      class="!w-150px mr-10px"
-    />
-    <ThingModelParamInput
-      v-if="
-        conditionParameter.operator !==
-        IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_NULL.value
-      "
-      class="!w-200px mr-10px"
-      v-model="conditionParameter.value"
-      :thing-model="model"
-    />
-    <!-- 按钮插槽 -->
-    <slot></slot>
-  </div>
-</template>
-
-<script setup lang="ts">
-import ConditionSelector from './ConditionSelector.vue'
-import {
-  IotDeviceMessageTypeEnum,
-  IotRuleSceneTriggerConditionParameterOperatorEnum,
-  TriggerConditionParameter
-} from '@/api/iot/rule/scene/scene.types'
-import { useVModel } from '@vueuse/core'
-import ThingModelParamInput from '@/views/iot/rule/scene/components/ThingModelParamInput.vue'
-
-/** 设备触发条件 */
-defineOptions({ name: 'DeviceListenerCondition' })
-const props = defineProps<{ modelValue: any; conditionType: any; thingModels: any }>()
-const emits = defineEmits(['update:modelValue'])
-const conditionParameter = useVModel(props, 'modelValue', emits) as Ref<TriggerConditionParameter>
-
-/** 属性就是 thingModels,服务和事件取对应的 outputParams */
-const getThingModels = computed(() => {
-  switch (props.conditionType) {
-    case IotDeviceMessageTypeEnum.PROPERTY:
-      return props.thingModels || []
-    case IotDeviceMessageTypeEnum.SERVICE:
-    case IotDeviceMessageTypeEnum.EVENT:
-      return (
-        props.thingModels.find(
-          (item: any) => item.identifier === conditionParameter.value.identifier0
-        )?.outputParams || []
-      )
-  }
-})
-
-/** 获得物模型属性、类型 */
-const model = computed(() =>
-  getThingModels.value.find((item: any) => item.identifier === conditionParameter.value.identifier)
-)
-</script>

+ 0 - 166
src/views/iot/rule/scene/components/listener/DeviceStateListener.vue

@@ -1,166 +0,0 @@
-<template>
-  <div>
-    <div class="m-10px">
-      <div class="relative bg-[#eff3f7] h-50px flex items-center px-10px">
-        <div class="flex items-center mr-60px">
-          <span class="mr-10px">触发条件</span>
-          <el-select
-            v-model="triggerConfig.type"
-            class="!w-240px"
-            clearable
-            placeholder="请选择触发条件"
-          >
-            <el-option
-              v-for="dict in getIntDictOptions(DICT_TYPE.IOT_RULE_SCENE_TRIGGER_TYPE_ENUM)"
-              :key="dict.value"
-              :label="dict.label"
-              :value="dict.value"
-            />
-          </el-select>
-        </div>
-        <div class="flex items-center mr-60px">
-          <span class="mr-10px">产品</span>
-          <el-button type="primary" @click="productTableSelectRef?.open()" size="small" plain>
-            {{ product ? product.name : '选择产品' }}
-          </el-button>
-        </div>
-        <div class="flex items-center mr-60px">
-          <span class="mr-10px">设备</span>
-          <el-button type="primary" @click="openDeviceSelect" size="small" plain>
-            {{ isEmpty(deviceList) ? '选择设备' : triggerConfig.deviceNames.join(',') }}
-          </el-button>
-        </div>
-        <!-- 删除触发器 -->
-        <div class="absolute top-auto right-16px bottom-auto">
-          <el-tooltip content="删除触发器" placement="top">
-            <slot></slot>
-          </el-tooltip>
-        </div>
-      </div>
-
-      <!-- 设备状态变更说明 -->
-      <div
-        v-if="triggerConfig.type === IotRuleSceneTriggerTypeEnum.DEVICE_STATE_UPDATE"
-        class="bg-[#dbe5f6] flex items-center justify-center p-10px"
-      >
-        <el-icon class="mr-5px text-blue-500"><Icon icon="ep:info-filled" /></el-icon>
-        <span class="text-gray-600">当选中的设备上线或下线时触发场景联动</span>
-      </div>
-
-      <!-- 定时触发 -->
-      <div
-        v-if="triggerConfig.type === IotRuleSceneTriggerTypeEnum.TIMER"
-        class="bg-[#dbe5f6] flex items-center justify-between p-10px"
-      >
-        <span class="w-120px">CRON 表达式</span>
-        <crontab v-model="triggerConfig.cronExpression" />
-      </div>
-    </div>
-
-    <!-- 产品、设备的选择 -->
-    <ProductTableSelect ref="productTableSelectRef" @success="handleProductSelect" />
-    <DeviceTableSelect
-      ref="deviceTableSelectRef"
-      multiple
-      :product-id="product?.id"
-      @success="handleDeviceSelect"
-    />
-  </div>
-</template>
-
-<script setup lang="ts">
-import { useVModel } from '@vueuse/core'
-import { isEmpty } from '@/utils/is'
-import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import ProductTableSelect from '@/views/iot/product/product/components/ProductTableSelect.vue'
-import DeviceTableSelect from '@/views/iot/device/device/components/DeviceTableSelect.vue'
-import { ProductApi, ProductVO } from '@/api/iot/product/product'
-import { DeviceApi, DeviceVO } from '@/api/iot/device/device'
-import { IotRuleSceneTriggerTypeEnum, TriggerConfig } from '@/api/iot/rule/scene/scene.types'
-import { Crontab } from '@/components/Crontab'
-
-/** 设备状态监听器组件 */
-defineOptions({ name: 'DeviceStateListener' })
-
-const props = defineProps<{ modelValue: any }>()
-const emits = defineEmits(['update:modelValue'])
-const triggerConfig = useVModel(props, 'modelValue', emits) as Ref<TriggerConfig>
-
-const message = useMessage()
-
-/** 产品和设备选择引用 */
-const productTableSelectRef = ref<InstanceType<typeof ProductTableSelect>>()
-const deviceTableSelectRef = ref<InstanceType<typeof DeviceTableSelect>>()
-const product = ref<ProductVO>()
-const deviceList = ref<DeviceVO[]>([])
-
-/** 处理产品选择 */
-const handleProductSelect = (val: ProductVO) => {
-  product.value = val
-  triggerConfig.value.productKey = val.productKey
-  deviceList.value = []
-}
-
-/** 处理设备选择 */
-const handleDeviceSelect = (val: DeviceVO[]) => {
-  deviceList.value = val
-  triggerConfig.value.deviceNames = val.map((item) => item.deviceName)
-}
-
-/** 打开设备选择器 */
-const openDeviceSelect = () => {
-  if (!product.value) {
-    message.warning('请先选择一个产品')
-    return
-  }
-  deviceTableSelectRef.value?.open()
-}
-
-/**
- * 初始化产品回显信息
- */
-const initProductInfo = async () => {
-  if (!triggerConfig.value.productKey) {
-    return
-  }
-
-  try {
-    const productData = await ProductApi.getProductByKey(triggerConfig.value.productKey)
-    if (productData) {
-      product.value = productData
-    }
-  } catch (error) {
-    console.error('获取产品信息失败:', error)
-  }
-}
-
-/**
- * 初始化设备回显信息
- */
-const initDeviceInfo = async () => {
-  if (!triggerConfig.value.productKey || !triggerConfig.value.deviceNames?.length) {
-    return
-  }
-
-  try {
-    const deviceData = await DeviceApi.getDevicesByProductKeyAndNames(
-      triggerConfig.value.productKey,
-      triggerConfig.value.deviceNames
-    )
-
-    if (deviceData && deviceData.length > 0) {
-      deviceList.value = deviceData
-    }
-  } catch (error) {
-    console.error('获取设备信息失败:', error)
-  }
-}
-
-/** 初始化 */
-onMounted(async () => {
-  if (triggerConfig.value) {
-    await initProductInfo()
-    await initDeviceInfo()
-  }
-})
-</script>