mirror of
https://github.com/yudaocode/yudao-ui-admin-vue3.git
synced 2026-03-29 23:25:52 +00:00
feat(iot):【网关设备:80%】动态注册的初步实现(已测试)
This commit is contained in:
@@ -21,7 +21,6 @@ export interface DeviceVO {
|
||||
mqttClientId: string // MQTT 客户端 ID
|
||||
mqttUsername: string // MQTT 用户名
|
||||
mqttPassword: string // MQTT 密码
|
||||
authType: string // 认证类型
|
||||
latitude?: number // 设备位置的纬度
|
||||
longitude?: number // 设备位置的经度
|
||||
areaId: number // 地区编码
|
||||
@@ -161,12 +160,12 @@ export const DeviceApi = {
|
||||
},
|
||||
|
||||
// 绑定子设备到网关
|
||||
bindDeviceGateway: async (data: { ids: number[]; gatewayId: number }) => {
|
||||
bindDeviceGateway: async (data: { subIds: number[]; gatewayId: number }) => {
|
||||
return await request.put({ url: `/iot/device/bind-gateway`, data })
|
||||
},
|
||||
|
||||
// 解绑子设备与网关
|
||||
unbindDeviceGateway: async (data: { ids: number[] }) => {
|
||||
unbindDeviceGateway: async (data: { subIds: number[]; gatewayId: number }) => {
|
||||
return await request.put({ url: `/iot/device/unbind-gateway`, data })
|
||||
},
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ export interface ProductVO {
|
||||
id: number // 产品编号
|
||||
name: string // 产品名称
|
||||
productKey: string // 产品标识
|
||||
productSecret?: string // 产品密钥
|
||||
registerEnabled?: boolean // 动态注册
|
||||
protocolId: number // 协议编号
|
||||
categoryId: number // 产品所属品类标识符
|
||||
categoryName?: string // 产品所属品类名称
|
||||
|
||||
@@ -30,20 +30,6 @@
|
||||
:disabled="formType === 'update'"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="formData.deviceType === DeviceTypeEnum.GATEWAY_SUB"
|
||||
label="网关设备"
|
||||
prop="gatewayId"
|
||||
>
|
||||
<el-select v-model="formData.gatewayId" placeholder="子设备可选择父设备" clearable>
|
||||
<el-option
|
||||
v-for="gateway in gatewayDevices"
|
||||
:key="gateway.id"
|
||||
:label="gateway.nickname || gateway.deviceName"
|
||||
:value="gateway.id"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
|
||||
<el-collapse>
|
||||
<el-collapse-item title="更多配置">
|
||||
@@ -114,7 +100,6 @@ const formData = ref({
|
||||
deviceName: undefined,
|
||||
nickname: undefined,
|
||||
picUrl: undefined,
|
||||
gatewayId: undefined,
|
||||
deviceType: undefined as number | undefined,
|
||||
serialNumber: undefined,
|
||||
longitude: undefined as number | string | undefined,
|
||||
@@ -222,7 +207,6 @@ const formRules = reactive({
|
||||
})
|
||||
const formRef = ref() // 表单 Ref
|
||||
const products = ref<ProductVO[]>([]) // 产品列表
|
||||
const gatewayDevices = ref<DeviceVO[]>([]) // 网关设备列表
|
||||
const deviceGroups = ref<any[]>([])
|
||||
|
||||
/** 打开弹窗 */
|
||||
@@ -242,8 +226,6 @@ const open = async (type: string, id?: number) => {
|
||||
}
|
||||
}
|
||||
|
||||
// 加载网关设备列表
|
||||
gatewayDevices.value = await DeviceApi.getSimpleDeviceList(DeviceTypeEnum.GATEWAY)
|
||||
// 加载产品列表
|
||||
products.value = await ProductApi.getSimpleProductList()
|
||||
// 加载设备分组列表
|
||||
@@ -283,7 +265,6 @@ const resetForm = () => {
|
||||
deviceName: undefined,
|
||||
nickname: undefined,
|
||||
picUrl: undefined,
|
||||
gatewayId: undefined,
|
||||
deviceType: undefined,
|
||||
serialNumber: undefined,
|
||||
longitude: undefined,
|
||||
|
||||
@@ -225,7 +225,7 @@ const handleBindSubmit = async () => {
|
||||
bindFormLoading.value = true
|
||||
try {
|
||||
await DeviceApi.bindDeviceGateway({
|
||||
ids: bindSelectedIds.value,
|
||||
subIds: bindSelectedIds.value,
|
||||
gatewayId: props.gatewayId
|
||||
})
|
||||
message.success('绑定成功')
|
||||
@@ -240,7 +240,7 @@ const handleBindSubmit = async () => {
|
||||
const handleUnbind = async (id: number) => {
|
||||
try {
|
||||
await message.confirm('确定要解绑该子设备吗?')
|
||||
await DeviceApi.unbindDeviceGateway({ ids: [id] })
|
||||
await DeviceApi.unbindDeviceGateway({ subIds: [id], gatewayId: props.gatewayId })
|
||||
message.success('解绑成功')
|
||||
await getSubDeviceList()
|
||||
} catch {}
|
||||
@@ -250,7 +250,7 @@ const handleUnbind = async (id: number) => {
|
||||
const handleUnbindBatch = async () => {
|
||||
try {
|
||||
await message.confirm(`确定要解绑选中的 ${selectedIds.value.length} 个子设备吗?`)
|
||||
await DeviceApi.unbindDeviceGateway({ ids: selectedIds.value })
|
||||
await DeviceApi.unbindDeviceGateway({ subIds: selectedIds.value, gatewayId: props.gatewayId })
|
||||
message.success('批量解绑成功')
|
||||
selectedIds.value = []
|
||||
await getSubDeviceList()
|
||||
|
||||
@@ -75,6 +75,20 @@
|
||||
</el-form-item>
|
||||
<el-collapse>
|
||||
<el-collapse-item title="更多配置">
|
||||
<el-form-item label="动态注册" prop="registerEnabled">
|
||||
<template #label>
|
||||
<el-tooltip
|
||||
content="设备动态注册无需一一烧录设备证书(DeviceSecret),每台设备烧录相同的产品证书,即 ProductKey 和 ProductSecret ,云端鉴权通过后下发设备证书,您可以根据需要开启或关闭动态注册,保障安全性。"
|
||||
placement="top"
|
||||
>
|
||||
<span>
|
||||
动态注册
|
||||
<Icon icon="ep:question-filled" class="ml-2px" />
|
||||
</span>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<el-switch v-model="formData.registerEnabled" />
|
||||
</el-form-item>
|
||||
<el-form-item label="产品图标" prop="icon">
|
||||
<UploadImg v-model="formData.icon" :height="'80px'" :width="'80px'" />
|
||||
</el-form-item>
|
||||
@@ -120,7 +134,8 @@ const formData = ref({
|
||||
description: undefined,
|
||||
deviceType: undefined,
|
||||
netType: undefined,
|
||||
codecType: CodecTypeEnum.ALINK
|
||||
codecType: CodecTypeEnum.ALINK,
|
||||
registerEnabled: false
|
||||
})
|
||||
const formRules = reactive({
|
||||
productKey: [{ required: true, message: 'ProductKey 不能为空', trigger: 'blur' }],
|
||||
@@ -194,7 +209,8 @@ const resetForm = () => {
|
||||
description: undefined,
|
||||
deviceType: undefined,
|
||||
netType: undefined,
|
||||
codecType: CodecTypeEnum.ALINK
|
||||
codecType: CodecTypeEnum.ALINK,
|
||||
registerEnabled: false
|
||||
}
|
||||
formRef.value?.resetFields()
|
||||
}
|
||||
|
||||
@@ -21,6 +21,28 @@
|
||||
>
|
||||
<dict-tag :type="DICT_TYPE.IOT_NET_TYPE" :value="product.netType" />
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="动态注册">
|
||||
<el-tag :type="product.registerEnabled ? 'success' : 'info'">
|
||||
{{ product.registerEnabled ? '已开启' : '已关闭' }}
|
||||
</el-tag>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="产品密钥">
|
||||
<div class="flex items-center">
|
||||
<span>{{ secretVisible ? product.productSecret : '******' }}</span>
|
||||
<el-button link type="primary" class="ml-2" @click="secretVisible = !secretVisible">
|
||||
<Icon :icon="secretVisible ? 'ep:hide' : 'ep:view'" />
|
||||
</el-button>
|
||||
<el-button
|
||||
v-if="secretVisible && product.productSecret"
|
||||
link
|
||||
type="primary"
|
||||
class="ml-1"
|
||||
@click="copySecret"
|
||||
>
|
||||
<Icon icon="ep:document-copy" />
|
||||
</el-button>
|
||||
</div>
|
||||
</el-descriptions-item>
|
||||
<el-descriptions-item label="产品描述">{{ product.description }}</el-descriptions-item>
|
||||
</el-descriptions>
|
||||
</ContentWrap>
|
||||
@@ -29,6 +51,19 @@
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
import { DeviceTypeEnum, ProductVO } from '@/api/iot/product/product'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
import { useClipboard } from '@vueuse/core'
|
||||
|
||||
const { product } = defineProps<{ product: ProductVO }>()
|
||||
|
||||
const message = useMessage()
|
||||
const secretVisible = ref(false)
|
||||
const { copy } = useClipboard()
|
||||
|
||||
/** 复制产品密钥 */
|
||||
const copySecret = async () => {
|
||||
if (product.productSecret) {
|
||||
await copy(product.productSecret)
|
||||
message.success('复制成功')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -24,7 +24,41 @@ export const IotDeviceMessageMethodEnum = {
|
||||
// ========== 设备状态 ==========
|
||||
STATE_UPDATE: {
|
||||
method: 'thing.state.update',
|
||||
name: '设备状态变更',
|
||||
name: '设备状态更新',
|
||||
upstream: true
|
||||
},
|
||||
|
||||
// ========== 拓扑管理 ==========
|
||||
TOPO_ADD: {
|
||||
method: 'thing.topo.add',
|
||||
name: '添加拓扑关系',
|
||||
upstream: true
|
||||
},
|
||||
TOPO_DELETE: {
|
||||
method: 'thing.topo.delete',
|
||||
name: '删除拓扑关系',
|
||||
upstream: true
|
||||
},
|
||||
TOPO_GET: {
|
||||
method: 'thing.topo.get',
|
||||
name: '获取拓扑关系',
|
||||
upstream: true
|
||||
},
|
||||
TOPO_CHANGE: {
|
||||
method: 'thing.topo.change',
|
||||
name: '拓扑关系变更通知',
|
||||
upstream: false
|
||||
},
|
||||
|
||||
// ========== 设备注册 ==========
|
||||
DEVICE_REGISTER: {
|
||||
method: 'thing.auth.register',
|
||||
name: '设备动态注册',
|
||||
upstream: true
|
||||
},
|
||||
SUB_DEVICE_REGISTER: {
|
||||
method: 'thing.auth.register.sub',
|
||||
name: '子设备动态注册',
|
||||
upstream: true
|
||||
},
|
||||
|
||||
@@ -39,6 +73,11 @@ export const IotDeviceMessageMethodEnum = {
|
||||
name: '属性设置',
|
||||
upstream: false
|
||||
},
|
||||
PROPERTY_PACK_POST: {
|
||||
method: 'thing.event.property.pack.post',
|
||||
name: '批量上报(属性 + 事件 + 子设备)',
|
||||
upstream: true
|
||||
},
|
||||
|
||||
// ========== 设备事件 ==========
|
||||
EVENT_POST: {
|
||||
@@ -59,6 +98,18 @@ export const IotDeviceMessageMethodEnum = {
|
||||
method: 'thing.config.push',
|
||||
name: '配置推送',
|
||||
upstream: false
|
||||
},
|
||||
|
||||
// ========== OTA 固件 ==========
|
||||
OTA_UPGRADE: {
|
||||
method: 'thing.ota.upgrade',
|
||||
name: 'OTA 固件信息推送',
|
||||
upstream: false
|
||||
},
|
||||
OTA_PROGRESS: {
|
||||
method: 'thing.ota.progress',
|
||||
name: 'OTA 升级进度上报',
|
||||
upstream: true
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user