|
|
|
|
@ -1,10 +1,9 @@
|
|
|
|
|
<script setup lang="ts">
|
|
|
|
|
import type { EchartsUIType } from '@vben/plugins/echarts';
|
|
|
|
|
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
|
|
|
|
|
import { useRoute } from 'vue-router';
|
|
|
|
|
|
|
|
|
|
import { AnalysisChartCard } from '@vben/common-ui';
|
|
|
|
|
import * as echarts from 'echarts';
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
Descriptions,
|
|
|
|
|
DescriptionsItem,
|
|
|
|
|
@ -13,15 +12,96 @@ import {
|
|
|
|
|
Tabs,
|
|
|
|
|
Tag,
|
|
|
|
|
} from 'ant-design-vue';
|
|
|
|
|
import * as echarts from 'echarts';
|
|
|
|
|
|
|
|
|
|
import { deviceInfo } from '#/api/hazard/device';
|
|
|
|
|
import { sensorQuery } from '#/api/hazard/sensor';
|
|
|
|
|
|
|
|
|
|
import { useNotifyStore } from '#/store/notify';
|
|
|
|
|
// 响应式数据
|
|
|
|
|
const deviceData = ref<any>({});
|
|
|
|
|
const sensors = ref<any[]>([]);
|
|
|
|
|
const route = useRoute();
|
|
|
|
|
const activeTab = ref('basic');
|
|
|
|
|
const notifyStore = useNotifyStore();
|
|
|
|
|
// 监听最新的 IoT 消息
|
|
|
|
|
watch(
|
|
|
|
|
() => notifyStore.latestIotMessage,
|
|
|
|
|
(newMessage) => {
|
|
|
|
|
if (newMessage) {
|
|
|
|
|
handleIotMessage(newMessage);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
// 处理 IoT 消息
|
|
|
|
|
const handleIotMessage = (message: any) => {
|
|
|
|
|
// console.log('设备仪表盘页面接收到数据:', message);
|
|
|
|
|
// 检查是否是我们关心的设备消息
|
|
|
|
|
if (message.deviceId !== route.params.id) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// console.log('message.type',message.type)
|
|
|
|
|
// 根据传感器类型更新相应的数据
|
|
|
|
|
switch (message.type) {
|
|
|
|
|
// 温度传感器
|
|
|
|
|
case '0': {
|
|
|
|
|
deviceData.value[`temperature-${message.sensorId}`] = message.value;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// 湿度传感器
|
|
|
|
|
case '1': {
|
|
|
|
|
deviceData.value[`humidity-${message.sensorId}`] = message.value;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// 压力传感器
|
|
|
|
|
case '2': {
|
|
|
|
|
deviceData.value[`pressure-${message.sensorId}`] = message.value;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新图表
|
|
|
|
|
updateChart(message);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 更新特定图表
|
|
|
|
|
const updateChart = (message: any) => {
|
|
|
|
|
let chartKey;
|
|
|
|
|
switch (message.type) {
|
|
|
|
|
case '0': {
|
|
|
|
|
chartKey = `temperature-${message.sensorId}`;
|
|
|
|
|
console.log('更新温度图表:', chartKey);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case '1': {
|
|
|
|
|
chartKey = `humidity-${message.sensorId}`;
|
|
|
|
|
console.log('更新湿度图表:', chartKey);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case '2': {
|
|
|
|
|
chartKey = `pressure-${message.sensorId}`;
|
|
|
|
|
console.log('更新压力图表:', chartKey);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
// No default
|
|
|
|
|
}
|
|
|
|
|
const chart = chartInstances.value[chartKey];
|
|
|
|
|
console.log('更新图表:', chart);
|
|
|
|
|
if (chart) {
|
|
|
|
|
const option = {
|
|
|
|
|
series: [
|
|
|
|
|
{
|
|
|
|
|
data: [
|
|
|
|
|
{
|
|
|
|
|
value: message.value,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
};
|
|
|
|
|
chart.setOption(option);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 计算属性 - 获取各类传感器列表
|
|
|
|
|
const temperatureSensors = computed(() => {
|
|
|
|
|
@ -72,8 +152,8 @@ const createChart = (chartKey: string, container: HTMLElement) => {
|
|
|
|
|
if (chartInstances.value[chartKey]) {
|
|
|
|
|
try {
|
|
|
|
|
chartInstances.value[chartKey].dispose();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.warn(`Error disposing chart ${chartKey}`, e);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.warn(`Error disposing chart ${chartKey}`, error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -87,8 +167,8 @@ const createChart = (chartKey: string, container: HTMLElement) => {
|
|
|
|
|
const renderChart = (chart: any, type: string, sensor: any, index: number) => {
|
|
|
|
|
let option;
|
|
|
|
|
|
|
|
|
|
switch(type) {
|
|
|
|
|
case 'temperature':
|
|
|
|
|
switch (type) {
|
|
|
|
|
case 'humidity': {
|
|
|
|
|
option = {
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
series: [
|
|
|
|
|
@ -97,17 +177,17 @@ const renderChart = (chart: any, type: string, sensor: any, index: number) => {
|
|
|
|
|
center: ['50%', '60%'],
|
|
|
|
|
startAngle: 180,
|
|
|
|
|
endAngle: 0,
|
|
|
|
|
min: -50,
|
|
|
|
|
max: deviceData.value.maxTemp || 100,
|
|
|
|
|
min: 0,
|
|
|
|
|
max: deviceData.value.maxHumidity || 100,
|
|
|
|
|
splitNumber: 10,
|
|
|
|
|
radius: '90%',
|
|
|
|
|
axisLine: {
|
|
|
|
|
lineStyle: {
|
|
|
|
|
width: 10,
|
|
|
|
|
color: [
|
|
|
|
|
[0.3, '#67e0e3'],
|
|
|
|
|
[0.7, '#37a2da'],
|
|
|
|
|
[1, '#fd666d'],
|
|
|
|
|
[0.3, '#a0cfff'],
|
|
|
|
|
[0.7, '#40a9ff'],
|
|
|
|
|
[1, '#2f54eb'],
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
@ -140,7 +220,7 @@ const renderChart = (chart: any, type: string, sensor: any, index: number) => {
|
|
|
|
|
},
|
|
|
|
|
detail: {
|
|
|
|
|
show: true,
|
|
|
|
|
formatter: '{value}°C',
|
|
|
|
|
formatter: '{value}%',
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
offsetCenter: [0, '40%'],
|
|
|
|
|
color: '#333',
|
|
|
|
|
@ -153,16 +233,20 @@ const renderChart = (chart: any, type: string, sensor: any, index: number) => {
|
|
|
|
|
},
|
|
|
|
|
data: [
|
|
|
|
|
{
|
|
|
|
|
value: deviceData.value[`temperature${index}`] || deviceData.value.temperature || 0,
|
|
|
|
|
name: sensor.name || `温度${index + 1}`,
|
|
|
|
|
value:
|
|
|
|
|
deviceData.value[`humidity${index}`] ||
|
|
|
|
|
deviceData.value.humidity ||
|
|
|
|
|
0,
|
|
|
|
|
name: sensor.name || `湿度${index + 1}`,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 'humidity':
|
|
|
|
|
case 'pressure': {
|
|
|
|
|
option = {
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
series: [
|
|
|
|
|
@ -172,16 +256,16 @@ const renderChart = (chart: any, type: string, sensor: any, index: number) => {
|
|
|
|
|
startAngle: 180,
|
|
|
|
|
endAngle: 0,
|
|
|
|
|
min: 0,
|
|
|
|
|
max: deviceData.value.maxHumidity || 100,
|
|
|
|
|
max: deviceData.value.maxPressure || 100,
|
|
|
|
|
splitNumber: 10,
|
|
|
|
|
radius: '90%',
|
|
|
|
|
axisLine: {
|
|
|
|
|
lineStyle: {
|
|
|
|
|
width: 10,
|
|
|
|
|
color: [
|
|
|
|
|
[0.3, '#a0cfff'],
|
|
|
|
|
[0.7, '#40a9ff'],
|
|
|
|
|
[1, '#2f54eb'],
|
|
|
|
|
[0.3, '#ffd666'],
|
|
|
|
|
[0.7, '#ffa940'],
|
|
|
|
|
[1, '#ff4d4f'],
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
@ -214,7 +298,7 @@ const renderChart = (chart: any, type: string, sensor: any, index: number) => {
|
|
|
|
|
},
|
|
|
|
|
detail: {
|
|
|
|
|
show: true,
|
|
|
|
|
formatter: '{value}%',
|
|
|
|
|
formatter: '{value}kPa',
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
offsetCenter: [0, '40%'],
|
|
|
|
|
color: '#333',
|
|
|
|
|
@ -227,16 +311,20 @@ const renderChart = (chart: any, type: string, sensor: any, index: number) => {
|
|
|
|
|
},
|
|
|
|
|
data: [
|
|
|
|
|
{
|
|
|
|
|
value: deviceData.value[`humidity${index}`] || deviceData.value.humidity || 0,
|
|
|
|
|
name: sensor.name || `湿度${index + 1}`,
|
|
|
|
|
value:
|
|
|
|
|
deviceData.value[`pressure${index}`] ||
|
|
|
|
|
deviceData.value.pressure ||
|
|
|
|
|
0,
|
|
|
|
|
name: sensor.name || `压力${index + 1}`,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 'pressure':
|
|
|
|
|
case 'temperature': {
|
|
|
|
|
option = {
|
|
|
|
|
backgroundColor: 'transparent',
|
|
|
|
|
series: [
|
|
|
|
|
@ -245,17 +333,17 @@ const renderChart = (chart: any, type: string, sensor: any, index: number) => {
|
|
|
|
|
center: ['50%', '60%'],
|
|
|
|
|
startAngle: 180,
|
|
|
|
|
endAngle: 0,
|
|
|
|
|
min: 0,
|
|
|
|
|
max: deviceData.value.maxPressure || 100,
|
|
|
|
|
min: -20,
|
|
|
|
|
max: deviceData.value.maxTemp || 100,
|
|
|
|
|
splitNumber: 10,
|
|
|
|
|
radius: '90%',
|
|
|
|
|
axisLine: {
|
|
|
|
|
lineStyle: {
|
|
|
|
|
width: 10,
|
|
|
|
|
color: [
|
|
|
|
|
[0.3, '#ffd666'],
|
|
|
|
|
[0.7, '#ffa940'],
|
|
|
|
|
[1, '#ff4d4f'],
|
|
|
|
|
[0.3, '#67e0e3'],
|
|
|
|
|
[0.7, '#37a2da'],
|
|
|
|
|
[1, '#fd666d'],
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
@ -288,7 +376,7 @@ const renderChart = (chart: any, type: string, sensor: any, index: number) => {
|
|
|
|
|
},
|
|
|
|
|
detail: {
|
|
|
|
|
show: true,
|
|
|
|
|
formatter: '{value}kPa',
|
|
|
|
|
formatter: '{value}°C',
|
|
|
|
|
fontSize: 16,
|
|
|
|
|
offsetCenter: [0, '40%'],
|
|
|
|
|
color: '#333',
|
|
|
|
|
@ -301,14 +389,18 @@ const renderChart = (chart: any, type: string, sensor: any, index: number) => {
|
|
|
|
|
},
|
|
|
|
|
data: [
|
|
|
|
|
{
|
|
|
|
|
value: deviceData.value[`pressure${index}`] || deviceData.value.pressure || 0,
|
|
|
|
|
name: sensor.name || `压力${index + 1}`,
|
|
|
|
|
value:
|
|
|
|
|
deviceData.value[`temperature${index}`] ||
|
|
|
|
|
deviceData.value.temperature ||
|
|
|
|
|
0,
|
|
|
|
|
name: sensor.name || `温度${index + 1}`,
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
};
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (option) {
|
|
|
|
|
@ -373,12 +465,12 @@ watch(activeTab, (newTab) => {
|
|
|
|
|
|
|
|
|
|
// 窗口大小变化时重绘图表
|
|
|
|
|
const handleResize = () => {
|
|
|
|
|
Object.values(chartInstances.value).forEach(chart => {
|
|
|
|
|
Object.values(chartInstances.value).forEach((chart) => {
|
|
|
|
|
if (chart) {
|
|
|
|
|
try {
|
|
|
|
|
chart.resize();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.warn('Error resizing chart:', e);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.warn('Error resizing chart:', error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
@ -386,12 +478,12 @@ const handleResize = () => {
|
|
|
|
|
|
|
|
|
|
// 清理图表实例
|
|
|
|
|
const cleanupCharts = () => {
|
|
|
|
|
Object.values(chartInstances.value).forEach(chart => {
|
|
|
|
|
Object.values(chartInstances.value).forEach((chart) => {
|
|
|
|
|
if (chart) {
|
|
|
|
|
try {
|
|
|
|
|
chart.dispose();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.warn('Error disposing chart:', e);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
console.warn('Error disposing chart:', error);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
@ -423,7 +515,11 @@ onUnmounted(() => {
|
|
|
|
|
|
|
|
|
|
<template>
|
|
|
|
|
<div class="device-detail-page">
|
|
|
|
|
<Tabs v-model:activeKey="activeTab" tab-position="left" class="device-tabs">
|
|
|
|
|
<Tabs
|
|
|
|
|
v-model:active-key="activeTab"
|
|
|
|
|
tab-position="left"
|
|
|
|
|
class="device-tabs"
|
|
|
|
|
>
|
|
|
|
|
<!-- 基本信息标签页 -->
|
|
|
|
|
<TabPane key="basic" tab="基础信息">
|
|
|
|
|
<Descriptions bordered>
|
|
|
|
|
@ -444,9 +540,9 @@ onUnmounted(() => {
|
|
|
|
|
? deviceData.sensorCode
|
|
|
|
|
: typeof deviceData.sensorCode === 'string'
|
|
|
|
|
? deviceData.sensorCode
|
|
|
|
|
.split(',')
|
|
|
|
|
.map((id) => id.trim())
|
|
|
|
|
.filter((id) => id)
|
|
|
|
|
.split(',')
|
|
|
|
|
.map((id) => id.trim())
|
|
|
|
|
.filter((id) => id)
|
|
|
|
|
: [];
|
|
|
|
|
|
|
|
|
|
return sensorIds
|
|
|
|
|
@ -488,7 +584,10 @@ onUnmounted(() => {
|
|
|
|
|
:key="`temp-${sensor.id}`"
|
|
|
|
|
class="chart-item"
|
|
|
|
|
>
|
|
|
|
|
<AnalysisChartCard class="chart-card" :title="sensor.name || `温度${index + 1}`">
|
|
|
|
|
<AnalysisChartCard
|
|
|
|
|
class="chart-card"
|
|
|
|
|
:title="sensor.name || `温度${index + 1}`"
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
:ref="(el) => setChartRef(el, `temperature-${sensor.id}`)"
|
|
|
|
|
class="chart-container"
|
|
|
|
|
@ -502,7 +601,10 @@ onUnmounted(() => {
|
|
|
|
|
:key="`humidity-${sensor.id}`"
|
|
|
|
|
class="chart-item"
|
|
|
|
|
>
|
|
|
|
|
<AnalysisChartCard class="chart-card" :title="sensor.name || `湿度${index + 1}`">
|
|
|
|
|
<AnalysisChartCard
|
|
|
|
|
class="chart-card"
|
|
|
|
|
:title="sensor.name || `湿度${index + 1}`"
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
:ref="(el) => setChartRef(el, `humidity-${sensor.id}`)"
|
|
|
|
|
class="chart-container"
|
|
|
|
|
@ -516,7 +618,10 @@ onUnmounted(() => {
|
|
|
|
|
:key="`pressure-${sensor.id}`"
|
|
|
|
|
class="chart-item"
|
|
|
|
|
>
|
|
|
|
|
<AnalysisChartCard class="chart-card" :title="sensor.name || `压力${index + 1}`">
|
|
|
|
|
<AnalysisChartCard
|
|
|
|
|
class="chart-card"
|
|
|
|
|
:title="sensor.name || `压力${index + 1}`"
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
:ref="(el) => setChartRef(el, `pressure-${sensor.id}`)"
|
|
|
|
|
class="chart-container"
|
|
|
|
|
@ -526,9 +631,13 @@ onUnmounted(() => {
|
|
|
|
|
|
|
|
|
|
<!-- 无传感器提示 -->
|
|
|
|
|
<Empty
|
|
|
|
|
v-if="temperatureSensors.length === 0 && humiditySensors.length === 0 && pressureSensors.length === 0"
|
|
|
|
|
v-if="
|
|
|
|
|
temperatureSensors.length === 0 &&
|
|
|
|
|
humiditySensors.length === 0 &&
|
|
|
|
|
pressureSensors.length === 0
|
|
|
|
|
"
|
|
|
|
|
description="暂无数据"
|
|
|
|
|
style="grid-column: 1 / -1;"
|
|
|
|
|
style="grid-column: 1 / -1"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@ -587,7 +696,9 @@ onUnmounted(() => {
|
|
|
|
|
|
|
|
|
|
.chart-item {
|
|
|
|
|
min-width: 0;
|
|
|
|
|
transition: transform 0.3s ease, box-shadow 0.3s ease;
|
|
|
|
|
transition:
|
|
|
|
|
transform 0.3s ease,
|
|
|
|
|
box-shadow 0.3s ease;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.chart-item:hover {
|
|
|
|
|
|