This commit is contained in:
2025-08-11 17:34:39 +08:00
parent 7a13a73758
commit 9db3b4f9f7
9 changed files with 342 additions and 127 deletions

View File

@ -0,0 +1,94 @@
<template>
<div class="time-range">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator=""
start-placeholder="开始时间"
value-format="yyyy-MM-dd"
:clearable="false"
:picker-options="pickerOptions"
end-placeholder="结束时间">
</el-date-picker>
<el-button type="default" size="mini" style="margin-left: 10px;" :loading="loading" @click="reset">重置</el-button>
<el-button type="primary" size="mini" :loading="loading" @click="search">搜索</el-button>
<el-button type="primary" size="mini" :loading="loading" @click="timeLine('before')">上一时段</el-button>
<el-button type="primary" size="mini" :loading="loading" @click="timeLine('next')" :disabled="disabledNextBtn">下一时段</el-button>
</div>
</template>
<script>
import {formatDate} from '@/filters/ems'
export default {
computed:{
disabledNextBtn(){
return new Date(this.dateRange[1]) >= new Date(this.defaultDateRange[1])
}
},
data() {
return {
loading:false,
dateRange:[],
defaultDateRange:[],
pickerOptions:{
disabledDate(time) {
return time.getTime() > Date.now();
},
},
}
},
methods: {
init(){
const now = new Date(),formatNow = formatDate(now);
const weekAgo = formatDate(new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000))
this.dateRange = [weekAgo, formatNow];
this.defaultDateRange=[weekAgo, formatNow];
this.$emit('updateDate',this.dateRange)
},
showBtnLoading(status){
this.loading = status
},
resetDate(){
this.dateRange = this.defaultDateRange
},
//重置 设置时间范围为初始化时间段
reset(){
this.resetDate()
this.$emit('updateDate',this.dateRange)
},
// 搜索
search(){
this.$emit('updateDate',this.dateRange)
},
timeLine(type){
//baseTime,maxTime 毫秒数
let baseTime = new Date(this.dateRange[type === 'before' ? 0 : 1]).getTime(),maxTime = new Date(this.defaultDateRange[1]).getTime()
//updateTime 毫秒数
let updateTime = type === 'before' ? baseTime - 7 * 24 * 60 * 60 * 1000 : baseTime + 7 * 24 * 60 * 60 * 1000
if(type === 'next' && updateTime >= maxTime) updateTime = maxTime
const start = formatDate(type === 'before' ? updateTime : baseTime)
const end = formatDate(type === 'before' ? baseTime : updateTime)
this.dateRange = [start,end]
this.$emit('updateDate',this.dateRange)
},
}
}
</script>
<style lang="scss" scoped>
.time-range{
display: flex;
::v-deep {
.el-range-editor--medium.el-input__inner{
height: 30px;
}
.el-range-editor--medium .el-range-separator{
line-height: 24px;
}
.el-button--mini{
padding:3px 10px;
}
}
}
</style>

View File

@ -3,7 +3,7 @@
<el-card v-loading="loading" gshadow="always" class="common-card-container common-card-container-no-title-bg"> <el-card v-loading="loading" gshadow="always" class="common-card-container common-card-container-no-title-bg">
<!-- 搜索栏--> <!-- 搜索栏-->
<el-form :inline="true" class="select-container"> <el-form :inline="true" class="select-container">
<el-form-item label="设备类型"> <el-form-item label="设备清单">
<el-select v-model="search.deviceType" clearable placeholder="请选择" :loading="loading" loading-text="正在加载数据"> <el-select v-model="search.deviceType" clearable placeholder="请选择" :loading="loading" loading-text="正在加载数据">
<el-option :label="value" :value="key" v-for="(value,key) in $store.state.ems.deviceTypeOptions" :key="key+'deviceTypeOptions'"></el-option> <el-option :label="value" :value="key" v-for="(value,key) in $store.state.ems.deviceTypeOptions" :key="key+'deviceTypeOptions'"></el-option>
</el-select> </el-select>

View File

