【功能完善】IoT: 规则场景监听器相关组件
This commit is contained in:
@ -1,12 +1,13 @@
|
|||||||
import request from '@/config/axios'
|
import request from '@/config/axios'
|
||||||
|
import { IotRuleSceneTriggerConfig } from '@/api/iot/rule/scene/scene.types'
|
||||||
|
|
||||||
// IoT 规则场景(场景联动) VO
|
// IoT 规则场景(场景联动) VO
|
||||||
export interface RuleSceneVO {
|
export interface RuleSceneVO {
|
||||||
id?: number // 场景编号
|
id?: number // 场景编号
|
||||||
name?: string // 场景名称
|
name: string // 场景名称
|
||||||
description?: string // 场景描述
|
description?: string // 场景描述
|
||||||
status?: number // 场景状态
|
status: number // 场景状态
|
||||||
triggers?: any[] // 触发器数组
|
triggers: IotRuleSceneTriggerConfig[] // 触发器数组
|
||||||
actions?: any[] // 执行器数组
|
actions?: any[] // 执行器数组
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,11 +9,11 @@ export interface IotRuleSceneTriggerConfig {
|
|||||||
*/
|
*/
|
||||||
type: number
|
type: number
|
||||||
/** 产品标识 */
|
/** 产品标识 */
|
||||||
productKey?: string
|
productKey: string
|
||||||
/** 设备名称数组 */
|
/** 设备名称数组 */
|
||||||
deviceNames?: string[]
|
deviceNames: string[]
|
||||||
/** 触发条件数组。条件之间是"或"的关系 */
|
/** 触发条件数组。条件之间是"或"的关系 */
|
||||||
conditions?: IotRuleSceneTriggerCondition[]
|
conditions: IotRuleSceneTriggerCondition[]
|
||||||
/** CRON 表达式。当 type = 2 时必填 */
|
/** CRON 表达式。当 type = 2 时必填 */
|
||||||
cronExpression?: string
|
cronExpression?: string
|
||||||
}
|
}
|
||||||
@ -29,7 +29,7 @@ export interface IotRuleSceneTriggerCondition {
|
|||||||
*/
|
*/
|
||||||
type: string
|
type: string
|
||||||
/** 消息标识符 */
|
/** 消息标识符 */
|
||||||
identifier: string
|
identifier?: string
|
||||||
/** 参数数组。参数之间是"或"的关系 */
|
/** 参数数组。参数之间是"或"的关系 */
|
||||||
parameters: IotRuleSceneTriggerConditionParameter[]
|
parameters: IotRuleSceneTriggerConditionParameter[]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,7 +61,7 @@ export const useAppStore = defineStore('app', {
|
|||||||
tagsView: true, // 标签页
|
tagsView: true, // 标签页
|
||||||
tagsViewImmerse: false, // 标签页沉浸
|
tagsViewImmerse: false, // 标签页沉浸
|
||||||
tagsViewIcon: true, // 是否显示标签图标
|
tagsViewIcon: true, // 是否显示标签图标
|
||||||
logo: true, // logo
|
logo: false, // logo
|
||||||
fixedHeader: true, // 固定toolheader
|
fixedHeader: true, // 固定toolheader
|
||||||
footer: true, // 显示页脚
|
footer: true, // 显示页脚
|
||||||
greyMode: false, // 是否开始灰色模式,用于特殊悼念日
|
greyMode: false, // 是否开始灰色模式,用于特殊悼念日
|
||||||
|
|||||||
@ -35,10 +35,19 @@
|
|||||||
<el-divider content-position="left">触发器配置</el-divider>
|
<el-divider content-position="left">触发器配置</el-divider>
|
||||||
<device-listener
|
<device-listener
|
||||||
v-for="(trigger, index) in formData.triggers"
|
v-for="(trigger, index) in formData.triggers"
|
||||||
:model-value="trigger"
|
|
||||||
:key="index"
|
:key="index"
|
||||||
|
:model-value="trigger"
|
||||||
|
@update:model-value="(val) => (formData.triggers[index] = val)"
|
||||||
class="mb-10px"
|
class="mb-10px"
|
||||||
/>
|
>
|
||||||
|
<el-button
|
||||||
|
type="danger"
|
||||||
|
round
|
||||||
|
:icon="Delete"
|
||||||
|
size="small"
|
||||||
|
@click="removeTrigger(index)"
|
||||||
|
/>
|
||||||
|
</device-listener>
|
||||||
<el-text class="ml-10px!" type="primary" @click="addTrigger">添加触发器</el-text>
|
<el-text class="ml-10px!" type="primary" @click="addTrigger">添加触发器</el-text>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
@ -59,6 +68,8 @@
|
|||||||
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
|
||||||
import { RuleSceneApi, RuleSceneVO } from '@/api/iot/rule/scene'
|
import { RuleSceneApi, RuleSceneVO } from '@/api/iot/rule/scene'
|
||||||
import DeviceListener from './components/DeviceListener.vue'
|
import DeviceListener from './components/DeviceListener.vue'
|
||||||
|
import { Delete } from '@element-plus/icons-vue'
|
||||||
|
import { IotRuleSceneTriggerConfig } from '@/api/iot/rule/scene/scene.types'
|
||||||
|
|
||||||
/** IoT 规则场景(场景联动) 表单 */
|
/** IoT 规则场景(场景联动) 表单 */
|
||||||
defineOptions({ name: 'RuleSceneForm' })
|
defineOptions({ name: 'RuleSceneForm' })
|
||||||
@ -72,7 +83,7 @@ const formLoading = ref(false) // 表单的加载中:1)修改时的数据加
|
|||||||
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
const formType = ref('') // 表单的类型:create - 新增;update - 修改
|
||||||
const formData = ref<RuleSceneVO>({
|
const formData = ref<RuleSceneVO>({
|
||||||
status: 0,
|
status: 0,
|
||||||
triggers: []
|
triggers: [] as IotRuleSceneTriggerConfig[]
|
||||||
} as RuleSceneVO)
|
} as RuleSceneVO)
|
||||||
const formRules = reactive({
|
const formRules = reactive({
|
||||||
name: [{ required: true, message: '场景名称不能为空', trigger: 'blur' }],
|
name: [{ required: true, message: '场景名称不能为空', trigger: 'blur' }],
|
||||||
@ -82,10 +93,26 @@ const formRules = reactive({
|
|||||||
})
|
})
|
||||||
const formRef = ref() // 表单 Ref
|
const formRef = ref() // 表单 Ref
|
||||||
|
|
||||||
|
/** 添加触发器 */
|
||||||
const addTrigger = () => {
|
const addTrigger = () => {
|
||||||
formData.value.triggers?.push({})
|
formData.value.triggers.push({
|
||||||
|
type: 1,
|
||||||
|
productKey: '',
|
||||||
|
deviceNames: [],
|
||||||
|
conditions: [
|
||||||
|
{
|
||||||
|
type: 'property',
|
||||||
|
parameters: []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/** 移除触发器 */
|
||||||
|
const removeTrigger = (index: number) => {
|
||||||
|
const newTriggers = [...formData.value.triggers]
|
||||||
|
newTriggers.splice(index, 1)
|
||||||
|
formData.value.triggers = newTriggers
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 打开弹窗 */
|
/** 打开弹窗 */
|
||||||
const open = async (type: string, id?: number) => {
|
const open = async (type: string, id?: number) => {
|
||||||
dialogVisible.value = true
|
dialogVisible.value = true
|
||||||
@ -132,7 +159,7 @@ const submitForm = async () => {
|
|||||||
const resetForm = () => {
|
const resetForm = () => {
|
||||||
formData.value = {
|
formData.value = {
|
||||||
status: 0,
|
status: 0,
|
||||||
triggers: []
|
triggers: [] as IotRuleSceneTriggerConfig[]
|
||||||
} as RuleSceneVO
|
} as RuleSceneVO
|
||||||
formRef.value?.resetFields()
|
formRef.value?.resetFields()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,12 @@
|
|||||||
<div class="device-listener-header h-50px flex items-center px-10px">
|
<div class="device-listener-header h-50px flex items-center px-10px">
|
||||||
<div class="flex items-center mr-60px">
|
<div class="flex items-center mr-60px">
|
||||||
<span class="mr-10px">触发条件</span>
|
<span class="mr-10px">触发条件</span>
|
||||||
<el-select v-model="triggerType" class="!w-240px" clearable placeholder="请选择触发条件">
|
<el-select
|
||||||
|
v-model="triggerConfig.type"
|
||||||
|
class="!w-240px"
|
||||||
|
clearable
|
||||||
|
placeholder="请选择触发条件"
|
||||||
|
>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="dict in getIntDictOptions(DICT_TYPE.IOT_RULE_SCENE_TRIGGER_TYPE_ENUM)"
|
v-for="dict in getIntDictOptions(DICT_TYPE.IOT_RULE_SCENE_TRIGGER_TYPE_ENUM)"
|
||||||
:key="dict.value"
|
:key="dict.value"
|
||||||
@ -20,12 +25,19 @@
|
|||||||
<span class="mr-10px">设备</span>
|
<span class="mr-10px">设备</span>
|
||||||
<el-button type="primary">选择设备</el-button>
|
<el-button type="primary">选择设备</el-button>
|
||||||
</div>
|
</div>
|
||||||
<!-- 添加规则 -->
|
<!-- 删除触发器 -->
|
||||||
<el-button class="device-listener-delete" type="danger" round :icon="Delete" size="small" />
|
<div class="device-listener-delete">
|
||||||
|
<slot></slot>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="device-listener-condition flex p-10px">
|
<!-- 触发器条件 -->
|
||||||
|
<div
|
||||||
|
class="device-listener-condition flex p-10px"
|
||||||
|
v-for="(condition, index) in triggerConfig.conditions"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
<div class="flex flex-col items-center justify-center mr-10px h-a">
|
<div class="flex flex-col items-center justify-center mr-10px h-a">
|
||||||
<el-select v-model="messageType" class="!w-160px" clearable placeholder="">
|
<el-select v-model="condition.type" class="!w-160px" clearable placeholder="">
|
||||||
<el-option
|
<el-option
|
||||||
v-for="dict in getStrDictOptions(DICT_TYPE.IOT_DEVICE_MESSAGE_TYPE_ENUM)"
|
v-for="dict in getStrDictOptions(DICT_TYPE.IOT_DEVICE_MESSAGE_TYPE_ENUM)"
|
||||||
:key="dict.value"
|
:key="dict.value"
|
||||||
@ -36,62 +48,74 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="">
|
<div class="">
|
||||||
<DeviceListenerCondition
|
<DeviceListenerCondition
|
||||||
v-for="(conditionParameter, index) in conditionParameters"
|
v-for="(parameter, index2) in condition.parameters"
|
||||||
:key="index"
|
:key="index2"
|
||||||
:model-value="conditionParameter"
|
:model-value="parameter"
|
||||||
@update:model-value="(val) => (conditionParameters[index] = val)"
|
@update:model-value="(val) => (condition.parameters[index2] = val)"
|
||||||
class="mb-10px last:mb-0"
|
class="mb-10px last:mb-0"
|
||||||
>
|
>
|
||||||
<!-- 添加规则 -->
|
<!-- 删除规则 -->
|
||||||
<el-button
|
<el-button
|
||||||
class="device-listener-delete"
|
class="device-listener-delete"
|
||||||
type="danger"
|
type="danger"
|
||||||
circle
|
circle
|
||||||
:icon="Delete"
|
:icon="Delete"
|
||||||
size="small"
|
size="small"
|
||||||
@click="removeConditionParameter(index)"
|
@click="removeConditionParameter(condition.parameters, index2)"
|
||||||
/>
|
/>
|
||||||
</DeviceListenerCondition>
|
</DeviceListenerCondition>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-1 flex-col items-center justify-center w-a h-a">
|
<div class="flex flex-1 flex-col items-center justify-center w-a h-a">
|
||||||
<!-- 添加规则 -->
|
<!-- 添加规则 -->
|
||||||
<el-button type="primary" circle :icon="Plus" size="small" @click="addConditionParameter" />
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
circle
|
||||||
|
:icon="Plus"
|
||||||
|
size="small"
|
||||||
|
@click="addConditionParameter(condition.parameters)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<el-text class="ml-10px!" type="primary" @click="addCondition">添加触发条件</el-text>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Delete, Plus } from '@element-plus/icons-vue'
|
import { Delete, Plus } from '@element-plus/icons-vue'
|
||||||
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
|
import { DICT_TYPE, getIntDictOptions, getStrDictOptions } from '@/utils/dict'
|
||||||
import { ref } from 'vue'
|
|
||||||
import DeviceListenerCondition from './DeviceListenerCondition.vue'
|
import DeviceListenerCondition from './DeviceListenerCondition.vue'
|
||||||
import { IotRuleSceneTriggerConditionParameter } from '@/api/iot/rule/scene/scene.types'
|
import {
|
||||||
|
IotRuleSceneTriggerConditionParameter,
|
||||||
|
IotRuleSceneTriggerConfig
|
||||||
|
} from '@/api/iot/rule/scene/scene.types'
|
||||||
|
import { useVModel } from '@vueuse/core'
|
||||||
|
|
||||||
/** 场景联动之监听器组件 */
|
/** 场景联动之监听器组件 */
|
||||||
defineOptions({ name: 'DeviceListener' })
|
defineOptions({ name: 'DeviceListener' })
|
||||||
|
|
||||||
defineProps<{
|
const props = defineProps<{ modelValue: any }>()
|
||||||
modelValue: any
|
const emits = defineEmits(['update:modelValue'])
|
||||||
}>()
|
const triggerConfig = useVModel(props, 'modelValue', emits) as Ref<IotRuleSceneTriggerConfig>
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
|
||||||
|
|
||||||
// 添加响应式变量
|
|
||||||
const triggerType = ref()
|
|
||||||
const messageType = ref('property')
|
|
||||||
const conditionParameters = ref<IotRuleSceneTriggerConditionParameter[]>([])
|
|
||||||
/** 添加触发条件 */
|
/** 添加触发条件 */
|
||||||
const addConditionParameter = () => {
|
const addCondition = () => {
|
||||||
conditionParameters.value?.push({} as IotRuleSceneTriggerConditionParameter)
|
triggerConfig.value.conditions.push({
|
||||||
|
type: 'property',
|
||||||
|
parameters: []
|
||||||
|
})
|
||||||
}
|
}
|
||||||
/** 移除触发条件 */
|
|
||||||
const removeConditionParameter = (index: number) => {
|
/** 添加参数 */
|
||||||
conditionParameters.value?.splice(index, 1)
|
const addConditionParameter = (conditionParameters: IotRuleSceneTriggerConditionParameter[]) => {
|
||||||
|
conditionParameters.push({} as IotRuleSceneTriggerConditionParameter)
|
||||||
|
}
|
||||||
|
/** 移除参数 */
|
||||||
|
const removeConditionParameter = (
|
||||||
|
conditionParameters: IotRuleSceneTriggerConditionParameter[],
|
||||||
|
index: number
|
||||||
|
) => {
|
||||||
|
conditionParameters.splice(index, 1)
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
|
||||||
addConditionParameter()
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
|||||||
@ -1,379 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="trigger-conditions">
|
|
||||||
<div class="conditions-header mb-3">
|
|
||||||
<el-button type="primary" @click="addCondition" :disabled="!productKey">
|
|
||||||
<Icon icon="ep:plus" class="mr-5px" /> 添加条件
|
|
||||||
</el-button>
|
|
||||||
<div class="conditions-tips" v-if="modelValue && modelValue.length > 0">
|
|
||||||
注:多个条件之间为"或"关系
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-empty v-if="!modelValue || modelValue.length === 0" description="暂无触发条件" />
|
|
||||||
|
|
||||||
<div class="conditions-list" v-else>
|
|
||||||
<div v-for="(condition, index) in modelValue" :key="index" class="condition-item mb-3">
|
|
||||||
<el-card class="box-card">
|
|
||||||
<template #header>
|
|
||||||
<div class="card-header">
|
|
||||||
<span>条件 {{ index + 1 }}</span>
|
|
||||||
<el-button type="danger" link @click="removeCondition(index)"> 删除 </el-button>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div class="condition-content">
|
|
||||||
<el-form label-width="100px" :model="condition">
|
|
||||||
<el-form-item label="消息类型">
|
|
||||||
<el-select
|
|
||||||
v-model="condition.type"
|
|
||||||
placeholder="请选择消息类型"
|
|
||||||
@change="handleMessageTypeChange(index)"
|
|
||||||
>
|
|
||||||
<el-option label="属性上报" :value="IotDeviceMessageTypeEnum.PROPERTY" />
|
|
||||||
<el-option label="事件上报" :value="IotDeviceMessageTypeEnum.EVENT" />
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="消息标识符">
|
|
||||||
<el-select
|
|
||||||
v-model="condition.identifier"
|
|
||||||
placeholder="请选择消息标识符"
|
|
||||||
filterable
|
|
||||||
:loading="thingModelLoading"
|
|
||||||
@change="handleIdentifierChange(index)"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in getThingModelOptions(condition.type)"
|
|
||||||
:key="item.identifier"
|
|
||||||
:label="item.name"
|
|
||||||
:value="item.identifier"
|
|
||||||
>
|
|
||||||
<div class="thing-model-option">
|
|
||||||
<span>{{ item.name }}</span>
|
|
||||||
<span class="thing-model-identifier">{{ item.identifier }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="thing-model-desc" v-if="item.description">{{
|
|
||||||
item.description
|
|
||||||
}}</div>
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
|
|
||||||
<div class="parameters-area mt-3 mb-2">
|
|
||||||
<div class="parameters-header">
|
|
||||||
<div>参数列表(多个参数之间为"或"关系)</div>
|
|
||||||
<el-button type="primary" link @click="addParameter(index)"> 添加参数 </el-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-empty
|
|
||||||
v-if="!condition.parameters || condition.parameters.length === 0"
|
|
||||||
description="暂无参数"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div class="parameters-list mt-2" v-else>
|
|
||||||
<div
|
|
||||||
v-for="(param, pIndex) in condition.parameters"
|
|
||||||
:key="pIndex"
|
|
||||||
class="parameter-item mb-2"
|
|
||||||
>
|
|
||||||
<el-card shadow="hover">
|
|
||||||
<div class="parameter-item-header">
|
|
||||||
<span>参数 {{ pIndex + 1 }}</span>
|
|
||||||
<el-button type="danger" link @click="removeParameter(index, pIndex)">
|
|
||||||
删除
|
|
||||||
</el-button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<el-form label-width="90px" :model="param" class="mt-2">
|
|
||||||
<el-form-item label="标识符">
|
|
||||||
<el-select
|
|
||||||
v-model="param.identifier"
|
|
||||||
placeholder="请选择参数标识符"
|
|
||||||
filterable
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in getParameterOptions(condition)"
|
|
||||||
:key="item.identifier"
|
|
||||||
:label="item.name"
|
|
||||||
:value="item.identifier"
|
|
||||||
>
|
|
||||||
<div class="thing-model-option">
|
|
||||||
<span>{{ item.name }}</span>
|
|
||||||
<span class="thing-model-identifier">{{ item.identifier }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="thing-model-desc" v-if="item.description">{{
|
|
||||||
item.description
|
|
||||||
}}</div>
|
|
||||||
</el-option>
|
|
||||||
</el-select>
|
|
||||||
</el-form-item>
|
|
||||||
<el-form-item label="条件">
|
|
||||||
<condition-selector
|
|
||||||
v-model="param.condition"
|
|
||||||
:placeholder="'请选择条件'"
|
|
||||||
:value-placeholder="'请输入比较值'"
|
|
||||||
/>
|
|
||||||
</el-form-item>
|
|
||||||
</el-form>
|
|
||||||
</el-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-form>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { defineEmits, defineProps, onMounted, ref, watch } from 'vue'
|
|
||||||
import {
|
|
||||||
IotDeviceMessageIdentifierEnum,
|
|
||||||
IotDeviceMessageTypeEnum,
|
|
||||||
IotRuleSceneTriggerCondition,
|
|
||||||
IotRuleSceneTriggerConditionParameter
|
|
||||||
} from '@/api/iot/rule/scene/scene.types'
|
|
||||||
import { ThingModelApi, ThingModelData } from '@/api/iot/thingmodel'
|
|
||||||
import ConditionSelector from './ConditionSelector.vue'
|
|
||||||
|
|
||||||
const props = defineProps({
|
|
||||||
modelValue: {
|
|
||||||
type: Array as () => IotRuleSceneTriggerCondition[],
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
productKey: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
const emit = defineEmits(['update:modelValue'])
|
|
||||||
|
|
||||||
// 物模型数据
|
|
||||||
const thingModelList = ref<ThingModelData[]>([])
|
|
||||||
const thingModelLoading = ref(false)
|
|
||||||
|
|
||||||
// 加载物模型数据
|
|
||||||
const loadThingModelData = async () => {
|
|
||||||
if (!props.productKey) return
|
|
||||||
|
|
||||||
try {
|
|
||||||
thingModelLoading.value = true
|
|
||||||
const result = await ThingModelApi.getThingModelListByProductId({
|
|
||||||
productKey: props.productKey
|
|
||||||
})
|
|
||||||
thingModelList.value = result || []
|
|
||||||
} catch (error) {
|
|
||||||
console.error('获取物模型数据失败', error)
|
|
||||||
} finally {
|
|
||||||
thingModelLoading.value = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取物模型选项
|
|
||||||
const getThingModelOptions = (type: string) => {
|
|
||||||
if (!thingModelList.value) return []
|
|
||||||
|
|
||||||
return thingModelList.value.filter((item) => {
|
|
||||||
if (type === IotDeviceMessageTypeEnum.PROPERTY) {
|
|
||||||
return item.property
|
|
||||||
} else if (type === IotDeviceMessageTypeEnum.EVENT) {
|
|
||||||
return item.event
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取参数选项
|
|
||||||
const getParameterOptions = (condition: IotRuleSceneTriggerCondition) => {
|
|
||||||
if (!condition || !condition.identifier) return []
|
|
||||||
|
|
||||||
const model = thingModelList.value?.find((item) => item.identifier === condition.identifier)
|
|
||||||
if (!model) return []
|
|
||||||
|
|
||||||
if (condition.type === IotDeviceMessageTypeEnum.PROPERTY) {
|
|
||||||
return [model] // 属性本身就是参数
|
|
||||||
} else if (condition.type === IotDeviceMessageTypeEnum.EVENT) {
|
|
||||||
// TODO: 获取事件的输出参数列表
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加条件
|
|
||||||
const addCondition = () => {
|
|
||||||
const newCondition: IotRuleSceneTriggerCondition = {
|
|
||||||
type: IotDeviceMessageTypeEnum.PROPERTY,
|
|
||||||
identifier: IotDeviceMessageIdentifierEnum.PROPERTY_REPORT,
|
|
||||||
parameters: []
|
|
||||||
}
|
|
||||||
|
|
||||||
const newValue = [...(props.modelValue || []), newCondition]
|
|
||||||
emit('update:modelValue', newValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 移除条件
|
|
||||||
const removeCondition = (index: number) => {
|
|
||||||
const newValue = [...props.modelValue]
|
|
||||||
newValue.splice(index, 1)
|
|
||||||
emit('update:modelValue', newValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 消息类型变更
|
|
||||||
const handleMessageTypeChange = (index: number) => {
|
|
||||||
const newValue = [...props.modelValue]
|
|
||||||
// 更新标识符
|
|
||||||
if (newValue[index].type === IotDeviceMessageTypeEnum.PROPERTY) {
|
|
||||||
newValue[index].identifier = IotDeviceMessageIdentifierEnum.PROPERTY_REPORT
|
|
||||||
} else if (newValue[index].type === IotDeviceMessageTypeEnum.EVENT) {
|
|
||||||
newValue[index].identifier = IotDeviceMessageIdentifierEnum.EVENT_REPORT
|
|
||||||
}
|
|
||||||
// 清空参数
|
|
||||||
newValue[index].parameters = []
|
|
||||||
emit('update:modelValue', newValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 标识符变更
|
|
||||||
const handleIdentifierChange = (index: number) => {
|
|
||||||
const newValue = [...props.modelValue]
|
|
||||||
// 清空参数
|
|
||||||
newValue[index].parameters = []
|
|
||||||
emit('update:modelValue', newValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加参数
|
|
||||||
const addParameter = (conditionIndex: number) => {
|
|
||||||
const newValue = [...props.modelValue]
|
|
||||||
if (!newValue[conditionIndex].parameters) {
|
|
||||||
newValue[conditionIndex].parameters = []
|
|
||||||
}
|
|
||||||
|
|
||||||
const newParameter: IotRuleSceneTriggerConditionParameter = {
|
|
||||||
identifier: '',
|
|
||||||
condition: {
|
|
||||||
operator: 'eq',
|
|
||||||
value: ''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
newValue[conditionIndex].parameters.push(newParameter)
|
|
||||||
emit('update:modelValue', newValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 移除参数
|
|
||||||
const removeParameter = (conditionIndex: number, paramIndex: number) => {
|
|
||||||
const newValue = [...props.modelValue]
|
|
||||||
newValue[conditionIndex].parameters.splice(paramIndex, 1)
|
|
||||||
emit('update:modelValue', newValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听 productKey 变化
|
|
||||||
watch(
|
|
||||||
() => props.productKey,
|
|
||||||
(newVal) => {
|
|
||||||
if (!newVal) {
|
|
||||||
// 清空条件
|
|
||||||
if (props.modelValue?.length > 0) {
|
|
||||||
emit('update:modelValue', [])
|
|
||||||
}
|
|
||||||
// 清空物模型数据
|
|
||||||
thingModelList.value = []
|
|
||||||
} else {
|
|
||||||
// 加载物模型数据
|
|
||||||
loadThingModelData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// 初始化
|
|
||||||
onMounted(() => {
|
|
||||||
if (props.productKey) {
|
|
||||||
loadThingModelData()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.trigger-conditions {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conditions-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.conditions-tips {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition-item {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.parameters-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
.parameter-item-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.value-tips {
|
|
||||||
margin-top: 5px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thing-model-option {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thing-model-identifier {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
.thing-model-desc {
|
|
||||||
margin-top: 4px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-3 {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mb-2 {
|
|
||||||
margin-bottom: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mt-3 {
|
|
||||||
margin-top: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mt-2 {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mr-5px {
|
|
||||||
margin-right: 5px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
Reference in New Issue
Block a user