mirror of
https://github.com/yudaocode/yudao-ui-admin-vue3.git
synced 2026-04-19 13:28:39 +00:00
feat(iot):【场景联动】定时触发,增加条件组
This commit is contained in:
@@ -0,0 +1,174 @@
|
|||||||
|
<!-- 定时触发器条件组配置组件 -->
|
||||||
|
<template>
|
||||||
|
<div class="space-y-16px">
|
||||||
|
<!-- 条件组容器头部 -->
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between p-16px bg-gradient-to-r from-blue-50 to-cyan-50 border border-blue-200 rounded-8px"
|
||||||
|
>
|
||||||
|
<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"
|
||||||
|
>
|
||||||
|
组
|
||||||
|
</div>
|
||||||
|
<span>附加条件组</span>
|
||||||
|
</div>
|
||||||
|
<el-tag size="small" type="info">定时触发时需满足以下条件</el-tag>
|
||||||
|
<el-tag size="small" type="warning">
|
||||||
|
{{ conditionGroups?.length || 0 }} 个子条件组
|
||||||
|
</el-tag>
|
||||||
|
</div>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
size="small"
|
||||||
|
@click="addConditionGroup"
|
||||||
|
:disabled="(conditionGroups?.length || 0) >= maxGroups"
|
||||||
|
>
|
||||||
|
<Icon icon="ep:plus" />
|
||||||
|
添加条件组
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 条件组列表 -->
|
||||||
|
<div v-if="conditionGroups && conditionGroups.length > 0" class="space-y-16px">
|
||||||
|
<div
|
||||||
|
v-for="(group, groupIndex) in conditionGroups"
|
||||||
|
:key="`group-${groupIndex}`"
|
||||||
|
class="relative"
|
||||||
|
>
|
||||||
|
<!-- 条件组容器 -->
|
||||||
|
<div
|
||||||
|
class="border-2 border-orange-200 rounded-8px bg-orange-50 shadow-sm hover:shadow-md transition-shadow"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="flex items-center justify-between p-16px bg-gradient-to-r from-orange-50 to-yellow-50 border-b border-orange-200 rounded-t-6px"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-12px">
|
||||||
|
<div class="flex items-center gap-8px text-16px font-600 text-orange-700">
|
||||||
|
<div
|
||||||
|
class="w-24px h-24px bg-orange-500 text-white rounded-full flex items-center justify-center text-12px font-bold"
|
||||||
|
>
|
||||||
|
{{ groupIndex + 1 }}
|
||||||
|
</div>
|
||||||
|
<span>子条件组 {{ groupIndex + 1 }}</span>
|
||||||
|
</div>
|
||||||
|
<el-tag size="small" type="warning" class="font-500">组内条件为"且"关系</el-tag>
|
||||||
|
<el-tag size="small" type="info"> {{ group?.length || 0 }}个条件 </el-tag>
|
||||||
|
</div>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
size="small"
|
||||||
|
text
|
||||||
|
@click="removeConditionGroup(groupIndex)"
|
||||||
|
class="hover:bg-red-50"
|
||||||
|
>
|
||||||
|
<Icon icon="ep:delete" />
|
||||||
|
删除组
|
||||||
|
</el-button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<SubConditionGroupConfig
|
||||||
|
:model-value="group"
|
||||||
|
@update:model-value="(value) => updateConditionGroup(groupIndex, value)"
|
||||||
|
:trigger-type="IotRuleSceneTriggerTypeEnum.TIMER"
|
||||||
|
:max-conditions="maxConditionsPerGroup"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 条件组间的"或"连接符 -->
|
||||||
|
<div
|
||||||
|
v-if="groupIndex < conditionGroups.length - 1"
|
||||||
|
class="flex items-center justify-center py-12px"
|
||||||
|
>
|
||||||
|
<div class="flex items-center gap-8px">
|
||||||
|
<!-- 连接线 -->
|
||||||
|
<div class="w-32px h-1px bg-orange-300"></div>
|
||||||
|
<!-- 或标签 -->
|
||||||
|
<div class="px-16px py-6px bg-orange-100 border-2 border-orange-300 rounded-full">
|
||||||
|
<span class="text-14px font-600 text-orange-600">或</span>
|
||||||
|
</div>
|
||||||
|
<!-- 连接线 -->
|
||||||
|
<div class="w-32px h-1px bg-orange-300"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 空状态 -->
|
||||||
|
<div
|
||||||
|
v-else
|
||||||
|
class="p-24px border-2 border-dashed border-blue-200 rounded-8px text-center bg-blue-50"
|
||||||
|
>
|
||||||
|
<div class="flex flex-col items-center gap-12px">
|
||||||
|
<Icon icon="ep:plus" class="text-32px text-blue-400" />
|
||||||
|
<div class="text-blue-600">
|
||||||
|
<p class="text-14px font-500 mb-4px">暂无附加条件</p>
|
||||||
|
<p class="text-12px">定时触发时将直接执行动作</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useVModel } from '@vueuse/core'
|
||||||
|
import SubConditionGroupConfig from './SubConditionGroupConfig.vue'
|
||||||
|
import type { TriggerCondition } from '@/api/iot/rule/scene'
|
||||||
|
import { IotRuleSceneTriggerTypeEnum } from '@/views/iot/utils/constants'
|
||||||
|
|
||||||
|
/** 定时触发器条件组配置组件 */
|
||||||
|
defineOptions({ name: 'TimerConditionGroupConfig' })
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
modelValue?: TriggerCondition[][]
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const emit = defineEmits<{
|
||||||
|
(e: 'update:modelValue', value: TriggerCondition[][]): void
|
||||||
|
}>()
|
||||||
|
|
||||||
|
const conditionGroups = useVModel(props, 'modelValue', emit)
|
||||||
|
|
||||||
|
const maxGroups = 3 // 最多 3 个条件组
|
||||||
|
const maxConditionsPerGroup = 3 // 每组最多 3 个条件
|
||||||
|
|
||||||
|
/** 添加条件组 */
|
||||||
|
const addConditionGroup = async () => {
|
||||||
|
if (!conditionGroups.value) {
|
||||||
|
conditionGroups.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否达到最大条件组数量限制
|
||||||
|
if (conditionGroups.value.length >= maxGroups) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用 nextTick 确保响应式更新完成后再添加新的条件组
|
||||||
|
await nextTick()
|
||||||
|
if (conditionGroups.value) {
|
||||||
|
conditionGroups.value.push([])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 移除条件组
|
||||||
|
* @param index 条件组索引
|
||||||
|
*/
|
||||||
|
const removeConditionGroup = (index: number) => {
|
||||||
|
if (conditionGroups.value) {
|
||||||
|
conditionGroups.value.splice(index, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新条件组
|
||||||
|
* @param index 条件组索引
|
||||||
|
* @param group 条件组数据
|
||||||
|
*/
|
||||||
|
const updateConditionGroup = (index: number, group: TriggerCondition[]) => {
|
||||||
|
if (conditionGroups.value) {
|
||||||
|
conditionGroups.value[index] = group
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@@ -90,6 +90,12 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- 附加条件组配置 -->
|
||||||
|
<TimerConditionGroupConfig
|
||||||
|
:model-value="triggerItem.conditionGroups"
|
||||||
|
@update:model-value="(value) => updateTriggerConditionGroups(index, value)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -115,8 +121,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useVModel } from '@vueuse/core'
|
import { useVModel } from '@vueuse/core'
|
||||||
import DeviceTriggerConfig from '../configs/DeviceTriggerConfig.vue'
|
import DeviceTriggerConfig from '../configs/DeviceTriggerConfig.vue'
|
||||||
|
import TimerConditionGroupConfig from '../configs/TimerConditionGroupConfig.vue'
|
||||||
import { Crontab } from '@/components/Crontab'
|
import { Crontab } from '@/components/Crontab'
|
||||||
import type { Trigger } from '@/api/iot/rule/scene'
|
import type { Trigger, TriggerCondition } from '@/api/iot/rule/scene'
|
||||||
import {
|
import {
|
||||||
getTriggerTypeLabel,
|
getTriggerTypeLabel,
|
||||||
IotRuleSceneTriggerTypeEnum,
|
IotRuleSceneTriggerTypeEnum,
|
||||||
@@ -197,6 +204,15 @@ const updateTriggerCronConfig = (index: number, cronExpression?: string) => {
|
|||||||
triggers.value[index].cronExpression = cronExpression
|
triggers.value[index].cronExpression = cronExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新触发器条件组配置
|
||||||
|
* @param index 触发器索引
|
||||||
|
* @param conditionGroups 条件组数组
|
||||||
|
*/
|
||||||
|
const updateTriggerConditionGroups = (index: number, conditionGroups: TriggerCondition[][]) => {
|
||||||
|
triggers.value[index].conditionGroups = conditionGroups
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理触发器类型变化事件
|
* 处理触发器类型变化事件
|
||||||
* @param index 触发器索引
|
* @param index 触发器索引
|
||||||
|
|||||||
@@ -219,13 +219,23 @@ const thingModelTSL = ref<IotThingModelTSLResp | null>(null) // 物模型TSL数
|
|||||||
const propertyGroups = computed(() => {
|
const propertyGroups = computed(() => {
|
||||||
const groups: { label: string; options: any[] }[] = []
|
const groups: { label: string; options: any[] }[] = []
|
||||||
|
|
||||||
if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST) {
|
// 设备属性上报触发器 或 定时触发器(条件组中的设备属性条件)
|
||||||
groups.push({
|
if (
|
||||||
label: THING_MODEL_GROUP_LABELS.PROPERTY,
|
props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST ||
|
||||||
options: propertyList.value.filter((p) => p.type === IoTThingModelTypeEnum.PROPERTY)
|
props.triggerType === IotRuleSceneTriggerTypeEnum.TIMER
|
||||||
})
|
) {
|
||||||
|
const propertyOptions = propertyList.value.filter(
|
||||||
|
(p) => p.type === IoTThingModelTypeEnum.PROPERTY
|
||||||
|
)
|
||||||
|
if (propertyOptions.length > 0) {
|
||||||
|
groups.push({
|
||||||
|
label: THING_MODEL_GROUP_LABELS.PROPERTY,
|
||||||
|
options: propertyOptions
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设备事件上报触发器
|
||||||
if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST) {
|
if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST) {
|
||||||
groups.push({
|
groups.push({
|
||||||
label: THING_MODEL_GROUP_LABELS.EVENT,
|
label: THING_MODEL_GROUP_LABELS.EVENT,
|
||||||
@@ -233,6 +243,7 @@ const propertyGroups = computed(() => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 设备服务调用触发器
|
||||||
if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE) {
|
if (props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE) {
|
||||||
groups.push({
|
groups.push({
|
||||||
label: THING_MODEL_GROUP_LABELS.SERVICE,
|
label: THING_MODEL_GROUP_LABELS.SERVICE,
|
||||||
|
|||||||
Reference in New Issue
Block a user