Files
yudao-ui-admin-vue3/src/views/iot/rule/scene/form/sections/ActionSection.vue

262 lines
8.4 KiB
Vue
Raw Normal View History

<!-- 执行器配置组件 -->
<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 }}/{{ maxActions }}</el-tag>
</div>
<div class="flex items-center gap-8px">
<el-button
type="primary"
size="small"
@click="addAction"
:disabled="actions.length >= maxActions"
>
<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 === 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>
<!-- 添加提示 -->
<div v-if="actions.length > 0 && actions.length < maxActions" class="text-center py-16px">
<el-button type="primary" plain @click="addAction">
<Icon icon="ep:plus" />
继续添加执行器
</el-button>
<span class="block mt-8px text-12px text-[var(--el-text-color-secondary)]">
最多可添加 {{ maxActions }} 个执行器
</span>
</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 {
IotRuleSceneActionTypeEnum as ActionTypeEnum,
isDeviceAction,
isAlertAction,
getActionTypeLabel,
getActionTypeOptions,
getActionTypeTag,
SCENE_RULE_CONFIG
} 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)
const maxActions = SCENE_RULE_CONFIG.MAX_ACTIONS // 最大执行器数量
/**
* 创建默认的执行器数据
* @returns 默认执行器对象
*/
const createDefaultActionData = (): Action => {
return {
type: ActionTypeEnum.DEVICE_PROPERTY_SET, // 默认为设备属性设置
productId: undefined,
deviceId: undefined,
identifier: undefined, // 物模型标识符(服务调用时使用)
params: undefined,
alertConfigId: undefined
}
}
/**
* 添加执行器
*/
const addAction = () => {
if (actions.value.length >= maxActions) {
return
}
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 = ''
}
// 如果从其他类型切换到设备控制类型清空identifier让用户重新选择
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>