admin-vue3/src/views/iot/rule/scene/form/configs/MainConditionInnerConfig.vue

398 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<el-form
ref="innerFormRef"
:model="condition"
:rules="conditionRules"
label-width="110px"
class="space-y-16px"
>
<!-- 触发事件类型选择 -->
<el-form-item label="触发事件类型" required>
<el-select
:model-value="triggerType"
@update:model-value="handleTriggerTypeChange"
placeholder="请选择触发事件类型"
class="w-full"
>
<el-option
v-for="option in triggerTypeOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
</el-form-item>
<!-- 设备属性条件配置 -->
<div v-if="isDevicePropertyTrigger" class="space-y-16px">
<!-- 产品设备选择 -->
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="产品" prop="productId" required>
<ProductSelector
:model-value="condition.productId"
@update:model-value="(value) => updateConditionField('productId', value)"
@change="handleProductChange"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备" prop="deviceId" required>
<DeviceSelector
:model-value="condition.deviceId"
@update:model-value="(value) => updateConditionField('deviceId', value)"
:product-id="condition.productId"
@change="handleDeviceChange"
/>
</el-form-item>
</el-col>
</el-row>
<!-- 属性配置 -->
<el-row :gutter="16">
<!-- 属性/事件/服务选择 -->
<el-col :span="6">
<el-form-item label="监控项" prop="identifier" required>
<PropertySelector
:model-value="condition.identifier"
@update:model-value="(value) => updateConditionField('identifier', value)"
:trigger-type="triggerType"
:product-id="condition.productId"
:device-id="condition.deviceId"
@change="handlePropertyChange"
/>
</el-form-item>
</el-col>
<!-- 操作符选择 - 服务调用和事件上报不需要操作符 -->
<el-col v-if="needsOperatorSelector" :span="6">
<el-form-item label="操作符" prop="operator" required>
<OperatorSelector
:model-value="condition.operator"
@update:model-value="(value) => updateConditionField('operator', value)"
:property-type="propertyType"
/>
</el-form-item>
</el-col>
<!-- 值输入 -->
<el-col :span="isWideValueColumn ? 18 : 12">
<el-form-item :label="valueInputLabel" prop="value" :required="needsValueRequired">
<!-- 服务调用参数配置 -->
<JsonParamsInput
v-if="triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE"
v-model="condition.value"
type="service"
:config="serviceConfig"
placeholder="请输入 JSON 格式的服务参数"
/>
<!-- 事件上报比较值:标量填裸值;结构体/数组填 JSON 整体相等;留空则事件发生即匹配 -->
<template v-else-if="triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST">
<el-input
:model-value="condition.value"
@update:model-value="(value) => updateConditionField('value', value)"
placeholder="留空则事件发生即匹配"
/>
<div class="text-12px text-[var(--el-text-color-secondary)] mt-4px leading-relaxed">
标量事件值填裸值(如
<code class="px-2px">normal</code>);结构体/数组事件值填合法
JSON
<code class="px-2px">{"level":"high"}</code>
</div>
</template>
<!-- 普通值输入 -->
<ValueInput
v-else
:model-value="condition.value"
@update:model-value="(value) => updateConditionField('value', value)"
:property-type="propertyType"
:operator="condition.operator"
:property-config="propertyConfig"
/>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 设备状态条件配置 -->
<div v-else-if="isDeviceStatusTrigger" class="space-y-16px">
<!-- 设备状态触发器使用简化的配置 -->
<el-row :gutter="16">
<el-col :span="12">
<el-form-item label="产品" prop="productId" required>
<ProductSelector
:model-value="condition.productId"
@update:model-value="(value) => updateConditionField('productId', value)"
@change="handleProductChange"
/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="设备" prop="deviceId" required>
<DeviceSelector
:model-value="condition.deviceId"
@update:model-value="(value) => updateConditionField('deviceId', value)"
:product-id="condition.productId"
@change="handleDeviceChange"
/>
</el-form-item>
</el-col>
</el-row>
<el-row :gutter="16">
<el-col :span="6">
<el-form-item label="操作符" prop="operator" required>
<el-select
:model-value="condition.operator"
@update:model-value="(value) => updateConditionField('operator', value)"
placeholder="请选择操作符"
class="w-full"
>
<el-option
:label="IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.name"
:value="IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.value"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="参数" prop="value" required>
<el-select
:model-value="condition.value"
@update:model-value="(value) => updateConditionField('value', value)"
placeholder="请选择设备状态"
class="w-full"
>
<el-option
v-for="option in deviceStatusChangeOptions"
:key="option.value"
:label="option.label"
:value="option.value"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</div>
<!-- 其他触发类型的提示 -->
<div v-else class="text-center py-20px">
<p class="text-14px text-[var(--el-text-color-secondary)] mb-4px">
当前触发事件类型:{{ getTriggerTypeLabel(triggerType) }}
</p>
<p class="text-12px text-[var(--el-text-color-placeholder)]">
此触发类型暂不需要配置额外条件
</p>
</div>
</el-form>
</template>
<script setup lang="ts">
import type { FormInstance } from 'element-plus'
import ProductSelector from '../selectors/ProductSelector.vue'
import DeviceSelector from '../selectors/DeviceSelector.vue'
import PropertySelector from '../selectors/PropertySelector.vue'
import OperatorSelector from '../selectors/OperatorSelector.vue'
import ValueInput from '../inputs/ValueInput.vue'
import JsonParamsInput from '../inputs/JsonParamsInput.vue'
import type { Trigger } from '@/api/iot/rule/scene'
import {
IotRuleSceneTriggerTypeEnum,
triggerTypeOptions,
getTriggerTypeLabel,
IotRuleSceneTriggerConditionParameterOperatorEnum,
IoTDeviceStatusEnum
} from '@/views/iot/utils/constants'
import { buildMainConditionRules } from '@/views/iot/utils/sceneRule'
import { useVModel } from '@vueuse/core'
/** 主条件内部配置组件 */
defineOptions({ name: 'MainConditionInnerConfig' })
const props = defineProps<{
modelValue: Trigger
triggerType: number
}>()
const emit = defineEmits<{
(e: 'update:modelValue', value: Trigger): void
(e: 'trigger-type-change', value: number): void
}>()
/** 获取设备状态变更选项(用于触发器配置) */
const deviceStatusChangeOptions = [
{
label: IoTDeviceStatusEnum.ONLINE.label,
value: IoTDeviceStatusEnum.ONLINE.value
},
{
label: IoTDeviceStatusEnum.OFFLINE.label,
value: IoTDeviceStatusEnum.OFFLINE.value
}
]
const condition = useVModel(props, 'modelValue', emit)
const innerFormRef = ref<FormInstance>()
const propertyType = ref('') // 属性类型
const propertyConfig = ref<any>(null) // 属性配置
const conditionRules = computed(() => buildMainConditionRules(props.triggerType))
// 计算属性:是否为设备属性触发器
const isDevicePropertyTrigger = computed(() => {
return (
props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST ||
props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST ||
props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE
)
})
// 计算属性:是否为设备状态触发器
const isDeviceStatusTrigger = computed(() => {
return props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_STATE_UPDATE
})
// 计算属性:是否需要操作符选择(服务调用和事件上报不需要操作符)
const needsOperatorSelector = computed(() => {
const noOperatorTriggerTypes = [
IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE,
IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST
] as number[]
return !noOperatorTriggerTypes.includes(props.triggerType)
})
// 比较值是否必填(属性上报必填,事件/服务可选)
const needsValueRequired = computed(() => {
return props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST
})
// 计算属性:是否需要宽列布局(服务调用和事件上报不需要操作符列,所以值输入列更宽)
const isWideValueColumn = computed(() => {
const wideColumnTriggerTypes = [
IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE,
IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST
] as number[]
return wideColumnTriggerTypes.includes(props.triggerType)
})
// 计算属性:值输入字段的标签文本
const valueInputLabel = computed(() => {
return props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE
? '服务参数'
: '比较值'
})
// 计算属性:服务配置 - 用于 JsonParamsInput
const serviceConfig = computed(() => {
if (
propertyConfig.value &&
props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE
) {
return {
service: {
name: propertyConfig.value.name || '服务',
inputParams: propertyConfig.value.inputParams || []
}
}
}
return undefined
})
/** 设备状态触发器默认操作符为「等于」 */
const ensureDeviceStatusDefaults = () => {
if (props.triggerType !== IotRuleSceneTriggerTypeEnum.DEVICE_STATE_UPDATE) {
return
}
if (!condition.value.operator) {
condition.value.operator = IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.value
}
}
/**
* 更新条件字段
* @param field 字段名
* @param value 字段值
*/
const updateConditionField = (field: keyof Trigger, value: any) => {
condition.value[field] = value
nextTick(() => {
innerFormRef.value?.validateField(field as string).catch(() => {})
})
}
/**
* 处理触发器类型变化事件
* @param type 触发器类型
*/
const handleTriggerTypeChange = (type: number) => {
emit('trigger-type-change', type)
}
/** 处理产品变化事件 */
const handleProductChange = () => {
condition.value.deviceId = undefined
condition.value.identifier = ''
nextTick(() => {
innerFormRef.value?.clearValidate(['deviceId', 'identifier'])
})
}
/** 处理设备变化事件 */
const handleDeviceChange = () => {
condition.value.identifier = ''
nextTick(() => {
innerFormRef.value?.clearValidate('identifier')
})
}
/**
* 处理属性变化事件
* @param propertyInfo 属性信息对象
*/
const handlePropertyChange = (propertyInfo: any) => {
if (propertyInfo) {
propertyType.value = propertyInfo.type
propertyConfig.value = propertyInfo.config
if (
props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST ||
props.triggerType === IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE
) {
condition.value.operator = IotRuleSceneTriggerConditionParameterOperatorEnum.EQUALS.value
}
}
}
/** 校验主条件表单 */
const validate = async (): Promise<boolean> => {
if (!innerFormRef.value || Object.keys(conditionRules.value).length === 0) {
return true
}
try {
await innerFormRef.value.validate()
return true
} catch {
return false
}
}
const clearValidate = () => {
innerFormRef.value?.clearValidate()
}
defineExpose({ validate, clearValidate })
watch(
() => props.triggerType,
() => {
ensureDeviceStatusDefaults()
nextTick(() => clearValidate())
},
{ immediate: true }
)
onMounted(() => {
ensureDeviceStatusDefaults()
})
</script>