From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/views/iot/rule/scene/form/sections/ActionSection.vue |  272 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 272 insertions(+), 0 deletions(-)

diff --git a/src/views/iot/rule/scene/form/sections/ActionSection.vue b/src/views/iot/rule/scene/form/sections/ActionSection.vue
new file mode 100644
index 0000000..6357afe
--- /dev/null
+++ b/src/views/iot/rule/scene/form/sections/ActionSection.vue
@@ -0,0 +1,272 @@
+<!-- 鎵ц鍣ㄩ厤缃粍浠� -->
+<template>
+  <el-card class="border border-[var(--el-border-color-light)] rounded-8px" shadow="never">
+    <template #header>
+      <div class="flex items-center justify-between">
+        <div class="flex items-center gap-8px">
+          <Icon icon="ep:setting" class="text-[var(--el-color-primary)] text-18px" />
+          <span class="text-16px font-600 text-[var(--el-text-color-primary)]">鎵ц鍣ㄩ厤缃�</span>
+          <el-tag size="small" type="info">{{ actions.length }} 涓墽琛屽櫒</el-tag>
+        </div>
+        <div class="flex items-center gap-8px">
+          <el-button type="primary" size="small" @click="addAction">
+            <Icon icon="ep:plus" />
+            娣诲姞鎵ц鍣�
+          </el-button>
+        </div>
+      </div>
+    </template>
+
+    <div class="p-0">
+      <!-- 绌虹姸鎬� -->
+      <div v-if="actions.length === 0">
+        <el-empty description="鏆傛棤鎵ц鍣ㄩ厤缃�">
+          <el-button type="primary" @click="addAction">
+            <Icon icon="ep:plus" />
+            娣诲姞绗竴涓墽琛屽櫒
+          </el-button>
+        </el-empty>
+      </div>
+
+      <!-- 鎵ц鍣ㄥ垪琛� -->
+      <div v-else class="space-y-24px">
+        <div
+          v-for="(action, index) in actions"
+          :key="`action-${index}`"
+          class="border-2 border-blue-200 rounded-8px bg-blue-50 shadow-sm hover:shadow-md transition-shadow"
+        >
+          <!-- 鎵ц鍣ㄥご閮� - 钃濊壊涓婚 -->
+          <div
+            class="flex items-center justify-between p-16px bg-gradient-to-r from-blue-50 to-sky-50 border-b border-blue-200 rounded-t-6px"
+          >
+            <div class="flex items-center gap-12px">
+              <div class="flex items-center gap-8px text-16px font-600 text-blue-700">
+                <div
+                  class="w-24px h-24px bg-blue-500 text-white rounded-full flex items-center justify-center text-12px font-bold"
+                >
+                  {{ index + 1 }}
+                </div>
+                <span>鎵ц鍣� {{ index + 1 }}</span>
+              </div>
+              <el-tag :type="getActionTypeTag(action.type)" size="small" class="font-500">
+                {{ getActionTypeLabel(action.type) }}
+              </el-tag>
+            </div>
+            <div class="flex items-center gap-8px">
+              <el-button
+                v-if="actions.length > 1"
+                type="danger"
+                size="small"
+                text
+                @click="removeAction(index)"
+                class="hover:bg-red-50"
+              >
+                <Icon icon="ep:delete" />
+                鍒犻櫎
+              </el-button>
+            </div>
+          </div>
+
+          <!-- 鎵ц鍣ㄥ唴瀹瑰尯鍩� -->
+          <div class="p-16px space-y-16px">
+            <!-- 鎵ц绫诲瀷閫夋嫨 -->
+            <div class="w-full">
+              <el-form-item label="鎵ц绫诲瀷" required>
+                <el-select
+                  :model-value="action.type"
+                  @update:model-value="(value) => updateActionType(index, value)"
+                  @change="(value) => onActionTypeChange(action, value)"
+                  placeholder="璇烽�夋嫨鎵ц绫诲瀷"
+                  class="w-full"
+                >
+                  <el-option
+                    v-for="option in getActionTypeOptions()"
+                    :key="option.value"
+                    :label="option.label"
+                    :value="option.value"
+                  />
+                </el-select>
+              </el-form-item>
+            </div>
+
+            <!-- 璁惧鎺у埗閰嶇疆 -->
+            <DeviceControlConfig
+              v-if="isDeviceAction(action.type)"
+              :model-value="action"
+              @update:model-value="(value) => updateAction(index, value)"
+            />
+
+            <!-- 鍛婅閰嶇疆 - 鍙湁鎭㈠鍛婅鏃舵墠鏄剧ず -->
+            <AlertConfig
+              v-if="action.type === IotRuleSceneActionTypeEnum.ALERT_RECOVER"
+              :model-value="action.alertConfigId"
+              @update:model-value="(value) => updateActionAlertConfig(index, value)"
+            />
+
+            <!-- 瑙﹀彂鍛婅鎻愮ず - 瑙﹀彂鍛婅鏃舵樉绀� -->
+            <div
+              v-if="action.type === IotRuleSceneActionTypeEnum.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>
+
+      <!-- 娣诲姞鎻愮ず -->
+      <div v-if="actions.length > 0" class="text-center py-16px">
+        <el-button type="primary" plain @click="addAction">
+          <Icon icon="ep:plus" />
+          缁х画娣诲姞鎵ц鍣�
+        </el-button>
+      </div>
+    </div>
+  </el-card>
+</template>
+
+<script setup lang="ts">
+import { useVModel } from '@vueuse/core'
+import DeviceControlConfig from '../configs/DeviceControlConfig.vue'
+import AlertConfig from '../configs/AlertConfig.vue'
+import type { Action } from '@/api/iot/rule/scene'
+import {
+  getActionTypeLabel,
+  getActionTypeOptions,
+  IotRuleSceneActionTypeEnum
+} from '@/views/iot/utils/constants'
+
+/** 鎵ц鍣ㄩ厤缃粍浠� */
+defineOptions({ name: 'ActionSection' })
+
+const props = defineProps<{
+  actions: Action[]
+}>()
+
+const emit = defineEmits<{
+  (e: 'update:actions', value: Action[]): void
+}>()
+
+const actions = useVModel(props, 'actions', emit)
+
+/** 鑾峰彇鎵ц鍣ㄦ爣绛剧被鍨嬶紙鐢ㄤ簬 el-tag 鐨� type 灞炴�э級 */
+const getActionTypeTag = (type: number): 'primary' | 'success' | 'info' | 'warning' | 'danger' => {
+  const actionTypeTags = {
+    [IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET]: 'primary',
+    [IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE]: 'success',
+    [IotRuleSceneActionTypeEnum.ALERT_TRIGGER]: 'danger',
+    [IotRuleSceneActionTypeEnum.ALERT_RECOVER]: 'warning'
+  } as const
+  return actionTypeTags[type] || 'info'
+}
+
+/** 鍒ゆ柇鏄惁涓鸿澶囨墽琛屽櫒绫诲瀷 */
+const isDeviceAction = (type: number): boolean => {
+  const deviceActionTypes = [
+    IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET,
+    IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE
+  ] as number[]
+  return deviceActionTypes.includes(type)
+}
+
+/** 鍒ゆ柇鏄惁涓哄憡璀︽墽琛屽櫒绫诲瀷 */
+const isAlertAction = (type: number): boolean => {
+  const alertActionTypes = [
+    IotRuleSceneActionTypeEnum.ALERT_TRIGGER,
+    IotRuleSceneActionTypeEnum.ALERT_RECOVER
+  ] as number[]
+  return alertActionTypes.includes(type)
+}
+
+/**
+ * 鍒涘缓榛樿鐨勬墽琛屽櫒鏁版嵁
+ * @returns 榛樿鎵ц鍣ㄥ璞�
+ */
+const createDefaultActionData = (): Action => {
+  return {
+    type: IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET, // 榛樿涓鸿澶囧睘鎬ц缃�
+    productId: undefined,
+    deviceId: undefined,
+    identifier: undefined, // 鐗╂ā鍨嬫爣璇嗙锛堟湇鍔¤皟鐢ㄦ椂浣跨敤锛�
+    params: undefined,
+    alertConfigId: undefined
+  }
+}
+
+/**
+ * 娣诲姞鎵ц鍣�
+ */
+const addAction = () => {
+  const newAction = createDefaultActionData()
+  actions.value.push(newAction)
+}
+
+/**
+ * 鍒犻櫎鎵ц鍣�
+ * @param index 鎵ц鍣ㄧ储寮�
+ */
+const removeAction = (index: number) => {
+  actions.value.splice(index, 1)
+}
+
+/**
+ * 鏇存柊鎵ц鍣ㄧ被鍨�
+ * @param index 鎵ц鍣ㄧ储寮�
+ * @param type 鎵ц鍣ㄧ被鍨�
+ */
+const updateActionType = (index: number, type: number) => {
+  actions.value[index].type = type
+  onActionTypeChange(actions.value[index], type)
+}
+
+/**
+ * 鏇存柊鎵ц鍣�
+ * @param index 鎵ц鍣ㄧ储寮�
+ * @param action 鎵ц鍣ㄥ璞�
+ */
+const updateAction = (index: number, action: Action) => {
+  actions.value[index] = action
+}
+
+/**
+ * 鏇存柊鍛婅閰嶇疆
+ * @param index 鎵ц鍣ㄧ储寮�
+ * @param alertConfigId 鍛婅閰嶇疆ID
+ */
+const updateActionAlertConfig = (index: number, alertConfigId?: number) => {
+  actions.value[index].alertConfigId = alertConfigId
+}
+
+/**
+ * 鐩戝惉鎵ц鍣ㄧ被鍨嬪彉鍖�
+ * @param action 鎵ц鍣ㄥ璞�
+ * @param type 鎵ц鍣ㄧ被鍨�
+ */
+const onActionTypeChange = (action: Action, type: number) => {
+  // 娓呯悊涓嶇浉鍏崇殑閰嶇疆锛岀‘淇濇暟鎹粨鏋勫共鍑�
+  if (isDeviceAction(type)) {
+    // 璁惧鎺у埗绫诲瀷锛氭竻鐞嗗憡璀﹂厤缃紝纭繚璁惧鍙傛暟瀛樺湪
+    action.alertConfigId = undefined
+    if (!action.params) {
+      action.params = ''
+    }
+    // 濡傛灉浠庡叾浠栫被鍨嬪垏鎹㈠埌璁惧鎺у埗绫诲瀷锛屾竻绌篿dentifier锛堣鐢ㄦ埛閲嶆柊閫夋嫨锛�
+    if (action.identifier && type !== action.type) {
+      action.identifier = undefined
+    }
+  } else if (isAlertAction(type)) {
+    action.productId = undefined
+    action.deviceId = undefined
+    action.identifier = undefined // 娓呯悊鏈嶅姟鏍囪瘑绗�
+    action.params = undefined
+    action.alertConfigId = undefined
+  }
+}
+</script>

--
Gitblit v1.8.0