30 Commits

Author SHA1 Message Date
29ab53056a 故障告警,搜索栏 告警等级宽度调整 2026-01-29 19:57:10 +08:00
5250db915f Merge branch 'develop' of http://101.43.41.9:13000/xzzn/emsfront into develop 2026-01-28 21:36:14 +08:00
814103c881 统计报表优化 2026-01-28 21:34:58 +08:00
55b7fba021 修改图片 2026-01-27 16:58:50 +08:00
da4ecc4792 修改顺序 2026-01-27 13:45:14 +08:00
498dc117f2 变更图片 2026-01-27 10:43:54 +08:00
4d29de93a1 大数据图片更新 2026-01-26 23:30:01 +08:00
445e9dfc9f 大数据图片改为切换模式 2026-01-26 22:40:57 +08:00
ac1d1ae154 更新workStatus状态枚举 2026-01-25 16:45:33 +08:00
825243e741 电池簇备注 2026-01-25 16:36:23 +08:00
0389ed85f3 Merge branch 'develop' of http://101.43.41.9:13000/xzzn/emsfront into develop 2026-01-25 16:33:00 +08:00
aef94f406a 电池簇、电池堆工作状态更新 2026-01-25 16:30:43 +08:00
95d69fb7b1 簇枚举变更 2026-01-25 16:27:35 +08:00
684002ffc8 簇枚举变更 2026-01-25 15:12:07 +08:00
098dfa05f8 簇枚举变更 2026-01-25 14:34:01 +08:00
d6c9310e50 净置改成静置 2026-01-25 13:54:23 +08:00
142de3102b 大数据图片更新 2026-01-24 21:14:43 +08:00
9b5806a2c0 0或没有返回值隐藏alarmNum的展示 2026-01-24 10:27:43 +08:00
2b6697fa5a pointName改成 dataPointName 2026-01-24 10:02:11 +08:00
3bb859b693 BMS电池簇数据同步 2026-01-23 22:32:12 +08:00
5b3701afd0 BMS总览数据同步 2026-01-23 22:02:02 +08:00
f531075853 电表数据同步 2026-01-23 21:46:02 +08:00
8cb6fbee3e 大数据展示页面 2026-01-23 18:00:14 +08:00
f454b02c99 pcs、bmszl设备工作状态更新 2026-01-23 16:30:20 +08:00
bfe72cf2c3 首页字段、收益表格 2026-01-23 14:18:22 +08:00
fb90d81bb3 站点首页优化 2026-01-22 17:27:03 +08:00
823c0949d0 文案修改,实时运行图表切换站点数据未更新问题修复,电表未知类型 2026-01-21 18:58:37 +08:00
c1c411e48a 用户归属站点 2026-01-21 14:37:39 +08:00
43153a791d 用户归属站点 2026-01-21 14:05:09 +08:00
11111d035b 优化 2026-01-13 16:38:21 +08:00
35 changed files with 1500 additions and 2262 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 MiB

View File

@ -104,6 +104,10 @@
.el-card__header {
background-color: #b64040; //#fc6b69;
}
.work-status {
color: #b64040 !important;;
}
}
//绿色背景颜色标题
@ -111,6 +115,10 @@
.el-card__header {
background-color: #40b6a5; //#05aea3;
}
.work-status {
color: #40b6a5 !important;
}
}
//灰色背景颜色标题
@ -118,6 +126,10 @@
.el-card__header {
background-color: #666666;
}
.work-status {
color: #666666 !important;;
}
}
}

View File

@ -0,0 +1,137 @@
<template>
<el-dialog
:fullscreen="true"
:append-to-body="true"
:visible.sync="show"
:show-close="false"
top="0"
custom-class="big-data-dialog"
>
<div class="swiper-container">
<div class="swiper-icon left-icon" v-show="imgIndex > 0">
<i class="el-icon-d-arrow-left icon" @click="toLeft"></i>
</div>
<div v-show="showRightIcon" class="swiper-icon right-icon">
<i class="el-icon-d-arrow-right icon" @click="toRight"></i>
</div>
<div
class="img-container"
:style="{ transform: 'translateX(' + imgIndex * -100 + 'vw)' }"
>
<img
v-for="index in maxImgNumber"
:key="'swiperImg' + index"
:src="require(`@/assets/images/ems/bigData-${index}.png`)"
alt=""
/>
</div>
</div>
<div class="close-btn" @click="show = false">
<i class="el-icon-close"></i>
</div>
</el-dialog>
</template>
<style lang="scss" scoped>
.close-btn {
position: absolute;
right: 10px;
top: 10px;
font-size: 23px;
line-height: 20px;
color: rgba(217, 242, 255, 1);
cursor: pointer;
}
.swiper-container {
height: 100%;
width: 100%;
overflow: hidden;
position: relative;
.swiper-icon {
color: rgba(217, 242, 255, 1);
position: absolute;
top: 50%;
transform: translateY(-50%);
z-index: 20;
cursor: pointer;
font-size: 30px;
padding: 20px;
background: transparent;
&.left-icon {
left: 20px;
}
&.right-icon {
right: 20px;
}
&:hover {
.icon {
opacity: 1;
}
}
.icon {
transition: all 0.6s;
opacity: 0;
}
}
.img-container {
height: 100%;
transition: all 1s;
display: flex;
flex-direction: row;
z-index: 0;
img {
width: 100vw;
height: 100vh;
display: block;
margin: 0;
flex-shrink: 0;
}
}
}
</style>
<style lang="scss">
.big-data-dialog {
.el-dialog__header {
display: none;
}
.el-dialog__body {
padding: 0;
margin: 0;
position: relative;
}
}
</style>
<script>
export default {
data() {
return {
show: false,
imgIndex: 0,
maxImgNumber: 3,
};
},
computed: {
showRightIcon() {
return this.imgIndex < this.maxImgNumber - 1;
},
},
watch: {
show: {
handler(newValue) {
if (!newValue) this.imgIndex = 0;
},
immediate: true,
},
},
methods: {
toLeft() {
if (this.imgIndex === 0) return;
this.imgIndex -= 1;
},
toRight() {
if (this.imgIndex >= this.maxImgNumber - 1) return;
this.imgIndex += 1;
},
},
};
</script>

View File

