前端接受数据并显示在仪表盘,以及设备上下线状态修改

master
yangxiaozhong 1 month ago
parent 8a65bfd4d9
commit a06fec10ad

@ -32,6 +32,16 @@ export const useNotifyStore = defineStore(
);
});
// 添加 IoT 消息专用状态
const iotMessages = ref<any[]>([]);
// 添加获取最新 IoT 消息的计算属性
const latestIotMessage = computed(() => {
return iotMessages.value.length > 0
? iotMessages.value[iotMessages.value.length - 1]
: null;
});
/**
* sse
*/
@ -68,7 +78,21 @@ export const useNotifyStore = defineStore(
title: $t('component.notice.title'),
userId: userId.value,
});
} else if (event.value === SSEEvent.HAZARD) { /* empty */ }
} else if (event.value === SSEEvent.HAZARD) {
try {
// 解析消息内容
const parsedMessage = JSON.parse(message);
// console.log('解析后的 IoT 消息:', parsedMessage);
// 将消息添加到 IoT 消息队列
iotMessages.value.push(parsedMessage);
// 保持最新的几条消息,防止内存泄漏
if (iotMessages.value.length > 100) {
iotMessages.value.shift();
}
} catch (e) {
console.error('解析 IoT 消息失败:', e);
}
}
// 需要手动置空 vue3在值相同时不会触发watch
data.value = null;
@ -125,6 +149,8 @@ export const useNotifyStore = defineStore(
);
return {
iotMessages,
latestIotMessage,
$reset,
clearAllMessage,
notificationList,

@ -72,11 +72,11 @@ export const columns: VxeGridProps['columns'] = [
title: '设备名称',
field: 'name',
},
{
title: '拥有传感器',
field: 'sensorCode',
slots: { default: 'sensorCode'},
},
// {
// title: '拥有传感器',
// field: 'sensorCode',
// slots: { default: 'sensorCode'},
// },
{
title: '状态',
field: 'status',
@ -138,6 +138,7 @@ export const modalSchema: FormSchemaGetter = () => [
label: '设备名称',
fieldName: 'name',
component: 'Input',
rules: 'required',
},
{
label: '拥有传感器',
@ -169,6 +170,7 @@ export const modalSchema: FormSchemaGetter = () => [
label: '设备编号',
fieldName: 'deviceCode',
component: 'Input',
rules: 'required',
},
{
label: '设备传入',

@ -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 {

@ -94,11 +94,13 @@ export const modalSchema: FormSchemaGetter = () => [
label: '传感器名称',
fieldName: 'name',
component: 'Input',
rules: 'required',
},
{
label: '传感器代号',
fieldName: 'code',
component: 'Input',
rules: 'required',
},
{
label: '传感器类型',
@ -108,6 +110,7 @@ export const modalSchema: FormSchemaGetter = () => [
// 可选从DictEnum中获取 DictEnum.ACTIVED 便于维护
options: getDictOptions(DictEnum.SCENSOR_TYPE),
},
rules: 'required',
},
{
label: '描述',

Loading…
Cancel
Save