|
|
<template>
|
|
|
<div>
|
|
|
<div class="bg">
|
|
|
<div class="title">正道能源监控系统</div>
|
|
|
<div class="time">{{ clockText }}</div>
|
|
|
<div class="subTitle" style="top: 13.5%;left: 6%;">设备总览</div>
|
|
|
<div class="subTitle" style="top: 42.3%;left: 6%">本月{{ currentTypeMeta.rankName }}排行</div>
|
|
|
<div class="subTitle" style="top: 71.2%;left: 6%">本月{{ currentTypeMeta.rankName }}分项统计</div>
|
|
|
<div class="subTitle" style="top: 71.2%;left: 30.5%">能耗统计</div>
|
|
|
<div class="subTitle" style="top: 71.2%;left: 78%">实时预警</div>
|
|
|
<div class="subTitle" style="top: 13.5%;left: 78%">近7天能耗统计</div>
|
|
|
<div class="select">
|
|
|
<div class="selectItem" style="left: 57%" :class="{'active': selectData === 'day'}"
|
|
|
@click="selectChange('day')">
|
|
|
本 日
|
|
|
</div>
|
|
|
<div class="selectItem" style="left: calc(57% + 4vw)" :class="{'active': selectData === 'month'}"
|
|
|
@click="selectChange('month')">
|
|
|
本 月
|
|
|
</div>
|
|
|
<!-- <div class="selectItem" style="left: calc(57% + 8vw)" :class="{'active': selectData === '3'}"-->
|
|
|
<!-- @click="selectChange('3')">-->
|
|
|
<!-- 本季度-->
|
|
|
<!-- </div>-->
|
|
|
<div class="selectItem" style="left: calc(57% + 8vw)" :class="{'active': selectData === 'year'}"
|
|
|
@click="selectChange('year')">
|
|
|
本年度
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="typeSelect">
|
|
|
<div class="selectItem" style="width:2.4vw;left: calc(57%)" :class="{'active': typeData === '4'}"
|
|
|
@click="typeChange('4')">
|
|
|
蒸汽
|
|
|
</div>
|
|
|
<div class="selectItem" style="width:2.4vw;left: calc(57% + 2.4vw)" :class="{'active': typeData === '3'}"
|
|
|
@click="typeChange('3')">
|
|
|
水
|
|
|
</div>
|
|
|
<div class="selectItem" style="width:3.8vw;left: calc(57% + 4.8vw)" :class="{'active': typeData === '5'}"
|
|
|
@click="typeChange('5')">
|
|
|
压缩空气
|
|
|
</div>
|
|
|
<div class="selectItem" style="width:3vw;left: calc(57% + 8.6vw)" :class="{'active': typeData === '6'}"
|
|
|
@click="typeChange('6')">
|
|
|
氮气
|
|
|
</div>
|
|
|
<div class="selectItem" style="width:3vw;left: calc(57% + 11.6vw)" :class="{'active': typeData === '2'}"
|
|
|
@click="typeChange('2')">
|
|
|
电
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="sbzl">
|
|
|
<div class="num" style="top: 22%;left: 7%;">{{ deviceOverviewData.deviceSum }}</div>
|
|
|
<div class="num" style="top: 22%;left: 14.3%">{{ deviceOverviewData.waterSum }}</div>
|
|
|
<div class="num" style="top: 22%;left: 21.7%">{{ deviceOverviewData.dnbSum }}</div>
|
|
|
<div class="num" style="top: 31%;left: 7%">{{ deviceOverviewData.airSum }}</div>
|
|
|
<div class="num" style="top: 31%;left: 14.3%">{{ deviceOverviewData.steamSum }}</div>
|
|
|
<div class="num" style="top: 31%;left: 21.7%">{{ deviceOverviewData.nitrogenSum }}</div>
|
|
|
<div class="text" style="top: 22.2%;left: 7%">网关总数</div>
|
|
|
<div class="text" style="top: 22.2%;left: 14.3%">水表总数</div>
|
|
|
<div class="text" style="top: 22.2%;left: 21.7%">电表总数</div>
|
|
|
<div class="text" style="top: 31.2%;left: 7%">压缩空气表总数</div>
|
|
|
<div class="text" style="top: 31.2%;left: 14.3%">蒸汽表总数</div>
|
|
|
<div class="text" style="top: 31.2%;left: 21.7%">氮气表总数</div>
|
|
|
</div>
|
|
|
<div class="zxnr">
|
|
|
<div class="text" style="top: 18.5%;left: 45%;">用电量(kwh)</div>
|
|
|
<div class="text" style="top: 18.5%;left: 57%;">用水量(m³)</div>
|
|
|
<div class="text" style="top: 30%;left: 38.5%;">用压缩空气量(m³)</div>
|
|
|
<div class="text" style="top: 31.5%;left: 51.5%;">用蒸汽量(m³)</div>
|
|
|
<div class="text" style="top: 30%;left: 65%;">用氮气量(m³)</div>
|
|
|
<div class="num" style="top: 20.3%;left: 45%">{{ fiveConsumptionStatisticsData.dnbSum }}</div>
|
|
|
<div class="num" style="top: 20.3%;left: 57%;">{{ fiveConsumptionStatisticsData.waterSum }}</div>
|
|
|
<div class="num" style="top: 31.8%;left: 38.5%">{{ fiveConsumptionStatisticsData.airSum }}</div>
|
|
|
<div class="num" style="top: 33.3%;left: 51.5%">{{ fiveConsumptionStatisticsData.steamSum }}</div>
|
|
|
<div class="num" style="top: 31.8%;left: 65%">{{ fiveConsumptionStatisticsData.nitrogenSum }}</div>
|
|
|
<div class="qs" style="top: 23.3%;left: 45%">
|
|
|
<span>{{
|
|
|
fiveConsumptionStatisticsData.dnbRate > 0 ? '上升' : '下降'
|
|
|
}}{{ Math.abs(fiveConsumptionStatisticsData.dnbRate) }}%</span>
|
|
|
<div :class="fiveConsumptionStatisticsData.dnbRate > 0 ? 'img':'img1'"></div>
|
|
|
</div>
|
|
|
<div class="qs" style="top: 23.3%;left: 57%;">
|
|
|
<span>{{
|
|
|
fiveConsumptionStatisticsData.waterRate > 0 ? '上升' : '下降'
|
|
|
}}{{ Math.abs(fiveConsumptionStatisticsData.waterRate) }}%</span>
|
|
|
<div :class="fiveConsumptionStatisticsData.waterRate > 0 ? 'img':'img1'"></div>
|
|
|
</div>
|
|
|
<div class="qs" style="top: 34.8%;left: 38.5%">
|
|
|
<span>{{
|
|
|
fiveConsumptionStatisticsData.airRate > 0 ? '上升' : '下降'
|
|
|
}}{{ Math.abs(fiveConsumptionStatisticsData.airRate) }}%</span>
|
|
|
<div :class="fiveConsumptionStatisticsData.airRate > 0 ? 'img':'img1'"></div>
|
|
|
</div>
|
|
|
<div class="qs" style="top: 36.3%;left: 51.5%">
|
|
|
<span>{{
|
|
|
fiveConsumptionStatisticsData.steamRate > 0 ? '上升' : '下降'
|
|
|
}}{{ Math.abs(fiveConsumptionStatisticsData.steamRate) }}%</span>
|
|
|
<div :class="fiveConsumptionStatisticsData.steamRate > 0 ? 'img':'img1'"></div>
|
|
|
</div>
|
|
|
<div class="qs" style="top: 34.8%;left: 65%">
|
|
|
<span>{{
|
|
|
fiveConsumptionStatisticsData.nitrogenRate > 0 ? '上升' : '下降'
|
|
|
}}{{ Math.abs(fiveConsumptionStatisticsData.nitrogenRate) }}%</span>
|
|
|
<div :class="fiveConsumptionStatisticsData.nitrogenRate > 0 ? 'img':'img1'"></div>
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="table1">
|
|
|
<div class="h1" style="line-height: 1vw">
|
|
|
<div class="scrollTable" :style="getTableCellStyle(true)">
|
|
|
设备名称
|
|
|
</div>
|
|
|
<div
|
|
|
class="scrollTable"
|
|
|
v-for="column in currentTypeMeta.columns"
|
|
|
:key="column.key"
|
|
|
:style="getTableCellStyle(true)"
|
|
|
>
|
|
|
{{ column.label }}
|
|
|
</div>
|
|
|
</div>
|
|
|
<vue-seamless-scroll
|
|
|
:class-option="{...chart1TableOption,limitMoveNum:6}"
|
|
|
:data="table1Data"
|
|
|
:key="scrollKey1"
|
|
|
class="case-item"
|
|
|
style="height: calc(100% - 1vw);overflow: hidden;"
|
|
|
>
|
|
|
<div
|
|
|
v-for="(item, index) in table1Data"
|
|
|
:key="index"
|
|
|
>
|
|
|
<div class="T1">
|
|
|
<div class="scrollTable" :style="getTableCellStyle()">
|
|
|
{{ item.monitorName || '' }}
|
|
|
</div>
|
|
|
<div
|
|
|
class="scrollTable"
|
|
|
v-for="column in currentTypeMeta.columns"
|
|
|
:key="column.key"
|
|
|
:style="getTableCellStyle()"
|
|
|
>
|
|
|
{{ item[column.key] || 0 }}
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</vue-seamless-scroll>
|
|
|
</div>
|
|
|
<div class="table2">
|
|
|
<div class="h2">
|
|
|
<div class="scrollTable" style="font-weight: bold;width: calc(33% - 60px);">
|
|
|
区域
|
|
|
</div>
|
|
|
<div class="scrollTable" style="font-weight: bold;width: calc(66% - 120px);">
|
|
|
设备
|
|
|
</div>
|
|
|
<div class="scrollTable" style="font-weight: bold;width: calc(180px);">
|
|
|
报警时间
|
|
|
</div>
|
|
|
</div>
|
|
|
<vue-seamless-scroll
|
|
|
:class-option="{...chart1TableOption,limitMoveNum:6}"
|
|
|
:data="realTimeAlarmData"
|
|
|
:key="scrollKey2"
|
|
|
class="case-item"
|
|
|
style="height: 84%;overflow: hidden;"
|
|
|
>
|
|
|
<div
|
|
|
v-for="(item, index) in realTimeAlarmData"
|
|
|
:key="index"
|
|
|
>
|
|
|
<div class="T2">
|
|
|
<div class="scrollTable" style="width: calc(33% - 60px);font-size: 0.7vw">
|
|
|
{{ item.deviceName }}
|
|
|
</div>
|
|
|
<div class="scrollTable" style="width: calc(66% - 120px);font-size: 0.7vw">
|
|
|
<span style="color:red">{{ item.monitorName }}</span>:{{ item.alarmData }}
|
|
|
</div>
|
|
|
<div class="scrollTable" style="width: 180px; font-size: 0.7vw">
|
|
|
{{ item.collectTime }}
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</vue-seamless-scroll>
|
|
|
</div>
|
|
|
<Chart class="jfpgtjBar" ref="jfpgtjBar"></Chart>
|
|
|
<Chart class="nhtjBar" ref="nhtjBar"></Chart>
|
|
|
<Chart class="jfpgtjPie" ref="jfpgtjPie"></Chart>
|
|
|
<Chart class="ydfxtjPie" ref="ydfxtjPie"></Chart>
|
|
|
<div class="jfpgtjInfo">
|
|
|
<div style="width: 100%"></div>
|
|
|
<div class="jfpgtjInfoItem" v-for="(i,k) in peaksValleysConsumptionData">
|
|
|
<div class="market" :style="`background-color:${colors[k]}`"></div>
|
|
|
<div class="text">
|
|
|
{{ i[0] }}
|
|
|
</div>
|
|
|
<div class="num">
|
|
|
<span class="numValue" :style="`color:${colors[k]}`">
|
|
|
{{ i[2] }}
|
|
|
</span>%
|
|
|
</div>
|
|
|
</div>
|
|
|
<div style="width: 100%"></div>
|
|
|
</div>
|
|
|
<div class="ydph">
|
|
|
<template v-for="(i,k) in topRankingData">
|
|
|
<div class="icon" :class="`icon${k+1}`">
|
|
|
<div class="img"></div>
|
|
|
</div>
|
|
|
<div class="ph" :class="`ph${k+1}`">
|
|
|
<div class="text">{{ i.workUnitName }}</div>
|
|
|
<div class="num">
|
|
|
<span style="color: #25B89A">{{ i.expend }}</span>
|
|
|
<span>{{ currentTypeMeta.unit }}</span>
|
|
|
</div>
|
|
|
<div class="schedule">
|
|
|
<div class="schedule1" :style="`width:${Math.min(100,i.expend)}%`"></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
</template>
|
|
|
<script>
|
|
|
import vueSeamlessScroll from "vue-seamless-scroll";
|
|
|
import Chart from "@/components/Charts/Chart.vue";
|
|
|
import * as echarts from 'echarts'
|
|
|
import {
|
|
|
deviceOverview, energyConsumptionStatistics,
|
|
|
fiveConsumptionStatistics,
|
|
|
monthConsumptionRanking,
|
|
|
peaksValleysConsumption, realTimeAlarm,
|
|
|
realTimeDataByEnergy
|
|
|
} from "@/api/board";
|
|
|
export default {
|
|
|
name: 'Board',
|
|
|
components: {
|
|
|
vueSeamlessScroll,
|
|
|
Chart
|
|
|
},
|
|
|
computed: {
|
|
|
topRankingData() {
|
|
|
return this.rankingData.slice(0, 5)
|
|
|
},
|
|
|
currentTypeMeta() {
|
|
|
const map = {
|
|
|
'2': {
|
|
|
rankName: '用电',
|
|
|
unit: 'kWh',
|
|
|
columns: [
|
|
|
{ key: 'iA', label: '电流' },
|
|
|
{ key: 'vA', label: '电压' },
|
|
|
{ key: 'zxyg', label: '正向有功' }
|
|
|
]
|
|
|
},
|
|
|
'3': {
|
|
|
rankName: '用水',
|
|
|
unit: 'm³',
|
|
|
columns: [
|
|
|
{ key: 'fluxFlow', label: '瞬时流量' },
|
|
|
{ key: 'waterFlow', label: '累计流量' }
|
|
|
]
|
|
|
},
|
|
|
'4': {
|
|
|
rankName: '用蒸汽',
|
|
|
unit: 't',
|
|
|
columns: [
|
|
|
{ key: 'fluxFlow', label: '瞬时流量' },
|
|
|
{ key: 'steamFlow', label: '累计流量' }
|
|
|
]
|
|
|
},
|
|
|
'5': {
|
|
|
rankName: '用压缩空气',
|
|
|
unit: 'm³',
|
|
|
columns: [
|
|
|
{ key: 'fluxFlow', label: '瞬时流量' },
|
|
|
{ key: 'steamFlow', label: '累计流量' }
|
|
|
]
|
|
|
},
|
|
|
'6': {
|
|
|
rankName: '用氮气',
|
|
|
unit: 'm³',
|
|
|
columns: [
|
|
|
{ key: 'fluxFlow', label: '瞬时流量' },
|
|
|
{ key: 'steamFlow', label: '累计流量' }
|
|
|
]
|
|
|
}
|
|
|
}
|
|
|
return map[this.typeData] || map['4']
|
|
|
}
|
|
|
},
|
|
|
data() {
|
|
|
return {
|
|
|
|
|
|
selectData: 'day',
|
|
|
typeData: "4",
|
|
|
colors: ['#30A0FB', '#00FF89', '#F9E435', '#FB5C2D', '#73c0de'],
|
|
|
chart1TableOption: {
|
|
|
step: 0.5, // 数值越大速度滚动越快
|
|
|
limitMoveNum: 3, // 开始无缝滚动的数据量 this.dataList.length
|
|
|
hoverStop: true, // 是否开启鼠标悬停stop
|
|
|
direction: 1, // 0向下 1向上 2向左 3向右
|
|
|
openWatch: true, // 开启数据实时监控刷新dom
|
|
|
singleHeight: 0, // 单步运动停止的高度(默认值0是无缝不停止的滚动) direction => 0/1
|
|
|
singleWidth: 0, // 单步运动停止的宽度(默认值0是无缝不停止的滚动) direction => 2/3
|
|
|
waitTime: 0,
|
|
|
},
|
|
|
table1Data: [],
|
|
|
scrollKey1: '',
|
|
|
scrollKey2: '',
|
|
|
clockText: '',
|
|
|
timer: null,
|
|
|
dataTimer: null,
|
|
|
deviceOverviewData: {},
|
|
|
rankingData: [],
|
|
|
statisticsData: [],
|
|
|
peaksValleysConsumptionData: [],
|
|
|
fiveConsumptionStatisticsData: {},
|
|
|
realTimeAlarmData: []
|
|
|
}
|
|
|
},
|
|
|
async mounted() {
|
|
|
this.tickClock()
|
|
|
this.timer = setInterval(this.tickClock, 1000)
|
|
|
this.getData()
|
|
|
this.dataTimer = setInterval(this.getData, 10 * 60 * 1000)
|
|
|
},
|
|
|
beforeDestroy() {
|
|
|
if (this.timer) clearInterval(this.timer)
|
|
|
if (this.dataTimer) clearInterval(this.dataTimer)
|
|
|
},
|
|
|
methods: {
|
|
|
tickClock() {
|
|
|
const d = new Date()
|
|
|
const pad = n => (n < 10 ? '0' + n : '' + n)
|
|
|
this.clockText = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
|
|
|
},
|
|
|
getTableCellStyle(isHeader = false) {
|
|
|
const width = `calc(100% / ${this.currentTypeMeta.columns.length + 1})`
|
|
|
return {
|
|
|
width,
|
|
|
...(isHeader ? { lineHeight: '1vw', fontWeight: 'bold' } : {})
|
|
|
}
|
|
|
},
|
|
|
getData() {
|
|
|
deviceOverview().then(res => {
|
|
|
this.deviceOverviewData = res.data
|
|
|
})
|
|
|
monthConsumptionRanking({monitorType: this.typeData}).then(res => {
|
|
|
this.rankingData = res.data.ranking
|
|
|
this.statisticsData = res.data.statistics
|
|
|
this.$refs.ydfxtjPie.setData({
|
|
|
graphic: [
|
|
|
{
|
|
|
type: 'text',
|
|
|
left: 'center',
|
|
|
top: 'center',
|
|
|
style: {
|
|
|
text: '能耗\n占比',
|
|
|
textAlign: 'center',
|
|
|
fill: '#4FB8FF', // 数字颜色
|
|
|
fontSize: 20,
|
|
|
fontWeight: 'bold',
|
|
|
lineHeight: 30
|
|
|
}
|
|
|
}
|
|
|
],
|
|
|
series: [
|
|
|
{
|
|
|
type: 'pie',
|
|
|
radius: ['55%', '70%'],
|
|
|
tooltip: {
|
|
|
show: false
|
|
|
},
|
|
|
label: {
|
|
|
formatter: params => {
|
|
|
return `${params.name}\n${params.value}`
|
|
|
},
|
|
|
color: '#fff'
|
|
|
|
|
|
},
|
|
|
labelLine: {
|
|
|
length: 10,
|
|
|
length2: 10,
|
|
|
},
|
|
|
data: res.data.statistics.map((e, k) => {
|
|
|
return {
|
|
|
value: e.expend,
|
|
|
name: e.workUnitName,
|
|
|
itemStyle: {
|
|
|
color: this.colors[k] + '99',
|
|
|
shadowColor: this.colors[k] + 'cc',
|
|
|
shadowBlur: 20,
|
|
|
shadowOffsetX: 0,
|
|
|
shadowOffsetY: 0
|
|
|
}
|
|
|
}
|
|
|
})
|
|
|
|
|
|
},
|
|
|
]
|
|
|
})
|
|
|
})
|
|
|
peaksValleysConsumption({ monitorType: this.typeData }).then(async res => {
|
|
|
let oriData = (res.data?.reportList || []).reduce((acc, item) => {
|
|
|
if (!acc[item.unitName]) {
|
|
|
acc[item.unitName] = 0;
|
|
|
}
|
|
|
acc[item.unitName] += Number(item.expend || 0);
|
|
|
return acc;
|
|
|
}, {})
|
|
|
let all = Object.values(oriData).reduce((acc, item) => {
|
|
|
return Number(acc) + Number(item)
|
|
|
}, 0)
|
|
|
let chartData = Object.keys(oriData).map((e) => {
|
|
|
const percentage = all === 0 ? 0 : (oriData[e] / all * 100)
|
|
|
return [e, oriData[e], percentage.toFixed(2)]
|
|
|
})
|
|
|
this.peaksValleysConsumptionData = chartData
|
|
|
let seriesData = []
|
|
|
chartData.forEach(e => {
|
|
|
seriesData.push({
|
|
|
value: all / 100 / chartData.length, name: '',
|
|
|
label: {
|
|
|
show: false
|
|
|
},
|
|
|
tooltip: {
|
|
|
show: false
|
|
|
},
|
|
|
itemStyle: {
|
|
|
color: '#0000'
|
|
|
}
|
|
|
})
|
|
|
seriesData.push({
|
|
|
value: e[1], name: e[0], percentage: e[2]
|
|
|
})
|
|
|
})
|
|
|
|
|
|
this.$refs.jfpgtjPie.setData({
|
|
|
tooltip: {
|
|
|
trigger: 'item',
|
|
|
formatter: (params) => {
|
|
|
return `${params.marker}${params.name}:${params.data.percentage}%`
|
|
|
}
|
|
|
},
|
|
|
graphic: [
|
|
|
{
|
|
|
type: 'text',
|
|
|
left: 'center',
|
|
|
top: 'center',
|
|
|
style: {
|
|
|
text: `{num|${Number(all).toFixed(2)}}\n{unit|${this.currentTypeMeta.unit}}`,
|
|
|
textAlign: 'center',
|
|
|
rich: {
|
|
|
num: {
|
|
|
fill: '#4FB8FF', // 数字颜色
|
|
|
fontSize: 20,
|
|
|
fontWeight: 'bold',
|
|
|
lineHeight: 30
|
|
|
},
|
|
|
unit: {
|
|
|
fill: '#4FB8FF', // 字母颜色
|
|
|
fontSize: 16,
|
|
|
fontWeight: 'bold'
|
|
|
}
|
|
|
},
|
|
|
}
|
|
|
}
|
|
|
],
|
|
|
series: [
|
|
|
{
|
|
|
name: 'pie1',
|
|
|
type: 'pie',
|
|
|
radius: ['62%', '70%'],
|
|
|
label: {
|
|
|
show: false
|
|
|
},
|
|
|
labelLine: {
|
|
|
show: false
|
|
|
},
|
|
|
tooltip: {
|
|
|
show: false
|
|
|
},
|
|
|
data: seriesData
|
|
|
|
|
|
},
|
|
|
{
|
|
|
name: 'pie2',
|
|
|
type: 'pie',
|
|
|
radius: ['45%', '62%'],
|
|
|
itemStyle: {
|
|
|
|
|
|
opacity: 0.6,
|
|
|
},
|
|
|
label: {
|
|
|
show: false
|
|
|
},
|
|
|
labelLine: {
|
|
|
show: false
|
|
|
},
|
|
|
data: seriesData
|
|
|
}
|
|
|
]
|
|
|
})
|
|
|
await this.$nextTick()
|
|
|
const chart = this.$refs.jfpgtjPie.getChart()
|
|
|
chart.on('mouseover', (params) => {
|
|
|
if (params.seriesType === 'pie') {
|
|
|
const other = params.seriesName === 'pie1' ? 'pie2' : 'pie1'
|
|
|
chart.dispatchAction({
|
|
|
type: 'highlight',
|
|
|
seriesName: other,
|
|
|
name: params.name
|
|
|
})
|
|
|
}
|
|
|
})
|
|
|
chart.on('mouseout', (params) => {
|
|
|
if (params.seriesType === 'pie') {
|
|
|
const other = params.seriesName === 'pie1' ? 'pie2' : 'pie1'
|
|
|
chart.dispatchAction({
|
|
|
type: 'downplay',
|
|
|
seriesName: other,
|
|
|
name: params.name
|
|
|
})
|
|
|
}
|
|
|
})
|
|
|
|
|
|
function groupByDate(data) {
|
|
|
const result = {};
|
|
|
const types = new Set();
|
|
|
|
|
|
data.forEach(item => {
|
|
|
if (!result[item.date]) {
|
|
|
result[item.date] = {date: item.date, data: {}};
|
|
|
}
|
|
|
result[item.date].data[item.unitName] = Number(item.expend || 0);
|
|
|
types.add(item.unitName);
|
|
|
});
|
|
|
|
|
|
return {
|
|
|
grouped: Object.values(result),
|
|
|
types: Array.from(types),
|
|
|
typeCount: types.size
|
|
|
};
|
|
|
}
|
|
|
|
|
|
let barData = groupByDate(res.data?.reportList)?.grouped
|
|
|
let types = groupByDate(res.data?.reportList)?.types
|
|
|
this.$refs.jfpgtjBar.setData({
|
|
|
tooltip: {
|
|
|
trigger: 'axis',
|
|
|
axisPointer: {type: 'shadow'}
|
|
|
},
|
|
|
legend: {
|
|
|
show: false
|
|
|
},
|
|
|
grid: {
|
|
|
left: '5%',
|
|
|
right: '5%',
|
|
|
bottom: '5%',
|
|
|
top: '10%',
|
|
|
containLabel: true
|
|
|
},
|
|
|
yAxis: {
|
|
|
type: 'value',
|
|
|
name: `单位(${this.currentTypeMeta.unit})`,
|
|
|
max: function (value) {
|
|
|
return parseFloat((value.max * 1.2).toFixed(1));
|
|
|
},
|
|
|
nameTextStyle: {color: '#ccc'},
|
|
|
axisLabel: {color: '#ccc'},
|
|
|
axisLine: {
|
|
|
show: true
|
|
|
},
|
|
|
splitLine: {
|
|
|
show: true,
|
|
|
lineStyle: {
|
|
|
color: 'rgba(255, 255,255, 0.3)',
|
|
|
type: 'dashed'
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
xAxis: {
|
|
|
type: 'category',
|
|
|
data: barData.map(e => e.date),
|
|
|
axisLabel: {color: '#ccc'},
|
|
|
splitLine: {
|
|
|
show: true,
|
|
|
lineStyle: {
|
|
|
color: 'rgba(255, 255,255, 0.3)',
|
|
|
type: 'dashed'
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
series: types.map((e, k) => {
|
|
|
return {
|
|
|
name: e,
|
|
|
type: 'bar',
|
|
|
stack: 'total',
|
|
|
label: {
|
|
|
show: false,
|
|
|
position: 'top',
|
|
|
color: '#fff',
|
|
|
fontSize: 10
|
|
|
},
|
|
|
barWidth: '50%',
|
|
|
barMaxWidth: '60px',
|
|
|
barMinWidth: '30px',
|
|
|
data: barData.map(v => {
|
|
|
return v.data[e] || 0
|
|
|
}),
|
|
|
itemStyle: {color: this.colors[k]}
|
|
|
}
|
|
|
})
|
|
|
})
|
|
|
})
|
|
|
fiveConsumptionStatistics().then(res => {
|
|
|
this.fiveConsumptionStatisticsData = res.data
|
|
|
})
|
|
|
energyConsumptionStatistics({monitorType: this.typeData, dateType: this.selectData}).then(res => {
|
|
|
this.$refs.nhtjBar.setData({
|
|
|
tooltip: {
|
|
|
trigger: 'axis',
|
|
|
axisPointer: {type: 'shadow'}
|
|
|
},
|
|
|
legend: {
|
|
|
show: false
|
|
|
},
|
|
|
grid: {
|
|
|
left: '5%',
|
|
|
right: '5%',
|
|
|
bottom: '0',
|
|
|
top: '35',
|
|
|
containLabel: true
|
|
|
},
|
|
|
yAxis: {
|
|
|
type: 'value',
|
|
|
name: `单位(${this.currentTypeMeta.unit})`,
|
|
|
max: function (value) {
|
|
|
return value.max * 1.2;
|
|
|
},
|
|
|
nameTextStyle: {color: '#ccc'},
|
|
|
axisLabel: {color: '#ccc'},
|
|
|
axisLine: {
|
|
|
show: true
|
|
|
},
|
|
|
splitLine: {
|
|
|
show: true,
|
|
|
lineStyle: {
|
|
|
color: 'rgba(255, 255,255, 0.3)',
|
|
|
type: 'dashed'
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
xAxis: {
|
|
|
type: 'category',
|
|
|
data: res.data.reportList.map(v => v.date),
|
|
|
axisLabel: {color: '#ccc'},
|
|
|
splitLine: {
|
|
|
show: true,
|
|
|
lineStyle: {
|
|
|
color: 'rgba(255, 255,255, 0.3)',
|
|
|
type: 'dashed'
|
|
|
}
|
|
|
}
|
|
|
},
|
|
|
series: [
|
|
|
{
|
|
|
name: '能耗',
|
|
|
type: 'bar',
|
|
|
label: {
|
|
|
show: false,
|
|
|
},
|
|
|
barWidth: '30px',
|
|
|
data: res.data.reportList.map(v => v.expend),
|
|
|
itemStyle: {
|
|
|
color: new echarts.graphic.LinearGradient(
|
|
|
0, 0, 0, 1, // 从顶部到底部
|
|
|
[
|
|
|
{offset: 0, color: '#1FA7F4'}, // 顶部颜色
|
|
|
{offset: 1, color: '#3351B4'} // 底部颜色
|
|
|
]
|
|
|
)
|
|
|
}
|
|
|
},
|
|
|
{
|
|
|
tooltip: {
|
|
|
show: false
|
|
|
},
|
|
|
type: 'line',
|
|
|
label: {
|
|
|
show: false,
|
|
|
},
|
|
|
barWidth: '30px',
|
|
|
data: res.data.reportList.map(v => v.expend),
|
|
|
itemStyle: {color: '#fff'},
|
|
|
areaStyle: {
|
|
|
color: new echarts.graphic.LinearGradient(
|
|
|
0, 0, 0, 1, // x0,y0 → x1,y1 (垂直渐变)
|
|
|
[
|
|
|
{offset: 0, color: 'rgba(255,255,255,0.53)'}, // #fff8
|
|
|
{offset: 1, color: 'rgba(255,255,255,0)'} // #fff0
|
|
|
]
|
|
|
)
|
|
|
}
|
|
|
},
|
|
|
]
|
|
|
})
|
|
|
})
|
|
|
realTimeAlarm().then(res => {
|
|
|
this.realTimeAlarmData = JSON.parse(JSON.stringify(res.data.alarmDataList))
|
|
|
this.scrollKey2 = new Date().getTime()
|
|
|
})
|
|
|
|
|
|
realTimeDataByEnergy({
|
|
|
monitorType: this.typeData,
|
|
|
isAmmeter: '1'
|
|
|
}).then(res => {
|
|
|
this.table1Data = res.data
|
|
|
this.scrollKey1 = new Date().getTime()
|
|
|
})
|
|
|
},
|
|
|
selectChange(data) {
|
|
|
this.selectData = data
|
|
|
this.getData()
|
|
|
},
|
|
|
typeChange(data) {
|
|
|
this.typeData = data
|
|
|
this.getData()
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
<style scoped lang="less">
|
|
|
.scrollTable {
|
|
|
color: rgb(185, 186, 192);
|
|
|
margin: auto 0px;
|
|
|
padding: 4px 0;
|
|
|
white-space: nowrap;
|
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
|
text-align: center;
|
|
|
display: inline-block;
|
|
|
width: 25%;
|
|
|
}
|
|
|
|
|
|
.table1 {
|
|
|
position: absolute;
|
|
|
top: 44%;
|
|
|
left: 28%;
|
|
|
width: 44%;
|
|
|
height: 21%;
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.h1 {
|
|
|
background-size: 100% 100%;
|
|
|
background-repeat: no-repeat;
|
|
|
background-image: url('~@/assets/board/T1bg.png')
|
|
|
}
|
|
|
|
|
|
.T1 {
|
|
|
background-size: 100% 100%;
|
|
|
background-repeat: no-repeat;
|
|
|
background-image: url('~@/assets/board/h1bg.png');
|
|
|
margin-top: 2px;
|
|
|
}
|
|
|
|
|
|
.table2 {
|
|
|
position: absolute;
|
|
|
top: 74%;
|
|
|
left: 75%;
|
|
|
width: 22%;
|
|
|
height: 21%;
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.h2 {
|
|
|
background-size: 100% 100%;
|
|
|
background-repeat: no-repeat;
|
|
|
background-image: url('~@/assets/board/T1-1bg.png')
|
|
|
}
|
|
|
|
|
|
.T2 {
|
|
|
background-size: 100% 100%;
|
|
|
background-repeat: no-repeat;
|
|
|
background-image: url('~@/assets/board/h1-1bg.png');
|
|
|
margin-top: 2px;
|
|
|
}
|
|
|
|
|
|
.bg {
|
|
|
width: 100%;
|
|
|
height: 100%;
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
background-repeat: no-repeat;
|
|
|
background-size: 100% 100%;
|
|
|
background-image: url('~@/assets/board/bg.jpg');
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
|
|
|
.title {
|
|
|
position: absolute;
|
|
|
top: 2%;
|
|
|
left: 50%;
|
|
|
color: #eee;
|
|
|
font-size: 2vw;
|
|
|
font-weight: 600;
|
|
|
letter-spacing: 0.5vw;
|
|
|
transform: translateX(-50%);
|
|
|
|
|
|
}
|
|
|
|
|
|
.time {
|
|
|
position: absolute;
|
|
|
top: 2.4%;
|
|
|
right: 2%;
|
|
|
font-size: 1vw;
|
|
|
color: #9fc4e8;
|
|
|
}
|
|
|
|
|
|
.subTitle {
|
|
|
position: absolute;
|
|
|
font-size: 1vw;
|
|
|
color: #eee;
|
|
|
font-weight: 600;
|
|
|
transform: translateY(-50%);
|
|
|
}
|
|
|
|
|
|
.sbzl {
|
|
|
.num {
|
|
|
position: absolute;
|
|
|
font-size: 1.2vw;
|
|
|
color: #66D49E;
|
|
|
transform: translateY(-100%);
|
|
|
}
|
|
|
|
|
|
.text {
|
|
|
position: absolute;
|
|
|
font-size: 0.6vw;
|
|
|
color: #fff;
|
|
|
width: 3vw;
|
|
|
text-align: left;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.zxnr {
|
|
|
.text {
|
|
|
position: absolute;
|
|
|
font-size: 0.6vw;
|
|
|
color: #fff;
|
|
|
text-align: left;
|
|
|
}
|
|
|
|
|
|
.num {
|
|
|
position: absolute;
|
|
|
font-size: 1.2vw;
|
|
|
color: #4EACF3;
|
|
|
font-weight: 600;
|
|
|
letter-spacing: 0.2vw;
|
|
|
}
|
|
|
|
|
|
.qs {
|
|
|
position: absolute;
|
|
|
font-size: 0.6vw;
|
|
|
color: #fff;
|
|
|
text-align: left;
|
|
|
|
|
|
.img {
|
|
|
display: inline-block;
|
|
|
vertical-align: middle;
|
|
|
width: 1vw;
|
|
|
height: 1vw;
|
|
|
background-repeat: no-repeat;
|
|
|
background-size: 100% 100%;
|
|
|
background-image: url('~@/assets/board/向上箭头.png');
|
|
|
}
|
|
|
|
|
|
.img1 {
|
|
|
display: inline-block;
|
|
|
vertical-align: middle;
|
|
|
width: 1vw;
|
|
|
height: 1vw;
|
|
|
background-repeat: no-repeat;
|
|
|
background-size: 100% 100%;
|
|
|
background-image: url('~@/assets/board/向下箭头.png');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.jfpgtjBar {
|
|
|
position: absolute;
|
|
|
top: 39%;
|
|
|
left: 75%;
|
|
|
width: 22%;
|
|
|
height: 27%;
|
|
|
}
|
|
|
|
|
|
.nhtjBar {
|
|
|
position: absolute;
|
|
|
top: 74%;
|
|
|
left: 27.5%;
|
|
|
width: 45%;
|
|
|
height: 20.5%;
|
|
|
}
|
|
|
|
|
|
|
|
|
.jfpgtjPie {
|
|
|
position: absolute;
|
|
|
top: 17%;
|
|
|
left: 75%;
|
|
|
width: 12.5%;
|
|
|
height: 20%;
|
|
|
}
|
|
|
|
|
|
.ydfxtjPie {
|
|
|
position: absolute;
|
|
|
top: 74%;
|
|
|
left: 3%;
|
|
|
width: 22%;
|
|
|
height: 20%;
|
|
|
}
|
|
|
|
|
|
.jfpgtjInfo {
|
|
|
position: absolute;
|
|
|
top: 17%;
|
|
|
left: 87.5%;
|
|
|
width: 8.5%;
|
|
|
height: 20%;
|
|
|
color: #fff;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
justify-content: space-between;
|
|
|
|
|
|
.jfpgtjInfoItem {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
min-width: 0;
|
|
|
width: 100%;
|
|
|
white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
.market {
|
|
|
flex: 0 0 auto;
|
|
|
width: 0.8vw;
|
|
|
height: 0.8vw;
|
|
|
margin-right: 0.45vw;
|
|
|
background-color: #28A7FC;
|
|
|
border-radius: 50%;
|
|
|
}
|
|
|
|
|
|
.text {
|
|
|
flex: 1;
|
|
|
min-width: 0;
|
|
|
font-size: 0.8vw;
|
|
|
overflow: hidden;
|
|
|
text-overflow: ellipsis;
|
|
|
text-align: left;
|
|
|
}
|
|
|
|
|
|
.num {
|
|
|
flex: 0 0 2.9vw;
|
|
|
font-size: 0.8vw;
|
|
|
text-align: right;
|
|
|
white-space: nowrap;
|
|
|
}
|
|
|
|
|
|
.numValue {
|
|
|
font-weight: bold;
|
|
|
font-size: 0.85vw;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.icon {
|
|
|
position: absolute;
|
|
|
width: 2vw;
|
|
|
height: 2vw;
|
|
|
background-color: #fff1;
|
|
|
|
|
|
.img {
|
|
|
position: absolute;
|
|
|
top: 50%;
|
|
|
left: 50%;
|
|
|
transform: translate(-50%, -50%);
|
|
|
width: 60%;
|
|
|
height: 60%;
|
|
|
background-repeat: no-repeat;
|
|
|
background-size: 100% 100%;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.icon1 {
|
|
|
top: 46%;
|
|
|
left: 4%;
|
|
|
|
|
|
.img {
|
|
|
background-image: url('~@/assets/board/jz1.png');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.icon2 {
|
|
|
top: 50%;
|
|
|
left: 4%;
|
|
|
|
|
|
.img {
|
|
|
background-image: url('~@/assets/board/jz2.png');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.icon3 {
|
|
|
top: 54%;
|
|
|
left: 4%;
|
|
|
|
|
|
.img {
|
|
|
background-image: url('~@/assets/board/jz3.png');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.icon4 {
|
|
|
top: 58%;
|
|
|
left: 4%;
|
|
|
|
|
|
.img {
|
|
|
background-image: url('~@/assets/board/jz4.png');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.icon5 {
|
|
|
top: 62%;
|
|
|
left: 4%;
|
|
|
|
|
|
.img {
|
|
|
background-image: url('~@/assets/board/jz5.png');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.ph {
|
|
|
position: absolute;
|
|
|
width: 19vw;
|
|
|
height: 2vw;
|
|
|
background: linear-gradient(to right, rgba(255, 255, 255, 0.067), rgba(255, 255, 255, 0));
|
|
|
|
|
|
.text {
|
|
|
position: absolute;
|
|
|
font-size: 0.8vw;
|
|
|
color: #fff;
|
|
|
top: 70%;
|
|
|
transform: translateY(-100%);
|
|
|
left: 1vw;
|
|
|
}
|
|
|
|
|
|
.num {
|
|
|
position: absolute;
|
|
|
font-size: 0.8vw;
|
|
|
text-align: right;
|
|
|
color: #fff;
|
|
|
top: 70%;
|
|
|
transform: translateY(-100%);
|
|
|
right: 1vw;
|
|
|
}
|
|
|
|
|
|
.schedule {
|
|
|
position: absolute;
|
|
|
top: 80%;
|
|
|
left: 1vw;
|
|
|
width: calc(100% - 2vw);
|
|
|
height: 3px;
|
|
|
background-color: #fff2;
|
|
|
|
|
|
.schedule1 {
|
|
|
position: absolute;
|
|
|
top: 0;
|
|
|
left: 0;
|
|
|
height: 100%;
|
|
|
background: linear-gradient(to right, #249CE3, #2FE1E0);
|
|
|
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.ph1 {
|
|
|
top: 46%;
|
|
|
left: 6.5%;
|
|
|
}
|
|
|
|
|
|
.ph2 {
|
|
|
top: 50%;
|
|
|
left: 6.5%;
|
|
|
}
|
|
|
|
|
|
.ph3 {
|
|
|
top: 54%;
|
|
|
left: 6.5%;
|
|
|
}
|
|
|
|
|
|
.ph4 {
|
|
|
top: 58%;
|
|
|
left: 6.5%;
|
|
|
}
|
|
|
|
|
|
.ph5 {
|
|
|
top: 62%;
|
|
|
left: 6.5%;
|
|
|
}
|
|
|
|
|
|
.select {
|
|
|
.selectItem {
|
|
|
position: absolute;
|
|
|
font-size: 0.7vw;
|
|
|
color: #fff9;
|
|
|
top: 11%;
|
|
|
width: 3.7vw;
|
|
|
height: 1.58vw;
|
|
|
line-height: 1.58vw;
|
|
|
text-align: center;
|
|
|
cursor: pointer;
|
|
|
background-repeat: no-repeat;
|
|
|
background-size: 100% 100%;
|
|
|
background-image: url("~@/assets/board/未选中按钮.png");
|
|
|
|
|
|
&.active {
|
|
|
color: #fff;
|
|
|
background-image: url("~@/assets/board/选中按钮.png");
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
.typeSelect {
|
|
|
.selectItem {
|
|
|
position: absolute;
|
|
|
font-size: 0.7vw;
|
|
|
color: #fff9;
|
|
|
top: 69.5%;
|
|
|
height: 2.1vw;
|
|
|
line-height: 2.1vw;
|
|
|
text-align: center;
|
|
|
cursor: pointer;
|
|
|
background-color: #0000;
|
|
|
|
|
|
&.active {
|
|
|
background-color: #0F2E51;
|
|
|
color: #4096D7;
|
|
|
border-bottom: 2px solid #4096D7;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
</style>
|