南瑞意见修改:前端页面和后端接口

This commit is contained in:
lixiaoyuan
2026-01-05 16:13:13 +08:00
parent 97e4b182de
commit e278ae1003
51 changed files with 2812 additions and 958 deletions

View File

@@ -18,6 +18,24 @@ const locale = ref(zhCN)
</script>
<style lang="scss">
*{
-webkit-touch-callout:none; /*系统默认菜单被禁用*/
-webkit-user-select:none; /*webkit浏览器*/
-khtml-user-select:none; /*早期浏览器*/
-moz-user-select:none;/*火狐*/
-ms-user-select:none; /*IE10*/
user-select:none;
}
input{
-webkit-user-select:auto; /*webkit浏览器*/
user-select:auto;
}
textarea{
-webkit-user-select:auto; /*webkit浏览器*/
user-select:auto;
}
#app {
position: absolute;
top: 0;

View File

@@ -1,12 +1,12 @@
<template>
<div class="alarm">
<div class="text_Cur">
<!-- <div class="text_Cur">
<div v-for="item in curList" :key="item.key">
<div>{{ item.name }}</div>
<span class="mark">{{ item.value ? item.value : 0 }}</span>
<span class="d">{{ item.d }}</span>
</div>
</div>
</div> -->
<div id="alarm-chart"></div>
</div>
</template>

View File

@@ -1,12 +1,12 @@
<template>
<div class="charge">
<div class="text_Cur">
<!-- <div class="text_Cur">
<div v-for="item in curList" :key="item.key">
<div>{{ item.name }}</div>
<span class="mark">{{ item.value ? item.value : 0 }}</span>
<span class="d">{{ item.d }}</span>
</div>
</div>
</div> -->
<div id="charge-chart"></div>
</div>
</template>
@@ -24,6 +24,10 @@ export default {
deviceInfo: {
type: Array,
default: () => []
},
myData: {
type: Number,
default: () => -1
}
},
data() {
@@ -95,6 +99,10 @@ export default {
}
},
deep: true // 确保深度比较
},
myData: {
handler(newVal,oldVal) {
},
}
},
mounted() {},
@@ -122,34 +130,33 @@ export default {
arr.forEach((item, index) => {
this.chargeChartData.ydata[index] = {
name: item.name,
smooth: true,
type: 'line',
barWidth: 10,
itemStyle: {
borderRadius: 10,
color: item.lineColor
},
emphasis: {
focus: 'series'
},
areaStyle: {
global: false,
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: JSON.parse(JSON.stringify(item)).colorStart }, // 顶部颜色
{ offset: 1, color: JSON.parse(JSON.stringify(item)).colorEnd } // 底部颜色
]
}
},
global: false,
showSymbol: false,
yAxisIndex: index,
data: result.values[index]
// smooth: true,
// type: 'line',
// barWidth: 10,
// itemStyle: {
// borderRadius: 10,
// color: item.lineColor
// },
// emphasis: {
// focus: 'series'
// },
// areaStyle: {
// global: false,
// color: {
// type: 'linear', x: 0, y: 0, x2: 0, y2: 1,
// colorStops: [
// { offset: 0, color: JSON.parse(JSON.stringify(item)).colorStart }, // 顶部颜色
// { offset: 1, color: JSON.parse(JSON.stringify(item)).colorEnd } // 底部颜色
// ]
// }
// },
// global: false,
// showSymbol: false,
// yAxisIndex: index,
// data: result.values[index]
type: 'bar',
data: [18,25,39,17,37,41,62],
color: item.lineColor
}
})
},
@@ -196,8 +203,9 @@ export default {
},
yAxis: [
{
name: '充电电量(kW·h)',
name: '充电电量(kWh)',
type: 'value',
splitNumber: 2,
nameTextStyle: {
color: '#fff' // 绿色名称
},
@@ -205,15 +213,16 @@ export default {
lineStyle: { type: 'dashed', color: '#435463' }
},
axisLabel: {
interval: 4,
// interval: 2,
color: '#fff',
fontSize:12
},
// axisLine : {show: true, color: '#f00'}
},
{
name: '充电收益(元)',
type: 'value',
splitNumber: 2,
splitLine: {
lineStyle: { type: 'dashed', color: '#435463' }
},
@@ -221,14 +230,18 @@ export default {
color: '#fff' // 绿色名称
},
axisLabel: {
interval: 4,
// interval: 4,
color: '#fff',
fontSize:12
},
// axisLine : {show: true, lineStyle: { color: '#ff0000', width: 2 } }
},
],
series: this.chargeChartData.ydata
// serise: [
// { name: '2011', type: 'bar', data: [18, 23, 29, 10, 13, 63] }
// ]
}
option && chargeChart.setOption(option)
this.setupResizeListener()
@@ -244,10 +257,10 @@ export default {
<style lang="scss" scoped>
.charge {
height: calc(100% - 45px);
height: calc(100% - 35px);
background-color: #50505050;
#charge-chart {
height: calc(100% - 45px);
height: calc(100% - 5px);
}
}

View File

@@ -1,6 +1,6 @@
<template>
<div class="energy">
<div class="text_Cur">
<!-- <div class="text_Cur">
<div v-for="item in curList" :key="item.key">
<div>{{ item.name }}</div>
<div>
@@ -8,7 +8,7 @@
<span class="d">{{ item.d }}</span>
</div>
</div>
</div>
</div> -->
<div id="energy-chart"></div>
</div>
</template>
@@ -104,19 +104,22 @@ export default {
arr.forEach((item, index) => {
this.energyChartData.ydata[index] = {
name: item.name,
smooth: true,
type: 'line',
barWidth: 5,
itemStyle: {
borderRadius: [5, 5, 0, 0],
color: item.lineColor
},
emphasis: {
focus: 'series'
},
global: false,
showSymbol: false,
data: result.values[index]
// type: 'line',
// smooth: true,
// barWidth: 5,
// itemStyle: {
// borderRadius: [5, 5, 0, 0],
// color: item.lineColor
// },
// emphasis: {
// focus: 'series'
// },
// global: false,
// showSymbol: false,
// data: result.values[index]
type: 'bar',
data: [5,3,6,3,8,4,6],
color: item.lineColor
}
})
},
@@ -164,6 +167,7 @@ export default {
name: '电量(kW·h)',
nameTextStyle: { color: '#fff' },
type: 'value',
splitNumber: 2,
splitLine: {
lineStyle: { type: 'dashed', color: '#435463' }
},
@@ -189,10 +193,10 @@ export default {
<style lang="scss" scoped>
.energy {
height: calc(100% - 45px);
height: calc(100% - 35px);
background-color: #50505030;
#energy-chart {
height: calc(100% - 45px);
height: calc(100% - 5px);
}
}

View File

@@ -15,7 +15,7 @@
:position="[marker.lon, marker.lat]"
:key="marker.id"
:icon="marker.iconMap"
style="width: 20px;height: auto"
style="height: auto"
@click="clickArrayMarker(marker)"
:title="marker.name"
>
@@ -235,7 +235,8 @@ export default {
}
:deep(.tdt-marker-icon){
height:auto!important;
width: 40px !important;
height:auto !important;
}
}
</style>

View File

