feat:【IoT 物联网】完善设备消息的查询
This commit is contained in:
@ -157,8 +157,8 @@ export const DeviceApi = {
|
||||
},
|
||||
|
||||
// 查询设备日志分页
|
||||
getDeviceLogPage: async (params: any) => {
|
||||
return await request.get({ url: `/iot/device/log/page`, params })
|
||||
getDeviceMessagePage: async (params: any) => {
|
||||
return await request.get({ url: `/iot/device/message/page`, params })
|
||||
},
|
||||
|
||||
// 获取设备 MQTT 连接参数
|
||||
|
||||
@ -1,51 +0,0 @@
|
||||
import request from '@/config/axios'
|
||||
|
||||
// IoT 插件配置 VO
|
||||
export interface PluginConfigVO {
|
||||
id: number // 主键ID
|
||||
pluginKey: string // 插件标识
|
||||
name: string // 插件名称
|
||||
description: string // 描述
|
||||
deployType: number // 部署方式
|
||||
fileName: string // 插件包文件名
|
||||
version: string // 插件版本
|
||||
type: number // 插件类型
|
||||
protocol: string // 设备插件协议类型
|
||||
status: number // 状态
|
||||
configSchema: string // 插件配置项描述信息
|
||||
config: string // 插件配置信息
|
||||
script: string // 插件脚本
|
||||
}
|
||||
|
||||
// IoT 插件配置 API
|
||||
export const PluginConfigApi = {
|
||||
// 查询插件配置分页
|
||||
getPluginConfigPage: async (params: any) => {
|
||||
return await request.get({ url: `/iot/plugin-config/page`, params })
|
||||
},
|
||||
|
||||
// 查询插件配置详情
|
||||
getPluginConfig: async (id: number) => {
|
||||
return await request.get({ url: `/iot/plugin-config/get?id=` + id })
|
||||
},
|
||||
|
||||
// 新增插件配置
|
||||
createPluginConfig: async (data: PluginConfigVO) => {
|
||||
return await request.post({ url: `/iot/plugin-config/create`, data })
|
||||
},
|
||||
|
||||
// 修改插件配置
|
||||
updatePluginConfig: async (data: PluginConfigVO) => {
|
||||
return await request.put({ url: `/iot/plugin-config/update`, data })
|
||||
},
|
||||
|
||||
// 删除插件配置
|
||||
deletePluginConfig: async (id: number) => {
|
||||
return await request.delete({ url: `/iot/plugin-config/delete?id=` + id })
|
||||
},
|
||||
|
||||
// 修改插件状态
|
||||
updatePluginStatus: async (data: any) => {
|
||||
return await request.put({ url: `/iot/plugin-config/update-status`, data })
|
||||
}
|
||||
}
|
||||
@ -733,17 +733,6 @@ const remainingRouter: AppRouteRecordRaw[] = [
|
||||
activeMenu: '/iot/device/device'
|
||||
},
|
||||
component: () => import('@/views/iot/device/device/detail/index.vue')
|
||||
},
|
||||
{
|
||||
path: 'plugin/detail/:id',
|
||||
name: 'IoTPluginDetail',
|
||||
meta: {
|
||||
title: '插件详情',
|
||||
noCache: true,
|
||||
hidden: true,
|
||||
activeMenu: '/iot/plugin'
|
||||
},
|
||||
component: () => import('@/views/iot/plugin/detail/index.vue')
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,166 +0,0 @@
|
||||
<!-- 设备日志 -->
|
||||
<template>
|
||||
<ContentWrap>
|
||||
<!-- 搜索区域 -->
|
||||
<el-form :model="queryParams" inline>
|
||||
<el-form-item>
|
||||
<el-select v-model="queryParams.type" placeholder="所有" class="!w-160px">
|
||||
<el-option label="所有" value="" />
|
||||
<!-- TODO @super:搞成枚举 -->
|
||||
<el-option label="状态" value="state" />
|
||||
<el-option label="事件" value="event" />
|
||||
<el-option label="属性" value="property" />
|
||||
<el-option label="服务" value="service" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-input v-model="queryParams.identifier" placeholder="日志识符" class="!w-200px" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">
|
||||
<Icon icon="ep:search" class="mr-5px" /> 搜索
|
||||
</el-button>
|
||||
<el-switch
|
||||
size="large"
|
||||
width="80"
|
||||
v-model="autoRefresh"
|
||||
class="ml-20px"
|
||||
inline-prompt
|
||||
active-text="定时刷新"
|
||||
inactive-text="定时刷新"
|
||||
style="--el-switch-on-color: #13ce66"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 日志列表 -->
|
||||
<el-table v-loading="loading" :data="list" :stripe="true" class="whitespace-nowrap">
|
||||
<el-table-column label="时间" align="center" prop="ts" width="180">
|
||||
<template #default="scope">
|
||||
{{ formatDate(scope.row.ts) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="类型" align="center" prop="type" width="120" />
|
||||
<!-- TODO @super:标识符需要翻译 -->
|
||||
<el-table-column label="标识符" align="center" prop="identifier" width="120" />
|
||||
<el-table-column label="内容" align="center" prop="content" :show-overflow-tooltip="true" />
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="mt-10px flex justify-end">
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getLogList"
|
||||
/>
|
||||
</div>
|
||||
</ContentWrap>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DeviceApi } from '@/api/iot/device/device'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
|
||||
const props = defineProps<{
|
||||
deviceKey: string
|
||||
}>()
|
||||
|
||||
// 查询参数
|
||||
const queryParams = reactive({
|
||||
deviceKey: props.deviceKey,
|
||||
type: '',
|
||||
identifier: '',
|
||||
pageNo: 1,
|
||||
pageSize: 10
|
||||
})
|
||||
|
||||
// 列表数据
|
||||
const loading = ref(false)
|
||||
const total = ref(0)
|
||||
const list = ref([])
|
||||
const autoRefresh = ref(false)
|
||||
let timer: any = null // TODO @super:autoRefreshEnable,autoRefreshTimer;对应上
|
||||
|
||||
// 类型映射 TODO @super:需要删除么?
|
||||
const typeMap = {
|
||||
lifetime: '生命周期',
|
||||
state: '设备状态',
|
||||
property: '属性',
|
||||
event: '事件',
|
||||
service: '服务'
|
||||
}
|
||||
|
||||
/** 查询日志列表 */
|
||||
const getLogList = async () => {
|
||||
if (!props.deviceKey) return
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await DeviceApi.getDeviceLogPage(queryParams)
|
||||
total.value = data.total
|
||||
list.value = data.list
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取日志名称 */
|
||||
const getLogName = (log: any) => {
|
||||
const { type, identifier } = log
|
||||
let name = '未知'
|
||||
|
||||
if (type === 'property') {
|
||||
if (identifier === 'set_reply') name = '设置回复'
|
||||
else if (identifier === 'report') name = '上报'
|
||||
else if (identifier === 'set') name = '设置'
|
||||
} else if (type === 'state') {
|
||||
name = identifier === 'online' ? '上线' : '下线'
|
||||
} else if (type === 'lifetime') {
|
||||
name = identifier === 'register' ? '注册' : name
|
||||
}
|
||||
|
||||
return `${name}(${identifier})`
|
||||
}
|
||||
|
||||
/** 搜索操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getLogList()
|
||||
}
|
||||
|
||||
/** 监听自动刷新 */
|
||||
watch(autoRefresh, (newValue) => {
|
||||
if (newValue) {
|
||||
timer = setInterval(() => {
|
||||
getLogList()
|
||||
}, 5000)
|
||||
} else {
|
||||
clearInterval(timer)
|
||||
timer = null
|
||||
}
|
||||
})
|
||||
|
||||
/** 监听设备标识变化 */
|
||||
watch(
|
||||
() => props.deviceKey,
|
||||
(newValue) => {
|
||||
if (newValue) {
|
||||
handleQuery()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/** 组件卸载时清除定时器 */
|
||||
onBeforeUnmount(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
})
|
||||
|
||||
/** 初始化 */
|
||||
onMounted(() => {
|
||||
if (props.deviceKey) {
|
||||
getLogList()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
169
src/views/iot/device/device/detail/DeviceDetailsMessage.vue
Normal file
169
src/views/iot/device/device/detail/DeviceDetailsMessage.vue
Normal file
@ -0,0 +1,169 @@
|
||||
<!-- 设备消息列表 -->
|
||||
<template>
|
||||
<ContentWrap>
|
||||
<!-- 搜索区域 -->
|
||||
<el-form :model="queryParams" inline>
|
||||
<el-form-item>
|
||||
<el-select v-model="queryParams.method" placeholder="所有方法" class="!w-160px" clearable>
|
||||
<el-option v-for="item in methodOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-select v-model="queryParams.upstream" placeholder="上行/下行" class="!w-160px" clearable>
|
||||
<el-option label="上行" value="true" />
|
||||
<el-option label="下行" value="false" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleQuery">
|
||||
<Icon icon="ep:search" class="mr-5px" /> 搜索
|
||||
</el-button>
|
||||
<el-switch
|
||||
size="large"
|
||||
width="80"
|
||||
v-model="autoRefresh"
|
||||
class="ml-20px"
|
||||
inline-prompt
|
||||
active-text="定时刷新"
|
||||
inactive-text="定时刷新"
|
||||
style="--el-switch-on-color: #13ce66"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 消息列表 -->
|
||||
<el-table v-loading="loading" :data="list" :stripe="true" class="whitespace-nowrap">
|
||||
<el-table-column label="请求编号" align="center" prop="requestId" width="300" />
|
||||
<el-table-column label="时间" align="center" prop="ts" width="180">
|
||||
<template #default="scope">
|
||||
{{ formatDate(scope.row.ts) }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="上行/下行" align="center" prop="upstream" width="140">
|
||||
<template #default="scope">
|
||||
<el-tag :type="scope.row.upstream ? 'primary' : 'success'">
|
||||
{{ scope.row.upstream ? '上行' : '下行' }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="是否回复" align="center" prop="reply" width="140">
|
||||
<template #default="scope">
|
||||
<dict-tag :type="DICT_TYPE.INFRA_BOOLEAN_STRING" :value="scope.row.reply" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="请求方法" align="center" prop="method" width="140">
|
||||
<template #default="scope">
|
||||
{{ methodOptions.find(item => item.value === scope.row.method)?.label }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="请求/响应数据" align="center" prop="params" :show-overflow-tooltip="true">
|
||||
<template #default="scope">
|
||||
<span v-if="scope.row.reply">
|
||||
{{ `{"code":${scope.row.code},"msg":"${scope.row.msg}","data":${scope.row.data}\}` }}
|
||||
</span>
|
||||
<span v-else>{{ scope.row.params }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="mt-10px flex justify-end">
|
||||
<Pagination
|
||||
:total="total"
|
||||
v-model:page="queryParams.pageNo"
|
||||
v-model:limit="queryParams.pageSize"
|
||||
@pagination="getMessageList"
|
||||
/>
|
||||
</div>
|
||||
</ContentWrap>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
import { DeviceApi } from '@/api/iot/device/device'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
import { IotDeviceMessageMethodEnum } from '@/views/iot/utils/constants'
|
||||
|
||||
const props = defineProps<{
|
||||
deviceId: number
|
||||
}>()
|
||||
|
||||
// 查询参数
|
||||
const queryParams = reactive({
|
||||
deviceId: props.deviceId,
|
||||
method: undefined,
|
||||
upstream: undefined,
|
||||
pageNo: 1,
|
||||
pageSize: 10
|
||||
})
|
||||
|
||||
// 列表数据
|
||||
const loading = ref(false)
|
||||
const total = ref(0)
|
||||
const list = ref([])
|
||||
const autoRefresh = ref(false)
|
||||
let autoRefreshTimer: any = null // TODO @super:autoRefreshEnable,autoRefreshTimer;对应上
|
||||
|
||||
// 消息方法选项
|
||||
const methodOptions = computed(() => {
|
||||
return Object.values(IotDeviceMessageMethodEnum).map(item => ({
|
||||
label: item.name,
|
||||
value: item.method
|
||||
}))
|
||||
})
|
||||
|
||||
/** 查询消息列表 */
|
||||
const getMessageList = async () => {
|
||||
if (!props.deviceId) return
|
||||
loading.value = true
|
||||
try {
|
||||
const data = await DeviceApi.getDeviceMessagePage(queryParams)
|
||||
total.value = data.total
|
||||
list.value = data.list
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
/** 搜索操作 */
|
||||
const handleQuery = () => {
|
||||
queryParams.pageNo = 1
|
||||
getMessageList()
|
||||
}
|
||||
|
||||
/** 监听自动刷新 */
|
||||
watch(autoRefresh, (newValue) => {
|
||||
if (newValue) {
|
||||
autoRefreshTimer = setInterval(() => {
|
||||
getMessageList()
|
||||
}, 5000)
|
||||
} else {
|
||||
clearInterval(autoRefreshTimer)
|
||||
autoRefreshTimer = null
|
||||
}
|
||||
})
|
||||
|
||||
/** 监听设备标识变化 */
|
||||
watch(
|
||||
() => props.deviceId,
|
||||
(newValue) => {
|
||||
if (newValue) {
|
||||
handleQuery()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
/** 组件卸载时清除定时器 */
|
||||
onBeforeUnmount(() => {
|
||||
if (autoRefreshTimer) {
|
||||
clearInterval(autoRefreshTimer)
|
||||
}
|
||||
})
|
||||
|
||||
/** 初始化 */
|
||||
onMounted(() => {
|
||||
if (props.deviceId) {
|
||||
getMessageList()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@ -134,7 +134,7 @@
|
||||
<el-col :span="12">
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane label="设备日志">
|
||||
<DeviceDetailsLog :device-key="device.deviceKey" />
|
||||
<DeviceDetailsMessage :device-id="device.id" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-col>
|
||||
@ -146,7 +146,7 @@
|
||||
import { ProductVO } from '@/api/iot/product/product'
|
||||
import { SimulatorData, ThingModelApi } from '@/api/iot/thingmodel'
|
||||
import { DeviceApi, DeviceStateEnum, DeviceVO } from '@/api/iot/device/device'
|
||||
import DeviceDetailsLog from './DeviceDetailsLog.vue'
|
||||
import DeviceDetailsMessage from './DeviceDetailsMessage.vue'
|
||||
import { getDataTypeOptionsLabel } from '@/views/iot/thingmodel/config'
|
||||
import { DataDefinition } from '@/views/iot/thingmodel/components'
|
||||
|
||||
|
||||
@ -10,14 +10,12 @@
|
||||
<el-tab-pane label="设备信息" name="info">
|
||||
<DeviceDetailsInfo v-if="activeTab === 'info'" :product="product" :device="device" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="Topic 列表" />
|
||||
<el-tab-pane label="物模型数据" name="model">
|
||||
<DeviceDetailsModel v-if="activeTab === 'model'" :product="product" :device="device" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="子设备管理" v-if="product.deviceType === DeviceTypeEnum.GATEWAY" />
|
||||
<el-tab-pane label="设备影子" />
|
||||
<el-tab-pane label="设备日志" name="log">
|
||||
<DeviceDetailsLog v-if="activeTab === 'log'" :device-key="device.deviceKey" />
|
||||
<el-tab-pane label="设备消息" name="log">
|
||||
<DeviceDetailsMessage v-if="activeTab === 'log'" :device-id="device.id" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="模拟设备" name="simulator">
|
||||
<DeviceDetailsSimulator
|
||||
@ -43,7 +41,7 @@ import { DeviceTypeEnum, ProductApi, ProductVO } from '@/api/iot/product/product
|
||||
import DeviceDetailsHeader from './DeviceDetailsHeader.vue'
|
||||
import DeviceDetailsInfo from './DeviceDetailsInfo.vue'
|
||||
import DeviceDetailsModel from './DeviceDetailsModel.vue'
|
||||
import DeviceDetailsLog from './DeviceDetailsLog.vue'
|
||||
import DeviceDetailsMessage from './DeviceDetailsMessage.vue'
|
||||
import DeviceDetailsSimulator from './DeviceDetailsSimulator.vue'
|
||||
import DeviceDetailConfig from './DeviceDetailConfig.vue'
|
||||
|
||||
@ -75,7 +73,8 @@ const getProductData = async (id: number) => {
|
||||
|
||||
/** 初始化 */
|
||||
const { delView } = useTagsViewStore() // 视图操作
|
||||
const { currentRoute } = useRouter() // 路由
|
||||
const router = useRouter() // 路由
|
||||
const { currentRoute } = router
|
||||
onMounted(async () => {
|
||||
if (!id) {
|
||||
message.warning('参数错误,产品不能为空!')
|
||||
|
||||
@ -2,3 +2,39 @@
|
||||
export const IOT_PROVIDE_KEY = {
|
||||
PRODUCT: 'IOT_PRODUCT'
|
||||
}
|
||||
|
||||
/**
|
||||
* IoT 设备消息的方法枚举
|
||||
*/
|
||||
export const IotDeviceMessageMethodEnum = {
|
||||
// ========== 设备状态 ==========
|
||||
STATE_ONLINE: {
|
||||
method: 'thing.state.online',
|
||||
name: '设备上线',
|
||||
upstream: true
|
||||
},
|
||||
STATE_OFFLINE: {
|
||||
method: 'thing.state.offline',
|
||||
name: '设备下线',
|
||||
upstream: true
|
||||
},
|
||||
|
||||
// ========== 设备属性 ==========
|
||||
PROPERTY_POST: {
|
||||
method: 'thing.property.post',
|
||||
name: '属性上报',
|
||||
upstream: true
|
||||
},
|
||||
PROPERTY_SET: {
|
||||
method: 'thing.property.set',
|
||||
name: '属性设置',
|
||||
upstream: false
|
||||
},
|
||||
|
||||
// ========== 设备事件 ==========
|
||||
EVENT_POST: {
|
||||
method: 'thing.event.post',
|
||||
name: '事件上报',
|
||||
upstream: true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user