|
|
|
@ -1,4 +1,5 @@ |
|
|
|
<template> |
|
|
|
<template class=""> |
|
|
|
|
|
|
|
<div class="index-box"> |
|
|
|
<div id="app" class="dashboard" style="overflow-x: hidden;"> |
|
|
|
<div id="app" class="dashboard" style="overflow-x: hidden;"> |
|
|
|
|
|
|
|
|
|
|
|
<div class="header"> |
|
|
|
<div class="header"> |
|
|
|
@ -36,8 +37,8 @@ |
|
|
|
<div v-for="floor in floorDeviceDistribution" |
|
|
|
<div v-for="floor in floorDeviceDistribution" |
|
|
|
:key="floor.level" |
|
|
|
:key="floor.level" |
|
|
|
class="floor-device-card"> |
|
|
|
class="floor-device-card"> |
|
|
|
<div class="floor-level">{{ floor.level }}层</div> |
|
|
|
<div class="floor-level">{{ floor.floor }}</div> |
|
|
|
<div class="floor-count">{{ floor.count }}台</div> |
|
|
|
<div class="floor-count">{{ floor.count }}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
@ -48,7 +49,7 @@ |
|
|
|
<div class="right-panel"> |
|
|
|
<div class="right-panel"> |
|
|
|
|
|
|
|
|
|
|
|
<div class="panel"> |
|
|
|
<div class="panel"> |
|
|
|
<div class="panel-title">设备类型分布</div> |
|
|
|
<div class="panel-title">设备信息统计</div> |
|
|
|
<div class="device-stats-container"> |
|
|
|
<div class="device-stats-container"> |
|
|
|
<div class="device-stat-item"> |
|
|
|
<div class="device-stat-item"> |
|
|
|
<div class="device-stat-value">{{ totalDevices }}</div> |
|
|
|
<div class="device-stat-value">{{ totalDevices }}</div> |
|
|
|
@ -107,11 +108,11 @@ |
|
|
|
class="warning-item" |
|
|
|
class="warning-item" |
|
|
|
@click="showDeviceDetail(warning)"> |
|
|
|
@click="showDeviceDetail(warning)"> |
|
|
|
<div class="warning-header"> |
|
|
|
<div class="warning-header"> |
|
|
|
<span :class="['warning-type', `level-${warning.level}`]">{{ warning.name }}</span> |
|
|
|
<span :class="['warning-type', `level-${warning.displayLevel}`]">{{ warning.name }}</span> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
<div class="warning-time">预警时间: {{ warning.time }}</div> |
|
|
|
<div class="warning-time">预警时间: {{ warning.time }}</div> |
|
|
|
<div class="warning-position">设备位置: {{ warning.location }}</div> |
|
|
|
<div class="warning-position">设备位置: {{ warning.location }}</div> |
|
|
|
<div class="warning-detail">设备编号 {{ warning.deviceId }} 设备名称{{ warning.deviceName }}{{ warning.description }}</div> |
|
|
|
<div class="warning-detail">预警信息: {{ warning.ruleName }}</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</el-scrollbar> |
|
|
|
</el-scrollbar> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
@ -236,10 +237,12 @@ |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
</div> |
|
|
|
</template> |
|
|
|
</template> |
|
|
|
|
|
|
|
|
|
|
|
<script> |
|
|
|
<script> |
|
|
|
import { getInfo, historyQuery } from "@/api/inMonitoring/devicesState" |
|
|
|
import { getInfo, historyQuery } from "@/api/inMonitoring/devicesState" |
|
|
|
|
|
|
|
import { byEquType, statistic, alertMessageTimes, floorStatistic } from "@/api/index/index" |
|
|
|
import "@riophae/vue-treeselect/dist/vue-treeselect.css" |
|
|
|
import "@riophae/vue-treeselect/dist/vue-treeselect.css" |
|
|
|
import "splitpanes/dist/splitpanes.css" |
|
|
|
import "splitpanes/dist/splitpanes.css" |
|
|
|
import * as echarts from 'echarts' |
|
|
|
import * as echarts from 'echarts' |
|
|
|
@ -283,18 +286,7 @@ export default { |
|
|
|
], |
|
|
|
], |
|
|
|
currentFloor: 1, |
|
|
|
currentFloor: 1, |
|
|
|
floorDeviceDistribution: [ |
|
|
|
floorDeviceDistribution: [ |
|
|
|
{ level: 1, count: 15 }, |
|
|
|
{ floor: "1层", count: 6 }, |
|
|
|
{ level: 2, count: 18 }, |
|
|
|
|
|
|
|
{ level: 3, count: 22 }, |
|
|
|
|
|
|
|
{ level: 4, count: 14 }, |
|
|
|
|
|
|
|
{ level: 5, count: 16 }, |
|
|
|
|
|
|
|
{ level: 6, count: 13 }, |
|
|
|
|
|
|
|
{ level: 7, count: 17 }, |
|
|
|
|
|
|
|
{ level: 8, count: 11 }, |
|
|
|
|
|
|
|
{ level: 9, count: 12 }, |
|
|
|
|
|
|
|
{ level: 10, count: 9 }, |
|
|
|
|
|
|
|
{ level: 11, count: 14 }, |
|
|
|
|
|
|
|
{ level: 12, count: 16 } |
|
|
|
|
|
|
|
], |
|
|
|
], |
|
|
|
floors: [ |
|
|
|
floors: [ |
|
|
|
{ |
|
|
|
{ |
|
|
|
@ -401,7 +393,13 @@ export default { |
|
|
|
barChart: null, |
|
|
|
barChart: null, |
|
|
|
pieChart: null, |
|
|
|
pieChart: null, |
|
|
|
historyChart: null, |
|
|
|
historyChart: null, |
|
|
|
highlightedDevice: null |
|
|
|
highlightedDevice: null, |
|
|
|
|
|
|
|
totalDevices: 0, |
|
|
|
|
|
|
|
onlineDevices: 0, |
|
|
|
|
|
|
|
deviceTypeData: [], |
|
|
|
|
|
|
|
alertStatistics: {}, |
|
|
|
|
|
|
|
alertTimes: {}, |
|
|
|
|
|
|
|
floorDeviceDistribution: [] |
|
|
|
}}, |
|
|
|
}}, |
|
|
|
computed: { |
|
|
|
computed: { |
|
|
|
// 直接使用deviceStatus,不再需要过滤计算属性 |
|
|
|
// 直接使用deviceStatus,不再需要过滤计算属性 |
|
|
|
@ -410,10 +408,32 @@ export default { |
|
|
|
if (this.warningLevelFilter === 'all') { |
|
|
|
if (this.warningLevelFilter === 'all') { |
|
|
|
return this.deviceWarnings; |
|
|
|
return this.deviceWarnings; |
|
|
|
} |
|
|
|
} |
|
|
|
return this.deviceWarnings.filter(warning => |
|
|
|
|
|
|
|
(this.warningLevelFilter === 'error' && warning.level === 'error') || |
|
|
|
// 根据不同的过滤条件进行处理 |
|
|
|
(this.warningLevelFilter === 'warning' && warning.level === 'warning') |
|
|
|
switch (this.warningLevelFilter) { |
|
|
|
); |
|
|
|
case 'level1': |
|
|
|
|
|
|
|
// 过滤1级预警(level为1) |
|
|
|
|
|
|
|
return this.deviceWarnings.filter(warning => warning.level === 1 || warning.level === '1'); |
|
|
|
|
|
|
|
case 'level2': |
|
|
|
|
|
|
|
// 过滤2级预警(level为2) |
|
|
|
|
|
|
|
return this.deviceWarnings.filter(warning => warning.level === 2 || warning.level === '2'); |
|
|
|
|
|
|
|
case 'level3': |
|
|
|
|
|
|
|
// 过滤3级预警(level为3) |
|
|
|
|
|
|
|
return this.deviceWarnings.filter(warning => warning.level === 3 || warning.level === '3' || warning.level === 'error'); |
|
|
|
|
|
|
|
case 'annual': |
|
|
|
|
|
|
|
case 'monthly': |
|
|
|
|
|
|
|
// 按时间范围过滤(这里可以根据实际需求实现时间过滤逻辑) |
|
|
|
|
|
|
|
// 暂时返回所有数据 |
|
|
|
|
|
|
|
return this.deviceWarnings; |
|
|
|
|
|
|
|
case 'error': |
|
|
|
|
|
|
|
// 过滤错误级别的预警 |
|
|
|
|
|
|
|
return this.deviceWarnings.filter(warning => warning.level > 2 || warning.level === 'error'); |
|
|
|
|
|
|
|
case 'warning': |
|
|
|
|
|
|
|
// 过滤警告级别的预警 |
|
|
|
|
|
|
|
return this.deviceWarnings.filter(warning => warning.level <= 2 || warning.level === 'warning'); |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
return this.deviceWarnings; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
mounted() { |
|
|
|
mounted() { |
|
|
|
@ -440,6 +460,15 @@ export default { |
|
|
|
// 首次进入时自动加载设备状态数据 |
|
|
|
// 首次进入时自动加载设备状态数据 |
|
|
|
this.refreshDeviceStatus(); |
|
|
|
this.refreshDeviceStatus(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 加载设备类型统计数据 |
|
|
|
|
|
|
|
this.loadDeviceTypeData(); |
|
|
|
|
|
|
|
// 加载预警统计数据 |
|
|
|
|
|
|
|
this.loadAlertStatistics(); |
|
|
|
|
|
|
|
// 加载预警次数统计 |
|
|
|
|
|
|
|
this.loadAlertTimes(); |
|
|
|
|
|
|
|
// 加载楼层设备分布 |
|
|
|
|
|
|
|
this.loadFloorDeviceDistribution(); |
|
|
|
|
|
|
|
|
|
|
|
// 定期更新设备状态数据(每分钟更新一次) |
|
|
|
// 定期更新设备状态数据(每分钟更新一次) |
|
|
|
setInterval(() => { |
|
|
|
setInterval(() => { |
|
|
|
this.refreshDeviceStatus(); |
|
|
|
this.refreshDeviceStatus(); |
|
|
|
@ -480,7 +509,140 @@ export default { |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
loadDeviceTypeData() { |
|
|
|
|
|
|
|
byEquType().then(response => { |
|
|
|
|
|
|
|
const data = response.data || {}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 直接从返回数据中获取设备总数和在线设备数 |
|
|
|
|
|
|
|
this.totalDevices = data.totalCount || 0; |
|
|
|
|
|
|
|
this.onlineDevices = data.onlineCount || 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 准备饼图数据,从list数组中提取 |
|
|
|
|
|
|
|
const colors = ['#4dabff', '#62f7ff', '#ffa726', '#4CAF50', '#a0aec0', '#ff6b6b', '#95e1d3']; |
|
|
|
|
|
|
|
this.deviceTypeData = (data.list || []).map((item, index) => ({ |
|
|
|
|
|
|
|
name: item.equTypeName || '未知类型', |
|
|
|
|
|
|
|
value: item.count || 0, |
|
|
|
|
|
|
|
itemStyle: { color: colors[index % colors.length] } |
|
|
|
|
|
|
|
})); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 更新饼图 |
|
|
|
|
|
|
|
this.initPieChart(); |
|
|
|
|
|
|
|
}).catch(error => { |
|
|
|
|
|
|
|
console.error('获取设备类型数据失败:', error); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 加载预警统计数据 |
|
|
|
|
|
|
|
loadAlertStatistics() { |
|
|
|
|
|
|
|
statistic().then(response => { |
|
|
|
|
|
|
|
this.alertStatistics = response.data || {}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 处理rows数据并更新deviceWarnings |
|
|
|
|
|
|
|
if (response.rows && Array.isArray(response.rows)) { |
|
|
|
|
|
|
|
this.deviceWarnings = response.rows.map((row, index) => ({ |
|
|
|
|
|
|
|
id: row.id || index + 1, |
|
|
|
|
|
|
|
name: row.name || '未命名设备', |
|
|
|
|
|
|
|
level: row.level, // 保留原始的level值 |
|
|
|
|
|
|
|
displayLevel: row.level > 2 ? 'error' : 'warning', // 用于显示的级别 |
|
|
|
|
|
|
|
time: row.occurTime ? this.formatOccurTime(row.occurTime) : '', |
|
|
|
|
|
|
|
location: row.location || '未知位置', |
|
|
|
|
|
|
|
ruleName: row.ruleName || '-', |
|
|
|
|
|
|
|
message: row.message || '-' |
|
|
|
|
|
|
|
})); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}).catch(error => { |
|
|
|
|
|
|
|
console.error('获取预警统计数据失败:', error); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 格式化occurTime时间 |
|
|
|
|
|
|
|
formatOccurTime(timeString) { |
|
|
|
|
|
|
|
if (!timeString) return ''; |
|
|
|
|
|
|
|
const date = new Date(timeString); |
|
|
|
|
|
|
|
if (isNaN(date.getTime())) return timeString; |
|
|
|
|
|
|
|
return date.toLocaleString('zh-CN', { |
|
|
|
|
|
|
|
year: 'numeric', |
|
|
|
|
|
|
|
month: '2-digit', |
|
|
|
|
|
|
|
day: '2-digit', |
|
|
|
|
|
|
|
hour: '2-digit', |
|
|
|
|
|
|
|
minute: '2-digit', |
|
|
|
|
|
|
|
second: '2-digit', |
|
|
|
|
|
|
|
hour12: false |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 加载预警次数统计 |
|
|
|
|
|
|
|
loadAlertTimes() { |
|
|
|
|
|
|
|
alertMessageTimes().then(response => { |
|
|
|
|
|
|
|
this.alertTimes = response.data || {}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 根据接口返回的数据更新warningStats |
|
|
|
|
|
|
|
if (response.code === 200 && response.data) { |
|
|
|
|
|
|
|
const data = response.data; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 更新年度和月度预警数据 |
|
|
|
|
|
|
|
this.warningStats.annual = data.yearCount || 0; |
|
|
|
|
|
|
|
this.warningStats.monthly = data.monthCount || 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 从levelCount中提取1-3级预警数据 |
|
|
|
|
|
|
|
if (data.levelCount && Array.isArray(data.levelCount)) { |
|
|
|
|
|
|
|
// 初始化1-3级预警数据为0 |
|
|
|
|
|
|
|
this.warningStats.level1 = 0; |
|
|
|
|
|
|
|
this.warningStats.level2 = 0; |
|
|
|
|
|
|
|
this.warningStats.level3 = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 根据level字段更新对应级别的数据 |
|
|
|
|
|
|
|
data.levelCount.forEach(item => { |
|
|
|
|
|
|
|
if (item.level === '1') { |
|
|
|
|
|
|
|
this.warningStats.level1 = item.count || 0; |
|
|
|
|
|
|
|
} else if (item.level === '2') { |
|
|
|
|
|
|
|
this.warningStats.level2 = item.count || 0; |
|
|
|
|
|
|
|
} else if (item.level === '3') { |
|
|
|
|
|
|
|
this.warningStats.level3 = item.count || 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}).catch(error => { |
|
|
|
|
|
|
|
console.error('获取预警次数数据失败:', error); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 加载楼层设备分布 |
|
|
|
|
|
|
|
loadFloorDeviceDistribution() { |
|
|
|
|
|
|
|
floorStatistic().then(response => { |
|
|
|
|
|
|
|
// 创建1-12层的默认数组,初始count为0,使用floor字段存储楼层名称 |
|
|
|
|
|
|
|
const floorData = []; |
|
|
|
|
|
|
|
for (let i = 1; i <= 12; i++) { |
|
|
|
|
|
|
|
floorData.push({ floor: i + '层', count: 0 }); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果API返回了数据,更新对应楼层的count值 |
|
|
|
|
|
|
|
if (response && response.code === 200 && response.data && Array.isArray(response.data)) { |
|
|
|
|
|
|
|
response.data.forEach(item => { |
|
|
|
|
|
|
|
// 查找对应的楼层索引 |
|
|
|
|
|
|
|
const index = floorData.findIndex(f => f.floor === item.floor); |
|
|
|
|
|
|
|
if (index !== -1) { |
|
|
|
|
|
|
|
floorData[index].count = item.count || 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.floorDeviceDistribution = floorData; |
|
|
|
|
|
|
|
}).catch(error => { |
|
|
|
|
|
|
|
console.error('获取楼层设备分布失败:', error); |
|
|
|
|
|
|
|
// 出错时仍显示1-12层,count为0 |
|
|
|
|
|
|
|
const floorData = []; |
|
|
|
|
|
|
|
for (let i = 1; i <= 12; i++) { |
|
|
|
|
|
|
|
floorData.push({ floor: i + '层', count: 0 }); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
this.floorDeviceDistribution = floorData; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
|
|
initPieChart() { |
|
|
|
initPieChart() { |
|
|
|
|
|
|
|
if (!this.$refs.pieChart) return; |
|
|
|
|
|
|
|
|
|
|
|
this.pieChart = echarts.init(this.$refs.pieChart); |
|
|
|
this.pieChart = echarts.init(this.$refs.pieChart); |
|
|
|
|
|
|
|
|
|
|
|
const option = { |
|
|
|
const option = { |
|
|
|
@ -523,12 +685,8 @@ export default { |
|
|
|
labelLine: { |
|
|
|
labelLine: { |
|
|
|
show: false |
|
|
|
show: false |
|
|
|
}, |
|
|
|
}, |
|
|
|
data: [ |
|
|
|
data: this.deviceTypeData.length > 0 ? this.deviceTypeData : [ |
|
|
|
{ value: 35, name: '服务器', itemStyle: { color: '#4dabff' } }, |
|
|
|
{ value: 0, name: '暂无数据', itemStyle: { color: '#a0aec0' } } |
|
|
|
{ value: 25, name: '网络设备', itemStyle: { color: '#62f7ff' } }, |
|
|
|
|
|
|
|
{ value: 18, name: '存储设备', itemStyle: { color: '#ffa726' } }, |
|
|
|
|
|
|
|
{ value: 15, name: '安全设备', itemStyle: { color: '#4CAF50' } }, |
|
|
|
|
|
|
|
{ value: 7, name: '其他设备', itemStyle: { color: '#a0aec0' } } |
|
|
|
|
|
|
|
] |
|
|
|
] |
|
|
|
} |
|
|
|
} |
|
|
|
] |
|
|
|
] |
|
|
|
@ -903,10 +1061,11 @@ export default { |
|
|
|
font-family: "Microsoft YaHei", sans-serif; |
|
|
|
font-family: "Microsoft YaHei", sans-serif; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.dashboard { |
|
|
|
.index-box { |
|
|
|
background-color: #0a1633; |
|
|
|
background-color: #0a1633; |
|
|
|
color: #e6e6e6; |
|
|
|
color: #e6e6e6; |
|
|
|
overflow: hidden; |
|
|
|
overflow: hidden; |
|
|
|
|
|
|
|
padding: 1.5vh 1.5vw; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
.dashboard { |
|
|
|
.dashboard { |
|
|
|
|