【优化】 IOT 设备管理

pull/542/head
安浩浩 2024-09-22 13:17:12 +08:00
parent b69a784e86
commit 63a0e5dc3d
3 changed files with 95 additions and 61 deletions

View File

@ -1,6 +1,6 @@
import request from '@/config/axios'
// IoT 设备 VO
// 设备 VO
export interface DeviceVO {
id: number // 设备 ID主键自增
deviceKey: string // 设备唯一标识符,全局唯一,用于识别设备
@ -29,35 +29,45 @@ export interface DeviceVO {
serialNumber: string // 设备序列号
}
// IoT 设备 API
export interface DeviceUpdateStatusVO {
id: number // 设备 ID主键自增
status: number // 设备状态0 - 未激活1 - 在线2 - 离线3 - 已禁用
}
// 设备 API
export const DeviceApi = {
// 查询IoT 设备分页
// 查询设备分页
getDevicePage: async (params: any) => {
return await request.get({ url: `/iot/device/page`, params })
},
// 查询IoT 设备详情
// 查询设备详情
getDevice: async (id: number) => {
return await request.get({ url: `/iot/device/get?id=` + id })
},
// 新增IoT 设备
// 新增设备
createDevice: async (data: DeviceVO) => {
return await request.post({ url: `/iot/device/create`, data })
},
// 修改IoT 设备
// 修改设备
updateDevice: async (data: DeviceVO) => {
return await request.put({ url: `/iot/device/update`, data })
},
// 删除IoT 设备
// 修改设备状态
updateDeviceStatus: async (data: DeviceUpdateStatusVO) => {
return await request.put({ url: `/iot/device/update-status`, data })
},
// 删除设备
deleteDevice: async (id: number) => {
return await request.delete({ url: `/iot/device/delete?id=` + id })
},
// 导出IoT 设备 Excel
// 导出设备 Excel
exportDevice: async (params) => {
return await request.download({ url: `/iot/device/export-excel`, params })
}
}
}

View File

@ -8,7 +8,12 @@
v-loading="formLoading"
>
<el-form-item label="产品" prop="productId">
<el-select v-model="formData.productId" placeholder="请选择产品" clearable>
<el-select
v-model="formData.productId"
placeholder="请选择产品"
:disabled="formType === 'update'"
clearable
>
<el-option
v-for="product in products"
:key="product.id"
@ -18,7 +23,11 @@
</el-select>
</el-form-item>
<el-form-item label="DeviceName" prop="deviceName">
<el-input v-model="formData.deviceName" placeholder="请输入 DeviceName" />
<el-input
v-model="formData.deviceName"
placeholder="请输入 DeviceName"
:disabled="formType === 'update'"
/>
</el-form-item>
<el-form-item label="备注名称" prop="nickname">
<el-input v-model="formData.nickname" placeholder="请输入备注名称" />
@ -52,7 +61,34 @@ const formData = ref({
serialNumber: undefined
})
const formRules = reactive({
productId: [{ required: true, message: '产品不能为空', trigger: 'blur' }]
productId: [{ required: true, message: '产品不能为空', trigger: 'blur' }],
deviceName: [
{
pattern: /^[a-zA-Z0-9_.\-:@]{4,32}$/,
message:
'支持英文字母、数字、下划线_、中划线-)、点号(.)、半角冒号(:)和特殊字符@长度限制为4~32个字符',
trigger: 'blur'
}
],
nickname: [
{
validator: (rule, value, callback) => {
if (value === undefined || value === null) {
callback()
return
}
const length = value.replace(/[\u4e00-\u9fa5\u3040-\u30ff]/g, 'aa').length
if (length < 4 || length > 64) {
callback(new Error('备注名称长度限制为4~64个字符中文及日文算2个字符'))
} else if (!/^[\u4e00-\u9fa5\u3040-\u30ff_a-zA-Z0-9]+$/.test(value)) {
callback(new Error('备注名称只能包含中文、英文字母、日文、数字和下划线_'))
} else {
callback()
}
},
trigger: 'blur'
}
]
})
const formRef = ref() // Ref

View File

