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/data/rule/components/SourceConfigForm.vue |  262 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 262 insertions(+), 0 deletions(-)

diff --git a/src/views/iot/rule/data/rule/components/SourceConfigForm.vue b/src/views/iot/rule/data/rule/components/SourceConfigForm.vue
new file mode 100644
index 0000000..4e10138
--- /dev/null
+++ b/src/views/iot/rule/data/rule/components/SourceConfigForm.vue
@@ -0,0 +1,262 @@
+<template>
+  <el-form
+    ref="formRef"
+    :model="formData"
+    :rules="formRules"
+    label-width="0px"
+    :inline-message="true"
+  >
+    <el-table :data="formData" class="-mt-10px">
+      <el-table-column label="浜у搧" min-width="150">
+        <template #default="{ row, $index }">
+          <el-form-item :prop="`${$index}.productId`" :rules="formRules.productId" class="mb-0px!">
+            <el-select
+              v-model="row.productId"
+              placeholder="璇烽�夋嫨浜у搧"
+              @change="handleProductChange(row, $index)"
+              clearable
+              filterable
+              style="width: 100%"
+            >
+              <el-option
+                v-for="product in productList"
+                :key="product.id"
+                :label="product.name"
+                :value="product.id"
+              />
+            </el-select>
+          </el-form-item>
+        </template>
+      </el-table-column>
+      <el-table-column label="璁惧" min-width="150">
+        <template #default="{ row, $index }">
+          <el-form-item :prop="`${$index}.deviceId`" :rules="formRules.deviceId" class="mb-0px!">
+            <el-select
+              v-model="row.deviceId"
+              placeholder="璇烽�夋嫨璁惧"
+              clearable
+              filterable
+              style="width: 100%"
+            >
+              <el-option label="鍏ㄩ儴璁惧" :value="0" />
+              <el-option
+                v-for="device in getFilteredDevices(row.productId)"
+                :key="device.id"
+                :label="device.deviceName"
+                :value="device.id"
+              />
+            </el-select>
+          </el-form-item>
+        </template>
+      </el-table-column>
+      <el-table-column label="娑堟伅" min-width="150">
+        <template #default="{ row, $index }">
+          <el-form-item :prop="`${$index}.method`" :rules="formRules.method" class="mb-0px!">
+            <el-select
+              v-model="row.method"
+              placeholder="璇烽�夋嫨娑堟伅"
+              @change="handleMethodChange(row, $index)"
+              clearable
+              filterable
+              style="width: 100%"
+            >
+              <el-option
+                v-for="method in upstreamMethods"
+                :key="method.method"
+                :label="method.name"
+                :value="method.method"
+              />
+            </el-select>
+          </el-form-item>
+        </template>
+      </el-table-column>
+      <el-table-column label="鏍囪瘑绗�" min-width="200">
+        <template #default="{ row, $index }">
+          <el-form-item :prop="`${$index}.identifier`" class="mb-0px!">
+            <el-select
+              v-if="shouldShowIdentifierSelect(row)"
+              v-model="row.identifier"
+              placeholder="璇烽�夋嫨鏍囪瘑绗�"
+              clearable
+              filterable
+              style="width: 100%"
+              v-loading="row.identifierLoading"
+            >
+              <el-option
+                v-for="item in getThingModelOptions(row)"
+                :key="item.value"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </el-form-item>
+        </template>
+      </el-table-column>
+      <el-table-column align="center" fixed="right" label="鎿嶄綔" width="60">
+        <template #default="{ $index }">
+          <el-button @click="handleDelete($index)" link type="danger">鈥�</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <el-row justify="center" class="mt-3">
+      <el-button @click="handleAdd" type="primary" plain round>+ 娣诲姞鏁版嵁婧�</el-button>
+    </el-row>
+  </el-form>
+</template>
+
+<script setup lang="ts">
+import { ProductApi } from '@/api/iot/product/product'
+import { DeviceApi } from '@/api/iot/device/device'
+import { ThingModelApi } from '@/api/iot/thingmodel'
+import { IotDeviceMessageMethodEnum, IoTThingModelTypeEnum } from '@/views/iot/utils/constants'
+
+const formData = ref<any[]>([])
+const productList = ref<any[]>([]) // 浜у搧鍒楄〃
+const deviceList = ref<any[]>([]) // 璁惧鍒楄〃
+const thingModelCache = ref<Map<number, any[]>>(new Map()) // 缂撳瓨鐗╂ā鍨嬫暟鎹紝key 涓� productId
+
+const formRules = reactive({
+  productId: [{ required: true, message: '浜у搧涓嶈兘涓虹┖', trigger: 'change' }],
+  deviceId: [{ required: true, message: '璁惧涓嶈兘涓虹┖', trigger: 'change' }],
+  method: [{ required: true, message: '娑堟伅鏂规硶涓嶈兘涓虹┖', trigger: 'change' }]
+})
+const formRef = ref() // 琛ㄥ崟 Ref
+
+// 鑾峰彇涓婅娑堟伅鏂规硶鍒楄〃
+const upstreamMethods = computed(() => {
+  return Object.values(IotDeviceMessageMethodEnum).filter((item) => item.upstream)
+})
+
+/** 鏍规嵁浜у搧 ID 杩囨护璁惧 */
+const getFilteredDevices = (productId: number) => {
+  if (!productId) return []
+  return deviceList.value.filter((device: any) => device.productId === productId)
+}
+
+/** 鍒ゆ柇鏄惁闇�瑕佹樉绀烘爣璇嗙閫夋嫨鍣� */
+const shouldShowIdentifierSelect = (row: any) => {
+  return [
+    IotDeviceMessageMethodEnum.EVENT_POST.method,
+    IotDeviceMessageMethodEnum.PROPERTY_POST.method
+  ].includes(row.method)
+}
+
+/** 鑾峰彇鐗╂ā鍨嬮�夐」 */
+const getThingModelOptions = (row: any) => {
+  if (!row.productId || !shouldShowIdentifierSelect(row)) {
+    return []
+  }
+  const thingModels: any[] = thingModelCache.value.get(row.productId) || []
+  let filteredModels: any[] = []
+  if (row.method === IotDeviceMessageMethodEnum.EVENT_POST.method) {
+    filteredModels = thingModels.filter((item: any) => item.type === IoTThingModelTypeEnum.EVENT)
+  } else if (row.method === IotDeviceMessageMethodEnum.PROPERTY_POST.method) {
+    filteredModels = thingModels.filter((item: any) => item.type === IoTThingModelTypeEnum.PROPERTY)
+  }
+  return filteredModels.map((item: any) => ({
+    label: `${item.name} (${item.identifier})`,
+    value: item.identifier
+  }))
+}
+
+/** 鍔犺浇浜у搧鍒楄〃 */
+const loadProductList = async () => {
+  try {
+    productList.value = await ProductApi.getSimpleProductList()
+  } catch (error) {
+    console.error('鍔犺浇浜у搧鍒楄〃澶辫触:', error)
+  }
+}
+
+/** 鍔犺浇璁惧鍒楄〃 */
+const loadDeviceList = async () => {
+  try {
+    deviceList.value = await DeviceApi.getSimpleDeviceList()
+  } catch (error) {
+    console.error('鍔犺浇璁惧鍒楄〃澶辫触:', error)
+  }
+}
+
+/** 鍔犺浇鐗╂ā鍨嬫暟鎹� */
+const loadThingModel = async (productId: number) => {
+  // 宸茬紦瀛橈紝鏃犻渶閲嶅鍔犺浇
+  if (thingModelCache.value.has(productId)) {
+    return
+  }
+  try {
+    const thingModels = await ThingModelApi.getThingModelList({ productId })
+    thingModelCache.value.set(productId, thingModels)
+  } catch (error) {
+    console.error('鍔犺浇鐗╂ā鍨嬪け璐�:', error)
+  }
+}
+
+/** 浜у搧鍙樺寲鏃跺鐞� */
+const handleProductChange = async (row: any, _index: number) => {
+  row.deviceId = 0
+  row.method = undefined
+  row.identifier = undefined
+  row.identifierLoading = false
+}
+
+/** 娑堟伅鏂规硶鍙樺寲鏃跺鐞� */
+const handleMethodChange = async (row: any, _index: number) => {
+  // 娓呯┖鏍囪瘑绗�
+  row.identifier = undefined
+  // 濡傛灉闇�瑕佸姞杞界墿妯″瀷鏁版嵁
+  if (shouldShowIdentifierSelect(row) && row.productId) {
+    row.identifierLoading = true
+    await loadThingModel(row.productId)
+    row.identifierLoading = false
+  }
+}
+
+/** 鏂板鎸夐挳鎿嶄綔 */
+const handleAdd = () => {
+  const row = {
+    productId: undefined,
+    deviceId: undefined,
+    method: undefined,
+    identifier: undefined,
+    identifierLoading: false
+  }
+  formData.value.push(row)
+}
+
+/** 鍒犻櫎鎸夐挳鎿嶄綔 */
+const handleDelete = (index: number) => {
+  formData.value.splice(index, 1)
+}
+
+/** 琛ㄥ崟鏍¢獙 */
+const validate = () => {
+  return formRef.value.validate()
+}
+
+/** 琛ㄥ崟鍊� */
+const getData = () => {
+  return formData.value
+}
+
+/** 璁剧疆琛ㄥ崟鍊� */
+const setData = (data: any[]) => {
+  // 纭繚姣忎釜椤归兘鏈夊繀瑕佺殑瀛楁
+  formData.value = (data || []).map((item) => ({
+    ...item,
+    identifierLoading: false
+  }))
+  // 涓哄凡鏈夋暟鎹鍔犺浇鐗╂ā鍨�
+  data?.forEach(async (item) => {
+    if (item.productId && shouldShowIdentifierSelect(item)) {
+      await loadThingModel(item.productId)
+    }
+  })
+}
+
+/** 鍒濆鍖� */
+onMounted(async () => {
+  await Promise.all([loadProductList(), loadDeviceList()])
+})
+
+defineExpose({ validate, getData, setData })
+</script>

--
Gitblit v1.8.0