@ -1,26 +1,29 @@
<template> <template>
<el-row style="background:#fff;margin-top:30px;"> <el-card shadow="always" class="common-card-container common-card-container-body-no-padding time-range-card">
<el-col :xs="24" :sm="24" :lg="24"> <div slot="header" class="time-range-header">
<el-card shadow="always" class="common-card-container common-card-container-body-no-padding">
<div slot="header">
<span class="card-title">当日功率曲线</span> <span class="card-title">当日功率曲线</span>
<date-range-select ref="dateRangeSelect" @updateDate="updateDate"/>
</div> </div>
<div style="height: 310px" id="activeChart"></div> <div style="height: 310px" id="activeChart"></div>
</el-card> </el-card>
</el-col>
</el-row>
</template> </template>
<script> <script>
import * as echarts from 'echarts' import * as echarts from 'echarts'
import resize from '@/mixins/ems/resize' import resize from '@/mixins/ems/resize'
import DateRangeSelect from '@/components/Ems/DateRangeSelect.vue'
import {getPcsNameList, getPowerData} from '@/api/ems/dzjk'
export default { export default {
mixins: [resize], mixins: [resize],
components: {DateRangeSelect},
data() { data() {
return { return {
chart: null chart: null,
timeRange:[],
siteId:'',
deviceId:''
} }
}, },
mounted() { mounted() {
@ -36,22 +39,56 @@ export default {
this.chart = null this.chart = null
}, },
methods: { methods: {
// 更新时间范围 重置图表
updateDate(data){
this.timeRange=data
this.getGVQXData()
},
getGVQXData(){
this.showLoading()
const {siteId,deviceId,timeRange}=this
if(!deviceId) return this.hideLoading()
getPowerData({siteId,deviceId,startDate:timeRange[0],endDate:timeRange[1],dataType:'1'}).then(response => {
this.setOption(response?.data || [])
}).finally(()=>this.hideLoading())
},
init(siteId){
//初始化 清空数据
this.siteId = siteId
this.timeRange=[]
this.deviceId=''
this.$refs.dateRangeSelect.init()
this.showLoading()
getPcsNameList(siteId).then(response=>{
const data=response?.data || [];
if(data.length>0){
this.deviceId=data[0].id
//接口调用完成之后 设置图表、结束loading
this.getGVQXData()
}else{
this.hideLoading()
}
})
},
initChart() { initChart() {
this.chart = echarts.init(document.querySelector('#activeChart')) this.chart = echarts.init(document.querySelector('#activeChart'))
}, },
showLoading(){ showLoading(){
this.chart && this.chart.showLoading() this.chart && this.chart.showLoading()
}, },
hideLoading(){
this.chart && this.chart.hideLoading()
},
setOption(data) { setOption(data) {
const source = [['日期','电网功率']] const source = [['日期','电网功率']]
data.forEach((item)=>{ this.chart && data.forEach((item)=>{
source.push([item.statisDate,item.gridPower]) source.push([item.statisDate,item.gridPower])
}) })
this.chart.setOption({ this.chart.setOption({
color:['#FFBD00','#3C81FF'], color:['#FFBD00','#3C81FF'],
legend: { legend: {
left: 'center', left: 'center',
bottom: '10', bottom: '15',
}, },
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
@ -76,7 +113,6 @@ export default {
} }
] ]
}) })
this.chart.hideLoading()
}, },
} }

View File