@ -72,24 +72,22 @@
</el-select>
</el-form-item>
<el-form-item>
<el-button @click="handleQuery"><Icon icon="ep:search" class="mr-5px" /> 搜索</el-button>
<el-button @click="resetQuery"><Icon icon="ep:refresh" class="mr-5px" /> 重置</el-button>
<el-button @click="handleQuery">
<Icon icon="ep:search" class="mr-5px" />
搜索
</el-button>
<el-button @click="resetQuery">
<Icon icon="ep:refresh" class="mr-5px" />
重置
</el-button>
<el-button
type="primary"
plain
@click="openForm('create')"
v-hasPermi="['iot:device:create']"
>
<Icon icon="ep:plus" class="mr-5px" /> 新增
</el-button>
<el-button
type="success"
plain
@click="handleExport"
:loading="exportLoading"
v-hasPermi="['iot:device:export']"
>
<Icon icon="ep:download" class="mr-5px" /> 导出
<Icon icon="ep:plus" class="mr-5px" />
新增
</el-button>
</el-form-item>
</el-form>
@ -100,9 +98,21 @@
<el-table v-loading="loading" :data="list" :stripe="true" :show-overflow-tooltip="true">
<el-table-column label="DeviceName" align="center" prop="deviceName" />
<el-table-column label="备注名称" align="center" prop="nickname" />
<el-table-column label="设备所属产品" align="center" prop="productName" />
<el-table-column label="设备类型" align="center" prop="deviceType" />
<el-table-column label="设备状态" align="center" prop="status" />
<el-table-column label="设备所属产品" align="center" prop="productId">
<template #default="scope">
{{ productMap[scope.row.productId] }}
</template>
</el-table-column>
<el-table-column label="设备类型" align="center" prop="deviceType">
<template #default="scope">
<dict-tag :type="DICT_TYPE.IOT_PRODUCT_DEVICE_TYPE" :value="scope.row.deviceType" />
</template>
</el-table-column>
<el-table-column label="设备状态" align="center" prop="status">
<template #default="scope">
<dict-tag :type="DICT_TYPE.IOT_DEVICE_STATUS" :value="scope.row.status" />
</template>
</el-table-column>
<el-table-column
label="最后上线时间"
align="center"
@ -110,18 +120,6 @@
:formatter="dateFormatter"
width="180px"
/>
<el-table-column label="启用禁用">
<template #default="scope">
<el-switch
v-model="scope.row.status"
active-value="1"
inactive-value="0"
active-text="启用"
inactive-text="禁用"
@change="handleUpdate(scope.row)"
/>
</template>
</el-table-column>
<el-table-column label="操作" align="center" min-width="120px">
<template #default="scope">
<el-button
@ -160,7 +158,7 @@
import { DICT_TYPE, getIntDictOptions } from '@/utils/dict'
import { dateFormatter } from '@/utils/formatTime'
import download from '@/utils/download'
import { DeviceApi, DeviceVO } from '@/api/iot/device'
import { DeviceApi, DeviceUpdateStatusVO, DeviceVO } from '@/api/iot/device'
import DeviceForm from './DeviceForm.vue'
import { ProductApi } from '@/api/iot/product'
@ -176,35 +174,18 @@ const total = ref(0) // 列表的总页数
const queryParams = reactive({
pageNo: 1,
pageSize: 10,
deviceKey: undefined,
deviceName: undefined,
productId: undefined,
productKey: undefined,
deviceType: undefined,
nickname: undefined,
gatewayId: undefined,
status: undefined,
statusLastUpdateTime: [],
lastOnlineTime: [],
lastOfflineTime: [],
activeTime: [],
ip: undefined,
firmwareVersion: undefined,
deviceSecret: undefined,
mqttClientId: undefined,
mqttUsername: undefined,
mqttPassword: undefined,
authType: undefined,
latitude: undefined,
longitude: undefined,
areaId: undefined,
address: undefined,
serialNumber: undefined,
createTime: []
status: undefined
})
const queryFormRef = ref() //
const exportLoading = ref(false) //
/** 产品ID到名称的映射 */
const productMap = reactive({})
/** 查询列表 */
const getList = async () => {
loading.value = true
@ -212,6 +193,13 @@ 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))]
//
const products = await Promise.all(productIds.map((id) => ProductApi.getProduct(id)))
products.forEach((product) => {
productMap[product.id] = product.name
})
} finally {
loading.value = false
}