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" "source.fixAll.stylelint": "explicit"
}, },
"[vue]": { "[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode" "editor.defaultFormatter": "octref.vetur"
}, },
"i18n-ally.localesPaths": ["src/locales"], "i18n-ally.localesPaths": ["src/locales"],
"i18n-ally.keystyle": "nested", "i18n-ally.keystyle": "nested",

View File

@ -69,7 +69,7 @@ export interface SimulatorDataVO {
deviceKey: string deviceKey: string
type: string type: string
subType: string subType: string
reportTime: string reportTime: number // 时间戳
content: string // 存储 JSON 字符串 content: string // 存储 JSON 字符串
} }
@ -151,5 +151,9 @@ export const DeviceApi = {
// 模拟设备 // 模拟设备
simulatorDevice: async (data: SimulatorDataVO) => { simulatorDevice: async (data: SimulatorDataVO) => {
return await request.post({ url: `/iot/device/data/simulator`, data }) 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 // 服务 service?: ThingModelService // 服务
} }
/**
* IoT
*/
export interface SimulatorData extends ThingModelData {
simulateValue?: string | number // 用于存储模拟值
}
/** /**
* ThingModelProperty * ThingModelProperty
*/ */

View File

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

View File

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

View File

@ -17,7 +17,7 @@
<el-tab-pane label="子设备管理" v-if="product.deviceType === DeviceTypeEnum.GATEWAY" /> <el-tab-pane label="子设备管理" v-if="product.deviceType === DeviceTypeEnum.GATEWAY" />
<el-tab-pane label="设备影子" /> <el-tab-pane label="设备影子" />
<el-tab-pane label="设备日志" name="log"> <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>
<el-tab-pane label="模拟设备" name="simulator"> <el-tab-pane label="模拟设备" name="simulator">
<DeviceDetailsSimulator v-if="activeTab === 'simulator'" :product="product" :device="device" /> <DeviceDetailsSimulator v-if="activeTab === 'simulator'" :product="product" :device="device" />