@@ -1,27 +1,25 @@
<template>
<div class="Home">
<div class="content-left">
<div v-for="item in leftList" :key="item.componentId" :class="`grid-item ${item.class}`">
<div v-for="item in listLeft" :key="item.componentId" :class="`grid-item ${item.class}`">
<div class="tool">
<div class="title">
<span class="linear-text">{{ item.title }}</span>
</div>
</div>
<component
:is="item.componentId"
:props-info="modalInfo[item.infoKey]"
:props-total="
['prefab', 'envTotal'].includes(item.infoKey)
? item.infoKey == 'prefab'
? modalInfo.prefabTotal
: modalInfo.envInfoTotal
: modalInfo.allTotal
"
></component>
<component :is="item.componentId" :prop-key="item.infoKey"
:prop-data="compData[item.infoKey]"
:props-info="modalInfo[item.infoKey]"
:props-total="['prefab', 'envTotal'].includes(item.infoKey)
? item.infoKey == 'prefab'
? modalInfo.prefabTotal
: modalInfo.envInfoTotal
: modalInfo.allTotal
"></component>
</div>
</div>
<div class="content-right">
<div v-for="item in rightList" :key="item.componentId" :class="`grid-item ${item.class}`">
<div v-for="item in listRight" :key="item.componentId" :class="`grid-item ${item.class}`">
<div class="tool">
<div class="title">
<span class="linear-text">{{ item.title }}</span>
@@ -43,12 +41,14 @@ import OperationalInfo from '@/components/Home/Modal/OperationalInfo.vue'
import StatisticalInfo from '@/components/Home/Modal/StatisticalInfo.vue'
import Revenue from '@/components/Home/Modal/Revenue.vue'
import Utilization from '@/components/Home/Modal/Utilization.vue'
import DisCharge from '@/components/Home/Modal/DisCharge.vue'
// import DisCharge from '@/components/Home/Modal/DisCharge.vue'
import { getReq, postReq } from '@/request/api'
import { getRunDays, getDateDaysAgo } from '@/utils/dealWithData'
import EnvInfo from './Modal/EnvInfo.vue'
import { markRaw } from 'vue';
import StationVoltage from '@/components/Home/Modal/StationVoltage.vue'
import StationCurrent from '@/components/Home/Modal/StationCurrent.vue'
import StationPower from '@/components/Home/Modal/StationPower.vue'
export default {
name: 'Home',
components: {},
@@ -63,62 +63,79 @@ export default {
refreshInterval:null,
modalInfo: {},
list: [
{
title: '预制舱信息',
class: '',
componentId: markRaw( PrefabCabin),
infoKey: 'prefab'
},
{
title: '储能充放电量',
class: 'stats-cards',
componentId:markRaw( DisCharge),
infoKey: 'energy'
},
{
title: '运行信息',
class: 'operation-status',
componentId:markRaw( OperationalInfo),
infoKey: 'envTotal'
},
{
title: '场站收益情况',
class: 'revenue',
componentId:markRaw( Revenue),
infoKey: 'energy'
},
compData: {},
{
title: '统计信息',
class: 'statistical',
componentId:markRaw( StatisticalInfo),
infoKey: ''
},
{
title: '设备利用率',
class: '',
componentId:markRaw( Utilization),
infoKey: 'energy'
},
{
title: '环境信息',
class: 'envInfo',
componentId:markRaw( EnvInfo),
infoKey: 'envTotal'
}
listLeft: [
{ title: '场站信息', class: '', componentId: markRaw( PrefabCabin), infoKey: 'prefab' },
{ title: '储能运行信息', class: 'operation-status', componentId: markRaw(OperationalInfo), infoKey: 'storage' },
{ title: '充电运行信息', class: 'operation-status', componentId: markRaw(OperationalInfo), infoKey: 'charge' },
{ title: '光伏运行信息', class: 'operation-status', componentId: markRaw(OperationalInfo), infoKey: 'pv' },
{ title: '电网侧运行信息', class: 'operation-status', componentId: markRaw(OperationalInfo), infoKey: 'grid' },
{ title: '环境信息', class: 'envInfo', componentId:markRaw( EnvInfo), infoKey: 'envTotal' }
],
listRight: [
{ title: '今日电压曲线', class: 'stats-cards', componentId:markRaw(StationVoltage), infoKey: 'voltage' },
{ title: '今日电流曲线', class: 'revenue', componentId:markRaw(StationCurrent), infoKey: 'current' },
{ title: '今日功率曲线', class: '', componentId:markRaw(StationPower), infoKey: 'power' },
],
// list: [
// {
// title: '场站信息',
// class: '',
// componentId: markRaw( PrefabCabin),
// infoKey: 'prefab'
// },
// {
// title: '储能充放电量',
// class: 'stats-cards',
// componentId:markRaw( DisCharge),
// infoKey: 'energy'
// },
// {
// title: '运行信息',
// class: 'operation-status',
// componentId:markRaw( OperationalInfo),
// infoKey: 'envTotal'
// },
// {
// title: '场站收益情况',
// class: 'revenue',
// componentId:markRaw( Revenue),
// infoKey: 'energy'
// },
// {
// title: '统计信息',
// class: 'statistical',
// componentId:markRaw( StatisticalInfo),
// infoKey: ''
// },
// {
// title: '设备利用率',
// class: '',
// componentId:markRaw( Utilization),
// infoKey: 'energy'
// },
// {
// title: '环境信息',
// class: 'envInfo',
// componentId:markRaw( EnvInfo),
// infoKey: 'envTotal'
// }
// ],
sysName: '',
user: JSON.parse(localStorage.getItem('permission')) || {}
}
},
computed: {
leftList() {
return this.list.filter((_, index) => index % 2 === 0).slice(0, 4) // 左列取前3个偶数索引
},
rightList() {
return this.list.filter((_, index) => index % 2 !== 0).slice(0, 3) // 右列取前3个奇数索引
}
// leftList() {
// return this.list.filter((_, index) => index % 2 === 0).slice(0, 4) // 左列取前3个偶数索引
// },
// rightList() {
// return this.list.filter((_, index) => index % 2 !== 0).slice(0, 3) // 右列取前3个奇数索引
// }
},
beforeUnmount() {
if(this.refreshInterval){
@@ -140,7 +157,9 @@ export default {
this.getStatTotalList(),
this.queryStationInfo(),
this.queryStationData(),
this.getStatDayList(1)
this.getStatDayList(1),
this.getStatDayList(2),
this.getStatDayList(3),
])
},
// 查询系统累计统计信息
@@ -157,10 +176,12 @@ export default {
}
const res = await getReq('/queryStatTotal', query)
if (res.errcode === 0) {
this.modalInfo.allTotal = res.data
this.modalInfo.allTotal.runDays = getRunDays(res.data.launch_date)
const { income_charge: incomeCharge, income_elect: incomeElect } = this.modalInfo.allTotal
this.modalInfo.allTotal.incomeTotal = +incomeCharge + +incomeElect
this.compData.prefab = { stats: res.data }
// this.compData.prefab.run_days = getRunDays(res.data.launch_date)
// this.modalInfo.allTotal = res.data
// this.modalInfo.allTotal.run_days = getRunDays(res.data.launch_date)
// const { income_charge: incomeCharge, income_elect: incomeElect } = this.modalInfo.allTotal
// this.modalInfo.allTotal.incomeTotal = +incomeCharge + +incomeElect
} else {
throw res
}
@@ -171,37 +192,32 @@ export default {
// 查询场站实时数据
async queryStationData() {
try {
// station_id场站ID
const query = {
station_id: this.stationId
}
const res = await getReq('/queryStationData', query)
const res = await getReq('/queryStationData', { station_id: this.stationId })
if (res.errcode === 0) {
this.modalInfo.envInfoTotal = res.data
// this.compData.prefab = { data: res.data }
this.compData.storage = res.data['storage']
this.compData.charge = res.data['charge']
this.compData.pv = res.data['pv']
this.compData.grid = res.data['grid']
} else {
throw res
}
} catch (error) {
this.modalInfo.envInfoTotal = {}
this.compData.storage = this.compData.charge = this.compData.pv = this.compData.grid = {}
}
},
// 查询场站信息
async queryStationInfo() {
try {
// station_id场站ID
const query = {
station_id: this.stationId
}
const res = await getReq('/queryStationInfo', query)
const res = await getReq('/queryStationInfo', { station_id: this.stationId })
if (res.errcode === 0) {
this.modalInfo.prefabTotal = res.data
this.compData.prefab = { info: res.data }
this.compData.prefab.info.run_days = getRunDays(res.data.launch_date)
} else {
throw res
}
} catch (error) {
this.modalInfo.allTotal = {}
this.compData.prefab = { info: {}}
}
},
// 查询场站日统计信息
@@ -214,19 +230,27 @@ export default {
const query = {
station_id: this.stationId,
category,
start_date: getDateDaysAgo(7 - 1),
end_date: getDateDaysAgo(0)
// start_date: getDateDaysAgo(7 - 1),
// end_date: getDateDaysAgo(0)
}
const categoryObj = { 1: 'energy' }
const res = await getReq('/queryStatDayList', query)
// const res = await getReq('/queryStatDayList', query)
const res = await getReq('/queryStationTodayU', query)
if (res.errcode === 0) {
this.modalInfo[categoryObj[category]] = res.data.map((item) => {
const { income_charge: incomeCharge, income_elect: incomeElect } = item
return {
...item,
incomeTotal: +incomeCharge + +incomeElect
}
})
if (category === 1) {
this.modalInfo.voltage = [{ index: 0, data: res.data.U }]
this.modalInfo.current = [{ index: 0, data: res.data.I }]
this.modalInfo.power = [{ index: 0, data: res.data.P }]
}
else if (category === 2){
this.modalInfo.voltage = [{ index: 1, data: res.data.U }]
this.modalInfo.current = [{ index: 1, data: res.data.I }]
this.modalInfo.power = [{ index: 1, data: res.data.P }]
}
else if (category === 3){
this.modalInfo.voltage = [{ index: 2, data: res.data.U }]
this.modalInfo.current = [{ index: 2, data: res.data.I }]
this.modalInfo.power = [{ index: 2, data: res.data.P }]
}
} else {
throw res
}
@@ -284,7 +308,7 @@ export default {
-webkit-background-clip: text;
background-clip: text;
font-size: 18px;
font-weight: 400;
font-weight: 1000;
margin-left: 28px;
}
@@ -315,7 +339,7 @@ export default {
.text {
margin-left: 20px;
font-size: 16px;
font-weight: 700;
font-weight: 1000;
background: linear-gradient(
90deg,
rgba(0, 186, 173, 0.15) 0%,
@@ -330,7 +354,7 @@ export default {
}
}
.operation-status {
height: calc(25% - 10px);
height: calc(15% - 10px);
}
.statistical {
height: calc(18% - 10px);

View File

@@ -8,7 +8,7 @@
/>
<div class="right">
<span>{{ item.label }}</span>
<span>{{ item.value }} {{ item.d }}</span>
<span style="color: #a0f0a0; font-size: 16px;">{{ item.value }} {{ item.d }}</span>
</div>
</div>
</div>

View File

@@ -4,8 +4,11 @@
<div v-for="item in list" :key="item.key" :class="`item ${item.class}`">
<a-image :preview="false" :src="item.iconPath" :width="50" class="left"> </a-image>
<div class="right">
<span>{{ item.label }}</span>
<span>{{ item.value }} {{ item.d }}</span>
<span class="k">{{ item.label }}</span>
<div>
<span class="v">{{ item.value }}</span>
<span class="d">{{ item.d }}</span>
</div>
</div>
</div>
</div>
@@ -16,86 +19,48 @@
export default {
name: '',
props: {
propsTotal: {
type: Object,
default: () => {}
},
propsInfo: {
type: Array,
default: () => []
},
propKey: { type: String, default: '' },
propData: { type: Object, default: () => { } },
},
data() {
return {
list: [
// {
// key: 'tianshu',
// value: 26,
// d: '℃',
// label: '舱内温度',
// class: 'item-1',
// iconPath: require('@/assets/home/wendu.png')
// },
// {
// key: 'shouyi',
// value: 25,
// d: '%',
// label: '舱内湿度',
// class: 'item-2',
// iconPath: require('@/assets/home/shidu.png')
// },
{
key: 'voltage',
value: 24,
d: 'V',
label: '电压',
class: 'item-3',
iconPath: require('@/assets/home/dianya.png')
},
{
key: 'current',
value: 26,
d: 'A',
label: '电流',
class: 'item-4',
iconPath: require('@/assets/home/dianliu.png')
},
{
key: 'power',
value: 20,
d: 'kW',
label: '功率',
class: 'item-5',
iconPath: require('@/assets/home/gonglv.png')
},
{
key: 'powerFactor',
value: 100,
d: '',
label: '功率因数',
class: 'item-6',
iconPath: require('@/assets/home/gonglv.png')
}
]
itemDef: {
U: { key: 'U', value: '--', d: 'V', label: '电压', class: 'item-3', iconPath: require('@/assets/home/dianya.png') },
I: { key: 'I', value: '--', d: 'A', label: '电流', class: 'item-4', iconPath: require('@/assets/home/dianliu.png') },
P: { key: 'P', value: '--', d: 'kW', label: '功率', class: 'item-5', iconPath: require('@/assets/home/gonglv.png') },
// PF: { key: 'PF', value: '--', d: '', label: '功率因数', class: 'item-6', iconPath: require('@/assets/home/gonglv.png') }
},
}
},
computed: {
},
watch: {
propsTotal: {
propKey: {
handler(newVal, oldVal) {
if (this.propKey === 'grid') {
this.list = [this.itemDef.P]
}
else if (this.propKey === 'pv') {
this.list = [this.itemDef.P]
}
else {
this.list = [this.itemDef.U, this.itemDef.I, this.itemDef.P]
}
},
immediate: true,
},
propData: {
handler(newVal, oldVal) {
if (newVal !== oldVal) {
this.list.forEach((item) => {
item.value = this.propsTotal[item.key]||0
item.value = this.propData[item.key] || 0
})
}
},
}
}
},
mounted() {},
mounted() { },
methods: {}
}
</script>
@@ -104,44 +69,51 @@ export default {
.operationlInfo {
height: calc(100% - 45px);
display: flex;
justify-content: center;
// justify-content: center;
align-items: center;
width: 95%;
margin: auto;
}
.content {
flex-wrap: wrap;
width: 90%;
width: 100%;
display: flex;
align-items: center;
justify-content: space-around;
// align-items: center;
// justify-content: space-around;
height: 100%;
padding-left: calc(10%);
.item {
height: 50%;
width: 45%;
// height: 47px;
width: 30%;
height: 50px;
box-sizing: border-box;
display: flex;
align-items: center;
// align-items: center;
// justify-content: center;
// text-align: center;
& > span:nth-child(1) {
font-size: 12px;
margin-bottom: 10px;
}
.d {
margin-left: 1px;
font-size: 12px;
}
}
.right {
display: flex;
flex-direction: column;
margin-left: 20px;
margin-left: 10px;
.k {
color: #e0e0e0;
font-size: 12px;
}
.v {
color: #a0f0a0;
font-size: 16px;
}
.d {
margin-left: 8px;
font-size: 14px;
}
}
}
</style>
</style>

View File

@@ -1,6 +1,18 @@
<template>
<div class="prefabCabin">
<div class="content-left">
<div style="display: flex; flex-direction: row; flex-wrap: wrap;" >
<div v-for="item in [...myItemsInfo, ...myItemsStats]" :key="item.key" :class="`item ${item.class}`">
<div style="display: flex; flex-direction: column; justify-items: flex-start;">
<span style="color: #e0e0e0;">{{ item.label }}</span>
<div style="display: flex; justify-content: flex-end; line-height: 1;">
<span class="v">{{ item.value ? item.value : 0 }}</span>
<span class="d">{{ item.d }}</span>
</div>
</div>
</div>
</div>
<!-- <div class="content-left">
<div v-for="item in leftList" :key="item.key" :class="`item ${item.class}`">
<div>
<span>{{ item.value ? item.value : 0 }}</span
@@ -8,13 +20,13 @@
</div>
<span>{{ item.label }}</span>
</div>
</div>
<div style="text-align: center; font-weight: 500">
</div> -->
<!-- <div style="text-align: center; font-weight: 500">
<div class="prefabCabin-icon"></div>
<span>{{ curStatus }}</span>
</div>
</div> -->
<div class="content-right">
<!-- <div class="content-right">
<div v-for="item in rightList" :key="item.key" :class="`item ${item.class}`">
<div>
<span>{{ item.value ? item.value : 0 }}</span
@@ -22,7 +34,7 @@
</div>
<span>{{ item.label }}</span>
</div>
</div>
</div> -->
</div>
</template>
@@ -30,6 +42,7 @@
export default {
name: '',
props: {
propData: { type: Object, default: () => {} },
propsTotal: {
type: Object,
default: () => {}
@@ -42,6 +55,24 @@ export default {
data() {
return {
curStatus: '充电',
myItemsInfo: [
{ key: 'capacity', value: '', label: '电池储能容量', d: 'kWh' },
{ key: 'voltage_rated', value: '', label: '电池额定总电压', d: 'V' },
{ key: 'cooling_type', value: '', label: '冷却方式', d: '' },
{ key: 'batttey_type', value: '', label: '电池类型', d: '' },
{ key: 'run_days', value: '', label: '场站运行天数', d: '天' },
],
myItemsStats: [
{ key: 'storage_device_num', value: '', label: '储能设备数量', d: '个' },
{ key: 'solar_device_num', value: '', label: '光伏设备数量', d: '个' },
{ key: 'charge_device_num', value: '', label: '充电设备数量', d: '个' },
{ key: 'solar_elect_grid', value: '', label: '上网总电量', d: 'kWh' },
{ key: 'storage_elect_in', value: '', label: '储能充电总电量', d: 'kWh' },
{ key: 'solar_elect_gen', value: '', label: '光伏发电总电量', d: 'kWh' },
{ key: 'charge_elect', value: '', label: '充电桩充电总电量', d: 'kWh' },
{ key: 'income_elect', value: '', label: '收益总金额', d: '元' },
{ key: 'storage_elect_out', value: '', label: '储能放电总电量', d: 'kWh' },
],
list: [
{
key: 'batttey_type',
@@ -123,20 +154,41 @@ export default {
}
},
watch: {
propData: {
handler(newVal, oldVal) {
if (newVal !== oldVal) {
if (this.propData.stats) {
this.myItemsStats.forEach((item) => {
item.value = this.propData.stats[item.key] != undefined ? this.propData.stats[item.key] : '--'
});
}
if (this.propData.info) {
this.myItemsInfo.forEach((item) => {
item.value = this.propData.info[item.key] != undefined ? this.propData.info[item.key] : '--'
});
}
}
}
},
propsTotal: {
handler(newVal, oldVal) {
if (newVal !== oldVal) {
// 0正常 1故障
this.curStatus=['故障','正常'][this.propsTotal.status]
this.list.forEach((item) => {
if(item.key=='work_mode'){
item.value = ['手动','峰谷套利','配网增容','应急供电','并网保电','自定时段'][this.propsTotal[item.key]]
// console.log(item.list.map((item)=>this.propsTotal[item.key]==item.value)[0].label,"145",item.list.map((item)=>this.propsTotal[item.key]==item.value))
// item.value =item.list.map((item)=>==item.value)[0].label
}else {
item.value = this.propsTotal[item.key]
}
})
// this.list.forEach((item) => {
// if(item.key=='work_mode'){
// item.value = ['手动','峰谷套利','配网增容','应急供电','并网保电','自定时段'][this.propsTotal[item.key]]
// // console.log(item.list.map((item)=>this.propsTotal[item.key]==item.value)[0].label,"145",item.list.map((item)=>this.propsTotal[item.key]==item.value))
// // item.value =item.list.map((item)=>==item.value)[0].label
// }else {
// item.value = this.propsTotal[item.key]
// }
// })
}
}
}
@@ -152,29 +204,48 @@ export default {
display: flex;
justify-content: center;
align-items: center;
margin-left: 10px;
margin-right: 10px;
}
.item {
height: 57px;
background: linear-gradient(
180deg,
rgba(15, 227, 255, 0.3) 0%,
rgba(15, 227, 255, 0.09) 45.6%,
rgba(15, 227, 255, 0.3) 100%
);
padding: 10px 8px;
height: 40px;
width: calc(25% - 5px);
margin-right: 5px;
margin-bottom: 5px;
background: url('@/assets/home/onLineBg.png');
background-size: contain;
background-size: 100% 100%;
background-repeat: no-repeat;
// background: linear-gradient(
// 180deg,
// rgba(15, 227, 255, 0.3) 0%,
// rgba(15, 227, 255, 0.09) 45.6%,
// rgba(15, 227, 255, 0.3) 100%
// );
// padding: 10px 8px;
min-width: 115px;
display: flex;
flex-direction: column;
text-align: center;
& > span:nth-child(1) {
padding: 0;
margin: 0;
font-size: 12px;
margin-bottom: 10px;
}
.v {
color: #a0f0a0;
line-height: 1;
}
.d {
margin-left: 1px;
display: block;
text-align: left;
margin-left: 5px;
font-size: 12px;
min-width: 40px;
height: 16px;
}
}

View File

@@ -0,0 +1,177 @@
<template>
<div class="mychart">
<div id="chart-current"></div>
</div>
</template>
<script>
import {processData} from '@/utils/dealWithData'
export default {
name: '',
props: {
propsInfo: {
type: Array,
default: () => []
}
},
data() {
return {
curList: [
{
name: '储能设备',
key: 'storage_elect_in',
lineColor: '#9BD801',
value: 0,
d: 'kW·h'
},
{
name: '充电设备',
key: 'storage_elect_out',
lineColor: '#3DFEFA',
value: 0,
d: 'kW·h'
}
],
myChart: null,
chartData: {
ydata: [],
xdata: []
}
}
},
watch: {
propsInfo: {
handler(newVal, oldVal) {
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
this.$nextTick(() => {
this.updateChart()
})
}
},
deep: true // 确保深度比较
}
},
mounted() {},
beforeUnmount() {
window.removeEventListener('resize', this.handleResize)
if (this.myChart) {
this.myChart.dispose()
this.myChart = null
}
},
methods: {
handleResize() {
if (this.myChart) {
this.myChart.resize()
}
},
createChartXData()
{
const timeArray = [];
const dateZero = new Date();
dateZero.setHours(0, 0, 0, 0); // 重置为当天0点
for (let i=0; i<144; ++i)
{
// 累加10分钟
const currentTime = new Date(dateZero.getTime() + i * 600 * 1000);
// 格式化为 HH:mm
const hours = currentTime.getHours().toString().padStart(2, '0');
const minutes = currentTime.getMinutes().toString().padStart(2, '0');
timeArray.push(`${hours}:${minutes}`);
}
return timeArray
},
initChart() {
const chartDom = document.getElementById('chart-current')
if (!chartDom) return
if (this.myChart) this.myChart.dispose()
this.myChart = this.$echarts.init(chartDom)
const xdata = this.createChartXData();
const option = {
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
legend: { top: 0, textStyle: { color: '#fff' } },
grid: { left: '3%', right: '4%', top: '40px', bottom: '5%', },
xAxis: {
type: 'category',
data: xdata,
axisLine: { lineStyle: { type: 'dashed', color: '#435463' } },
axisLabel: { color: '#fff' }
},
yAxis: {
name: "电流(A)",
type: 'value',
nameTextStyle: { color: '#fff' },
splitLine: {
lineStyle: { type: 'dashed', color: '#435463' }
},
axisLabel: { color: '#fff', fontSize: 12 },
},
series: []
}
this.curList.forEach((item, index) => {
option.series.push({
name: item.name,
index: index,
smooth: true,
type: 'line',
barWidth: 10,
itemStyle: { borderRadius: 10, color: item.lineColor },
emphasis: { focus: 'series' },
global: false,
showSymbol: false,
data: []
})
})
option && this.myChart.setOption(option)
},
updateChart(activeKey) {
if (!this.myChart) {
this.initChart()
}
if (this.propsInfo) {
let series = []
this.propsInfo.forEach((item)=> {
if (item.index != undefined && item.index < this.curList.length) {
series.push({
name: this.curList[item.index].name,
data: item.data
})
}
})
if (series.length > 0) {
this.myChart.setOption({
xAxis: { data: this.createChartXData() },
series: series
});
this.setupResizeListener()
}
}
},
setupResizeListener() {
window.removeEventListener('resize', this.handleResize)
window.addEventListener('resize', this.handleResize)
}
}
}
</script>
<style lang="scss" scoped>
.mychart {
height: calc(100% - 35px);
#chart-current {
height: calc(100% - 5px);
}
}
</style>

View File

@@ -0,0 +1,191 @@
<template>
<div class="mychart">
<div id="chart-power"></div>
</div>
</template>
<script>
import {processData} from '@/utils/dealWithData'
export default {
name: '',
props: {
propsInfo: {
type: Array,
default: () => []
}
},
data() {
return {
curList: [
{
name: '储能设备',
key: 'storage_elect_in',
lineColor: '#9BD801',
value: 0,
d: 'kW·h'
},
{
name: '充电设备',
key: 'storage_elect_out',
lineColor: '#3DFEFA',
value: 0,
d: 'kW·h'
},
{
name: '光伏设备',
key: 'storage_elect_out',
lineColor: '#3DFEFA',
value: 0,
d: 'kW·h'
},
{
name: '电网侧',
key: 'storage_elect_out',
lineColor: '#3DFEFA',
value: 0,
d: 'kW·h'
}
],
myChart: null,
chartData: {
ydata: [],
xdata: []
}
}
},
watch: {
propsInfo: {
handler(newVal, oldVal) {
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
this.$nextTick(() => {
this.updateChart()
})
}
},
deep: true // 确保深度比较
}
},
mounted() {},
beforeUnmount() {
window.removeEventListener('resize', this.handleResize)
if (this.myChart) {
this.myChart.dispose()
this.myChart = null
}
},
methods: {
handleResize() {
if (this.myChart) {
this.myChart.resize()
}
},
createChartXData()
{
const timeArray = [];
const dateZero = new Date();
dateZero.setHours(0, 0, 0, 0); // 重置为当天0点
for (let i=0; i<144; ++i)
{
// 累加10分钟
const currentTime = new Date(dateZero.getTime() + i * 600 * 1000);
// 格式化为 HH:mm
const hours = currentTime.getHours().toString().padStart(2, '0');
const minutes = currentTime.getMinutes().toString().padStart(2, '0');
timeArray.push(`${hours}:${minutes}`);
}
return timeArray
},
initChart() {
const chartDom = document.getElementById('chart-power')
if (!chartDom) return
if (this.myChart) this.myChart.dispose()
this.myChart = this.$echarts.init(chartDom)
const xdata = this.createChartXData();
const option = {
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
legend: { top: 0, textStyle: { color: '#fff' } },
grid: { left: '3%', right: '4%', top: '40px', bottom: '5%', },
xAxis: {
type: 'category',
data: xdata,
axisLine: { lineStyle: { type: 'dashed', color: '#435463' } },
axisLabel: { color: '#fff' }
},
yAxis: {
name: "功率(kW)",
type: 'value',
nameTextStyle: { color: '#fff' },
splitLine: {
lineStyle: { type: 'dashed', color: '#435463' }
},
axisLabel: { color: '#fff', fontSize: 12 },
},
series: []
}
this.curList.forEach((item, index) => {
option.series.push({
name: item.name,
index: index,
smooth: true,
type: 'line',
barWidth: 10,
itemStyle: { borderRadius: 10, color: item.lineColor },
emphasis: { focus: 'series' },
global: false,
showSymbol: false,
data: []
})
})
option && this.myChart.setOption(option)
},
updateChart(activeKey) {
if (!this.myChart) {
this.initChart()
}
if (this.propsInfo) {
let series = []
this.propsInfo.forEach((item)=> {
if (item.index != undefined && item.index < this.curList.length) {
series.push({
name: this.curList[item.index].name,
data: item.data
})
}
})
if (series.length > 0) {
this.myChart.setOption({
xAxis: { data: this.createChartXData() },
series: series
});
this.setupResizeListener()
}
}
},
setupResizeListener() {
window.removeEventListener('resize', this.handleResize)
window.addEventListener('resize', this.handleResize)
}
}
}
</script>
<style lang="scss" scoped>
.mychart {
height: calc(100% - 35px);
#chart-power {
height: calc(100% - 5px);
}
}
</style>

View File

@@ -0,0 +1,178 @@
<template>
<div class="mychart">
<div id="chart-voltage"></div>
</div>
</template>
<script>
import {processData} from '@/utils/dealWithData'
export default {
name: '',
props: {
propsInfo: {
type: Array,
default: () => []
}
},
data() {
return {
curList: [
{
name: '储能设备',
key: 'storage_elect_in',
lineColor: '#9BD801',
value: 0,
d: 'kW·h'
},
{
name: '充电设备',
key: 'storage_elect_out',
lineColor: '#3DFEFA',
value: 0,
d: 'kW·h'
}
],
myChart: null,
chartData: {
ydata: [],
xdata: []
}
}
},
watch: {
propsInfo: {
handler(newVal, oldVal) {
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
this.$nextTick(() => {
this.updateChart()
})
}
},
deep: true // 确保深度比较
}
},
mounted() {},
beforeUnmount() {
window.removeEventListener('resize', this.handleResize)
if (this.myChart) {
this.myChart.dispose()
this.myChart = null
}
},
methods: {
handleResize() {
if (this.myChart) {
this.myChart.resize()
}
},
createChartXData()
{
const timeArray = [];
const dateZero = new Date();
dateZero.setHours(0, 0, 0, 0); // 重置为当天0点
for (let i=0; i<144; ++i)
{
// 累加10分钟
const currentTime = new Date(dateZero.getTime() + i * 600 * 1000);
// 格式化为 HH:mm
const hours = currentTime.getHours().toString().padStart(2, '0');
const minutes = currentTime.getMinutes().toString().padStart(2, '0');
timeArray.push(`${hours}:${minutes}`);
}
return timeArray
},
initChart() {
const chartDom = document.getElementById('chart-voltage')
if (!chartDom) return
if (this.myChart) this.myChart.dispose()
this.myChart = this.$echarts.init(chartDom)
const xdata = this.createChartXData();
const option = {
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
legend: { top: 0, textStyle: { color: '#fff' } },
grid: { left: '3%', right: '4%', top: '40px', bottom: '5%', },
xAxis: {
type: 'category',
data: xdata,
axisLine: { lineStyle: { type: 'dashed', color: '#435463' } },
axisLabel: { color: '#fff' }
},
yAxis: {
name: '电压(V)',
type: 'value',
nameTextStyle: { color: '#fff' },
splitLine: {
lineStyle: { type: 'dashed', color: '#435463' }
},
axisLabel: { color: '#fff', fontSize: 12 },
},
series: []
}
this.curList.forEach((item, index) => {
option.series.push({
name: item.name,
index: index,
smooth: true,
type: 'line',
barWidth: 10,
itemStyle: { borderRadius: 10, color: item.lineColor },
emphasis: { focus: 'series' },
global: false,
showSymbol: false,
data: []
})
})
option && this.myChart.setOption(option)
},
updateChart(activeKey) {
if (!this.myChart) {
this.initChart()
}
if (this.propsInfo) {
let series = []
this.propsInfo.forEach((item)=> {
if (item.index != undefined && item.index < this.curList.length) {
series.push({
name: this.curList[item.index].name,
data: item.data
})
}
})
if (series.length > 0) {
this.myChart.setOption({
xAxis: { data: this.createChartXData() },
series: series
});
this.setupResizeListener()
}
}
},
setupResizeListener() {
window.removeEventListener('resize', this.handleResize)
window.addEventListener('resize', this.handleResize)
}
}
}
</script>
<style lang="scss" scoped>
.mychart {
height: calc(100% - 35px);
#chart-voltage {
height: calc(100% - 5px);
}
}
</style>

View File

@@ -0,0 +1,173 @@
<template>
<div class="mychart">
<!-- <div class="text_Cur">
<div v-for="item in curList" :key="item.key">
<div>{{ item.name }}</div>
<span class="mark">{{ item.value ? item.value : 0 }}</span>
<span class="d">{{ item.d }}</span>
</div>
</div> -->
<div :id="myChartId" class="mychart"></div>
</div>
</template>
<script>
import { processData } from '@/utils/dealWithData'
export default {
name: '',
props: {
propKey: { type: String, default: '' },
propData: { type: Array, default: () => [] },
propOption: { type: Object, default: { series: [] } }
},
data() {
return {
myChartId: 'mychart' + Math.floor(Math.random() * 9999),
myEchart: null,
xData: [], // EChart的 x 轴 option
yData: [], // EChart的 y 轴 option
}
},
watch: {
propData: {
handler(newVal, oldVal) {
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
this.$nextTick(() => {
this.drawLineChart()
})
}
},
immediate: true, // 初始化时更新
deep: true // 确保深度比较
},
propOption: {
handler(newVal, oldVal) {
},
immediate: true,
}
},
mounted() { },
beforeUnmount() {
window.removeEventListener('resize', this.handleResize)
if (this.myEchart) {
this.myEchart.dispose()
this.myEchart = null
}
},
methods: {
handleResize() {
if (this.myEchart) {
this.myEchart.resize()
}
},
getChartData() {
const keyList = this.propOption.series.map((item) => item.key)
const result = processData(this.propData, keyList)
this.xData = result.dates
this.yData = result.values
if (this.xData.length == 0) {
const today = new Date();
for (let i = 6; i >= 0; i--) {
const date = new Date(today); // 每次创建新日期实例(避免修改原日期)
date.setDate(today.getDate() - i); // 往前推 i 天
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); // 月份 0-11需 +1
const day = String(date.getDate()).padStart(2, '0');
this.xData.push(`${month}-${day}`);
for (let j = 0; j < keyList.length; j++) {
if (j == 0) this.yData.push([])
else this.yData[j].push(0)
}
}
}
},
drawLineChart(activeKey) {
this.getChartData(activeKey)
if (this.myEchart) {
this.myEchart.dispose()
}
const chartDom = document.getElementById(this.myChartId)
if (!chartDom) return;
let myEchart = this.$echarts.init(chartDom)
this.myEchart = myEchart
let option = {
animation: false,
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
legend: { top: 10, textStyle: { color: '#fff' } },
grid: { left: '3%', right: '4%', bottom: '1%', top: '32%' },
xAxis: {
type: 'category',
data: this.xData,
axisLine: { lineStyle: { type: 'dashed', color: '#435463' } },
axisLabel: { color: '#fff' }
},
yAxis: [],
series: []
}
const yAxisItem = {
name: '',
type: 'value',
min: 0,
max: 2,
//interval: 1, // 强制步长
splitNumber: 2, // 分段数
nameTextStyle: { color: '#fff' },
splitLine: { lineStyle: { type: 'dashed', color: '#435463' } },
axisLabel: { color: '#fff', fontSize: 12 },
}
if (this.propOption.yAxis) {
this.propOption.yAxis.forEach((item, index) => {
const maxVal = Math.max(...this.yData[index]);
if (maxVal && maxVal > 0) {
yAxisItem.min = undefined
yAxisItem.max = maxVal
}
yAxisItem.name = item
option.yAxis.push(yAxisItem)
})
}
if (this.propOption.series) {
this.propOption.series.forEach((item, index) => {
option.series.push({
name: item.name,
type: 'bar',
color: item.color,
data: this.yData[index],
barWidth: '20%'
})
})
}
if (option.yAxis.length == 0) { option.yAxis.push(yAxisItem) }
option && myEchart.setOption(option)
this.setupResizeListener()
},
setupResizeListener() {
window.removeEventListener('resize', this.handleResize);
window.addEventListener('resize', this.handleResize)
}
}
}
</script>
<style lang="scss" scoped>
.mychart {
height: calc(100% - 35px);
background-color: #80808010;
.mychart {
height: calc(100% - 5px);
}
}
</style>

View File

@@ -166,6 +166,7 @@ export default {
{
name: '收益(元)',
type: 'value',
splitNumber: 2,
splitLine: {
lineStyle: { type: 'dashed', color: '#435463' }
},
@@ -173,7 +174,7 @@ export default {
color: '#fff' // 绿色名称
},
axisLabel: {
interval: 4,
// interval: 4,
color: '#fff',
fontSize:12
@@ -182,6 +183,7 @@ export default {
{
name: '利用率(%)',
type: 'value',
splitNumber: 2,
nameTextStyle: {
color: '#fff' // 绿色名称
},
@@ -189,10 +191,9 @@ export default {
lineStyle: { type: 'dashed', color: '#435463' }
},
axisLabel: {
interval: 4,
// interval: 4,
color: '#fff',
fontSize:12
},
},
],
@@ -212,7 +213,7 @@ export default {
<style lang="scss" scoped>
.operational {
height: calc(100% - 45px);
background-color: #50505030;
#operational-chart {
height: 100%;

View File

@@ -1,6 +1,6 @@
<template>
<div class="pv">
<div class="text_Cur">
<!-- <div class="text_Cur">
<div v-for="item in curList" :key="item.key">
<div>{{ item.name }}</div>
<div>
@@ -8,7 +8,7 @@
<span class="d">{{ item.d }}</span>
</div>
</div>
</div>
</div> -->
<div id="pv-chart"></div>
</div>
</template>
@@ -37,13 +37,13 @@ export default {
value: 0,
d: 'kW·h'
},
{
name: '入网电量',
key: 'solar_elect_grid',
lineColor: '#0E68E4',
value: 0,
d: 'kW·h'
}
// {
// name: '入网电量',
// key: 'solar_elect_grid',
// lineColor: '#0E68E4',
// value: 0,
// d: 'kW·h'
// }
],
pvChart: null,
pvChartData: {
@@ -164,6 +164,7 @@ export default {
name: '电量(kW·h)',
nameTextStyle: { color: '#fff' },
type: 'value',
splitNumber: 2,
splitLine: {
lineStyle: { type: 'dashed', color: '#435463' }
},
@@ -189,10 +190,10 @@ export default {
<style lang="scss" scoped>
.pv {
height: calc(100% - 45px);
height: calc(100% - 35px);
background-color: #50505050;
#pv-chart {
height: calc(100% - 45px);
height: calc(100% - 5px);
}
}

View File

@@ -0,0 +1,177 @@
<template>
<div class="total-station">
<div class="content-my">
<div v-for="item in myItems" :key="item.key" :class="`item ${item.class}`" >
<span style="color:#d0d0d0; margin: 0 0 0 0">{{ item.label }}</span>
<div style="margin-left: 20%;">
<span :style="{ 'color': item.color, 'font-size':'16px', 'font-weight':600}">{{ item.value ? item.value : (item.d ? 0 : '--') }}</span>
<span style="font-size:16px; margin-left: 8px;">{{ item.d }}</span>
</div>
</div>
</div>
<!-- <div class="content-left">
<div v-for="item in leftList" :key="item.key" :class="`item ${item.class}`">
<span>{{ item.label }}</span>
<div>
<span>{{ item.value ? item.value : 0 }}</span
><span class="d">{{ item.d }}</span>
</div>
</div>
</div> -->
<!-- <div class="online-icon"></div> -->
<!-- <div class="content-right">
<div v-for="item in rightList" :key="item.key" :class="`item ${item.class}`">
<span>{{ item.label }}</span>
<div>
<span>{{ item.value ? item.value : 0 }}</span
><span class="d">{{ item.d }}</span>
</div>
</div>
</div> -->
</div>
</template>
<script>
export default {
name: '',
props: {
propKey: {
type: String,
default: ''
},
propData: {
type: Object,
default: () => {}
},
deviceInfo: {
type: Array,
default: () => []
}
},
data() {
return {
myItems: [
{ color:'#a0f0a0', key: 'runDays', value: 0, label:'场站运行天数', d:'天'},
// { color:'#a0f0a0', key: 'storage_device_num', value: 0, label:'储能设备数量', d:'个'},
// { color:'#a0f0a0', key: 'charge_device_num', value: 0, label:'充电设备数量', d:'个'},
// { color:'#a0f0a0', key: 'solar_device_num', value: 0, label:'光伏设备数量', d:'个'},
// { color:'#a0f0a0', key: 'solar_elect_grid', value: 0, label:'上网总电量', d:'kWh'},
{ color:'#a0f0a0', key: 'storage_elect_in', value: 0, label:'累计储能总电量', d:'kWh'},
// { color:'#a0f0a0', key: 'charge_elect_out', value: 0, label:'充电桩充电总电量', d:'kWh'},
// { color:'#a0f0a0', key: 'solar_elect_gen', value: 0, label:'光伏发电总电量', d:'kWh'},
{ color:'#a0f0a0', key: 'income_elect', value: 0, label:'累计收益总金额', d:'元'},
// { color:'#a0f0a0', key: 'storage_elect_out', value: 0, label:'储能放电总电量', d:'kWh'},
{ color:'#a0f0a0', key: 'storage_status', value: '空闲', label:'储能状态'},
{ color:'#a0f0a0', key: 'charge_status', value: '空闲', label:'充电状态'},
{ color:'#a0f0a0', key: 'pv_status', value: '离线', label:'光伏状态'},
],
}
},
computed: {
},
watch: {
propKey: {
handler(newVal, oldVal) {
// if (this.propKey === 'totalStation') this.myItems[0].label = '场站运行天数'
},
immediate: true,
},
propData: {
handler(newVal, oldVal) {
if (newVal && newVal !== oldVal) {
this.myItems.forEach((item) => {
item.value = newVal[item.key] || (item.d ? 0 : '')
if (item.value === '离线' || item.value === '故障') item.color = '#f08080'
else if (item.value === '空闲') item.color = '#f0f0a0'
else if (item.value === '充电' || item.value === '放电' || item.value === '发电') item.color = '#f0f0a0'
})
}
},
immediate: true,
deep: true
}
},
mounted() {},
methods: {}
}
</script>
<style lang="scss" scoped>
.total-station {
height: calc(100% - 45px);
display: flex;
justify-content: center;
align-items: center;
padding-left: 0px;
}
.item {
height: calc(50% - 10px);
background: url('../../assets//home/onLineBg.png');
background-size: contain;
background-size: 100% 100%;
background-repeat: no-repeat;
padding: 8px 3px;
min-width: 115px;
display: flex;
flex-direction: column;
background-color: #072d42;
& > span:nth-child(1) {
font-size: 12px;
margin-bottom: 10px;
}
.d {
margin-left: 1px;
font-size: 12px;
}
}
.content-my {
// background-color: chocolate;
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
// align-items: center;
justify-content: flex-start;
height: 100%;
.item {
width: calc(33% - 6px);
margin-left: 3px;
margin-right: 3px;
margin-top: 8px;
}
}
.content-left,
.content-right {
width: 40%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
height: 100%;
.item {
align-items: flex-start;
justify-content: center;
}
}
.online-icon {
width: 20%;
height: 130px;
background-image: url('@/assets/home/onLineIcon.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.item-3 {
margin-right: auto;
}
.item-4 {
margin-left: auto;
}
</style>

View File

@@ -1,6 +1,16 @@
<template>
<div class="onLine">
<div class="content-left">
<div class="content-my">
<div v-for="item in myItems" :key="item.key" :class="`item ${item.class}`" >
<span style="height: 50%; color:#d0d0d0; margin:0 0 0 0">{{ item.label }}</span>
<div style="height: 50%; margin-left: 20%;">
<span style="color:#a0f0a0; font-size:16px; font-weight:600;">{{ item.value ? item.value : 0 }}</span>
<span style="font-size:16px; margin-left: 8px;">{{ item.d }}</span>
</div>
</div>
</div>
<!-- <div class="content-left">
<div v-for="item in leftList" :key="item.key" :class="`item ${item.class}`">
<span>{{ item.label }}</span>
<div>
@@ -8,9 +18,9 @@
><span class="d">{{ item.d }}</span>
</div>
</div>
</div>
<div class="online-icon"></div>
<div class="content-right">
</div> -->
<!-- <div class="online-icon"></div> -->
<!-- <div class="content-right">
<div v-for="item in rightList" :key="item.key" :class="`item ${item.class}`">
<span>{{ item.label }}</span>
<div>
@@ -18,7 +28,7 @@
><span class="d">{{ item.d }}</span>
</div>
</div>
</div>
</div> -->
</div>
</template>
@@ -26,11 +36,11 @@
export default {
name: '',
props: {
infoKey: {
propKey: {
type: String,
default: ''
},
total: {
propData: {
type: Object,
default: () => {}
},
@@ -41,13 +51,26 @@ export default {
},
data() {
return {
myItems: [
{ key: 'runDays', value: 0, label:'系统运行天数', d:'天'},
{ key: 'storage_device_num', value: 0, label:'储能设备数量', d:'个'},
{ key: 'charge_device_num', value: 0, label:'充电设备数量', d:'个'},
{ key: 'solar_device_num', value: 0, label:'光伏设备数量', d:'个'},
{ key: 'solar_elect_grid', value: 0, label:'上网总电量', d:'kWh'},
{ key: 'storage_elect_in', value: 0, label:'储能充电总电量', d:'kWh'},
{ key: 'charge_elect_out', value: 0, label:'充电桩充电总电量', d:'kWh'},
{ key: 'solar_elect_gen', value: 0, label:'光伏发电总电量', d:'kWh'},
{ key: 'income_elect', value: 0, label:'累计收益总金额', d:'元'},
{ key: 'storage_elect_out', value: 0, label:'储能放电总电量', d:'kWh'},
],
curList: [
{
key: 'runDays', //根据launch_date字段计算得出
value: 20,
d: '天',
label: '系统运行天数',
class: 'item-1'
class: 'item-2'
},
{
key: 'income_total',
@@ -97,10 +120,16 @@ export default {
},
watch: {
total: {
propKey: {
handler(newVal, oldVal) {
if (this.propKey === 'totalStation') this.myItems[0].label = '场站运行天数'
},
immediate: true,
},
propData: {
handler(newVal, oldVal) {
if (newVal && newVal !== oldVal) {
this.curList.forEach((item) => {
this.myItems.forEach((item) => {
item.value = newVal[item.key] || 0
})
}
@@ -128,8 +157,8 @@ export default {
background-size: contain;
background-size: 100% 100%;
background-repeat: no-repeat;
padding: 10px 8px;
min-width: 115px;
padding: 3px 3px;
// min-width: 100px;
display: flex;
flex-direction: column;
background-color: #072d42;
@@ -143,6 +172,22 @@ export default {
font-size: 12px;
}
}
.content-my {
// background-color: chocolate;
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
// align-items: center;
justify-content: flex-start;
height: 100%;
.item {
width: calc(25% - 6px);
margin-left: 3px;
margin-right: 3px;
margin-top: 8px;
}
}
.content-left,
.content-right {

View File

@@ -1,6 +1,11 @@
<template>
<div class="device" ref="device">
<div class="device-item" v-for="item in deviceList" :key="item">
<div class="device" ref="device" :style="{ width: systemType==2 ? '420px': '100%'}">
<div class="device-item"
v-for="item in deviceList" :key="item.device_id"
@click="chooseItem(item)"
:class="systemType==2 && selectedDeviceId==item.device_id ? 'active' : ''"
:style="{minWidth: systemType==2 ? '420px' : '380px'}"
>
<div class="item-header">
<div style="display: flex; width: 50%">
<div class="icon-bg">
@@ -9,7 +14,7 @@
<div class="title">
<span class="number type">{{ item.typename }}</span>
<span class="name" :title="item.name">{{ item.name }}</span>
<span class="number">{{ item.device_id }}</span>
<span class="number"></span>
</div>
</div>
@@ -18,60 +23,31 @@
<a-tag :color="item.is_online == 1 ? 'green' : 'red'">{{
['离线', '在线'][item.is_online]
}}</a-tag>
<span class="text">在线状态</span>
</div>
<div class="status-item">
<a-tag :color="item.is_error == 0 ? 'green' : 'red'">{{
['正常', '错误'][item.is_error]
}}</a-tag>
<span class="text">故障状态</span>
<!-- <span class="text">在线状态</span> -->
</div>
<div class="status-item">
<a-tag :color="item.is_running == 0 ? 'orange' : 'green'">{{
['空闲', '工作'][item.is_running]
}}</a-tag>
<span class="text">工作状态</span>
<!-- <span class="text">工作状态</span> -->
</div>
<div class="status-item">
<a-tag :color="item.is_error == 0 ? 'green' : 'red'">{{
['正常', '故障'][item.is_error]
}}</a-tag>
<!-- <span class="text">故障状态</span> -->
</div>
</div>
</div>
<div class="item-gun" v-if="item.type == 106">
<div class="gun">
<div class="header">
<div class="verline"></div>
<span>1</span>
</div>
<div class="gun-content">
<div v-for="info in item.params" :key="info.k" class="gun-info">
<span class="text">{{ info.k }}</span>
<span class="value">{{ info.v }}</span>
</div>
</div>
</div>
<div class="gun">
<div class="header">
<div class="verline"></div>
<span>2</span>
</div>
<div class="gun-content">
<div v-for="info in item.params1" :key="info.k" class="gun-info">
<span class="text">{{ info.k }}</span>
<span class="value">{{ info.v }}</span>
</div>
</div>
</div>
</div>
<div class="item-content" v-else>
<div class="item-content" v-if="systemType!=2">
<div v-for="info in item.params" :key="info.k" class="item-info">
<span class="text">{{ info.k }}</span>
<span class="value">{{ info.v }}</span>
</div>
</div>
<div class="item-button">
<div class="item-button" v-if="systemType!=2">
<div v-if="item.view == 1">
<span class="text">实时数据</span>
<a-button type="primary" size="small" @click="openModal(item, 1)">查看</a-button>
@@ -82,54 +58,82 @@
</div>
</div>
</div>
<a-modal
v-model:open="modalOpen"
@ok="handleOk"
width="60%"
class="modal-device"
:get-container="() => $refs.device"
>
<div v-if="modalComponent == 1" class="modal-content">
<div class="item">
<div class="title">
电流电压
<!-- <div>电流电压</div>
<img src="@/assets/images/titleLine.png" alt="" /> -->
</div>
<div class="echarts">
<predictEcharts
:chart-options="chartOptions[0]"
:chart-data="chartData"
ref="chartRef1"
/>
</div>
</div>
<div class="item">
<div class="title">功率</div>
<div class="echarts">
<predictEcharts
:chart-options="chartOptions[1]"
:chart-data="chartData"
ref="chartRef2"
/>
</div>
</div>
</div>
<div class="content-table" style="height: 600px" v-else>
<a-table
:columns="columns"
:data-source="tableData"
size="small"
:scroll="{ y: 500 }"
:pagination="false"
row-class-name="no-hover-row"
row-key="id"
>
</a-table>
</div>
</a-modal>
</div>
<div style="width: calc(100% - 500px);" v-if="systemType==2">
<div class="item-gun" >
<div class="gun">
<div class="header">
<div class="verline"></div>
<span style="font-size: 16px; font-weight: 1000; color: #5bcdd1">1</span>
</div>
<div class="gun-content">
<div v-for="info in (selectedItem ? selectedItem.params : [])" :key="info.k" class="gun-info">
<span class="text">{{ info.k }}</span>
<span class="value">{{ info.v }}</span>
</div>
</div>
</div>
<div class="gun">
<div class="header">
<div class="verline"></div>
<span style="font-size: 16px; font-weight: 1000; color: #5bcdd1">2</span>
</div>
<div class="gun-content">
<div v-for="info in (selectedItem ? selectedItem.params1 : [])" :key="info.k" class="gun-info">
<span class="text">{{ info.k }}</span>
<span class="value">{{ info.v }}</span>
</div>
</div>
</div>
</div>
</div>
<a-modal
v-model:open="modalOpen"
@ok="handleOk"
width="60%"
class="modal-device"
:get-container="() => $refs.device"
>
<div v-if="modalComponent == 1" class="modal-content">
<div class="item">
<div class="title">
电流电压
<!-- <div>电流电压</div>
<img src="@/assets/images/titleLine.png" alt="" /> -->
</div>
<div class="echarts">
<predictEcharts
:chart-options="chartOptions[0]"
:chart-data="chartData"
ref="chartRef1"
/>
</div>
</div>
<div class="item">
<div class="title">功率</div>
<div class="echarts">
<predictEcharts
:chart-options="chartOptions[1]"
:chart-data="chartData"
ref="chartRef2"
/>
</div>
</div>
</div>
<div class="content-table" style="height: 600px" v-else>
<a-table
:columns="columns"
:data-source="tableData"
size="small"
:scroll="{ y: 500 }"
:pagination="false"
row-class-name="no-hover-row"
row-key="id"
>
</a-table>
</div>
</a-modal>
</template>
<script>
@@ -147,13 +151,15 @@ export default {
systemType: {
type: Number,
default: 1
}
},
propType: { type: Number, default: 1 }
},
data() {
return {
modalOpen: false,
deviceList: [],
selectedDeviceId: undefined,
selectedItem: undefined,
chartOptions: [
{
type: 'line',
@@ -270,11 +276,16 @@ export default {
// 监听父组件数据变化
stationId(newVal) {
if (newVal) {
this.selectedItem = undefined
this.selectedDeviceId = undefined
this.getDeviceList()
}
},
systemType(newVal, oldVal) {
if (newVal !== oldVal) {
this.selectedItem = undefined
this.selectedDeviceId = undefined
this.deviceList = []
this.getDeviceList()
}
}
@@ -282,7 +293,7 @@ export default {
mounted() {
this.getDeviceList()
this.timer=setInterval(() => {
this.getDeviceList()
// this.getDeviceList()
}, 20000)
},
@@ -291,6 +302,10 @@ export default {
},
methods: {
chooseItem(item) {
this.selectedItem = item
this.selectedDeviceId = item.device_id
},
handlePagesizeChange(pageOption) {
this.pageOption.pageSize = pageOption.pageSize
this.pageOption.page = pageOption.page
@@ -313,7 +328,6 @@ export default {
// 格式化小时和分钟,确保两位数
const formattedHour = hour.toString().padStart(2, '0')
const formattedMinute = minute.toString().padStart(2, '0')
timePoints.push(`${formattedHour}:${formattedMinute}`)
}
}
@@ -363,13 +377,19 @@ export default {
//请求运行监控系统设备信息
async getDeviceList() {
try {
const res = await getReq('/queryDevicByCategory', {
station_id: this.stationId,
category: this.systemType
})
if (this.selectedDeviceId == undefined) {
if (res.data.length > 0) {
this.selectedItem = res.data[0]
this.selectedDeviceId = this.selectedItem.device_id
}
}
this.deviceList = res.data
this.$emit('updateGatewayData', res.gateway);
} catch (error) {
this.deviceList = []
@@ -395,12 +415,13 @@ export default {
<style lang="scss" scoped>
.device {
// background-color: #08a5ff;
width: 100%;
height: 100%;
margin-left: 20px;
display: flex;
flex-wrap: wrap;
grid-gap: 20px;
grid-gap: 15px;
overflow-y: auto;
align-content: flex-start;
// grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
@@ -408,10 +429,16 @@ export default {
border-radius: 15px;
background: $bg2-color;
padding: 15px;
min-width: 390px;
min-width: 380px;
max-width: 450px;
width: calc(25% - 15px);
// height: 260px;
flex: 1;
// flex: 1;
cursor: pointer;
&:hover {
border: 1px solid #aaa;
}
.item-header {
display: flex;
align-items: center;
@@ -491,47 +518,6 @@ export default {
height: 24px;
}
}
.item-gun {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
width: 100%;
.gun {
border: 1px solid #37d6d970;
border-radius: 5px;
margin: 5px 0;
}
.header {
height: 20px;
font-size: 12px;
display: flex;
align-items: center;
margin: 5px;
.verline {
margin-right: 10px;
background: linear-gradient(
180deg,
rgba(0, 230, 172, 1) 0%,
rgba(0, 210, 255, 1) 98.78%,
rgba(0, 210, 255, 1) 100%
),
rgba(1, 223, 239, 1);
width: 4px;
height: 15px;
border-radius: 6px;
}
}
.gun-content {
display: grid;
grid-template-columns: 1fr;
height: 120px;
padding: 0 5px;
overflow-y: auto;
.gun-info {
height: 30px;
}
}
}
.item-button {
display: grid;
grid-template-columns: 1fr 1fr;
@@ -550,6 +536,12 @@ export default {
margin-top: 10px;
}
}
.active {
// background: #012036;
border: 1px solid #aaa;
}
.content-table {
height: 700px;
margin-top: 40px;
@@ -564,6 +556,60 @@ export default {
}
}
}
.item-gun {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
width: 100%;
height: 100%;
.gun {
border: 1px solid #37d6d970;
border-radius: 5px;
margin: 5px 0;
}
.header {
height: 20px;
font-size: 12px;
display: flex;
align-items: center;
margin: 5px;
.verline {
margin-right: 10px;
background: linear-gradient(
180deg,
rgba(0, 230, 172, 1) 0%,
rgba(0, 210, 255, 1) 98.78%,
rgba(0, 210, 255, 1) 100%
),
rgba(1, 223, 239, 1);
width: 4px;
height: 15px;
border-radius: 6px;
}
}
.gun-content {
display: grid;
grid-template-columns: 1fr;
height: 200px;
padding: 0 5px;
overflow-y: auto;
.gun-info {
height: 30px;
.text {
margin-left: 20px;
color: $text-color;
font-size: 14px;
}
.value {
font-weight: 700;
font-size: 16px;
}
}
}
}
.environment {
width: 200px;
}

View File

@@ -1,5 +1,5 @@
<template>
<div class="videosPage" id="videosPage">
<!-- <div class="videosPage" id="videosPage">
<div
class="content"
:class="videosPageWidth < 900 ? 'con-w2' : 'con-w1'"
@@ -8,9 +8,29 @@
>
<haikang :index="index" :item="item" class="video"></haikang>
</div>
</div>
</div> -->
<div class="environment">
<div class="tab-header">
<!-- <div style="display: flex; flex-direction: row;"> -->
<!-- <div style="background-color: chocolate; width: 24%; height: 100px; margin: 5px 5px 5px 5px;"> </div>
<div style="background-color: chocolate; width: 24%; height: 100px; margin: 5px 5px 5px 5px;"> </div>
<div style="background-color: chocolate; width: 24%; height: 100px; margin: 5px 5px 5px 5px;"> </div>
<div style="background-color: chocolate; width: 24%; height: 100px; margin: 5px 5px 5px 5px;"> </div> -->
<div class="env-content">
<div v-for="item in tabList" :key="item.key" class="env-item">
<div class="tab">
<span :class="['uactived']" @click="activeTab = item.key">{{ item.name
}}</span>
</div>
<div class="table-content">
<ComTable :columns="columns[item.key]" :table-data="tableDatas[item.key]" ref="comTable"
:table-option="{ page: false, select: false }">
</ComTable>
</div>
</div>
</div>
<!-- </div> -->
<!-- <div class="tab-header">
<div v-for="item in tabList" :key="item.key" class="tab">
<span
:class="[activeTab == item.key ? 'actived' : 'uactived']"
@@ -27,7 +47,7 @@
:table-option="{ page: false, select: false }"
>
</ComTable>
</div>
</div> -->
</div>
</template>
@@ -128,15 +148,14 @@ export default {
key: 'cooling',
name: '冷机信息'
},
{
key: 'fire40',
name: '消防信息'
},
{
key: 'airc',
name: '空调信息'
},
{
key: 'fire40',
name: '消防信息'
}
],
tableDatas: {},
@@ -161,9 +180,9 @@ export default {
},
mounted() {
this.$nextTick(() => {
const div = document.getElementById('videosPage')
const width = div.offsetWidth
this.videosPageWidth = width
// const div = document.getElementById('videosPage')
// const width = div.offsetWidth
// this.videosPageWidth = width
})
this.getEnvironment()
@@ -233,10 +252,42 @@ export default {
}
}
.environment {
width: 430px;
width: 100%; //430px;
margin-left: 20px;
color: #fff;
.env-content {
width: 100%;
height: 100%;
display: flex;
.env-item {
width: 24%;
.tab {
&>span {
font-size: 14px;
margin-right: 15px;
display: inline-block;
padding: 10px;
// cursor: pointer;
border: 1px solid $tab-border;
border-radius: 4px;
text-align: center;
width: 50%;
}
}
.actived {
color: #ffffff;
background-color: $green;
}
.uactived {
color: #a6b8dd;
background-color: $bg2-color;
}
}
}
.title {
font-size: 24px;
font-weight: 700;
@@ -291,6 +342,7 @@ export default {
}
.table-content {
margin-top: 20px;
margin-right: 10px;
height: calc(100% - 60px);
:deep(.ant-table) {
border-radius: 10px 10px 0 0 !important;

View File

@@ -128,6 +128,7 @@ export default {
getCommonOption(option, dataKeys, isLineChart = false) {
console.log(option,"ooooooooooooo")
return {
animation: false,
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
@@ -197,9 +198,9 @@ export default {
series: option.infoKeys.map((info, i) => ({
name: info.label,
type: 'bar',
barWidth: 10,
barWidth: '20%',
itemStyle: {
borderRadius: [10, 10, 0, 0],
borderRadius: [0, 0, 0, 0],
color: info.lineColor,
},
index:option.yAxisOption&&option.yAxisOption.length?i:1,

View File

@@ -8,9 +8,9 @@ export function getRunDays(date) {
return daysRun
}
export function processData(data, keys) {
data.sort((a, b) => {
return new Date(a.dt) - new Date(b.dt)
})
// data.sort((a, b) => {
// return new Date(a.dt) - new Date(b.dt)
// })
const dates = data.map((item) => item.dt)
const values = []
keys.forEach((item, index) => {

View File

@@ -9,9 +9,9 @@
>{{ station.name }}
</a-select-option>
</a-select>
<a-button type="primary" @click="handleMessage" style="margin-left: 20px">查看预制舱参数</a-button>
<a-button type="primary" @click="openDispatchModeModal" style="margin-left: 20px">模式设置</a-button>
<a-button type="primary" @click="openDispatchParamModal" style="margin-left: 20px">参数设置</a-button>
<a-button type="primary" @click="handleMessage" style="margin-left: 20px">运行参数查看</a-button>
<a-button type="primary" @click="openDispatchModeModal" style="margin-left: 20px">运行模式设置</a-button>
<a-button type="primary" @click="openDispatchParamModal" style="margin-left: 20px">运行参数设置</a-button>
</div>
</div>
<!-- <div class="right">
@@ -133,11 +133,11 @@ export default {
msgModal: false,
systems: [
{
name: '储能系统',
name: '储能设备',
titles: [
{ v: '运行模式', key: 'workmode' },
{ v: '储能EMU状态', key: 'emu' },
{ v: '充电桩状态', key: 'cdz' }
// { v: '运行模式', key: 'workmode' },
// { v: '储能EMU状态', key: 'emu' },
// { v: '充电桩状态', key: 'cdz' }
//{ v: '总有功功率(台区)', key: 'power', sufix: 'kW' }
],
power: 60,
@@ -145,33 +145,33 @@ export default {
systemType: 1
},
{
name: '充电系统',
name: '充电设备',
power: 60,
num: 62,
systemType: 2,
titles: [
//{ v: '总功率', key: 'power', sufix: 'kW' },
{ v: '数量', key: 'num' }
// { v: '数量', key: 'num' }
]
},
{
name: '光伏系统',
name: '光伏设备',
power: 60,
num: 62,
systemType: 3,
titles: [
//{ v: '总功率', key: 'power', sufix: 'kW' },
{ v: '数量', key: 'num' }
// { v: '数量', key: 'num' }
]
},
{
name: '安防系统',
name: '辅助设备',
power: 60,
num: 62,
systemType: 4,
titles: [
// { v: '总功率', key: 'power', sufix: 'kW' },
{ v: '数量', key: 'num' }
// { v: '数量', key: 'num' }
]
}
// {
@@ -203,7 +203,7 @@ export default {
},
{
value: 5,
label: '自定时段'
label: '运营支撑'
}
],
deviceGroup: [],
@@ -224,7 +224,7 @@ export default {
{ value: '2', label: '配网增容' },
{ value: '3', label: '应急供电' },
{ value: '4', label: '并网保电' },
{ value: '5', label: '自定时段' }
{ value: '5', label: '运营支撑' }
],
options: { label: 'label', value: 'value' }
}
@@ -509,7 +509,6 @@ export default {
chooseStation(system) {
console.log(system, 'system')
this.systemType = system.systemType
}
}
@@ -551,40 +550,43 @@ export default {
display: flex;
justify-content: space-between;
.stations {
display: grid;
display: flex;
flex-direction: column;
//grid-template-rows: repeat(auto-fit, minmax(140px, 4fr));
border-radius: 12px;
background: $bg2-color;
padding-top: 15px;
grid-template-rows: repeat(auto-fit, minmax(140px, 4fr));
.station-item {
flex: 1;
// flex: 1;
margin: 0 15px 15px 15px;
border-radius: 12px;
border-radius: 10px;
width: 180px;
height: 50px;
display: flex;
flex-direction: column;
color: #fff;
padding: 10px 10px;
// color: #fff;
// padding: 10px 10px;
cursor: pointer;
&:hover {
background: $table-bg;
}
.name {
padding-left: 20px;
font-size: 20px;
font-weight: 700;
line-height: 50px;
}
.des {
font-size: 14px;
font-weight: 600;
line-height: 30px;
display: inline-block;
max-width: 160px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
// .des {
// font-size: 14px;
// font-weight: 600;
// line-height: 30px;
// display: inline-block;
// max-width: 160px;
// white-space: nowrap;
// overflow: hidden;
// text-overflow: ellipsis;
// }
}
.active {
background: $bg3-color;

View File

@@ -1,7 +1,7 @@
<template>
<div class="Home">
<div class="content-left">
<div v-for="item in leftList" :key="item.componentId" :class="`grid-item ${item.class}`">
<div v-for="item in listLeft" :key="item.componentId" :class="`grid-item ${item.class}`">
<div class="tool">
<div class="title">
<i class="iconfont icon-hebing linear-text"></i>
@@ -9,30 +9,32 @@
</div>
</div>
<component
:is="item.componentId"
:info-key="item.infoKey"
:device-info="deviceInfo[item.infoKey]"
:total="item.infoKey === 'onLineTotal' ? deviceInfo.onLine : deviceInfo.allTotal"
></component>
<component :is="item.componentId" :prop-key="item.infoKey" :prop-option="compInfo[item.infoKey]"
:prop-data="compData[item.infoKey]">
</component>
</div>
</div>
<div class="tianditu">
<Map @changeStation="getCurrentStation"></Map>
</div>
<div class="content-right">
<div v-for="item in rightList" :key="item.componentId" :class="`grid-item ${item.class}`">
<div style="width:100%; height:32px;">
<span style="width:120px">场站选择</span>
<a-select v-model:value="selectStationId" style="margin-left: 10px; width: 200px;" @change="getStationChange">
<a-select-option v-for="station in stationList" :value="station['station_id']">{{ station.name }}
</a-select-option>
</a-select>
</div>
<div v-for="item in listRight" :key="item.componentId" :class="`grid-item ${item.class}`">
<div class="tool">
<div class="title">
<i class="iconfont icon-hebing linear-text"></i>
<span class="linear-text">{{ item.title }}</span>
</div>
</div>
<component
:is="item.componentId"
:device-info="deviceInfo[item.infoKey]"
:total="item.infoKey === 'onLineTotal' ? deviceInfo.onLine : deviceInfo.allTotal"
></component>
<component :is="item.componentId" :prop-key="item.infoKey" :prop-option="compInfo[item.infoKey]"
:prop-data="compDataStation[item.infoKey]">
</component>
</div>
</div>
</div>
@@ -40,12 +42,14 @@
<script>
import onLine from '@/components/Home/onLine.vue'
import TotalStation from '@/components/Home/TotalStation.vue'
import Operational from '@/components/Home/Operational.vue'
import Energy from '@/components/Home/Energy.vue'
import Charge from '@/components/Home/Charge.vue'
import Pv from '@/components/Home/Pv.vue'
import Alarm from '@/components/Home/Alarm.vue'
import Map from '@/components/Home/Map.vue'
import MyChartBar from '@/components/Home/MyChartBar.vue'
import { getReq, postReq } from '@/request/api'
import { getRunDays, getDateDaysAgo } from '@/utils/dealWithData'
import { markRaw } from 'vue'
@@ -54,13 +58,70 @@ export default {
components: { Map },
data() {
return {
refreshInterval:null,
refreshInterval: null,
showFlag: false,
stationId: null,
deviceInfo: {},
compData: {
total: {},
energy: [],
charge: [],
pv: [],
stateGrid: [],
},
compDataStation: {
totalStation: {},
energy: [],
charge: [],
pv: [],
stateGrid: [],
},
compInfo: {
total: {},
energy: {
yAxis: ['电量(kWh)'],
series: [
{ name: '日充电电量', key: 'storage_elect_in', color: '#22E4FF' },
{ name: '日放电电量', key: 'storage_elect_out', color: '#0E68E4' },
]
},
pv: {
yAxis: ['电量(kWh)'],
series: [
{ name: '日发电电量', key: 'solar_elect_gen', color: '#22E4FF' },
]
},
charge: {
yAxis: ['电量(kWh)'],
series: [
{ name: '日充电电量', key: 'charge_elect', color: '#22E4FF' },
]
},
stateGrid: {
yAxis: ['电量(kWh)'],
series: [
{ name: '日上网电量', key: 'solar_elect_grid', color: '#22E4FF' },
]
}
},
listLeft: [
{ title: '系统运行统计', class: 'online-status', componentId: markRaw(onLine), infoKey: 'total' },
{ title: '储能设备', class: 'energy-status', componentId: markRaw(MyChartBar), infoKey: 'energy' },
{ title: '充电设备', class: 'charge-analysis', componentId: markRaw(MyChartBar), infoKey: 'charge' },
{ title: '光伏设备', class: 'work-order', componentId: markRaw(MyChartBar), infoKey: 'pv' },
{ title: '电网侧', class: 'work-order', componentId: markRaw(MyChartBar), infoKey: 'stateGrid' },
],
listRight: [
{ title: '场站运行统计', class: 'online-status', componentId: markRaw(TotalStation), infoKey: 'totalStation' },
{ title: '储能设备', class: 'energy-status', componentId: markRaw(MyChartBar), infoKey: 'energy' },
{ title: '充电设备', class: 'charge-analysis', componentId: markRaw(MyChartBar), infoKey: 'charge' },
{ title: '光伏设备', class: 'work-order', componentId: markRaw(MyChartBar), infoKey: 'pv' },
{ title: '电网侧', class: 'work-order', componentId: markRaw(MyChartBar), infoKey: 'stateGrid' },
],
stationList: [],
selectStationId: '',
list: [
{
title: '运行状态',
title: '系统运行统计',
class: 'online-status',
componentId: markRaw(onLine),
infoKey: 'onLineTotal'
@@ -83,7 +144,6 @@ export default {
componentId: markRaw(Charge),
infoKey: 'charge'
},
{
title: '光伏设备',
class: 'work-order',
@@ -104,93 +164,96 @@ export default {
},
computed: {
leftList() {
return this.list.filter((_, index) => index % 2 === 0).slice(0, 3) // 左列取前3个偶数索引
return {} //this.list.filter((_, index) => index % 2 === 0).slice(0, 3) // 左列取前3个偶数索引
},
rightList() {
return this.list.filter((_, index) => index % 2 !== 0).slice(0, 3) // 右列取前3个奇数索引
return {} //this.list.filter((_, index) => index % 2 !== 0).slice(0, 3) // 右列取前3个奇数索引
}
},
beforeUnmount() {
if(this.refreshInterval){
if (this.refreshInterval) {
clearInterval(this.refreshInterval)
this.refreshInterval=null
this.refreshInterval = null
}
},
async mounted() {
await this.getStationList()
await this.loadAllData()
this.refreshInterval=setInterval(async()=>{
this.refreshInterval = setInterval(async () => {
await this.loadAllData()
},30000) //30s刷新一次
}, 30000) //30s刷新一次
},
methods: {
async loadAllData(){
async loadAllData() {
await Promise.all([
this.getOnLineList(),
this.getStatTotalList(),
this.getOperTotalList(),
this.getStatDayList(1),
this.getStatDayList(2),
this.getStatDayList(3)
this.queryStatTotal(),
this.queryStatTotal(this.selectStationId),
// this.getOperTotalList(),
this.getStatDayList(),
this.getStatDayList(this.selectStationId),
// this.getStatDayList(1),
// this.getStatDayList(2),
// this.getStatDayList(3)
]).then((r) => {
if (
this.deviceInfo.energy &&
this.deviceInfo.charge &&
this.deviceInfo.pv
) {
const newArr = this.mergedArray(
this.deviceInfo.energy,
this.deviceInfo.charge,
this.deviceInfo.pv
)
this.deviceInfo.alarm = newArr
}
// if (
// this.compData.energy &&
// this.compData.charge &&
// this.compData.pv
// ) {
// const newArr = this.mergedArray(
// this.compData.energy,
// this.compData.charge,
// this.compData.pv
// )
// this.compData.alarm = newArr
// }
})
},
getCurrentStation(e) {
this.stationId = e
},
// 查询系统统计信息
async getOnLineList() {
// 查询系统的场站列表
async getStationList() {
try {
// token: 用户TOKEN
const res = await getReq('/queryStatSystem')
const res = await getReq('/queryStationList', { page: 0, page_size: 100 })
if (res.errcode === 0) {
this.deviceInfo.onLine = JSON.parse(JSON.stringify(res.data))
this.deviceInfo.onLine.runDays = getRunDays(res.data.launch_date)
// 设置场站下拉列表,默认选中第一项
this.stationList = res.data
this.selectStationId = this.stationList[0]['station_id']
} else {
throw res
}
} catch (error) {
this.deviceInfo.onLine = {}
this.stationList = []
this.selectStationId = ''
}
},
// 查询系统累计统计信息
async getStatTotalList() {
// 查询系统累计统计信息, 不传参数 curStationId 时查询所有场站数据
async queryStatTotal(curStationId) {
try {
// token: 用户TOKEN
// date:日期
// station_id:场站ID为0或不传查询所有场站总计
// category:类别1:储能设备,2:充电设备,3:光伏设备,为0或不传查询所有类别总计
const query = {
date: getDateDaysAgo(0),
station_id: this.stationId,
category: 0
}
const res = await getReq('/queryStatTotal', query)
const res = await getReq('/queryStatTotal', { station_id: curStationId })
if (res.errcode === 0) {
this.deviceInfo.allTotal = res.data
const { income_charge: incomeCharge, income_elect: incomeElect } =
this.deviceInfo.allTotal
this.deviceInfo.allTotal.incomeTotal = +incomeCharge + +incomeElect
// this.compData.total = res.data
// const { income_charge: incomeCharge, income_elect: incomeElect } =
// this.compData.total
// this.compData.total.incomeTotal = +incomeCharge + +incomeElect
// this.compData.total.runDays = getRunDays(res.data.launch_date)
if (curStationId === undefined) {
this.compData.total = res.data
this.compData.total.runDays = getRunDays(res.data.launch_date)
} else {
this.compDataStation.totalStation = res.data
this.compDataStation.totalStation.runDays = getRunDays(res.data.launch_date)
}
} else {
throw res
}
} catch (error) {
this.deviceInfo.allTotal = {}
this.deviceInfo.allTotal.incomeTotal = 0
this.compData.total = {}
this.compData.total.incomeTotal = 0
}
},
// 运行分析 联调
@@ -198,35 +261,56 @@ export default {
try {
const res = await getReq('/queryStatStation', {})
if (res.errcode === 0) {
this.deviceInfo.operationTotal = res.data
this.compData.operationTotal = res.data
} else {
throw res
}
} catch (error) {
this.deviceInfo.operationTotal = [ ]
this.compData.operationTotal = []
}
},
// 示例获取7天前的日期
// 查询场站日统计信息
async getStatDayList(category) {
// 查询近7日的统计信息
async getStatDayList(curStationId) {
try {
if (curStationId === '') {
return
}
// station_id: 场站ID
// category: 类别: 1储能设备,2:充电设备,3:光伏设备
// start_date开始日期格式yyyy-mm-dd
// end_date结束日期格式yyyy-mm-dd
const query = {
station_id: this.stationId,
category,
let query = {
//station_id: this.stationId,
// category,
start_date: getDateDaysAgo(7 - 1),
end_date: getDateDaysAgo(0)
}
const arr = { 1: 'energy', 2: 'charge', 3: 'pv' }
if (curStationId) {
query.station_id = curStationId
}
//const arr = { 1: 'energy', 2: 'charge', 3: 'pv' }
const res = await getReq('/queryStatDayList', query)
if (res.errcode === 0) {
this.list.forEach((item) => {
this.deviceInfo[arr[category]] = res.data
})
if (curStationId) {
this.compDataStation.energy
= this.compDataStation.charge
= this.compDataStation.pv
= this.compDataStation.stateGrid
= res.data
} else {
this.compData.energy
= this.compData.pv
= this.compData.stateGrid
= this.compData.charge
= res.data
}
// this.list.forEach((item) => {
// //this.compData[arr[category]] = res.data
// alert(JSON.stringify(item))
// return
// })
} else {
throw res
}
@@ -251,6 +335,10 @@ export default {
})
})
return newArr
},
getStationChange() {
this.queryStatTotal(this.selectStationId),
this.getStatDayList(this.selectStationId)
}
}
}
@@ -278,13 +366,13 @@ export default {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
justify-content: flex-start;
}
.grid-item {
box-sizing: border-box;
width: 100%;
height: calc(33% - 10px);
height: calc(25% - 10px);
z-index: 20;
.tool {
@@ -295,7 +383,7 @@ export default {
display: flex;
justify-content: space-between;
align-items: center;
height: 45px;
height: 32px;
.linear-text {
background: linear-gradient(180deg, rgba(255, 255, 255, 1) 0%, rgba(40, 235, 231, 1) 100%);
@@ -335,12 +423,10 @@ export default {
margin-left: 20px;
font-size: 16px;
font-weight: 700;
background: linear-gradient(
90deg,
rgba(0, 186, 173, 0.15) 0%,
rgba(61, 254, 250, 0.15) 49.2%,
rgba(61, 254, 250, 0) 100%
);
background: linear-gradient(90deg,
rgba(0, 186, 173, 0.15) 0%,
rgba(61, 254, 250, 0.15) 49.2%,
rgba(61, 254, 250, 0) 100%);
-webkit-background-clip: text;
display: inline-block;
background-clip: text;

View File

@@ -2,30 +2,38 @@
<div class="device">
<searchBox :btn-option-list="btnOptionList" @operateForm="operateForm"></searchBox>
<div class="content-table">
<ComTable
:columns="columns"
:table-data="tableData"
@handlePagesizeChange="handlePagesizeChange"
ref="comTable"
:table-option="tableOption"
:page-option="pageOption"
>
<template #type="record">
<span>{{ getType(record.type) }}</span>
</template>
<template #isEnable="record">
<span
><a-tag :color="record.is_open == 1 ? 'green' : 'red'">{{
record.is_open == 1 ? '启用' : '禁用'
}}</a-tag></span
>
</template>
<div style="display: flex; height: calc(100% - 40px); ">
<div style="display: block; min-width:200px; width: 200px; height: 100%; overflow-y: auto; background-color: #08365c; border-radius: 5px; padding-top: 10px;">
<a-tree v-model:expandedKeys="expandedKeys" v-model:selectedKeys="selectedKeys"
v-model:checkedKeys="checkedKeys" :tree-data="stationTreeData" @select="onSelectStation">
</a-tree>
</div>
<template #action="record">
<OperateCom :record="record" :operate-list="operateList" @operateForm="operateForm" />
</template>
</ComTable>
<div class="content-table">
<ComTable
:columns="columns"
:table-data="tableData"
@handlePagesizeChange="handlePagesizeChange"
ref="comTable"
:table-option="tableOption"
:page-option="pageOption"
>
<template #type="record">
<span>{{ getType(record.type) }}</span>
</template>
<template #isEnable="record">
<span
><a-tag :color="record.is_open == 1 ? 'green' : 'red'">{{
record.is_open == 1 ? '启用' : '禁用'
}}</a-tag></span
>
</template>
<template #action="record">
<OperateCom :record="record" :operate-list="operateList" @operateForm="operateForm" />
</template>
</ComTable>
</div>
</div>
<a-modal v-model:open="formModal" width="750px" style="top: 80px" :footer="null">
<!-- action:edit add -->
@@ -75,7 +83,9 @@ export default {
paramsDate: {},
tableData: [],
tableOption: {},
stations: [] //场站列表
stations: [], //场站列表
stationTreeData: [],
selectedStationId: undefined
}
},
computed: {},
@@ -93,8 +103,8 @@ export default {
mounted() {
this.operateList = this.$getBtns(['查看', '修改', '删除'])
this.btnOptionList = this.$getBtns(['新增'])
this.getList()
this.getStations()
//this.getList()
},
methods: {
@@ -103,8 +113,11 @@ export default {
this.stations = []
try {
const res = await getReq('/queryStationList', { page: 0, page_size: 10000 })
this.stations = res.data
this.stationTreeData = []
res.data.forEach((item)=>{
this.stationTreeData.push( { title: item.name, key: item.station_id})
})
} catch (error) {
this.stations = []
}
@@ -122,6 +135,7 @@ export default {
const { page, pageSize } = this.pageOption
const params = {
station_id: this.selectedStationId,
...this.paramsDate,
page_size: pageSize,
page
@@ -216,6 +230,10 @@ export default {
this.pageOption.pageSize = pageOption.pageSize
this.pageOption.page = pageOption.page
this.getList()
},
onSelectStation(selectedKey, ) {
this.selectedStationId = selectedKey
this.getList()
}
}
}
@@ -229,6 +247,26 @@ export default {
.content-table {
width: 100%;
height: calc(100% - 52px);
margin-left: 20px;
}
}
:deep(.ant-tree-list) {
background-color: #08365c;
font-size: 16px;
color: white;
}
:deep(.ant-tree-treenode ) {
width: 100%;
height: 30px;
}
:deep(.ant-tree-node-content-wrapper) {
width: calc(100% - 34px);
height: 30px;
}
:deep(.ant-tree-node-selected) {
background-color: #27a188 !important;
border-radius: 5px !important;
}
</style>