@ -0,0 +1,80 @@
<template>
<el-card shadow="always" class="common-card-container common-card-container-body-no-padding">
<div slot="header">
<span class="card-title">当前报警</span>
</div>
<div class="ssgj-container">
<el-table
class="common-table"
:data="tableData"
height="100%"
stripe
style="width: 100%">
<el-table-column
prop="deviceName"
label="名称">
</el-table-column>
<el-table-column
label="状态"
>
<template slot-scope="scope">
<span :class="{'circle warning-status' : scope.row.status !== 0}">{{ $store.state.ems.warnOptions[scope.row.status]}}</span>
</template>
</el-table-column>
<el-table-column
class-name="alarm-content"
prop="alarmContent"
show-overflow-tooltip
label="告警内容">
</el-table-column>
<el-table-column
label="工单"
fixed="right"
show-overflow-tooltip
>
<template slot-scope="scope">
<el-button type="text" size="mini" v-if="scope.row.ticketNo" @click="toTicket">已生成工单(工单号:{{scope.row.ticketNo}})</el-button>
<el-button type="primary" size="mini" v-else @click="toTicket">生成工单</el-button>
</template>
</el-table-column>
</el-table>
</div>
</el-card>
</template>
<script>
export default{
props:{
tableData:{
require:true,
type:Array,
default:()=>{
return []
}
}
},
data(){
return {
}
},
methods:{
toTicket(){
this.$router.push({path:'/ticket'})
},
}
}
</script>
<style lang="scss" scoped>
//实时告警
.ssgj-container{
padding:20px;
height: 250px;
box-sizing: border-box;
::v-deep{
.el-table .el-table__header-wrapper th, .el-table .el-table__fixed-header-wrapper th{
background:#FFF2CB ;
}
}
}
</style>

View File

@ -1,26 +1,27 @@
<template> <template>
<el-row style="background:#fff;margin-top:30px;"> <el-card shadow="always" class="common-card-container common-card-container-body-no-padding time-range-card">
<el-col :xs="24" :sm="24" :lg="24"> <div slot="header" class="time-range-header">
<el-card shadow="always" class="common-card-container common-card-container-body-no-padding">
<div slot="header">
<span class="card-title">一周充放曲线</span> <span class="card-title">一周充放曲线</span>
<date-range-select ref="dateRangeSelect" @updateDate="updateDate"/>
</div> </div>
<div style="height: 310px" id="weekChart"></div> <div style="height: 310px" id="weekChart"></div>
</el-card> </el-card>
</el-col>
</el-row>
</template> </template>
<script> <script>
import * as echarts from 'echarts' import * as echarts from 'echarts'
import resize from '@/mixins/ems/resize' import resize from '@/mixins/ems/resize'
import DateRangeSelect from '@/components/Ems/DateRangeSelect.vue'
// import {getPcsNameList, getPowerData} from '@/api/ems/dzjk'
export default { export default {
mixins: [resize], mixins: [resize],
components: {DateRangeSelect},
data() { data() {
return { return {
chart: null chart: null,
timeRange:[],
siteId:'',
} }
}, },
mounted() { mounted() {
@ -36,18 +37,43 @@ export default {
this.chart = null this.chart = null
}, },
methods: { methods: {
// 更新时间范围 重置图表
updateDate(data){
this.timeRange=data
this.getWeekKData()
},
getWeekKData(){
this.showLoading()
const {siteId,timeRange}=this
//todo delete
this.hideLoading()
// todo({siteId,startDate:timeRange[0],endDate:timeRange[1]}).then(response => {
// this.setOption(response?.data || [])
// }).finally(()=>this.hideLoading())
},
init(siteId){
//初始化 清空数据
this.siteId = siteId
this.timeRange=[]
this.deviceId=''
this.$refs.dateRangeSelect.init()
this.getWeekKData()
},
initChart() { initChart() {
this.chart = echarts.init(document.querySelector('#weekChart')) this.chart = echarts.init(document.querySelector('#weekChart'))
}, },
showLoading(){ showLoading(){
this.chart && this.chart.showLoading() this.chart && this.chart.showLoading()
}, },
hideLoading(){
this.chart && this.chart.hideLoading()
},
setOption(data,unit) { setOption(data,unit) {
const source = [['日期','充电量','放电量']] const source = [['日期','充电量','放电量']]
data.forEach(item=>{ data.forEach(item=>{
source.push([item.ammeterDate, item.chargedCap,item.disChargedCap]) source.push([item.ammeterDate, item.chargedCap,item.disChargedCap])
}) })
this.chart.setOption({ this.chart && this.chart.setOption({
color:['#FFBD00','#3C81FF','#05AEA3'], color:['#FFBD00','#3C81FF','#05AEA3'],
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
@ -57,7 +83,7 @@ export default {
}, },
legend: { legend: {
left: 'center', left: 'center',
bottom: '10', bottom: '15',
}, },
xAxis: { xAxis: {
type: 'category', type: 'category',
@ -88,10 +114,7 @@ export default {
}, },
] ]
}) })
this.chart.hideLoading()
} }
} }
} }
</script> </script>

