perf: 【IoT 物联网】场景联动移除自定义校验规则简化校验逻辑
parent
09be0a10b1
commit
9684857174
|
|
@ -106,7 +106,6 @@ const props = defineProps<{
|
|||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: TriggerCondition): void
|
||||
(e: 'validate', result: { valid: boolean; message: string }): void
|
||||
}>()
|
||||
|
||||
const condition = useVModel(props, 'modelValue', emit)
|
||||
|
|
@ -155,10 +154,6 @@ const timeOperatorOptions = [
|
|||
}
|
||||
]
|
||||
|
||||
// 状态
|
||||
const validationMessage = ref('')
|
||||
const isValid = ref(true)
|
||||
|
||||
// 计算属性
|
||||
const needsTimeInput = computed(() => {
|
||||
const timeOnlyOperators = [
|
||||
|
|
@ -181,62 +176,16 @@ const needsSecondTimeInput = computed(() => {
|
|||
// 事件处理
|
||||
const updateConditionField = (field: keyof TriggerCondition, value: any) => {
|
||||
condition.value[field] = value
|
||||
updateValidationResult()
|
||||
}
|
||||
|
||||
const updateValidationResult = () => {
|
||||
if (!condition.value.operator) {
|
||||
isValid.value = false
|
||||
validationMessage.value = '请选择时间条件'
|
||||
emit('validate', { valid: false, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
|
||||
// 今日条件不需要时间值
|
||||
if (condition.value.operator === IotRuleSceneTriggerTimeOperatorEnum.TODAY.value) {
|
||||
isValid.value = true
|
||||
validationMessage.value = '当前时间条件配置验证通过'
|
||||
emit('validate', { valid: true, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
|
||||
if (needsTimeInput.value && !condition.value.timeValue) {
|
||||
isValid.value = false
|
||||
validationMessage.value = '请设置时间值'
|
||||
emit('validate', { valid: false, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
|
||||
if (needsSecondTimeInput.value && !condition.value.timeValue2) {
|
||||
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 })
|
||||
}
|
||||
|
||||
// 监听变化
|
||||
watch(
|
||||
() => [condition.value.operator, condition.value.timeValue, condition.value.timeValue2],
|
||||
() => {
|
||||
updateValidationResult()
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
|
||||
// 监听操作符变化,清理不相关的时间值
|
||||
watch(
|
||||
() => condition.value.operator,
|
||||
(newOperator) => {
|
||||
if (newOperator === IotRuleSceneTriggerTimeOperatorEnum.TODAY.value) {
|
||||
condition.value.timeValue = undefined
|
||||
condition.value.timeValue2 = undefined
|
||||
;(condition.value as any).timeValue = undefined(condition.value as any).timeValue2 = undefined
|
||||
} else if (!needsSecondTimeInput.value) {
|
||||
condition.value.timeValue2 = undefined
|
||||
;(condition.value as any).timeValue2 = undefined
|
||||
}
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -55,7 +55,6 @@
|
|||
type="service"
|
||||
:config="{ service: selectedService }"
|
||||
placeholder="请输入JSON格式的服务参数"
|
||||
@validate="handleParamsValidate"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
|
@ -70,7 +69,6 @@
|
|||
type="property"
|
||||
:config="{ properties: thingModelProperties }"
|
||||
placeholder="请输入JSON格式的控制参数"
|
||||
@validate="handleParamsValidate"
|
||||
/>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
|
@ -86,7 +84,8 @@ import type { Action } from '@/api/iot/rule/scene'
|
|||
import type { ThingModelProperty, ThingModelService } from '@/api/iot/thingmodel'
|
||||
import {
|
||||
IotRuleSceneActionTypeEnum,
|
||||
IoTThingModelAccessModeEnum
|
||||
IoTThingModelAccessModeEnum,
|
||||
IoTDataSpecsDataTypeEnum
|
||||
} from '@/views/iot/utils/constants'
|
||||
import { ThingModelApi } from '@/api/iot/thingmodel'
|
||||
|
||||
|
|
@ -126,12 +125,6 @@ const paramsValue = computed({
|
|||
}
|
||||
})
|
||||
|
||||
// 参数验证处理
|
||||
const handleParamsValidate = (result: { valid: boolean; message: string }) => {
|
||||
// 可以在这里处理验证结果,比如显示错误信息
|
||||
console.log('参数验证结果:', result)
|
||||
}
|
||||
|
||||
const isPropertySetAction = computed(() => {
|
||||
// 是否为属性设置类型
|
||||
return action.value.type === IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET
|
||||
|
|
@ -301,16 +294,16 @@ const loadServiceFromTSL = async (productId: number, serviceIdentifier: string)
|
|||
*/
|
||||
const getDefaultValueForParam = (param: any) => {
|
||||
switch (param.dataType) {
|
||||
case 'int':
|
||||
case IoTDataSpecsDataTypeEnum.INT:
|
||||
return 0
|
||||
case 'float':
|
||||
case 'double':
|
||||
case IoTDataSpecsDataTypeEnum.FLOAT:
|
||||
case IoTDataSpecsDataTypeEnum.DOUBLE:
|
||||
return 0.0
|
||||
case 'bool':
|
||||
case IoTDataSpecsDataTypeEnum.BOOL:
|
||||
return false
|
||||
case 'text':
|
||||
case IoTDataSpecsDataTypeEnum.TEXT:
|
||||
return ''
|
||||
case 'enum':
|
||||
case IoTDataSpecsDataTypeEnum.ENUM:
|
||||
// 如果有枚举值,使用第一个
|
||||
if (param.dataSpecs?.dataSpecsList && param.dataSpecs.dataSpecsList.length > 0) {
|
||||
return param.dataSpecs.dataSpecsList[0].value
|
||||
|
|
|
|||
|
|
@ -29,7 +29,6 @@
|
|||
:model-value="trigger"
|
||||
@update:model-value="updateCondition"
|
||||
:trigger-type="trigger.type"
|
||||
@validate="handleValidate"
|
||||
@trigger-type-change="handleTriggerTypeChange"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -123,7 +122,6 @@
|
|||
@update:model-value="(value) => updateSubGroup(subGroupIndex, value)"
|
||||
:trigger-type="trigger.type"
|
||||
:max-conditions="maxConditionsPerGroup"
|
||||
@validate="(result) => handleSubGroupValidate(subGroupIndex, result)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
@ -182,7 +180,6 @@ const props = defineProps<{
|
|||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: Trigger): void
|
||||
(e: 'validate', value: { valid: boolean; message: string }): void
|
||||
(e: 'trigger-type-change', type: number): void
|
||||
}>()
|
||||
|
||||
|
|
@ -192,18 +189,11 @@ const trigger = useVModel(props, 'modelValue', emit)
|
|||
const maxSubGroups = 3 // 最多 3 个子条件组
|
||||
const maxConditionsPerGroup = 3 // 每组最多 3 个条件
|
||||
|
||||
// 验证状态
|
||||
const subGroupValidations = ref<{ [key: number]: { valid: boolean; message: string } }>({})
|
||||
|
||||
// 事件处理
|
||||
const updateCondition = (condition: Trigger) => {
|
||||
trigger.value = condition
|
||||
}
|
||||
|
||||
const handleValidate = (result: { valid: boolean; message: string }) => {
|
||||
emit('validate', result)
|
||||
}
|
||||
|
||||
const handleTriggerTypeChange = (type: number) => {
|
||||
trigger.value.type = type
|
||||
emit('trigger-type-change', type)
|
||||
|
|
@ -231,21 +221,6 @@ const addSubGroup = () => {
|
|||
const removeSubGroup = (index: number) => {
|
||||
if (trigger.value.conditionGroups) {
|
||||
trigger.value.conditionGroups.splice(index, 1)
|
||||
delete subGroupValidations.value[index]
|
||||
|
||||
// 重新索引验证结果
|
||||
const newValidations: { [key: number]: { valid: boolean; message: string } } = {}
|
||||
Object.keys(subGroupValidations.value).forEach((key) => {
|
||||
const numKey = parseInt(key)
|
||||
if (numKey > index) {
|
||||
newValidations[numKey - 1] = subGroupValidations.value[numKey]
|
||||
} else if (numKey < index) {
|
||||
newValidations[numKey] = subGroupValidations.value[numKey]
|
||||
}
|
||||
})
|
||||
subGroupValidations.value = newValidations
|
||||
|
||||
updateValidationResult()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -258,35 +233,4 @@ const updateSubGroup = (index: number, subGroup: any) => {
|
|||
const removeConditionGroup = () => {
|
||||
trigger.value.conditionGroups = undefined
|
||||
}
|
||||
|
||||
const handleSubGroupValidate = (index: number, result: { valid: boolean; message: string }) => {
|
||||
subGroupValidations.value[index] = result
|
||||
updateValidationResult()
|
||||
}
|
||||
|
||||
const updateValidationResult = () => {
|
||||
if (!trigger.value.conditionGroups || trigger.value.conditionGroups.length === 0) {
|
||||
emit('validate', { valid: true, message: '条件组容器为空,验证通过' })
|
||||
return
|
||||
}
|
||||
|
||||
const validations = Object.values(subGroupValidations.value)
|
||||
const allValid = validations.every((v: any) => v.valid)
|
||||
|
||||
if (allValid) {
|
||||
emit('validate', { valid: true, message: '条件组容器配置验证通过' })
|
||||
} else {
|
||||
const errorMessages = validations.filter((v: any) => !v.valid).map((v: any) => v.message)
|
||||
emit('validate', { valid: false, message: `子条件组配置错误: ${errorMessages.join('; ')}` })
|
||||
}
|
||||
}
|
||||
|
||||
// 监听变化
|
||||
watch(
|
||||
() => trigger.value.conditionGroups,
|
||||
() => {
|
||||
updateValidationResult()
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -100,7 +100,6 @@
|
|||
type="service"
|
||||
:config="serviceConfig"
|
||||
placeholder="请输入JSON格式的服务参数"
|
||||
@validate="handleValueValidate"
|
||||
/>
|
||||
<!-- 事件上报参数配置 -->
|
||||
<JsonParamsInput
|
||||
|
|
@ -109,7 +108,6 @@
|
|||
type="event"
|
||||
:config="eventConfig"
|
||||
placeholder="请输入JSON格式的事件参数"
|
||||
@validate="handleValueValidate"
|
||||
/>
|
||||
<!-- 普通值输入 -->
|
||||
<ValueInput
|
||||
|
|
@ -119,7 +117,6 @@
|
|||
:property-type="propertyType"
|
||||
:operator="condition.operator"
|
||||
:property-config="propertyConfig"
|
||||
@validate="handleValueValidate"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
|
|
@ -202,15 +199,11 @@ const props = defineProps<{
|
|||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: Trigger): void
|
||||
(e: 'validate', result: { valid: boolean; message: string }): void
|
||||
(e: 'trigger-type-change', value: number): void
|
||||
}>()
|
||||
|
||||
// 响应式数据
|
||||
const condition = useVModel(props, 'modelValue', emit)
|
||||
// TODO @puhui999:是不是 validationMessage 非空,就是不通过哈;
|
||||
const isValid = ref(true)
|
||||
const validationMessage = ref('')
|
||||
const propertyType = ref('')
|
||||
const propertyConfig = ref<any>(null)
|
||||
|
||||
|
|
@ -279,7 +272,6 @@ const triggerTypeOptions = getTriggerTypeOptions()
|
|||
// 事件处理
|
||||
const updateConditionField = (field: keyof Trigger, value: any) => {
|
||||
;(condition.value as any)[field] = value
|
||||
updateValidationResult()
|
||||
}
|
||||
|
||||
const handleTriggerTypeChange = (type: number) => {
|
||||
|
|
@ -290,13 +282,11 @@ const handleProductChange = () => {
|
|||
// 产品变化时清空设备和属性
|
||||
condition.value.deviceId = undefined
|
||||
condition.value.identifier = ''
|
||||
updateValidationResult()
|
||||
}
|
||||
|
||||
const handleDeviceChange = () => {
|
||||
// 设备变化时清空属性
|
||||
condition.value.identifier = ''
|
||||
updateValidationResult()
|
||||
}
|
||||
|
||||
const handlePropertyChange = (propertyInfo: any) => {
|
||||
|
|
@ -312,88 +302,9 @@ const handlePropertyChange = (propertyInfo: any) => {
|
|||
condition.value.operator = '='
|
||||
}
|
||||
}
|
||||
updateValidationResult()
|
||||
}
|
||||
|
||||
const handleOperatorChange = () => {
|
||||
updateValidationResult()
|
||||
// 操作符变化处理
|
||||
}
|
||||
|
||||
// 处理参数验证结果
|
||||
const handleValueValidate = (result: { valid: boolean; message: string }) => {
|
||||
isValid.value = result.valid
|
||||
validationMessage.value = result.message
|
||||
emit('validate', result)
|
||||
updateValidationResult()
|
||||
}
|
||||
|
||||
// 验证逻辑
|
||||
// TODO @puhui999:这个校验,是不是用更原生的 validator 哈。项目风格更统一点。
|
||||
const updateValidationResult = () => {
|
||||
if (isDevicePropertyTrigger.value) {
|
||||
// 设备属性触发验证
|
||||
if (!condition.value.productId) {
|
||||
isValid.value = false
|
||||
validationMessage.value = '请选择产品'
|
||||
emit('validate', { valid: false, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
|
||||
if (!condition.value.deviceId) {
|
||||
isValid.value = false
|
||||
validationMessage.value = '请选择设备'
|
||||
emit('validate', { valid: false, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
|
||||
if (!condition.value.identifier) {
|
||||
isValid.value = false
|
||||
validationMessage.value = '请选择监控项'
|
||||
emit('validate', { valid: false, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
|
||||
// 服务调用和事件上报不需要操作符
|
||||
if (
|
||||
props.triggerType !== IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE &&
|
||||
props.triggerType !== IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST &&
|
||||
!condition.value.operator
|
||||
) {
|
||||
isValid.value = false
|
||||
validationMessage.value = '请选择操作符'
|
||||
emit('validate', { valid: false, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
|
||||
if (!condition.value.value) {
|
||||
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 })
|
||||
}
|
||||
|
||||
// 监听变化
|
||||
watch(
|
||||
() => [
|
||||
condition.value.productId,
|
||||
condition.value.deviceId,
|
||||
condition.value.identifier,
|
||||
// 服务调用和事件上报不需要监听操作符
|
||||
props.triggerType !== IotRuleSceneTriggerTypeEnum.DEVICE_SERVICE_INVOKE &&
|
||||
props.triggerType !== IotRuleSceneTriggerTypeEnum.DEVICE_EVENT_POST
|
||||
? condition.value.operator
|
||||
: null,
|
||||
condition.value.value
|
||||
],
|
||||
() => {
|
||||
updateValidationResult()
|
||||
},
|
||||
{ immediate: true }
|
||||
)
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@
|
|||
:model-value="condition"
|
||||
@update:model-value="(value) => updateCondition(conditionIndex, value)"
|
||||
:trigger-type="triggerType"
|
||||
@validate="(result) => handleConditionValidate(conditionIndex, result)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -100,7 +99,6 @@ const props = defineProps<{
|
|||
|
||||
const emit = defineEmits<{
|
||||
(e: 'update:modelValue', value: TriggerCondition[]): void
|
||||
(e: 'validate', result: { valid: boolean; message: string }): void
|
||||
}>()
|
||||
|
||||
const subGroup = useVModel(props, 'modelValue', emit)
|
||||
|
|
@ -108,9 +106,6 @@ const subGroup = useVModel(props, 'modelValue', emit)
|
|||
// 配置常量
|
||||
const maxConditions = computed(() => props.maxConditions || 3)
|
||||
|
||||
// 验证状态
|
||||
const conditionValidations = ref<{ [key: number]: { valid: boolean; message: string } }>({})
|
||||
|
||||
// 事件处理
|
||||
const addCondition = () => {
|
||||
// 确保 subGroup.value 是一个数组
|
||||
|
|
@ -143,21 +138,6 @@ const addCondition = () => {
|
|||
const removeCondition = (index: number) => {
|
||||
if (subGroup.value) {
|
||||
subGroup.value.splice(index, 1)
|
||||
delete conditionValidations.value[index]
|
||||
|
||||
// 重新索引验证结果
|
||||
const newValidations: { [key: number]: { valid: boolean; message: string } } = {}
|
||||
Object.keys(conditionValidations.value).forEach((key) => {
|
||||
const numKey = parseInt(key)
|
||||
if (numKey > index) {
|
||||
newValidations[numKey - 1] = conditionValidations.value[numKey]
|
||||
} else if (numKey < index) {
|
||||
newValidations[numKey] = conditionValidations.value[numKey]
|
||||
}
|
||||
})
|
||||
conditionValidations.value = newValidations
|
||||
|
||||
updateValidationResult()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,35 +146,4 @@ const updateCondition = (index: number, condition: TriggerCondition) => {
|
|||
subGroup.value[index] = condition
|
||||
}
|
||||
}
|
||||
|
||||
const handleConditionValidate = (index: number, result: { valid: boolean; message: string }) => {
|
||||
conditionValidations.value[index] = result
|
||||
updateValidationResult()
|
||||
}
|
||||
|
||||
const updateValidationResult = () => {
|
||||
if (!subGroup.value || subGroup.value.length === 0) {
|
||||
emit('validate', { valid: false, message: '子条件组至少需要一个条件' })
|
||||
return
|
||||
}
|
||||
|
||||
const validations = Object.values(conditionValidations.value)
|
||||
const allValid = validations.every((v: any) => v.valid)
|
||||
|
||||
if (allValid) {
|
||||
emit('validate', { valid: true, message: '子条件组配置验证通过' })
|
||||
} else {
|
||||
const errorMessages = validations.filter((v: any) => !v.valid).map((v: any) => v.message)
|
||||
emit('validate', { valid: false, message: `条件配置错误: ${errorMessages.join('; ')}` })
|
||||
}
|
||||
}
|
||||
|
||||
// 监听变化
|
||||
watch(
|
||||
() => subGroup.value,
|
||||
() => {
|
||||
updateValidationResult()
|
||||
},
|
||||
{ deep: true, immediate: true }
|
||||
)
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -136,6 +136,7 @@
|
|||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { InfoFilled } from '@element-plus/icons-vue'
|
||||
import { IoTDataSpecsDataTypeEnum } from '@/views/iot/utils/constants'
|
||||
|
||||
/** JSON参数输入组件 - 通用版本 */
|
||||
defineOptions({ name: 'JsonParamsInput' })
|
||||
|
|
@ -169,7 +170,6 @@ interface Props {
|
|||
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: string): void
|
||||
(e: 'validate', result: { valid: boolean; message: string }): void
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
|
|
@ -317,7 +317,6 @@ const handleParamsChange = () => {
|
|||
// 额外的参数验证
|
||||
if (typeof parsed !== 'object' || parsed === null) {
|
||||
jsonError.value = '参数必须是一个有效的 JSON 对象'
|
||||
emit('validate', { valid: false, message: jsonError.value })
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -325,7 +324,6 @@ const handleParamsChange = () => {
|
|||
for (const param of paramsList.value) {
|
||||
if (param.required && (!parsed[param.identifier] || parsed[param.identifier] === '')) {
|
||||
jsonError.value = `参数 ${param.name} 为必填项`
|
||||
emit('validate', { valid: false, message: jsonError.value })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
|
@ -334,10 +332,9 @@ const handleParamsChange = () => {
|
|||
}
|
||||
|
||||
// 验证通过
|
||||
emit('validate', { valid: true, message: 'JSON格式正确' })
|
||||
jsonError.value = ''
|
||||
} catch (error) {
|
||||
jsonError.value = `JSON格式错误: ${error instanceof Error ? error.message : '未知错误'}`
|
||||
emit('validate', { valid: false, message: jsonError.value })
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -352,7 +349,6 @@ const clearParams = () => {
|
|||
paramsJson.value = ''
|
||||
localValue.value = ''
|
||||
jsonError.value = ''
|
||||
emit('validate', { valid: true, message: '' })
|
||||
}
|
||||
|
||||
// 工具函数
|
||||
|
|
@ -373,35 +369,35 @@ const getParamTypeName = (dataType: string) => {
|
|||
|
||||
const getParamTypeTag = (dataType: string) => {
|
||||
const tagMap = {
|
||||
int: 'primary',
|
||||
float: 'success',
|
||||
double: 'success',
|
||||
text: 'info',
|
||||
bool: 'warning',
|
||||
enum: 'danger',
|
||||
date: 'primary',
|
||||
struct: 'info',
|
||||
array: 'warning'
|
||||
[IoTDataSpecsDataTypeEnum.INT]: 'primary',
|
||||
[IoTDataSpecsDataTypeEnum.FLOAT]: 'success',
|
||||
[IoTDataSpecsDataTypeEnum.DOUBLE]: 'success',
|
||||
[IoTDataSpecsDataTypeEnum.TEXT]: 'info',
|
||||
[IoTDataSpecsDataTypeEnum.BOOL]: 'warning',
|
||||
[IoTDataSpecsDataTypeEnum.ENUM]: 'danger',
|
||||
[IoTDataSpecsDataTypeEnum.DATE]: 'primary',
|
||||
[IoTDataSpecsDataTypeEnum.STRUCT]: 'info',
|
||||
[IoTDataSpecsDataTypeEnum.ARRAY]: 'warning'
|
||||
}
|
||||
return tagMap[dataType] || 'info'
|
||||
}
|
||||
|
||||
const getExampleValue = (param: any) => {
|
||||
switch (param.dataType) {
|
||||
case 'int':
|
||||
case IoTDataSpecsDataTypeEnum.INT:
|
||||
return '25'
|
||||
case 'float':
|
||||
case 'double':
|
||||
case IoTDataSpecsDataTypeEnum.FLOAT:
|
||||
case IoTDataSpecsDataTypeEnum.DOUBLE:
|
||||
return '25.5'
|
||||
case 'bool':
|
||||
case IoTDataSpecsDataTypeEnum.BOOL:
|
||||
return 'false'
|
||||
case 'text':
|
||||
case IoTDataSpecsDataTypeEnum.TEXT:
|
||||
return '"auto"'
|
||||
case 'enum':
|
||||
case IoTDataSpecsDataTypeEnum.ENUM:
|
||||
return '"option1"'
|
||||
case 'struct':
|
||||
case IoTDataSpecsDataTypeEnum.STRUCT:
|
||||
return '{}'
|
||||
case 'array':
|
||||
case IoTDataSpecsDataTypeEnum.ARRAY:
|
||||
return '[]'
|
||||
default:
|
||||
return '""'
|
||||
|
|
|
|||
|
|
@ -132,19 +132,12 @@
|
|||
</el-tooltip>
|
||||
</template>
|
||||
</el-input>
|
||||
|
||||
<!-- 验证提示 -->
|
||||
<div v-if="validationMessage" class="mt-4px">
|
||||
<el-text :type="isValid ? 'success' : 'danger'" size="small">
|
||||
<Icon :icon="isValid ? 'ep:check' : 'ep:warning-filled'" />
|
||||
{{ validationMessage }}
|
||||
</el-text>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { IoTDataSpecsDataTypeEnum } from '@/views/iot/utils/constants'
|
||||
|
||||
/** 值输入组件 */
|
||||
defineOptions({ name: 'ValueInput' })
|
||||
|
|
@ -158,7 +151,6 @@ interface Props {
|
|||
|
||||
interface Emits {
|
||||
(e: 'update:modelValue', value: string): void
|
||||
(e: 'validate', result: { valid: boolean; message: string }): void
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
|
|
@ -173,8 +165,6 @@ const rangeStart = ref('')
|
|||
const rangeEnd = ref('')
|
||||
const dateValue = ref('')
|
||||
const numberValue = ref<number>()
|
||||
const validationMessage = ref('')
|
||||
const isValid = ref(true)
|
||||
|
||||
// 计算属性
|
||||
const enumOptions = computed(() => {
|
||||
|
|
@ -199,14 +189,18 @@ const listPreview = computed(() => {
|
|||
|
||||
// 工具函数
|
||||
const isNumericType = () => {
|
||||
return ['int', 'float', 'double'].includes(props.propertyType || '')
|
||||
return [
|
||||
IoTDataSpecsDataTypeEnum.INT,
|
||||
IoTDataSpecsDataTypeEnum.FLOAT,
|
||||
IoTDataSpecsDataTypeEnum.DOUBLE
|
||||
].includes(props.propertyType || '')
|
||||
}
|
||||
|
||||
const getInputType = () => {
|
||||
switch (props.propertyType) {
|
||||
case 'int':
|
||||
case 'float':
|
||||
case 'double':
|
||||
case IoTDataSpecsDataTypeEnum.INT:
|
||||
case IoTDataSpecsDataTypeEnum.FLOAT:
|
||||
case IoTDataSpecsDataTypeEnum.DOUBLE:
|
||||
return 'number'
|
||||
default:
|
||||
return 'text'
|
||||
|
|
@ -215,22 +209,22 @@ const getInputType = () => {
|
|||
|
||||
const getPlaceholder = () => {
|
||||
const typeMap = {
|
||||
string: '请输入字符串',
|
||||
int: '请输入整数',
|
||||
float: '请输入浮点数',
|
||||
double: '请输入双精度数',
|
||||
struct: '请输入JSON格式数据',
|
||||
array: '请输入数组格式数据'
|
||||
[IoTDataSpecsDataTypeEnum.TEXT]: '请输入字符串',
|
||||
[IoTDataSpecsDataTypeEnum.INT]: '请输入整数',
|
||||
[IoTDataSpecsDataTypeEnum.FLOAT]: '请输入浮点数',
|
||||
[IoTDataSpecsDataTypeEnum.DOUBLE]: '请输入双精度数',
|
||||
[IoTDataSpecsDataTypeEnum.STRUCT]: '请输入JSON格式数据',
|
||||
[IoTDataSpecsDataTypeEnum.ARRAY]: '请输入数组格式数据'
|
||||
}
|
||||
return typeMap[props.propertyType || ''] || '请输入值'
|
||||
}
|
||||
|
||||
const getPrecision = () => {
|
||||
return props.propertyType === 'int' ? 0 : 2
|
||||
return props.propertyType === IoTDataSpecsDataTypeEnum.INT ? 0 : 2
|
||||
}
|
||||
|
||||
const getStep = () => {
|
||||
return props.propertyType === 'int' ? 1 : 0.1
|
||||
return props.propertyType === IoTDataSpecsDataTypeEnum.INT ? 1 : 0.1
|
||||
}
|
||||
|
||||
const getMin = () => {
|
||||
|
|
@ -243,7 +237,7 @@ const getMax = () => {
|
|||
|
||||
// 事件处理
|
||||
const handleChange = () => {
|
||||
validateValue()
|
||||
// 值变化处理
|
||||
}
|
||||
|
||||
const handleRangeChange = () => {
|
||||
|
|
@ -252,106 +246,16 @@ const handleRangeChange = () => {
|
|||
} else {
|
||||
localValue.value = ''
|
||||
}
|
||||
validateValue()
|
||||
}
|
||||
|
||||
const handleDateChange = (value: string) => {
|
||||
localValue.value = value || ''
|
||||
validateValue()
|
||||
}
|
||||
|
||||
const handleNumberChange = (value: number | undefined) => {
|
||||
localValue.value = value?.toString() || ''
|
||||
validateValue()
|
||||
}
|
||||
|
||||
// 验证函数
|
||||
const validateValue = () => {
|
||||
if (!localValue.value) {
|
||||
isValid.value = false
|
||||
validationMessage.value = '请输入值'
|
||||
emit('validate', { valid: false, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
|
||||
// 数字类型验证
|
||||
if (isNumericType()) {
|
||||
const num = parseFloat(localValue.value)
|
||||
if (isNaN(num)) {
|
||||
isValid.value = false
|
||||
validationMessage.value = '请输入有效的数字'
|
||||
emit('validate', { valid: false, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
|
||||
// 范围验证
|
||||
const min = getMin()
|
||||
const max = getMax()
|
||||
if (min !== undefined && num < min) {
|
||||
isValid.value = false
|
||||
validationMessage.value = `值不能小于 ${min}`
|
||||
emit('validate', { valid: false, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
if (max !== undefined && num > max) {
|
||||
isValid.value = false
|
||||
validationMessage.value = `值不能大于 ${max}`
|
||||
emit('validate', { valid: false, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 范围输入验证
|
||||
if (props.operator === 'between') {
|
||||
const parts = localValue.value.split(',')
|
||||
if (parts.length !== 2) {
|
||||
isValid.value = false
|
||||
validationMessage.value = '范围格式错误'
|
||||
emit('validate', { valid: false, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
|
||||
const start = parseFloat(parts[0])
|
||||
const end = parseFloat(parts[1])
|
||||
if (isNaN(start) || isNaN(end)) {
|
||||
isValid.value = false
|
||||
validationMessage.value = '范围值必须是数字'
|
||||
emit('validate', { valid: false, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
|
||||
if (start >= end) {
|
||||
isValid.value = false
|
||||
validationMessage.value = '起始值必须小于结束值'
|
||||
emit('validate', { valid: false, message: validationMessage.value })
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 列表输入验证
|
||||
if (props.operator === 'in') {
|
||||
if (listPreview.value.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 })
|
||||
}
|
||||
|
||||
// 监听值变化
|
||||
watch(
|
||||
() => localValue.value,
|
||||
() => {
|
||||
validateValue()
|
||||
}
|
||||
)
|
||||
|
||||
// 监听操作符变化
|
||||
watch(
|
||||
() => props.operator,
|
||||
|
|
@ -363,11 +267,4 @@ watch(
|
|||
numberValue.value = undefined
|
||||
}
|
||||
)
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
if (localValue.value) {
|
||||
validateValue()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -35,7 +35,10 @@
|
|||
|
||||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { IotRuleSceneTriggerConditionParameterOperatorEnum } from '@/views/iot/utils/constants'
|
||||
import {
|
||||
IotRuleSceneTriggerConditionParameterOperatorEnum,
|
||||
IoTDataSpecsDataTypeEnum
|
||||
} from '@/views/iot/utils/constants'
|
||||
|
||||
/** 操作符选择器组件 */
|
||||
defineOptions({ name: 'OperatorSelector' })
|
||||
|
|
@ -60,7 +63,14 @@ const allOperators = [
|
|||
symbol: '=',
|
||||
description: '值完全相等时触发',
|
||||
example: 'temperature = 25',
|
||||
supportedTypes: ['int', 'float', 'double', 'string', 'bool', 'enum']
|
||||
supportedTypes: [
|
||||
IoTDataSpecsDataTypeEnum.INT,
|
||||
IoTDataSpecsDataTypeEnum.FLOAT,
|
||||
IoTDataSpecsDataTypeEnum.DOUBLE,
|
||||
IoTDataSpecsDataTypeEnum.TEXT,
|
||||
IoTDataSpecsDataTypeEnum.BOOL,
|
||||
IoTDataSpecsDataTypeEnum.ENUM
|
||||
]
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_EQUALS.value,
|
||||
|
|
@ -68,7 +78,14 @@ const allOperators = [
|
|||
symbol: '≠',
|
||||
description: '值不相等时触发',
|
||||
example: 'power != false',
|
||||
supportedTypes: ['int', 'float', 'double', 'string', 'bool', 'enum']
|
||||
supportedTypes: [
|
||||
IoTDataSpecsDataTypeEnum.INT,
|
||||
IoTDataSpecsDataTypeEnum.FLOAT,
|
||||
IoTDataSpecsDataTypeEnum.DOUBLE,
|
||||
IoTDataSpecsDataTypeEnum.TEXT,
|
||||
IoTDataSpecsDataTypeEnum.BOOL,
|
||||
IoTDataSpecsDataTypeEnum.ENUM
|
||||
]
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN.value,
|
||||
|
|
@ -76,7 +93,12 @@ const allOperators = [
|
|||
symbol: '>',
|
||||
description: '值大于指定值时触发',
|
||||
example: 'temperature > 30',
|
||||
supportedTypes: ['int', 'float', 'double', 'date']
|
||||
supportedTypes: [
|
||||
IoTDataSpecsDataTypeEnum.INT,
|
||||
IoTDataSpecsDataTypeEnum.FLOAT,
|
||||
IoTDataSpecsDataTypeEnum.DOUBLE,
|
||||
IoTDataSpecsDataTypeEnum.DATE
|
||||
]
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerConditionParameterOperatorEnum.GREATER_THAN_OR_EQUALS.value,
|
||||
|
|
@ -84,7 +106,12 @@ const allOperators = [
|
|||
symbol: '≥',
|
||||
description: '值大于或等于指定值时触发',
|
||||
example: 'humidity >= 80',
|
||||
supportedTypes: ['int', 'float', 'double', 'date']
|
||||
supportedTypes: [
|
||||
IoTDataSpecsDataTypeEnum.INT,
|
||||
IoTDataSpecsDataTypeEnum.FLOAT,
|
||||
IoTDataSpecsDataTypeEnum.DOUBLE,
|
||||
IoTDataSpecsDataTypeEnum.DATE
|
||||
]
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN.value,
|
||||
|
|
@ -92,7 +119,12 @@ const allOperators = [
|
|||
symbol: '<',
|
||||
description: '值小于指定值时触发',
|
||||
example: 'temperature < 10',
|
||||
supportedTypes: ['int', 'float', 'double', 'date']
|
||||
supportedTypes: [
|
||||
IoTDataSpecsDataTypeEnum.INT,
|
||||
IoTDataSpecsDataTypeEnum.FLOAT,
|
||||
IoTDataSpecsDataTypeEnum.DOUBLE,
|
||||
IoTDataSpecsDataTypeEnum.DATE
|
||||
]
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerConditionParameterOperatorEnum.LESS_THAN_OR_EQUALS.value,
|
||||
|
|
@ -100,7 +132,12 @@ const allOperators = [
|
|||
symbol: '≤',
|
||||
description: '值小于或等于指定值时触发',
|
||||
example: 'battery <= 20',
|
||||
supportedTypes: ['int', 'float', 'double', 'date']
|
||||
supportedTypes: [
|
||||
IoTDataSpecsDataTypeEnum.INT,
|
||||
IoTDataSpecsDataTypeEnum.FLOAT,
|
||||
IoTDataSpecsDataTypeEnum.DOUBLE,
|
||||
IoTDataSpecsDataTypeEnum.DATE
|
||||
]
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerConditionParameterOperatorEnum.IN.value,
|
||||
|
|
@ -108,7 +145,12 @@ const allOperators = [
|
|||
symbol: '∈',
|
||||
description: '值在指定列表中时触发',
|
||||
example: 'status in [1,2,3]',
|
||||
supportedTypes: ['int', 'float', 'string', 'enum']
|
||||
supportedTypes: [
|
||||
IoTDataSpecsDataTypeEnum.INT,
|
||||
IoTDataSpecsDataTypeEnum.FLOAT,
|
||||
IoTDataSpecsDataTypeEnum.TEXT,
|
||||
IoTDataSpecsDataTypeEnum.ENUM
|
||||
]
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_IN.value,
|
||||
|
|
@ -116,7 +158,12 @@ const allOperators = [
|
|||
symbol: '∉',
|
||||
description: '值不在指定列表中时触发',
|
||||
example: 'status not in [1,2,3]',
|
||||
supportedTypes: ['int', 'float', 'string', 'enum']
|
||||
supportedTypes: [
|
||||
IoTDataSpecsDataTypeEnum.INT,
|
||||
IoTDataSpecsDataTypeEnum.FLOAT,
|
||||
IoTDataSpecsDataTypeEnum.TEXT,
|
||||
IoTDataSpecsDataTypeEnum.ENUM
|
||||
]
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerConditionParameterOperatorEnum.BETWEEN.value,
|
||||
|
|
@ -124,7 +171,12 @@ const allOperators = [
|
|||
symbol: '⊆',
|
||||
description: '值在指定范围内时触发',
|
||||
example: 'temperature between 20,30',
|
||||
supportedTypes: ['int', 'float', 'double', 'date']
|
||||
supportedTypes: [
|
||||
IoTDataSpecsDataTypeEnum.INT,
|
||||
IoTDataSpecsDataTypeEnum.FLOAT,
|
||||
IoTDataSpecsDataTypeEnum.DOUBLE,
|
||||
IoTDataSpecsDataTypeEnum.DATE
|
||||
]
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_BETWEEN.value,
|
||||
|
|
@ -132,7 +184,12 @@ const allOperators = [
|
|||
symbol: '⊄',
|
||||
description: '值不在指定范围内时触发',
|
||||
example: 'temperature not between 20,30',
|
||||
supportedTypes: ['int', 'float', 'double', 'date']
|
||||
supportedTypes: [
|
||||
IoTDataSpecsDataTypeEnum.INT,
|
||||
IoTDataSpecsDataTypeEnum.FLOAT,
|
||||
IoTDataSpecsDataTypeEnum.DOUBLE,
|
||||
IoTDataSpecsDataTypeEnum.DATE
|
||||
]
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerConditionParameterOperatorEnum.LIKE.value,
|
||||
|
|
@ -140,7 +197,7 @@ const allOperators = [
|
|||
symbol: '≈',
|
||||
description: '字符串匹配指定模式时触发',
|
||||
example: 'message like "%error%"',
|
||||
supportedTypes: ['string']
|
||||
supportedTypes: [IoTDataSpecsDataTypeEnum.TEXT]
|
||||
},
|
||||
{
|
||||
value: IotRuleSceneTriggerConditionParameterOperatorEnum.NOT_NULL.value,
|
||||
|
|
@ -148,7 +205,15 @@ const allOperators = [
|
|||
symbol: '≠∅',
|
||||
description: '值非空时触发',
|
||||
example: 'data not null',
|
||||
supportedTypes: ['int', 'float', 'double', 'string', 'bool', 'enum', 'date']
|
||||
supportedTypes: [
|
||||
IoTDataSpecsDataTypeEnum.INT,
|
||||
IoTDataSpecsDataTypeEnum.FLOAT,
|
||||
IoTDataSpecsDataTypeEnum.DOUBLE,
|
||||
IoTDataSpecsDataTypeEnum.TEXT,
|
||||
IoTDataSpecsDataTypeEnum.BOOL,
|
||||
IoTDataSpecsDataTypeEnum.ENUM,
|
||||
IoTDataSpecsDataTypeEnum.DATE
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -159,7 +159,11 @@
|
|||
<script setup lang="ts">
|
||||
import { useVModel } from '@vueuse/core'
|
||||
import { InfoFilled } from '@element-plus/icons-vue'
|
||||
import { IotRuleSceneTriggerTypeEnum, IoTThingModelTypeEnum } from '@/views/iot/utils/constants'
|
||||
import {
|
||||
IotRuleSceneTriggerTypeEnum,
|
||||
IoTThingModelTypeEnum,
|
||||
IoTDataSpecsDataTypeEnum
|
||||
} from '@/views/iot/utils/constants'
|
||||
import type {
|
||||
IotThingModelTSLResp,
|
||||
ThingModelEvent,
|
||||
|
|
@ -246,30 +250,30 @@ const selectedProperty = computed(() => {
|
|||
// 工具函数
|
||||
const getPropertyTypeName = (dataType: string) => {
|
||||
const typeMap = {
|
||||
int: '整数',
|
||||
float: '浮点数',
|
||||
double: '双精度',
|
||||
text: '字符串',
|
||||
bool: '布尔值',
|
||||
enum: '枚举',
|
||||
date: '日期',
|
||||
struct: '结构体',
|
||||
array: '数组'
|
||||
[IoTDataSpecsDataTypeEnum.INT]: '整数',
|
||||
[IoTDataSpecsDataTypeEnum.FLOAT]: '浮点数',
|
||||
[IoTDataSpecsDataTypeEnum.DOUBLE]: '双精度',
|
||||
[IoTDataSpecsDataTypeEnum.TEXT]: '字符串',
|
||||
[IoTDataSpecsDataTypeEnum.BOOL]: '布尔值',
|
||||
[IoTDataSpecsDataTypeEnum.ENUM]: '枚举',
|
||||
[IoTDataSpecsDataTypeEnum.DATE]: '日期',
|
||||
[IoTDataSpecsDataTypeEnum.STRUCT]: '结构体',
|
||||
[IoTDataSpecsDataTypeEnum.ARRAY]: '数组'
|
||||
}
|
||||
return typeMap[dataType] || dataType
|
||||
}
|
||||
|
||||
const getPropertyTypeTag = (dataType: string) => {
|
||||
const tagMap = {
|
||||
int: 'primary',
|
||||
float: 'success',
|
||||
double: 'success',
|
||||
text: 'info',
|
||||
bool: 'warning',
|
||||
enum: 'danger',
|
||||
date: 'primary',
|
||||
struct: 'info',
|
||||
array: 'warning'
|
||||
[IoTDataSpecsDataTypeEnum.INT]: 'primary',
|
||||
[IoTDataSpecsDataTypeEnum.FLOAT]: 'success',
|
||||
[IoTDataSpecsDataTypeEnum.DOUBLE]: 'success',
|
||||
[IoTDataSpecsDataTypeEnum.TEXT]: 'info',
|
||||
[IoTDataSpecsDataTypeEnum.BOOL]: 'warning',
|
||||
[IoTDataSpecsDataTypeEnum.ENUM]: 'danger',
|
||||
[IoTDataSpecsDataTypeEnum.DATE]: 'primary',
|
||||
[IoTDataSpecsDataTypeEnum.STRUCT]: 'info',
|
||||
[IoTDataSpecsDataTypeEnum.ARRAY]: 'warning'
|
||||
}
|
||||
return tagMap[dataType] || 'info'
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue