diff --git a/src/api/iot/rule/scene/scene.types.ts b/src/api/iot/rule/scene/scene.types.ts
index b1e899305..a9ba63b9c 100644
--- a/src/api/iot/rule/scene/scene.types.ts
+++ b/src/api/iot/rule/scene/scene.types.ts
@@ -256,10 +256,6 @@ export {
IotAlertConfigReceiveTypeEnum,
DeviceStateEnum,
CommonStatusEnum,
- TriggerType,
- ActionType,
- MessageType,
- OperatorType,
ValidationRule,
FormValidationRules
}
diff --git a/src/views/iot/rule/scene/form/RuleSceneForm.vue b/src/views/iot/rule/scene/form/RuleSceneForm.vue
index 3b00fdb7a..6c4a96859 100644
--- a/src/views/iot/rule/scene/form/RuleSceneForm.vue
+++ b/src/views/iot/rule/scene/form/RuleSceneForm.vue
@@ -1,5 +1,5 @@
-
+
-
-
-
-
+
+
+
-
-
+
+
-
-
-
-
+
+
+
- 确 定
- 取 消
+
@@ -41,38 +40,36 @@ import BasicInfoSection from './sections/BasicInfoSection.vue'
import TriggerSection from './sections/TriggerSection.vue'
import ActionSection from './sections/ActionSection.vue'
import {
- RuleSceneFormData,
+ CommonStatusEnum,
IotRuleScene,
IotRuleSceneActionTypeEnum,
IotRuleSceneTriggerTypeEnum,
- CommonStatusEnum
+ RuleSceneFormData
} from '@/api/iot/rule/scene/scene.types'
-import { getBaseValidationRules } from '../utils/validation'
import { ElMessage } from 'element-plus'
import { generateUUID } from '@/utils'
/** IoT 场景联动规则表单 - 主表单组件 */
defineOptions({ name: 'RuleSceneForm' })
-// TODO @puhui999:是不是融合到 props
-interface Props {
+/** 组件属性定义 */
+const props = defineProps<{
+ /** 抽屉显示状态 */
modelValue: boolean
+ /** 编辑的规则数据(新增时为空) */
ruleScene?: IotRuleScene
-}
+}>()
-// TODO @puhui999:Emits 是不是融合到 emit
-interface Emits {
- (e: 'update:modelValue', value: boolean): void
- (e: 'success'): void
-}
-
-const props = defineProps()
-const emit = defineEmits()
+/** 组件事件定义 */
+const emit = defineEmits<{
+ /** 更新抽屉显示状态 */
+ 'update:modelValue': [value: boolean]
+ /** 操作成功事件 */
+ success: []
+}>()
const drawerVisible = useVModel(props, 'modelValue', emit) // 是否可见
-// TODO @puhui999:使用 /** 注释风格哈 */
-
/** 创建默认的表单数据 */
const createDefaultFormData = (): RuleSceneFormData => {
return {
@@ -94,11 +91,50 @@ const createDefaultFormData = (): RuleSceneFormData => {
}
}
-// TODO @puhui999:使用 convertFormToVO;下面也是类似哈;
/**
* 将表单数据转换为 API 请求格式
*/
-const transformFormToApi = (formData: RuleSceneFormData): IotRuleScene => {
+const convertFormToVO = (formData: RuleSceneFormData): IotRuleScene => {
+ // 构建触发器条件
+ const buildTriggerConditions = () => {
+ const conditions: any[] = []
+
+ // 处理主条件
+ if (formData.trigger.mainCondition) {
+ const mainCondition = formData.trigger.mainCondition
+ conditions.push({
+ type: mainCondition.type === 2 ? 'property' : 'event',
+ identifier: mainCondition.identifier || '',
+ parameters: [
+ {
+ operator: mainCondition.operator,
+ value: mainCondition.param
+ }
+ ]
+ })
+ }
+
+ // 处理条件组
+ if (formData.trigger.conditionGroup?.subGroups) {
+ formData.trigger.conditionGroup.subGroups.forEach((subGroup) => {
+ subGroup.conditions.forEach((condition) => {
+ conditions.push({
+ type: condition.type === 2 ? 'property' : 'event',
+ identifier: condition.identifier || '',
+ parameters: [
+ {
+ operator: condition.operator,
+ value: condition.param
+ }
+ ]
+ })
+ })
+ })
+ }
+
+ return conditions
+ }
+
return {
id: formData.id,
name: formData.name,
@@ -114,7 +150,7 @@ const transformFormToApi = (formData: RuleSceneFormData): IotRuleScene => {
? [`device_${formData.trigger.deviceId}`]
: undefined,
cronExpression: formData.trigger.cronExpression,
- conditions: [] // TODO: 实现新的条件转换逻辑
+ conditions: buildTriggerConditions()
}
],
actions:
@@ -127,8 +163,12 @@ const transformFormToApi = (formData: RuleSceneFormData): IotRuleScene => {
? {
productKey: action.productId ? `product_${action.productId}` : '',
deviceNames: action.deviceId ? [`device_${action.deviceId}`] : [],
- type: 'property',
- identifier: 'set',
+ type:
+ action.type === IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET
+ ? 'property'
+ : 'service',
+ identifier:
+ action.type === IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET ? 'set' : 'invoke',
params: action.params || {}
}
: undefined
@@ -139,15 +179,55 @@ const transformFormToApi = (formData: RuleSceneFormData): IotRuleScene => {
/**
* 将 API 响应数据转换为表单格式
*/
-const transformApiToForm = (apiData: IotRuleScene): RuleSceneFormData => {
+const convertVOToForm = (apiData: IotRuleScene): RuleSceneFormData => {
const firstTrigger = apiData.triggers?.[0]
+
+ // 解析触发器条件
+ const parseConditions = (trigger: any) => {
+ if (!trigger?.conditions?.length) {
+ return {
+ mainCondition: undefined,
+ conditionGroup: undefined
+ }
+ }
+
+ // 简化处理:将第一个条件作为主条件
+ const firstCondition = trigger.conditions[0]
+ const mainCondition = {
+ type: firstCondition.type === 'property' ? 2 : 3,
+ productId: undefined, // 需要从 productKey 解析
+ deviceId: undefined, // 需要从 deviceNames 解析
+ identifier: firstCondition.identifier,
+ operator: firstCondition.parameters?.[0]?.operator || '=',
+ param: firstCondition.parameters?.[0]?.value || ''
+ }
+
+ return {
+ mainCondition,
+ conditionGroup: undefined // 暂时简化处理
+ }
+ }
+
+ const conditionData = firstTrigger
+ ? parseConditions(firstTrigger)
+ : {
+ mainCondition: undefined,
+ conditionGroup: undefined
+ }
+
return {
...apiData,
- status: Number(apiData.status), // 确保状态为数字类型
+ status: Number(apiData.status),
trigger: firstTrigger
? {
- ...firstTrigger,
- type: Number(firstTrigger.type)
+ type: Number(firstTrigger.type),
+ productId: undefined, // 需要从 productKey 解析
+ deviceId: undefined, // 需要从 deviceNames 解析
+ identifier: undefined,
+ operator: undefined,
+ value: undefined,
+ cronExpression: firstTrigger.cronExpression,
+ ...conditionData
}
: {
type: IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST,
@@ -164,6 +244,9 @@ const transformApiToForm = (apiData: IotRuleScene): RuleSceneFormData => {
apiData.actions?.map((action) => ({
...action,
type: Number(action.type),
+ productId: undefined, // 需要从 deviceControl.productKey 解析
+ deviceId: undefined, // 需要从 deviceControl.deviceNames 解析
+ params: action.deviceControl?.params || {},
// 为每个执行器添加唯一标识符,解决组件索引重用问题
key: generateUUID()
})) || []
@@ -173,7 +256,33 @@ const transformApiToForm = (apiData: IotRuleScene): RuleSceneFormData => {
// 表单数据和状态
const formRef = ref()
const formData = ref(createDefaultFormData())
-const formRules = getBaseValidationRules()
+const formRules = reactive({
+ name: [
+ { required: true, message: '场景名称不能为空', trigger: 'blur' },
+ { type: 'string', min: 1, max: 50, message: '场景名称长度应在1-50个字符之间', trigger: 'blur' }
+ ],
+ status: [
+ { required: true, message: '场景状态不能为空', trigger: 'change' },
+ {
+ type: 'enum',
+ enum: [CommonStatusEnum.ENABLE, CommonStatusEnum.DISABLE],
+ message: '状态值必须为启用或禁用',
+ trigger: 'change'
+ }
+ ],
+ description: [
+ { type: 'string', max: 200, message: '场景描述不能超过200个字符', trigger: 'blur' }
+ ],
+ triggers: [
+ { required: true, message: '触发器数组不能为空', 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)
// 验证状态
@@ -212,11 +321,18 @@ const handleSubmit = async () => {
submitLoading.value = true
try {
// 转换数据格式
- const apiData = transformFormToApi(formData.value)
+ const apiData = convertFormToVO(formData.value)
- // 这里应该调用API保存数据
- // TODO @puhui999:貌似还没接入
- console.log('提交数据:', apiData)
+ // 调用API保存数据
+ if (isEdit.value) {
+ // 更新场景联动规则
+ // await RuleSceneApi.updateRuleScene(apiData)
+ console.log('更新数据:', apiData)
+ } else {
+ // 创建场景联动规则
+ // await RuleSceneApi.createRuleScene(apiData)
+ console.log('创建数据:', apiData)
+ }
// 模拟API调用
await new Promise((resolve) => setTimeout(resolve, 1000))
@@ -224,6 +340,9 @@ const handleSubmit = async () => {
ElMessage.success(isEdit.value ? '更新成功' : '创建成功')
drawerVisible.value = false
emit('success')
+ } catch (error) {
+ console.error('保存失败:', error)
+ ElMessage.error(isEdit.value ? '更新失败' : '创建失败')
} finally {
submitLoading.value = false
}
@@ -233,10 +352,10 @@ const handleClose = () => {
drawerVisible.value = false
}
-// 初始化表单数据
+/** 初始化表单数据 */
const initFormData = () => {
if (props.ruleScene) {
- formData.value = transformApiToForm(props.ruleScene)
+ formData.value = convertVOToForm(props.ruleScene)
} else {
formData.value = createDefaultFormData()
}
@@ -262,64 +381,3 @@ watch(
}
)
-
-
-
diff --git a/src/views/iot/rule/scene/utils/validation.ts b/src/views/iot/rule/scene/utils/validation.ts
deleted file mode 100644
index d5430aa87..000000000
--- a/src/views/iot/rule/scene/utils/validation.ts
+++ /dev/null
@@ -1,188 +0,0 @@
-// TODO @puhui999:貌似很多地方,都用不到啦?这个文件
-/**
- * IoT 场景联动表单验证工具函数
- */
-import { FormValidationRules, TriggerConfig, ActionConfig } from '@/api/iot/rule/scene/scene.types'
-import {
- IotRuleSceneTriggerTypeEnum,
- IotRuleSceneActionTypeEnum,
- CommonStatusEnum
-} from '@/api/iot/rule/scene/scene.types'
-
-/** 基础表单验证规则 */
-export const getBaseValidationRules = (): FormValidationRules => ({
- name: [
- { required: true, message: '场景名称不能为空', trigger: 'blur' },
- { type: 'string', min: 1, max: 50, message: '场景名称长度应在1-50个字符之间', trigger: 'blur' }
- ],
- status: [
- { required: true, message: '场景状态不能为空', trigger: 'change' },
- {
- type: 'enum',
- enum: [CommonStatusEnum.ENABLE, CommonStatusEnum.DISABLE],
- message: '状态值必须为启用或禁用',
- trigger: 'change'
- }
- ],
- description: [
- { type: 'string', max: 200, message: '场景描述不能超过200个字符', trigger: 'blur' }
- ],
- triggers: [
- { required: true, message: '触发器数组不能为空', trigger: 'change' },
- { type: 'array', min: 1, message: '至少需要一个触发器', trigger: 'change' }
- ],
- actions: [
- { required: true, message: '执行器数组不能为空', trigger: 'change' },
- { type: 'array', min: 1, message: '至少需要一个执行器', trigger: 'change' }
- ]
-})
-
-/** 验证CRON表达式格式 */
-// TODO @puhui999:这个可以拿到 cron 组件里哇?
-export function validateCronExpression(cron: string): boolean {
- if (!cron || cron.trim().length === 0) return false
- // 基础的 CRON 表达式正则验证(支持 6 位和 7 位格式)
- const cronRegex =
- /^(\*|([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])|\*\/([0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9])) (\*|([0-9]|1[0-9]|2[0-3])|\*\/([0-9]|1[0-9]|2[0-3])) (\*|([1-9]|1[0-9]|2[0-9]|3[0-1])|\*\/([1-9]|1[0-9]|2[0-9]|3[0-1])) (\*|([1-9]|1[0-2])|\*\/([1-9]|1[0-2])) (\*|([0-6])|\*\/([0-6]))( (\*|([1-9][0-9]{3})|\*\/([1-9][0-9]{3})))?$/
- return cronRegex.test(cron.trim())
-}
-
-/** 验证设备名称数组 */
-export function validateDeviceNames(deviceNames: string[]): boolean {
- return (
- Array.isArray(deviceNames) &&
- deviceNames.length > 0 &&
- deviceNames.every((name) => name && name.trim().length > 0)
- )
-}
-
-/** 验证比较值格式 */
-export function validateCompareValue(operator: string, value: string): boolean {
- if (!value || value.trim().length === 0) return false
- const trimmedValue = value.trim()
- // TODO @puhui999:这里要用下枚举哇?
- switch (operator) {
- case 'between':
- case 'not between':
- const betweenValues = trimmedValue.split(',')
- return (
- betweenValues.length === 2 &&
- betweenValues.every((v) => v.trim().length > 0) &&
- !isNaN(Number(betweenValues[0].trim())) &&
- !isNaN(Number(betweenValues[1].trim()))
- )
- case 'in':
- case 'not in':
- const inValues = trimmedValue.split(',')
- return inValues.length > 0 && inValues.every((v) => v.trim().length > 0)
- case '>':
- case '>=':
- case '<':
- case '<=':
- return !isNaN(Number(trimmedValue))
- case '=':
- case '!=':
- case 'like':
- case 'not null':
- // TODO @puhui999:这里要不加个 default 抛出异常?
- default:
- return true
- }
-}
-
-// TODO @puhui999:貌似没用到?
-/** 验证触发器配置 */
-export function validateTriggerConfig(trigger: TriggerConfig): {
- valid: boolean
- message?: string
-} {
- if (!trigger.type) {
- return { valid: false, message: '触发类型不能为空' }
- }
- // 定时触发验证
- if (trigger.type === IotRuleSceneTriggerTypeEnum.TIMER) {
- if (!trigger.cronExpression) {
- return { valid: false, message: 'CRON表达式不能为空' }
- }
- if (!validateCronExpression(trigger.cronExpression)) {
- return { valid: false, message: 'CRON表达式格式不正确' }
- }
- return { valid: true }
- }
- // 设备触发验证
- if (!trigger.productKey) {
- return { valid: false, message: '产品标识不能为空' }
- }
- if (!trigger.deviceNames || !validateDeviceNames(trigger.deviceNames)) {
- return { valid: false, message: '设备名称不能为空' }
- }
- // 设备状态变更无需额外条件验证
- if (trigger.type === IotRuleSceneTriggerTypeEnum.DEVICE_STATE_UPDATE) {
- return { valid: true }
- }
- // 其他设备触发类型需要验证条件
- if (!trigger.conditions || trigger.conditions.length === 0) {
- return { valid: false, message: '触发条件不能为空' }
- }
- // 验证每个条件的参数
- for (const condition of trigger.conditions) {
- if (!condition.parameters || condition.parameters.length === 0) {
- return { valid: false, message: '触发条件参数不能为空' }
- }
- for (const param of condition.parameters) {
- if (!param.operator) {
- return { valid: false, message: '操作符不能为空' }
- }
- if (!validateCompareValue(param.operator, param.value)) {
- return { valid: false, message: `操作符 "${param.operator}" 对应的比较值格式不正确` }
- }
- }
- }
- return { valid: true }
-}
-
-// TODO @puhui999:貌似没用到?
-/** 验证执行器配置 */
-export function validateActionConfig(action: ActionConfig): { valid: boolean; message?: string } {
- if (!action.type) {
- return { valid: false, message: '执行类型不能为空' }
- }
- // 告警触发/恢复验证
- if (
- action.type === IotRuleSceneActionTypeEnum.ALERT_TRIGGER ||
- action.type === IotRuleSceneActionTypeEnum.ALERT_RECOVER
- ) {
- if (!action.alertConfigId) {
- return { valid: false, message: '告警配置ID不能为空' }
- }
- return { valid: true }
- }
- // 设备控制验证
- if (
- action.type === IotRuleSceneActionTypeEnum.DEVICE_PROPERTY_SET ||
- action.type === IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE
- ) {
- if (!action.deviceControl) {
- return { valid: false, message: '设备控制配置不能为空' }
- }
- const { deviceControl } = action
- if (!deviceControl.productKey) {
- return { valid: false, message: '产品标识不能为空' }
- }
- if (!deviceControl.deviceNames || !validateDeviceNames(deviceControl.deviceNames)) {
- return { valid: false, message: '设备名称不能为空' }
- }
- if (!deviceControl.type) {
- return { valid: false, message: '消息类型不能为空' }
- }
- if (!deviceControl.identifier) {
- return { valid: false, message: '消息标识符不能为空' }
- }
- if (!deviceControl.params || Object.keys(deviceControl.params).length === 0) {
- return { valid: false, message: '参数不能为空' }
- }
- return { valid: true }
- }
-
- return { valid: false, message: '未知的执行类型' }
-}