View File

@ -1,6 +1,9 @@
<template> <template>
<div v-loading="loading"> <div v-loading="loading">
<el-row :gutter="15" style="background:#fff;"> <el-row style="background:#fff;" class="row-container">
<el-col v-if="tableData.length>0" :xs="24" :sm="24" :lg="24">
<alarm-table :tableData="tableData"/>
</el-col>
<el-col :xs="24" :sm="24" :lg="6"> <el-col :xs="24" :sm="24" :lg="6">
<el-card shadow="always" class="common-card-container common-card-container-body-no-padding"> <el-card shadow="always" class="common-card-container common-card-container-body-no-padding">
<div slot="header"> <div slot="header">
@ -22,7 +25,7 @@
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="12" v-for="(item,index) in sjglData" :key="index+'sjglData'" class="sjgl-data"> <el-col :span="12" v-for="(item,index) in sjglData" :key="index+'sjglData'" class="sjgl-data">
<div class="sjgl-title">{{item.title}}</div> <div class="sjgl-title">{{item.title}}</div>
<div class="sjgl-value">{{item.value | formatNumber}}</div> <div class="sjgl-value">{{runningInfo[item.attr] | formatNumber}}</div>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
@ -31,70 +34,35 @@
<el-col :xs="24" :sm="24" :lg="10"> <el-col :xs="24" :sm="24" :lg="10">
<el-card shadow="always" class="common-card-container common-card-container-body-no-padding"> <el-card shadow="always" class="common-card-container common-card-container-body-no-padding">
<div slot="header"> <div slot="header">
<span class="card-title">当前报警</span> <span class="card-title">策略信息</span>
<!-- <el-button style="float: right; padding: 3px 0" type="text" size="small">通讯状态<span style="color:red">超时</span></el-button>-->
</div> </div>
<div class="ssgj-container"> <div style="box-sizing: border-box; height: 250px;padding:20px 15px;" >
<el-table
class="common-table"
:data="tableData"
height="100%"
stripe
style="width: 100%">
<el-table-column
prop="deviceName"
label="名称">
</el-table-column>
<el-table-column
label="状态"
>
<template slot-scope="scope">
<span :class="{'circle warning-status' : scope.row.status !== 0}">{{ $store.state.ems.warnOptions[scope.row.status]}}</span>
</template>
</el-table-column>
<el-table-column
class-name="alarm-content"
prop="alarmContent"
show-overflow-tooltip
label="告警内容">
</el-table-column>
<el-table-column
label="工单"
fixed="right"
show-overflow-tooltip
>
<template slot-scope="scope">
<el-button type="text" size="mini" v-if="scope.row.ticketNo" @click="toTicket">已生成工单(工单号:{{scope.row.ticketNo}})</el-button>
<el-button type="primary" size="mini" v-else @click="toTicket">生成工单</el-button>
</template>
</el-table-column>
</el-table>
</div> </div>
</el-card> </el-card>
</el-col> </el-col>
</el-row> <el-col :xs="24" :sm="24" :lg="24">
<el-row :gutter="15" style="background:#fff;">
<el-col :xs="24" :sm="24" :lg="12">
<week-chart ref="weekChart"/> <week-chart ref="weekChart"/>
</el-col> </el-col>
<el-col :xs="24" :sm="24" :lg="12"> <el-col :xs="24" :sm="24" :lg="24">
<active-chart ref="activeChart"/> <active-chart ref="activeChart"/>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</template> </template>
<script> <script>
import {getSingleSiteBaseInfo} from '@/api/ems/zddt' import {getSingleSiteBaseInfo} from '@/api/ems/zddt'
import {getDzjkHomeView, getPcsNameList, getPowerData} from '@/api/ems/dzjk' import {getDzjkHomeView} from '@/api/ems/dzjk'
import WeekChart from "./WeekChart.vue"; import WeekChart from "./WeekChart.vue";
import ActiveChart from "./ActiveChart.vue"; import ActiveChart from "./ActiveChart.vue";
import AlarmTable from "./AlarmTable.vue";
import getQuerySiteId from '@/mixins/ems/getQuerySiteId' import getQuerySiteId from '@/mixins/ems/getQuerySiteId'
import {formatDate} from "@/filters/ems"; import {formatDate} from "@/filters/ems";
export default { export default {
name:'DzjkSbjkHome', name:'DzjkSbjkHome',
components: {WeekChart,ActiveChart}, components: {WeekChart,ActiveChart,AlarmTable},
mixins: [getQuerySiteId], mixins: [getQuerySiteId],
data() { data() {
return { return {
@ -114,67 +82,50 @@ export default {
}], }],
sjglData:[{ sjglData:[{
title:'今日充电量MWh', title:'今日充电量MWh',
value:'',
attr:'dayChargedCap' attr:'dayChargedCap'
},{ },{
title:'今日放电量MWh', title:'今日放电量MWh',
value:'',
attr:'dayDisChargedCap' attr:'dayDisChargedCap'
},{ },{
title:'总充电量MWh', title:'总充电量MWh',
value:'',
attr:'totalChargedCap' attr:'totalChargedCap'
},{ },{
title:'总放电量MWh', title:'总放电量MWh',
value:'',
attr:'totalDischargedCap' attr:'totalDischargedCap'
}], }],
tableData:[], info:{},//基本信息
info:{} runningInfo:{},//总累计运行数据+报警表格
}
},
computed:{
tableData(){
console.log('this.runningInfo?.siteMonitorHomeAlarmVo ',this.runningInfo?.siteMonitorHomeAlarmVo )
return this.runningInfo?.siteMonitorHomeAlarmVo || []
} }
}, },
methods:{ methods:{
toTicket(){
this.$router.push({path:'/ticket'})
},
getGVQXData(){
this.$refs.activeChart.showLoading()
const {siteId}=this,now=new Date()
getPcsNameList(this.siteId).then(response=>{
const data=response?.data || [];
if(data.length>0){
//接口调用完成之后 设置图表、结束loading
getPowerData({siteId,deviceId:data[0].id,startDate:formatDate(now),endDate:formatDate(now),dataType:'1'}).then(response => {
this.$refs.activeChart.setOption(response?.data || [])
})
}
})
},
getBaseInfo(){ getBaseInfo(){
this.$refs.weekChart.showLoading() return getSingleSiteBaseInfo(this.siteId).then(response => {
getSingleSiteBaseInfo(this.siteId).then(response => {
this.info = response?.data || {} this.info = response?.data || {}
const {sevenDayDisChargeStats=[],unit=''} = this.info
this.$refs.weekChart.setOption(sevenDayDisChargeStats,unit)
}) })
}, },
getTableData(){ getRunningInfo(){
getDzjkHomeView(this.siteId).then(response => { return getDzjkHomeView(this.siteId).then(response => {
const data = response?.data || {} const data = response?.data || {}
this.sjglData.forEach(item=>{ this.runningInfo = data
item.value =data[item.attr]
}) })
this.tableData = data?.siteMonitorHomeAlarmVo || []
}).finally(() => {this.loading = false})
}, },
init(){ init(){
this.loading = true this.loading = true
// 功率曲线 // 功率曲线
this.getGVQXData() this.$refs.activeChart.init(this.siteId)
// 基本信息+冲放曲线 // 一周冲放曲线
this.getBaseInfo() this.$refs.weekChart.init(this.siteId)
//其他数据 // 静态信息 this.getBaseInfo()
this.getTableData() // 总累计运行数据+故障告警 this.getRunningInfo()
Promise.all([this.getBaseInfo(),this.getRunningInfo()]).finally(()=>{
this.loading = false
})
} }
}, },
@ -182,6 +133,11 @@ export default {
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.row-container{
&>.el-col{
margin-bottom: 20px;
}
}
//数据概览 //数据概览
.sjgl-data{ .sjgl-data{
text-align: center; text-align: center;
@ -201,16 +157,25 @@ export default {
word-wrap: break-word; word-wrap: break-word;
} }
} }
//实时告警
.ssgj-container{
padding:20px;
height: 250px;
box-sizing: border-box;
::v-deep{
.el-table .el-table__header-wrapper th, .el-table .el-table__fixed-header-wrapper th{
background:#FFF2CB ;
}
}
}
</style> </style>
<style lang="scss">
/* card标题里的时间选择器 */
.time-range-card{
&.common-card-container .el-card__header{
padding-top: 0;
padding-bottom: 0;
.time-range-header{
height: 40px;
display: flex;
justify-content: space-between;
align-items: center;
.card-title{
line-height: 40px;
}
}
}
}
</style>

