2025-05-22 16:37:43 +08:00

368 lines
10 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="device-monitor">
<view class="search-wrap">
<u--text :text="$tt('monitior.monitoringInterval')"
:customStyle="{color: '#045FFA', fontSize: '12px', marginBottom: '10px'}"></u--text>
<u-row :gutter="10">
<u-col span="3">
<u--input :placeholder=" $tt('monitior.inputNumber')" placeholderStyle="font-size: 12px"
v-model="monitorInterval" border="surround" color="#666"
customStyle="padding:4px; background: #ffffff;"></u--input>
</u-col>
<u-col span="3">
<u--input :placeholder="$tt('monitior.inputTimes')" placeholderStyle="font-size: 12px"
v-model="monitorNumber" border="surround" cocclor="#666"
customStyle="padding:4px; background: #ffffff;"></u--input>
</u-col>
<u-col span="3">
<u-button type="primary" :text="$tt('monitior.monitior')" @tap="updateMonitorParameters()"
size="small"
:disabled="deviceInfo.monitorList && deviceInfo.monitorList.length == 0"></u-button>
</u-col>
<u-col span="3">
<u-button type="info" :text="$tt('monitior.stop')" @tap="stopMonitor()" size="small"
:disabled="deviceInfo.monitorList && deviceInfo.monitorList.length == 0"></u-button>
</u-col>
</u-row>
</view>
<view class="charts-box" v-for="(chart, index) in monitorChart" :key="index">
<qiun-data-charts type="area" :canvas2d="true" :reshow="reshow" :opts="chart.opts" :chartData="chart.data"
:animation="false" tooltipFormat="tooltipStatistic" />
<view style="position:relative;bottom:100px;">
<u-loading-icon :text="$tt('monitior.receivingData')" textSize="14" :show="chart.show"></u-loading-icon>
</view>
</view>
<u-empty mode="data" :show="deviceInfo.monitorList && deviceInfo.monitorList.length === 0"
marginTop="30"></u-empty>
</view>
</template>
<script>
import { listMonitor } from '@/apis/modules/deviceLog';
export default {
name: 'DeviceMonitor',
props: {
show: {
type: Boolean,
default: false,
required: true
},
device: {
type: Object,
default: null,
required: true
},
},
watch: {
// 兼容小程序
show: function(newVal, oldVal) {
this.reshow = newVal;
},
device: function(newVal, oldVal) {
this.deviceInfo = newVal;
this.initChart(); // 初始化图表
uni.stopPullDownRefresh();
},
},
data() {
return {
reshow: false,
// 图表数据集合
monitorChart: [{
opts: {},
data: {
categories: [],
series: []
},
show: false,
id: ''
}],
// 设备信息
deviceInfo: {
monitorList: [],
},
// 实时监测间隔
monitorInterval: 1000,
// 实时监测次数
monitorNumber: 30,
// 停止实时监测
isStopMonitor: true,
};
},
created() {
// 获取显示状态(兼容H5和APP)
if (this.show != null) {
this.reshow = this.show;
}
if (this.device.monitorList && this.device.monitorList.length !== 0) {
this.deviceInfo = this.device;
this.initChart(); // 初始化图表
uni.stopPullDownRefresh();
}
// 监听回调
this.$nextTick(function() {
this.mqttCallback();
});
},
methods: {
/* Mqtt回调处理 */
mqttCallback() {
this.$mqttTool.client.on('message', (topic, message, buffer) => {
let topics = topic.split('/');
let productId = topics[1];
let deviceNum = topics[2];
message = JSON.parse(message.toString());
if (topics[3] == 'monitor' && !this.isStopMonitor) {
console.log('接收到【实时监测】主题:', topic);
console.log('接收到【实时监测】内容:', message);
// 实时监测
for (let k = 0; k < message.length; k++) {
let value = message[k].value;
let id = message[k].id;
let remark = message[k].remark;
// 数据加载到图表
for (let i = 0; i < this.monitorChart.length; i++) {
this.monitorChart[i].show = false;
if (id == this.monitorChart[i].id) {
if (this.monitorChart[i].data.series[0].data.length > 50) {
this.monitorChart[i].data.series[0].data.shift();
}
this.monitorChart[i].data.categories.push(this.getTime());
this.monitorChart[i].data.series[0].data.push(value);
break;
}
}
}
}
});
},
/** 更新实时监测参数*/
updateMonitorParameters() {
this.isStopMonitor = false;
if (this.monitorInterval < 500 || this.monitorInterval > 10000) {
uni.showToast({
icon: 'none',
title: this.$tt('monitior.MonitoringRange'),
duration: 3000
});
return;
}
if (this.monitorNumber == 0 || this.monitorNumber > 300) {
uni.showToast({
icon: 'none',
title: this.$tt('monitior.monitoringQuantity'),
duration: 3000
});
return;
}
// 清空图表数据
for (let i = 0; i < this.monitorChart.length; i++) {
this.monitorChart[i].data.series[0].data = [];
this.monitorChart[i].data.categories = [];
this.monitorChart[i].show = true;
}
this.publishMonitor({
name: this.$tt('monitior.real-timeMonitor'),
value: this.monitorNumber
});
},
/*停止实时监测*/
stopMonitor() {
this.isStopMonitor = true;
// 发布指令
this.publishMonitor({
name: this.$tt('monitior.stopMonitor'),
value: 0
});
},
/* 发布消息 */
publishMonitor(model) {
// 实时监测
const {
productId,
serialNumber
} = this.deviceInfo;
let topic = '/' + productId + '/' + serialNumber + '/monitor/get';
let message = '{"count":' + model.value + ',"interval":' + this.monitorInterval + '}';
if (topic != '') {
this.$mqttTool.publish(topic, message, model.name); // 发布
}
},
// 获取当前时间
getTime() {
let date = new Date();
let y = date.getFullYear();
let m = date.getMonth() + 1;
let d = date.getDate();
let H = date.getHours();
let mm = date.getMinutes();
let s = date.getSeconds();
m = m < 10 ? '0' + m : m;
d = d < 10 ? '0' + d : d;
H = H < 10 ? '0' + H : H;
return y + '-' + m + '-' + d + ' ' + H + ':' + mm + ':' + s;
},
// 初始化图表
initChart() {
let color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4',
'#ea7ccc'
];
this.monitorChart = [];
if (this.deviceInfo.monitorList && this.deviceInfo.monitorList.length !== 0) {
for (let i = 0; i < this.deviceInfo.monitorList.length; i++) {
let data = {};
let res = {
categories: [],
series: [{
name: this.deviceInfo.monitorList[i].name + '(单位 ' + (this.deviceInfo
.monitorList[i].datatype.unit !=
undefined ? this.deviceInfo.monitorList[i].datatype.unit : '无') + '',
data: []
}]
};
data = JSON.parse(JSON.stringify(res));
let opts = {
// 自定义名称和单位,用于图表提示框显示
name: this.deviceInfo.monitorList[i].name,
unit: this.deviceInfo.monitorList[i].datatype.unit,
update: true,
timing: 'easeOut',
duration: 1000,
color: [color[i % color.length]],
padding: [0, 15, 15, 15],
fontSize: 12,
fontColor: '#666666',
dataLabel: false, //是否显示值
dataPointShape: true,
dataPointShapeType: 'solid',
touchMoveLimit: 60,
enableScroll: true,
enableMarkLine: false,
legend: {
show: true,
position: 'top', // 可以选择合适的位置
float: 'left',
padding: 10,
margin: 5,
backgroundColor: 'rgba(0,0,0,0)',
borderColor: 'rgba(0,0,0,0)',
borderWidth: 0,
fontSize: 14,
fontColor: '#000',
lineHeight: 16,
hiddenColor: '#CECECE',
itemGap: 10
},
xAxis: {
disableGrid: true,
disabled: true, // 隐藏分类名称
axisLine: true,
axisLineColor: '#CCCCCC',
calibration: false,
fontColor: '#666666',
fontSize: 13,
rotateLabel: false,
rotateAngle: 45,
itemCount: 30,
boundaryGap: 'justify',
splitNumber: 5,
gridColor: '#CCCCCC',
gridType: 'solid',
dashLength: 1,
gridEval: 1,
scrollShow: false,
scrollAlign: 'right',
scrollColor: '#A6A6A6',
scrollBackgroundColor: '#ccc',
format: ''
},
yAxis: {
gridType: 'dash',
dashLength: 2,
disabled: false,
tofix: 3, //刻度保留小数位数
disableGrid: false,
splitNumber: 5,
gridColor: '#CCCCCC',
padding: 10,
showTitle: false,
data: []
},
extra: {
area: {
type: 'curve',
opacity: 0.5,
addLine: true,
width: 1,
gradient: false
},
tooltip: {
showBox: true,
showArrow: true,
showCategory: true,
borderWidth: 0,
borderRadius: 0,
borderColor: '#000000',
borderOpacity: 0.7,
bgColor: '#000000',
bgOpacity: 0.7,
gridType: 'solid',
dashLength: 4,
gridColor: '#CCCCCC',
fontColor: '#FFFFFF',
splitLine: true,
horizentalLine: false,
xAxisLabel: false,
yAxisLabel: false,
labelBgColor: '#FFFFFF',
labelBgOpacity: 0.7,
labelFontColor: '#666666'
},
markLine: {
type: 'solid',
dashLength: 2,
data: []
}
}
};
opts && this.monitorChart.push({
opts: opts,
data: data,
show: false,
id: this.deviceInfo.monitorList[i].id
});
}
}
}
}
};
</script>
<style lang="scss" scoped>
.device-monitor {
height: 100%;
.search-wrap {
margin-bottom: 20rpx;
}
/* 请根据实际需求修改父元素尺寸,组件自动识别宽高 */
.charts-box {
width: 100%;
height: 500rpx;
background: #FFFFFF;
border-radius: 20rpx;
padding: 20rpx 0;
&:not(:last-child) {
margin-bottom: 20rpx;
}
}
}
</style>