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

perf:【IoT 物联网】场景联动优化统一类型定义,简化告警配置

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

+ 10 - 7
src/api/iot/rule/scene/index.ts

@@ -1,5 +1,5 @@
 import request from '@/config/axios'
-import { IotRuleScene } from './scene.types'
+import { IotSceneRule } from './scene.types'
 
 // IoT 场景联动 API
 export const RuleSceneApi = {
@@ -14,21 +14,24 @@ export const RuleSceneApi = {
   },
 
   // 新增场景联动
-  createRuleScene: async (data: IotRuleScene) => {
+  createRuleScene: async (data: IotSceneRule) => {
     return await request.post({ url: `/iot/rule-scene/create`, data })
   },
 
   // 修改场景联动
-  updateRuleScene: async (data: IotRuleScene) => {
+  updateRuleScene: async (data: IotSceneRule) => {
     return await request.put({ url: `/iot/rule-scene/update`, data })
   },
 
   // 修改场景联动
   updateRuleSceneStatus: async (id: number, status: number) => {
-    return await request.put({ url: `/iot/rule-scene/update-status`, data: {
-      id,
-      status
-    }})
+    return await request.put({
+      url: `/iot/rule-scene/update-status`,
+      data: {
+        id,
+        status
+      }
+    })
   },
 
   // 删除场景联动

+ 9 - 130
src/api/iot/rule/scene/scene.types.ts

@@ -137,122 +137,18 @@ export interface PropertySelectorItem {
 
 // ========== 场景联动规则相关接口定义 ==========
 
-// 基础接口(如果项目中有全局的 BaseDO,可以使用全局的)
-interface TenantBaseDO {
-  createTime?: Date // 创建时间
-  updateTime?: Date // 更新时间
-  creator?: string // 创建者
-  updater?: string // 更新者
-  deleted?: boolean // 是否删除
-  tenantId?: number // 租户编号
-}
-
-// 触发条件参数
-interface TriggerConditionParameter {
-  identifier0?: string // 标识符(事件、服务)
-  identifier?: string // 标识符(属性)
-  operator: string // 操作符(必填)
-  value: string // 比较值(必填,多值用逗号分隔)
-}
-
-// 触发条件
-interface TriggerCondition {
-  type: string // 消息类型
-  identifier: string // 消息标识符
-  parameters: TriggerConditionParameter[] // 参数数组
-}
-
-// 触发器配置
-interface TriggerConfig {
-  key?: string // 组件唯一标识符,用于解决索引重用问题
-  type: number // 触发类型(必填)
-  productKey?: string // 产品标识(设备触发时必填)
-  deviceNames?: string[] // 设备名称数组(设备触发时必填)
-  conditions?: TriggerCondition[] // 触发条件数组(设备触发时必填)
-  cronExpression?: string // CRON表达式(定时触发时必填)
-}
-
-// 执行设备控制
-interface ActionDeviceControl {
-  productKey: string // 产品标识(必填)
-  deviceNames: string[] // 设备名称数组(必填)
-  type: string // 消息类型(必填)
-  identifier: string // 消息标识符(必填)
-  params: Record<string, any> // 参数对象(必填)- 统一使用 params 字段
-}
-
-// 执行器配置
-interface ActionConfig {
-  key?: string // 组件唯一标识符,用于解决索引重用问题
-  type: number // 执行类型(必填)
-  deviceControl?: ActionDeviceControl // 设备控制(设备控制时必填)
-  alertConfigId?: number // 告警配置ID(告警恢复时必填)
-}
-
-// 表单数据接口 - 直接对应后端 DO 结构
-interface RuleSceneFormData {
-  id?: number
-  name: string
-  description?: string
-  status: number
-  triggers: TriggerFormData[] // 支持多个触发器
-  actions: ActionFormData[]
-}
-
-// 触发器表单数据 - 直接对应 TriggerDO
-interface TriggerFormData {
-  type: number // 触发类型
-  productId?: number // 产品编号
-  deviceId?: number // 设备编号
-  identifier?: string // 物模型标识符
-  operator?: string // 操作符
-  value?: string // 参数值
-  cronExpression?: string // CRON 表达式
-  conditionGroups?: TriggerConditionFormData[][] // 条件组(二维数组)
-}
-
-// 触发条件表单数据 - 直接对应 TriggerConditionDO
-interface TriggerConditionFormData {
-  type: number // 条件类型:1-设备状态,2-设备属性,3-当前时间
-  productId?: number // 产品编号
-  deviceId?: number // 设备编号
-  identifier?: string // 标识符
-  operator: string // 操作符
-  param: string // 参数值
-}
-
-// 执行器表单数据 - 直接对应 ActionDO
-interface ActionFormData {
-  type: number // 执行类型
-  productId?: number // 产品编号
-  deviceId?: number // 设备编号
-  identifier?: string // 物模型标识符(服务调用时使用)
-  params?: Record<string, any> // 请求参数
-  alertConfigId?: number // 告警配置编号
-}
-
-// 主接口 - 原有的 API 接口格式(保持兼容性)
-interface IotRuleScene extends TenantBaseDO {
-  id?: number // 场景编号(新增时为空)
-  name: string // 场景名称(必填)
-  description?: string // 场景描述(可选)
-  status: number // 场景状态:0-开启,1-关闭
-  triggers: TriggerConfig[] // 触发器数组(必填,至少一个)
-  actions: ActionConfig[] // 执行器数组(必填,至少一个)
-}
-
 // 后端 DO 接口 - 匹配后端数据结构
-interface IotRuleSceneDO {
+interface IotSceneRule {
   id?: number // 场景编号
   name: string // 场景名称
   description?: string // 场景描述
   status: number // 场景状态:0-开启,1-关闭
-  triggers: TriggerDO[] // 触发器数组
-  actions: ActionDO[] // 执行器数组
+  triggers: Trigger[] // 触发器数组
+  actions: Action[] // 执行器数组
 }
 
 // 触发器 DO 结构
-interface TriggerDO {
+interface Trigger {
   type: number // 触发类型
   productId?: number // 产品编号
   deviceId?: number // 设备编号
@@ -260,12 +156,12 @@ interface TriggerDO {
   operator?: string // 操作符
   value?: string // 参数值
   cronExpression?: string // CRON 表达式
-  conditionGroups?: TriggerConditionDO[][] // 条件组(二维数组)
+  conditionGroups?: TriggerCondition[][] // 条件组(二维数组)
 }
 
 // 触发条件 DO 结构
-interface TriggerConditionDO {
-  type: number // 条件类型
+interface TriggerCondition {
+  type: number // 条件类型:1-设备状态,2-设备属性,3-当前时间
   productId?: number // 产品编号
   deviceId?: number // 设备编号
   identifier?: string // 标识符
@@ -274,7 +170,7 @@ interface TriggerConditionDO {
 }
 
 // 执行器 DO 结构
-interface ActionDO {
+interface Action {
   type: number // 执行类型
   productId?: number // 产品编号
   deviceId?: number // 设备编号
@@ -300,21 +196,4 @@ interface FormValidationRules {
 
 // TODO @puhui999:这个文件,目标最终没有哈,和别的模块一致;
 
-export {
-  IotRuleScene,
-  IotRuleSceneDO,
-  TriggerDO,
-  TriggerConditionDO,
-  ActionDO,
-  TriggerConfig,
-  TriggerCondition,
-  TriggerConditionParameter,
-  ActionConfig,
-  ActionDeviceControl,
-  RuleSceneFormData,
-  TriggerFormData,
-  TriggerConditionFormData,
-  ActionFormData,
-  ValidationRule,
-  FormValidationRules
-}
+export { IotSceneRule, Trigger, TriggerCondition, Action, ValidationRule, FormValidationRules }

+ 4 - 4
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 { IotRuleSceneDO, RuleSceneFormData } from '@/api/iot/rule/scene/scene.types'
+import { IotSceneRule } from '@/api/iot/rule/scene/scene.types'
 import { RuleSceneApi } from '@/api/iot/rule/scene'
 import {
   IotRuleSceneTriggerTypeEnum,
@@ -54,7 +54,7 @@ const props = defineProps<{
   /** 抽屉显示状态 */
   modelValue: boolean
   /** 编辑的场景联动规则数据 */
-  ruleScene?: IotRuleSceneDO
+  ruleScene?: IotSceneRule
 }>()
 
 /** 组件事件定义 */
@@ -66,7 +66,7 @@ const emit = defineEmits<{
 const drawerVisible = useVModel(props, 'modelValue', emit) // 是否可见
 
 /** 创建默认的表单数据 */
-const createDefaultFormData = (): RuleSceneFormData => {
+const createDefaultFormData = (): IotSceneRule => {
   return {
     name: '',
     description: '',
@@ -89,7 +89,7 @@ const createDefaultFormData = (): RuleSceneFormData => {
 
 // 表单数据和状态
 const formRef = ref()
-const formData = ref<RuleSceneFormData>(createDefaultFormData())
+const formData = ref<IotSceneRule>(createDefaultFormData())
 // 自定义校验器
 const validateTriggers = (_rule: any, value: any, callback: any) => {
   if (!value || !Array.isArray(value) || value.length === 0) {

+ 47 - 228
src/views/iot/rule/scene/form/configs/AlertConfig.vue

@@ -1,262 +1,81 @@
 <!-- 告警配置组件 -->
 <template>
   <div class="w-full">
-    <!-- 告警配置选择区域 -->
-    <div
-      class="border border-[var(--el-border-color-light)] rounded-6px p-16px bg-[var(--el-fill-color-blank)]"
-    >
-      <div class="flex items-center gap-8px mb-12px">
-        <Icon icon="ep:bell" class="text-[var(--el-color-warning)] text-16px" />
-        <span class="text-14px font-600 text-[var(--el-text-color-primary)]">告警配置选择</span>
-        <el-tag size="small" type="warning">必选</el-tag>
-      </div>
-
-      <el-form-item label="告警配置" required>
-        <el-select
-          v-model="localValue"
-          placeholder="请选择告警配置"
-          filterable
-          clearable
-          @change="handleChange"
-          class="w-full"
-          :loading="loading"
+    <el-form-item label="告警配置" required>
+      <el-select
+        v-model="localValue"
+        placeholder="请选择告警配置"
+        filterable
+        clearable
+        @change="handleChange"
+        class="w-full"
+        :loading="loading"
+      >
+        <el-option
+          v-for="config in alertConfigs"
+          :key="config.id"
+          :label="config.name"
+          :value="config.id"
         >
-          <template #empty>
-            <div class="text-center py-20px">
-              <Icon
-                icon="ep:warning"
-                class="text-24px text-[var(--el-text-color-placeholder)] mb-8px"
-              />
-              <p class="text-12px text-[var(--el-text-color-secondary)]">暂无可用的告警配置</p>
-            </div>
-          </template>
-          <el-option
-            v-for="config in alertConfigs"
-            :key="config.id"
-            :label="config.name"
-            :value="config.id"
-            :disabled="!config.enabled"
-          >
-            <div class="flex items-center justify-between w-full py-6px">
-              <div class="flex items-center gap-12px flex-1">
-                <Icon
-                  :icon="config.enabled ? 'ep:circle-check' : 'ep:circle-close'"
-                  :class="
-                    config.enabled
-                      ? 'text-[var(--el-color-success)]'
-                      : 'text-[var(--el-color-danger)]'
-                  "
-                  class="text-16px flex-shrink-0"
-                />
-                <div class="flex-1">
-                  <div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px">{{
-                    config.name
-                  }}</div>
-                  <div class="text-12px text-[var(--el-text-color-secondary)] line-clamp-1">{{
-                    config.description
-                  }}</div>
-                </div>
-              </div>
-              <div class="flex items-center gap-8px">
-                <el-tag :type="getNotifyTypeTag(config.notifyType)" size="small">
-                  {{ getNotifyTypeName(config.notifyType) }}
-                </el-tag>
-                <el-tag :type="config.enabled ? 'success' : 'danger'" size="small">
-                  {{ config.enabled ? '启用' : '禁用' }}
-                </el-tag>
-              </div>
-            </div>
-          </el-option>
-        </el-select>
-      </el-form-item>
-    </div>
-
-    <!-- 告警配置详情 -->
-    <div
-      v-if="selectedConfig"
-      class="mt-16px border border-[var(--el-border-color-light)] rounded-6px p-16px bg-gradient-to-r from-orange-50 to-yellow-50"
-    >
-      <div class="flex items-center gap-8px mb-16px">
-        <Icon icon="ep:info-filled" class="text-[var(--el-color-warning)] text-18px" />
-        <span class="text-16px font-600 text-[var(--el-text-color-primary)]">配置详情</span>
-      </div>
-
-      <div class="grid grid-cols-1 md:grid-cols-2 gap-16px">
-        <!-- 基本信息 -->
-        <div class="space-y-12px">
-          <div class="flex items-center gap-8px">
-            <Icon icon="ep:document" class="text-[var(--el-color-primary)] text-14px" />
-            <span class="text-14px font-500 text-[var(--el-text-color-primary)]">基本信息</span>
-          </div>
-          <div class="pl-22px space-y-8px">
-            <div class="flex items-start gap-8px">
-              <span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">名称:</span>
-              <span class="text-12px text-[var(--el-text-color-primary)] flex-1 font-500">{{
-                selectedConfig.name
-              }}</span>
-            </div>
-            <div class="flex items-start gap-8px">
-              <span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">描述:</span>
-              <span class="text-12px text-[var(--el-text-color-primary)] flex-1">{{
-                selectedConfig.description
-              }}</span>
-            </div>
-            <div class="flex items-start gap-8px">
-              <span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">状态:</span>
-              <el-tag :type="selectedConfig.enabled ? 'success' : 'danger'" size="small">
-                {{ selectedConfig.enabled ? '启用' : '禁用' }}
-              </el-tag>
-            </div>
-          </div>
-        </div>
-
-        <!-- 通知配置 -->
-        <div class="space-y-12px">
-          <div class="flex items-center gap-8px">
-            <Icon icon="ep:message" class="text-[var(--el-color-success)] text-14px" />
-            <span class="text-14px font-500 text-[var(--el-text-color-primary)]">通知配置</span>
-          </div>
-          <div class="pl-22px space-y-8px">
-            <div class="flex items-start gap-8px">
-              <span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">方式:</span>
-              <el-tag :type="getNotifyTypeTag(selectedConfig.notifyType)" size="small">
-                {{ getNotifyTypeName(selectedConfig.notifyType) }}
-              </el-tag>
-            </div>
-            <div
-              v-if="selectedConfig.receivers && selectedConfig.receivers.length > 0"
-              class="flex items-start gap-8px"
-            >
-              <span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px"
-                >接收人:</span
-              >
-              <div class="flex-1">
-                <div class="flex flex-wrap gap-4px">
-                  <el-tag
-                    v-for="receiver in selectedConfig.receivers.slice(0, 3)"
-                    :key="receiver"
-                    size="small"
-                    type="info"
-                  >
-                    {{ receiver }}
-                  </el-tag>
-                  <el-tag v-if="selectedConfig.receivers.length > 3" size="small" type="info">
-                    +{{ selectedConfig.receivers.length - 3 }}
-                  </el-tag>
-                </div>
-              </div>
-            </div>
+          <div class="flex items-center justify-between">
+            <span>{{ config.name }}</span>
+            <el-tag :type="config.enabled ? 'success' : 'danger'" size="small">
+              {{ config.enabled ? '启用' : '禁用' }}
+            </el-tag>
           </div>
-        </div>
-      </div>
-    </div>
+        </el-option>
+      </el-select>
+    </el-form-item>
   </div>
 </template>
 
 <script setup lang="ts">
 import { useVModel } from '@vueuse/core'
+import { AlertConfigApi } from '@/api/iot/alert/config'
 
 /** 告警配置组件 */
 defineOptions({ name: 'AlertConfig' })
 
-interface Props {
+const props = defineProps<{
   modelValue?: number
-}
+}>()
 
-interface Emits {
+const emit = defineEmits<{
   (e: 'update:modelValue', value?: number): void
-}
-
-const props = defineProps<Props>()
-const emit = defineEmits<Emits>()
+}>()
 
 const localValue = useVModel(props, 'modelValue', emit)
 
-// 状态
-const loading = ref(false)
-const alertConfigs = ref<any[]>([])
+const loading = ref(false) // 加载状态
+const alertConfigs = ref<any[]>([]) // 告警配置列表
 
-// 计算属性
-const selectedConfig = computed(() => {
-  return alertConfigs.value.find((config) => config.id === localValue.value)
-})
-
-// 工具函数
-const getNotifyTypeName = (type: number) => {
-  const typeMap = {
-    1: '邮件通知',
-    2: '短信通知',
-    3: '微信通知',
-    4: '钉钉通知'
-  }
-  return typeMap[type] || '未知'
-}
-
-const getNotifyTypeTag = (type: number) => {
-  const tagMap = {
-    1: 'primary', // 邮件
-    2: 'success', // 短信
-    3: 'warning', // 微信
-    4: 'info' // 钉钉
-  }
-  return tagMap[type] || 'info'
-}
-
-// 事件处理
+/**
+ * 处理选择变化事件
+ * @param value 选中的值
+ */
 const handleChange = (value?: number) => {
-  // 可以在这里添加额外的处理逻辑
-  console.log('告警配置选择变化:', value)
+  emit('update:modelValue', value)
 }
 
-// API 调用
-const getAlertConfigs = async () => {
+/**
+ * 加载告警配置列表
+ */
+const loadAlertConfigs = async () => {
   loading.value = true
   try {
-    // 这里应该调用真实的API获取告警配置
-    // 暂时使用模拟数据
-    // TODO @puhui999:这里是模拟数据
-    alertConfigs.value = [
-      {
-        id: 1,
-        name: '设备异常告警',
-        description: '设备状态异常时发送告警',
-        enabled: true,
-        notifyType: 1,
-        receivers: ['admin@example.com', 'operator@example.com']
-      },
-      {
-        id: 2,
-        name: '温度超限告警',
-        description: '温度超过阈值时发送告警',
-        enabled: true,
-        notifyType: 2,
-        receivers: ['13800138000', '13900139000']
-      },
-      {
-        id: 3,
-        name: '系统故障告警',
-        description: '系统发生故障时发送告警',
-        enabled: false,
-        notifyType: 3,
-        receivers: ['技术支持群']
-      }
-    ]
-  } catch (error) {
-    console.error('获取告警配置失败:', error)
+    const data = await AlertConfigApi.getAlertConfigPage({
+      pageNo: 1,
+      pageSize: 100,
+      enabled: true // 只加载启用的配置
+    })
+    alertConfigs.value = data.list || []
   } finally {
     loading.value = false
   }
 }
 
-// 初始化
+// 组件挂载时加载数据
 onMounted(() => {
-  getAlertConfigs()
+  loadAlertConfigs()
 })
 </script>
-
-<style scoped>
-:deep(.el-select-dropdown__item) {
-  height: auto;
-  padding: 8px 20px;
-}
-</style>

+ 5 - 5
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 { TriggerConditionFormData } from '@/api/iot/rule/scene/scene.types'
+import { TriggerCondition } from '@/api/iot/rule/scene/scene.types'
 import {
   IotRuleSceneTriggerConditionTypeEnum,
   IotRuleSceneTriggerConditionParameterOperatorEnum
@@ -133,12 +133,12 @@ import {
 defineOptions({ name: 'ConditionConfig' })
 
 const props = defineProps<{
-  modelValue: TriggerConditionFormData
+  modelValue: TriggerCondition
   triggerType: number
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: TriggerConditionFormData): void
+  (e: 'update:modelValue', value: TriggerCondition): void
   (e: 'validate', result: { valid: boolean; message: string }): void
 }>()
 
@@ -155,12 +155,12 @@ const isValid = ref(true)
 const valueValidation = ref({ valid: true, message: '' })
 
 // 事件处理
-const updateConditionField = (field: keyof TriggerConditionFormData, value: any) => {
+const updateConditionField = (field: keyof TriggerCondition, value: any) => {
   ;(condition.value as any)[field] = value
   emit('update:modelValue', condition.value)
 }
 
-const updateCondition = (newCondition: TriggerConditionFormData) => {
+const updateCondition = (newCondition: TriggerCondition) => {
   condition.value = newCondition
   emit('update:modelValue', condition.value)
 }

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

@@ -320,18 +320,18 @@ import { useVModel } from '@vueuse/core'
 import { InfoFilled } from '@element-plus/icons-vue'
 import ProductSelector from '../selectors/ProductSelector.vue'
 import DeviceSelector from '../selectors/DeviceSelector.vue'
-import { ActionFormData, ThingModelService } from '@/api/iot/rule/scene/scene.types'
+import { Action, ThingModelService } from '@/api/iot/rule/scene/scene.types'
 import { IotRuleSceneActionTypeEnum } from '@/views/iot/utils/constants'
 
 /** 设备控制配置组件 */
 defineOptions({ name: 'DeviceControlConfig' })
 
 const props = defineProps<{
-  modelValue: ActionFormData
+  modelValue: Action
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: ActionFormData): void
+  (e: 'update:modelValue', value: Action): void
 }>()
 
 const action = useVModel(props, 'modelValue', emit)

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

@@ -84,17 +84,17 @@
 import { useVModel } from '@vueuse/core'
 import ProductSelector from '../selectors/ProductSelector.vue'
 import DeviceSelector from '../selectors/DeviceSelector.vue'
-import { TriggerConditionFormData } from '@/api/iot/rule/scene/scene.types'
+import { TriggerCondition } from '@/api/iot/rule/scene/scene.types'
 
 /** 设备状态条件配置组件 */
 defineOptions({ name: 'DeviceStatusConditionConfig' })
 
 const props = defineProps<{
-  modelValue: TriggerConditionFormData
+  modelValue: TriggerCondition
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: TriggerConditionFormData): void
+  (e: 'update:modelValue', value: TriggerCondition): void
   (e: 'validate', result: { valid: boolean; message: string }): void
 }>()
 

+ 5 - 5
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 { TriggerConditionFormData } from '@/api/iot/rule/scene/scene.types'
+import { TriggerCondition } from '@/api/iot/rule/scene/scene.types'
 import {
   IotRuleSceneTriggerConditionTypeEnum,
   IotRuleSceneTriggerConditionParameterOperatorEnum
@@ -93,13 +93,13 @@ import {
 defineOptions({ name: 'SubConditionGroupConfig' })
 
 const props = defineProps<{
-  modelValue: TriggerConditionFormData[]
+  modelValue: TriggerCondition[]
   triggerType: number
   maxConditions?: number
 }>()
 
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: TriggerConditionFormData[]): void
+  (e: 'update:modelValue', value: TriggerCondition[]): void
   (e: 'validate', result: { valid: boolean; message: string }): void
 }>()
 
@@ -123,7 +123,7 @@ const addCondition = () => {
     return
   }
 
-  const newCondition: TriggerConditionFormData = {
+  const newCondition: TriggerCondition = {
     type: IotRuleSceneTriggerConditionTypeEnum.DEVICE_PROPERTY, // 默认为设备属性
     productId: undefined,
     deviceId: undefined,
@@ -161,7 +161,7 @@ const removeCondition = (index: number) => {
   }
 }
 
-const updateCondition = (index: number, condition: TriggerConditionFormData) => {
+const updateCondition = (index: number, condition: TriggerCondition) => {
   if (subGroup.value) {
     subGroup.value[index] = condition
   }

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

@@ -78,12 +78,27 @@
               @update:model-value="(value) => updateAction(index, value)"
             />
 
-            <!-- 告警配置 -->
+            <!-- 告警配置 - 只有恢复告警时才显示 -->
             <AlertConfig
-              v-if="isAlertAction(action.type)"
+              v-if="action.type === ActionTypeEnum.ALERT_RECOVER"
               :model-value="action.alertConfigId"
               @update:model-value="(value) => updateActionAlertConfig(index, value)"
             />
+
+            <!-- 触发告警提示 - 触发告警时显示 -->
+            <div
+              v-if="action.type === ActionTypeEnum.ALERT_TRIGGER"
+              class="border border-[var(--el-border-color-light)] rounded-6px p-16px bg-[var(--el-fill-color-blank)]"
+            >
+              <div class="flex items-center gap-8px mb-8px">
+                <Icon icon="ep:warning" class="text-[var(--el-color-warning)] text-16px" />
+                <span class="text-14px font-600 text-[var(--el-text-color-primary)]">触发告警</span>
+                <el-tag size="small" type="warning">自动执行</el-tag>
+              </div>
+              <div class="text-12px text-[var(--el-text-color-secondary)] leading-relaxed">
+                当触发条件满足时,系统将自动发送告警通知,无需额外配置。
+              </div>
+            </div>
           </div>
         </div>
       </div>
@@ -107,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 { ActionFormData } from '@/api/iot/rule/scene/scene.types'
+import { Action } from '@/api/iot/rule/scene/scene.types'
 import {
   IotRuleSceneActionTypeEnum as ActionTypeEnum,
   isDeviceAction,
@@ -118,23 +133,20 @@ import {
 /** 执行器配置组件 */
 defineOptions({ name: 'ActionSection' })
 
-interface Props {
-  actions: ActionFormData[]
-}
+const props = defineProps<{
+  actions: Action[]
+}>()
 
-interface Emits {
-  (e: 'update:actions', value: ActionFormData[]): void
-}
-
-const props = defineProps<Props>()
-const emit = defineEmits<Emits>()
+const emit = defineEmits<{
+  (e: 'update:actions', value: Action[]): void
+}>()
 
 const actions = useVModel(props, 'actions', emit)
 
 /**
  * 创建默认的执行器数据
  */
-const createDefaultActionData = (): ActionFormData => {
+const createDefaultActionData = (): Action => {
   return {
     type: ActionTypeEnum.DEVICE_PROPERTY_SET, // 默认为设备属性设置
     productId: undefined,
@@ -145,9 +157,7 @@ const createDefaultActionData = (): ActionFormData => {
   }
 }
 
-// 配置常量
-// TODO @puhui999:去掉最大;注释风格改下;
-const maxActions = 5
+const maxActions = 5 // 最大执行器数量
 
 // 工具函数
 const getActionTypeName = (type: number) => {
@@ -164,7 +174,7 @@ const getActionTypeTag = (type: number) => {
   return actionTypeTags[type] || 'info'
 }
 
-// 事件处理
+/** 添加执行器 */
 const addAction = () => {
   if (actions.value.length >= maxActions) {
     return
@@ -174,24 +184,29 @@ const addAction = () => {
   actions.value.push(newAction)
 }
 
+/** 删除执行器 */
 const removeAction = (index: number) => {
   actions.value.splice(index, 1)
 }
 
+/** 更新执行器类型 */
 const updateActionType = (index: number, type: number) => {
   actions.value[index].type = type
   onActionTypeChange(actions.value[index], type)
 }
 
-const updateAction = (index: number, action: ActionFormData) => {
+/** 更新执行器 */
+const updateAction = (index: number, action: Action) => {
   actions.value[index] = action
 }
 
+/** 更新告警配置 */
 const updateActionAlertConfig = (index: number, alertConfigId?: number) => {
   actions.value[index].alertConfigId = alertConfigId
 }
 
-const onActionTypeChange = (action: ActionFormData, type: number) => {
+/** 监听执行器类型变化 */
+const onActionTypeChange = (action: Action, type: number) => {
   // 清理不相关的配置,确保数据结构干净
   if (isDeviceAction(type)) {
     // 设备控制类型:清理告警配置,确保设备参数存在
@@ -204,16 +219,11 @@ const onActionTypeChange = (action: ActionFormData, type: number) => {
       action.identifier = undefined
     }
   } else if (isAlertAction(type)) {
-    // 告警类型:清理设备配置
     action.productId = undefined
     action.deviceId = undefined
     action.identifier = undefined // 清理服务标识符
     action.params = undefined
+    action.alertConfigId = undefined
   }
-
-  // 触发重新校验
-  nextTick(() => {
-    // 这里可以添加校验逻辑
-  })
 }
 </script>

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

@@ -58,17 +58,17 @@
 <script setup lang="ts">
 import { useVModel } from '@vueuse/core'
 import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
-import { RuleSceneFormData } from '@/api/iot/rule/scene/scene.types'
+import { IotSceneRule } from '@/api/iot/rule/scene/scene.types'
 
 /** 基础信息配置组件 */
 defineOptions({ name: 'BasicInfoSection' })
 
 const props = defineProps<{
-  modelValue: RuleSceneFormData
+  modelValue: IotSceneRule
   rules?: any
 }>()
 const emit = defineEmits<{
-  (e: 'update:modelValue', value: RuleSceneFormData): void
+  (e: 'update:modelValue', value: IotSceneRule): void
 }>()
 
 const formData = useVModel(props, 'modelValue', emit)

+ 10 - 10
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 { IotRuleSceneDO } from '@/api/iot/rule/scene/scene.types'
+import { IotSceneRule } from '@/api/iot/rule/scene/scene.types'
 import { RuleSceneApi } from '@/api/iot/rule/scene'
 import {
   IotRuleSceneTriggerTypeEnum,
@@ -264,14 +264,14 @@ const queryParams = reactive({
 })
 
 const loading = ref(true) // 列表的加载中
-const list = ref<IotRuleSceneDO[]>([]) // 列表的数据
+const list = ref<IotSceneRule[]>([]) // 列表的数据
 const total = ref(0) // 列表的总页数
-const selectedRows = ref<IotRuleSceneDO[]>([]) // 选中的行数据
+const selectedRows = ref<IotSceneRule[]>([]) // 选中的行数据
 const queryFormRef = ref() // 搜索的表单
 
 /** 表单状态 */
 const formVisible = ref(false) // 是否可见
-const currentRule = ref<IotRuleSceneDO>() // 表单数据
+const currentRule = ref<IotSceneRule>() // 表单数据
 
 /** 统计数据 */
 const statistics = ref({
@@ -327,7 +327,7 @@ const formatCronExpression = (cron: string): string => {
 }
 
 /** 获取规则摘要信息 */
-const getRuleSceneSummary = (rule: IotRuleSceneDO) => {
+const getRuleSceneSummary = (rule: IotSceneRule) => {
   const triggerSummary =
     rule.triggers?.map((trigger: any) => {
       // 构建基础描述
@@ -455,12 +455,12 @@ const updateStatistics = () => {
 }
 
 /** 获取触发器摘要 */
-const getTriggerSummary = (rule: IotRuleSceneDO) => {
+const getTriggerSummary = (rule: IotSceneRule) => {
   return getRuleSceneSummary(rule).triggerSummary
 }
 
 /** 获取执行器摘要 */
-const getActionSummary = (rule: IotRuleSceneDO) => {
+const getActionSummary = (rule: IotSceneRule) => {
   return getRuleSceneSummary(rule).actionSummary
 }
 
@@ -484,7 +484,7 @@ const handleAdd = () => {
 }
 
 /** 修改操作 */
-const handleEdit = (row: IotRuleSceneDO) => {
+const handleEdit = (row: IotSceneRule) => {
   currentRule.value = row
   formVisible.value = true
 }
@@ -506,7 +506,7 @@ const handleDelete = async (id: number) => {
 }
 
 /** 修改状态 */
-const handleToggleStatus = async (row: IotRuleSceneDO) => {
+const handleToggleStatus = async (row: IotSceneRule) => {
   try {
     // 修改状态的二次确认
     // TODO @puhui999:status 枚举;
@@ -525,7 +525,7 @@ const handleToggleStatus = async (row: IotRuleSceneDO) => {
 }
 
 /** 多选框选中数据 */
-const handleSelectionChange = (selection: IotRuleSceneDO[]) => {
+const handleSelectionChange = (selection: IotSceneRule[]) => {
   selectedRows.value = selection
 }