Эх сурвалжийг харах

【功能新增】IoT:设备管理界面增加设备分组选择功能

YunaiV 8 сар өмнө
parent
commit
14fe6c559f

+ 7 - 1
src/api/iot/device/group/index.ts

@@ -6,6 +6,7 @@ export interface DeviceGroupVO {
   name: string // 分组名字
   status: number // 分组状态
   description: string // 分组描述
+  deviceCount?: number // 设备数量
 }
 
 // IoT 设备分组 API
@@ -33,5 +34,10 @@ export const DeviceGroupApi = {
   // 删除IoT 设备分组
   deleteDeviceGroup: async (id: number) => {
     return await request.delete({ url: `/iot/device-group/delete?id=` + id })
+  },
+
+  // 获取设备分组的精简信息列表
+  getSimpleDeviceGroupList: async () => {
+    return await request.get({ url: `/iot/device-group/simple-list` })
   }
-}
+}

+ 1 - 0
src/api/iot/device/index.ts

@@ -28,6 +28,7 @@ export interface DeviceVO {
   areaId: number // 地区编码
   address: string // 设备详细地址
   serialNumber: string // 设备序列号
+  groupIds?: number[] // 添加分组 ID
 }
 
 export interface DeviceUpdateStatusVO {

+ 23 - 2
src/views/iot/device/device/DeviceForm.vue

@@ -62,6 +62,16 @@
           <el-form-item label="设备图片" prop="picUrl">
             <UploadImg v-model="formData.picUrl" :height="'120px'" :width="'120px'" />
           </el-form-item>
+          <el-form-item label="设备分组" prop="groupIds">
+            <el-select v-model="formData.groupIds" placeholder="请选择设备分组" multiple clearable>
+              <el-option
+                v-for="group in deviceGroups"
+                :key="group.id"
+                :label="group.name"
+                :value="group.id"
+              />
+            </el-select>
+          </el-form-item>
           <el-form-item label="设备序列号" prop="serialNumber">
             <el-input v-model="formData.serialNumber" placeholder="请输入设备序列号" />
           </el-form-item>
@@ -76,6 +86,7 @@
 </template>
 <script setup lang="ts">
 import { DeviceApi, DeviceVO } from '@/api/iot/device'
+import { DeviceGroupApi } from '@/api/iot/device/group'
 import { DeviceTypeEnum, ProductApi, ProductVO } from '@/api/iot/product/product'
 import { UploadImg } from '@/components/UploadFile'
 import { generateRandomStr } from '@/utils'
@@ -99,7 +110,8 @@ const formData = ref({
   picUrl: undefined,
   gatewayId: undefined,
   deviceType: undefined as number | undefined,
-  serialNumber: undefined
+  serialNumber: undefined,
+  groupIds: [] as number[]
 })
 const formRules = reactive({
   productId: [{ required: true, message: '产品不能为空', trigger: 'blur' }],
@@ -150,6 +162,7 @@ const formRules = reactive({
 const formRef = ref() // 表单 Ref
 const products = ref<ProductVO[]>([]) // 产品列表
 const gatewayDevices = ref<DeviceVO[]>([]) // 网关设备列表
+const deviceGroups = ref<any[]>([])
 
 /** 打开弹窗 */
 const open = async (type: string, id?: number) => {
@@ -178,6 +191,13 @@ const open = async (type: string, id?: number) => {
   }
   // 加载产品列表
   products.value = await ProductApi.getSimpleProductList()
+
+  // 加载设备分组列表
+  try {
+    deviceGroups.value = await DeviceGroupApi.getSimpleDeviceGroupList()
+  } catch (error) {
+    console.error('加载设备分组列表失败:', error)
+  }
 }
 defineExpose({ open }) // 提供 open 方法,用于打开弹窗
 
@@ -216,7 +236,8 @@ const resetForm = () => {
     picUrl: undefined,
     gatewayId: undefined,
     deviceType: undefined,
-    serialNumber: undefined
+    serialNumber: undefined,
+    groupIds: []
   }
   formRef.value?.resetFields()
 }

+ 38 - 23
src/views/iot/device/device/index.vue

@@ -71,6 +71,21 @@
           />
         </el-select>
       </el-form-item>
+      <el-form-item label="设备分组" prop="groupId">
+        <el-select
+          v-model="queryParams.groupId"
+          placeholder="请选择设备分组"
+          clearable
+          class="!w-240px"
+        >
+          <el-option
+            v-for="group in deviceGroups"
+            :key="group.id"
+            :label="group.name"
+            :value="group.id"
+          />
+        </el-select>
+      </el-form-item>
       <el-form-item>
         <el-button @click="handleQuery">
           <Icon icon="ep:search" class="mr-5px" />
@@ -104,7 +119,7 @@
       <el-table-column label="备注名称" align="center" prop="nickname" />
       <el-table-column label="设备所属产品" align="center" prop="productId">
         <template #default="scope">
-          {{ productMap[scope.row.productId] }}
+          {{ products.find((p) => p.id === scope.row.productId)?.name || '-' }}
         </template>
       </el-table-column>
       <el-table-column label="设备类型" align="center" prop="deviceType">
@@ -124,6 +139,15 @@
         :formatter="dateFormatter"
         width="180px"
       />
+      <el-table-column label="所属分组" align="center" prop="groupId">
+        <template #default="scope">
+          <template v-if="scope.row.groupIds?.length">
+            <el-tag v-for="id in scope.row.groupIds" :key="id" class="ml-5px" size="small">
+              {{ deviceGroups.find((g) => g.id === id)?.name }}
+            </el-tag>
+          </template>
+        </template>
+      </el-table-column>
       <el-table-column label="操作" align="center" min-width="120px">
         <template #default="scope">
           <el-button
@@ -171,7 +195,8 @@ import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
 import { dateFormatter } from '@/utils/formatTime'
 import { DeviceApi, DeviceVO } from '@/api/iot/device'
 import DeviceForm from './DeviceForm.vue'
-import { ProductApi } from '@/api/iot/product/product'
+import { ProductApi, ProductVO } from '@/api/iot/product/product'
+import { DeviceGroupApi, DeviceGroupVO } from '@/api/iot/device/group'
 
 /** IoT 设备 列表 */
 defineOptions({ name: 'IoTDevice' })
@@ -189,12 +214,12 @@ const queryParams = reactive({
   productId: undefined,
   deviceType: undefined,
   nickname: undefined,
-  status: undefined
+  status: undefined,
+  groupId: undefined
 })
 const queryFormRef = ref() // 搜索的表单
-
-/** 产品标号和名称的映射 */
-const productMap = reactive({})
+const products = ref<ProductVO[]>([]) // 产品列表
+const deviceGroups = ref<DeviceGroupVO[]>([]) // 设备分组列表
 
 /** 查询列表 */
 const getList = async () => {
@@ -203,14 +228,6 @@ const getList = async () => {
     const data = await DeviceApi.getDevicePage(queryParams)
     list.value = data.list
     total.value = data.total
-    // 获取产品ID列表
-    const productIds = [...new Set(data.list.map((device) => device.productId))]
-    // 获取产品名称
-    // TODO @haohao:最好后端拼接哈
-    const products = await Promise.all(productIds.map((id) => ProductApi.getProduct(id)))
-    products.forEach((product) => {
-      productMap[product.id] = product.name
-    })
   } finally {
     loading.value = false
   }
@@ -245,7 +262,7 @@ const handleDelete = async (id: number) => {
   try {
     // 删除的二次确认
     await message.delConfirm()
-    // 起删除
+    // 起删除
     await DeviceApi.deleteDevice(id)
     message.success(t('common.delSuccess'))
     // 刷新列表
@@ -253,15 +270,13 @@ const handleDelete = async (id: number) => {
   } catch {}
 }
 
-/** 查询字典下拉列表 */
-const products = ref()
-const getProducts = async () => {
-  products.value = await ProductApi.getSimpleProductList()
-}
-
 /** 初始化 **/
-onMounted(() => {
+onMounted(async () => {
   getList()
-  getProducts()
+
+  // 获取产品列表
+  products.value = await ProductApi.getSimpleProductList()
+  // 获取分组列表
+  deviceGroups.value = await DeviceGroupApi.getSimpleDeviceGroupList()
 })
 </script>

+ 1 - 0
src/views/iot/device/group/index.vue

@@ -61,6 +61,7 @@
         :formatter="dateFormatter"
         width="180px"
       />
+      <el-table-column label="设备数量" align="center" prop="deviceCount" />
       <el-table-column label="操作" align="center" min-width="120px">
         <template #default="scope">
           <el-button