@ -1,36 +1,68 @@
<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>
<div class="time-range">
<el-date-picker
v-model="dateRange"
:class="miniTimePicker ? 'mini-date-picker' : ''"
type="daterange"
range-separator=""
start-placeholder="开始时间"
value-format="yyyy-MM-dd"
:clearable="false"
:picker-options="pickerOptions"
end-placeholder="结束时间">
</el-date-picker>
<template v-if="!showIcon">
<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>
</template>
<template v-else>
<el-button class="btn-icon" icon="el-icon-refresh-right" circle size="mini" style="margin-left: 8px;"
:loading="loading"
@click="reset"></el-button>
<el-button class="btn-icon" type="primary" size="mini" icon="el-icon-search" circle :loading="loading"
@click="search"></el-button>
<el-button class="btn-icon" type="primary" size="mini" icon="el-icon-d-arrow-left" circle :loading="loading"
@click="timeLine('before')"></el-button>
<el-button class="btn-icon" type="primary" size="mini" icon="el-icon-d-arrow-right" circle :loading="loading"
@click="timeLine('next')"
:disabled="disabledNextBtn"></el-button>
</template>
</div>
</template>
<script>
import {formatDate} from '@/filters/ems'
export default {
computed:{
disabledNextBtn(){
props: {
showIcon: {
type: Boolean,
required: false,
default: false
},
miniTimePicker: {
type: Boolean,
required: false,
default: false
}
},
computed: {
disabledNextBtn() {
return new Date(this.dateRange[1]) >= new Date(this.defaultDateRange[1])
}
},
data() {
return {
loading:false,
dateRange:[],
defaultDateRange:[],
pickerOptions:{
loading: false,
dateRange: [],
defaultDateRange: [],
pickerOptions: {
disabledDate(time) {
return time.getTime() > Date.now();
},
@ -38,64 +70,81 @@ export default {
}
},
methods: {
init(today=false){
const now = new Date(),formatNow = formatDate(now);
const weekAgo = formatDate(today ? new Date(now.getTime()) : new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000))
this.dateRange = [weekAgo, formatNow];
this.defaultDateRange=[weekAgo, formatNow];
this.$emit('updateDate',this.dateRange)
init(today = false) {
const now = new Date(), formatNow = formatDate(now);
const weekAgo = formatDate(today ? new Date(now.getTime()) : 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
showBtnLoading(status) {
this.loading = status
},
resetDate(){
resetDate() {
this.dateRange = this.defaultDateRange
},
//重置 设置时间范围为初始化时间段
reset(){
this.resetDate()
this.$emit('reset')
this.$emit('updateDate',this.dateRange)
reset() {
this.resetDate()
this.$emit('reset')
this.$emit('updateDate', this.dateRange)
},
// 搜索
search(){
this.$emit('updateDate',this.dateRange)
search() {
this.$emit('updateDate', this.dateRange)
},
timeLine(type){
if(!this.dateRange || !this.dateRange[0] || !this.dateRange[1]) return
const nowStartTimes = new Date(this.dateRange[0]).getTime(),nowEndTimes = new Date(this.dateRange[1]).getTime(),maxTime = new Date(this.defaultDateRange[1]).getTime()
timeLine(type) {
if (!this.dateRange || !this.dateRange[0] || !this.dateRange[1]) return
const nowStartTimes = new Date(this.dateRange[0]).getTime(), nowEndTimes = new Date(this.dateRange[1]).getTime(),
maxTime = new Date(this.defaultDateRange[1]).getTime()
const nowDis = nowEndTimes - nowStartTimes//用户当前选择时间差 可能=0
//baseTime,maxTime 毫秒数
const baseDis = 24 * 60 * 60 * 1000
const baseDis = 24 * 60 * 60 * 1000
const calcDis = nowDis === 0 ? baseDis : nowDis
let start = type === 'before' ? nowStartTimes - calcDis : nowStartTimes + calcDis
if(start>maxTime) start=maxTime
if (start > maxTime) start = maxTime
let end = type === 'before' ? nowEndTimes - calcDis : nowEndTimes + calcDis
if(end>maxTime) end=maxTime
this.dateRange = [formatDate(start),formatDate(end)]
this.$emit('updateDate',this.dateRange)
if (end > maxTime) end = maxTime
this.dateRange = [formatDate(start), formatDate(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;
}
.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: 22px;
}
.el-button--mini {
padding: 3px 10px;
}
// 展示icon的小组件
.btn-icon.el-button--mini {
padding: 3px 8px;
margin-left: 6px;
}
//小宽度时间选择框
.mini-date-picker {
width: 250px !important;
}
}
}
</style>

View File

@ -32,13 +32,13 @@ export default {
attr:'installCapacity'
},{
title:'总充电量(MWh',
title:'总充电量(KWh',
num:'',
color:'#A696FF',
attr:'totalChargedCap'
},{
title:'总放电量(MWh',
title:'总放电量(KWh',
num:'',
color:'#A696FF',
attr:'totalDischargedCap'

View File

@ -1,19 +1,24 @@
<template>
<div class="navbar">
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
<hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container"
@toggleClick="toggleSideBar"/>
<breadcrumb v-if="!topNav" id="breadcrumb-container" class="breadcrumb-container" />
<top-nav v-if="topNav" id="topmenu-container" class="topmenu-container" />
<breadcrumb v-if="!topNav" id="breadcrumb-container" class="breadcrumb-container"/>
<top-nav v-if="topNav" id="topmenu-container" class="topmenu-container"/>
<div class="right-menu">
<template v-if="device!=='mobile'">
<search id="header-search" class="right-menu-item" />
<div class="big-data-container">
<i class="el-icon-s-marketing big-data-icon" @click.stop="showBigDataImg"></i>
</div>
<search id="header-search" class="right-menu-item"/>
<screenfull id="screenfull" class="right-menu-item hover-effect" />
<screenfull id="screenfull" class="right-menu-item hover-effect"/>
<el-tooltip content="布局大小" effect="dark" placement="bottom">
<size-select id="size-select" class="right-menu-item hover-effect" />
<size-select id="size-select" class="right-menu-item hover-effect"/>
</el-tooltip>
</template>
@ -32,22 +37,23 @@
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<div class="right-menu-item hover-effect setting" @click="setLayout" v-if="setting">
<svg-icon icon-class="more-up" />
<svg-icon icon-class="more-up"/>
</div>
</div>
<BigDataPopup ref="bigDataPopup"/>
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import {mapGetters} from 'vuex'
import Breadcrumb from '@/components/Breadcrumb'
import TopNav from '@/components/TopNav'
import Hamburger from '@/components/Hamburger'
import Screenfull from '@/components/Screenfull'
import SizeSelect from '@/components/SizeSelect'
import Search from '@/components/HeaderSearch'
import BigDataPopup from '@/components/BigDataPopup'
export default {
emits: ['setLayout'],
@ -57,7 +63,8 @@ export default {
Hamburger,
Screenfull,
SizeSelect,
Search
Search,
BigDataPopup
},
computed: {
...mapGetters([
@ -78,6 +85,9 @@ export default {
}
},
methods: {
showBigDataImg() {
this.$refs.bigDataPopup.show = true
},
toggleSideBar() {
this.$store.dispatch('app/toggleSideBar')
},
@ -93,7 +103,8 @@ export default {
this.$store.dispatch('LogOut').then(() => {
location.href = '/index'
})
}).catch(() => {})
}).catch(() => {
})
}
}
}
@ -105,7 +116,7 @@ export default {
overflow: hidden;
position: relative;
background: #fff;
box-shadow: 0 1px 4px rgba(0,21,41,.08);
box-shadow: 0 1px 4px rgba(0, 21, 41, .08);
.hamburger-container {
line-height: 46px;
@ -113,7 +124,7 @@ export default {
float: left;
cursor: pointer;
transition: background .3s;
-webkit-tap-highlight-color:transparent;
-webkit-tap-highlight-color: transparent;
&:hover {
background: rgba(0, 0, 0, .025)
@ -139,6 +150,17 @@ export default {
height: 100%;
line-height: 50px;
.big-data-container {
display: inline-block;
padding: 0 8px;
height: 100%;
font-size: 24px;
color: #5a5e66;
vertical-align: text-bottom;
cursor: pointer;
}
&:focus {
outline: none;
}
@ -177,7 +199,7 @@ export default {
border-radius: 50%;
}
.user-nickname{
.user-nickname {
position: relative;
bottom: 10px;
font-size: 14px;

View File

@ -193,7 +193,7 @@ export const dzjk = [
component: () => import('@/views/ems/dzjk/tjbb/gltj/index.vue'),
name: 'DzjkTjbbGltj',
meta: {
title: '概率统计',
title: '运行统计',
breadcrumb: false,
activeMenu: '/dzjk',
activeSecondMenuName: 'DzjkTjbb'

View File

@ -5,7 +5,17 @@ const ems = {
dzjkAlarmLighting: false,//单站监控 告警统计红点标志
zdList: [],
zdDeviceCategoryOptions: {},//站点各个站点包含的设备种类 {021_DDS_01:["BATTERY","CLUSTER","STACK", "DH", "AMMETER", "PCS", "XF"],021_DDS_02:[]...}
workStatusOptions: {'0': '运行', '1': '机', '2': '故障'},//工作状态
CLUSTERWorkStatusOptions: {'0': '静置', '1': '充电', '2': '放电', '3': '待机', '5': '运行', '9': "故障"},//电池簇工作状态
PCSWorkStatusOptions: {'0': '运行', '1': '停机', '2': '故障', '3': '待机', '4': '充电', '5': '放电'},//PCS工作状态
STACKWorkStatusOptions: {
"0": "静置",
"1": "充电",
"2": "放电",
"3": "浮充",
'4': '待机',
'5': '运行',
'9': "故障"
},//STACKBMS总览工作状态
deviceStatusOptions: {'0': '离线', '1': '在线'},//设备状态
gridStatusOptions: {'0': '并网', '1': '未并网'},//并网状态
controlModeOptions: {'0': '远程', '1': '本地'},//控制模式

View File

@ -1,27 +1,30 @@
<template>
<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-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 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="告警等级">
<el-select v-model="search.alarmLevel" clearable placeholder="请选择" :loading="loading" loading-text="正在加载数据">
<el-option :label="value" :value="key" v-for="(value,key) in $store.state.ems.alarmLevelOptions" :key="key+'alarmLevelOptions'"></el-option>
<el-select v-model="search.alarmLevel" clearable placeholder="请选择" :loading="loading"
loading-text="正在加载数据" style="width: 130px">
<el-option :label="value" :value="key" v-for="(value,key) in $store.state.ems.alarmLevelOptions"
:key="key+'alarmLevelOptions'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="时间选择">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator=""
start-placeholder="开始时间"
:picker-options="pickerOptions"
:default-value="defaultDateRange"
end-placeholder="结束时间">
v-model="dateRange"
type="daterange"
range-separator=""
start-placeholder="开始时间"
:picker-options="pickerOptions"
:default-value="defaultDateRange"
end-placeholder="结束时间">
</el-date-picker>
</el-form-item>
<el-form-item>
@ -36,7 +39,9 @@
<el-row style="">
<el-col :xs="24" :sm="24" :lg="24">
<el-button-group class="ems-btns-group">
<el-button v-for="(item,index) in btnList" :key="index+'dtdcBtns'" :class="{'activeBtn' : activeBtn === item.id}" @click="changeDataType(item.id)">{{item.name}}</el-button>
<el-button v-for="(item,index) in btnList" :key="index+'dtdcBtns'"
:class="{'activeBtn' : activeBtn === item.id}" @click="changeDataType(item.id)">{{ item.name }}
</el-button>
</el-button-group>
</el-col>
</el-row>
@ -47,64 +52,69 @@
stripe
max-height="500"
style="width: 100%;margin-top:25px;">
<el-table-column
<el-table-column
prop="deviceName"
label="设备名称">
</el-table-column>
<el-table-column
</el-table-column>
<el-table-column
label="告警等级"
>
<template slot-scope="scope">
<span>{{$store.state.ems.alarmLevelOptions[scope.row.alarmLevel]}}</span>
</template>
</el-table-column>
<el-table-column
>
<template slot-scope="scope">
<span>{{ $store.state.ems.alarmLevelOptions[scope.row.alarmLevel] }}</span>
</template>
</el-table-column>
<el-table-column
prop="alarmContent"
show-overflow-tooltip
label="告警内容">
</el-table-column>
<el-table-column
</el-table-column>
<el-table-column
prop="alarmStartTime"
label="告警发生时间">
<template slot-scope="scope">
<span>{{formatDate(scope.row.alarmStartTime,true)}}</span>
</template>
</el-table-column>
<el-table-column
<template slot-scope="scope">
<span>{{ formatDate(scope.row.alarmStartTime, true) }}</span>
</template>
</el-table-column>
<el-table-column
prop="alarmEndTime"
label="告警结束时间">
<template slot-scope="scope">
<span>{{formatDate(scope.row.alarmEndTime,true)}}</span>
</template>
</el-table-column>
<el-table-column
<template slot-scope="scope">
<span>{{ formatDate(scope.row.alarmEndTime, true) }}</span>
</template>
</el-table-column>
<el-table-column
label="状态">
<template slot-scope="scope">
<span :class="['0','2'].includes(scope.row.status) ? 'warning-status' : ''">{{$store.state.ems.alarmStatusOptions[scope.row.status]}}</span>
</template>
</el-table-column>
<el-table-column
<template slot-scope="scope">
<span
:class="['0','2'].includes(scope.row.status) ? 'warning-status' : ''">{{
$store.state.ems.alarmStatusOptions[scope.row.status]
}}</span>
</template>
</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="createTicket(scope.row.id)">生成工单</el-button>
</template>
</el-table-column>
</el-table>
>
<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="createTicket(scope.row.id)">生成工单</el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
v-show="tableData.length>0"
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
: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"
v-show="tableData.length>0"
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
: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>
@ -113,113 +123,127 @@
<script>
import {getAlarmDetailList,createTicketNo} from'@/api/ems/dzjk'
import {getDeviceList} from'@/api/ems/site'
import {createTicketNo, getAlarmDetailList} from '@/api/ems/dzjk'
import {getDeviceList} from '@/api/ems/site'
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import { formatDate } from '@/filters/ems'
import {formatDate} from '@/filters/ems'
export default {
name:'DzjkGzgj',
mixins:[getQuerySiteId],
name: 'DzjkGzgj',
mixins: [getQuerySiteId],
data() {
return {
loading:false,
btnList:[
{name:'未处理告警',id:'today'},
{name:'历史告警',id:'history'},
loading: false,
btnList: [
{name: '未处理告警', id: 'today'},
{name: '历史告警', id: 'history'},
],
deviceOptions:[],//设备列表
pickerOptions:{
deviceOptions: [],//设备列表
pickerOptions: {
disabledDate(time) {
return time.getTime() > Date.now();
},
},
defaultDateRange:[],//默认展示的时间
dateRange:[],//alarmStartTime,alarmEndTime
activeBtn:'today',
search:{deviceId:'',alarmLevel:''},
defaultDateRange: [],//默认展示的时间
dateRange: [],//alarmStartTime,alarmEndTime
activeBtn: 'today',
search: {deviceId: '', alarmLevel: ''},
// 表格、分页
tableData:[],
pageSize:10,//分页栏当前每个数据总数
pageNum:1,//分页栏当前页数
totalSize:0,//table表格数据总数
tableData: [],
pageSize: 10,//分页栏当前每个数据总数
pageNum: 1,//分页栏当前页数
totalSize: 0,//table表格数据总数
}
},
methods:{
methods: {
formatDate,
toTicket(){
this.$router.push({path:'/ticket'})
toTicket() {
this.$router.push({path: '/ticket'})
},
//生成工单
createTicket(id){
createTicket(id) {
this.loading = true
createTicketNo({id}).then(response=>{
createTicketNo({id}).then(response => {
response?.data && this.toTicket()
}).finally(()=>{this.loading = false})
}).finally(() => {
this.loading = false
})
},
// 判断是否是同一天
isSameDay(day1, day2) {
const date1 = new Date(day1),date2 = new Date(day2)
const date1 = new Date(day1), date2 = new Date(day2)
return date1.getFullYear() === date2.getFullYear() &&
date1.getMonth() === date2.getMonth() &&
date1.getDate() === date2.getDate();
date1.getMonth() === date2.getMonth() &&
date1.getDate() === date2.getDate();
},
// 分页
handleSizeChange(val) {
this.pageSize = val;
this.$nextTick(()=>{
this.$nextTick(() => {
this.getData()
})
},
handleCurrentChange(val) {
this.pageNum = val
this.$nextTick(()=>{
this.$nextTick(() => {
this.getData()
})
},
// 搜索
onSearch(){
this.pageNum =1//每次搜索从1开始搜索
onSearch() {
this.pageNum = 1//每次搜索从1开始搜索
this.getData()
},
// 重置
onReset(){
this.search={deviceId:'',alarmLevel:''}
this.dateRange=[]
this.pageNum =1//每次搜索从1开始搜索
onReset() {
this.search = {deviceId: '', alarmLevel: ''}
this.dateRange = []
this.pageNum = 1//每次搜索从1开始搜索
this.getData()
},
// 切换今日、历史告警
changeDataType(id){
if(id !== this.activeBtn){
changeDataType(id) {
if (id !== this.activeBtn) {
console.log('点击了不同的菜单,更新数据')
this.activeBtn=id;
this.activeBtn = id;
this.getData()
}
},
// 获取数据
getData(){
this.$store.dispatch('getSiteAlarmNum',this.siteId)
this.loading=true
const {deviceId,alarmLevel} = this.search
const {siteId,pageNum,pageSize,activeBtn} =this
const [alarmStartTime='',alarmEndTime='']=(this.dateRange || [])
getData() {
this.$store.dispatch('getSiteAlarmNum', this.siteId)
this.loading = true
const {deviceId, alarmLevel} = this.search
const {siteId, pageNum, pageSize, activeBtn} = this
const [alarmStartTime = '', alarmEndTime = ''] = (this.dateRange || [])
let status = activeBtn === 'today' ? '0' : '1,2'
getAlarmDetailList({status,deviceId,alarmLevel,siteId,pageSize,pageNum,alarmStartTime:formatDate(alarmStartTime),alarmEndTime:formatDate(alarmEndTime)}).then(response => {
this.tableData=response?.rows || [];
getAlarmDetailList({
status,
deviceId,
alarmLevel,
siteId,
pageSize,
pageNum,
alarmStartTime: formatDate(alarmStartTime),
alarmEndTime: formatDate(alarmEndTime)
}).then(response => {
this.tableData = response?.rows || [];
this.totalSize = response?.total || 0
}).finally(() => {this.loading=false})
}).finally(() => {
this.loading = false
})
},
getDeviceOptions(){
getDeviceOptions() {
getDeviceList(this.siteId).then(response => {
this.deviceOptions = JSON.parse(JSON.stringify(response?.data || []))
})
},
init(){
init() {
this.getDeviceOptions()
this.onReset()
},
},
mounted(){
mounted() {
const now = new Date();
const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1, 1);
this.defaultDateRange = [lastMonth, now];

View File

@ -1,30 +1,29 @@
<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>
<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" :showIcon="true" :mini-time-picker="true" @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 { getPointData } from '@/api/ems/dzjk'
import {getPointData} from '@/api/ems/dzjk'
import intervalUpdate from "@/mixins/ems/intervalUpdate";
export default {
mixins: [resize,intervalUpdate],
mixins: [resize, intervalUpdate],
components: {DateRangeSelect},
data() {
return {
chart: null,
timeRange:[],
siteId:'',
isInit:true
timeRange: [],
siteId: '',
isInit: true
}
},
mounted() {
@ -41,23 +40,23 @@ export default {
},
methods: {
// 更新时间范围 重置图表
updateDate(data){
this.timeRange=data
updateDate(data) {
this.timeRange = data
!this.isInit && this.getGVQXData()
this.isInit = false
},
getGVQXData(){
getGVQXData() {
this.showLoading()
const {siteId,timeRange}=this
getPointData({siteId,startDate:timeRange[0],endDate:timeRange[1]}).then(response => {
const {siteId, timeRange} = this
getPointData({siteId, startDate: timeRange[0], endDate: timeRange[1]}).then(response => {
this.setOption(response?.data || [])
}).finally(()=>this.hideLoading())
}).finally(() => this.hideLoading())
},
init(siteId){
init(siteId) {
//初始化 清空数据
this.siteId = siteId
this.isInit = true
this.timeRange=[]
this.timeRange = []
this.$refs.dateRangeSelect.init(true)
this.getGVQXData()
this.updateInterval(this.getGVQXData)
@ -65,17 +64,17 @@ export default {
initChart() {
this.chart = echarts.init(document.querySelector('#activeChart'))
},
showLoading(){
showLoading() {
this.chart && this.chart.showLoading()
},
hideLoading(){
hideLoading() {
this.chart && this.chart.hideLoading()
},
setOption(data) {
const source = [['日期','电网功率','负载功率','储能功率','光伏功率','soc平均值','soh平均值','电池平均温度平均值']]
console.log('source.slice(1)',source[0].slice(1))
this.chart && data.forEach((item)=>{
source.push([item.statisDate,item.gridPower,item.loadPower,item.storagePower,item.pvPower,item.avgSoc,item.avgSoh,item.avgTemp])
const source = [['日期', '电网功率', '负载功率', '储能功率', '光伏功率', 'soc平均值', 'soh平均值', '电池平均温度平均值']]
console.log('source.slice(1)', source[0].slice(1))
this.chart && data.forEach((item) => {
source.push([item.statisDate, item.gridPower, item.loadPower, item.storagePower, item.pvPower, item.avgSoc, item.avgSoh, item.avgTemp])
})
this.chart.setOption({
grid: {
@ -91,8 +90,8 @@ export default {
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
}
},
textStyle:{
color:"#333333",
textStyle: {
color: "#333333",
},
xAxis: {
type: 'category',
@ -105,11 +104,17 @@ export default {
type: 'value',
},
],
dataset:{source},
series: source[0].slice(1).map((item,index)=>{
dataset: {source},
series: source[0].slice(1).map((item, index) => {
return {
type: 'line',
yAxisIndex:index<=4 ? 0 : 1
type: 'line',//index === 5 ? 'bar' : 'line',
showSymbol: false,
symbolSize: 2,
smooth: true,
areaStyle: {
opacity: 0.5,
},
yAxisIndex: index <= 4 ? 0 : 1
}
})
})

View File

@ -1,12 +1,11 @@
<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>
<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" :showIcon="true" :mini-time-picker="true" @updateDate="updateDate"/>
</div>
<div style="height: 310px" id="weekChart"></div>
</el-card>
</template>
<script>
@ -14,14 +13,15 @@ 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:'',
timeRange: [],
siteId: '',
}
},
mounted() {
@ -38,41 +38,40 @@ export default {
},
methods: {
// 更新时间范围 重置图表
updateDate(data){
this.timeRange=data
updateDate(data) {
this.timeRange = data
this.getWeekKData()
},
getWeekKData(){
getWeekKData() {
this.showLoading()
const {siteId,timeRange}=this
this.hideLoading()
getSevenChargeData({siteId,startDate:timeRange[0],endDate:timeRange[1]}).then(response => {
const {siteId, timeRange} = this
getSevenChargeData({siteId, startDate: timeRange[0], endDate: timeRange[1]}).then(response => {
this.setOption(response?.data || [])
}).finally(()=>this.hideLoading())
}).finally(() => this.hideLoading())
},
init(siteId){
init(siteId) {
//初始化 清空数据
this.siteId = siteId
this.timeRange=[]
this.deviceId=''
this.timeRange = []
this.deviceId = ''
this.$refs.dateRangeSelect.init()
},
initChart() {
this.chart = echarts.init(document.querySelector('#weekChart'))
},
showLoading(){
showLoading() {
this.chart && this.chart.showLoading()
},
hideLoading(){
hideLoading() {
this.chart && this.chart.hideLoading()
},
setOption(data,unit) {
const source = [['日期','充电量','放电量']]
data.forEach(item=>{
source.push([item.ammeterDate, item.chargedCap,item.disChargedCap])
setOption(data, unit) {
const source = [['日期', '充电量', '放电量']]
data.forEach(item => {
source.push([item.ammeterDate, item.chargedCap, item.disChargedCap])
})
this.chart && this.chart.setOption({
color:['#4472c4','#70ad47'],//所有充放电颜色保持统一
color: ['#4472c4', '#70ad47'],//所有充放电颜色保持统一
tooltip: {
trigger: 'axis',
axisPointer: { // 坐标轴指示器,坐标轴触发有效
@ -88,29 +87,29 @@ export default {
},
xAxis: {
type: 'category',
name:unit,
nameLocation:'center'
name: unit,
nameLocation: 'center'
},
yAxis: [{
type: 'value',
name:'充电量/放电量kWh',
name: '充电量/放电量kWh',
axisLine: {
lineStyle:{
lineStyle: {
color: '#333333',
},
onZero:false
onZero: false
}
}],
dataset:{
dataset: {
source
},
series: [
{
yAxisIndex:0,
yAxisIndex: 0,
type: 'bar',
},
{
yAxisIndex:0,
yAxisIndex: 0,
type: 'bar',
},
]

View File

@ -1,130 +1,164 @@
<template>
<div 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-col :xs="24" :sm="24" :lg="5">
<!-- 站点信息-->
<el-card
shadow="always"
class="common-card-container common-card-container-body-no-padding"
shadow="always"
class="common-card-container common-card-container-body-no-padding"
>
<div slot="header">
<span class="card-title">站点信息</span>
<div class="alarm-msg" v-if="tableData.length > 0" @click="toAlarm">
<i class="el-icon-message-solid"></i> 设备告警
</div>
</div>
<div
style="box-sizing: border-box; height: 250px; padding: 20px 15px"
style="box-sizing: border-box; height: 218px; 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">
<!-- 地址运行时间-->
<div class="site-info site-info-address">
<div class="title">
<i class="el-icon-location"></i>
</div>
<div class="value">{{ info.siteAddress }}</div>
</div>
<div class="site-info">
<div class="title">
<i class="el-icon-date"></i>
</div>
<div class="value">{{ info.runningTime || '-' }}</div>
</div>
<!-- 装机功率容量 -->
<el-row :gutter="10" style="margin-top:20px;">
<el-col
:span="12"
v-for="(item, index) in sjglData"
:key="index + 'sjglData'"
class="sjgl-data"
:span="12"
class="sjgl-col power-col"
>
<div class="sjgl-title">{{ item.title }}</div>
<div class="sjgl-value">
{{ runningInfo[item.attr] | formatNumber }}
<div class="sjgl-wrapper">
<div class="sjgl-title">装机功率(MW)</div>
<div class="sjgl-value">
{{ info.installPower | formatNumber }}
</div>
</div>
</el-col>
<el-col
:span="12"
class="sjgl-col power-col"
>
<div class="sjgl-wrapper">
<div class="sjgl-title">装机容量(MW)</div>
<div class="sjgl-value">
{{ info.installCapacity | formatNumber }}
</div>
</div>
</el-col>
</el-row>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :lg="10">
<cl-info :info="runningInfo.strategyTempInfo" />
<!-- 总累计运行数据-->
<el-col :xs="24" :sm="24" :lg="19">
<el-card
shadow="always"
class="common-card-container common-card-container-body-no-padding"
>
<div slot="header">
<span class="card-title">总累计运行数据</span>
<div class="total-count">
<span class="title">总收入</span>
<span class="value">{{ runningInfo.totalRevenue | formatNumber }}</span>
<span class="unit"></span>
</div>
</div>
<div
style="box-sizing: border-box; height: 218px; padding: 20px 15px"
>
<el-row :gutter="10">
<el-col
:span="6"
v-for="(item, index) in sjglData"
:key="index + 'sjglData'"
class="sjgl-col"
>
<div class="sjgl-wrapper">
<div class="sjgl-title">{{ item.title }}</div>
<div class="sjgl-value" :style="{color:item.color}">
{{ runningInfo[item.attr] | formatNumber }}
</div>
</div>
</el-col>
</el-row>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :lg="24">
<week-chart ref="weekChart" />
<el-col :xs="24" :sm="24" :lg="12">
<week-chart ref="weekChart"/>
</el-col>
<el-col :xs="24" :sm="24" :lg="24">
<active-chart ref="activeChart" />
<el-col :xs="24" :sm="24" :lg="12">
<active-chart ref="activeChart"/>
</el-col>
</el-row>
</div>
</template>
<script>
import { getSingleSiteBaseInfo } from "@/api/ems/zddt";
import { getDzjkHomeView } from "@/api/ems/dzjk";
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";
import intervalUpdate from "@/mixins/ems/intervalUpdate";
export default {
name: "DzjkSbjkHome",
components: { WeekChart, ActiveChart, AlarmTable, ClInfo },
components: {WeekChart, ActiveChart, AlarmTable, ClInfo},
mixins: [getQuerySiteId, intervalUpdate],
data() {
return {
loading: false,
singleZdInfo: [
{
title: "电站位置",
attr: "siteAddress",
},
{
title: "投运时间",
attr: "runningTime",
},
{
title: "装机功率(MW)",
attr: "installPower",
},
{
title: "装机容量(MW)",
attr: "installCapacity",
},
],
sjglData: [
{
title: "今日充电量kWh",
attr: "dayChargedCap",
color: '#4472c4'
},
{
title: "今日放电量kWh",
attr: "dayDisChargedCap",
color: '#70ad47'
},
{
title: "总充电量kWh",
attr: "totalChargedCap",
color: '#4472c4'
},
{
title: "今日实时收入(元)",
attr: "dayRevenue",
color: '#f67438'
},
{
title: "昨日充电量kWh",
attr: "yesterdayChargedCap",
color: '#4472c4'
},
{
title: "昨日放电量kWh",
attr: "yesterdayDisChargedCap",
color: '#70ad47'
},
{
title: "总放电量kWh",
attr: "totalDischargedCap",
color: '#70ad47'
},
{
title: "收入(元)",
attr: "totalRevenue",
},
{
title: "当日实时收入(元)",
attr: "dayRevenue",
title: "昨日实时收入(元)",
attr: "yesterdayRevenue",
color: '#f67438'
},
],
info: {}, //基本信息
@ -133,14 +167,13 @@ export default {
},
computed: {
tableData() {
console.log(
"this.runningInfo?.siteMonitorHomeAlarmVo ",
this.runningInfo?.siteMonitorHomeAlarmVo
);
return this.runningInfo?.siteMonitorHomeAlarmVo || [];
},
},
methods: {
toAlarm() {
this.$router.push({path: "/dzjk/gzgj", query: this.$route.query});
},
getBaseInfo() {
return getSingleSiteBaseInfo(this.siteId).then((response) => {
this.info = response?.data || {};
@ -170,6 +203,73 @@ export default {
</script>
<style scoped lang="scss">
//设备告警
.alarm-msg {
background: #ff4949;
padding: 2px 5px;
font-size: 10px;
font-weight: bolder;
border-radius: 3px;
line-height: 20px;
cursor: pointer;
color: #fff;
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
}
//基本信息-地址 运行️时间
.site-info {
display: flex;
font-size: 12px;
line-height: 20px;
margin-bottom: 10px;
align-items: center;
&.site-info-address {
height: 40px;
}
.title {
color: #1791ff;
font-size: 18px;
line-height: 20px;
margin-right: 7px;
}
.value {
color: #000;
font-size: 12px;
max-height: 40px;
overflow: hidden;
}
}
//总收入
.total-count {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
font-size: 12px;
font-weight: bolder;
color: #333;
line-height: 14px;
.unit {
font-style: italic;
}
.value {
font-size: 22px;
font-weight: bolder;
color: #ed2f1d;
font-style: italic;
padding: 0 5px;
}
}
.row-container {
& > .el-col {
margin-bottom: 20px;
@ -177,25 +277,47 @@ export default {
}
//数据概览
.sjgl-data {
text-align: center;
&:nth-child(1),
.sjgl-col {
.sjgl-wrapper {
text-align: left;
padding: 15px 20px;
background-color: #f2f7fb;
}
&.power-col {
.sjgl-wrapper {
padding: 10px;
.sjgl-value {
color: #c44444;
}
}
}
&:nth-child(4),
&:nth-child(2),
&:nth-child(3),
&:nth-child(4) {
margin-bottom: 25px;
margin-bottom: 10px;
}
.sjgl-title {
color: #666666;
color: #717171;
line-height: 14px;
font-weight: bold;
}
.sjgl-value {
color: rgba(51, 51, 51, 1);
font-size: 26px;
font-size: 22px;
line-height: 26px;
font-weight: 500;
font-weight: bolder;
font-style: italic;
margin-top: 14px;
word-wrap: break-word;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
</style>
@ -203,10 +325,12 @@ export default {
<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;
}

View File

@ -3,11 +3,7 @@
<div v-for="(baseInfo,index) in baseInfoList" :key="index+'bmsdccContainer'" style="margin-bottom:25px;">
<el-card shadow="always"
class="sbjk-card-container common-card-container-body-no-padding common-card-container-no-title-bg"
:class="{
'timing-card-container':!['0','2'].includes(baseInfo.workStatus),
'warning-card-container':baseInfo.workStatus === '2',
'running-card-container':baseInfo.workStatus === '0'
}">
:class="handleCardClass(baseInfo)">
<div slot="header">
<span
class="large-title">{{
@ -20,7 +16,7 @@
<el-button type="primary" round size="small" style="margin-right:20px;"
@click="pointDetail(baseInfo,'point')">详细
</el-button>
<el-badge :value="baseInfo.alarmNum || 0" class="item">
<el-badge :hidden="!baseInfo.alarmNum" :value="baseInfo.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(baseInfo,'alarmPoint')"
@ -30,16 +26,16 @@
</div>
<div class="descriptions-main">
<el-descriptions direction="vertical" :column="3" :colon="false">
<el-descriptions-item labelClassName="descriptions-label"
:contentClassName="`descriptions-direction ${baseInfo.workStatus === '0' ? 'save' :'danger'}`"
:span="1" label="工作状态">
{{ $store.state.ems.workStatusOptions[baseInfo.workStatus] }}
<el-descriptions-item
contentClassName="descriptions-direction work-status"
:span="1" label="工作状态">
{{ CLUSTERWorkStatusOptions[baseInfo.workStatus] }}
</el-descriptions-item>
<el-descriptions-item labelClassName="descriptions-label" contentClassName="descriptions-direction"
<el-descriptions-item contentClassName="descriptions-direction"
:span="1" label="与PCS通信">
{{ $store.state.ems.communicationStatusOptions[baseInfo.pcsCommunicationStatus] }}
</el-descriptions-item>
<el-descriptions-item labelClassName="descriptions-label" contentClassName="descriptions-direction"
<el-descriptions-item contentClassName="descriptions-direction"
:span="1" label="与EMS通信">
{{ $store.state.ems.communicationStatusOptions[baseInfo.emsCommunicationStatus] }}
</el-descriptions-item>
@ -132,11 +128,17 @@ import PointTable from "@/views/ems/site/sblb/PointTable.vue";
import {getBMSBatteryCluster} from '@/api/ems/dzjk'
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import intervalUpdate from "@/mixins/ems/intervalUpdate";
import {mapState} from "vuex";
export default {
name: 'DzjkSbjkBmsdcc',
mixins: [getQuerySiteId, intervalUpdate],
components: {PointTable, pointChart},
computed: {
...mapState({
CLUSTERWorkStatusOptions: state => state?.ems?.CLUSTERWorkStatusOptions || {},
})
},
data() {
return {
loading: false,
@ -171,6 +173,10 @@ export default {
}
},
methods: {
handleCardClass(item) {
const {workStatus = ''} = item
return !(Object.keys(this.CLUSTERWorkStatusOptions).includes(item.workStatus)) ? "timing-card-container" : workStatus === '9' ? 'warning-card-container' : 'running-card-container'
},
// 查看设备电位表格
pointDetail(row, dataType) {
const {siteId, deviceId} = row

View File

@ -1,12 +1,10 @@
<template>
<div v-loading="loading">
<div v-for="(baseInfo,index) in baseInfoList" :key="index+'bmszlContainer'" style="margin-bottom:25px;">
<el-card :class="{
'timing-card-container':!['0','2'].includes(baseInfo.workStatus),
'warning-card-container':baseInfo.workStatus === '2',
'running-card-container':baseInfo.workStatus === '0'
}" class="sbjk-card-container common-card-container-body-no-padding common-card-container-no-title-bg"
shadow="always">
<el-card
:class="handleCardClass(baseInfo)"
class="sbjk-card-container common-card-container-body-no-padding common-card-container-no-title-bg"
shadow="always">
<div slot="header">
<span class="large-title">{{ baseInfo.deviceName }}</span>
<div class="info">
@ -16,7 +14,7 @@
<el-button type="primary" round size="small" style="margin-right:20px;"
@click="pointDetail(baseInfo,'point')">详细
</el-button>
<el-badge :value="baseInfo.alarmNum || 0" class="item">
<el-badge :hidden="!baseInfo.alarmNum" :value="baseInfo.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(baseInfo,'alarmPoint')"
@ -27,9 +25,9 @@
<div class="descriptions-main">
<el-descriptions :colon="false" :column="3" direction="vertical">
<el-descriptions-item
:contentClassName="`descriptions-direction ${baseInfo.workStatus === '0' ? 'save' :'danger'}`" :span="1"
contentClassName="descriptions-direction work-status"
label="工作状态" labelClassName="descriptions-label">
{{ $store.state.ems.workStatusOptions[baseInfo.workStatus] }}
{{ STACKWorkStatusOptions[baseInfo.workStatus] }}
</el-descriptions-item>
<el-descriptions-item :span="1" contentClassName="descriptions-direction" label="与PCS通信"
labelClassName="descriptions-label">
@ -164,11 +162,17 @@ import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import intervalUpdate from "@/mixins/ems/intervalUpdate";
import pointChart from "./../PointChart.vue";
import PointTable from "@/views/ems/site/sblb/PointTable.vue";
import {mapState} from "vuex";
export default {
name: 'DzjkSbjkBmszl',
components: {pointChart, PointTable},
mixins: [getQuerySiteId, intervalUpdate],
computed: {
...mapState({
STACKWorkStatusOptions: state => state?.ems?.STACKWorkStatusOptions || {},
})
},
data() {
return {
loading: false,
@ -187,6 +191,11 @@ export default {
}
},
methods: {
handleCardClass(item) {
const {workStatus = ''} = item
return !Object.keys(this.STACKWorkStatusOptions).find(i => i === workStatus) ? "timing-card-container" : workStatus === '9' ? 'warning-card-container' : 'running-card-container'
},
// 查看设备电位表格
pointDetail(row, dataType) {
const {siteId, deviceId} = row

View File

@ -6,7 +6,8 @@
shadow="always"
class="sbjk-card-container list"
:class="{
'warning-card-container':item.emsCommunicationStatus && item.emsCommunicationStatus !== '0',
'timing-card-container':!['0','2'].includes(item.emsCommunicationStatus),
'warning-card-container':item.emsCommunicationStatus === '2',
'running-card-container':item.emsCommunicationStatus === '0'
}"
>
@ -15,18 +16,16 @@
<div class="info">
<div>
{{
$store.state.ems.communicationStatusOptions[
item.emsCommunicationStatus
]
communicationStatusOptions[item.emsCommunicationStatus] || '-'
}}
</div>
<div>数据更新时间{{ item.dataUpdateTime }}</div>
<div>数据更新时间{{ item.dataUpdateTime || '-' }}</div>
</div>
<div class="alarm">
<el-button type="primary" round size="small" style="margin-right:20px;" @click="pointDetail(item,'point')">
详细
</el-button>
<el-badge :value="item.alarmNum || 0" class="item">
<el-badge :hidden="!item.alarmNum" :value="item.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(item,'alarmPoint')"
@ -35,10 +34,11 @@
</div>
</div>
<el-row class="device-info-row">
<el-col v-for="(tempDataItem,tempDataIndex) in deviceIdTypeMsg[item.deviceId]" :key="tempDataIndex+'dbTempData'"
<el-col v-for="(tempDataItem,tempDataIndex) in (deviceIdTypeMsg[item.deviceId] || otherTypeMsg)"
:key="tempDataIndex+'dbTempData'"
:span="8" class="device-info-col">
<span class="pointer" @click="showChart(tempDataItem.pointName,item.deviceId)">
<span class="left">{{ tempDataItem.name }}</span> <span class="right">{{ item[tempDataItem.attr] }}<span
<span class="left">{{ tempDataItem.name }}</span> <span class="right">{{ item[tempDataItem.attr] || '-' }}<span
v-html="tempDataItem.unit"></span></span>
</span>
</el-col>
@ -56,11 +56,18 @@ import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import {getAmmeterDataList} from "@/api/ems/dzjk";
import intervalUpdate from "@/mixins/ems/intervalUpdate";
import PointTable from "@/views/ems/site/sblb/PointTable.vue";
import {mapState} from "vuex";
export default {
name: "DzjkSbjkDb",
mixins: [getQuerySiteId, intervalUpdate],
components: {PointTable, pointChart},
computed: {
...mapState({
communicationStatusOptions: state => state?.ems?.communicationStatusOptions || {},
})
},
data() {
return {
loading: false,
@ -70,89 +77,125 @@ export default {
{
name: '正向有功电能',
attr: 'forwardActive',
pointName: '正向有功电能'
pointName: '正向有功电能',
unit: 'kWh'
},
{
name: '反向有功电能',
attr: 'reverseActive',
pointName: '反向有功电能'
pointName: '反向有功电能',
unit: 'kWh'
},
{
name: '正向无功电能',
attr: 'forwardReactive',
pointName: '正向无功电能'
pointName: '正向无功电能',
unit: 'kvarh'
},
{
name: '反向无功电能',
attr: 'reverseReactive',
pointName: '反向无功电能'
pointName: '反向无功电能',
unit: 'kvarh'
},
{
name: '有功功率',
attr: 'activePower',
pointName: '总有功功率'
pointName: '总有功功率',
unit: 'kW'
},
{
name: '无功功率',
attr: 'reactivePower',
pointName: '总无功功率'
pointName: '总无功功率',
unit: 'kvar'
}
],
'METE': [
{
name: '正向有功电能',
attr: 'forwardActive',
pointName: '正向有功电能'
pointName: '正向有功电能',
unit: 'kWh'
},
{
name: '反向有功电能',
attr: 'reverseActive',
pointName: '反向有功电能'
pointName: '反向有功电能',
unit: 'kWh'
},
{
name: '正向无功电能',
attr: 'forwardReactive',
pointName: '正向无功电能'
pointName: '正向无功电能',
unit: 'kvarh'
},
{
name: '反向无功电能',
attr: 'reverseReactive',
pointName: '反向无功电能'
pointName: '反向无功电能',
unit: 'kvarh'
},
{
name: '有功功率',
attr: 'activePower',
pointName: '总有功功率'
pointName: '总有功功率',
unit: 'kW'
},
{
name: '无功功率',
attr: 'reactivePower',
pointName: '总无功功率'
pointName: '总无功功率',
unit: 'kvar'
}
],
'METEGF': [
{
name: '有功电能',
attr: 'activeEnergy',
pointName: '有功电能'
pointName: '有功电能',
unit: 'kWh'
},
{
name: '无功电能',
attr: 'reactiveEnergy',
pointName: '无功电能'
pointName: '无功电能',
unit: 'kvarh'
},
{
name: '有功功率',
attr: 'activePower',
pointName: '总有功功率'
pointName: '总有功功率',
unit: 'kW'
},
{
name: '无功功率',
attr: 'reactivePower',
pointName: '总无功功率'
pointName: '总无功功率',
unit: 'kvar'
}
]
}
},
otherTypeMsg: [
{
name: '正向有功电能',
attr: 'forwardActive',
pointName: '正向有功电能',
unit: 'kWh'
},
{
name: '反向有功电能',
attr: 'reverseActive',
pointName: '反向有功电能',
unit: 'kWh'
},
{
name: '有功功率',
attr: 'activePower',
pointName: '总有功功率',
unit: 'kW'
},
]
};
},
methods: {

View File

@ -14,7 +14,7 @@
<el-button type="primary" round size="small" style="margin-right:20px;" @click="pointDetail(item,'point')">
详细
</el-button>
<el-badge :value="item.alarmNum || 0" class="item">
<el-badge :hidden="!item.alarmNum" :value="item.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(item,'alarmPoint')"
@ -26,7 +26,8 @@
<el-col v-for="(tempDataItem,tempDataIndex) in tempData" :key="tempDataIndex+'hdTempData'" :span="12"
class="device-info-col">
<span class="pointer" @click="showChart(tempDataItem.title,item.deviceId)">
<span class="left">{{ tempDataItem.title }}</span> <span class="right">{{ item[tempDataItem.attr] }}<span
<span class="left">{{ tempDataItem.title }}</span> <span
class="right">{{ item[tempDataItem.attr] || '-' }}<span
v-html="tempDataItem.unit"></span></span>
</span>
</el-col>

View File

@ -1,206 +1,5 @@
<template>
<div v-loading="loading" class="ems">
<!-- <div-->
<!-- v-for="(item, index) in list"-->
<!-- :key="index + 'PcsHome'"-->
<!-- style="margin-bottom: 25px"-->
<!-- >-->
<!-- <el-card-->
<!-- :class="{-->
<!-- 'warning-card-container': item.workStatus === '1',-->
<!-- 'timing-card-container': item.workStatus === '2',-->
<!-- 'running-card-container': !['1', '2'].includes(item.workStatus),-->
<!-- }"-->
<!-- class="sbjk-card-container common-card-container-body-no-padding common-card-container-no-title-bg"-->
<!-- shadow="always"-->
<!-- >-->
<!-- &lt;!&ndash; 标题&ndash;&gt;-->
<!-- <div slot="header">-->
<!-- <span class="large-title"-->
<!-- >{{ item.deviceName }}</span-->
<!-- >-->
<!-- <div class="info">-->
<!-- <div>-->
<!-- {{-->
<!-- $store.state.ems.workStatusOptions[item.workStatus]-->
<!-- }}-->
<!-- </div>-->
<!-- <div>数据更新时间{{ item.dataUpdateTime }}</div>-->
<!-- </div>-->
<!-- <div class="alarm">-->
<!-- <el-button type="primary" size="small" style="margin-right:20px;" @click="pointDetail(item,'point')">-->
<!-- 详细-->
<!-- </el-button>-->
<!-- <el-badge :value="item.alarmNum || 0" class="item">-->
<!-- <i-->
<!-- class="el-icon-message-solid alarm-icon"-->
<!-- @click="pointDetail(item,'alarmPoint')"-->
<!-- ></i>-->
<!-- </el-badge>-->
<!-- </div>-->
<!-- </div>-->
<!-- &lt;!&ndash; 工作状态&ndash;&gt;-->
<!-- <div class="descriptions-main">-->
<!-- <el-descriptions :colon="false" :column="5" direction="vertical">-->
<!-- <el-descriptions-item-->
<!-- :contentClassName="`descriptions-direction ${-->
<!-- item.workStatus === '0' ? 'save' : 'danger'-->
<!-- }`"-->
<!-- :span="1"-->
<!-- label="工作状态"-->
<!-- labelClassName="descriptions-label"-->
<!-- >{{-->
<!-- $store.state.ems.workStatusOptions[item.workStatus]-->
<!-- }}-->
<!-- </el-descriptions-item-->
<!-- >-->
<!-- <el-descriptions-item-->
<!-- :span="1"-->
<!-- contentClassName="descriptions-direction"-->
<!-- label="工作模式"-->
<!-- labelClassName="descriptions-label"-->
<!-- >-->
<!-- todo 手动/自动-->
<!-- {{-->
<!-- $store.state.ems.gridStatusOptions[item.gridStatus]-->
<!-- }}-->
<!-- </el-descriptions-item-->
<!-- >-->
<!-- <el-descriptions-item-->
<!-- :span="1"-->
<!-- contentClassName="descriptions-direction"-->
<!-- label="并网状态"-->
<!-- labelClassName="descriptions-label"-->
<!-- >{{-->
<!-- $store.state.ems.gridStatusOptions[item.gridStatus]-->
<!-- }}-->
<!-- </el-descriptions-item-->
<!-- >-->
<!-- <el-descriptions-item-->
<!-- :span="1"-->
<!-- contentClassName="descriptions-direction"-->
<!-- label="告警状态"-->
<!-- labelClassName="descriptions-label"-->
<!-- >-->
<!-- todo-->
<!-- &lt;!&ndash;-->
<!-- {{-->
<!-- $store.state.ems.warnOptions[item.warnMode]-->
<!-- }}&ndash;&gt;-->
<!-- </el-descriptions-item-->
<!-- >-->
<!-- <el-descriptions-item-->
<!-- :contentClassName="`descriptions-direction ${-->
<!-- item.deviceStatus === '2' ? 'save' : 'danger'-->
<!-- }`"-->
<!-- :span="1"-->
<!-- label="设备状态"-->
<!-- labelClassName="descriptions-label"-->
<!-- >{{-->
<!-- $store.state.ems.deviceStatusOptions[item.deviceStatus]-->
<!-- }}-->
<!-- </el-descriptions-item-->
<!-- >-->
<!-- </el-descriptions>-->
<!-- </div>-->
<!-- &lt;!&ndash; 用电量&ndash;&gt;-->
<!-- <div class="descriptions-main descriptions-main-bg-color">-->
<!-- <el-descriptions :colon="false" :column="5" direction="vertical">-->
<!-- <el-descriptions-item-->
<!-- :span="5"-->
<!-- contentClassName="descriptions-direction"-->
<!-- label="当日用电量:"-->
<!-- labelClassName="descriptions-label"-->
<!-- >-->
<!-- </el-descriptions-item-->
<!-- >-->
<!-- <el-descriptions-item-->
<!-- :span="1"-->
<!-- contentClassName="descriptions-direction"-->
<!-- label="电网用电量"-->
<!-- labelClassName="descriptions-label"-->
<!-- >-->
<!-- </el-descriptions-item-->
<!-- >-->
<!-- <el-descriptions-item-->
<!-- :span="1"-->
<!-- contentClassName="descriptions-direction"-->
<!-- label="储能放电量"-->
<!-- labelClassName="descriptions-label"-->
<!-- >-->
<!-- </el-descriptions-item-->
<!-- >-->
<!-- <el-descriptions-item-->
<!-- :span="1"-->
<!-- contentClassName="descriptions-direction"-->
<!-- label="储能充电量"-->
<!-- labelClassName="descriptions-label"-->
<!-- >-->
<!-- </el-descriptions-item-->
<!-- >-->
<!-- <el-descriptions-item-->
<!-- :span="1"-->
<!-- contentClassName="descriptions-direction"-->
<!-- label="负荷用电量"-->
<!-- labelClassName="descriptions-label"-->
<!-- >-->
<!-- </el-descriptions-item-->
<!-- >-->
<!-- <el-descriptions-item-->
<!-- :span="1"-->
<!-- contentClassName="descriptions-direction"-->
<!-- label="光伏发电量"-->
<!-- labelClassName="descriptions-label"-->
<!-- >-->
<!-- </el-descriptions-item-->
<!-- >-->
<!-- </el-descriptions>-->
<!-- </div>-->
<!-- &lt;!&ndash; 表格&ndash;&gt;-->
<!-- <el-table-->
<!-- class="common-table"-->
<!-- stripe-->
<!-- style="width: 100%;margin-top:25px;">-->
<!-- <el-table-column-->
<!-- label="功率"-->
<!-- prop="type">-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- label="电网"-->
<!-- >-->
<!-- <template slot-scope="scope">-->
<!-- <span class="pointer"-->
<!-- @click="showChart('簇电压',scope.row.clusterId)">{{ scope.row.clusterVoltage }} V</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- label="储能">-->
<!-- <template slot-scope="scope">-->
<!-- <span class="pointer"-->
<!-- @click="showChart('簇电流',scope.row.clusterId)">{{ scope.row.clusterCurrent }} A</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- label="负荷">-->
<!-- <template slot-scope="scope">-->
<!-- <span class="pointer"-->
<!-- @click="showChart('簇电流',scope.row.clusterId)">{{ scope.row.clusterCurrent }} A</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- <el-table-column-->
<!-- label="光伏">-->
<!-- <template slot-scope="scope">-->
<!-- <span class="pointer"-->
<!-- @click="showChart('当前SOC',scope.row.clusterId)">{{ scope.row.currentSoc }} %</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<!-- </el-table>-->
<!-- &lt;!&ndash; 图表&ndash;&gt;-->
<!-- <div id="emsChart" style="height: 350px"></div>-->
<!-- </el-card>-->
<!-- </div>-->
<el-card
v-for="(item,index) in list"
:key="index+'emsList'"
@ -220,7 +19,7 @@
<div class="alarm">
<el-button size="small" round style="margin-right:20px;" type="primary" @click="pointDetail(item,'point')">详细
</el-button>
<el-badge :value="item.alarmNum || 0" class="item">
<el-badge :hidden="!item.alarmNum" :value="item.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(item,'alarmPoint')"

View File

@ -8,11 +8,7 @@
style="margin-bottom: 25px"
>
<el-card
:class="{
'timing-card-container':!['0','2'].includes(pcsItem.workStatus),
'warning-card-container':pcsItem.workStatus === '2',
'running-card-container':pcsItem.workStatus === '0'
}"
:class="handleCardClass(pcsItem)"
class="sbjk-card-container common-card-container-body-no-padding common-card-container-no-title-bg"
shadow="always"
>
@ -31,17 +27,11 @@
<div>数据更新时间{{ pcsItem.dataUpdateTime }}</div>
</div>
<div class="alarm">
<!-- <pcs-switch style="margin-right:10px;"-->
<!-- :round="true"-->
<!-- size="small"-->
<!-- type="danger"-->
<!-- :data="pcsItem"-->
<!-- @updateSuccess="init"/>-->
<el-button type="primary" round size="small" style="margin-right:20px;"
@click="pointDetail(pcsItem,'point')">
详细
</el-button>
<el-badge :value="pcsItem.alarmNum || 0" class="item">
<el-badge :hidden="!pcsItem.alarmNum" :value="pcsItem.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(pcsItem,'alarmPoint')"
@ -52,14 +42,12 @@
<div class="descriptions-main">
<el-descriptions :colon="false" :column="4" direction="vertical">
<el-descriptions-item
:contentClassName="`descriptions-direction ${
pcsItem.workStatus === '0' ? 'save' : 'danger'
}`"
contentClassName="descriptions-direction work-status"
:span="1"
label="工作状态"
labelClassName="descriptions-label"
>{{
$store.state.ems.workStatusOptions[pcsItem.workStatus]
PCSWorkStatusOptions[pcsItem.workStatus]
}}
</el-descriptions-item
>
@ -196,12 +184,17 @@ import RealTimeBaseInfo from "./../RealTimeBaseInfo.vue";
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import {getPcsDetailInfo, getRunningHeadInfo} from "@/api/ems/dzjk";
import intervalUpdate from "@/mixins/ems/intervalUpdate";
// import PcsSwitch from "@/views/ems/site/sblb/PcsSwitch.vue";
import {mapState} from "vuex";
export default {
name: "DzjkSbjkPcs",
components: {RealTimeBaseInfo, pointChart, PointTable},
mixins: [getQuerySiteId, intervalUpdate],
computed: {
...mapState({
PCSWorkStatusOptions: state => state?.ems?.PCSWorkStatusOptions || {},
})
},
data() {
return {
loading: false,
@ -209,10 +202,10 @@ export default {
pcsList: [],
infoData: [
{
label: "总交流有功率",
label: "总交流有功率",
attr: "totalActivePower",
unit: "kW",
pointName: "总交流有功率",
pointName: "总交流有功率",
},
{
label: "当天交流充电量",
@ -228,10 +221,10 @@ export default {
pointName: "A相电流",
},
{
label: "总交流无功率",
label: "总交流无功率",
attr: "totalReactivePower",
unit: "kVar",
pointName: "总交流无功率",
pointName: "总交流无功率",
},
{
label: "当天交流放电量",
@ -288,6 +281,10 @@ export default {
};
},
methods: {
handleCardClass(item) {
const {workStatus = ''} = item
return workStatus === '1' || !Object.keys(this.PCSWorkStatusOptions).find(i => i === workStatus) ? "timing-card-container" : workStatus === '2' ? 'warning-card-container' : 'running-card-container'
},
// 查看设备电位表格
pointDetail(row, dataType) {
const {deviceId} = row

View File

@ -1,12 +1,12 @@
<template>
<el-card
shadow="always"
class="common-card-container common-card-container-body-no-padding"
shadow="always"
class="common-card-container common-card-container-body-no-padding"
>
<div slot="header">
<span class="card-title">PCS有功功率/PCS无功功率</span>
</div>
<div style="height: 360px" id="cnglqxChart" />
<div style="height: 360px" id="cnglqxChart"/>
</el-card>
</template>
@ -14,7 +14,7 @@
<script>
import * as echarts from "echarts";
import resize from "@/mixins/ems/resize";
import { storagePower } from "@/api/ems/dzjk";
import {storagePower} from "@/api/ems/dzjk";
export default {
mixins: [resize],
@ -36,56 +36,56 @@ export default {
methods: {
init(siteId, timeRange) {
this.chart.showLoading();
const [startTime='', endTime=''] = timeRange;
storagePower(siteId,startTime,endTime)
.then((response) => {
this.setOption(response?.data?.pcsPowerList || []);
})
.finally(() => {
this.chart.hideLoading();
});
const [startTime = '', endTime = ''] = timeRange;
storagePower(siteId, startTime, endTime)
.then((response) => {
this.setOption(response?.data?.pcsPowerList || []);
})
.finally(() => {
this.chart.hideLoading();
});
},
setOption(data) {
let xdata = [],
series = [];
series = [];
data.forEach((element, index) => {
if (index === 0) {
xdata = (element.energyStoragePowList || []).map((i) => i.createDate);
}
series.push(
{
type: "line",
name: `${element.deviceId}有功功率`,
areaStyle: {
// color:'#FFBD00'
{
type: "line",
name: `${element.deviceId}有功功率`,
areaStyle: {
// color:'#FFBD00'
},
data: (element.energyStoragePowList || []).map(
(i) => {
return {
value: i.pcsTotalActPower,
year: i.dateDay || ''
}
}
)
},
data: (element.energyStoragePowList || []).map(
(i) => {
return {
value:i.pcsTotalActPower,
year:i.dateDay || ''
}
}
)
},
{
type: "line",
name: `${element.deviceId}无功功率`,
areaStyle: {
// color:'#FFBD00'
},
data: (element.energyStoragePowList || []).map(
(i) => {
return {
value: i.pcsTotalReactivePower,
year:i.dateDay || ''
}
}
),
}
{
type: "line",
name: `${element.deviceId}无功功率`,
areaStyle: {
// color:'#FFBD00'
},
data: (element.energyStoragePowList || []).map(
(i) => {
return {
value: i.pcsTotalReactivePower,
year: i.dateDay || ''
}
}
),
}
);
});
this.chart.setOption({
this.chart && this.chart.setOption({
legend: {
left: "center",
top: "5",
@ -99,29 +99,29 @@ export default {
containLabel: true,
},
tooltip: {
show:true,
show: true,
trigger: "axis",
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
},
formatter :(params)=>{
if(params.length <= 0) return
let result = (params[0].data.year || '')+' '+ params[0].name + '<div>'
params.forEach(item=>{
const {color,seriesName,value} = item
result += `<div style="position: relative;padding-left:20px;line-height: 20px;">
formatter: (params) => {
if (params.length <= 0) return
let result = (params[0].data.year || '') + ' ' + params[0].name + '<div>'
params.forEach(item => {
const {color, seriesName, value} = item
result += `<div style="position: relative;padding-left:20px;line-height: 20px;">
<div style="position: absolute;top:50%;left:0;width:12px;height:12px;border-radius:100%;background: ${color};transform: translateY(-50%)"></div>
<span>${seriesName}</span><span style="margin-left:20px;font-weight: 700">${value}</span></div>`
})
result+='</div>'
result += '</div>'
return result
}
},
textStyle: {
color: "#333333",
},
xAxis: { type: "category", data: xdata },
xAxis: {type: "category", data: xdata},
yAxis: {
type: "value",
},
@ -137,7 +137,7 @@ export default {
},
],
series,
});
}, true);
},
},
};

View File

@ -54,7 +54,7 @@ export default {
year:element.dateDay,
});
});
xdata = this.chart.setOption({
this.chart && this.chart.setOption({
legend: {
left: "center",
top: "5",
@ -115,7 +115,7 @@ export default {
data: ydata,
},
],
});
},true);
},
},
};

View File

@ -57,7 +57,7 @@ export default {
}
);
});
xdata = this.chart.setOption({
this.chart && this.chart.setOption({
legend: {
left: "center",
top: "5",
@ -118,7 +118,7 @@ export default {
data: ydata,
},
],
});
},true);
},
},
};

View File

@ -66,7 +66,7 @@ export default {
}),
});
});
this.chart.setOption({
this.chart && this.chart.setOption({
legend: {
left: "center",
top: "5",
@ -118,7 +118,7 @@ export default {
},
],
series,
});
},true);
},
},
};

View File

@ -25,7 +25,7 @@
<el-button type="primary" round size="small" style="margin-right:20px;" @click="pointDetail(item,'point')">
详细
</el-button>
<el-badge :value="item.alarmNum || 0" class="item">
<el-badge :hidden="!item.alarmNum" :value="item.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(item,'alarmPoint')"
@ -37,8 +37,10 @@
<el-col v-for="(tempDataItem,tempDataIndex) in tempData" :key="tempDataIndex+'hdTempData'" :span="12"
class="device-info-col">
<span class="pointer" @click="showChart(tempDataItem.title,item.deviceId)">
<span class="left">{{ tempDataItem.title }}</span> <span class="right">{{ item[tempDataItem.attr] || '' }}<span
v-html="tempDataItem.unit"></span></span>
<span class="left">{{ tempDataItem.title }}</span> <span class="right">{{
item[tempDataItem.attr] || '-'
}}<span
v-html="tempDataItem.unit"></span></span>
</span>
</el-col>
</el-row>

View File

@ -14,7 +14,7 @@
<el-button type="primary" round size="small" style="margin-right:20px;" @click="pointDetail(item,'point')">
详细
</el-button>
<el-badge :value="item.alarmNum || 0" class="item">
<el-badge :hidden="!item.alarmNum" :value="item.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(item,'alarmPoint')"
@ -26,7 +26,8 @@
<el-col v-for="(tempDataItem,tempDataIndex) in tempData" :key="tempDataIndex+'ylTempData'" :span="8"
class="device-info-col">
<span class="pointer" @click="showChart(tempDataItem.title,item.deviceId)">
<span class="left">{{ tempDataItem.title }}</span> <span class="right">{{ item[tempDataItem.attr] }}<span
<span class="left">{{ tempDataItem.title }}</span> <span
class="right">{{ item[tempDataItem.attr] || '-' }}<span
v-html="tempDataItem.unit"></span></span>
</span>
</el-col>

View File

@ -1,4 +1,3 @@
<template>
<div style="width:100%" v-loading="loading">
<!-- 搜索栏-->
@ -22,172 +21,185 @@
<el-form-item>
<el-button @click="onReset" native-type="button">重置</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="exportTable" native-type="button">导出</el-button>
</el-form-item>
</el-form>
<!--表格-->
<el-table
class="common-table"
:data="tableData"
stripe
style="width: 100%;margin-top:25px;">
<!-- 汇总列-->
<el-table-column label="汇总">
<el-table-column
prop="dataTime"
label="日期"
width="120">
</el-table-column>
</el-table-column>
<!--充电量列-->
<el-table-column label="充电量" align="center">
<el-table-column
align="center"
prop="activePeakKwh"
label="尖">
</el-table-column>
<el-table-column
align="center"
prop="activeHighKwh"
label="峰">
</el-table-column>
<el-table-column
align="center"
prop="activeFlatKwh"
label="平">
</el-table-column>
<el-table-column
align="center"
prop="activeValleyKwh"
label="谷">
</el-table-column>
<el-table-column
align="center"
prop="activeTotalKwh"
label="总">
</el-table-column>
</el-table-column>
<!--充电量列-->
<el-table-column label="放电量" align="center">
<el-table-column
align="center"
prop="reActivePeakKwh"
label="尖">
</el-table-column>
<el-table-column
align="center"
prop="reActiveHighKwh"
label="峰">
</el-table-column>
<el-table-column
align="center"
prop="reActiveFlatKwh"
label="平">
</el-table-column>
<el-table-column
align="center"
prop="reActiveValleyKwh"
label="谷">
</el-table-column>
<el-table-column
align="center"
prop="reActiveTotalKwh"
label="总">
</el-table-column>
</el-table-column>
<!-- 效率-->
<el-table-column label="效率(%)" align="center">
<el-table-column
align="center"
prop="effect">
</el-table-column>
</el-table-column>
</el-table>
<el-pagination
v-show="tableData.length>0"
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
: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>
class="common-table"
:data="tableData"
stripe
style="width: 100%;margin-top:25px;">
<!-- 汇总列-->
<el-table-column label="汇总">
<el-table-column
prop="dataTime"
label="日期"
width="120">
</el-table-column>
</el-table-column>
<!--充电量列-->
<el-table-column label="充电量" align="center">
<el-table-column
align="center"
prop="activePeakKwh"
label="尖">
</el-table-column>
<el-table-column
align="center"
prop="activeHighKwh"
label="峰">
</el-table-column>
<el-table-column
align="center"
prop="activeFlatKwh"
label="平">
</el-table-column>
<el-table-column
align="center"
prop="activeValleyKwh"
label="谷">
</el-table-column>
<el-table-column
align="center"
prop="activeTotalKwh"
label="总">
</el-table-column>
</el-table-column>
<!--充电量列-->
<el-table-column label="放电量" align="center">
<el-table-column
align="center"
prop="reActivePeakKwh"
label="尖">
</el-table-column>
<el-table-column
align="center"
prop="reActiveHighKwh"
label="峰">
</el-table-column>
<el-table-column
align="center"
prop="reActiveFlatKwh"
label="平">
</el-table-column>
<el-table-column
align="center"
prop="reActiveValleyKwh"
label="谷">
</el-table-column>
<el-table-column
align="center"
prop="reActiveTotalKwh"
label="总">
</el-table-column>
</el-table-column>
<!-- 效率-->
<el-table-column label="效率(%)" align="center">
<el-table-column
align="center"
prop="effect">
</el-table-column>
</el-table-column>
</el-table>
<el-pagination
v-show="tableData.length>0"
background
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
: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>
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import { getAmmeterData} from '@/api/ems/dzjk'
import {getAmmeterData} from '@/api/ems/dzjk'
import {formatDate} from "@/filters/ems";
export default {
name:'DzjkTjbbDbbb',
name: 'DzjkTjbbDbbb',
mixins: [getQuerySiteId],
data() {
return {
loading:false,
pickerOptions:{
loading: false,
pickerOptions: {
disabledDate(time) {
return time.getTime() > Date.now();
},
},
defaultDateRange:[],//默认展示的时间
dateRange:[],
tableData:[],
pageSize:10,//分页栏当前每个数据总数
pageNum:1,//分页栏当前页数
totalSize:0,//table表格数据总数
defaultDateRange: [],//默认展示的时间
dateRange: [],
tableData: [],
pageSize: 10,//分页栏当前每个数据总数
pageNum: 1,//分页栏当前页数
totalSize: 0,//table表格数据总数
}
},
methods:{
methods: {
// 导出表格
exportTable() {
if (!this.dateRange?.length) return
const [startTime, endTime] = this.dateRange
this.download('ems/statsReport/exportAmmeterData', {
siteId: this.siteId,
startTime,
endTime,
}, `电表报表_${startTime}-${endTime}.xlsx`)
},
// 搜索
onSearch(){
this.pageNum =1//每次搜索从1开始搜索
onSearch() {
this.pageNum = 1//每次搜索从1开始搜索
this.getData()
},
// 重置
onReset(){
this.dateRange=this.defaultDateRange
this.pageNum =1//每次搜索从1开始搜索
onReset() {
this.dateRange = this.defaultDateRange
this.pageNum = 1//每次搜索从1开始搜索
this.getData()
},
// 分页
handleSizeChange(val) {
this.pageSize = val;
this.$nextTick(()=>{
this.$nextTick(() => {
this.getData()
})
},
handleCurrentChange(val) {
this.pageNum = val
this.$nextTick(()=>{
this.$nextTick(() => {
this.getData()
})
},
// 获取数据
getData(){
this.loading=true
const {siteId,pageNum,pageSize} =this
const [startTime='',endTime='']=(this.dateRange || [])
getAmmeterData({siteId:siteId,startTime,endTime,pageSize,pageNum}).then(response=>{
this.tableData=response?.rows || [];
getData() {
this.loading = true
const {siteId, pageNum, pageSize} = this
const [startTime = '', endTime = ''] = (this.dateRange || [])
getAmmeterData({siteId: siteId, startTime, endTime, pageSize, pageNum}).then(response => {
this.tableData = response?.rows || [];
this.totalSize = response?.total || 0
}).finally(()=> {
}).finally(() => {
this.loading = false
})
},
init(){
this.dateRange=[]
this.tableData=[]
this.totalSize=0
this.pageSize=10
init() {
this.dateRange = []
this.tableData = []
this.totalSize = 0
this.pageSize = 10
this.pageNum = 1
const now = new Date().getTime();
const lastMonth = new Date(now-30 * 24 * 60 * 60 * 1000).getTime();
this.defaultDateRange = [formatDate(lastMonth), formatDate(now)];
this.dateRange=[formatDate(lastMonth), formatDate(now)];
let now = new Date(), lastDay = now.getTime(), firstDay = new Date(now.setDate(1)).getTime();
this.defaultDateRange = [formatDate(firstDay), formatDate(lastDay)];
this.dateRange = [formatDate(firstDay), formatDate(lastDay)];
this.getData()
},
},
@ -195,8 +207,8 @@ export default {
</script>
<style scoped lang="scss">
::v-deep{
.common-table.el-table .el-table__header-wrapper th, .common-table.el-table .el-table__fixed-header-wrapper th{
::v-deep {
.common-table.el-table .el-table__header-wrapper th, .common-table.el-table .el-table__fixed-header-wrapper th {
border-bottom: 1px solid #dfe6ec;
}
}

View File

@ -1,22 +1,23 @@
<template>
<el-card
shadow="always"
class="common-card-container time-range-card"
style="margin-top: 20px"
shadow="always"
class="common-card-container time-range-card"
style="margin-top: 20px"
>
<div slot="header" class="time-range-header">
<span class="card-title"> </span>
<date-range-select ref="dateRangeSelect" @updateDate="updateDate" />
<date-range-select ref="dateRangeSelect" @updateDate="updateDate"/>
</div>
<div class="card-main" v-loading="loading">
<el-button-group class="ems-btns-group">
<el-button
v-for="(item, index) in btnList"
:key="index + 'dcdqxBtns'"
size="mini"
:class="{ activeBtn: activeBtn === item.id }"
@click="changeDataType(item.id)"
>{{ item.name }}</el-button
v-for="(item, index) in btnList"
:key="index + 'dcdqxBtns'"
size="mini"
:class="{ activeBtn: activeBtn === item.id }"
@click="changeDataType(item.id)"
>{{ item.name }}
</el-button
>
</el-button-group>
<div id="dcdEchart" style="height: 310px"></div>
@ -28,12 +29,13 @@
import * as echarts from "echarts";
import resize from "@/mixins/ems/resize";
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import { getStackData, getStackNameList } from "@/api/ems/dzjk";
import { formatDate } from "@/filters/ems";
import {getStackData} from "@/api/ems/dzjk";
import {formatDate} from "@/filters/ems";
import DateRangeSelect from "@/components/Ems/DateRangeSelect/index.vue";
export default {
name: "DzjkTjbbDcdqx",
components: { DateRangeSelect },
components: {DateRangeSelect},
mixins: [resize, getQuerySiteId],
data() {
return {
@ -46,10 +48,10 @@ export default {
loading: false,
activeBtn: "1",
btnList: [
{ name: "堆平均维度", id: "1", attr: ["temp"], source: ["有功功率"] },
{ name: "堆电压", id: "2", attr: ["voltage"], source: ["堆电压"] },
{ name: "堆电流", id: "3", attr: ["current"], source: ["堆电流"] },
{ name: "堆soc", id: "4", attr: ["soc"], source: ["堆soc"] },
{name: "堆平均维度", id: "1", attr: ["temp"], source: ["有功功率"]},
{name: "堆电压", id: "2", attr: ["voltage"], source: ["堆电压"]},
{name: "堆电流", id: "3", attr: ["current"], source: ["堆电流"]},
{name: "堆soc", id: "4", attr: ["soc"], source: ["堆soc"]},
],
};
},
@ -66,7 +68,7 @@ export default {
this.getData();
},
getData() {
const { siteId, activeBtn } = this;
const {siteId, activeBtn} = this;
const [start = "", end = ""] = this.dateRange || [];
//接口调用完成之后 设置图表、结束loading
this.loading = true;
@ -76,12 +78,12 @@ export default {
endTime: formatDate(end),
dataType: activeBtn,
})
.then((response) => {
this.setOption(response?.data || []);
})
.finally(() => {
this.loading = false;
});
.then((response) => {
this.setOption(response?.data || []);
})
.finally(() => {
this.loading = false;
});
},
compareDate(date1, date2) {
console.log("比较时间", date1, date2);
@ -92,9 +94,9 @@ export default {
const [date1_Y = "", date1_M = "", date1_D = ""] = date1.split("-"); //根据空格区分[年月日,小时]
const [date2_Y = "", date2_M = "", date2_D = ""] = date2.split("-"); //根据空格区分[年月日,小时]
return (
(date1_Y === date2_Y && date1_M === date2_M && date1_D - date2_D) ||
(date1_Y === date2_Y && date1_M - date2_M) ||
date1_Y - date2_Y
(date1_Y === date2_Y && date1_M === date2_M && date1_D - date2_D) ||
(date1_Y === date2_Y && date1_M - date2_M) ||
date1_Y - date2_Y
);
},
setOption(data) {
@ -106,7 +108,7 @@ export default {
const source = [];
const sourceTop = ["日期"];
let map = {},
mapArr = [];
mapArr = [];
// 生成所有{日期:[],日期:[]}格式的对象和所有包含所有日期的[日期1,日期2...]
data.forEach((item) => {
item.dataList.forEach((inner) => {
@ -136,38 +138,53 @@ export default {
});
source.unshift(sourceTop);
this.chart.setOption(
{
grid: {
containLabel: true,
},
legend: {
left: "center",
bottom: "15",
},
tooltip: {
trigger: "axis",
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
{
grid: {
containLabel: true,
},
legend: {
left: "center",
top: "10",
},
tooltip: {
trigger: "axis",
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
},
},
textStyle: {
color: "#333333",
},
xAxis: {
type: "category",
},
yAxis: {
type: "value",
},
dataZoom: [
{
type: "inside",
start: 0,
end: 100,
},
{
start: 0,
end: 100,
},
],
dataset: {source},
series: source[0].slice(1).map((item) => {
return {
type: "line",
smooth: true,
areaStyle: {
opacity: 0.7,
},
};
}),
},
textStyle: {
color: "#333333",
},
xAxis: {
type: "category",
},
yAxis: {
type: "value",
},
dataset: { source },
series: source[0].slice(1).map((item) => {
return {
type: "line",
};
}),
},
true
true
);
},
initChart() {
@ -176,7 +193,7 @@ export default {
init() {
this.$nextTick(() => {
this.initChart();
this.$refs.dateRangeSelect.init();
this.$refs.dateRangeSelect.init(true);
});
},
},

View File

@ -1,15 +1,14 @@
<template>
<el-card
shadow="always"
class="common-card-container time-range-card"
style="margin-top: 20px"
shadow="always"
class="common-card-container time-range-card"
style="margin-top: 20px"
>
<div slot="header" class="time-range-header">
<span class="card-title">功率曲线</span>
<date-range-select
ref="dateRangeSelect"
@reset="resetTime"
@updateDate="updateDate"
ref="dateRangeSelect"
@updateDate="updateDate"
/>
</div>
<div class="card-main" v-loading="loading">
@ -22,12 +21,13 @@
import * as echarts from "echarts";
import resize from "@/mixins/ems/resize";
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import { getPcsNameList, getPowerData } from "@/api/ems/dzjk";
import { formatDate } from "@/filters/ems";
import {getPowerData} from "@/api/ems/dzjk";
import {formatDate} from "@/filters/ems";
import DateRangeSelect from "@/components/Ems/DateRangeSelect/index.vue";
export default {
name: "DzjkTjbbGlqx",
components: { DateRangeSelect },
components: {DateRangeSelect},
mixins: [resize, getQuerySiteId],
data() {
return {
@ -38,7 +38,6 @@ export default {
},
dateRange: [],
loading: false,
dateRangeInit: true,
};
},
methods: {
@ -47,30 +46,22 @@ export default {
this.dateRange = data || [];
this.getData();
},
resetTime() {
this.dateRangeInit = true;
},
getData() {
const { siteId } = this;
const {siteId} = this;
let [start = "", end = ""] = this.dateRange || [];
//接口调用完成之后 设置图表、结束loading
this.loading = true;
if (this.dateRangeInit) {
start = "";
end = "";
this.dateRangeInit = false;
}
getPowerData({
siteId,
startDate: formatDate(start),
endDate: formatDate(end),
})
.then((response) => {
this.setOption(response?.data || []);
})
.finally(() => {
this.loading = false;
});
.then((response) => {
this.setOption(response?.data || []);
})
.finally(() => {
this.loading = false;
});
},
setOption(data) {
const source = [["日期", "电网功率", "负载功率", "储能功率", "光伏功率"]];
@ -84,47 +75,74 @@ export default {
]);
});
this.chart.setOption(
{
grid: {
containLabel: true,
},
legend: {
left: "center",
bottom: "15",
},
tooltip: {
trigger: "axis",
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
{
grid: {
containLabel: true,
},
},
textStyle: {
color: "#333333",
},
xAxis: {
type: "category",
},
yAxis: {
type: "value",
},
dataset: { source },
series: [
{
type: "line",
legend: {
left: "center",
top: "10",
},
{
type: "line",
tooltip: {
trigger: "axis",
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
},
},
{
type: "line",
textStyle: {
color: "#333333",
},
{
type: "line",
xAxis: {
type: "category",
},
],
},
true
yAxis: {
type: "value",
},
dataset: {source},
dataZoom: [
{
type: "inside",
start: 0,
end: 100,
},
{
start: 0,
end: 100,
},
],
series: [
{
type: "line",
smooth: true,
areaStyle: {
opacity: 0.7,
},
},
{
type: "line",
smooth: true,
areaStyle: {
opacity: 0.7,
},
},
{
type: "line",
smooth: true,
areaStyle: {
opacity: 0.7,
},
},
{
type: "line",
smooth: true,
areaStyle: {
opacity: 0.7,
},
},
],
},
true
);
},
initChart() {
@ -133,7 +151,6 @@ export default {
},
init() {
this.$nextTick(() => {
this.dateRangeInit = true;
this.initChart();
this.$refs.dateRangeSelect.init();
});

View File

@ -1,22 +1,23 @@
<template>
<el-card
shadow="always"
class="common-card-container time-range-card"
style="margin-top: 20px"
shadow="always"
class="common-card-container time-range-card"
style="margin-top: 20px"
>
<div slot="header" class="time-range-header">
<span class="card-title"> </span>
<date-range-select ref="dateRangeSelect" @updateDate="updateDate" />
<date-range-select ref="dateRangeSelect" @updateDate="updateDate"/>
</div>
<div class="card-main" v-loading="loading">
<el-button-group class="ems-btns-group">
<el-button
v-for="(item, index) in btnList"
:key="index + 'flqxcBtns'"
size="mini"
:class="{ activeBtn: activeBtn === item.id }"
@click="changeDataType(item.id)"
>{{ item.name }}</el-button
v-for="(item, index) in btnList"
:key="index + 'flqxcBtns'"
size="mini"
:class="{ activeBtn: activeBtn === item.id }"
@click="changeDataType(item.id)"
>{{ item.name }}
</el-button
>
</el-button-group>
<div id="pcsEchart" style="height: 310px"></div>
@ -28,12 +29,13 @@
import * as echarts from "echarts";
import resize from "@/mixins/ems/resize";
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import { getPCSData, getPcsNameList } from "@/api/ems/dzjk";
import { formatDate } from "@/filters/ems";
import {getPCSData} from "@/api/ems/dzjk";
import {formatDate} from "@/filters/ems";
import DateRangeSelect from "@/components/Ems/DateRangeSelect/index.vue";
export default {
name: "DzjkTjbbPcsqx",
components: { DateRangeSelect },
components: {DateRangeSelect},
mixins: [resize, getQuerySiteId],
data() {
return {
@ -82,7 +84,7 @@ export default {
this.getData();
},
getData() {
const { siteId, activeBtn } = this;
const {siteId, activeBtn} = this;
const [start = "", end = ""] = this.dateRange || [];
this.loading = true;
//接口调用完成之后 设置图表、结束loading
@ -92,12 +94,12 @@ export default {
endTime: formatDate(end),
dataType: activeBtn,
})
.then((response) => {
this.setOption(response?.data || []);
})
.finally(() => {
this.loading = false;
});
.then((response) => {
this.setOption(response?.data || []);
})
.finally(() => {
this.loading = false;
});
},
compareDate(date1, date2) {
console.log("比较时间", date1, date2);
@ -108,9 +110,9 @@ export default {
const [date1_Y = "", date1_M = "", date1_D = ""] = date1.split("-"); //根据空格区分[年月日,小时]
const [date2_Y = "", date2_M = "", date2_D = ""] = date2.split("-"); //根据空格区分[年月日,小时]
return (
(date1_Y === date2_Y && date1_M === date2_M && date1_D - date2_D) ||
(date1_Y === date2_Y && date1_M - date2_M) ||
date1_Y - date2_Y
(date1_Y === date2_Y && date1_M === date2_M && date1_D - date2_D) ||
(date1_Y === date2_Y && date1_M - date2_M) ||
date1_Y - date2_Y
);
},
setOption(data) {
@ -122,7 +124,7 @@ export default {
const source = [];
const sourceTop = ["日期"];
let map = {},
mapArr = [];
mapArr = [];
// 生成所有{日期:[],日期:[]}格式的对象和所有包含所有日期的[日期1,日期2...]
data.forEach((item) => {
item.dataList.forEach((inner) => {
@ -152,38 +154,53 @@ export default {
});
source.unshift(sourceTop);
this.chart.setOption(
{
grid: {
containLabel: true,
},
legend: {
left: "center",
bottom: "15",
},
tooltip: {
trigger: "axis",
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
{
grid: {
containLabel: true,
},
legend: {
left: "center",
top: "10",
},
tooltip: {
trigger: "axis",
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
},
},
textStyle: {
color: "#333333",
},
xAxis: {
type: "category",
},
yAxis: {
type: "value",
},
dataZoom: [
{
type: "inside",
start: 0,
end: 100,
},
{
start: 0,
end: 100,
},
],
dataset: {source},
series: source[0].slice(1).map((item) => {
return {
type: "line",
smooth: true,
areaStyle: {
opacity: 0.7,
},
};
}),
},
textStyle: {
color: "#333333",
},
xAxis: {
type: "category",
},
yAxis: {
type: "value",
},
dataset: { source },
series: source[0].slice(1).map((item) => {
return {
type: "line",
};
}),
},
true
true
);
},
initChart() {
@ -192,7 +209,7 @@ export default {
init() {
this.$nextTick(() => {
this.initChart();
this.$refs.dateRangeSelect.init();
this.$refs.dateRangeSelect.init(true);
});
},
},

View File

@ -21,19 +21,23 @@
<el-form-item>
<el-button @click="onReset" native-type="button">重置</el-button>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="exportTable" native-type="button">导出</el-button>
</el-form-item>
</el-form>
<!--表格-->
<el-table
class="common-table"
:data="tableData"
show-summary
stripe
style="width: 100%;margin-top:25px;">
<!-- 汇总列-->
<el-table-column label="汇总">
<el-table-column label="汇总" min-width="100px" align="center">
<el-table-column
prop="dataTime"
label="日期"
width="120">
min-width="100px" align="center">
</el-table-column>
</el-table-column>
<!--充电量列-->
@ -92,13 +96,14 @@
label="总">
</el-table-column>
</el-table-column>
<!-- 效率-->
<!-- <el-table-column label="效率(%)" align="center">-->
<!-- <el-table-column-->
<!-- align="center"-->
<!-- prop="effect">-->
<!-- </el-table-column>-->
<!-- </el-table-column>-->
<!-- 实际收益-->
<el-table-column label="" align="center" fixed="right">
<el-table-column
prop="actualRevenue"
label="实际收益"
align="center">
</el-table-column>
</el-table-column>
</el-table>
<el-pagination
v-show="tableData.length>0"
@ -142,6 +147,16 @@ export default {
}
},
methods: {
// 导出表格
exportTable() {
if (!this.dateRange?.length) return
const [startTime, endTime] = this.dateRange
this.download('ems/statsReport/exportAmmeterRevenueData', {
siteId: this.siteId,
startTime,
endTime,
}, `收益报表_${startTime}-${endTime}.xlsx`)
},
// 搜索
onSearch() {
this.pageNum = 1//每次搜索从1开始搜索
@ -171,7 +186,6 @@ export default {
this.loading = true
const {siteId, pageNum, pageSize} = this
const [startTime = '', endTime = ''] = (this.dateRange || [])
//http://localhost:8089/ems/statsReport/getAmmeterRevenueData?siteId=021_DDS_01&startTime=2025-10-14&endTime=2025-10-15&pageSize=10&pageNum=1
getAmmeterRevenueData({siteId: siteId, startTime, endTime, pageSize, pageNum}).then(response => {
this.tableData = response?.rows || [];
this.totalSize = response?.total || 0
@ -185,10 +199,9 @@ export default {
this.totalSize = 0
this.pageSize = 10
this.pageNum = 1
const now = new Date().getTime();
const lastMonth = new Date(now - 30 * 24 * 60 * 60 * 1000).getTime();
this.defaultDateRange = [formatDate(lastMonth), formatDate(now)];
this.dateRange = [formatDate(lastMonth), formatDate(now)];
let now = new Date(), lastDay = now.getTime(), firstDay = new Date(now.setDate(1)).getTime();
this.defaultDateRange = [formatDate(firstDay), formatDate(lastDay)];
this.dateRange = [formatDate(firstDay), formatDate(lastDay)];
this.getData()
},
},
@ -197,9 +210,19 @@ export default {
<style scoped lang="scss">
::v-deep {
.common-table.el-table .el-table__header-wrapper th, .common-table.el-table .el-table__fixed-header-wrapper th {
border-bottom: 1px solid #dfe6ec;
.common-table.el-table {
.el-table__header-wrapper th, .common-table.el-table .el-table__fixed-header-wrapper th {
border-bottom: 1px solid #dfe6ec;
}
.el-table__footer-wrapper {
tbody td.el-table__cell {
color: #000;
font-weight: bolder;
}
}
}
}
</style>

View File

@ -1,577 +0,0 @@
<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

@ -1,614 +0,0 @@
<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>

View File

@ -80,7 +80,7 @@
<el-table-column label="数据点位" prop="dataPoint"></el-table-column>
<el-table-column
label="数据点位名称"
prop="pointName"
prop="dataPointName"
></el-table-column>
<!-- <el-table-column label="modbus地址">-->
<!-- <template slot-scope="scope">-->
@ -88,8 +88,8 @@
<!-- `${scope.row.ipAddress || ""} ${scope.row.ipPort || ""}`-->
<!-- }}</span>-->
<!-- </template>-->
<!-- </el-table-column>-->
<el-table-column label="寄存器地址" prop="寄存器地址"></el-table-column>
<!-- </el-table-column>
<el-table-column label="寄存器地址" prop="寄存器地址"></el-table-column>-->
<el-table-column
label="最新值"
prop="pointValue"

View File

@ -6,30 +6,39 @@
<pane size="16">
<el-col>
<div class="head-container">
<el-input v-model="deptName" placeholder="请输入部门名称" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px" />
<el-input v-model="deptName" placeholder="请输入部门名称" clearable size="small"
prefix-icon="el-icon-search" style="margin-bottom: 20px"/>
</div>
<div class="head-container">
<el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current @node-click="handleNodeClick" />
<el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false"
:filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current
@node-click="handleNodeClick"/>
</div>
</el-col>
</pane>
<!--用户数据-->
<pane size="84">
<el-col>
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
<el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch"
label-width="68px">
<el-form-item label="用户名称" prop="userName">
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
<el-input v-model="queryParams.userName" placeholder="请输入用户名称" clearable style="width: 240px"
@keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
<el-input v-model="queryParams.phonenumber" placeholder="请输入手机号码" clearable style="width: 240px"
@keyup.enter.native="handleQuery"/>
</el-form-item>
<el-form-item label="状态" prop="status">
<el-select v-model="queryParams.status" placeholder="用户状态" clearable style="width: 240px">
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
<el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label"
:value="dict.value"/>
</el-select>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="开始日期" end-placeholder="结束日期"></el-date-picker>
<el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange"
range-separator="-" start-placeholder="开始日期"
end-placeholder="结束日期"></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
@ -39,33 +48,48 @@
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:user:add']">新增</el-button>
<el-button type="primary" plain icon="el-icon-plus" size="mini" @click="handleAdd"
v-hasPermi="['system:user:add']">新增
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate" v-hasPermi="['system:user:edit']">修改</el-button>
<el-button type="success" plain icon="el-icon-edit" size="mini" :disabled="single" @click="handleUpdate"
v-hasPermi="['system:user:edit']">修改
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple" @click="handleDelete" v-hasPermi="['system:user:remove']">删除</el-button>
<el-button type="danger" plain icon="el-icon-delete" size="mini" :disabled="multiple"
@click="handleDelete" v-hasPermi="['system:user:remove']">删除
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['system:user:import']">导入</el-button>
<el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport"
v-hasPermi="['system:user:import']">导入
</el-button>
</el-col>
<el-col :span="1.5">
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['system:user:export']">导出</el-button>
<el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport"
v-hasPermi="['system:user:export']">导出
</el-button>
</el-col>
<right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
</el-row>
<el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="50" align="center" />
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
<el-table-column type="selection" width="50" align="center"/>
<el-table-column label="用户编号" align="center" key="userId" prop="userId" v-if="columns[0].visible"/>
<el-table-column label="用户名称" align="center" key="userName" prop="userName" v-if="columns[1].visible"
:show-overflow-tooltip="true"/>
<el-table-column label="用户昵称" align="center" key="nickName" prop="nickName" v-if="columns[2].visible"
:show-overflow-tooltip="true"/>
<el-table-column label="部门" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible"
:show-overflow-tooltip="true"/>
<el-table-column label="手机号码" align="center" key="phonenumber" prop="phonenumber"
v-if="columns[4].visible" width="120"/>
<el-table-column label="状态" align="center" key="status" v-if="columns[5].visible">
<template slot-scope="scope">
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
<el-switch v-model="scope.row.status" active-value="0" inactive-value="1"
@change="handleStatusChange(scope.row)"></el-switch>
</template>
</el-table-column>
<el-table-column label="创建时间" align="center" prop="createTime" v-if="columns[6].visible" width="160">
@ -75,20 +99,30 @@
</el-table-column>
<el-table-column label="操作" align="center" width="160" class-name="small-padding fixed-width">
<template slot-scope="scope" v-if="scope.row.userId !== 1">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']">修改</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']">删除</el-button>
<el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['system:user:resetPwd', 'system:user:edit']">
<el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)"
v-hasPermi="['system:user:edit']">修改
</el-button>
<el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)"
v-hasPermi="['system:user:remove']">删除
</el-button>
<el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)"
v-hasPermi="['system:user:resetPwd', 'system:user:edit']">
<el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="handleResetPwd" icon="el-icon-key" v-hasPermi="['system:user:resetPwd']">重置密码</el-dropdown-item>
<el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check" v-hasPermi="['system:user:edit']">分配角色</el-dropdown-item>
<el-dropdown-item command="handleResetPwd" icon="el-icon-key"
v-hasPermi="['system:user:resetPwd']">重置密码
</el-dropdown-item>
<el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check"
v-hasPermi="['system:user:edit']">分配角色
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
</el-table-column>
</el-table>
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
<pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum"
:limit.sync="queryParams.pageSize" @pagination="getList"/>
</el-col>
</pane>
</splitpanes>
@ -100,36 +134,38 @@
<el-row>
<el-col :span="12">
<el-form-item label="用户昵称" prop="nickName">
<el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30" />
<el-input v-model="form.nickName" placeholder="请输入用户昵称" maxlength="30"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="归属部门" prop="deptId">
<treeselect v-model="form.deptId" :options="enabledDeptOptions" :show-count="true" placeholder="请选择归属部门" />
<treeselect v-model="form.deptId" :options="enabledDeptOptions" :show-count="true"
placeholder="请选择归属部门"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item label="手机号码" prop="phonenumber">
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11" />
<el-input v-model="form.phonenumber" placeholder="请输入手机号码" maxlength="11"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="邮箱" prop="email">
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50" />
<el-input v-model="form.email" placeholder="请输入邮箱" maxlength="50"/>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户名称" prop="userName">
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30" />
<el-input v-model="form.userName" placeholder="请输入用户名称" maxlength="30"/>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item v-if="form.userId == undefined" label="用户密码" prop="password">
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20" show-password />
<el-input v-model="form.password" placeholder="请输入用户密码" type="password" maxlength="20"
show-password/>
</el-form-item>
</el-col>
</el-row>
@ -137,14 +173,17 @@
<el-col :span="12">
<el-form-item label="用户性别">
<el-select v-model="form.sex" placeholder="请选择性别">
<el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
<el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label"
:value="dict.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态">
<el-radio-group v-model="form.status">
<el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
<el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">
{{ dict.label }}
</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
@ -153,14 +192,33 @@
<el-col :span="12">
<el-form-item label="岗位">
<el-select v-model="form.postIds" multiple placeholder="请选择岗位">
<el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId" :disabled="item.status == 1" ></el-option>
<el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId"
:disabled="item.status == 1"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="角色">
<el-select v-model="form.roleIds" multiple placeholder="请选择角色">
<el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == 1"></el-option>
<el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId"
:disabled="item.status == 1"></el-option>
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="24">
<el-form-item label="归属站点" name="belongSite">
<el-select
v-model="form.belongSite"
multiple
collapse-tags
placeholder="请选择"
style="width:100%"
@change="selectBelongSite">
<el-option :label="item.siteName" :value="item.siteId" v-for="(item,index) in siteList"
:disabled="item.siteId!== 'all' && (form.belongSite || []).includes('all')"
:key="index+'zdxeSelect'"></el-option>
</el-select>
</el-form-item>
</el-col>
@ -181,15 +239,20 @@
<!-- 用户导入对话框 -->
<el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers"
:action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading"
:on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处<em>点击上传</em></div>
<div class="el-upload__tip text-center" slot="tip">
<div class="el-upload__tip" slot="tip">
<el-checkbox v-model="upload.updateSupport" />是否更新已经存在的用户数据
<el-checkbox v-model="upload.updateSupport"/>
是否更新已经存在的用户数据
</div>
<span>仅允许导入xlsxlsx格式文件</span>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">下载模板</el-link>
<el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline"
@click="importTemplate">下载模板
</el-link>
</div>
</el-upload>
<div slot="footer" class="dialog-footer">
@ -201,17 +264,27 @@
</template>
<script>
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user"
import { getToken } from "@/utils/auth"
import {
addUser,
changeUserStatus,
delUser,
deptTreeSelect,
getUser,
listUser,
resetUserPwd,
updateUser
} from "@/api/system/user"
import {getAllSites} from '@/api/ems/zddt'
import {getToken} from "@/utils/auth"
import Treeselect from "@riophae/vue-treeselect"
import "@riophae/vue-treeselect/dist/vue-treeselect.css"
import { Splitpanes, Pane } from "splitpanes"
import {Pane, Splitpanes} from "splitpanes"
import "splitpanes/dist/splitpanes.css"
export default {
name: "User",
dicts: ['sys_normal_disable', 'sys_user_sex'],
components: { Treeselect, Splitpanes, Pane },
components: {Treeselect, Splitpanes, Pane},
data() {
return {
// 遮罩层
@ -228,6 +301,8 @@ export default {
total: 0,
// 用户表格数据
userList: null,
// 站点列表数据
siteList: [],
// 弹出层标题
title: "",
// 所有部门树选项
@ -263,7 +338,7 @@ export default {
// 是否更新已经存在的用户数据
updateSupport: 0,
// 设置上传的请求头部
headers: { Authorization: "Bearer " + getToken() },
headers: {Authorization: "Bearer " + getToken()},
// 上传的地址
url: process.env.VUE_APP_BASE_API + "/system/user/importData"
},
@ -278,27 +353,27 @@ export default {
},
// 列信息
columns: [
{ key: 0, label: `用户编号`, visible: true },
{ key: 1, label: `用户名称`, visible: true },
{ key: 2, label: `用户昵称`, visible: true },
{ key: 3, label: `部门`, visible: true },
{ key: 4, label: `手机号码`, visible: true },
{ key: 5, label: `状态`, visible: true },
{ key: 6, label: `创建时间`, visible: true }
{key: 0, label: `用户编号`, visible: true},
{key: 1, label: `用户名称`, visible: true},
{key: 2, label: `用户昵称`, visible: true},
{key: 3, label: `部门`, visible: true},
{key: 4, label: `手机号码`, visible: true},
{key: 5, label: `状态`, visible: true},
{key: 6, label: `创建时间`, visible: true}
],
// 表单校验
rules: {
userName: [
{ required: true, message: "用户名称不能为空", trigger: "blur" },
{ min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur' }
{required: true, message: "用户名称不能为空", trigger: "blur"},
{min: 2, max: 20, message: '用户名称长度必须介于 2 和 20 之间', trigger: 'blur'}
],
nickName: [
{ required: true, message: "用户昵称不能为空", trigger: "blur" }
{required: true, message: "用户昵称不能为空", trigger: "blur"}
],
password: [
{ required: true, message: "用户密码不能为空", trigger: "blur" },
{ min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur' },
{ pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
{required: true, message: "用户密码不能为空", trigger: "blur"},
{min: 5, max: 20, message: '用户密码长度必须介于 5 和 20 之间', trigger: 'blur'},
{pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur"}
],
email: [
{
@ -313,7 +388,8 @@ export default {
message: "请输入正确的手机号码",
trigger: "blur"
}
]
],
}
}
},
@ -324,6 +400,7 @@ export default {
}
},
created() {
this.getZdList()
this.getList()
this.getDeptTree()
this.getConfigKey("sys.user.initPassword").then(response => {
@ -331,14 +408,37 @@ export default {
})
},
methods: {
selectBelongSite(data) {
console.log('选中的站点', data)
if (data.includes("all")) {
this.form.belongSite = ['all']
return
}
if (this.siteList.length && data.length === (this.siteList.length - 1)) {
this.form.belongSite = ['all']
}
},
//获取站点列表
getZdList() {
return getAllSites().then(response => {
this.siteList = response?.data || []
if (this.siteList.length > 0) {
this.siteList.unshift({
id: 'all',
siteId: "all",
siteName: "全部"
})
}
})
},
/** 查询用户列表 */
getList() {
this.loading = true
listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
this.userList = response.rows
this.total = response.total
this.loading = false
}
this.userList = response.rows
this.total = response.total
this.loading = false
}
)
},
/** 查询部门下拉树结构 */
@ -373,11 +473,11 @@ export default {
// 用户状态修改
handleStatusChange(row) {
let text = row.status === "0" ? "启用" : "停用"
this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function() {
this.$modal.confirm('确认要"' + text + '""' + row.userName + '"用户吗?').then(function () {
return changeUserStatus(row.userId, row.status)
}).then(() => {
this.$modal.msgSuccess(text + "成功")
}).catch(function() {
}).catch(function () {
row.status = row.status === "0" ? "1" : "0"
})
},
@ -400,7 +500,8 @@ export default {
status: "0",
remark: undefined,
postIds: [],
roleIds: []
roleIds: [],
belongSite: []
}
this.resetForm("form")
},
@ -455,6 +556,7 @@ export default {
this.form = response.data
this.postOptions = response.posts
this.roleOptions = response.roles
this.$set(this.form, "belongSite", response?.data?.belongSite ? JSON.parse(response.data.belongSite) : [])
this.$set(this.form, "postIds", response.postIds)
this.$set(this.form, "roleIds", response.roleIds)
this.open = true
@ -475,29 +577,30 @@ export default {
return "不能包含非法字符:< > \" ' \\\ |"
}
},
}).then(({ value }) => {
resetUserPwd(row.userId, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value)
})
}).catch(() => {})
}).then(({value}) => {
resetUserPwd(row.userId, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value)
})
}).catch(() => {
})
},
/** 分配角色操作 */
handleAuthRole: function(row) {
handleAuthRole: function (row) {
const userId = row.userId
this.$router.push("/system/user-auth/role/" + userId)
},
/** 提交按钮 */
submitForm: function() {
submitForm: function () {
this.$refs["form"].validate(valid => {
if (valid) {
if (this.form.userId != undefined) {
updateUser(this.form).then(response => {
updateUser({...this.form, belongSite: JSON.stringify(this.form.belongSite)}).then(response => {
this.$modal.msgSuccess("修改成功")
this.open = false
this.getList()
})
} else {
addUser(this.form).then(response => {
addUser({...this.form, belongSite: JSON.stringify(this.form.belongSite)}).then(response => {
this.$modal.msgSuccess("新增成功")
this.open = false
this.getList()
@ -509,12 +612,13 @@ export default {
/** 删除按钮操作 */
handleDelete(row) {
const userIds = row.userId || this.ids
this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function() {
this.$modal.confirm('是否确认删除用户编号为"' + userIds + '"的数据项?').then(function () {
return delUser(userIds)
}).then(() => {
this.getList()
this.$modal.msgSuccess("删除成功")
}).catch(() => {})
}).catch(() => {
})
},
/** 导出按钮操作 */
handleExport() {
@ -529,8 +633,7 @@ export default {
},
/** 下载模板操作 */
importTemplate() {
this.download('system/user/importTemplate', {
}, `user_template_${new Date().getTime()}.xlsx`)
this.download('system/user/importTemplate', {}, `user_template_${new Date().getTime()}.xlsx`)
},
// 文件上传中处理
handleFileUploadProgress(event, file, fileList) {
@ -541,7 +644,7 @@ export default {
this.upload.open = false
this.upload.isUploading = false
this.$refs.upload.clearFiles()
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", { dangerouslyUseHTMLString: true })
this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "导入结果", {dangerouslyUseHTMLString: true})
this.getList()
},
// 提交上传文件