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