perf:【IoT 物联网】场景联动表单校验规则优化
This commit is contained in:
@ -12,9 +12,9 @@
|
|||||||
<!-- 基础信息配置 -->
|
<!-- 基础信息配置 -->
|
||||||
<BasicInfoSection v-model="formData" :rules="formRules" />
|
<BasicInfoSection v-model="formData" :rules="formRules" />
|
||||||
<!-- 触发器配置 -->
|
<!-- 触发器配置 -->
|
||||||
<TriggerSection v-model:triggers="formData.triggers" @validate="handleTriggerValidate" />
|
<TriggerSection v-model:triggers="formData.triggers" />
|
||||||
<!-- 执行器配置 -->
|
<!-- 执行器配置 -->
|
||||||
<ActionSection v-model:actions="formData.actions" @validate="handleActionValidate" />
|
<ActionSection v-model:actions="formData.actions" />
|
||||||
</el-form>
|
</el-form>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<div class="drawer-footer">
|
<div class="drawer-footer">
|
||||||
@ -38,7 +38,11 @@ import TriggerSection from './sections/TriggerSection.vue'
|
|||||||
import ActionSection from './sections/ActionSection.vue'
|
import ActionSection from './sections/ActionSection.vue'
|
||||||
import { IotRuleSceneDO, RuleSceneFormData } from '@/api/iot/rule/scene/scene.types'
|
import { IotRuleSceneDO, RuleSceneFormData } from '@/api/iot/rule/scene/scene.types'
|
||||||
import { RuleSceneApi } from '@/api/iot/rule/scene'
|
import { RuleSceneApi } from '@/api/iot/rule/scene'
|
||||||
import { IotRuleSceneTriggerTypeEnum } from '@/views/iot/utils/constants'
|
import {
|
||||||
|
IotRuleSceneTriggerTypeEnum,
|
||||||
|
IotRuleSceneActionTypeEnum,
|
||||||
|
isDeviceTrigger
|
||||||
|
} from '@/views/iot/utils/constants'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { generateUUID } from '@/utils'
|
import { generateUUID } from '@/utils'
|
||||||
|
|
||||||
@ -174,6 +178,107 @@ const convertVOToForm = (apiData: IotRuleSceneDO): RuleSceneFormData => {
|
|||||||
// 表单数据和状态
|
// 表单数据和状态
|
||||||
const formRef = ref()
|
const formRef = ref()
|
||||||
const formData = ref<RuleSceneFormData>(createDefaultFormData())
|
const formData = ref<RuleSceneFormData>(createDefaultFormData())
|
||||||
|
// 自定义校验器
|
||||||
|
const validateTriggers = (rule: any, value: any, callback: any) => {
|
||||||
|
if (!value || !Array.isArray(value) || value.length === 0) {
|
||||||
|
callback(new Error('至少需要一个触发器'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < value.length; i++) {
|
||||||
|
const trigger = value[i]
|
||||||
|
|
||||||
|
// 校验触发器类型
|
||||||
|
if (!trigger.type) {
|
||||||
|
callback(new Error(`触发器 ${i + 1}: 触发器类型不能为空`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验设备触发器
|
||||||
|
if (isDeviceTrigger(trigger.type)) {
|
||||||
|
if (!trigger.productId) {
|
||||||
|
callback(new Error(`触发器 ${i + 1}: 产品不能为空`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!trigger.deviceId) {
|
||||||
|
callback(new Error(`触发器 ${i + 1}: 设备不能为空`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!trigger.identifier) {
|
||||||
|
callback(new Error(`触发器 ${i + 1}: 物模型标识符不能为空`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!trigger.operator) {
|
||||||
|
callback(new Error(`触发器 ${i + 1}: 操作符不能为空`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (trigger.value === undefined || trigger.value === null || trigger.value === '') {
|
||||||
|
callback(new Error(`触发器 ${i + 1}: 参数值不能为空`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验定时触发器
|
||||||
|
if (trigger.type === IotRuleSceneTriggerTypeEnum.TIMER) {
|
||||||
|
if (!trigger.cronExpression) {
|
||||||
|
callback(new Error(`触发器 ${i + 1}: CRON表达式不能为空`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
|
||||||
|
const validateActions = (rule: any, value: any, callback: any) => {
|
||||||
|
if (!value || !Array.isArray(value) || value.length === 0) {
|
||||||
|
callback(new Error('至少需要一个执行器'))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < value.length; i++) {
|
||||||
|
const action = value[i]
|
||||||
|
|
||||||
|
// 校验执行器类型
|
||||||
|
if (!action.type) {
|
||||||
|
callback(new Error(`执行器 ${i + 1}: 执行器类型不能为空`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验设备控制执行器
|
||||||
|
if (
|
||||||
|
action.type === IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET ||
|
||||||
|
action.type === IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE
|
||||||
|
) {
|
||||||
|
if (!action.productId) {
|
||||||
|
callback(new Error(`执行器 ${i + 1}: 产品不能为空`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!action.deviceId) {
|
||||||
|
callback(new Error(`执行器 ${i + 1}: 设备不能为空`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!action.params || Object.keys(action.params).length === 0) {
|
||||||
|
callback(new Error(`执行器 ${i + 1}: 参数配置不能为空`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验告警执行器
|
||||||
|
if (
|
||||||
|
action.type === IotRuleSceneActionTypeEnum.ALERT_TRIGGER ||
|
||||||
|
action.type === IotRuleSceneActionTypeEnum.ALERT_RECOVER
|
||||||
|
) {
|
||||||
|
if (!action.alertConfigId) {
|
||||||
|
callback(new Error(`执行器 ${i + 1}: 告警配置不能为空`))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
callback()
|
||||||
|
}
|
||||||
|
|
||||||
const formRules = reactive({
|
const formRules = reactive({
|
||||||
name: [
|
name: [
|
||||||
{ required: true, message: '场景名称不能为空', trigger: 'blur' },
|
{ required: true, message: '场景名称不能为空', trigger: 'blur' },
|
||||||
@ -191,36 +296,16 @@ const formRules = reactive({
|
|||||||
description: [
|
description: [
|
||||||
{ type: 'string', max: 200, message: '场景描述不能超过200个字符', trigger: 'blur' }
|
{ type: 'string', max: 200, message: '场景描述不能超过200个字符', trigger: 'blur' }
|
||||||
],
|
],
|
||||||
triggers: [
|
triggers: [{ required: true, validator: validateTriggers, trigger: 'change' }],
|
||||||
{ required: true, message: '触发器数组不能为空', trigger: 'change' },
|
actions: [{ required: true, validator: validateActions, trigger: 'change' }]
|
||||||
{ type: 'array', min: 1, message: '至少需要一个触发器', trigger: 'change' }
|
|
||||||
],
|
|
||||||
actions: [
|
|
||||||
{ required: true, message: '执行器数组不能为空', trigger: 'change' },
|
|
||||||
{ type: 'array', min: 1, message: '至少需要一个执行器', trigger: 'change' }
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const submitLoading = ref(false)
|
const submitLoading = ref(false)
|
||||||
|
|
||||||
// 验证状态
|
|
||||||
const triggerValidation = ref({ valid: true, message: '' })
|
|
||||||
const actionValidation = ref({ valid: true, message: '' })
|
|
||||||
|
|
||||||
// 计算属性
|
// 计算属性
|
||||||
const isEdit = ref(false)
|
const isEdit = ref(false)
|
||||||
const drawerTitle = computed(() => (isEdit.value ? '编辑场景联动规则' : '新增场景联动规则'))
|
const drawerTitle = computed(() => (isEdit.value ? '编辑场景联动规则' : '新增场景联动规则'))
|
||||||
|
|
||||||
// TODO @puhui999:方法的注释风格统一;
|
|
||||||
// 事件处理
|
|
||||||
const handleTriggerValidate = (result: { valid: boolean; message: string }) => {
|
|
||||||
triggerValidation.value = result
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleActionValidate = (result: { valid: boolean; message: string }) => {
|
|
||||||
actionValidation.value = result
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 提交表单 */
|
/** 提交表单 */
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
// 校验表单
|
// 校验表单
|
||||||
@ -228,16 +313,6 @@ const handleSubmit = async () => {
|
|||||||
const valid = await formRef.value.validate()
|
const valid = await formRef.value.validate()
|
||||||
if (!valid) return
|
if (!valid) return
|
||||||
|
|
||||||
// 验证触发器和执行器
|
|
||||||
if (!triggerValidation.value.valid) {
|
|
||||||
ElMessage.error(triggerValidation.value.message)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (!actionValidation.value.valid) {
|
|
||||||
ElMessage.error(actionValidation.value.message)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 提交请求
|
// 提交请求
|
||||||
submitLoading.value = true
|
submitLoading.value = true
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -20,8 +20,12 @@
|
|||||||
>
|
>
|
||||||
<div class="flex items-center justify-between w-full py-4px">
|
<div class="flex items-center justify-between w-full py-4px">
|
||||||
<div class="flex-1">
|
<div class="flex-1">
|
||||||
<div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px">{{ config.name }}</div>
|
<div class="text-14px font-500 text-[var(--el-text-color-primary)] mb-2px">{{
|
||||||
<div class="text-12px text-[var(--el-text-color-secondary)]">{{ config.description }}</div>
|
config.name
|
||||||
|
}}</div>
|
||||||
|
<div class="text-12px text-[var(--el-text-color-secondary)]">{{
|
||||||
|
config.description
|
||||||
|
}}</div>
|
||||||
</div>
|
</div>
|
||||||
<el-tag :type="config.enabled ? 'success' : 'danger'" size="small">
|
<el-tag :type="config.enabled ? 'success' : 'danger'" size="small">
|
||||||
{{ config.enabled ? '启用' : '禁用' }}
|
{{ config.enabled ? '启用' : '禁用' }}
|
||||||
@ -32,10 +36,15 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<!-- 告警配置详情 -->
|
<!-- 告警配置详情 -->
|
||||||
<div v-if="selectedConfig" class="mt-16px p-12px bg-[var(--el-fill-color-light)] rounded-6px border border-[var(--el-border-color-lighter)]">
|
<div
|
||||||
|
v-if="selectedConfig"
|
||||||
|
class="mt-16px p-12px bg-[var(--el-fill-color-light)] rounded-6px border border-[var(--el-border-color-lighter)]"
|
||||||
|
>
|
||||||
<div class="flex items-center gap-8px mb-12px">
|
<div class="flex items-center gap-8px mb-12px">
|
||||||
<Icon icon="ep:bell" class="text-[var(--el-color-warning)] text-16px" />
|
<Icon icon="ep:bell" class="text-[var(--el-color-warning)] text-16px" />
|
||||||
<span class="text-14px font-500 text-[var(--el-text-color-primary)]">{{ selectedConfig.name }}</span>
|
<span class="text-14px font-500 text-[var(--el-text-color-primary)]">{{
|
||||||
|
selectedConfig.name
|
||||||
|
}}</span>
|
||||||
<el-tag :type="selectedConfig.enabled ? 'success' : 'danger'" size="small">
|
<el-tag :type="selectedConfig.enabled ? 'success' : 'danger'" size="small">
|
||||||
{{ selectedConfig.enabled ? '启用' : '禁用' }}
|
{{ selectedConfig.enabled ? '启用' : '禁用' }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
@ -43,28 +52,24 @@
|
|||||||
<div class="space-y-8px">
|
<div class="space-y-8px">
|
||||||
<div class="flex items-start gap-8px">
|
<div class="flex items-start gap-8px">
|
||||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">描述:</span>
|
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">描述:</span>
|
||||||
<span class="text-12px text-[var(--el-text-color-primary)] flex-1">{{ selectedConfig.description }}</span>
|
<span class="text-12px text-[var(--el-text-color-primary)] flex-1">{{
|
||||||
|
selectedConfig.description
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex items-start gap-8px">
|
<div class="flex items-start gap-8px">
|
||||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">通知方式:</span>
|
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">通知方式:</span>
|
||||||
<span class="text-12px text-[var(--el-text-color-primary)] flex-1">{{ getNotifyTypeName(selectedConfig.notifyType) }}</span>
|
<span class="text-12px text-[var(--el-text-color-primary)] flex-1">{{
|
||||||
|
getNotifyTypeName(selectedConfig.notifyType)
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="selectedConfig.receivers" class="flex items-start gap-8px">
|
<div v-if="selectedConfig.receivers" class="flex items-start gap-8px">
|
||||||
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">接收人:</span>
|
<span class="text-12px text-[var(--el-text-color-secondary)] min-w-60px">接收人:</span>
|
||||||
<span class="text-12px text-[var(--el-text-color-primary)] flex-1">{{ selectedConfig.receivers.join(', ') }}</span>
|
<span class="text-12px text-[var(--el-text-color-primary)] flex-1">{{
|
||||||
|
selectedConfig.receivers.join(', ')
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 验证结果 -->
|
|
||||||
<div v-if="validationMessage" class="mt-16px">
|
|
||||||
<el-alert
|
|
||||||
:title="validationMessage"
|
|
||||||
:type="isValid ? 'success' : 'error'"
|
|
||||||
:closable="false"
|
|
||||||
show-icon
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -80,7 +85,6 @@ interface Props {
|
|||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
(e: 'update:modelValue', value?: number): void
|
(e: 'update:modelValue', value?: number): void
|
||||||
(e: 'validate', result: { valid: boolean; message: string }): void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
@ -91,8 +95,6 @@ const localValue = useVModel(props, 'modelValue', emit)
|
|||||||
// 状态
|
// 状态
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const alertConfigs = ref<any[]>([])
|
const alertConfigs = ref<any[]>([])
|
||||||
const validationMessage = ref('')
|
|
||||||
const isValid = ref(true)
|
|
||||||
|
|
||||||
// 计算属性
|
// 计算属性
|
||||||
const selectedConfig = computed(() => {
|
const selectedConfig = computed(() => {
|
||||||
@ -110,40 +112,6 @@ const getNotifyTypeName = (type: number) => {
|
|||||||
return typeMap[type] || '未知'
|
return typeMap[type] || '未知'
|
||||||
}
|
}
|
||||||
|
|
||||||
// 事件处理
|
|
||||||
const handleChange = () => {
|
|
||||||
updateValidationResult()
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateValidationResult = () => {
|
|
||||||
if (!localValue.value) {
|
|
||||||
isValid.value = false
|
|
||||||
validationMessage.value = '请选择告警配置'
|
|
||||||
emit('validate', { valid: false, message: validationMessage.value })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const config = selectedConfig.value
|
|
||||||
if (!config) {
|
|
||||||
isValid.value = false
|
|
||||||
validationMessage.value = '告警配置不存在'
|
|
||||||
emit('validate', { valid: false, message: validationMessage.value })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!config.enabled) {
|
|
||||||
isValid.value = false
|
|
||||||
validationMessage.value = '选择的告警配置已禁用'
|
|
||||||
emit('validate', { valid: false, message: validationMessage.value })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证通过
|
|
||||||
isValid.value = true
|
|
||||||
validationMessage.value = '告警配置验证通过'
|
|
||||||
emit('validate', { valid: true, message: validationMessage.value })
|
|
||||||
}
|
|
||||||
|
|
||||||
// API 调用
|
// API 调用
|
||||||
const getAlertConfigs = async () => {
|
const getAlertConfigs = async () => {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
@ -184,20 +152,9 @@ const getAlertConfigs = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 监听值变化
|
|
||||||
watch(
|
|
||||||
() => localValue.value,
|
|
||||||
() => {
|
|
||||||
updateValidationResult()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getAlertConfigs()
|
getAlertConfigs()
|
||||||
if (localValue.value) {
|
|
||||||
updateValidationResult()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -39,16 +39,6 @@
|
|||||||
</el-alert>
|
</el-alert>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 验证结果 -->
|
|
||||||
<div v-if="validationMessage" class="mt-16px">
|
|
||||||
<el-alert
|
|
||||||
:title="validationMessage"
|
|
||||||
:type="isValid ? 'success' : 'error'"
|
|
||||||
:closable="false"
|
|
||||||
show-icon
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -66,21 +56,17 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
(e: 'update:modelValue', value: ActionFormData): void
|
(e: 'update:modelValue', value: ActionFormData): void
|
||||||
(e: 'validate', result: { valid: boolean; message: string }): void
|
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const action = useVModel(props, 'modelValue', emit)
|
const action = useVModel(props, 'modelValue', emit)
|
||||||
|
|
||||||
// 状态
|
// 状态
|
||||||
const paramsJson = ref('')
|
const paramsJson = ref('')
|
||||||
const validationMessage = ref('')
|
|
||||||
const isValid = ref(true)
|
|
||||||
|
|
||||||
// 事件处理
|
// 事件处理
|
||||||
const handleDeviceChange = ({ productId, deviceId }: { productId?: number; deviceId?: number }) => {
|
const handleDeviceChange = ({ productId, deviceId }: { productId?: number; deviceId?: number }) => {
|
||||||
action.value.productId = productId
|
action.value.productId = productId
|
||||||
action.value.deviceId = deviceId
|
action.value.deviceId = deviceId
|
||||||
updateValidationResult()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleParamsChange = () => {
|
const handleParamsChange = () => {
|
||||||
@ -90,42 +76,16 @@ const handleParamsChange = () => {
|
|||||||
} else {
|
} else {
|
||||||
action.value.params = {}
|
action.value.params = {}
|
||||||
}
|
}
|
||||||
updateValidationResult()
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
isValid.value = false
|
console.error('JSON格式错误:', error)
|
||||||
validationMessage.value = 'JSON格式错误'
|
|
||||||
emit('validate', { valid: false, message: validationMessage.value })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateValidationResult = () => {
|
|
||||||
// 基础验证
|
|
||||||
if (!action.value.productId || !action.value.deviceId) {
|
|
||||||
isValid.value = false
|
|
||||||
validationMessage.value = '请选择产品和设备'
|
|
||||||
emit('validate', { valid: false, message: validationMessage.value })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!action.value.params || Object.keys(action.value.params).length === 0) {
|
|
||||||
isValid.value = false
|
|
||||||
validationMessage.value = '请配置控制参数'
|
|
||||||
emit('validate', { valid: false, message: validationMessage.value })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证通过
|
|
||||||
isValid.value = true
|
|
||||||
validationMessage.value = '设备控制配置验证通过'
|
|
||||||
emit('validate', { valid: true, message: validationMessage.value })
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化
|
// 初始化
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (action.value.params) {
|
if (action.value.params) {
|
||||||
paramsJson.value = JSON.stringify(action.value.params, null, 2)
|
paramsJson.value = JSON.stringify(action.value.params, null, 2)
|
||||||
}
|
}
|
||||||
updateValidationResult()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听参数变化
|
// 监听参数变化
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
<MainConditionConfig
|
<MainConditionConfig
|
||||||
v-model="trigger"
|
v-model="trigger"
|
||||||
:trigger-type="trigger.type"
|
:trigger-type="trigger.type"
|
||||||
@validate="handleMainConditionValidate"
|
|
||||||
@trigger-type-change="handleTriggerTypeChange"
|
@trigger-type-change="handleTriggerTypeChange"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -17,7 +16,6 @@
|
|||||||
<ConditionGroupContainerConfig
|
<ConditionGroupContainerConfig
|
||||||
v-model="trigger.conditionGroups"
|
v-model="trigger.conditionGroups"
|
||||||
:trigger-type="trigger.type"
|
:trigger-type="trigger.type"
|
||||||
@validate="handleConditionGroupValidate"
|
|
||||||
@remove="removeConditionGroup"
|
@remove="removeConditionGroup"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -48,14 +46,6 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const trigger = useVModel(props, 'modelValue', emit)
|
const trigger = useVModel(props, 'modelValue', emit)
|
||||||
|
|
||||||
// 验证状态
|
|
||||||
const mainConditionValidation = ref<{ valid: boolean; message: string }>({
|
|
||||||
valid: true,
|
|
||||||
message: ''
|
|
||||||
})
|
|
||||||
const validationMessage = ref('')
|
|
||||||
const isValid = ref(true)
|
|
||||||
|
|
||||||
// 初始化主条件
|
// 初始化主条件
|
||||||
const initMainCondition = () => {
|
const initMainCondition = () => {
|
||||||
// TODO @puhui999: 等到编辑回显时联调
|
// TODO @puhui999: 等到编辑回显时联调
|
||||||
@ -80,76 +70,12 @@ watch(
|
|||||||
{ immediate: true }
|
{ immediate: true }
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleMainConditionValidate = (result: { valid: boolean; message: string }) => {
|
|
||||||
mainConditionValidation.value = result
|
|
||||||
updateValidationResult()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleTriggerTypeChange = (type: number) => {
|
const handleTriggerTypeChange = (type: number) => {
|
||||||
trigger.value.type = type
|
trigger.value.type = type
|
||||||
emit('trigger-type-change', type)
|
emit('trigger-type-change', type)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 事件处理
|
|
||||||
const handleConditionGroupValidate = () => {
|
|
||||||
updateValidationResult()
|
|
||||||
}
|
|
||||||
|
|
||||||
const removeConditionGroup = () => {
|
const removeConditionGroup = () => {
|
||||||
trigger.value.conditionGroups = undefined
|
trigger.value.conditionGroups = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateValidationResult = () => {
|
|
||||||
// 主条件验证
|
|
||||||
if (!mainConditionValidation.value.valid) {
|
|
||||||
isValid.value = false
|
|
||||||
validationMessage.value = mainConditionValidation.value.message
|
|
||||||
emit('validate', { valid: false, message: validationMessage.value })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设备状态变更不需要条件验证
|
|
||||||
if (trigger.value.type === TriggerTypeEnum.DEVICE_STATE_UPDATE) {
|
|
||||||
isValid.value = true
|
|
||||||
validationMessage.value = '设备触发配置验证通过'
|
|
||||||
emit('validate', { valid: true, message: validationMessage.value })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 主条件验证
|
|
||||||
if (!trigger.value.value) {
|
|
||||||
isValid.value = false
|
|
||||||
validationMessage.value = '请配置主条件'
|
|
||||||
emit('validate', { valid: false, message: validationMessage.value })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 主条件详细验证
|
|
||||||
if (!mainConditionValidation.value.valid) {
|
|
||||||
isValid.value = false
|
|
||||||
validationMessage.value = `主条件配置错误: ${mainConditionValidation.value.message}`
|
|
||||||
emit('validate', { valid: false, message: validationMessage.value })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
isValid.value = true
|
|
||||||
validationMessage.value = '设备触发配置验证通过'
|
|
||||||
emit('validate', { valid: isValid.value, message: validationMessage.value })
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听触发器类型变化
|
|
||||||
watch(
|
|
||||||
() => trigger.value.type,
|
|
||||||
() => {
|
|
||||||
updateValidationResult()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// 监听产品设备变化
|
|
||||||
watch(
|
|
||||||
() => [trigger.value.productId, trigger.value.deviceId],
|
|
||||||
() => {
|
|
||||||
updateValidationResult()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -76,7 +76,6 @@
|
|||||||
v-if="isDeviceAction(action.type)"
|
v-if="isDeviceAction(action.type)"
|
||||||
:model-value="action"
|
:model-value="action"
|
||||||
@update:model-value="(value) => updateAction(index, value)"
|
@update:model-value="(value) => updateAction(index, value)"
|
||||||
@validate="(result) => handleActionValidate(index, result)"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 告警配置 -->
|
<!-- 告警配置 -->
|
||||||
@ -84,7 +83,6 @@
|
|||||||
v-if="isAlertAction(action.type)"
|
v-if="isAlertAction(action.type)"
|
||||||
:model-value="action.alertConfigId"
|
:model-value="action.alertConfigId"
|
||||||
@update:model-value="(value) => updateActionAlertConfig(index, value)"
|
@update:model-value="(value) => updateActionAlertConfig(index, value)"
|
||||||
@validate="(result) => handleActionValidate(index, result)"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -100,16 +98,6 @@
|
|||||||
最多可添加 {{ maxActions }} 个执行器
|
最多可添加 {{ maxActions }} 个执行器
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 验证结果 -->
|
|
||||||
<div v-if="validationMessage" class="validation-result">
|
|
||||||
<el-alert
|
|
||||||
:title="validationMessage"
|
|
||||||
:type="isValid ? 'success' : 'error'"
|
|
||||||
:closable="false"
|
|
||||||
show-icon
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
@ -131,7 +119,6 @@ interface Props {
|
|||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
(e: 'update:actions', value: ActionFormData[]): void
|
(e: 'update:actions', value: ActionFormData[]): void
|
||||||
(e: 'validate', result: { valid: boolean; message: string }): void
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<Props>()
|
const props = defineProps<Props>()
|
||||||
@ -155,11 +142,6 @@ const createDefaultActionData = (): ActionFormData => {
|
|||||||
// 配置常量
|
// 配置常量
|
||||||
const maxActions = 5
|
const maxActions = 5
|
||||||
|
|
||||||
// 验证状态
|
|
||||||
const actionValidations = ref<{ [key: number]: { valid: boolean; message: string } }>({})
|
|
||||||
const validationMessage = ref('')
|
|
||||||
const isValid = ref(true)
|
|
||||||
|
|
||||||
// 执行器类型映射
|
// 执行器类型映射
|
||||||
const actionTypeNames = {
|
const actionTypeNames = {
|
||||||
[ActionTypeEnum.DEVICE_PROPERTY_SET]: '属性设置',
|
[ActionTypeEnum.DEVICE_PROPERTY_SET]: '属性设置',
|
||||||
@ -206,21 +188,6 @@ const addAction = () => {
|
|||||||
|
|
||||||
const removeAction = (index: number) => {
|
const removeAction = (index: number) => {
|
||||||
actions.value.splice(index, 1)
|
actions.value.splice(index, 1)
|
||||||
delete actionValidations.value[index]
|
|
||||||
|
|
||||||
// 重新索引验证结果
|
|
||||||
const newValidations: { [key: number]: { valid: boolean; message: string } } = {}
|
|
||||||
Object.keys(actionValidations.value).forEach((key) => {
|
|
||||||
const numKey = parseInt(key)
|
|
||||||
if (numKey > index) {
|
|
||||||
newValidations[numKey - 1] = actionValidations.value[numKey]
|
|
||||||
} else if (numKey < index) {
|
|
||||||
newValidations[numKey] = actionValidations.value[numKey]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
actionValidations.value = newValidations
|
|
||||||
|
|
||||||
updateValidationResult()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateActionType = (index: number, type: number) => {
|
const updateActionType = (index: number, type: number) => {
|
||||||
@ -249,37 +216,4 @@ const onActionTypeChange = (action: ActionFormData, type: number) => {
|
|||||||
action.params = undefined
|
action.params = undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleActionValidate = (index: number, result: { valid: boolean; message: string }) => {
|
|
||||||
actionValidations.value[index] = result
|
|
||||||
updateValidationResult()
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateValidationResult = () => {
|
|
||||||
const validations = Object.values(actionValidations.value)
|
|
||||||
const allValid = validations.every((v) => v.valid)
|
|
||||||
const hasValidations = validations.length > 0
|
|
||||||
|
|
||||||
if (!hasValidations) {
|
|
||||||
isValid.value = true
|
|
||||||
validationMessage.value = ''
|
|
||||||
} else if (allValid) {
|
|
||||||
isValid.value = true
|
|
||||||
validationMessage.value = '所有执行器配置验证通过'
|
|
||||||
} else {
|
|
||||||
isValid.value = false
|
|
||||||
const errorMessages = validations.filter((v) => !v.valid).map((v) => v.message)
|
|
||||||
validationMessage.value = `执行器配置错误: ${errorMessages.join('; ')}`
|
|
||||||
}
|
|
||||||
|
|
||||||
emit('validate', { valid: isValid.value, message: validationMessage.value })
|
|
||||||
}
|
|
||||||
|
|
||||||
// 监听执行器数量变化
|
|
||||||
watch(
|
|
||||||
() => actions.value.length,
|
|
||||||
() => {
|
|
||||||
updateValidationResult()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user