add dashboard page
This commit is contained in:
parent
c8e494736e
commit
240f22c51e
|
@ -0,0 +1,33 @@
|
||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
export function getAlarmLevelCount(data) {
|
||||||
|
return request({
|
||||||
|
url: '/alarmInfo/getAlarmLevelCount',
|
||||||
|
method: 'get',
|
||||||
|
params: data || {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRunStatusCount(data) {
|
||||||
|
return request({
|
||||||
|
url: '/device/getRunStatusCount',
|
||||||
|
method: 'get',
|
||||||
|
params: data || {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTypeCount(data) {
|
||||||
|
return request({
|
||||||
|
url: '/device/getTypeCount',
|
||||||
|
method: 'get',
|
||||||
|
params: data || {}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getCount(data) {
|
||||||
|
return request({
|
||||||
|
url: '/alarmInfo/getCount',
|
||||||
|
method: 'get',
|
||||||
|
params: data || {}
|
||||||
|
})
|
||||||
|
}
|
|
@ -69,7 +69,7 @@ export default {
|
||||||
})
|
})
|
||||||
// When there is only one child router, the child router is displayed by default
|
// When there is only one child router, the child router is displayed by default
|
||||||
if (showingChildren.length === 1) {
|
if (showingChildren.length === 1) {
|
||||||
if (children[0].name === 'Overview') {
|
if (children[0].name === 'Overview' || children[0].name === 'Dashboard') {
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -48,7 +48,7 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
showBreadcrumb() {
|
showBreadcrumb() {
|
||||||
const whiteList = ['overview', 'terminal/add', 'terminal/plc', 'data/value', 'configuration/development']
|
const whiteList = ['overview', 'terminal/add', 'terminal/plc', 'data/value', 'configuration/development', 'dashboard']
|
||||||
return whiteList.every((item) => this.$route.path.indexOf(item) === -1)
|
return whiteList.every((item) => this.$route.path.indexOf(item) === -1)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -85,7 +85,6 @@ export const constantRoutes = [
|
||||||
component: () => import('@/views/404'),
|
component: () => import('@/views/404'),
|
||||||
hidden: true
|
hidden: true
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
path: '/overview',
|
path: '/overview',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
|
@ -97,18 +96,29 @@ export const constantRoutes = [
|
||||||
meta: { title: '概览', icon: 'overview' }
|
meta: { title: '概览', icon: 'overview' }
|
||||||
}]
|
}]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/dashboard',
|
||||||
|
component: Layout,
|
||||||
|
meta: {},
|
||||||
|
children: [{
|
||||||
|
path: '',
|
||||||
|
name: 'Dashboard',
|
||||||
|
component: () => import('@/views/dashboard/index'),
|
||||||
|
meta: { title: '设备看板', icon: 'dashboard' }
|
||||||
|
}]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/terminal',
|
path: '/terminal',
|
||||||
component: Layout,
|
component: Layout,
|
||||||
name: 'Terminal',
|
name: 'Terminal',
|
||||||
meta: { title: '设备管理', icon: 'terminal' },
|
meta: { title: '设备管理', icon: 'terminal' },
|
||||||
children: [
|
children: [
|
||||||
{
|
// {
|
||||||
path: 'product',
|
// path: 'product',
|
||||||
name: 'Product',
|
// name: 'Product',
|
||||||
// component: () => import(''),
|
// // component: () => import(''),
|
||||||
meta: { title: '产品分类', disabled: true }
|
// meta: { title: '产品分类', disabled: true }
|
||||||
},
|
// },
|
||||||
{
|
{
|
||||||
path: 'add',
|
path: 'add',
|
||||||
name: 'Add',
|
name: 'Add',
|
||||||
|
@ -177,6 +187,12 @@ export const constantRoutes = [
|
||||||
name: 'Development',
|
name: 'Development',
|
||||||
component: () => import('@/views/configuration/development'),
|
component: () => import('@/views/configuration/development'),
|
||||||
meta: { title: '组态开发' }
|
meta: { title: '组态开发' }
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'transferStation',
|
||||||
|
name: 'TransferStation',
|
||||||
|
component: () => import('@/views/configuration/transferStation'),
|
||||||
|
meta: { title: '变电站' }
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<iframe src="http://localhost:8080/" width="100%" :height="iframeHeight" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
computed: {
|
||||||
|
iframeHeight() {
|
||||||
|
return window.innerHeight - 185
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
|
@ -0,0 +1,429 @@
|
||||||
|
<template>
|
||||||
|
<div class="app-container">
|
||||||
|
<div class="header">
|
||||||
|
<el-col :span="6">
|
||||||
|
<div class="bg_green card">
|
||||||
|
<div class="title">设备总数</div>
|
||||||
|
<span class="num">{{ terminalTotalNum }}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<div class="bg_purple card">
|
||||||
|
<div class="title">运行设备总数</div>
|
||||||
|
<span class="num">{{ runningNum }}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<div class="bg_orange card">
|
||||||
|
<div class="title">报警总数</div>
|
||||||
|
<span class="num">{{ alarmTotalNum }}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="6">
|
||||||
|
<div class="bg_blue card">
|
||||||
|
<div class="title">未处理报警总数</div>
|
||||||
|
<span class="num">{{ unprocessedAlarmNum }}</span>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</div>
|
||||||
|
<div class="body-container">
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="chart-container">
|
||||||
|
<div class="chart-header">设备类型占比</div>
|
||||||
|
<div class="chart" />
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="chart-container">
|
||||||
|
<div class="chart-header">设备告警类型占比</div>
|
||||||
|
<div class="chart" /></div></el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<div class="chart-container">
|
||||||
|
<div class="chart-header">设备运行状态占比</div>
|
||||||
|
<div class="chart" /></div></el-col>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getAlarmLevelCount, getRunStatusCount, getTypeCount, getCount } from '@/api/dashboard'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
myCharts: [],
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
grid: {
|
||||||
|
left: 0,
|
||||||
|
right: 0
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
bottom: '5%',
|
||||||
|
left: 'center'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item'
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
type: 'pie',
|
||||||
|
center: ['50%', '40%'],
|
||||||
|
radius: ['30%', '40%'],
|
||||||
|
clockwise: true,
|
||||||
|
avoidLabelOverlap: true,
|
||||||
|
color: ['#50C4F4', '#C37EFA', '#14C9C9', '#165DFF', '#F7BA1E'],
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
position: 'outside',
|
||||||
|
formatter: '{a|{b}:{d}%}\n',
|
||||||
|
rich: {
|
||||||
|
a: {
|
||||||
|
padding: [0, 0, -20, 0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
normal: {
|
||||||
|
length: 10,
|
||||||
|
length2: 10,
|
||||||
|
lineStyle: {
|
||||||
|
width: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
scaleSize: 10
|
||||||
|
},
|
||||||
|
data: [{
|
||||||
|
'name': 'RV400-NPU16T-5G-AR100',
|
||||||
|
'value': 1
|
||||||
|
}, {
|
||||||
|
'name': 'RV400-NPU4T-5G-SR100',
|
||||||
|
'value': 2
|
||||||
|
}, {
|
||||||
|
'name': 'M528-A800-5G-HM100',
|
||||||
|
'value': 3
|
||||||
|
}, {
|
||||||
|
'name': 'RV400-4G-FR100',
|
||||||
|
'value': 4
|
||||||
|
}, {
|
||||||
|
'name': 'M168-LoRa-FM100',
|
||||||
|
'value': 5
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
legend: {
|
||||||
|
bottom: '5%',
|
||||||
|
left: 'center'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item'
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: '设备告警类型占比',
|
||||||
|
type: 'pie',
|
||||||
|
radius: '40%',
|
||||||
|
center: ['50%', '40%'],
|
||||||
|
clockwise: true,
|
||||||
|
data: [{
|
||||||
|
value: 1,
|
||||||
|
name: '紧急'
|
||||||
|
}, {
|
||||||
|
value: 2,
|
||||||
|
name: '重要'
|
||||||
|
}, {
|
||||||
|
value: 3,
|
||||||
|
name: '次要'
|
||||||
|
}, {
|
||||||
|
value: 4,
|
||||||
|
name: '提示'
|
||||||
|
}],
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
position: 'outside',
|
||||||
|
formatter: '{a|{b}}\n{b|{d}%}',
|
||||||
|
rich: {
|
||||||
|
a: {
|
||||||
|
color: '#606266',
|
||||||
|
fontWeight: 500
|
||||||
|
},
|
||||||
|
b: {
|
||||||
|
padding: [5, 0, 0, 0],
|
||||||
|
color: '#606266',
|
||||||
|
fontWeight: 500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
normal: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
scaleSize: 10
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
color: [
|
||||||
|
'#FF0000',
|
||||||
|
'#F7BA1E',
|
||||||
|
'#00B5C0',
|
||||||
|
'#F3F3F3'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
legend: {
|
||||||
|
bottom: '5%',
|
||||||
|
left: 'center'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item'
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
name: '设备运行状态占比',
|
||||||
|
type: 'pie',
|
||||||
|
radius: '40%',
|
||||||
|
center: ['50%', '40%'],
|
||||||
|
clockwise: true,
|
||||||
|
data: [{
|
||||||
|
value: 1,
|
||||||
|
name: '运行'
|
||||||
|
}, {
|
||||||
|
value: 2,
|
||||||
|
name: '警告'
|
||||||
|
}, {
|
||||||
|
value: 3,
|
||||||
|
name: '待机'
|
||||||
|
}],
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
position: 'outside',
|
||||||
|
formatter: '{a|{b}}\n{b|{d}%}',
|
||||||
|
rich: {
|
||||||
|
a: {
|
||||||
|
color: '#606266',
|
||||||
|
fontWeight: 500
|
||||||
|
},
|
||||||
|
b: {
|
||||||
|
padding: [5, 0, 0, 0],
|
||||||
|
color: '#606266',
|
||||||
|
fontWeight: 500
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
normal: {
|
||||||
|
show: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
scaleSize: 10
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
color: [
|
||||||
|
'#33BFFF',
|
||||||
|
'#F3F3F3',
|
||||||
|
'#F25656'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
animationIndex: [0, 0, 0],
|
||||||
|
index: 0,
|
||||||
|
alarmTotalNum: 0,
|
||||||
|
runningNum: 0,
|
||||||
|
terminalTotalNum: 0,
|
||||||
|
unprocessedAlarmNum: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
const doms = document.getElementsByClassName('chart')
|
||||||
|
doms.forEach(dom => {
|
||||||
|
this.myCharts.push(this.$echarts.init(dom))
|
||||||
|
})
|
||||||
|
this.getData()
|
||||||
|
window.addEventListener('resize', () => {
|
||||||
|
this.myCharts.forEach(chart => {
|
||||||
|
chart.resize()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
setInterval(this.animation, 3000)
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getData() {
|
||||||
|
getCount().then(res => {
|
||||||
|
this.unprocessedAlarmNum = res.data
|
||||||
|
})
|
||||||
|
getAlarmLevelCount().then(res => {
|
||||||
|
const level0Num = res.data.filter(item => item.alarm_level === 0)[0]?.count || 0
|
||||||
|
const level1Num = res.data.filter(item => item.alarm_level === 1)[0]?.count || 0
|
||||||
|
const level2Num = res.data.filter(item => item.alarm_level === 2)[0]?.count || 0
|
||||||
|
const level3Num = res.data.filter(item => item.alarm_level === 3)[0]?.count || 0
|
||||||
|
const alarmData = [{
|
||||||
|
value: level0Num,
|
||||||
|
name: '紧急'
|
||||||
|
}, {
|
||||||
|
value: level1Num,
|
||||||
|
name: '重要'
|
||||||
|
}, {
|
||||||
|
value: level2Num,
|
||||||
|
name: '次要'
|
||||||
|
}, {
|
||||||
|
value: level3Num,
|
||||||
|
name: '提示'
|
||||||
|
}]
|
||||||
|
this.alarmTotalNum = res.data.reduce((pre, cur) => pre + cur.count, 0)
|
||||||
|
this.options[1].series[0].data = alarmData
|
||||||
|
})
|
||||||
|
getRunStatusCount().then(res => {
|
||||||
|
const status0Num = res.data.filter(item => item.runstatus === 0)[0]?.count || 0
|
||||||
|
const status1Num = res.data.filter(item => item.runstatus === 1)[0]?.count || 0
|
||||||
|
const status2Num = res.data.filter(item => item.runstatus === 2)[0]?.count || 0
|
||||||
|
const runstatusData = [{
|
||||||
|
value: status0Num,
|
||||||
|
name: '运行'
|
||||||
|
}, {
|
||||||
|
value: status1Num,
|
||||||
|
name: '待机'
|
||||||
|
}, {
|
||||||
|
value: status2Num,
|
||||||
|
name: '警告'
|
||||||
|
}]
|
||||||
|
this.runningNum = status0Num
|
||||||
|
this.options[2].series[0].data = runstatusData
|
||||||
|
})
|
||||||
|
getTypeCount().then(res => {
|
||||||
|
const typeData = res.data.map(item => {
|
||||||
|
return { name: item.type, value: item.count }
|
||||||
|
})
|
||||||
|
this.options[0].series[0].data = typeData
|
||||||
|
this.terminalTotalNum = res.data.reduce((pre, cur) => pre + cur.count, 0)
|
||||||
|
})
|
||||||
|
this.myCharts.forEach((chart, index) => {
|
||||||
|
chart.setOption(this.options[index])
|
||||||
|
})
|
||||||
|
},
|
||||||
|
animation() {
|
||||||
|
this.myCharts.forEach((myChart, i) => {
|
||||||
|
const maxIndex = this.options[i].series[0].data.length - 1
|
||||||
|
myChart.dispatchAction({
|
||||||
|
type: 'hideTip',
|
||||||
|
seriesIndex: 0,
|
||||||
|
dataIndex: this.animationIndex[i]
|
||||||
|
})
|
||||||
|
// 显示提示框
|
||||||
|
myChart.dispatchAction({
|
||||||
|
type: 'showTip',
|
||||||
|
seriesIndex: 0,
|
||||||
|
dataIndex: this.animationIndex[i]
|
||||||
|
})
|
||||||
|
// 取消高亮指定的数据图形
|
||||||
|
myChart.dispatchAction({
|
||||||
|
type: 'downplay',
|
||||||
|
seriesIndex: 0,
|
||||||
|
dataIndex: this.animationIndex[i] == 0 ? maxIndex : this.animationIndex[i] - 1
|
||||||
|
})
|
||||||
|
myChart.dispatchAction({
|
||||||
|
type: 'highlight',
|
||||||
|
seriesIndex: 0,
|
||||||
|
dataIndex: this.animationIndex[i]
|
||||||
|
})
|
||||||
|
this.animationIndex[i]++
|
||||||
|
if (this.animationIndex[i] > maxIndex) {
|
||||||
|
this.animationIndex[i] = 0
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
fun() {
|
||||||
|
const myChart = this.myCharts[0]
|
||||||
|
myChart.dispatchAction({
|
||||||
|
type: 'hideTip',
|
||||||
|
seriesIndex: 0,
|
||||||
|
dataIndex: this.index
|
||||||
|
})
|
||||||
|
// 显示提示框
|
||||||
|
myChart.dispatchAction({
|
||||||
|
type: 'showTip',
|
||||||
|
seriesIndex: 0,
|
||||||
|
dataIndex: this.index
|
||||||
|
})
|
||||||
|
// 取消高亮指定的数据图形
|
||||||
|
myChart.dispatchAction({
|
||||||
|
type: 'downplay',
|
||||||
|
seriesIndex: 0,
|
||||||
|
dataIndex: this.index == 0 ? 3 : this.index - 1
|
||||||
|
})
|
||||||
|
myChart.dispatchAction({
|
||||||
|
type: 'highlight',
|
||||||
|
seriesIndex: 0,
|
||||||
|
dataIndex: this.index
|
||||||
|
})
|
||||||
|
this.index++
|
||||||
|
if (this.index > 3) {
|
||||||
|
this.index = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.card {
|
||||||
|
margin: 20px;
|
||||||
|
position: relative;
|
||||||
|
color: #ffffff;
|
||||||
|
box-shadow: 0px 2px 5px 0px rgba(38, 51, 77, 0.03);
|
||||||
|
border-radius: 10px;
|
||||||
|
height: 160px;
|
||||||
|
font-family: Roboto-Bold, Roboto;
|
||||||
|
.title {
|
||||||
|
position: absolute;
|
||||||
|
left: 20px;
|
||||||
|
top: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.num {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
font-size: 40px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.chart-container {
|
||||||
|
margin: 20px;
|
||||||
|
box-shadow: 0px 2px 5px 0px rgba(38, 51, 77, 0.03);
|
||||||
|
border-radius: 10px;
|
||||||
|
border: 1px solid #e9e9e9;
|
||||||
|
height: 500px;
|
||||||
|
.chart-header {
|
||||||
|
height: 60px;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 14px;
|
||||||
|
font-family: Roboto-Bold, Roboto;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #4d5e80;
|
||||||
|
border-bottom: 1px solid #F5F6F7;
|
||||||
|
padding-left: 25px;
|
||||||
|
padding-top: 20px;
|
||||||
|
}
|
||||||
|
.chart{
|
||||||
|
width: 100%;
|
||||||
|
height: calc(100% - 60px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.bg_green {
|
||||||
|
background-color: #29cc39;
|
||||||
|
}
|
||||||
|
.bg_purple {
|
||||||
|
background-color: #8833ff;
|
||||||
|
}
|
||||||
|
.bg_orange {
|
||||||
|
background-color: #ff6633;
|
||||||
|
}
|
||||||
|
.bg_blue {
|
||||||
|
background-color: #33bfff;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue