314 lines
13 KiB
Vue
314 lines
13 KiB
Vue
<template>
|
||
<div style="padding-left: 20px">
|
||
<el-form :inline="true" label-width="100px">
|
||
<el-form-item :label="$t('device.device-monitor.817489-0')">
|
||
<el-tooltip class="item" effect="light" :content="$t('device.device-monitor.817489-1')" placement="top">
|
||
<el-input v-model="monitorInterval" :placeholder="$t('device.device-monitor.817489-2')"
|
||
type="number" clearable size="small" style="width: 180px" />
|
||
</el-tooltip>
|
||
</el-form-item>
|
||
<el-form-item :label="$t('device.device-monitor.817489-3')">
|
||
<el-tooltip class="item" effect="light" :content="$t('device.device-monitor.817489-4')" placement="top">
|
||
<el-input v-model="monitorNumber" :placeholder="$t('device.device-monitor.817489-5')" type="number"
|
||
clearable size="small" style="width: 180px" />
|
||
</el-tooltip>
|
||
</el-form-item>
|
||
<el-form-item>
|
||
<el-button type="success" icon="el-icon-video-play" size="mini" @click="beginMonitor()"
|
||
style="margin-left: 30px" v-hasPermi="['iot:service:invoke']">
|
||
{{ $t('device.device-monitor.817489-6') }}
|
||
</el-button>
|
||
<el-button type="danger" icon="el-icon-video-pause" size="mini" @click="stopMonitor()"
|
||
v-hasPermi="['iot:service:invoke']">{{ $t('device.device-monitor.817489-7') }}</el-button>
|
||
</el-form-item>
|
||
</el-form>
|
||
<el-row :gutter="20" v-loading="chartLoading" :element-loading-text="$t('device.device-monitor.817489-8')"
|
||
element-loading-spinner="el-icon-loading" element-loading-background="rgba(0, 0, 0, 0.8)">
|
||
<el-col :span="12" v-for="(item, index) in monitorThings" :key="index" style="margin-bottom: 20px">
|
||
<el-card shadow="hover" :body-style="{ paddingTop: '10px', marginBottom: '-20px' }">
|
||
<div ref="monitor" style="height: 210px; padding: 0"></div>
|
||
</el-card>
|
||
</el-col>
|
||
</el-row>
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
import moment from 'moment';
|
||
|
||
export default {
|
||
name: 'DeviceMonitor',
|
||
props: {
|
||
device: {
|
||
type: Object,
|
||
default: null,
|
||
},
|
||
},
|
||
watch: {
|
||
// 获取到父组件传递的device后,刷新列表
|
||
device: function (newVal, oldVal) {
|
||
this.deviceInfo = newVal;
|
||
if (this.deviceInfo && this.deviceInfo.deviceId != 0) {
|
||
// 监测数据
|
||
this.monitorThings = this.deviceInfo.monitorList;
|
||
// 监测数据集合初始化
|
||
this.dataList = [];
|
||
for (let i = 0; i < this.monitorThings.length; i++) {
|
||
this.dataList.push({
|
||
id: this.monitorThings[i].id,
|
||
name: this.monitorThings[i].name,
|
||
data: [],
|
||
});
|
||
// this.dataList[i].data.push(["2022-03-14 23:32:09", "30"]);
|
||
}
|
||
// 绘制监测图表
|
||
this.$nextTick(function () {
|
||
this.getMonitorChart();
|
||
});
|
||
// 添加message事件监听器
|
||
this.mqttCallback();
|
||
}
|
||
},
|
||
},
|
||
data() {
|
||
return {
|
||
// 实时监测间隔
|
||
monitorInterval: 1000,
|
||
// 实时监测次数
|
||
monitorNumber: 60,
|
||
// 图表集合
|
||
chart: [],
|
||
// 图表数据集合
|
||
dataList: [],
|
||
// 监测物模型
|
||
monitorThings: [],
|
||
// 图表遮罩层
|
||
chartLoading: false,
|
||
// 设备信息
|
||
deviceInfo: {},
|
||
};
|
||
},
|
||
created() { },
|
||
methods: {
|
||
/**
|
||
* Mqtt发布消息
|
||
* @device 设备
|
||
* @model 物模型 ,type 类型(1=属性,2=功能,3=OTA升级,4=实时监测)
|
||
* */
|
||
mqttPublish(device, model) {
|
||
let topic = '';
|
||
let message = '';
|
||
if (model.type == 4) {
|
||
// 实时监测
|
||
topic = '/' + device.productId + '/' + device.serialNumber + '/monitor/get';
|
||
message = '{"count":' + model.value + ',"interval":' + this.monitorInterval + '}';
|
||
} else {
|
||
return;
|
||
}
|
||
if (topic != '') {
|
||
// 发布
|
||
this.$mqttTool
|
||
.publish(topic, message, model.name)
|
||
.then((res) => {
|
||
this.$modal.notifySuccess(res);
|
||
})
|
||
.catch((res) => {
|
||
this.$modal.notifyError(res);
|
||
});
|
||
}
|
||
},
|
||
/* 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 (!message) {
|
||
return;
|
||
}
|
||
if (topics[3] == 'status') {
|
||
console.log(this.$t('device.device-monitor.817489-9'), topic);
|
||
console.log(this.$t('device.device-monitor.817489-10'), message);
|
||
// 更新列表中设备的状态
|
||
if (this.deviceInfo.serialNumber == deviceNum) {
|
||
this.deviceInfo.status = message.status;
|
||
this.deviceInfo.isShadow = message.isShadow;
|
||
this.deviceInfo.rssi = message.rssi;
|
||
}
|
||
}
|
||
if (topics[3] == 'monitor') {
|
||
console.log(this.$t('device.device-monitor.817489-11'), topic);
|
||
console.log(this.$t('device.device-monitor.817489-12'), message);
|
||
// 实时监测
|
||
this.chartLoading = false;
|
||
for (let k = 0; k < message.length; k++) {
|
||
let value = message[k].value;
|
||
let id = message[k].id;
|
||
let remark = message[k].remark;
|
||
const time = moment(Number(remark)).format('YYYY-MM-DD HH:mm:ss');
|
||
// 数据加载到图表
|
||
for (let i = 0; i < this.dataList.length; i++) {
|
||
if (id == this.dataList[i].id) {
|
||
// 普通类型匹配
|
||
if (this.dataList[i].length > 50) {
|
||
this.dataList[i].shift();
|
||
}
|
||
this.dataList[i].data.push([remark ? time : this.getTime(), value]);
|
||
// 更新图表
|
||
this.chart[i].setOption({
|
||
series: [
|
||
{
|
||
data: this.dataList[i].data,
|
||
},
|
||
],
|
||
});
|
||
break;
|
||
} else if (this.dataList[i].id.indexOf('array_') == 0) {
|
||
// 数组类型匹配,例如:gateway_temperature,图表id去除前缀后匹配
|
||
let index = this.dataList[i].id.substring(6, 8);
|
||
let identity = this.dataList[i].id.substring(9);
|
||
if (identity == id) {
|
||
let values = value.split(',');
|
||
if (this.dataList[i].length > 50) {
|
||
this.dataList[i].shift();
|
||
}
|
||
this.dataList[i].data.push([remark ? time : this.getTime(), values[index]]);
|
||
// 更新图表
|
||
this.chart[i].setOption({
|
||
series: [
|
||
{
|
||
data: this.dataList[i].data,
|
||
},
|
||
],
|
||
});
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
});
|
||
},
|
||
/** 更新实时监测参数*/
|
||
beginMonitor() {
|
||
if (this.deviceInfo.status != 3) {
|
||
this.$modal.alertError(this.$t('device.device-monitor.817489-13'));
|
||
return;
|
||
}
|
||
// 清空图表数据
|
||
for (let i = 0; i < this.dataList.length; i++) {
|
||
this.dataList[i].data = [];
|
||
}
|
||
if (this.monitorInterval < 500 || this.monitorInterval > 10000) {
|
||
this.$modal.alertError(this.$t('device.device-monitor.817489-14'));
|
||
}
|
||
if (this.monitorNumber == 0 || this.monitorNumber > 300) {
|
||
this.$modal.alertError(this.$t('device.device-monitor.817489-15'));
|
||
}
|
||
// Mqtt发布实时监测消息
|
||
let model = {};
|
||
model.name = this.$t('device.device-monitor.817489-16');
|
||
model.value = this.monitorNumber;
|
||
model.type = 4;
|
||
this.mqttPublish(this.deviceInfo, model);
|
||
this.chartLoading = true;
|
||
},
|
||
/** 停止实时监测 */
|
||
stopMonitor() {
|
||
if (this.deviceInfo.status != 3) {
|
||
this.$modal.alertError(this.$t('device.device-monitor.817489-13'));
|
||
return;
|
||
}
|
||
this.chartLoading = false;
|
||
// Mqtt发布实时监测
|
||
let model = {};
|
||
model.name = this.$t('device.device-monitor.817489-17');
|
||
model.value = 0;
|
||
model.type = 4;
|
||
this.mqttPublish(this.deviceInfo, model);
|
||
},
|
||
/**监测数据 */
|
||
getMonitorChart() {
|
||
let color = ['#1890FF', '#91CB74', '#FAC858', '#EE6666', '#73C0DE', '#3CA272', '#FC8452', '#9A60B4', '#ea7ccc'];
|
||
for (let i = 0; i < this.monitorThings.length; i++) {
|
||
// 设置宽度
|
||
this.$refs.monitor[i].style.width = document.documentElement.clientWidth / 2 - 255 + 'px';
|
||
this.chart[i] = this.$echarts.init(this.$refs.monitor[i]);
|
||
var option;
|
||
option = {
|
||
title: {
|
||
left: 'center',
|
||
text: this.monitorThings[i].name + ' (单位 ' + (this.monitorThings[i].datatype.unit != undefined ? this.monitorThings[i].datatype.unit : this.$t('device.device-monitor.817489-19')) + ')',
|
||
textStyle: {
|
||
fontSize: 14,
|
||
},
|
||
},
|
||
grid: {
|
||
top: '50px',
|
||
left: '20px',
|
||
right: '20px',
|
||
bottom: '10px',
|
||
containLabel: true,
|
||
},
|
||
tooltip: {
|
||
trigger: 'axis',
|
||
axisPointer: {
|
||
animation: true,
|
||
},
|
||
},
|
||
xAxis: {
|
||
type: 'time',
|
||
show: false,
|
||
splitLine: {
|
||
show: false,
|
||
},
|
||
},
|
||
yAxis: {
|
||
type: 'value',
|
||
boundaryGap: [0, '100%'],
|
||
splitLine: {
|
||
show: true,
|
||
},
|
||
scale: true, //自适应
|
||
axisLabel: {
|
||
formatter: function (value, index) {
|
||
return value.toFixed(2);
|
||
},
|
||
}, //可根据实际情况修改y轴保留小数位数
|
||
},
|
||
series: [
|
||
{
|
||
name: this.monitorThings[i].name,
|
||
type: 'line',
|
||
symbol: 'none',
|
||
sampling: 'lttb',
|
||
itemStyle: {
|
||
color: i > 9 ? color[0] : color[i],
|
||
},
|
||
areaStyle: {},
|
||
data: [],
|
||
},
|
||
],
|
||
};
|
||
option && this.chart[i].setOption(option);
|
||
}
|
||
},
|
||
/* 获取当前时间*/
|
||
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;
|
||
},
|
||
},
|
||
};
|
||
</script>
|