<!-- 设备触发配置组件 -->
|
<script setup lang="ts">
|
import type { RuleSceneApi } from '#/api/iot/rule/scene';
|
|
import { nextTick } from 'vue';
|
|
import { IconifyIcon } from '..\..\..\..\..\..\packages\icons\src';
|
import { getStableObjectKey } from '..\..\..\..\..\..\packages\utils\src';
|
|
import { useVModel } from '@vueuse/core';
|
import { Button, Tag } from 'ant-design-vue';
|
|
import MainConditionInnerConfig from './main-condition-inner-config.vue';
|
import SubConditionGroupConfig from './sub-condition-group-config.vue';
|
|
/** 设备触发配置组件 */
|
defineOptions({ name: 'DeviceTriggerConfig' });
|
|
const props = defineProps<{
|
index: number;
|
modelValue: RuleSceneApi.Trigger;
|
}>();
|
|
const emit = defineEmits<{
|
(e: 'update:modelValue', value: RuleSceneApi.Trigger): void;
|
(e: 'triggerTypeChange', type: number): void;
|
}>();
|
|
const trigger = useVModel(props, 'modelValue', emit);
|
|
const maxSubGroups = 3; // 最多 3 个子条件组
|
const maxConditionsPerGroup = 3; // 每组最多 3 个条件
|
|
/**
|
* 更新条件
|
* @param condition 条件对象
|
*/
|
function updateCondition(condition: RuleSceneApi.Trigger) {
|
trigger.value = condition;
|
}
|
|
/**
|
* 处理触发器类型变化事件
|
* @param type 触发器类型
|
*/
|
function handleTriggerTypeChange(type: number) {
|
trigger.value.type = type;
|
emit('triggerTypeChange', type);
|
}
|
|
/** 添加子条件组 */
|
async function addSubGroup() {
|
if (!trigger.value.conditionGroups) {
|
trigger.value.conditionGroups = [];
|
}
|
|
// 检查是否达到最大子组数量限制
|
if (trigger.value.conditionGroups?.length >= maxSubGroups) {
|
return;
|
}
|
|
// 使用 nextTick 确保响应式更新完成后再添加新的子组
|
await nextTick();
|
if (trigger.value.conditionGroups) {
|
trigger.value.conditionGroups.push([] as any);
|
}
|
}
|
|
/**
|
* 移除子条件组
|
* @param index 子条件组索引
|
*/
|
function removeSubGroup(index: number) {
|
if (trigger.value.conditionGroups) {
|
trigger.value.conditionGroups.splice(index, 1);
|
}
|
}
|
|
/**
|
* 更新子条件组
|
* @param index 子条件组索引
|
* @param subGroup 子条件组数据
|
*/
|
function updateSubGroup(index: number, subGroup: any) {
|
if (trigger.value.conditionGroups) {
|
trigger.value.conditionGroups[index] = subGroup;
|
}
|
}
|
|
/** 移除整个条件组 */
|
function removeConditionGroup() {
|
trigger.value.conditionGroups = undefined;
|
}
|
</script>
|
|
<template>
|
<div class="gap-[16px] flex flex-col">
|
<!-- 主条件配置 - 默认直接展示 -->
|
<div class="space-y-[16px]">
|
<!-- 主条件配置 -->
|
<div class="gap-[16px] flex flex-col">
|
<!-- 主条件配置 -->
|
<div class="space-y-[16px]">
|
<!-- 主条件头部(绿色主题) -->
|
<div
|
class="px-[16px] py-[10px] rounded-[6px] flex items-center justify-between border border-green-200 bg-gradient-to-r from-green-50 to-emerald-50 dark:border-green-900/40 dark:from-green-950/30 dark:to-emerald-950/30"
|
>
|
<div class="gap-[10px] flex items-center">
|
<div
|
class="gap-[8px] text-[14px] font-semibold flex items-center text-green-700 dark:text-green-300"
|
>
|
<div
|
class="w-[22px] h-[22px] text-[12px] flex items-center justify-center rounded-full bg-green-500 font-bold text-white"
|
>
|
主
|
</div>
|
<span>主条件</span>
|
</div>
|
<Tag color="success">必须满足</Tag>
|
</div>
|
</div>
|
|
<!-- 主条件内容配置 -->
|
<MainConditionInnerConfig
|
:model-value="trigger"
|
@update:model-value="updateCondition"
|
:trigger-type="trigger.type as number"
|
@trigger-type-change="handleTriggerTypeChange"
|
/>
|
</div>
|
</div>
|
</div>
|
|
<!-- 条件组配置 -->
|
<div class="space-y-[16px]">
|
<!-- 条件组配置 -->
|
<div class="gap-[16px] flex flex-col">
|
<!-- 条件组容器头部(绿色主题) -->
|
<div
|
class="px-[16px] py-[10px] rounded-[6px] flex items-center justify-between border border-green-200 bg-gradient-to-r from-green-50 to-emerald-50 dark:border-green-900/40 dark:from-green-950/30 dark:to-emerald-950/30"
|
>
|
<div class="gap-[10px] flex items-center">
|
<div
|
class="gap-[8px] text-[14px] font-semibold flex items-center text-green-700 dark:text-green-300"
|
>
|
<div
|
class="w-[22px] h-[22px] text-[12px] flex items-center justify-center rounded-full bg-green-500 font-bold text-white"
|
>
|
组
|
</div>
|
<span>附加条件组</span>
|
</div>
|
<Tag color="success">与「主条件」为且关系</Tag>
|
<Tag>{{ trigger.conditionGroups?.length || 0 }} 个子条件组</Tag>
|
</div>
|
<div class="gap-[8px] flex items-center">
|
<Button
|
type="primary"
|
size="small"
|
@click="addSubGroup"
|
:disabled="(trigger.conditionGroups?.length || 0) >= maxSubGroups"
|
>
|
<IconifyIcon icon="lucide:plus" />
|
添加子条件组
|
</Button>
|
<Button
|
danger
|
size="small"
|
type="link"
|
@click="removeConditionGroup"
|
>
|
<IconifyIcon icon="lucide:trash-2" />
|
删除条件组
|
</Button>
|
</div>
|
</div>
|
|
<!-- 子条件组列表 -->
|
<div
|
v-if="trigger.conditionGroups && trigger.conditionGroups.length > 0"
|
class="space-y-[16px]"
|
>
|
<!-- 逻辑关系说明 -->
|
<div class="relative">
|
<div
|
v-for="(subGroup, subGroupIndex) in trigger.conditionGroups"
|
:key="getStableObjectKey(subGroup)"
|
class="relative"
|
>
|
<!-- 子条件组容器(橙色主题) -->
|
<div
|
class="rounded-[8px] border border-orange-200 bg-orange-50/40 shadow-sm transition-shadow hover:shadow-md dark:border-orange-900/40 dark:bg-orange-950/20"
|
>
|
<div
|
class="px-[16px] py-[10px] rounded-t-[8px] flex items-center justify-between border-b border-orange-200 bg-gradient-to-r from-orange-50 to-yellow-50 dark:border-orange-900/40 dark:from-orange-950/30 dark:to-yellow-950/30"
|
>
|
<div class="gap-[10px] flex items-center">
|
<div
|
class="gap-[8px] text-[14px] font-semibold flex items-center text-orange-700 dark:text-orange-300"
|
>
|
<div
|
class="w-[22px] h-[22px] text-[12px] flex items-center justify-center rounded-full bg-orange-500 font-bold text-white"
|
>
|
{{ subGroupIndex + 1 }}
|
</div>
|
<span>子条件组 {{ subGroupIndex + 1 }}</span>
|
</div>
|
<Tag color="warning" class="font-medium">
|
组内条件为「且」关系
|
</Tag>
|
<Tag color="default">
|
{{ (subGroup as any)?.length || 0 }} 个条件
|
</Tag>
|
</div>
|
<Button
|
danger
|
size="small"
|
type="link"
|
class="hover:bg-red-50"
|
@click="removeSubGroup(subGroupIndex)"
|
>
|
<IconifyIcon icon="lucide:trash-2" />
|
删除组
|
</Button>
|
</div>
|
|
<SubConditionGroupConfig
|
:model-value="subGroup as any"
|
@update:model-value="
|
(value) => updateSubGroup(subGroupIndex, value)
|
"
|
:trigger-type="trigger.type as number"
|
:max-conditions="maxConditionsPerGroup"
|
/>
|
</div>
|
|
<!-- 子条件组间的'或'连接符 -->
|
<div
|
v-if="subGroupIndex < trigger.conditionGroups!.length - 1"
|
class="py-[12px] flex items-center justify-center"
|
>
|
<div class="gap-[8px] flex items-center">
|
<!-- 连接线 -->
|
<div
|
class="w-[32px] h-[1px] bg-orange-300 dark:bg-orange-800"
|
></div>
|
<!-- 或标签 -->
|
<div
|
class="px-[14px] py-[3px] rounded-full border border-orange-300 bg-orange-100 dark:border-orange-800 dark:bg-orange-950/50"
|
>
|
<span
|
class="text-[13px] font-semibold text-orange-600 dark:text-orange-300"
|
>
|
或
|
</span>
|
</div>
|
<!-- 连接线 -->
|
<div
|
class="w-[32px] h-[1px] bg-orange-300 dark:bg-orange-800"
|
></div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
|
<!-- 空状态(橙色主题) -->
|
<div
|
v-else
|
class="p-[24px] rounded-[8px] border-2 border-dashed border-orange-200 bg-orange-50/40 text-center dark:border-orange-900/40 dark:bg-orange-950/10"
|
>
|
<div class="gap-[10px] flex flex-col items-center">
|
<IconifyIcon
|
icon="lucide:plus"
|
class="text-[28px] text-orange-400 dark:text-orange-300"
|
/>
|
<div class="text-orange-600 dark:text-orange-300">
|
<p class="text-[13px] font-medium mb-[2px]">暂无子条件组</p>
|
<p class="text-[12px]">点击上方「添加子条件组」按钮开始配置</p>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</div>
|
</template>
|