feat:deviceLog and deviceSimulator

This commit is contained in:
alwayssuper 2025-01-06 16:39:22 +08:00
parent b71fa84af3
commit c9e00d97eb
6 changed files with 143 additions and 142 deletions

View File

@ -87,7 +87,7 @@
"source.fixAll.stylelint": "explicit"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
"editor.defaultFormatter": "octref.vetur"
},
"i18n-ally.localesPaths": ["src/locales"],
"i18n-ally.keystyle": "nested",

View File

@ -69,7 +69,7 @@ export interface SimulatorDataVO {
deviceKey: string
type: string
subType: string
reportTime: string
reportTime: number // 时间戳
content: string // 存储 JSON 字符串
}
@ -151,5 +151,9 @@ export const DeviceApi = {
// 模拟设备
simulatorDevice: async (data: SimulatorDataVO) => {
return await request.post({ url: `/iot/device/data/simulator`, data })
},
//查询设备日志分页
getDeviceLogPage: async (params: any) => {
return await request.get({ url: `/iot/device/data/log/page`, params })
}
}

View File

@ -17,6 +17,13 @@ export interface ThingModelData {
service?: ThingModelService // 服务
}
/**
* IoT
*/
export interface SimulatorData extends ThingModelData {
simulateValue?: string | number // 用于存储模拟值
}
/**
* ThingModelProperty
*/

View File

