mirror of
https://gitee.com/myxzgzs/boyue-ui-admin-vue3
synced 2025-08-08 16:32:43 +08:00
Merge branch 'feature/iot' of https://gitee.com/alwayssuper/yudao-ui-admin-vue3 into feature/iot
# Conflicts: # pnpm-lock.yaml
This commit is contained in:
commit
f2f414a965
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -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",
|
||||||
|
@ -63,6 +63,16 @@ export enum DeviceStatusEnum {
|
|||||||
DISABLED = 3 // 已禁用
|
DISABLED = 3 // 已禁用
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IoT 模拟设备数据
|
||||||
|
export interface SimulatorDataVO {
|
||||||
|
productKey: string
|
||||||
|
deviceKey: string
|
||||||
|
type: string
|
||||||
|
subType: string
|
||||||
|
reportTime: number // 时间戳
|
||||||
|
content: string // 存储 JSON 字符串
|
||||||
|
}
|
||||||
|
|
||||||
// 设备 API
|
// 设备 API
|
||||||
export const DeviceApi = {
|
export const DeviceApi = {
|
||||||
// 查询设备分页
|
// 查询设备分页
|
||||||
@ -136,5 +146,14 @@ export const DeviceApi = {
|
|||||||
// 获取导入模板
|
// 获取导入模板
|
||||||
importDeviceTemplate: async () => {
|
importDeviceTemplate: async () => {
|
||||||
return await request.download({ url: `/iot/device/get-import-template` })
|
return await request.download({ url: `/iot/device/get-import-template` })
|
||||||
|
},
|
||||||
|
|
||||||
|
// 模拟设备
|
||||||
|
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 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,13 @@ export interface ThingModelData {
|
|||||||
service?: ThingModelService // 服务
|
service?: ThingModelService // 服务
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IoT 模拟设备
|
||||||
|
*/
|
||||||
|
export interface SimulatorData extends ThingModelData {
|
||||||
|
simulateValue?: string | number // 用于存储模拟值
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ThingModelProperty 类型
|
* ThingModelProperty 类型
|
||||||
*/
|
*/
|
||||||
@ -45,6 +52,11 @@ export const ThingModelApi = {
|
|||||||
return await request.get({ url: `/iot/thing-model/page`, params })
|
return await request.get({ url: `/iot/thing-model/page`, params })
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 获得产品物模型列表
|
||||||
|
getThingModelList: async (params: any) => {
|
||||||
|
return await request.get({ url: `/iot/thing-model/list`, params })
|
||||||
|
},
|
||||||
|
|
||||||
// 获得产品物模型
|
// 获得产品物模型
|
||||||
getThingModelListByProductId: async (params: any) => {
|
getThingModelListByProductId: async (params: any) => {
|
||||||
return await request.get({
|
return await request.get({
|
||||||
|
164
src/views/iot/device/device/detail/DeviceDetailsLog.vue
Normal file
164
src/views/iot/device/device/detail/DeviceDetailsLog.vue
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
<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" />
|
||||||
|
<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">
|
||||||
|
<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 { DICT_TYPE } from '@/utils/dict'
|
||||||
|
import { formatDate } from '@/utils/formatTime'
|
||||||
|
|
||||||
|
const props = defineProps<{
|
||||||
|
deviceKey: number
|
||||||
|
}>()
|
||||||
|
|
||||||
|
//TODO:后续看看使用什么查询条件 目前后端是留了时间范围 type subType
|
||||||
|
// 查询参数
|
||||||
|
const queryParams = reactive({
|
||||||
|
deviceKey: props.deviceKey,
|
||||||
|
// type: '',
|
||||||
|
// keyword: '',
|
||||||
|
pageNo: 1,
|
||||||
|
pageSize: 10
|
||||||
|
})
|
||||||
|
|
||||||
|
// 列表数据
|
||||||
|
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.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
|
||||||
|
})
|
||||||
|
} 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.deviceKey,
|
||||||
|
(newValue) => {
|
||||||
|
if (newValue) {
|
||||||
|
handleQuery()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
/** 组件卸载时清除定时器 */
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (timer) {
|
||||||
|
clearInterval(timer)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/** 初始化 */
|
||||||
|
onMounted(() => {
|
||||||
|
if (props.deviceKey) {
|
||||||
|
getLogList()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
387
src/views/iot/device/device/detail/DeviceDetailsSimulator.vue
Normal file
387
src/views/iot/device/device/detail/DeviceDetailsSimulator.vue
Normal file
@ -0,0 +1,387 @@
|
|||||||
|
<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="list" :show-overflow-tooltip="true" :stripe="true">
|
||||||
|
<el-table-column align="center" label="功能名称" prop="name" />
|
||||||
|
<el-table-column align="center" label="标识符" prop="identifier" />
|
||||||
|
<el-table-column align="center" label="数据类型" prop="identifier">
|
||||||
|
<template #default="{ row }">
|
||||||
|
{{ dataTypeOptionsLabel(row.property?.dataType) ?? '-' }}
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column align="left" label="数据定义" prop="identifier">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<!-- 属性 -->
|
||||||
|
<template v-if="row.type === ThingModelType.PROPERTY">
|
||||||
|
<!-- 非列表型:数值 -->
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
[
|
||||||
|
DataSpecsDataType.INT,
|
||||||
|
DataSpecsDataType.DOUBLE,
|
||||||
|
DataSpecsDataType.FLOAT
|
||||||
|
].includes(row.property.dataType)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
取值范围:{{
|
||||||
|
`${row.property.dataSpecs.min}~${row.property.dataSpecs.max}`
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
<!-- 非列表型:文本 -->
|
||||||
|
<div v-if="DataSpecsDataType.TEXT === row.property.dataType">
|
||||||
|
数据长度:{{ row.property.dataSpecs.length }}
|
||||||
|
</div>
|
||||||
|
<!-- 列表型: 数组、结构、时间(特殊) -->
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
[
|
||||||
|
DataSpecsDataType.ARRAY,
|
||||||
|
DataSpecsDataType.STRUCT,
|
||||||
|
DataSpecsDataType.DATE
|
||||||
|
].includes(row.property.dataType)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
-
|
||||||
|
</div>
|
||||||
|
<!-- 列表型: 布尔值、枚举 -->
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
[DataSpecsDataType.BOOL, DataSpecsDataType.ENUM].includes(
|
||||||
|
row.property.dataType
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
{{
|
||||||
|
DataSpecsDataType.BOOL === row.property.dataType
|
||||||
|
? '布尔值'
|
||||||
|
: '枚举值'
|
||||||
|
}}:
|
||||||
|
</div>
|
||||||
|
<div v-for="item in row.property.dataSpecsList" :key="item.value">
|
||||||
|
{{ `${item.name}-${item.value}` }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<!-- 服务 -->
|
||||||
|
<div v-if="row.type === ThingModelType.SERVICE">
|
||||||
|
调用方式:{{ getCallTypeByValue(row.service.callType) }}
|
||||||
|
</div>
|
||||||
|
<!-- 事件 -->
|
||||||
|
<div v-if="row.type === ThingModelType.EVENT">
|
||||||
|
事件类型:{{ getEventTypeByValue(row.event.type) }}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column label="值" align="center" width="80">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row.simulateValue" class="!w-60px" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</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" 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-column label="值" align="center" width="80">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row.simulateValue" class="!w-60px" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</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" 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-column label="值" align="center" width="80">
|
||||||
|
<template #default="scope">
|
||||||
|
<el-input v-model="scope.row.simulateValue" class="!w-60px" />
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</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 :deviceKey="device.deviceKey" />
|
||||||
|
</el-tab-pane>
|
||||||
|
</el-tabs>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</ContentWrap>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ProductVO } from '@/api/iot/product/product'
|
||||||
|
import { ThingModelApi, ThingModelData,SimulatorData } from '@/api/iot/thingmodel'
|
||||||
|
import { DeviceApi, DeviceVO,SimulatorDataVO } from '@/api/iot/device/device'
|
||||||
|
import DeviceDetailsLog from './DeviceDetailsLog.vue'
|
||||||
|
import {
|
||||||
|
DataSpecsDataType,
|
||||||
|
getCallTypeByValue,
|
||||||
|
getDataTypeOptionsLabel,
|
||||||
|
getEventTypeByValue,
|
||||||
|
ThingModelType
|
||||||
|
} from '@/views/iot/thingmodel/config'
|
||||||
|
|
||||||
|
const message = useMessage() // 消息弹窗
|
||||||
|
const loading = ref(false)
|
||||||
|
const activeTab = ref('up')
|
||||||
|
const subTab = ref('property')
|
||||||
|
|
||||||
|
const queryParams = reactive({
|
||||||
|
type: undefined,
|
||||||
|
productId: -1
|
||||||
|
})
|
||||||
|
const dataTypeOptionsLabel = computed(() => (value: string) => getDataTypeOptionsLabel(value)) // 解析数据类型
|
||||||
|
const props = defineProps<{ product: ProductVO; device: DeviceVO }>()
|
||||||
|
const list = ref<SimulatorData[]>([]) // 物模型列表的数据
|
||||||
|
|
||||||
|
/** 查询列表 */
|
||||||
|
const getList = async () => {
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
queryParams.productId = props.product?.id || -1
|
||||||
|
const data = await ThingModelApi.getThingModelList(queryParams)
|
||||||
|
// 转换数据,添加 simulateValue 字段
|
||||||
|
list.value = data.map(item => ({
|
||||||
|
...item,
|
||||||
|
simulateValue: ''
|
||||||
|
}))
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// // 功能列表数据结构定义
|
||||||
|
// 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 eventList = computed(() => {
|
||||||
|
// return list.value
|
||||||
|
// .filter((item) => item.type === 'event')
|
||||||
|
// .map((item) => ({
|
||||||
|
// name: item.name,
|
||||||
|
// identifier: item.identifier,
|
||||||
|
// value: ''
|
||||||
|
// }))
|
||||||
|
// })
|
||||||
|
|
||||||
|
// 监听标签页变化 todo:后续改成查询字典
|
||||||
|
watch(
|
||||||
|
[activeTab, subTab],
|
||||||
|
([newActiveTab, newSubTab]) => {
|
||||||
|
// 根据标签页设置查询类型
|
||||||
|
if (newActiveTab === 'up') {
|
||||||
|
switch (newSubTab) {
|
||||||
|
case 'property':
|
||||||
|
queryParams.type = 1
|
||||||
|
break
|
||||||
|
case 'event':
|
||||||
|
queryParams.type = 3
|
||||||
|
break
|
||||||
|
// case 'status':
|
||||||
|
// queryParams.type = 'status'
|
||||||
|
// break
|
||||||
|
}
|
||||||
|
} else if (newActiveTab === 'down') {
|
||||||
|
switch (newSubTab) {
|
||||||
|
case 'propertyDebug':
|
||||||
|
queryParams.type = 1
|
||||||
|
break
|
||||||
|
case 'service':
|
||||||
|
queryParams.type = 2
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getList() // 切换标签时重新获取数据
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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) => {
|
||||||
|
// 只有当 simulateValue 有值时才添加到 content 中
|
||||||
|
if (item.simulateValue !== undefined && item.simulateValue !== '') {
|
||||||
|
contentObj[item.identifier] = item.simulateValue
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const reportData: SimulatorDataVO = {
|
||||||
|
productKey: props.product.productKey,
|
||||||
|
deviceKey: props.device.deviceKey,
|
||||||
|
type: 'property',
|
||||||
|
subType: 'report',
|
||||||
|
reportTime: Date.now(), // 将 reportTime 变为数字类型的时间戳
|
||||||
|
content: JSON.stringify(contentObj) // 转换为 JSON 字符串
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
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 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('事件上报失败')
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 处理设备状态变更
|
||||||
|
// 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' ? '上线' : '下线'}失败`)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 处理属性获取
|
||||||
|
const handlePropertyGet = async () => {
|
||||||
|
// TODO: 实现属性获取逻辑
|
||||||
|
message.success('属性获取成功')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化
|
||||||
|
onMounted(() => {
|
||||||
|
getList()
|
||||||
|
})
|
||||||
|
</script>
|
@ -16,6 +16,12 @@
|
|||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<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">
|
||||||
|
<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" />
|
||||||
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</el-col>
|
</el-col>
|
||||||
</template>
|
</template>
|
||||||
@ -26,7 +32,8 @@ import { DeviceTypeEnum, ProductApi, ProductVO } from '@/api/iot/product/product
|
|||||||
import DeviceDetailsHeader from './DeviceDetailsHeader.vue'
|
import DeviceDetailsHeader from './DeviceDetailsHeader.vue'
|
||||||
import DeviceDetailsInfo from './DeviceDetailsInfo.vue'
|
import DeviceDetailsInfo from './DeviceDetailsInfo.vue'
|
||||||
import DeviceDetailsModel from './DeviceDetailsModel.vue'
|
import DeviceDetailsModel from './DeviceDetailsModel.vue'
|
||||||
|
import DeviceDetailsLog from './DeviceDetailsLog.vue'
|
||||||
|
import DeviceDetailsSimulator from './DeviceDetailsSimulator.vue'
|
||||||
defineOptions({ name: 'IoTDeviceDetail' })
|
defineOptions({ name: 'IoTDeviceDetail' })
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user