合并develop最新代码

This commit is contained in:
2025-08-20 17:53:26 +08:00
45 changed files with 3485 additions and 1325 deletions

View File

@ -7,6 +7,13 @@ export function getDzjkHomeView(siteId) {
method: 'get'
})
}
//站点首页 冲放曲线
export function getSevenChargeData({siteId,startDate,endDate}) {
return request({
url: `/ems/siteMap/getSevenChargeData?siteId=${siteId}&startDate=${startDate}&endDate=${endDate}`,
method: 'get'
})
}
//获取pcs、实时运行头部的设备信息
export function getRunningHeadInfo(siteId) {
@ -47,16 +54,16 @@ export function getStackNameList(siteId) {
})
}
//获取单体电池 电池簇列表数据
export function getClusterNameList(stackDeviceId) {
export function getClusterNameList({stackDeviceId,siteId}) {
return request({
url: `/ems/siteMonitor/getClusterNameList?stackDeviceId=${stackDeviceId}`,
url: `/ems/siteMonitor/getClusterNameList?stackDeviceId=${stackDeviceId}&siteId=${siteId}`,
method: 'get'
})
}
//单体电池表格数据
export function getClusterDataInfoList({siteId, stackDeviceId, clusterDeviceId, pageSize, pageNum}) {
export function getClusterDataInfoList({siteId, stackDeviceId, clusterDeviceId,batteryId, pageSize, pageNum}) {
return request({
url: `/ems/siteMonitor/getClusterDataInfoList?clusterDeviceId=${clusterDeviceId}&siteId=${siteId}&stackDeviceId=${stackDeviceId}&pageSize=${pageSize}&pageNum=${pageNum}`,
url: `/ems/siteMonitor/getClusterDataInfoList?clusterDeviceId=${clusterDeviceId}&siteId=${siteId}&stackDeviceId=${stackDeviceId}&batteryId=${batteryId}&pageSize=${pageSize}&pageNum=${pageNum}`,
method: 'get'
})
}
@ -86,9 +93,9 @@ export function getAmmeterDataList(siteId) {
}
// 故障告警
export function getAlarmDetailList({siteId, deviceType, alarmLevel, alarmStartTime, alarmEndTime,pageSize,pageNum}) {
export function getAlarmDetailList({siteId, deviceId, alarmLevel, alarmStartTime, alarmEndTime,pageSize,pageNum}) {
return request({
url: `/ems/siteAlarm/getAlarmDetailList?siteId=${siteId}&deviceType=${deviceType}&alarmLevel=${alarmLevel}&alarmStartTime=${alarmStartTime}&alarmEndTime=${alarmEndTime}&pageSize=${pageSize}&pageNum=${pageNum}`,
url: `/ems/siteAlarm/getAlarmDetailList?siteId=${siteId}&deviceId=${deviceId}&alarmLevel=${alarmLevel}&alarmStartTime=${alarmStartTime}&alarmEndTime=${alarmEndTime}&pageSize=${pageSize}&pageNum=${pageNum}`,
method: 'get'
})
}
@ -277,10 +284,10 @@ export function setTimeConfigList(data) {
})
}
// 策略曲线图
//http://localhost:8089/strategy/curve/list?strategyId=1&siteId=021_FXX_01
//http://localhost:8089/strategy/curve/curveList?strategyId=1&siteId=021_FXX_01
export function curveList({siteId,strategyId}) {
return request({
url: `/strategy/curve/list?siteId=${siteId}&strategyId=${strategyId}`,
url: `/strategy/curve/curveList?siteId=${siteId}&strategyId=${strategyId}`,
method: 'get',
})
}

View File

@ -126,10 +126,17 @@
background: #0366c1!important;
}
}
.ems-third-menu{
.ems-third-menu-container{
position: relative;
padding-left: 160px;
background-color: #ffffff;
.ems-third-menu{
border-right: none;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
height: fit-content;
position: absolute;
top:20px;
left:20px;
.el-menu-item{
line-height: 45px;
height: 45px;
@ -145,9 +152,11 @@
background: #409eff!important;
}
}
}
//按钮栏 选中样式
.ems-btns-group{
.activeBtn{

View File

@ -0,0 +1,98 @@
<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 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 = type === 'before' ? new Date(this.dateRange[0]).getTime() - ( 24 * 60 * 60 * 1000) :new Date(this.dateRange[1]).getTime() + ( 24 * 60 * 60 * 1000) ,
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-range__icon, .el-range-editor--medium .el-range__close-icon{
line-height: 22px;
}
.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

@ -1,23 +1,5 @@
import Layout from "@/layout/index.vue";
//todo delete 删除动态路由页面的定义 接口会传递进来
// const ems = [
// {
// path: '',
// component: Layout,
// redirect: 'noRedirect',
// children: [
// {
// path: 'zddt',
// component: () => import('@/views/ems/zddt/index'),
// name: 'zddt',
// meta: { title: '站点地图', icon: 'guide' }
// }
// ]
// }
// ]
// export default ems
//单站监控
// todo 本地设置了 hidden:true,不会显示在侧边栏,需要在系统管理、菜单管理中手动添加菜单后才会展示在侧边栏
export const dzjk=[

View File

@ -1,7 +1,5 @@
import Vue from 'vue'
import Router from 'vue-router'
// todo delete
import ems from './ems'//EMS管理系统routers引用
import {dzjk} from '@/router/ems'
Vue.use(Router)
@ -92,7 +90,6 @@ export const constantRoutes = [
]
},
// EMS管理系统routers
// ...ems
...dzjk
]

View File

@ -47,11 +47,34 @@ export default {
},
setOption(data) {
if(!this.chart) return
let obj = {}
for(var i=0;i<=23;i++){
obj[i] = {
title:i<=9?`0${i}:00` : `${i}:00`
}
}
const nowMonth = new Date().getMonth()+1;
const localMonth = data.find(item=>item.month === nowMonth)?.powerList || []
localMonth.forEach(item => {
const startHours = parseInt(item.startTime.split(':')[0], 10)
const endHours =parseInt(item.endTime.split(':')[0], 10)
for(let i=startHours;i<=endHours;i++){
obj[i].value = item.powerData
}
})
let source = [['时间','冲放功率']]
Object.values(obj).forEach(item => {
const {title,value} = item
source.push([title,value])
})
this.chart.setOption({
color:['#FFBD00','#3C81FF'],
grid: {
containLabel: true
},
legend: {
left: 'center',
bottom: '10',
bottom: '15',
},
tooltip: {
trigger: 'axis',
@ -63,7 +86,7 @@ export default {
color:"#333333",
},
xAxis: {
data: ['01:00','02:00','03:00','05:00','06:00','07:00','08:00','09:00','10:00'],
type: 'category',
axisLine: {
lineStyle:{
color: '#333333',
@ -78,14 +101,12 @@ export default {
}
}
},
dataset: {
source
},
series: [
{
name:'模板一',
data: [80,92,1,34,90,130,320,80,9,91],
type: 'line',
},{
name:'模板二',
data: [820,932,901,934,1290,1330,1320,820,932,901],
name:'冲放功率',
type: 'line',
}]
})

View File

@ -40,7 +40,6 @@ export default {
this.$refs.tomePowerChart.changeSiteId()
})
},
//在编辑、删除模板后更新时间配置、echart的数据todo
updateTimeSetting(){
this.$refs.timeSetting.init()
this.$refs.tomePowerChart.init()

View File

@ -3,9 +3,9 @@
<div v-loading="loading" class="ems-dashboard-editor-container ems-content-container-padding">
<!-- 搜索栏-->
<el-form :inline="true" class="select-container">
<el-form-item label="设备类型">
<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-form-item label="设备清单">
<el-select v-model="search.deviceId" clearable placeholder="请选择" :loading="loading" loading-text="正在加载数据">
<el-option :label="item.deviceName" :value="item.deviceId" v-for="(item,key) in deviceOptions" :key="key+'deviceIdOptions'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="告警等级">
@ -114,6 +114,7 @@
<script>
import {getAlarmDetailList} from'@/api/ems/dzjk'
import {getDeviceList} from'@/api/ems/site'
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import { formatDate } from '@/filters/ems'
export default {
@ -126,6 +127,7 @@ export default {
{name:'今日告警',id:'today'},
{name:'历史告警',id:'history'},
],
deviceOptions:[],//设备列表
pickerOptions:{
disabledDate(time) {
return time.getTime() > Date.now();
@ -134,7 +136,7 @@ export default {
defaultDateRange:[],//默认展示的时间
dateRange:[],//alarmStartTime,alarmEndTime
activeBtn:'today',
search:{deviceType:'',alarmLevel:''},
search:{deviceId:'',alarmLevel:''},
// 表格、分页
tableData:[],
pageSize:10,//分页栏当前每个数据总数
@ -186,7 +188,7 @@ export default {
},
// 重置
onReset(){
this.search={deviceType:'',alarmLevel:''}
this.search={deviceId:'',alarmLevel:''}
this.dateRange=[]
this.pageNum =1//每次搜索从1开始搜索
this.getData()
@ -213,7 +215,7 @@ export default {
// 获取数据
getData(){
this.loading=true
const {deviceType,alarmLevel} = this.search
const {deviceId,alarmLevel} = this.search
const {siteId,pageNum,pageSize,activeBtn} =this
const [alarmStartTime='',alarmEndTime='']=(this.dateRange || [])
let start='',end = '',now =new Date()
@ -230,12 +232,18 @@ export default {
// end.setDate(end.getDate() - 1);
}
}
getAlarmDetailList({deviceType,alarmLevel,siteId,pageSize,pageNum,alarmStartTime:formatDate(start),alarmEndTime:formatDate(end)}).then(response => {
getAlarmDetailList({deviceId,alarmLevel,siteId,pageSize,pageNum,alarmStartTime:formatDate(start),alarmEndTime:formatDate(end)}).then(response => {
this.tableData=response?.rows || [];
this.totalSize = response?.total || 0
}).finally(() => {this.loading=false})
},
getDeviceOptions(){
getDeviceList(this.siteId).then(response => {
this.deviceOptions = JSON.parse(JSON.stringify(response?.data || []))
})
},
init(){
this.getDeviceOptions()
this.onReset()
},
},

View File

@ -0,0 +1,125 @@
<template>
<el-card shadow="always" class="common-card-container common-card-container-body-no-padding time-range-card">
<div slot="header" class="time-range-header">
<span class="card-title">当日功率曲线</span>
<date-range-select ref="dateRangeSelect" @updateDate="updateDate"/>
</div>
<div style="height: 310px" id="activeChart"></div>
</el-card>
</template>
<script>
import * as echarts from 'echarts'
import resize from '@/mixins/ems/resize'
import DateRangeSelect from '@/components/Ems/DateRangeSelect/index.vue'
import {getPcsNameList, getPowerData} from '@/api/ems/dzjk'
export default {
mixins: [resize],
components: {DateRangeSelect},
data() {
return {
chart: null,
timeRange:[],
siteId:'',
deviceId:''
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
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() {
this.chart = echarts.init(document.querySelector('#activeChart'))
},
showLoading(){
this.chart && this.chart.showLoading()
},
hideLoading(){
this.chart && this.chart.hideLoading()
},
setOption(data) {
const source = [['日期','电网功率']]
this.chart && data.forEach((item)=>{
source.push([item.statisDate,item.gridPower])
})
this.chart.setOption({
color:['#FFBD00','#3C81FF'],
grid: {
containLabel: true
},
legend: {
left: 'center',
bottom: '15',
},
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
textStyle:{
color:"#333333",
},
xAxis: {
type: 'category',
},
yAxis: {
type: 'value',
},
dataset:{source},
series: [
{
name:'电网功率',
type: 'line',
}
]
})
},
}
}
</script>

View File

@ -0,0 +1,86 @@
<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> -->
<el-alert type="error" :closable="false">
<template>
<div style="cursor: pointer" @click="toAlarm">设备告警</div>
</template>
</el-alert>
</template>
<script>
export default {
props: {
tableData: {
require: true,
type: Array,
default: () => {
return [];
},
},
},
data() {
return {};
},
methods: {
toAlarm() {
this.$router.push({ path: "/dzjk/gzgj", query: this.$route.query });
},
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

@ -0,0 +1,82 @@
<template>
<el-card
shadow="always"
class="common-card-container common-card-container-body-no-padding"
>
<div slot="header">
<span class="card-title">策略信息</span>
</div>
<!-- <el-empty :image-size="100" ></el-empty> -->
<div
style="
box-sizing: border-box;
height: 250px;
padding: 20px 15px;
overflow-y: auto;
"
>
<el-descriptions class="home-normal-info" :column="2">
<el-descriptions-item size="mini" label="模板名称">{{
info.mainStrategyName || "-"
}}</el-descriptions-item>
<el-descriptions-item size="mini" label="SOC限制">{{
mainInfo.sdcLimit === 1 ? "开" : mainInfo.sdcLimit === 0 ? "关" : "-"
}}</el-descriptions-item>
<el-descriptions-item size="mini" label="SOC下限%">{{
formatNumber(mainInfo.sdcDown)
}}</el-descriptions-item>
<el-descriptions-item size="mini" label="SOC上限%">{{
formatNumber(mainInfo.sdcUp)
}}</el-descriptions-item>
</el-descriptions>
<el-table
:data="info.siteMonitorDataVo || []"
border
size="mini"
style="width: 100%; margin-top: 15px"
>
<el-table-column prop="startTime" label="开始时间"> </el-table-column>
<el-table-column prop="endTime" label="结束时间"> </el-table-column>
<el-table-column prop="chargeDischargePower" label="充放功率kW">
</el-table-column>
<el-table-column prop="chargeStatus" label="充电状态">
<template slot-scope="scope">
{{ chargeStatusOptions[scope.row.chargeStatus] }}
</template>
</el-table-column>
</el-table>
</div>
</el-card>
</template>
<script>
import { mapState } from "vuex";
import { formatNumber } from "@/filters/ems";
export default {
props: {
info: {
require: true,
type: Object,
default: () => {
return {};
},
},
},
computed: {
...mapState({
chargeStatusOptions: (state) => state?.ems?.chargeStatusOptions || {},
}),
mainInfo() {
return this.info?.siteMonitorDataVo?.length > 0
? this.info.siteMonitorDataVo[0]
: {};
},
},
data() {
return {};
},
methods: {
formatNumber,
},
};
</script>
<style lang="scss" scoped></style>

View File

@ -1,148 +0,0 @@
<template>
<el-row style="background:#fff;margin-top:30px;">
<el-col :xs="24" :sm="24" :lg="24">
<el-card shadow="always" class="common-card-container common-card-container-body-no-padding">
<div slot="header">
<span class="card-title">能量流转</span>
</div>
<div style="height: 310px" id="nllzChart"></div>
</el-card>
</el-col>
</el-row>
</template>
<script>
import * as echarts from 'echarts'
import resize from '@/mixins/ems/resize'
import {formatNumber} from "@/filters/ems";
export default {
mixins: [resize],
data() {
return {
chart: null
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(document.querySelector('#nllzChart'))
},
setOption(data) {
const {siteMonitorDataVo=[],gridNrtPower,loadNrtPower,energyStorageNrtPower,energyStorageAvailElec} = data
const source = [['日期','充电量','放电量']]
siteMonitorDataVo.forEach(item=>{
source.push([item.ammeterDate, item.chargedCap,item.disChargedCap])
})
this.chart.setOption({
title: [
// 右上角
{
text: `电网 实时功率:${formatNumber(gridNrtPower)} kW`,
top: 10,
right: 10,
textStyle:{
fontSize:12,
color:'#666666'
}
},
// 右下角
{
text: `负载 实时功率:${formatNumber(loadNrtPower)} kW`,
bottom: 10,
right: 10,
textStyle:{
fontSize:12,
color:'#666666'
}
},
// 左下角第一行
{
text: '储能',
bottom: 40,
left: 10,
textStyle:{
fontSize:12,
color:'#666666'
}
},
// 左下角第二行
{
text: `实时功率:${formatNumber(energyStorageNrtPower)} kW`,
bottom: 26,
left: 10,
textStyle:{
fontSize:12,
color:'#666666'
}
},
// 左下角第三行
{
text: `可用电量:${formatNumber(energyStorageAvailElec)} kWh`,
bottom: 10,
left: 10,
textStyle:{
fontSize:12,
color:'#666666'
}
}
],
grid:{
left:200
},
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
textStyle:{
color:"#333333",
},
xAxis: {
type: 'category',
axisLine: {
lineStyle:{
color: '#333333',
}
}
},
yAxis: {
type: 'value',
axisLine: {
lineStyle:{
color: '#333333',
}
}
},
dataset:{
source
// source: [['日期','充电量','放电量']]
},
series: [
{
name:'充电量',
type: 'line',
},{
name:'放电量',
type: 'line',
}]
})
}
}
}
</script>

View File

@ -0,0 +1,121 @@
<template>
<el-card shadow="always" class="common-card-container common-card-container-body-no-padding time-range-card">
<div slot="header" class="time-range-header">
<span class="card-title">一周充放曲线</span>
<date-range-select ref="dateRangeSelect" @updateDate="updateDate"/>
</div>
<div style="height: 310px" id="weekChart"></div>
</el-card>
</template>
<script>
import * as echarts from 'echarts'
import resize from '@/mixins/ems/resize'
import DateRangeSelect from '@/components/Ems/DateRangeSelect/index.vue'
import {getSevenChargeData} from '@/api/ems/dzjk'
export default {
mixins: [resize],
components: {DateRangeSelect},
data() {
return {
chart: null,
timeRange:[],
siteId:'',
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
// 更新时间范围 重置图表
updateDate(data){
this.timeRange=data
this.getWeekKData()
},
getWeekKData(){
this.showLoading()
const {siteId,timeRange}=this
this.hideLoading()
getSevenChargeData({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()
},
initChart() {
this.chart = echarts.init(document.querySelector('#weekChart'))
},
showLoading(){
this.chart && this.chart.showLoading()
},
hideLoading(){
this.chart && this.chart.hideLoading()
},
setOption(data,unit) {
const source = [['日期','充电量','放电量']]
data.forEach(item=>{
source.push([item.ammeterDate, item.chargedCap,item.disChargedCap])
})
this.chart && this.chart.setOption({
color:['#FFBD00','#3C81FF','#05AEA3'],
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
grid: {
containLabel: true
},
legend: {
left: 'center',
bottom: '15',
},
xAxis: {
type: 'category',
name:unit,
nameLocation:'center'
},
yAxis: [{
type: 'value',
name:'充电量/放电量kWh',
axisLine: {
lineStyle:{
color: '#333333',
},
onZero:false
}
}],
dataset:{
source
},
series: [
{
yAxisIndex:0,
type: 'line',
},
{
yAxisIndex:0,
type: 'line',
},
]
})
}
}
}
</script>

View File

@ -1,148 +1,221 @@
<template>
<div v-loading="loading" class="ems-dashboard-editor-container">
<el-row :gutter="32" style="background:#fff;">
<el-col :xs="24" :sm="24" :lg="10">
<el-card shadow="always" class="common-card-container common-card-container-body-no-padding">
<div
class="ems-dashboard-editor-container ems-content-container-padding"
v-loading="loading"
>
<el-row style="background: #fff" class="row-container" :gutter="15">
<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-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>
</div>
<div style="height: 310px" >
<div
style="box-sizing: border-box; height: 250px; padding: 20px 15px"
>
<el-descriptions class="home-normal-info" :column="1">
<el-descriptions-item
size="mini"
v-for="(item, index) in singleZdInfo"
:key="index + 'singleZdInfo'"
:label="item.title"
>{{ info[item.attr] | formatNumber }}</el-descriptions-item
>
</el-descriptions>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :lg="8">
<el-card
shadow="always"
class="common-card-container common-card-container-body-no-padding"
>
<div slot="header">
<span class="card-title">总累计运行数据</span>
</div>
<div
style="box-sizing: border-box; height: 250px; padding: 20px 15px"
>
<el-row :gutter="20">
<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-value">{{item.value | formatNumber}}</div>
<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-value">
{{ runningInfo[item.attr] | formatNumber }}
</div>
</el-col>
</el-row>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :lg="14">
<el-card shadow="always" class="common-card-container common-card-container-body-no-padding">
<div slot="header">
<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 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"
label="告警内容">
</el-table-column>
<el-table-column
label="工单"
fixed="right"
width="250"
>
<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>
<el-col :xs="24" :sm="24" :lg="10">
<cl-info :info="runningInfo.strategyTempInfo" />
</el-col>
<el-col :xs="24" :sm="24" :lg="24">
<week-chart ref="weekChart" />
</el-col>
<el-col :xs="24" :sm="24" :lg="24">
<active-chart ref="activeChart" />
</el-col>
</el-row>
<nllz-chart ref="nllzChart"/>
</div>
</template>
<script>
import {getDzjkHomeView} from '@/api/ems/dzjk'
import NllzChart from "./NllzChart.vue";
import getQuerySiteId from '@/mixins/ems/getQuerySiteId'
import { getSingleSiteBaseInfo } from "@/api/ems/zddt";
import { getDzjkHomeView } from "@/api/ems/dzjk";
import WeekChart from "./WeekChart.vue";
import ActiveChart from "./ActiveChart.vue";
import AlarmTable from "./AlarmTable.vue";
import ClInfo from "./ClInfo.vue";
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
export default {
name:'DzjkSbjkHome',
components: {NllzChart},
name: "DzjkSbjkHome",
components: { WeekChart, ActiveChart, AlarmTable, ClInfo },
mixins: [getQuerySiteId],
data() {
return {
loading:false,
sjglData:[{
title:'今日充电量MWh',
value:'',
attr:'dayChargedCap'
},{
title:'今日放电量MWh',
value:'',
attr:'dayDisChargedCap'
},{
title:'总充电量MWh',
value:'',
attr:'totalChargedCap'
},{
title:'总放电量MWh',
value:'',
attr:'totalDischargedCap'
}],
// todo 表格里的不同状态可能需要显示不同颜色 确定表格内容
tableData:[]
}
loading: false,
singleZdInfo: [
{
title: "电站位置",
attr: "siteAddress",
},
methods:{
toTicket(){
this.$router.push({path:'/ticket'})
{
title: "投运时间",
attr: "runningTime",
},
init(){
this.loading = true
getDzjkHomeView(this.siteId).then(response => {
const data = response?.data || {}
this.sjglData.forEach(item=>{
item.value =data[item.attr]
})
this.tableData = data?.siteMonitorHomeAlarmVo || []
this.$refs.nllzChart.setOption(data)
}).finally(() => {this.loading = false})
}
{
title: "装机功率(MW)",
attr: "installPower",
},
}
{
title: "装机容量(MW)",
attr: "installCapacity",
},
],
sjglData: [
{
title: "今日充电量MWh",
attr: "dayChargedCap",
},
{
title: "今日放电量MWh",
attr: "dayDisChargedCap",
},
{
title: "总充电量MWh",
attr: "totalChargedCap",
},
{
title: "总放电量MWh",
attr: "totalDischargedCap",
},
],
info: {}, //基本信息
runningInfo: {}, //总累计运行数据+报警表格
};
},
computed: {
tableData() {
console.log(
"this.runningInfo?.siteMonitorHomeAlarmVo ",
this.runningInfo?.siteMonitorHomeAlarmVo
);
return this.runningInfo?.siteMonitorHomeAlarmVo || [];
},
},
methods: {
getBaseInfo() {
return getSingleSiteBaseInfo(this.siteId).then((response) => {
this.info = response?.data || {};
});
},
getRunningInfo() {
return getDzjkHomeView(this.siteId).then((response) => {
this.runningInfo = response?.data || {};
});
},
init() {
this.loading = true;
// 功率曲线
this.$refs.activeChart.init(this.siteId);
// 一周冲放曲线
this.$refs.weekChart.init(this.siteId);
// 静态信息 this.getBaseInfo()
// 总累计运行数据+故障告警 this.getRunningInfo()
Promise.all([this.getBaseInfo(), this.getRunningInfo()]).finally(() => {
this.loading = false;
});
},
},
};
</script>
<style scoped lang="scss">
.row-container {
& > .el-col {
margin-bottom: 20px;
}
}
//数据概览
.sjgl-data{
.sjgl-data {
text-align: center;
margin-top:20px;
.sjgl-title{
&:nth-child(1),
&:nth-child(2) {
margin-bottom: 25px;
}
.sjgl-title {
color: #666666;
line-height: 14px;
padding-top: 18px;
}
.sjgl-value{
color: rgba(51,51,51,1);
.sjgl-value {
color: rgba(51, 51, 51, 1);
font-size: 26px;
line-height: 26px;
font-weight: 500;
margin-top: 14px;
word-wrap: break-word;
}
}
//实时告警
.ssgj-container{
padding:20px;
height: 310px;
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 lang="scss">
.home-normal-info {
font-size: 12px;
.el-descriptions-item__container {
.el-descriptions-item__label {
color: #666666;
}
.el-descriptions-item__content {
color: #333333;
}
}
}
/* 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>
<!-- 6个方块-->
<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>
</el-col>
</el-row>
@ -64,5 +64,10 @@ export default {
<style scoped lang="scss">
@media only screen and (min-width: 1200px) {
.single-square-box-container {
min-width: 16.6666666667%;
width: fit-content;
}
}
</style>

View File

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

View File

@ -1,134 +1,140 @@
<template>
<div v-loading="loading">
<el-card shadow="always" class="common-card-container" :class="zbInfo.emsCommunicationStatus === '1' ? 'zb-common-card-container' : 'cnb-common-card-container'">
<el-card
shadow="always"
class="common-card-container"
:class="
zbInfo.emsCommunicationStatus !== '0'
? 'zb-common-card-container'
: 'cnb-common-card-container'
"
>
<div slot="header">
<span class="large-title">1#{{zbInfo.deviceName}}</span>
<span class="large-title">1#{{ zbInfo.deviceName }}</span>
<div class="status">
<div>{{$store.state.ems.communicationStatusOptions[zbInfo.emsCommunicationStatus]}}</div>
<div>数据更新时间{{zbInfo.dataUpdateTime}}</div>
<div>
{{
$store.state.ems.communicationStatusOptions[
zbInfo.emsCommunicationStatus
]
}}
</div>
<div>数据更新时间{{ zbInfo.dataUpdateTime }}</div>
</div>
</div>
<el-table
class="common-table"
:data="zbInfo.loadDataDetailInfo"
stripe
style="width: 100%;">
<el-table-column
prop="category"
label="类别">
</el-table-column>
<el-table-column
prop="totalKwh"
label="总/kWh"
style="width: 100%"
>
</el-table-column>
<el-table-column
prop="peakKwh"
label="/kWh">
</el-table-column>
<el-table-column
prop="highKwh"
label="峰/kWh">
</el-table-column>
<el-table-column
prop="flatKwh"
label="平/kWh">
</el-table-column>
<el-table-column
prop="valleyKwh"
label="谷/kWh">
</el-table-column>
<el-table-column prop="category" label="类别"> </el-table-column>
<el-table-column prop="totalKwh" label="总/kWh"> </el-table-column>
<el-table-column prop="peakKwh" label="尖/kWh"> </el-table-column>
<el-table-column prop="highKwh" label="/kWh"> </el-table-column>
<el-table-column prop="flatKwh" label="平/kWh"> </el-table-column>
<el-table-column prop="valleyKwh" label="谷/kWh"> </el-table-column>
</el-table>
</el-card>
<el-card shadow="always" class="common-card-container" style="margin-top:20px" :class="cnbInfo.emsCommunicationStatus === '1' ? 'zb-common-card-container' : 'cnb-common-card-container'">
<el-card
shadow="always"
class="common-card-container"
style="margin-top: 20px"
:class="
cnbInfo.emsCommunicationStatus !== '0'
? 'zb-common-card-container'
: 'cnb-common-card-container'
"
>
<div slot="header">
<span class="large-title">2#{{cnbInfo.deviceName}}</span>
<span class="large-title">2#{{ cnbInfo.deviceName }}</span>
<div class="status">
<div>{{$store.state.ems.communicationStatusOptions[cnbInfo.emsCommunicationStatus]}}</div>
<div>数据更新时间{{cnbInfo.dataUpdateTime}}</div>
<div>
{{
$store.state.ems.communicationStatusOptions[
cnbInfo.emsCommunicationStatus
]
}}
</div>
<div>数据更新时间{{ cnbInfo.dataUpdateTime }}</div>
</div>
</div>
<el-table
class="common-table"
:data="cnbInfo.meteDataDetailInfo"
stripe
style="width: 100%;">
<el-table-column
prop="category"
label="类别">
</el-table-column>
<el-table-column
prop="activePower"
label="有功功率"
style="width: 100%"
>
</el-table-column>
<el-table-column
prop="reactivePower"
label="无功功率">
<el-table-column prop="category" label="类别"> </el-table-column>
<el-table-column prop="activePower" label="有功功率"> </el-table-column>
<el-table-column prop="reactivePower" label="无功功率">
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<script>
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import {getAmmeterDataList} from '@/api/ems/dzjk'
import { getAmmeterDataList } from "@/api/ems/dzjk";
export default {
name:'DzjkSbjkDb',
mixins:[getQuerySiteId],
name: "DzjkSbjkDb",
mixins: [getQuerySiteId],
data() {
return {
loading:false,
zbInfo:{},
cnbInfo:{},
}
loading: false,
zbInfo: {},
cnbInfo: {},
};
},
methods:{
init(){
this.loading = true
getAmmeterDataList(this.siteId).then(response => {
this.zbInfo =JSON.parse(JSON.stringify(response?.data?.ammeterLoadData || {}));
this.cnbInfo =JSON.parse(JSON.stringify(response?.data?.ammeterMeteData || {}));
}).finally(() => {this.loading = false})
}
methods: {
init() {
this.loading = true;
getAmmeterDataList(this.siteId)
.then((response) => {
this.zbInfo = JSON.parse(
JSON.stringify(response?.data?.ammeterLoadData || {})
);
this.cnbInfo = JSON.parse(
JSON.stringify(response?.data?.ammeterMeteData || {})
);
})
.finally(() => {
this.loading = false;
});
},
mounted(){
}
}
},
mounted() {},
};
</script>
<style scoped lang="scss">
.zb-common-card-container,.cnb-common-card-container{
::v-deep{
.el-card__header{
padding:10px 14px;
background-color: #FC6B69;
color:#ffffff;
.zb-common-card-container,
.cnb-common-card-container {
::v-deep {
.el-card__header {
padding: 10px 14px;
background-color: #fc6b69;
color: #ffffff;
position: relative;
}
}
}
.cnb-common-card-container{
margin-top:25px;
::v-deep{
.el-card__header{
background-color: #05AEA3;
.cnb-common-card-container {
margin-top: 25px;
::v-deep {
.el-card__header {
background-color: #05aea3;
}
}
}
.status{
.status {
position: absolute;
right:14px;
top:50%;
right: 14px;
top: 50%;
transform: translateY(-50%);
color: #ffffff;
font-size: 12px;
line-height: 20px;
}
</style>

View File

@ -20,8 +20,9 @@
start-placeholder="开始时间"
value-format="yyyy-MM-dd"
:picker-options="pickerOptions"
:default-value="defaultDateRange"
end-placeholder="结束时间">
end-placeholder="结束时间"
:clearable="false"
>
</el-date-picker>
</el-form-item>
<el-form-item>
@ -29,145 +30,181 @@
<el-button @click="onReset">重置</el-button>
</el-form-item>
</el-form>
<div id="lineChart" style="height: 360px;width: 100%;"></div>
<div id="lineChart" style="height: 360px; width: 100%"></div>
</div>
</el-dialog>
</template>
<script>
import * as echarts from 'echarts'
import resize from '@/mixins/ems/resize'
import {getSingleBatteryData} from '@/api/ems/dzjk'
import * as echarts from "echarts";
import resize from "@/mixins/ems/resize";
import { getSingleBatteryData } from "@/api/ems/dzjk";
import { formatDate } from "@/filters/ems";
export default {
mixins: [resize],
data() {
return {
loading: false,
siteId:'',
deviceId:'',
clusterDeviceId:'',
dataType:'',//展示的数据类型 空值展示所有数据
pickerOptions:{
siteId: "",
deviceId: "",
clusterDeviceId: "",
dataType: "", //展示的数据类型 空值展示所有数据
pickerOptions: {
disabledDate(time) {
return time.getTime() > Date.now();
},
},
dialogTableVisible: false,
dateRange: [],
defaultDateRange:[]
}
defaultDateRange: [],
};
},
methods: {
handleColsed(done){
if (!this.chart) {
return done()
}
this.chart.dispose()
this.chart = null
done()
resetDefaultDateRange() {
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];
},
getData(){
if(this.loading) return
handleColsed(done) {
if (!this.chart) {
return done();
}
this.chart.dispose();
this.chart = null;
done();
},
getData() {
if (this.loading) return;
this.loading = true;
this.chart.showLoading()
const {siteId, deviceId,clusterDeviceId,dateRange:[startDate='',endDate='']}=this;
getSingleBatteryData({siteId, deviceId,clusterDeviceId,startDate,endDate}).then(response => {
this.setOption(response?.data || [])
}).finally(()=>{
this.loading = false;
this.chart.hideLoading()
this.chart.showLoading();
const {
siteId,
deviceId,
clusterDeviceId,
dateRange: [startDate = "", endDate = ""],
} = this;
getSingleBatteryData({
siteId,
deviceId,
clusterDeviceId,
startDate,
endDate,
})
.then((response) => {
this.setOption(response?.data || []);
})
.finally(() => {
this.loading = false;
this.chart.hideLoading();
});
},
// 重置
onReset(){
this.dateRange=[]
this.getData()
onReset() {
this.dateRange = this.defaultDateRange;
this.getData();
},
initChart({siteId, clusterDeviceId, deviceId},dataType) {
this.siteId=siteId
this.clusterDeviceId=clusterDeviceId
this.deviceId=deviceId
this.dataType=dataType
this.dateRange=[]
this.dialogTableVisible = true
this.$nextTick(()=>{
!this.chart && (this.chart = echarts.init(document.querySelector('#lineChart')))
this.getData()
})
initChart({ siteId, clusterDeviceId, deviceId }, dataType) {
this.siteId = siteId;
this.clusterDeviceId = clusterDeviceId;
this.deviceId = deviceId;
this.dataType = dataType;
this.resetDefaultDateRange();
this.dialogTableVisible = true;
this.$nextTick(() => {
!this.chart &&
(this.chart = echarts.init(document.querySelector("#lineChart")));
this.getData();
});
},
setOption(data) {
const obj = {
voltage:'电压',
temperature:'温度',
soc:'SOC',
soh:'SOH',
}
let source,series,{dataType} = this
if(dataType){
source = [['日期',obj[dataType]]]
data.forEach(item => {
source.push([item.dataTimestamp,item[dataType]])
})
series=[{
name:obj[dataType],
type: 'line',
}]
}else{
source = [['日期','电压','温度','SOC','SOH']]
data.forEach(item => {
source.push([item.dataTimestamp,item.voltage,item.temperature,item.soc,item.soh])
})
series=[
voltage: "电压",
temperature: "温度",
soc: "SOC",
soh: "SOH",
};
let source,
series,
{ dataType } = this;
if (dataType) {
source = [["日期", obj[dataType]]];
data.forEach((item) => {
source.push([item.dataTimestamp, item[dataType]]);
});
series = [
{
name:'电压',
type: 'line',
},{
name:'温度',
type: 'line',
name: obj[dataType],
type: "line",
},
];
} else {
source = [["日期", "电压", "温度", "SOC", "SOH"]];
data.forEach((item) => {
source.push([
item.dataTimestamp,
item.voltage,
item.temperature,
item.soc,
item.soh,
]);
});
series = [
{
name: "电压",
type: "line",
},
{
name:'SOC',
type: 'line',
},{
name:'SOH',
type: 'line',
}]
name: "温度",
type: "line",
},
{
name: "SOC",
type: "line",
},
{
name: "SOH",
type: "line",
},
];
}
this.chart && this.chart.setOption({
color:['#FFBD00','#3C81FF','#05AEA3','#F86F70'],
this.chart &&
this.chart.setOption({
color: ["#FFBD00", "#3C81FF", "#05AEA3", "#F86F70"],
grid: {
containLabel: true,
},
legend: {
bottom: '10',
left: "center",
bottom: "15",
},
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
trigger: "axis",
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
},
textStyle:{
color:"#333333",
},
textStyle: {
color: "#333333",
},
xAxis: {
type: 'category',
type: "category",
},
yAxis: {
type: 'value',
type: "value",
},
dataset:{
source
dataset: {
source,
},
series
})
}
series,
});
},
mounted(){
const now = new Date();
const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
this.defaultDateRange = [lastMonth, now];
}
}
},
mounted() {},
};
</script>

View File

@ -0,0 +1,191 @@
<template>
<div>
<template v-if="totalSize.length === 0">
<el-empty :size="200"></el-empty>
</template>
<template v-else>
<div class="lists-container clearfix">
<div
class="lists"
v-for="(item, index) in tableData"
:key="index + 'dtdcList'"
:class="handleListClass(item)"
@click="chartDetail(item)"
>
<div style="font-size: 10px; font-weight: 600">
{{ item.clusterDeviceId }}
</div>
<div>#{{ item.deviceId }}</div>
<div class="dy">{{ item.voltage }}V</div>
<div class="wd">{{ item.temperature }}</div>
</div>
</div>
<!-- <el-pagination
v-show="tableData.length > 0"
background
@size-change="(val) => $emit('handleSizeChange', val)"
@current-change="(val) => $emit('handleCurrentChange', val)"
:current-page="pageNum"
:page-size="pageSize"
:page-sizes="[10, 20, 30, 40]"
layout="total, sizes, prev, pager, next, jumper"
:total="totalSize"
style="margin-top: 15px; text-align: center"
>
</el-pagination> -->
</template>
</div>
</template>
<script>
export default {
props: {
pointIdList: {
require: true,
type: Object,
default: () => {
return {};
},
},
tableData: {
require: true,
type: Array,
default: () => {
return [];
},
},
totalSize: {
require: true,
type: Number,
default: 0,
},
// pageNum: {
// require: true,
// type: Number,
// default: 1,
// },
// pageSize: {
// require: true,
// type: Number,
// default: 10,
// },
},
data() {
return {
//最低单体温度 最高温度 最低电压 最高电压 todo 这里的顺序需要和图形组件里的顺序保持一致,
colorMap: {
0: "minwd",
1: "maxwd",
2: "mindy",
3: "maxdy",
},
};
},
methods: {
//处理图形class 对应高亮设置
handleListClass(item) {
let className = "";
const { clusterDeviceId, deviceId } = item,
clusterIdList = Object.keys(this.pointIdList);
if (clusterIdList.includes(clusterDeviceId)) {
const index = this.pointIdList[clusterDeviceId].findIndex(
(ids) => ids === parseInt(deviceId)
);
if (index > -1) {
className = this.colorMap[index];
}
}
return className;
},
//查看表格行图表
chartDetail(row, dataType = "") {
const { clusterDeviceId, deviceId } = row;
this.$emit("chart", { clusterDeviceId, deviceId, dataType });
},
},
};
</script>
<style lang="scss" scoped>
.lists-container {
padding: 20px 0;
.lists {
margin: 10px 5px;
padding: 5px 9px;
font-size: 11px;
line-height: 20px;
border: 1.6px solid #09ada3;
border-radius: 5px;
position: relative;
color: #333333;
float: left;
box-sizing: content-box;
min-width: 60px;
width: auto;
cursor: pointer;
&::before {
display: block;
content: "";
top: -7px;
left: 50%;
transform: translateX(-50%);
position: absolute;
width: 45%;
height: 0;
border-bottom: 7px solid #09ada3;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
}
&.minwd {
border-color: #3794ff;
.wd {
color: #3794ff;
}
&::before {
border-bottom-color: #3794ff;
}
}
&.maxwd {
border-color: #ff3a3b;
.wd {
color: #ff3a3b;
}
&::before {
border-bottom-color: #ff3a3b;
}
}
&.mindy {
border-color: #de6902;
.dy {
color: #de6902;
}
&::before {
border-bottom-color: #de6902;
}
}
&.maxdy {
border-color: #ffb521;
.dy {
color: #ffb521;
}
&::before {
border-bottom-color: #ffb521;
}
}
}
}
.dtdc-pagination {
::v-deep {
.el-button {
padding: 2px 10px !important;
font-size: 11px;
line-height: 16px;
}
.activeBtn {
background-color: #09ada3;
border-color: #09ada3;
}
}
}
</style>

View File

@ -0,0 +1,125 @@
<template>
<div>
<el-table
class="common-table"
:data="tableData"
stripe
style="width: 100%; margin-top: 25px"
>
<el-table-column prop="deviceId" label="单体编号"> </el-table-column>
<el-table-column prop="clusterDeviceId" label="簇号"> </el-table-column>
<el-table-column prop="voltage" label="电压V">
<template slot-scope="scope">
<el-button
@click="chartDetail(scope.row, 'voltage')"
type="text"
size="small"
>
{{ scope.row.voltage }}
</el-button>
</template>
</el-table-column>
<el-table-column prop="temperature" label="温度(℃)">
<template slot-scope="scope">
<el-button
@click="chartDetail(scope.row, 'temperature')"
type="text"
size="small"
>
{{ scope.row.temperature }}
</el-button>
</template>
</el-table-column>
<el-table-column prop="soc" label="SOC%">
<template slot-scope="scope">
<el-button
@click="chartDetail(scope.row, 'soc')"
type="text"
size="small"
>
{{ scope.row.soc }}
</el-button>
</template>
</el-table-column>
<el-table-column prop="soh" label="SOH%">
<template slot-scope="scope">
<el-button
@click="chartDetail(scope.row, 'soh')"
type="text"
size="small"
>
{{ scope.row.soh }}
</el-button>
</template>
</el-table-column>
<el-table-column label="曲线图">
<template slot-scope="scope">
<el-button @click="chartDetail(scope.row)" type="text" size="small">
展示
</el-button>
</template>
</el-table-column>
</el-table>
<!-- <el-pagination
v-show="tableData.length > 0"
background
@size-change="(val) => $emit('handleSizeChange', val)"
@current-change="(val) => $emit('handleCurrentChange', val)"
:current-page="pageNum"
:page-size="pageSize"
:page-sizes="[10, 20, 30, 40]"
layout="total, sizes, prev, pager, next, jumper"
:total="totalSize"
style="margin-top: 15px; text-align: center"
>
</el-pagination> -->
</div>
</template>
<script>
export default {
props: {
tableData: {
require: true,
type: Array,
default: () => {
return [];
},
},
pointIdList: {
require: true,
type: Object,
default: () => {
return {};
},
},
totalSize: {
require: true,
type: Number,
default: 0,
},
// pageNum: {
// require: true,
// type: Number,
// default: 1,
// },
// pageSize: {
// require: true,
// type: Number,
// default: 10,
// },
},
data() {
return {};
},
methods: {
//查看表格行图表
chartDetail(row, dataType = "") {
const { clusterDeviceId, deviceId } = row;
this.$emit("chart", { clusterDeviceId, deviceId, dataType });
},
},
};
</script>
<style></style>

View File

@ -1,112 +1,96 @@
<template>
<el-card v-loading="loading" shadow="always" class="common-card-container common-card-container-no-title-bg">
<el-card
v-loading="loading"
shadow="always"
class="common-card-container common-card-container-no-title-bg"
>
<div slot="header">
<span class="large-title">单体电池实时数据</span>
</div>
<!-- 搜索栏-->
<el-form :inline="true" class="select-container">
<el-form-item label="编号">
<el-input
v-model="search.batteryId"
placeholder="请输入"
clearable
style="width: 150px"
/>
</el-form-item>
<el-form-item label="电池堆">
<el-select v-model="search.stackId" placeholder="请选择" @change="changeStackId">
<el-option :label="item.deviceName" :value="item.id" v-for="(item,index) in stackOptions" :key="index+'stackOptions'"></el-option>
<el-select
v-model="search.stackId"
placeholder="请选择"
@change="changeStackId"
>
<el-option
:label="item.deviceName"
:value="item.id"
v-for="(item, index) in stackOptions"
:key="index + 'stackOptions'"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="电池簇">
<el-select v-model="search.clusterId" :no-data-text="!search.stackId && stackOptions.length > 0 ? '请先选择电池堆':'无数据'" placeholder="请选择" :loading="clusterloading" loading-text="正在加载数据">
<el-option :label="item.deviceName" :value="item.id" v-for="(item,index) in clusterOptions" :key="index+'clusterOptions'"></el-option>
<el-select
v-model="search.clusterId"
:no-data-text="
!search.stackId && stackOptions.length > 0
? '请先选择电池堆'
: '无数据'
"
placeholder="请选择"
:loading="clusterloading"
loading-text="正在加载数据"
>
<el-option
:label="item.deviceName"
:value="item.id"
v-for="(item, index) in clusterOptions"
:key="index + 'clusterOptions'"
></el-option>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSearch" native-type="button">搜索</el-button>
<el-button type="primary" @click="onSearch" native-type="button"
>搜索</el-button
>
</el-form-item>
<el-form-item>
<el-button @click="onReset" native-type="button">重置</el-button>
</el-form-item>
</el-form>
<!-- 图表-->
<!-- <div style="margin:30px 0;box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);">-->
<!-- <el-row style="background:#fff;margin:30px 0;">-->
<!-- <el-col :xs="24" :sm="24" :lg="24">-->
<!-- <bar-chart ref="barChart"/>-->
<!-- </el-col>-->
<!-- </el-row>-->
<!-- </div>-->
<el-table
class="common-table"
:data="tableData"
stripe
style="width: 100%;margin-top: 25px">
<el-table-column
prop="deviceId"
label="单体编号">
</el-table-column>
<el-table-column
prop="clusterDeviceId"
label="簇号">
</el-table-column>
<el-table-column
prop="voltage"
label="电压V"
<!-- 切换 -->
<div class="tip-container">
<div class="color-tip" v-show="activeBtn === 'list'">
单体信息
<span class="tip minwd">最低单体温度</span>
<span class="tip maxwd">最高单体温度</span>
<span class="tip mindy">单体最低电压</span>
<span class="tip maxdy">单体最高电压</span>
</div>
<el-button-group class="ems-btns-group">
<el-button
:class="{ activeBtn: activeBtn === 'table' }"
@click="changeMenu('table')"
>图表</el-button
>
<template slot-scope="scope">
<el-button
@click="chartDetail(scope.row,'voltage')"
type="text"
size="small">
{{scope.row.voltage}}
</el-button>
</template>
</el-table-column>
<el-table-column
prop="temperature"
label="温度(℃)">
<template slot-scope="scope">
<el-button
@click="chartDetail(scope.row,'temperature')"
type="text"
size="small">
{{scope.row.temperature}}
</el-button>
</template>
</el-table-column>
<el-table-column
prop="soc"
label="SOC%">
<template slot-scope="scope">
<el-button
@click="chartDetail(scope.row,'soc')"
type="text"
size="small">
{{scope.row.soc}}
</el-button>
</template>
</el-table-column>
<el-table-column
prop="soh"
label="SOH%">
<template slot-scope="scope">
<el-button
@click="chartDetail(scope.row,'soh')"
type="text"
size="small">
{{scope.row.soh}}
</el-button>
</template>
</el-table-column>
<el-table-column
label="曲线图">
<template slot-scope="scope">
<el-button
@click="chartDetail(scope.row)"
type="text"
size="small">
展示
</el-button>
</template>
</el-table-column>
</el-table>
:class="{ activeBtn: activeBtn === 'list' }"
@click="changeMenu('list')"
>图形</el-button
>
</el-button-group>
</div>
<component
:is="activeBtn === 'table' ? 'DtdcTable' : 'DtdcList'"
:tableData="tableData"
:totalSize="totalSize"
:pointIdList="pointIdList"
@chart="chartDetail"
></component>
<el-pagination
v-show="tableData.length>0"
v-show="tableData.length > 0"
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
@ -115,110 +99,237 @@
:page-sizes="[10, 20, 30, 40]"
layout="total, sizes, prev, pager, next, jumper"
:total="totalSize"
style="margin-top:15px;text-align: center"
style="margin-top: 15px; text-align: center"
>
</el-pagination>
<chart-detail ref="chartDetail"/>
<chart-detail ref="chartDetail" />
</el-card>
</template>
<script>
import BarChart from './BarChart'
import {getStackNameList, getClusterNameList, getClusterDataInfoList} from '@/api/ems/dzjk'
import BarChart from "./BarChart";
import {
getStackNameList,
getClusterNameList,
getClusterDataInfoList,
} from "@/api/ems/dzjk";
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import ChartDetail from "./ChartDetail.vue";
import Table from "./Table.vue";
import List from "./List.vue";
export default {
name:'DzjkSbjkDtdc',
mixins:[getQuerySiteId],
components:{BarChart, ChartDetail},
name: "DzjkSbjkDtdc",
mixins: [getQuerySiteId],
components: { BarChart, ChartDetail, DtdcTable: Table, DtdcList: List },
computed: {
pointIdList() {
let obj = {};
this.pointData.forEach((item) => {
const {
maxCellTempId,
maxCellVoltageId,
minCellTempId,
minCellVoltageId,
} = item;
obj[item.clusterId] = [
parseInt(minCellTempId || 0),
parseInt(maxCellTempId || 0),
parseInt(minCellVoltageId || 0),
parseInt(maxCellVoltageId || 0),
]; //最低单体温度 最高温度 最低电压 最高电压 todo 这里的顺序需要和图形组件里的顺序保持一致,
});
return obj;
},
},
data() {
return {
loading:false,
clusterloading:false,
search:{stackId:'',clusterId:''},
stackOptions:[],//{id:'',deviceName:''}
clusterOptions:[],//{id:'',deviceName:''}
tableData:[],
pageSize:10,//分页栏当前每个数据总数
pageNum:1,//分页栏当前
totalSize:0,//table表格数据总
}
loading: false,
clusterloading: false,
search: { stackId: "", clusterId: "", batteryId: "" },
stackOptions: [], //{id:'',deviceName:''}
clusterOptions: [], //{id:'',deviceName:''}
tableData: [],
pointData: [],
pageSize: 40, //分页栏当前每个数据总
pageNum: 1, //分页栏当前页
totalSize: 0, //table表格数据总数
activeBtn: "table",
};
},
methods: {
changeMenu(menu) {
const { activeBtn } = this;
activeBtn !== menu && (this.activeBtn = menu);
},
methods:{
//查看表格行图表
chartDetail(row,dataType = ''){
const { clusterDeviceId, deviceId} = row,{siteId} = this
this.$refs.chartDetail.initChart({siteId,clusterDeviceId,deviceId},dataType)
chartDetail({ clusterDeviceId, deviceId, dataType = "" }) {
const { siteId } = this;
this.$refs.chartDetail.initChart(
{ siteId, clusterDeviceId, deviceId },
dataType
);
},
// 分页
handleSizeChange(val) {
this.pageSize = val;
this.$nextTick(()=>{
this.getTableData()
})
this.$nextTick(() => {
this.getTableData();
});
},
handleCurrentChange(val) {
this.pageNum = val
this.$nextTick(()=>{
this.getTableData()
})
this.pageNum = val;
this.$nextTick(() => {
this.getTableData();
});
},
// 搜索
onSearch(){
this.pageNum =1//每次搜索从1开始搜索
this.getTableData()
onSearch() {
this.pageNum = 1; //每次搜索从1开始搜索
this.getTableData();
},
// 重置
// 清空搜索栏选中数据
// 清空电池簇列表,保留电池堆列表
onReset(){
this.search={stackId:'',clusterId:''}
this.clusterOptions=[]
this.pageNum = 1
this.getTableData()
onReset() {
this.search = { stackId: "", clusterId: "", batteryId: "" };
this.clusterOptions = [];
this.pageNum = 1;
this.getTableData();
},
changeStackId(val){
if(val){
console.log('选择了电池堆,需要获取对应的电池簇',val,this.search.stackId)
this.search.clusterId=''
this.getClusterList()
changeStackId(val) {
if (val) {
console.log(
"选择了电池堆需要获取对应的电池簇",
val,
this.search.stackId
);
this.search.clusterId = "";
this.getClusterList();
}
},
//表格数据
getTableData(){
this.loading=true;
const {stackId:stackDeviceId,clusterId:clusterDeviceId} =this.search
const {siteId,pageNum,pageSize}=this
getClusterDataInfoList({stackDeviceId,clusterDeviceId,siteId,pageNum,pageSize}).then(response => {
this.tableData=response?.rows || [];
this.totalSize = response?.total || 0
}).finally(()=>{
this.loading=false;
getTableData() {
this.loading = true;
const {
stackId: stackDeviceId,
clusterId: clusterDeviceId,
batteryId,
} = this.search;
const { siteId, pageNum, pageSize } = this;
getClusterDataInfoList({
stackDeviceId,
clusterDeviceId,
siteId,
batteryId,
pageNum,
pageSize,
})
},
getStackList(){
getStackNameList(this.siteId).then(response => {
this.stackOptions = JSON.parse(JSON.stringify(response?.data || []))
.then((response) => {
this.tableData = response?.rows?.[0]?.batteryList || []; //todo check
this.pointData = response?.rows?.[0]?.clusterList || []; //todo check
this.totalSize = response?.total || 0;
})
.finally(() => {
this.loading = false;
});
},
getClusterList(){
this.clusterloading =true
getClusterNameList(this.search.stackId).then(response => {
this.clusterOptions = JSON.parse(JSON.stringify(response?.data || []))
}).finally(() => {this.clusterloading =false})
getStackList() {
getStackNameList(this.siteId).then((response) => {
this.stackOptions = JSON.parse(JSON.stringify(response?.data || []));
});
},
init(){
getClusterList() {
this.clusterloading = true;
getClusterNameList({
stackDeviceId: this.search.stackId,
siteId: this.siteId,
})
.then((response) => {
this.clusterOptions = JSON.parse(
JSON.stringify(response?.data || [])
);
})
.finally(() => {
this.clusterloading = false;
});
},
init() {
// 只有页面初次加载或切换站点的时候调用电池堆列表,其他情况不需要
this.search={stackId:'',clusterId:''}//保证切换站点时,清空选择项
this.getStackList()
this.getTableData()
}
this.search = { stackId: "", clusterId: "", batteryId: "" }; //保证切换站点时,清空选择项
this.clusterOptions = [];
this.pageNum = 1;
this.totalSize = 0;
this.getStackList();
this.getTableData();
},
mounted(){
},
mounted() {},
};
</script>
<style scoped lang="scss">
.tip-container {
text-align: right;
position: relative;
.color-tip {
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
font-size: 11px;
line-height: 12px;
color: #333;
.tip {
padding-left: 30px;
position: relative;
&::before {
display: block;
content: "";
position: absolute;
left: 14px;
top: 50%;
transform: translateY(-50%);
width: 8px;
height: 8px;
border-radius: 50%;
}
&.minwd {
color: #3794ff;
&::before {
background: #3794ff;
}
}
&.maxwd {
color: #ff3a3b;
&::before {
background: #ff3a3b;
}
}
&.mindy {
color: #de6902;
&::before {
background: #de6902;
}
}
&.maxdy {
color: #ffb521;
&::before {
background: #ffb521;
}
}
}
}
::v-deep {
.el-button-group.ems-btns-group {
& > .el-button {
padding: 5px 30px !important;
font-size: 11px;
line-height: 16px;
// padding-left: 50px;
// padding-right: 50px;
// font-size: 16px;
// line-height: 24px;
}
}
}
}
</script>
</style>

View File

@ -1,5 +1,7 @@
<template>
<div class="ems-dashboard-editor-container ems-content-container-padding sbjk-ems-dashboard-editor-container">
<div
class="ems-dashboard-editor-container ems-content-container-padding sbjk-ems-dashboard-editor-container ems-third-menu-container"
>
<el-menu
class="ems-third-menu"
:default-active="$route.name"
@ -7,50 +9,58 @@
text-color="#666666"
active-text-color="#ffffff"
>
<el-menu-item :index="item.name" v-for="(item,index) in childrenRoute" :key="index+'dzjkChildrenRoute'">
<router-link style="height: 100%;width: 100%;display: block" :to="{path:item.path,query:$route.query}">
{{item.meta.title}}
<el-menu-item
:index="item.name"
v-for="(item, index) in childrenRoute"
:key="index + 'dzjkChildrenRoute'"
>
<router-link
style="height: 100%; width: 100%; display: block"
:to="{ path: item.path, query: $route.query }"
>
{{ item.meta.title }}
</router-link>
</el-menu-item>
</el-menu>
<div class="ems-content-container ems-content-container-padding sbjk-ems-content-container">
<div
class="ems-content-container ems-content-container-padding sbjk-ems-content-container"
>
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
</div>
</template>
<script>
import { dzjk } from '@/router/ems'
const childrenRoute = dzjk[0].children.find(item=> item.name==='DzjkSbjk').children//获取到单站监控-设备监控下面的字路由
console.log('设备监控子路由',childrenRoute)
import { dzjk } from "@/router/ems";
const childrenRoute = dzjk[0].children.find(
(item) => item.name === "DzjkSbjk"
).children; //获取到单站监控-设备监控下面的字路由
console.log("设备监控子路由", childrenRoute);
export default {
name:'DzjkSbjk',
data(){
name: "DzjkSbjk",
data() {
return {
childrenRoute,
activeMenu:''
}
activeMenu: "",
};
},
mounted() {
console.log('当前设备监控页面路由',this.$route)
}
}
console.log("当前设备监控页面路由", this.$route);
},
};
</script>
<style scoped lang="scss">
.sbjk-ems-dashboard-editor-container{
.sbjk-ems-dashboard-editor-container {
display: flex;
background: #FFFFFF;
background: #ffffff;
}
.sbjk-ems-content-container{
margin-top:0;
padding-top:0;
.sbjk-ems-content-container {
margin-top: 0;
padding-top: 0;
padding-right: 0;
flex: 1;
}
</style>

View File

@ -12,10 +12,11 @@
<div>{{$store.state.ems.communicationStatusOptions[pcsItem.communicationStatus]}}</div>
<div>数据更新时间{{pcsItem.dataUpdateTime}}</div>
</div>
<!-- <div class="pcs-btns">-->
<!-- <el-button type="warning" size="small" @click="problemSaved">故障复位</el-button>-->
<!-- <el-button size="small" @click="machineClosed">关机</el-button>-->
<!-- </div>-->
<div class="pcs-btns">
<el-badge :value="pcsItem.alarmNum || 0" class="item">
<i class="el-icon-message-solid" style="font-size: 26px;color: #fff;display: block;"></i>
</el-badge>
</div>
</el-header>
<el-main style="padding: 0">
<div class="descriptions-main">
@ -91,11 +92,8 @@ export default {
if (action === 'confirm') {
instance.confirmButtonLoading = true;
setTimeout(() => {
// todo 调用接口如果关机成功 调用done方法 否则不关闭弹窗
done();
// setTimeout(() => {
instance.confirmButtonLoading = false;
// }, 300);
}, 3000);
} else {
done();
@ -122,11 +120,8 @@ export default {
if (action === 'confirm') {
instance.confirmButtonLoading = true;
setTimeout(() => {
// todo 调用接口如果关机成功 调用done方法 否则不关闭弹窗
done();
// setTimeout(() => {
instance.confirmButtonLoading = false;
// }, 300);
}, 3000);
} else {
done();

View File

@ -57,7 +57,7 @@ export default {
top: '10',
},
grid: {
left: "15%"
containLabel: true
},
tooltip: {
trigger: 'axis',

View File

@ -61,7 +61,7 @@ export default {
}
},
grid: {
left: "15%"
containLabel: true
},
textStyle:{
color:"#333333",

View File

@ -62,7 +62,7 @@ export default {
}
},
grid: {
left: "15%"
containLabel: true
},
textStyle:{
color:"#333333",

View File

@ -58,7 +58,7 @@ export default {
}
},
grid: {
left: "15%"
containLabel: true
},
textStyle:{
color:"#333333",

View File

@ -1,7 +1,6 @@
<template>
<div v-loading="loading">
<!-- todo 判断条件是否需要更新-->
<div class="yl-item-container" :class="{'yl-warn-item-container':item.workMode !== '0'}" v-for="(item,index) in list" :key="index+'ylLise'">
<div class="header">
<div class="header-title">{{item.systemName}}</div>

View File

@ -125,9 +125,12 @@ export default {
})
this.chart.setOption({
color:['#FFBD00','#3C81FF'],
grid: {
containLabel: true
},
legend: {
left: 'center',
bottom: '10',
bottom: '15',
},
tooltip: {
trigger: 'axis',

View File

@ -171,7 +171,7 @@ export default {
},
async getClusterList(){
this.clusterloading =true
await getClusterNameList(this.search.stackId).then(response => {
await getClusterNameList({stackDeviceId: this.search.stackId, siteId: this.siteId}).then(response => {
const data = JSON.parse(JSON.stringify(response?.data || []))
this.clusterOptions = data
this.search.clusterId = data.length > 0 ? data[0].id : ''

View File

@ -121,9 +121,12 @@ export default {
})
this.chart.setOption({
color:['#FFBD00','#3C81FF'],
grid: {
containLabel: true
},
legend: {
left: 'center',
bottom: '10',
bottom: '15',
},
tooltip: {
trigger: 'axis',

View File

@ -31,7 +31,7 @@
<div>总放电量:<span class="point">{{totalDisChargedCap | formatNumber}}kWh</span></div>
<div>综合效率:<span class="point">{{efficiency | formatNumber}}%</span></div>
</div>
<div id="dlzbChart" style="height: 310px"></div>
<div id="dlzbChart" style="height: 310px;"></div>
</div>
</el-card>
</template>
@ -73,16 +73,21 @@ export default {
})
this.chart.setOption({
color:['#FFBD00','#3C81FF','#05AEA3'],
// legend: {
// left: 'right',
// bottom: '10',
// },
tooltip: {},
xAxis: {
type: 'category',
name:unit,
nameLocation:'center'
legend: {
left: 'center',
bottom: '15',
},
grid: {
top:40,
containLabel: true
},
tooltip: {},
xAxis: [{
type: 'category',
name:`单位:${unit}`,
nameLocation:'center',
nameGap:30
}],
yAxis: [{
type: 'value',
name:'充电量/放电量kWh',
@ -102,7 +107,6 @@ export default {
onZero:false
}
}],
grid:{top:40},
dataset:{
source
},
@ -163,7 +167,7 @@ export default {
line-height: 18px;
color: #333333;
font-size: 16px;
padding:10px 0;
padding:20px 0;
>div{
display: inline-block;
margin-right: 20px;

View File

@ -1,5 +1,5 @@
<template>
<div class="ems-dashboard-editor-container ems-content-container-padding tjbb-ems-dashboard-editor-container">
<div class="ems-dashboard-editor-container ems-third-menu-container">
<el-menu
class="ems-third-menu"
:default-active="$route.name"
@ -7,51 +7,55 @@
text-color="#666666"
active-text-color="#ffffff"
>
<el-menu-item :index="item.name" v-for="(item,index) in childrenRoute" :key="index+'tjbbChildrenRoute'">
<router-link style="height: 100%;width: 100%;display: block;" :to="{path:item.path,query:$route.query}">
{{item.meta.title}}
<el-menu-item
:index="item.name"
v-for="(item, index) in childrenRoute"
:key="index + 'tjbbChildrenRoute'"
>
<router-link
style="height: 100%; width: 100%; display: block"
:to="{ path: item.path, query: $route.query }"
>
{{ item.meta.title }}
</router-link>
</el-menu-item>
</el-menu>
<div class="ems-content-container ems-content-container-padding tjbb-ems-content-container">
<div
class="ems-content-container ems-content-container-padding tjbb-ems-content-container"
>
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
</div>
</template>
<script>
import { dzjk } from '@/router/ems'
const childrenRoute = dzjk[0].children.find(item=> item.name==='DzjkTjbb').children//获取到统计报表下面的字路由
console.log('设备监控子路由',childrenRoute)
import { dzjk } from "@/router/ems";
const childrenRoute = dzjk[0].children.find(
(item) => item.name === "DzjkTjbb"
).children; //获取到统计报表下面的字路由
console.log("设备监控子路由", childrenRoute);
export default {
name:'DzjkTjbb',
data(){
name: "DzjkTjbb",
data() {
return {
childrenRoute,
activeMenu:''
}
activeMenu: "",
};
},
mounted() {
console.log('当前统计报表页面路由',this.$route)
}
}
console.log("当前统计报表页面路由", this.$route);
},
};
</script>
<style scoped lang="scss">
.tjbb-ems-dashboard-editor-container{
display: flex;
background: #FFFFFF;
}
.tjbb-ems-content-container{
margin-top:0;
padding-top:0;
.tjbb-ems-content-container {
margin-top: 0;
padding-top: 0;
padding-right: 0;
flex: 1;
}
</style>

View File

@ -128,9 +128,12 @@ export default {
})
this.chart.setOption({
color:['#FFBD00','#3C81FF','#91cc74'],
grid: {
containLabel: true
},
legend: {
left: 'center',
bottom: '10',
bottom: '15',
},
tooltip: {
trigger: 'axis',

View File

@ -0,0 +1,577 @@
<template>
<div class="ems-dashboard-editor-container" v-loading="loading">
<div class="container" v-show="!empty">
<!-- 电脑 -->
<div class="top">
<div class="cloud-container">
<div class="cloud">
<span style="z-index: 2; position: relative"></span>
</div>
</div>
<div class="double-arrows">
<div class="top-arrows"></div>
<div class="bottom-arrows"></div>
</div>
<div class="computer">
<img src="@/assets/images/ems/computer.png" alt="" />
<span style="z-index: 2; position: relative">ems</span>
</div>
</div>
<div class="outer-border">
<!-- 电表-->
<div class="row-lists-container" v-if="showDb">
<div class="row-title">电表({{ db.length }})</div>
<div class="row-lists">
<div v-for="item in db" :key="item.deviceId" class="row-items">
<div
class="status"
:class="
item.communicationStatus === '0' ? 'status-running' : ''
"
>
{{ communicationStatusOptions[item.communicationStatus] }}
</div>
<div class="row-items-img">
<img
class="img-db"
:src="require('@/assets/images/ems/db.png')"
/>
<div class="name">{{ item.deviceName }}</div>
</div>
</div>
</div>
</div>
<!-- 液冷-->
<div class="row-lists-container" v-if="showLq">
<div class="row-title">冷却({{ lq.length }})</div>
<div class="row-lists">
<div v-for="item in lq" :key="item.deviceId" class="row-items">
<div
class="status"
:class="
item.communicationStatus === '0' ? 'status-running' : ''
"
>
{{ communicationStatusOptions[item.communicationStatus] }}
</div>
<div class="row-items-img">
<img
class="img-lq"
:src="require('@/assets/images/ems/lq.png')"
/>
<div class="name">{{ item.deviceName }}</div>
</div>
</div>
</div>
</div>
<!-- PCS-->
<div class="row-lists-container" v-if="showPcs">
<div class="row-lists">
<div class="row-title">PCS({{ pcs.length }})</div>
<div
v-for="(item, index) in pcs"
:key="item.deviceId"
class="row-items row-items-pcs"
>
<!-- pcs -->
<div class="parent-dash">
<div
class="status"
:class="
item.communicationStatus === '0' ? 'status-running' : ''
"
>
{{ communicationStatusOptions[item.communicationStatus] }}
</div>
<div class="row-items-img">
<img
class="img-pcs"
:src="require('@/assets/images/ems/pcs.png')"
/>
<div class="name">{{ item.deviceName }}</div>
</div>
</div>
<!-- 子设备 bms -->
<div
v-if="item.children && item.children.length > 0"
class="children-dash"
>
<div
class="row-children-title"
v-if="bmsHasParentLength > 0 && index === 0"
>
BMS({{ bmsHasParentLength }})
</div>
<div
v-for="(childrenItem, childrenIndex) in item.children"
:key="childrenIndex + 'childrenBms'"
class="children-dash-items"
>
<div
class="status"
:class="
childrenItem.communicationStatus === '0'
? 'status-running'
: ''
"
>
{{
communicationStatusOptions[
childrenItem.communicationStatus
]
}}
</div>
<div class="row-items-img">
<img
class="img-pcs"
:src="require('@/assets/images/ems/bms.png')"
/>
<div class="name">{{ childrenItem.deviceName }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row-lists-container" v-if="showPcs">
<div class="row-title">PCS({{ pcs.length }})</div>
<div class="row-lists">
<div
v-for="item in bmsNoParent"
:key="item.deviceId"
class="row-items row-items-pcs"
>
<!-- pcs -->
<div class="parent-dash">
<div
class="status"
:class="
item.communicationStatus === '0' ? 'status-running' : ''
"
>
{{ communicationStatusOptions[item.communicationStatus] }}
</div>
<div class="row-items-img">
<img :src="require('@/assets/images/ems/bms.png')" />
<div class="name">{{ item.deviceName }}</div>
</div>
</div>
</div>
</div>
</div>
<!-- bms没有上级设备-->
<div class="row-lists-container" v-if="bmsNoParent.length > 0">
<div class="row-title">BMS({{ bmsNoParent.length }})</div>
<div class="row-lists">
<div
v-for="item in bmsNoParent"
:key="item.deviceId"
class="row-items row-items-pcs"
>
<!-- pcs -->
<div class="parent-dash">
<div
class="status"
:class="
item.communicationStatus === '0' ? 'status-running' : ''
"
>
{{ communicationStatusOptions[item.communicationStatus] }}
</div>
<div class="row-items-img">
<img :src="require('@/assets/images/ems/bms.png')" />
<div class="name">{{ item.deviceName }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<el-empty v-show="empty" :image-size="200"></el-empty>
</div>
</template>
<script>
import { getDeviceList } from "@/api/ems/site";
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import { mapState } from "vuex";
export default {
name: "DzjkZxlt",
mixins: [getQuerySiteId],
data() {
return {
loading: false,
pcs: [],
bms: [],
db: [],
lq: [],
pcsHasChildren: [],
pcsNoChildren: [],
bmsNoParent: [],
};
},
computed: {
...mapState({
communicationStatusOptions: (state) =>
state.ems.communicationStatusOptions,
}),
showPcs() {
return this.pcs.length > 0;
},
showBms() {
return this.bms.length > 0;
},
showDb() {
return this.db.length > 0;
},
showLq() {
return this.lq.length > 0;
},
bmsHasParentLength() {
let count = 0;
this.pcs.forEach((item) => (count += item.children.length));
return count;
},
empty() {
return !this.showBms && !this.showPcs && !this.showDb && !this.showLq;
},
},
methods: {
init() {
this.pcs = [];
this.bms = [];
this.lq = [];
this.db = [];
this.bmsNoParent = [];
this.loading = true;
getDeviceList(this.siteId)
.then((response) => {
const data = JSON.parse(JSON.stringify(response?.data || []));
let pcs = [],
bms = [],
db = [],
lq = [],
bmsNoParent = [];
data.forEach((item) => {
// 电表
if (item.deviceCategory === "AMMETER") {
db.push({ ...item, children: [] });
} else if (item.deviceCategory === "PCS") {
// pcs
pcs.push({ ...item, children: [] });
} else if (item.deviceCategory === "STACK") {
// bms
bms.push({ ...item, children: [] });
} else if (item.deviceCategory === "COOLING") {
// 液冷
lq.push({ ...item, children: [] });
}
});
bms.forEach((item, index) => {
if (item.parentId) {
pcs
.find((pcsItem) => pcsItem.deviceId === item.parentId)
.children.push(item);
} else {
bmsNoParent.push(item);
}
});
this.pcs = pcs;
this.bms = bms;
this.lq = lq;
this.db = db;
this.pcsHasChildren = pcs.filter((item) => item.children.length > 0);
this.pcsNoChildren = pcs.filter((item) => item.children.length === 0);
this.bmsNoParent = bmsNoParent;
})
.finally(() => {
this.loading = false;
});
},
},
};
</script>
<style lang="scss" scoped>
$sqDistance: 30px;
$borderColor: #174a8e;
$lineColor: #86bcc7;
.ems-dashboard-editor-container {
background-color: #ffffff;
padding: 0;
color: #666666;
.container {
display: flex;
position: relative;
}
//云 、计算机 、箭头
.top {
z-index: 2;
width: fit-content;
display: flex;
justify-content: center;
align-items: center;
// position: absolute;
// top: 50%;
// left: 0;
// transform: translateY(-50%);
//云 样式
.cloud-container {
margin: 0 auto;
.cloud {
width: 60px;
height: 26px;
background: #cbebfd;
border-radius: 100px;
position: relative;
text-align: center;
font-weight: bold;
font-size: 14px;
line-height: 26px;
}
.cloud:before,
.cloud:after {
content: "";
position: absolute;
background: #cbebfd;
width: 30px;
height: 30px;
border-radius: 100%;
}
.cloud:before {
top: -9px;
left: 8px;
}
.cloud:after {
top: -6px;
right: 9px;
}
}
//双箭头
.double-arrows {
height: fit-content;
margin: 0 10px;
text-align: center;
.top-arrows,
.bottom-arrows {
height: 4px;
width: 30px;
background-color: #5ea9df;
margin: 0 10px;
position: relative;
&::after {
content: "";
position: absolute;
left: 0;
width: 0;
height: 0;
}
}
.top-arrows {
vertical-align: super;
}
.top-arrows::after {
top: -4px;
border-bottom: 6px solid transparent;
border-left: 6px solid transparent;
border-right: 6px solid #5ea9df;
border-top: 6px solid transparent;
left: -11px;
}
.bottom-arrows {
margin-top: 8px;
&::after {
top: -4px;
border-top: 6px solid transparent;
border-left: 6px solid #5ea9df;
border-right: 6px solid transparent;
border-bottom: 6px solid transparent;
right: -11px;
left: auto;
}
}
}
//电脑
.computer {
text-align: center;
font-size: 14px;
line-height: 16px;
font-weight: bold;
position: relative;
background: #fff;
img {
width: 80px;
height: auto;
display: block;
}
}
}
.outer-border {
position: relative;
width: fit-content;
border: 1.5px solid $borderColor;
border-radius: 5px;
padding-left: 120px;
padding-right: 20px;
margin-left: -40px;
}
// 设备列表
.row-lists-container {
font-size: 10px;
position: relative;
padding: 10px;
.row-title {
position: absolute;
left: -$sqDistance - 30px;
top: calc(50% + 10px);
transform: translateY(-50%);
color: #000;
font-weight: bolder;
}
.row-lists {
display: flex;
position: relative;
.row-items {
position: relative;
padding: 5px 0;
&:not(:first-child) {
margin-left: $sqDistance; //和外层父元素上下padding一致
}
&::before {
content: "";
display: block;
height: 3px;
width: $sqDistance - 2px;
background: $lineColor;
position: absolute;
left: -$sqDistance;
top: calc(50% + 10px);
transform: scale(1, 0.4);
}
// 一列 第一个设备最上面的线
&:first-child {
&::before {
width: $sqDistance + 20px;
// top: -$sqDistance - 20px;
}
}
// 一列 最后一个设备最下面的线
// &:last-child {
// &::after {
// content: "";
// display: block;
// width: 3px;
// height: $sqDistance - 2px;
// background: $lineColor;
// position: absolute;
// bottom: -$sqDistance;
// left: 50%;
// transform: scale(0.4, 1);
// }
// }
// 设备状态
.status {
margin: 0 auto 4px;
width: fit-content;
height: 18px;
padding: 0 8px;
box-sizing: border-box;
text-align: center;
font-size: 8px;
line-height: 18px;
border: 1px solid #08ffff;
border-radius: 2px;
background: #aaaaaa;
color: #ffffff;
&.status-running {
background: #00c69c;
}
}
// 图片+设备名称
.row-items-img {
position: relative;
padding-top: 12px;
img {
width: 80px;
height: auto;
display: block;
&.img-lq {
width: 50px;
}
&.img-pcs {
width: 50px;
}
&.img-db {
width: 56px;
}
}
.name {
position: absolute;
top: 1px;
left: 0;
color: #666;
white-space: nowrap;
}
}
}
}
}
//子设备
.row-lists-container-children {
margin: 10px 0 0 $sqDistance;
.parent-dash {
position: relative;
&::before {
content: "";
display: block;
height: 40px;
width: 3px;
background: #ec7f8c;
position: absolute;
left: 20%;
top: -40px;
transform: scale(0.4, 1) rotate(-40deg);
}
}
}
.parent-dash {
width: fit-content;
}
.children-dash {
margin: $sqDistance 0 0 $sqDistance;
position: relative;
.row-children-title {
position: absolute;
left: -$sqDistance - 30px;
top: calc(50% + 10px);
transform: translateY(-50%);
color: #000;
font-weight: bolder;
}
.children-dash-items {
position: relative;
&::before {
content: "";
display: block;
height: $sqDistance;
width: 3px;
background: #ec7f8c;
position: absolute;
left: 20%;
top: -$sqDistance;
transform: scale(0.4, 1) rotate(-40deg);
}
}
}
}
</style>

View File

@ -0,0 +1,614 @@
<template>
<div class="ems-dashboard-editor-container" v-loading="loading" >
<div class="container" v-show="!empty">
<div class="top">
<div class="cloud-container">
<div class="cloud">
<span style="z-index:2;position: relative;"></span>
</div>
</div>
<div class="double-arrows">
<div class="top-arrows"></div>
<div class="bottom-arrows"></div>
</div>
<div class="computer">
<img src="@/assets/images/ems/computer.png" alt="">
<span style="z-index:2;position: relative;">ems</span>
</div>
<div class="arrow"></div>
</div>
<div class="bottom">
<!-- 四列设备-->
<div class="zxlt-row">
<!-- bmspcs 下级和上级在一列 -->
<div class="row-lists pcs-row-lists" v-if="showPcsAndBms">
<div class="item-square">
<div class="row-lists-title" v-if="showPcs">PCS({{pcs.length}})</div>
<div class="row-lists-title" v-if="showBms">BMS({{bms.length}})</div>
</div>
<!-- 上下级块 class区分-->
<div class="item-square pcs-has-children-item-square" :class="{'no-bms-list':!showBms}" v-for="(item,index) in pcsHasChildren" :key="index+'pcsHasChildren'">
<!-- 左边的上级 上级只有一个-->
<div class="item-lists parent-item-lists">
<!-- 上级设备-->
<div class="items normal-items-arrow">
<div class="items-inner">
<div style="text-align: center;margin-bottom:10px;">
<div class="status" :class="item.communicationStatus === '0' ?'status-normal' : 'status-warn'">通讯状态:{{communicationStatusOptions[item.communicationStatus] || '-'}}</div>
</div>
<img v-if="item.pictureUrl" :src="item.pictureUrl">
<img v-else :src="require('@/assets/images/ems/pcs.png')"/>
<div class="name">{{item.deviceName}}</div>
</div>
</div>
</div>
<!-- 右边的下级 下级有多个-->
<div class="item-lists children-item-lists">
<!-- 下级设备 循环生成-->
<div class="items children-items-arrow bms-children-arrow" v-for="children in item.children" :key="children.deviceId">
<div class="items-inner">
<div style="text-align: center;margin-bottom:10px;">
<div class="status" :class="children.communicationStatus === '0' ?'status-normal' : 'status-warn'">通讯状态:{{communicationStatusOptions[children.communicationStatus] || '-'}}</div>
</div>
<img v-if="children.pictureUrl" :src="children.pictureUrl">
<img v-else :src="require('@/assets/images/ems/bms.png')"/>
<div class="name">{{children.deviceName}}</div>
</div>
</div>
</div>
</div>
<!-- 没有上下级关系的bmspcs-->
<div class="item-square" :class="{'no-bms-list':!showBms}">
<!-- 左边没有下级的pcs-->
<div class="item-lists">
<div class="items normal-items-arrow" v-for="item in pcsNoChildren" :key="item.deviceId">
<div class="items-inner">
<div style="text-align: center;margin-bottom:10px;">
<div class="status" :class="item.communicationStatus === '0' ?'status-normal' : 'status-warn'">通讯状态:{{communicationStatusOptions[item.communicationStatus] || '-'}}</div>
</div>
<img v-if="item.pictureUrl" :src="item.pictureUrl">
<img v-else :src="require('@/assets/images/ems/pcs.png')"/>
<div class="name">{{item.deviceName}}</div>
</div>
</div>
</div>
<!-- 右边没有上级的bms-->
<div class="item-lists">
<!-- 下级设备 循环生成-->
<div class="items children-items-arrow" v-for="item in bmsNoParent" :key="item.deviceId">
<div class="items-inner">
<div style="text-align: center;margin-bottom:10px;">
<div class="status" :class="item.communicationStatus === '0' ?'status-normal' : 'status-warn'">通讯状态:{{communicationStatusOptions[item.communicationStatus] || '-'}}</div>
</div>
<img v-if="item.pictureUrl" :src="item.pictureUrl">
<img v-else :src="require('@/assets/images/ems/bms.png')"/>
<div class="name">{{item.deviceName}}</div>
</div>
</div>
</div>
</div>
</div>
<!-- 电表-->
<div class="row-lists" v-if="showDb">
<div class="item-square">
<div class="row-lists-title" style="width:100%;">电表({{db.length}})</div>
</div>
<div class="item-square">
<!-- 左边的下级 下级有多个-->
<div class="item-lists">
<!-- 下级设备 循环生成-->
<div class="items normal-items-arrow" v-for="item in db" :key="item.deviceId">
<div class="items-inner">
<div style="text-align: center;margin-bottom:10px;">
<div class="status" :class="item.communicationStatus === '0' ?'status-normal' : 'status-warn'">通讯状态:{{communicationStatusOptions[item.communicationStatus] || '-'}}</div>
</div>
<img v-if="item.pictureUrl" :src="item.pictureUrl">
<img v-else :src="require('@/assets/images/ems/bms.png')"/>
<div class="name">{{item.deviceName}}</div>
</div>
</div>
</div>
</div>
</div>
<!--冷却-->
<div class="row-lists" v-if="showLq">
<div class="item-square">
<div class="row-lists-title" style="width:100%;">冷却({{lq.length}})</div>
</div>
<div class="item-square">
<div class="item-lists">
<div class="items normal-items-arrow" v-for="item in lq" :key="item.deviceId">
<div class="items-inner">
<div style="text-align: center;margin-bottom:10px;">
<div class="status" :class="item.communicationStatus === '0' ?'status-normal' : 'status-warn'">通讯状态:{{communicationStatusOptions[item.communicationStatus] || '-'}}</div>
</div>
<img v-if="item.pictureUrl" :src="item.pictureUrl">
<img v-else :src="require('@/assets/images/ems/bms.png')"/>
<div class="name">{{item.deviceName}}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<el-empty v-show="empty" :image-size="200"></el-empty>
</div>
</template>
<script>
import {getDeviceList} from'@/api/ems/site'
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import {mapState} from "vuex";
export default {
name: 'DzjkZxlt',
mixins: [getQuerySiteId],
data() {
return {
loading:false,
pcs :[],
bms:[],
db:[],
lq:[],
pcsHasChildren:[],
pcsNoChildren:[],
bmsNoParent:[]
}
},
computed:{
...mapState({
communicationStatusOptions:(state)=>state.ems.communicationStatusOptions
}),
showPcs(){
return this.pcs.length>0
},
showBms(){
return this.bms.length>0
},
showDb(){
return this.db.length>0
},
showLq(){
return this.lq.length>0
},
showPcsAndBms(){
return this.showPcs || this.showBms
},
empty(){
return !this.showBms && !this.showPcs && !this.showDb && !this.showLq
},
},
methods: {
init(){
this.pcs = []
this.bms = []
this.lq=[]
this.db=[]
this.bmsNoParent=[]
this.loading = true
getDeviceList(this.siteId).then(response => {
const data =JSON.parse(JSON.stringify(response?.data || []))
let pcs = [],bms=[],db=[],lq=[],bmsNoParent=[]
data.forEach(item=>{
// 电表
if(item.deviceCategory === 'AMMETER'){
db.push({...item,children:[]})
}else if(item.deviceCategory === 'PCS'){
// pcs
pcs.push({...item,children:[]})
}else if(item.deviceCategory === 'STACK'){
// bms
bms.push({...item,children:[]})
}else if(item.deviceCategory === 'COOLING'){
// 液冷
lq.push({...item,children:[]})
}
})
bms.forEach((item,index)=>{
if(item.parentId){
pcs.find(pcsItem=>pcsItem.deviceId === item.parentId).children.push(item)
}else{
bmsNoParent.push(item)
}
})
this.pcs = pcs
this.bms = bms
this.lq=lq
this.db=db
this.pcsHasChildren = pcs.filter(item=>item.children.length > 0)
this.pcsNoChildren = pcs.filter(item=>item.children.length === 0)
this.bmsNoParent = bmsNoParent
}).finally(() => {
this.loading = false
})
}
},
}
</script>
<style lang="scss" scoped>
$distance:60px;
$arrowDistance:80px;//margin:60+quare的padding10
$arrowColoe:#5ea9df;
$lineColoe:#5ea9df;
.ems-dashboard-editor-container {
background-color: #ffffff;
padding:0;
.container{
position: relative;
overflow-x: auto;
}
//云 、计算机 、箭头
.top{
width: 280px;
font-size: 30px;
line-height: 40px;
font-weight: 500;
display: flex;
flex-direction: column;
//云 样式
.cloud-container{
padding-top:40px;
margin:0 auto;
.cloud {
width: 150px;
height: 60px;
background: #cbebfd;
border-radius: 200px;
position: relative;
text-align: center;
color:#666666;
}
.cloud:before, .cloud:after {
content: '';
position: absolute;
background:#cbebfd;
width: 80px;
height: 80px;
border-radius: 50%;
}
.cloud:before {
top: -28px;
left: 20px;
}
.cloud:after {
top: -31px;
right: 20px;
}
}
//双箭头
.double-arrows {
height: 50px;
margin:20px 0;
text-align: center;
.top-arrows,.bottom-arrows{
height: 100%;
width: 6px;
background-color: $arrowColoe;
display: inline-block;
margin: 0 10px;
position: relative;
vertical-align: super;
&::after {
content: '';
position: absolute;
left:0;
width: 0;
height: 0;
}
}
.top-arrows{
vertical-align: super;
}
.top-arrows::after {
bottom: -24px;
border-bottom: 12px solid transparent;
border-left: 12px solid transparent;
border-right: 12px solid transparent;
border-top: 14px solid $arrowColoe;
left: -9px;
}
.bottom-arrows{
margin-top:12px;
&::after {
top: -24px;
border-top: 12px solid transparent;
border-left: 12px solid transparent;
border-right: 12px solid transparent;
border-bottom: 14px solid $arrowColoe;
left: -9px;
}
}
}
//电脑
.computer{
margin:20px auto;
text-align: center;
color:#666666;
position: relative;
img {
width: auto;
height: 100px;
display: block;
}
}
.arrow{
height: 50px;
width: 30px;
border-radius: 5px;
background-color: $arrowColoe;
position: relative;
margin:0 auto;
&::after{
content: "";
position: absolute;
width: 0;
height: 0;
left: -9px;
border-top: 24px solid $arrowColoe;
border-left: 24px solid transparent;
border-bottom: 24px solid transparent;
border-right: 24px solid transparent;
bottom: -44px;
}
}
}
.bottom{
z-index:1;
box-sizing: border-box;
margin-top:50px;
.zxlt-row{
display: flex;
padding:20px $distance;
position: relative;
width: fit-content;
&:before{
content: '';
display: block;
width:calc(100% - 100px);
height:1px;
background-color: $lineColoe;
position:absolute;
top:0;
left: $distance/2;
}
.row-lists{
height: fit-content;
position: relative;
&:before{
content: '';
display: block;
height: 100%;
width: 1px;
position: absolute;
left:-($distance/2);
top:-20px;
background-color: $lineColoe;
}
//pcs列 bms右侧的边框
&.pcs-row-lists{
&:after{
content: '';
display: block;
height: 100%;
width: 1px;
position: absolute;
right:-(($distance/2) + 1);
top:-20px;
background-color: $lineColoe;
}
}
&:not(:last-child){
margin-right: $distance;
}
.item-square{
//左右 两列
display: flex;
vertical-align: middle;
align-items: flex-start;
padding:10px;
border-radius: 5px;
&:not(:last-child){
margin-bottom: 40px;
}
.row-lists-title{
font-size: 20px;
line-height: 20px;
color: #333333;
font-weight: 500;
text-align: center;
flex: 1;
}
.item-lists{
position: relative;
&:not(:last-child){
margin-right:$distance;
}
//每个设备
.items{
background-color: #cbebfd;
position: relative;
border-radius: 5px;
padding: 10px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1), 0 0 0 rgba(0, 0, 0, 0.5);
//普通设备 箭头方向
&.normal-items-arrow{
&:before{
content: '';
display: block;
width:($arrowDistance/2) - 15;
height: 4px;
background-color: $arrowColoe;
position: absolute;
top:50%;
left: -($arrowDistance/2);
transform: translateY(-50%);
}
&:after{
content: '';
display: block;
height: 0;
width: 0;
border-left: 10px solid #5ea9df;
border-right: 10px solid transparent;
border-bottom: 10px solid transparent;
border-top: 10px solid transparent;
position: absolute;
top: 50%;
left: -15px;
transform: translateY(-50%);
}
}
//下级的箭头
&.children-items-arrow{
&:before{
content: '';
display: block;
width:($arrowDistance/2) - 15;
height: 4px;
background-color: $arrowColoe;
position: absolute;
top:50%;
right: -($arrowDistance/2);
transform: translateY(-50%);
}
&:after{
content: '';
display: block;
height: 0;
width: 0;
border-right: 10px solid #5ea9df;
border-left: 10px solid transparent;
border-bottom: 10px solid transparent;
border-top: 10px solid transparent;
position: absolute;
top: 50%;
right: -15px;
transform: translateY(-50%);
}
}
&:not(:last-child){
margin-bottom: 15px;
}
.items-inner{
background-color: #ffffff;
border-radius: 5px;
padding:10px;
width:130px;
text-align: center;
}
img{
width: 80px;
height: auto;
display: block;
z-index:2;
margin: 0 auto;
}
.name{
text-align: center;
margin-top:10px;
font-size: 14px;
line-height: 20px;
z-index:2;
}
.status{
z-index:2;
margin-top:10px;
font-size: 14px;
line-height: 20px;
position: relative;
padding-left:20px;
display: inline;
&.status-normal {
&:before {
content: "";
display: block;
width: 15px;
height: 15px;
border-radius: 50%;
background-color: #05AEA3;
position: absolute;
top:50%;
left:0;
transform: translate(0,-50%);
}
}
&.status-warn{
&:before{
content: "";
display: inline-block;
width: 15px;
height: 15px;
border-radius: 50%;
background-color: #FC6B69;
position: absolute;
top:50%;
left:0;
transform: translate(0,-50%);
}
}
}
}
}
.children-item-lists{
//todo 手动修改
&:before{
content: '';
display: block;
width:40px;
height: 4px;
background-color: $arrowColoe;
position: absolute;
top:50%;
left: -50px;
transform:translateY(-50%);
}
&:after{
content: '';
display: block;
height: 0;
width: 0;
border-left: 10px solid #5ea9df;
border-right: 10px solid transparent;
border-bottom: 10px solid transparent;
border-top: 10px solid transparent;
position: absolute;
top: 50%;
left: -14px;
transform:translateY(-50%);
}
}
}
.pcs-has-children-item-square{
vertical-align: middle;
align-items: center;
background-color: #ffefad;
}
.no-bms-list{
.item-lists{
&:not(:last-child){
margin-right:0;
}
}
}
}
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -39,9 +39,12 @@ export default {
source.push([item.dateMonth,item.chargeEnergy,item.disChargeEnergy])
})
this.chart.setOption({
grid: {
containLabel: true
},
legend: {
left: 'center',
bottom: '10',
bottom: '15',
},
tooltip: {
trigger: 'axis',

View File

@ -39,9 +39,12 @@ export default {
})
this.chart.setOption({
color:['#3C81FF','#FFBE29'],
grid: {
containLabel: true
},
legend: {
left: 'center',
bottom: '10',
bottom: '15',
},
tooltip: {
trigger: 'axis',

View File

@ -39,9 +39,12 @@ export default {
})
this.chart.setOption({
color:['#F86F70'],
grid: {
containLabel: true
},
legend: {
left: 'center',
bottom: '10',
bottom: '15',
},
tooltip: {
trigger: 'axis',

View File

@ -42,9 +42,12 @@ export default {
tooltip: {
trigger: 'item'
},
grid: {
containLabel: true
},
legend: {
left: 'center',
bottom:'10'
bottom: '15',
},
series: [
{

View File

@ -39,9 +39,12 @@ export default {
})
this.chart.setOption({
color:['#FFBE01'],
grid: {
containLabel: true
},
legend: {
left: 'center',
bottom: '10',
bottom: '15',
},
tooltip: {
trigger: 'axis',

View File

@ -3,7 +3,7 @@
<zd-info></zd-info>
<div class="ems-content-container ems-content-container-padding">
<div class="content-title">数据概览</div>
<el-row :gutter="32" style="background:#fff;margin:30px 0;">
<el-row :gutter="15" style="background:#fff;margin:30px 0;">
<el-col :xs="24" :sm="12" :lg="12">
<dlzb-chart ref="dlzbchart"/>
</el-col>
@ -12,7 +12,7 @@
</el-col>
</el-row>
<el-row :gutter="32" style="background:#fff;margin:0;">
<el-row :gutter="15" style="background:#fff;margin:0;">
<el-col :xs="24" :sm="8" :lg="8">
<gjqs-chart ref="gjqsChart"/>
</el-col>

View File

@ -33,13 +33,11 @@
<el-option :label="item" :value="item" v-for="(item,index) in deviceCategoryList" :key="index+'deviceCategoryList'"></el-option>
</el-select>
</el-form-item>
<!-- todo 只有电池簇展示-->
<el-form-item label="上级设备" prop="parentId" v-if="formData.deviceCategory === dccDeviceCategory">
<el-select v-model="formData.parentId" :placeholder="parentDeviceList.length === 0 && !formData.siteId ? '请先选择站点' : '请选择'" :style="{width: '100%'}">
<el-option :label="item.deviceName" :value="item.id" v-for="(item,index) in parentDeviceList" :key="index+'parentDeviceList'" ></el-option>
</el-select>
</el-form-item>
<!--todo tcp设备才展示ip地址端口号-->
<el-form-item label="TCP设备的ip地址" prop="ipAddress" v-if="formData.deviceType === 'TCP'">
<el-input v-model="formData.ipAddress" placeholder="请输入" clearable :style="{width: '100%'}">
</el-input>

View File

@ -33,14 +33,17 @@ export default {
})
this.chart.setOption({
color:['#A796FF','#FFBE01'],
grid: {
top:30,
containLabel: true
},
legend: {
left: 'right',
bottom: '10',
bottom: '15',
},
tooltip: {},
xAxis: { type: 'category' },
yAxis: { },
grid:{top:30},
dataset:{
source
// source:[//格式