From 6e0ba43db65cd9b9bda806b237fa2998526dd032 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 14 Jun 2025 14:37:39 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E3=80=90IoT=20=E7=89=A9=E8=81=94?= =?UTF-8?q?=E7=BD=91=E3=80=91=E8=B0=83=E6=95=B4=E8=AE=BE=E5=A4=87=E6=A8=A1?= =?UTF-8?q?=E6=8B=9F=E5=8F=91=E9=80=81=E6=B6=88=E6=81=AF=E7=9A=84=E6=8E=A5?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/iot/device/device/index.ts | 53 +++++++------------ .../device/detail/DeviceDetailsMessage.vue | 53 +++++++++++++++---- .../device/detail/DeviceDetailsSimulator.vue | 48 ++++++++--------- 3 files changed, 86 insertions(+), 68 deletions(-) diff --git a/src/api/iot/device/device/index.ts b/src/api/iot/device/device/index.ts index 7a0ef6def..99968e264 100644 --- a/src/api/iot/device/device/index.ts +++ b/src/api/iot/device/device/index.ts @@ -49,6 +49,7 @@ export interface DeviceHistoryDataVO { data: string // 数据 } +// TODO @芋艿:调整到 constants // IoT 设备状态枚举 export enum DeviceStateEnum { INACTIVE = 0, // 未激活 @@ -56,22 +57,6 @@ export enum DeviceStateEnum { OFFLINE = 2 // 离线 } -// IoT 设备上行 Request VO -export interface IotDeviceUpstreamReqVO { - id: number // 设备编号 - type: string // 消息类型 - identifier: string // 标识符 - data: any // 请求参数 -} - -// IoT 设备下行 Request VO -export interface IotDeviceDownstreamReqVO { - id: number // 设备编号 - type: string // 消息类型 - identifier: string // 标识符 - data: any // 请求参数 -} - // 设备认证参数 VO export interface IotDeviceAuthInfoVO { clientId: string // 客户端 ID @@ -79,6 +64,13 @@ export interface IotDeviceAuthInfoVO { password: string // 密码 } +// IoT 设备发送消息 Request VO +export interface IotDeviceMessageSendReqVO { + deviceId: number // 设备编号 + method: string // 请求方法 + params?: any // 请求参数 +} + // 设备 API export const DeviceApi = { // 查询设备分页 @@ -136,16 +128,6 @@ export const DeviceApi = { return await request.download({ url: `/iot/device/get-import-template` }) }, - // 设备上行 - upstreamDevice: async (data: IotDeviceUpstreamReqVO) => { - return await request.post({ url: `/iot/device/upstream`, data }) - }, - - // 设备下行 - downstreamDevice: async (data: IotDeviceDownstreamReqVO) => { - return await request.post({ url: `/iot/device/downstream`, data }) - }, - // 获取设备属性最新数据 getLatestDeviceProperties: async (params: any) => { return await request.get({ url: `/iot/device/property/latest`, params }) @@ -156,18 +138,13 @@ export const DeviceApi = { return await request.get({ url: `/iot/device/property/history-page`, params }) }, - // 查询设备日志分页 - getDeviceMessagePage: async (params: any) => { - return await request.get({ url: `/iot/device/message/page`, params }) - }, - - // 获取设备 MQTT 连接参数 + // 获取设备认证信息 getDeviceAuthInfo: async (id: number) => { return await request.get({ url: `/iot/device/get-auth-info`, params: { id } }) }, // 根据 ProductKey 和 DeviceNames 获取设备列表 - // TODO @puhui999:getDeviceListByProductKeyAndNames 哈。项目的风格统一~ + // TODO @puhui999:有没可能搞成基于 id 的查询哈? getDevicesByProductKeyAndNames: async (productKey: string, deviceNames: string[]) => { return await request.get({ url: `/iot/device/list-by-product-key-and-names`, @@ -176,5 +153,15 @@ export const DeviceApi = { deviceNames: deviceNames.join(',') } }) + }, + + // 查询设备消息分页 + getDeviceMessagePage: async (params: any) => { + return await request.get({ url: `/iot/device/message/page`, params }) + }, + + // 发送设备消息 + sendDeviceMessage: async (params: IotDeviceMessageSendReqVO) => { + return await request.post({ url: `/iot/device/message/send`, data: params }) } } diff --git a/src/views/iot/device/device/detail/DeviceDetailsMessage.vue b/src/views/iot/device/device/detail/DeviceDetailsMessage.vue index 6abf6d627..637cb7e75 100644 --- a/src/views/iot/device/device/detail/DeviceDetailsMessage.vue +++ b/src/views/iot/device/device/detail/DeviceDetailsMessage.vue @@ -5,11 +5,21 @@ - + - + @@ -33,7 +43,6 @@ - + - - + @@ -106,7 +121,7 @@ let autoRefreshTimer: any = null // TODO @super:autoRefreshEnable,autoRefres // 消息方法选项 const methodOptions = computed(() => { - return Object.values(IotDeviceMessageMethodEnum).map(item => ({ + return Object.values(IotDeviceMessageMethodEnum).map((item) => ({ label: item.name, value: item.method })) @@ -166,4 +181,20 @@ onMounted(() => { getMessageList() } }) + +/** 刷新消息列表 */ +const refresh = (delay = 0) => { + if (delay > 0) { + setTimeout(() => { + handleQuery() + }, delay) + } else { + handleQuery() + } +} + +/** 暴露方法给父组件 */ +defineExpose({ + refresh +}) diff --git a/src/views/iot/device/device/detail/DeviceDetailsSimulator.vue b/src/views/iot/device/device/detail/DeviceDetailsSimulator.vue index c37405c6b..2f4858aa8 100644 --- a/src/views/iot/device/device/detail/DeviceDetailsSimulator.vue +++ b/src/views/iot/device/device/detail/DeviceDetailsSimulator.vue @@ -41,7 +41,7 @@
- 发送 + 发送
@@ -50,7 +50,7 @@ - + - - - - - + + + @@ -149,6 +147,7 @@ import { DeviceApi, DeviceStateEnum, DeviceVO } from '@/api/iot/device/device' import DeviceDetailsMessage from './DeviceDetailsMessage.vue' import { getDataTypeOptionsLabel } from '@/views/iot/thingmodel/config' import { DataDefinition } from '@/views/iot/thingmodel/components' +import { IotDeviceMessageMethodEnum } from '@/views/iot/utils/constants' const props = defineProps<{ product: ProductVO @@ -158,10 +157,12 @@ const props = defineProps<{ const message = useMessage() // 消息弹窗 const activeTab = ref('up') // TODO @super:upstream 上行、downstream 下行 const subTab = ref('property') // TODO @super:upstreamTab +const deviceMessageRef = ref() // 设备消息组件引用 +const deviceMessageRefresnhDelay = 2000 // 延迟 N 秒,保证模拟上行的消息被处理 const loading = ref(false) const queryParams = reactive({ - type: undefined, // TODO @super:type 默认给个第一个 tab 对应的,避免下面 watch 爆红 + type: undefined as number | undefined, // TODO @super:type 默认给个第一个 tab 对应的,避免下面 watch 爆红 productId: -1 }) const list = ref([]) // 物模型列表的数据 TODO @super:thingModelList @@ -228,9 +229,6 @@ watch( case 'event': queryParams.type = 3 break - // case 'status': - // queryParams.type = 'status' - // break } } else if (newActiveTab === 'down') { switch (newSubTab) { @@ -248,26 +246,26 @@ watch( ) /** 处理属性上报 */ -const handlePropertyReport = async () => { +const handlePropertyPost = async () => { // TODO @super:数据类型效验 - const data: Record = {} + const data: Record = {} list.value.forEach((item) => { // 只有当 simulateValue 有值时才添加到 content 中 // TODO @super:直接 if (item.simulateValue) 就可以哈,js 这块还是比较灵活的 - if (item.simulateValue !== undefined && item.simulateValue !== '') { + if (item.simulateValue !== undefined && item.simulateValue !== '' && item.identifier) { // TODO @super:这里有个红色的 idea 告警,觉得去除下 data[item.identifier] = item.simulateValue } }) try { - await DeviceApi.upstreamDevice({ - id: props.device.id, - type: 'property', - identifier: 'report', - data: data + await DeviceApi.sendDeviceMessage({ + deviceId: props.device.id, + method: IotDeviceMessageMethodEnum.PROPERTY_POST.method, + params: data }) message.success('属性上报成功') + deviceMessageRef.value.refresh(deviceMessageRefresnhDelay) } catch (error) { message.error('属性上报失败') } @@ -305,13 +303,15 @@ const handlePropertyReport = async () => { /** 处理设备状态 */ const handleDeviceState = async (state: number) => { try { - await DeviceApi.upstreamDevice({ - id: props.device.id, - type: 'state', - identifier: 'report', - data: state + await DeviceApi.sendDeviceMessage({ + deviceId: props.device.id, + method: + state === DeviceStateEnum.ONLINE + ? IotDeviceMessageMethodEnum.STATE_ONLINE.method + : IotDeviceMessageMethodEnum.STATE_OFFLINE.method }) message.success(`设备${state === DeviceStateEnum.ONLINE ? '上线' : '下线'}成功`) + deviceMessageRef.value.refresh(deviceMessageRefresnhDelay) } catch (error) { message.error(`设备${state === DeviceStateEnum.ONLINE ? '上线' : '下线'}失败`) }