mirror of
https://gitee.com/myxzgzs/boyue-ui-admin-vue3
synced 2025-08-08 16:32:43 +08:00
feat:DeviceDetailsLog DeviceDetailsSimulator
This commit is contained in:
parent
77e0a76389
commit
61ebe5b9a2
12621
pnpm-lock.yaml
generated
12621
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
168
src/views/iot/device/device/detail/DeviceDetailsLog.vue
Normal file
168
src/views/iot/device/device/detail/DeviceDetailsLog.vue
Normal file
@ -0,0 +1,168 @@
|
||||
<template>
|
||||
<ContentWrap>
|
||||
<!-- 搜索区域 -->
|
||||
<el-form :model="queryParams" inline>
|
||||
<el-form-item>
|
||||
<el-select v-model="queryParams.type" placeholder="所有" class="!w-120px">
|
||||
<el-option label="所有" value="" />
|
||||
<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.keyword" 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 v-model="autoRefresh" class="ml-10px" /> 定时刷新
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<!-- 日志列表 -->
|
||||
<el-table v-loading="loading" :data="logList" :stripe="true" class="whitespace-nowrap">
|
||||
<el-table-column label="时间" align="center" prop="time" width="180">
|
||||
<template #default="scope">
|
||||
{{ 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="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"
|
||||
:total="total"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
small
|
||||
background
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleQuery"
|
||||
@current-change="handleQuery"
|
||||
/>
|
||||
</div>
|
||||
</ContentWrap>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { DeviceApi } from '@/api/iot/device/device'
|
||||
import { DICT_TYPE } from '@/utils/dict'
|
||||
import { formatDate } from '@/utils/formatTime'
|
||||
|
||||
const props = defineProps<{
|
||||
deviceId: number
|
||||
}>()
|
||||
|
||||
// 查询参数
|
||||
const queryParams = reactive({
|
||||
type: '',
|
||||
keyword: '',
|
||||
pageNo: 1,
|
||||
pageSize: 20
|
||||
})
|
||||
|
||||
// 列表数据
|
||||
const loading = ref(false)
|
||||
const total = ref(0)
|
||||
const logList = ref([])
|
||||
const autoRefresh = ref(false)
|
||||
let timer: any = null
|
||||
|
||||
// 类型映射
|
||||
const typeMap = {
|
||||
lifetime: '生命周期',
|
||||
state: '设备状态',
|
||||
property: '属性',
|
||||
event: '事件',
|
||||
service: '服务'
|
||||
}
|
||||
|
||||
/** 查询日志列表 */
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
/** 获取日志名称 */
|
||||
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
|
||||
}
|
||||
})
|
||||
|
||||
/** 监听设备ID变化 */
|
||||
watch(() => props.deviceId, (newValue) => {
|
||||
if (newValue) {
|
||||
handleQuery()
|
||||
}
|
||||
})
|
||||
|
||||
/** 组件卸载时清除定时器 */
|
||||
onBeforeUnmount(() => {
|
||||
if (timer) {
|
||||
clearInterval(timer)
|
||||
}
|
||||
})
|
||||
|
||||
/** 初始化 */
|
||||
onMounted(() => {
|
||||
if (props.deviceId) {
|
||||
getLogList()
|
||||
}
|
||||
})
|
||||
</script>
|
192
src/views/iot/device/device/detail/DeviceDetailsSimulator.vue
Normal file
192
src/views/iot/device/device/detail/DeviceDetailsSimulator.vue
Normal file
@ -0,0 +1,192 @@
|
||||
<template>
|
||||
<ContentWrap>
|
||||
<el-row :gutter="20">
|
||||
<!-- 左侧指令调试区域 -->
|
||||
<el-col :span="12">
|
||||
<el-tabs v-model="activeTab" type="border-card">
|
||||
<!-- 上行指令调试 -->
|
||||
<el-tab-pane label="上行指令调试" name="up">
|
||||
<el-tabs v-model="subTab" v-if="activeTab === 'up'">
|
||||
<!-- 属性上报 -->
|
||||
<el-tab-pane label="属性上报" name="property">
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="propertyList" :stripe="true">
|
||||
<el-table-column label="值" align="center" width="80">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.value" class="!w-60px" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="功能名称" align="center" prop="name" />
|
||||
<el-table-column label="标识符" align="center" prop="identifier" />
|
||||
<el-table-column label="数据类型" align="center" prop="dataType" />
|
||||
<el-table-column label="数据定义" align="center" prop="specs" :show-overflow-tooltip="true" />
|
||||
</el-table>
|
||||
<div class="mt-10px">
|
||||
<el-button type="primary" @click="handlePropertyReport">发送</el-button>
|
||||
</div>
|
||||
</ContentWrap>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 事件上报 -->
|
||||
<el-tab-pane label="事件上报" name="event">
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="eventList" :stripe="true">
|
||||
<el-table-column label="值" align="center" width="80">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.value" class="!w-60px" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="功能名称" align="center" prop="name" />
|
||||
<el-table-column label="标识符" align="center" prop="identifier" />
|
||||
<el-table-column label="数据类型" align="center" prop="dataType" />
|
||||
<el-table-column label="数据定义" align="center" prop="specs" :show-overflow-tooltip="true" />
|
||||
</el-table>
|
||||
<div class="mt-10px">
|
||||
<el-button type="primary" @click="handleEventReport">发送</el-button>
|
||||
</div>
|
||||
</ContentWrap>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 状态变更 -->
|
||||
<el-tab-pane label="状态变更" name="status">
|
||||
<ContentWrap>
|
||||
<div class="flex gap-4">
|
||||
<el-button type="primary" @click="handleDeviceState('online')">设备上线</el-button>
|
||||
<el-button type="primary" @click="handleDeviceState('offline')">设备下线</el-button>
|
||||
</div>
|
||||
</ContentWrap>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 下行指令调试 -->
|
||||
<el-tab-pane label="下行指令调试" name="down">
|
||||
<el-tabs v-model="subTab" v-if="activeTab === 'down'">
|
||||
<!-- 属性调试 -->
|
||||
<el-tab-pane label="属性调试" name="propertyDebug">
|
||||
<ContentWrap>
|
||||
<el-table v-loading="loading" :data="propertyList" :stripe="true">
|
||||
<el-table-column label="值" align="center" width="80">
|
||||
<template #default="scope">
|
||||
<el-input v-model="scope.row.value" class="!w-60px" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="功能名称" align="center" prop="name" />
|
||||
<el-table-column label="标识符" align="center" prop="identifier" />
|
||||
<el-table-column label="数据类型" align="center" prop="dataType" />
|
||||
<el-table-column label="数据定义" align="center" prop="specs" :show-overflow-tooltip="true" />
|
||||
</el-table>
|
||||
<div class="mt-10px">
|
||||
<el-button type="primary" @click="handlePropertyGet">获取</el-button>
|
||||
</div>
|
||||
</ContentWrap>
|
||||
</el-tab-pane>
|
||||
|
||||
<!-- 服务调用 -->
|
||||
<el-tab-pane label="服务调用" name="service">
|
||||
<ContentWrap>
|
||||
<!-- 服务调用相关内容 -->
|
||||
</ContentWrap>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-col>
|
||||
|
||||
<!-- 右侧设备日志区域 -->
|
||||
<el-col :span="12">
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane label="设备日志">
|
||||
<DeviceDetailsLog :device-id="device.id" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</ContentWrap>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ProductVO } from '@/api/iot/product/product'
|
||||
import { DeviceApi, DeviceVO } from '@/api/iot/device/device'
|
||||
import DeviceDetailsLog from './DeviceDetailsLog.vue'
|
||||
|
||||
const message = useMessage() // 消息弹窗
|
||||
const loading = ref(false)
|
||||
const activeTab = ref('up')
|
||||
const subTab = ref('property')
|
||||
|
||||
const props = defineProps<{ product: ProductVO; device: DeviceVO }>()
|
||||
|
||||
// 功能列表数据结构定义
|
||||
interface TableItem {
|
||||
name: string
|
||||
identifier: string
|
||||
dataType: string
|
||||
specs: string
|
||||
value: string | number
|
||||
}
|
||||
|
||||
// 属性列表数据
|
||||
const propertyList = ref<TableItem[]>([
|
||||
{
|
||||
name: '电量',
|
||||
identifier: 'power',
|
||||
dataType: 'int32',
|
||||
specs: '',
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
name: '设备型号',
|
||||
identifier: 'DeviceType',
|
||||
dataType: 'text',
|
||||
specs: '{ "length": "128" }',
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
name: '信号强度',
|
||||
identifier: 'rssi',
|
||||
dataType: 'int32',
|
||||
specs: '{ "min": "-127", "max": "127" }',
|
||||
value: ''
|
||||
},
|
||||
{
|
||||
name: '门状态',
|
||||
identifier: 'doorStatus',
|
||||
dataType: 'enum',
|
||||
specs: '{ "0": "关", "1": "开" }',
|
||||
value: ''
|
||||
}
|
||||
])
|
||||
|
||||
// 事件列表数据
|
||||
const eventList = ref<TableItem[]>([])
|
||||
|
||||
// 处理属性上报
|
||||
const handlePropertyReport = async () => {
|
||||
// TODO: 实现属性上报逻辑
|
||||
message.success('属性上报成功')
|
||||
}
|
||||
|
||||
// 处理事件上报
|
||||
const handleEventReport = async () => {
|
||||
// TODO: 实现事件上报逻辑
|
||||
message.success('事件上报成功')
|
||||
}
|
||||
|
||||
// 处理设备状态变更
|
||||
const handleDeviceState = async (state: 'online' | 'offline') => {
|
||||
// TODO: 实现设备状态变更逻辑
|
||||
message.success(`设备${state === 'online' ? '上线' : '下线'}成功`)
|
||||
}
|
||||
|
||||
// 处理属性获取
|
||||
const handlePropertyGet = async () => {
|
||||
// TODO: 实现属性获取逻辑
|
||||
message.success('属性获取成功')
|
||||
}
|
||||
|
||||
// 初始化
|
||||
onMounted(() => {
|
||||
// TODO: 获取初始数据
|
||||
})
|
||||
</script>
|
@ -16,6 +16,12 @@
|
||||
</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'" :product="product" :device="device" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="模拟设备" name="simulator">
|
||||
<DeviceDetailsSimulator v-if="activeTab === 'simulator'" :product="product" :device="device" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-col>
|
||||
</template>
|
||||
@ -26,7 +32,8 @@ 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 DeviceDetailsSimulator from './DeviceDetailsSimulator.vue'
|
||||
defineOptions({ name: 'IoTDeviceDetail' })
|
||||
|
||||
const route = useRoute()
|
||||
|
Loading…
x
Reference in New Issue
Block a user