From a1d7e81859f554f3a53680cc35f0f49bf1f77098 Mon Sep 17 00:00:00 2001
From: wwf <1971391498@qq.com>
Date: 星期四, 14 五月 2026 14:37:02 +0800
Subject: [PATCH] 导入项目

---
 src/views/iot/rule/scene/form/RuleSceneForm.vue |  330 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 330 insertions(+), 0 deletions(-)

diff --git a/src/views/iot/rule/scene/form/RuleSceneForm.vue b/src/views/iot/rule/scene/form/RuleSceneForm.vue
new file mode 100644
index 0000000..22ba268
--- /dev/null
+++ b/src/views/iot/rule/scene/form/RuleSceneForm.vue
@@ -0,0 +1,330 @@
+<template>
+  <el-drawer
+    v-model="drawerVisible"
+    :title="drawerTitle"
+    size="80%"
+    direction="rtl"
+    :close-on-click-modal="false"
+    :close-on-press-escape="false"
+    @close="handleClose"
+  >
+    <el-form ref="formRef" :model="formData" :rules="formRules" label-width="110px">
+      <!-- 鍩虹淇℃伅閰嶇疆 -->
+      <BasicInfoSection v-model="formData" :rules="formRules" />
+      <!-- 瑙﹀彂鍣ㄩ厤缃� -->
+      <TriggerSection v-model:triggers="formData.triggers" />
+      <!-- 鎵ц鍣ㄩ厤缃� -->
+      <ActionSection v-model:actions="formData.actions" />
+    </el-form>
+    <template #footer>
+      <div class="drawer-footer">
+        <el-button :disabled="submitLoading" type="primary" @click="handleSubmit">
+          <Icon icon="ep:check" />
+          纭� 瀹�
+        </el-button>
+        <el-button @click="handleClose">
+          <Icon icon="ep:close" />
+          鍙� 娑�
+        </el-button>
+      </div>
+    </template>
+  </el-drawer>
+</template>
+
+<script setup lang="ts">
+import { useVModel } from '@vueuse/core'
+import BasicInfoSection from './sections/BasicInfoSection.vue'
+import TriggerSection from './sections/TriggerSection.vue'
+import ActionSection from './sections/ActionSection.vue'
+import { IotSceneRule } from '@/api/iot/rule/scene'
+import { RuleSceneApi } from '@/api/iot/rule/scene'
+import {
+  IotRuleSceneTriggerTypeEnum,
+  IotRuleSceneActionTypeEnum,
+  isDeviceTrigger
+} from '@/views/iot/utils/constants'
+import { ElMessage } from 'element-plus'
+import { CommonStatusEnum } from '@/utils/constants'
+
+/** IoT 鍦烘櫙鑱斿姩瑙勫垯琛ㄥ崟 - 涓昏〃鍗曠粍浠� */
+defineOptions({ name: 'RuleSceneForm' })
+
+/** 缁勪欢灞炴�у畾涔� */
+const props = defineProps<{
+  /** 鎶藉眽鏄剧ず鐘舵�� */
+  modelValue: boolean
+  /** 缂栬緫鐨勫満鏅仈鍔ㄨ鍒欐暟鎹� */
+  ruleScene?: IotSceneRule
+}>()
+
+/** 缁勪欢浜嬩欢瀹氫箟 */
+const emit = defineEmits<{
+  (e: 'update:modelValue', value: boolean): void
+  (e: 'success'): void
+}>()
+
+const drawerVisible = useVModel(props, 'modelValue', emit) // 鎶藉眽鏄剧ず鐘舵��
+
+/**
+ * 鍒涘缓榛樿鐨勮〃鍗曟暟鎹�
+ * @returns 榛樿琛ㄥ崟鏁版嵁瀵硅薄
+ */
+const createDefaultFormData = (): IotSceneRule => {
+  return {
+    name: '',
+    description: '',
+    status: CommonStatusEnum.ENABLE, // 榛樿鍚敤鐘舵��
+    triggers: [
+      {
+        type: IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST,
+        productId: undefined,
+        deviceId: undefined,
+        identifier: undefined,
+        operator: undefined,
+        value: undefined,
+        cronExpression: undefined,
+        conditionGroups: [] // 绌虹殑鏉′欢缁勬暟缁�
+      }
+    ],
+    actions: []
+  }
+}
+
+const formRef = ref() // 琛ㄥ崟寮曠敤
+const formData = ref<IotSceneRule>(createDefaultFormData()) // 琛ㄥ崟鏁版嵁
+
+/**
+ * 瑙﹀彂鍣ㄦ牎楠屽櫒
+ * @param _rule 鏍¢獙瑙勫垯锛堟湭浣跨敤锛�
+ * @param value 鏍¢獙鍊�
+ * @param callback 鍥炶皟鍑芥暟
+ */
+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()
+}
+
+/**
+ * 鎵ц鍣ㄦ牎楠屽櫒
+ * @param _rule 鏍¢獙瑙勫垯锛堟湭浣跨敤锛�
+ * @param value 鏍¢獙鍊�
+ * @param 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.type === IotRuleSceneActionTypeEnum.DEVICE_SERVICE_INVOKE) {
+        if (!action.identifier) {
+          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({
+  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, validator: validateTriggers, trigger: 'change' }],
+  actions: [{ required: true, validator: validateActions, trigger: 'change' }]
+}) // 琛ㄥ崟鏍¢獙瑙勫垯
+
+const submitLoading = ref(false) // 鎻愪氦鍔犺浇鐘舵��
+const isEdit = ref(false) // 鏄惁涓虹紪杈戞ā寮�
+const drawerTitle = computed(() => (isEdit.value ? '缂栬緫鍦烘櫙鑱斿姩瑙勫垯' : '鏂板鍦烘櫙鑱斿姩瑙勫垯')) // 鎶藉眽鏍囬
+
+/** 鎻愪氦琛ㄥ崟 */
+const handleSubmit = async () => {
+  // 鏍¢獙琛ㄥ崟
+  if (!formRef.value) return
+  const valid = await formRef.value.validate()
+  if (!valid) return
+
+  // 鎻愪氦璇锋眰
+  submitLoading.value = true
+  try {
+    if (isEdit.value) {
+      // 鏇存柊鍦烘櫙鑱斿姩瑙勫垯
+      await RuleSceneApi.updateRuleScene(formData.value)
+      ElMessage.success('鏇存柊鎴愬姛')
+    } else {
+      // 鍒涘缓鍦烘櫙鑱斿姩瑙勫垯
+      await RuleSceneApi.createRuleScene(formData.value)
+      ElMessage.success('鍒涘缓鎴愬姛')
+    }
+
+    // 鍏抽棴鎶藉眽骞惰Е鍙戞垚鍔熶簨浠�
+    drawerVisible.value = false
+    emit('success')
+  } catch (error) {
+    console.error('淇濆瓨澶辫触:', error)
+    ElMessage.error(isEdit.value ? '鏇存柊澶辫触' : '鍒涘缓澶辫触')
+  } finally {
+    submitLoading.value = false
+  }
+}
+
+/** 澶勭悊鎶藉眽鍏抽棴浜嬩欢 */
+const handleClose = () => {
+  drawerVisible.value = false
+}
+
+/** 鍒濆鍖栬〃鍗曟暟鎹� */
+const initFormData = () => {
+  if (props.ruleScene) {
+    // 缂栬緫妯″紡锛氭暟鎹粨鏋勫凡瀵归綈锛岀洿鎺ヤ娇鐢ㄥ悗绔暟鎹�
+    isEdit.value = true
+    formData.value = {
+      ...props.ruleScene,
+      // 纭繚瑙﹀彂鍣ㄦ暟缁勪笉涓虹┖
+      triggers: props.ruleScene.triggers?.length
+        ? props.ruleScene.triggers
+        : [
+            {
+              type: IotRuleSceneTriggerTypeEnum.DEVICE_PROPERTY_POST,
+              productId: undefined,
+              deviceId: undefined,
+              identifier: undefined,
+              operator: undefined,
+              value: undefined,
+              cronExpression: undefined,
+              conditionGroups: []
+            }
+          ],
+      // 纭繚鎵ц鍣ㄦ暟缁勪笉涓虹┖
+      actions: props.ruleScene.actions || []
+    }
+  } else {
+    // 鏂板妯″紡锛氫娇鐢ㄩ粯璁ゆ暟鎹�
+    isEdit.value = false
+    formData.value = createDefaultFormData()
+  }
+}
+
+/** 鐩戝惉鎶藉眽鏄剧ず */
+watch(drawerVisible, async (visible) => {
+  if (visible) {
+    initFormData()
+    // 閲嶇疆琛ㄥ崟楠岃瘉鐘舵��
+    await nextTick()
+    formRef.value?.clearValidate()
+  }
+})
+
+/** 鐩戝惉缂栬緫鏁版嵁鍙樺寲 */
+watch(
+  () => props.ruleScene,
+  () => {
+    if (drawerVisible.value) {
+      initFormData()
+    }
+  },
+  { deep: true }
+)
+</script>

--
Gitblit v1.8.0