@ -29,27 +29,18 @@
{{ formatDate(scope.row.time) }}
</template>
</el-table-column>
<el-table-column label="类型" align="center" prop="type" width="120">
<template #default="scope">
<dict-tag :type="DICT_TYPE.IOT_MESSAGE_TYPE" :value="scope.row.type" />
</template>
</el-table-column>
<el-table-column label="名称(标识符)" align="center" prop="name" />
<el-table-column label="类型" align="center" prop="type" width="120" />
<el-table-column label="名称(标识符)" align="center" prop="subType" width="120" />
<el-table-column label="内容" align="center" prop="content" :show-overflow-tooltip="true" />
</el-table>
<!-- 分页 -->
<div class="mt-10px flex justify-end">
<el-pagination
v-model:current-page="queryParams.pageNo"
v-model:page-size="queryParams.pageSize"
<Pagination
:total="total"
:page-sizes="[10, 20, 50, 100]"
small
background
layout="total, sizes, prev, pager, next, jumper"
@size-change="handleQuery"
@current-change="handleQuery"
v-model:page="queryParams.pageNo"
v-model:limit="queryParams.pageSize"
@pagination="getLogList"
/>
</div>
</ContentWrap>
@ -61,15 +52,17 @@ import { DICT_TYPE } from '@/utils/dict'
import { formatDate } from '@/utils/formatTime'
const props = defineProps<{
deviceId: number
deviceKey: number
}>()
//
//TODO:使 type subType
//
const queryParams = reactive({
type: '',
keyword: '',
deviceKey: props.deviceKey,
// type: '',
// keyword: '',
pageNo: 1,
pageSize: 20
pageSize: 10
})
//
@ -90,30 +83,31 @@ const typeMap = {
/** 查询日志列表 */
const getLogList = async () => {
// if (!props.deviceId) return
// loading.value = true
// try {
// const res = await DeviceApi.getDeviceLogs(props.deviceId, queryParams)
// total.value = res.total
// logList.value = res.list.map((item: any) => {
// const log = {
// time: item.time,
// type: typeMap[item.type as keyof typeof typeMap] || item.type,
// name: getLogName(item),
// content: item.content
// }
// return log
// })
// } finally {
// loading.value = false
// }
if (!props.deviceKey) return
loading.value = true
try {
const res = await DeviceApi.getDeviceLogPage(queryParams)
total.value = res.total
logList.value = res.list.map((item: any) => {
const log = {
time: item.reportTime,
type: item.type,
subType: item.subType,
content: item.content
}
return log
})
console.log(logList.value)
} 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 = '上报'
@ -123,7 +117,7 @@ const getLogName = (log: any) => {
} else if (type === 'lifetime') {
name = identifier === 'register' ? '注册' : name
}
return `${name}(${identifier})`
}
@ -146,11 +140,14 @@ watch(autoRefresh, (newValue) => {
})
/** 监听设备ID变化 */
watch(() => props.deviceId, (newValue) => {
if (newValue) {
handleQuery()
watch(
() => props.deviceKey,
(newValue) => {
if (newValue) {
handleQuery()
}
}
})
)
/** 组件卸载时清除定时器 */
onBeforeUnmount(() => {
@ -161,7 +158,7 @@ onBeforeUnmount(() => {
/** 初始化 */
onMounted(() => {
if (props.deviceId) {
if (props.deviceKey) {
getLogList()
}
})

View File

@ -97,7 +97,7 @@
<!-- 事件上报 -->
<el-tab-pane label="事件上报" name="event">
<ContentWrap>
<el-table v-loading="loading" :data="eventList" :stripe="true">
<!-- <el-table v-loading="loading" :data="eventList" :stripe="true">
<el-table-column label="功能名称" align="center" prop="name" />
<el-table-column label="标识符" align="center" prop="identifier" />
<el-table-column label="数据类型" align="center" prop="dataType" />
@ -115,7 +115,7 @@
</el-table>
<div class="mt-10px">
<el-button type="primary" @click="handleEventReport">发送</el-button>
</div>
</div> -->
</ContentWrap>
</el-tab-pane>
@ -141,7 +141,7 @@
<!-- 属性调试 -->
<el-tab-pane label="属性调试" name="propertyDebug">
<ContentWrap>
<el-table v-loading="loading" :data="propertyList" :stripe="true">
<!-- <el-table v-loading="loading" :data="propertyList" :stripe="true">
<el-table-column label="功能名称" align="center" prop="name" />
<el-table-column label="标识符" align="center" prop="identifier" />
<el-table-column label="数据类型" align="center" prop="dataType" />
@ -159,7 +159,7 @@
</el-table>
<div class="mt-10px">
<el-button type="primary" @click="handlePropertyGet">获取</el-button>
</div>
</div> -->
</ContentWrap>
</el-tab-pane>
@ -178,7 +178,7 @@
<el-col :span="12">
<el-tabs type="border-card">
<el-tab-pane label="设备日志">
<DeviceDetailsLog :device-id="device.id" />
<DeviceDetailsLog :deviceKey="device.deviceKey" />
</el-tab-pane>
</el-tabs>
</el-col>
@ -188,7 +188,7 @@
<script setup lang="ts">
import { ProductVO } from '@/api/iot/product/product'
import { ThingModelApi, ThingModelData } from '@/api/iot/thingmodel'
import { ThingModelApi, ThingModelData,SimulatorData } from '@/api/iot/thingmodel'
import { DeviceApi, DeviceVO,SimulatorDataVO } from '@/api/iot/device/device'
import DeviceDetailsLog from './DeviceDetailsLog.vue'
import {
@ -212,9 +212,6 @@ const dataTypeOptionsLabel = computed(() => (value: string) => getDataTypeOption
const props = defineProps<{ product: ProductVO; device: DeviceVO }>()
const list = ref<SimulatorData[]>([]) //
interface SimulatorData extends ThingModelData {
simulateValue?: string | number //
}
/** 查询列表 */
const getList = async () => {
loading.value = true
@ -231,33 +228,33 @@ const getList = async () => {
}
}
//
interface TableItem {
name: string
identifier: string
value: string | number
}
// //
// interface TableItem {
// name: string
// identifier: string
// value: string | number
// }
//
const propertyList = computed(() => {
return list.value
.filter((item) => item.type === 'property')
.map((item) => ({
name: item.name,
identifier: item.identifier,
value: ''
}))
})
// //
// const propertyList = computed(() => {
// return list.value
// .filter((item) => item.type === 'property')
// .map((item) => ({
// name: item.name,
// identifier: item.identifier,
// value: ''
// }))
// })
const eventList = computed(() => {
return list.value
.filter((item) => item.type === 'event')
.map((item) => ({
name: item.name,
identifier: item.identifier,
value: ''
}))
})
// const eventList = computed(() => {
// return list.value
// .filter((item) => item.type === 'event')
// .map((item) => ({
// name: item.name,
// identifier: item.identifier,
// value: ''
// }))
// })
// todo:
watch(
@ -291,16 +288,16 @@ watch(
{ immediate: true }
)
interface ReportData {
productKey: string
deviceKey: string
type: string
subType: string
reportTime: string
content: string // string JSON
}
// interface ReportData {
// productKey: string
// deviceKey: string
// type: string
// subType: string
// reportTime: string
// content: string // string JSON
// }
//
// TODO:
const handlePropertyReport = async () => {
const contentObj: Record<string, any> = {}
list.value.forEach((item) => {
@ -315,71 +312,67 @@ const handlePropertyReport = async () => {
deviceKey: props.device.deviceKey,
type: 'property',
subType: 'report',
reportTime: new Date().toISOString(),
reportTime: Date.now(), // reportTime
content: JSON.stringify(contentObj) // JSON
}
try {
// TODO: API
console.log('上报数据:', reportData)
console.log('reportData.content', reportData.content)
const data = await DeviceApi.simulatorDevice(reportData)
console.log(data)
message.success('属性上报成功123')
await DeviceApi.simulatorDevice(reportData)
message.success('属性上报成功')
} catch (error) {
message.error('属性上报失败')
}
}
//
const handleEventReport = async () => {
const contentObj: Record<string, any> = {}
list.value
.filter(item => item.type === 'event')
.forEach((item) => {
if (item.simulateValue !== undefined && item.simulateValue !== '') {
contentObj[item.identifier] = item.simulateValue
}
})
// //
// const handleEventReport = async () => {
// const contentObj: Record<string, any> = {}
// list.value
// .filter(item => item.type === 'event')
// .forEach((item) => {
// if (item.simulateValue !== undefined && item.simulateValue !== '') {
// contentObj[item.identifier] = item.simulateValue
// }
// })
const reportData: ReportData = {
productKey: props.product.productKey,
deviceKey: props.device.deviceKey,
type: 'event',
subType: list.value.find(item => item.type === 'event')?.identifier || '',
reportTime: new Date().toISOString(),
content: JSON.stringify(contentObj) // JSON
}
// const reportData: ReportData = {
// productKey: props.product.productKey,
// deviceKey: props.device.deviceKey,
// type: 'event',
// subType: list.value.find(item => item.type === 'event')?.identifier || '',
// reportTime: new Date().toISOString(),
// content: JSON.stringify(contentObj) // JSON
// }
try {
// TODO: API
console.log('上报数据:', reportData)
message.success('事件上报成功')
} catch (error) {
message.error('事件上报失败')
}
}
// try {
// // TODO: API
// console.log(':', reportData)
// message.success('')
// } catch (error) {
// message.error('')
// }
// }
//
const handleDeviceState = async (state: 'online' | 'offline') => {
const reportData: ReportData = {
productKey: props.product.productKey,
deviceKey: props.device.deviceKey,
type: 'status',
subType: state,
reportTime: new Date().toISOString(),
content: JSON.stringify({ status: state }) // JSON
}
// //
// const handleDeviceState = async (state: 'online' | 'offline') => {
// const reportData: ReportData = {
// productKey: props.product.productKey,
// deviceKey: props.device.deviceKey,
// type: 'status',
// subType: state,
// reportTime: new Date().toISOString(),
// content: JSON.stringify({ status: state }) // JSON
// }
try {
// TODO: API
console.log('状态变更数据:', reportData)
console.log('reportData.content111111111', reportData.content)
message.success(`设备${state === 'online' ? '上线' : '下线'}成功`)
} catch (error) {
message.error(`设备${state === 'online' ? '上线' : '下线'}失败`)
}
}
// try {
// // TODO: API
// console.log(':', reportData)
// console.log('reportData.content111111111', reportData.content)
// message.success(`${state === 'online' ? '线' : '线'}`)
// } catch (error) {
// message.error(`${state === 'online' ? '线' : '线'}`)
// }
// }
//
const handlePropertyGet = async () => {

View File

@ -17,7 +17,7 @@
<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'" :product="product" :device="device" />
<DeviceDetailsLog v-if="activeTab === 'log'" :deviceKey="device.deviceKey" />
</el-tab-pane>
<el-tab-pane label="模拟设备" name="simulator">
<DeviceDetailsSimulator v-if="activeTab === 'simulator'" :product="product" :device="device" />