View File

@ -2,7 +2,7 @@
<template> <template>
<!-- 6个方块--> <!-- 6个方块-->
<el-row :gutter="10"> <el-row :gutter="10">
<el-col :xs="12" :sm="8" :lg="4" class="single-square-box-container" v-for="(item,index) in singleZdSqaure" :key="index+'singleSquareBox'"> <el-col :xs="12" :sm="8" :lg="4" style="margin-bottom: 10px;" class="single-square-box-container" v-for="(item,index) in singleZdSqaure" :key="index+'singleSquareBox'">
<single-square-box :data="{...item,value:formatNumber(data[item.attr])}" ></single-square-box> <single-square-box :data="{...item,value:formatNumber(data[item.attr])}" ></single-square-box>
</el-col> </el-col>
</el-row> </el-row>

View File

@ -61,6 +61,10 @@
<span>{{scope.row.maxCellVoltage}} V</span> <span>{{scope.row.maxCellVoltage}} V</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column
prop="maxVoltage"
label="电池号码">
</el-table-column>
<el-table-column <el-table-column
prop="minVoltage" prop="minVoltage"
label="单体最低电压"> label="单体最低电压">
@ -68,12 +72,20 @@
<span>{{scope.row.minCellVoltage}} V</span> <span>{{scope.row.minCellVoltage}} V</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column
prop="maxVoltage"
label="电池号码">
</el-table-column>
<el-table-column <el-table-column
label="单体最高温度"> label="单体最高温度">
<template slot-scope="scope"> <template slot-scope="scope">
<span>{{scope.row.maxCellTemp}} &#8451;</span> <span>{{scope.row.maxCellTemp}} &#8451;</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column
prop="maxVoltage"
label="电池号码">
</el-table-column>
<el-table-column <el-table-column
prop="minTemperature" prop="minTemperature"
label="单体最低温度"> label="单体最低温度">
@ -81,6 +93,10 @@
<span>{{scope.row.minCellTemp}} &#8451;</span> <span>{{scope.row.minCellTemp}} &#8451;</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column
prop="maxVoltage"
label="电池号码">
</el-table-column>
</el-table> </el-table>
</el-card> </el-card>

View File

@ -12,10 +12,11 @@
<div>{{$store.state.ems.communicationStatusOptions[pcsItem.communicationStatus]}}</div> <div>{{$store.state.ems.communicationStatusOptions[pcsItem.communicationStatus]}}</div>
<div>数据更新时间{{pcsItem.dataUpdateTime}}</div> <div>数据更新时间{{pcsItem.dataUpdateTime}}</div>
</div> </div>
<!-- <div class="pcs-btns">--> <div class="pcs-btns">
<!-- <el-button type="warning" size="small" @click="problemSaved">故障复位</el-button>--> <el-badge :value="0" class="item">
<!-- <el-button size="small" @click="machineClosed">关机</el-button>--> <i class="el-icon-message-solid" style="font-size: 26px;color: #fff;display: block;"></i>
<!-- </div>--> </el-badge>
</div>
</el-header> </el-header>
<el-main style="padding: 0"> <el-main style="padding: 0">
<div class="descriptions-main"> <div class="descriptions-main">