工作栏

This commit is contained in:
白菜
2025-07-29 23:05:58 +08:00
parent 2b4022d1d0
commit ce9b4a4ca4
13 changed files with 2173 additions and 634 deletions

View File

@ -29,5 +29,6 @@
</script> </script>
<style lang="scss"> <style lang="scss">
@import '@/static/scss/index.scss' @import '@/static/scss/index.scss';
@import '@/uni_modules/uni-scss/index.scss';
</style> </style>

76
api/ems/site.js Normal file
View File

@ -0,0 +1,76 @@
import request from '@/utils/request'
export function getAllSites() {
return request({
url: '/ems/homePage/getAllSites',
method: 'get'
})
}
//获取BMS总览数据
export function getBMSOverView(data) {
return request({
url: `/ems/siteMonitor/getBMSOverView`, //?siteId=${siteId}
method: 'get',
data
})
}
//获取BMS电池簇总览数据
export function getBMSBatteryCluster(data) {
return request({
url: `/ems/siteMonitor/getBMSBatteryCluster`, //?siteId=${siteId}
method: 'get',
data
})
}
//获取电表数据
export function getAmmeterDataList(data) {
return request({
url: `/ems/siteMonitor/getAmmeterDataList`, //?siteId=${siteId}
method: 'get',
data
})
}
//获取pcs头部的设备信息
export function getRunningHeadInfo(data) {
return request({
url: `/ems/siteMonitor/runningHeadInfo`, //?siteId=${siteId}
method: 'get',
data
})
}
//获取pcs列表
export function getPcsDetailInfo(data) {
return request({
url: `/ems/siteMonitor/getPcsDetailInfo`, //?siteId=${siteId}
method: 'get',
data
})
}
//获取单体电池 电池堆列表数据
export function getStackNameList(data) {
return request({
url: `/ems/siteMonitor/getStackNameList`, //?siteId=${siteId}
method: 'get',
data
})
}
//获取单体电池 电池簇列表数据
export function getClusterNameList(data) {
return request({
url: `/ems/siteMonitor/getClusterNameList`, //?stackDeviceId=${stackDeviceId}&siteId=${siteId}
method: 'get',
data
})
}
//单体电池表格数据
export function getClusterDataInfoList(data) {
return request({
url: `/ems/siteMonitor/getClusterDataInfoList?`, //clusterDeviceId=${clusterDeviceId}&siteId=${siteId}&stackDeviceId=${stackDeviceId}&pageSize=${pageSize}&pageNum=${pageNum}
method: 'get',
data
})
}

View File

@ -1,108 +1,140 @@
{ {
"pages": [{ "pages": [{
"path": "pages/login", "path": "pages/login",
"style": { "style": {
"navigationBarTitleText": "登录" "navigationBarTitleText": "登录"
} }
}, { }, {
"path": "pages/register", "path": "pages/register",
"style": { "style": {
"navigationBarTitleText": "注册" "navigationBarTitleText": "注册"
} }
}, { }, {
"path": "pages/index", "path": "pages/index",
"style": { "style": {
"navigationBarTitleText": "移动端框架", "navigationBarTitleText": "移动端框架",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
}, { }, {
"path": "pages/work/index", "path": "pages/work/index",
"style": { "style": {
"navigationBarTitleText": "工作台" "navigationBarTitleText": "工作台"
} }
}, { }, {
"path": "pages/mine/index", "path": "pages/mine/index",
"style": { "style": {
"navigationBarTitleText": "我的" "navigationBarTitleText": "我的"
} }
}, { }, {
"path": "pages/mine/avatar/index", "path": "pages/mine/avatar/index",
"style": { "style": {
"navigationBarTitleText": "修改头像" "navigationBarTitleText": "修改头像"
} }
}, { }, {
"path": "pages/mine/info/index", "path": "pages/mine/info/index",
"style": { "style": {
"navigationBarTitleText": "个人信息" "navigationBarTitleText": "个人信息"
} }
}, { }, {
"path": "pages/mine/info/edit", "path": "pages/mine/info/edit",
"style": { "style": {
"navigationBarTitleText": "编辑资料" "navigationBarTitleText": "编辑资料"
} }
}, { }, {
"path": "pages/mine/pwd/index", "path": "pages/mine/pwd/index",
"style": { "style": {
"navigationBarTitleText": "修改密码" "navigationBarTitleText": "修改密码"
} }
}, { }, {
"path": "pages/mine/setting/index", "path": "pages/mine/setting/index",
"style": { "style": {
"navigationBarTitleText": "应用设置" "navigationBarTitleText": "应用设置"
} }
}, { }, {
"path": "pages/mine/help/index", "path": "pages/mine/help/index",
"style": { "style": {
"navigationBarTitleText": "常见问题" "navigationBarTitleText": "常见问题"
} }
}, { }, {
"path": "pages/mine/about/index", "path": "pages/mine/about/index",
"style": { "style": {
"navigationBarTitleText": "关于我们" "navigationBarTitleText": "关于我们"
} }
}, { }, {
"path": "pages/common/webview/index", "path": "pages/common/webview/index",
"style": { "style": {
"navigationBarTitleText": "浏览网页" "navigationBarTitleText": "浏览网页"
} }
}, { }, {
"path": "pages/common/textview/index", "path": "pages/common/textview/index",
"style": { "style": {
"navigationBarTitleText": "浏览文本" "navigationBarTitleText": "浏览文本"
} }
}, },
{ {
"path": "pages/ticket/index", "path": "pages/ticket/index",
"style": { "style": {
"navigationBarTitleText": "工单详情" "navigationBarTitleText": "工单详情"
} }
}], },
"tabBar": { {
"color": "#000000", "path": "pages/work/bmszl/index",
"selectedColor": "#000000", "style": {
"borderStyle": "white", "navigationBarTitleText": "BMS总览"
"backgroundColor": "#ffffff", }
"list": [{ },
"pagePath": "pages/index", {
"iconPath": "static/images/tabbar/home.png", "path": "pages/work/bmsdcc/index",
"selectedIconPath": "static/images/tabbar/home_.png", "style": {
"text": "首页" "navigationBarTitleText": "BMS电池簇"
}, { }
"pagePath": "pages/work/index", },
"iconPath": "static/images/tabbar/work.png", {
"selectedIconPath": "static/images/tabbar/work_.png", "path": "pages/work/db/index",
"text": "工作台" "style": {
}, { "navigationBarTitleText": "电表"
"pagePath": "pages/mine/index", }
"iconPath": "static/images/tabbar/mine.png", },
"selectedIconPath": "static/images/tabbar/mine_.png", {
"text": "我的" "path": "pages/work/pcs/index",
} "style": {
] "navigationBarTitleText": "PCS"
}, }
"globalStyle": { },
"navigationBarTextStyle": "black", {
"navigationBarTitleText": "EMS", "path": "pages/work/dtdc/index",
"navigationBarBackgroundColor": "#FFFFFF" "style": {
} "navigationBarTitleText": "单体电池",
} "onReachBottomDistance": 100
}
}
],
"tabBar": {
"color": "#000000",
"selectedColor": "#000000",
"borderStyle": "white",
"backgroundColor": "#ffffff",
"list": [{
"pagePath": "pages/index",
"iconPath": "static/images/tabbar/home.png",
"selectedIconPath": "static/images/tabbar/home_.png",
"text": "首页"
}, {
"pagePath": "pages/work/index",
"iconPath": "static/images/tabbar/work.png",
"selectedIconPath": "static/images/tabbar/work_.png",
"text": "工作台"
}, {
"pagePath": "pages/mine/index",
"iconPath": "static/images/tabbar/mine.png",
"selectedIconPath": "static/images/tabbar/mine_.png",
"text": "我的"
}]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "EMS",
"navigationBarBackgroundColor": "#FFFFFF"
}
}

View File

@ -1,165 +1,184 @@
<template> <template>
<view class="container"> <view class="container">
<view class="btn-list"> <view class="btn-list">
<uni-row > <uni-row>
<uni-col :span="12"> <uni-col :span="12">
<button type="default" class="btns" :class="{'active-btn' : active === 'undone'}" @click="changeTab('undone')">未处理</button> <button type="default" class="btns" :class="{'active-btn' : active === 'undone'}"
</uni-col> @click="changeTab('undone')">未处理</button>
<uni-col :span="12"> </uni-col>
<button type="default" class="btns" :class="{'active-btn' : active === 'done'}" @click="changeTab('done')">已处理</button> <uni-col :span="12">
</uni-col> <button type="default" class="btns" :class="{'active-btn' : active === 'done'}"
</uni-row> @click="changeTab('done')">已处理</button>
</view> </uni-col>
<scroll-view class="scroll-y" :scroll-y="true" @scrolltolower="lower" scrolltoupper="upper" > </uni-row>
<view class="content"> </view>
<view class="item-list" v-for="item in list" :key="item.ticketNo+'ticket'" @click="toDetail(item.id)"> <scroll-view class="scroll-y" :scroll-y="true" @scrolltolower="lower" scrolltoupper="upper">
<view class="item-title" :class="item.status === 1 ? 'done' : 'undone'" >工单号{{item.ticketNo}}</view> <view class="content">
<view class="item-content"> <view class="item-list" v-for="item in list" :key="item.ticketNo+'ticket'" @click="toDetail(item.id)">
<view class="item-info">工单标题:{{item.title}}</view> <view class="item-title" :class="item.status === 1 ? 'done' : 'undone'">工单{{item.ticketNo}}</view>
<view class="item-info">问题描述:{{item.content}}</view> <view class="item-content">
<view class="item-info">工单状态:{{ticketStatusOptions[item.status]}}</view> <view class="item-info">工单标题:{{item.title}}</view>
<view class="item-info">预期完成时间:{{item.expectedCompleteTime || '-'}}</view> <view class="item-info">问题描述:{{item.content}}</view>
<view class="item-info">处理人:{{item.workName || '-'}}</view> <view class="item-info">工单状态:{{ticketStatusOptions[item.status]}}</view>
</view> <view class="item-info">预期完成时间:{{item.expectedCompleteTime || '-'}}</view>
</view> <view class="item-info">处理人:{{item.workName || '-'}}</view>
<view v-if="list.length===0" style='text-align: center;margin-top:40px;color:#666;'>暂无数据</view> </view>
</view> </view>
</scroll-view> <view v-if="list.length===0" class="no-data">暂无数据</view>
</view> </view>
</template> </scroll-view>
<script> </view>
import {mapState} from 'vuex' </template>
import {listTicket} from 'api/ems/ticket' <script>
export default{ import {
computed:{ mapState
...mapState({ } from 'vuex'
ticketStatusOptions:(state)=>state.ems.ticketStatusOptions import {
}) listTicket
}, } from 'api/ems/ticket'
data(){ export default {
return { computed: {
active:'undone', ...mapState({
total:0, ticketStatusOptions: (state) => state.ems.ticketStatusOptions
list:[], })
pageNum:1, },
pageSize:10 data() {
} return {
}, active: 'undone',
methods:{ total: 0,
changeTab(active){ list: [],
if(active===this.active)return pageNum: 1,
this.active = active pageSize: 10
this.reset() }
this.init() },
}, methods: {
lower(){ changeTab(active) {
if(this.list.length>=this.total){ if (active === this.active) return
return console.log('数据已经加载完成') this.active = active
} this.reset()
this.pageNum+=1; this.init()
this.init().catch(()=>{this.pageNum-=1}) },
}, lower() {
init(){ if (this.list.length >= this.total) {
//0:'待处理', 1:'已处理', 2:'处理中' return console.log('数据已经加载完成')
let url=`/ticket/list?pageNum=${this.pageNum}&pageSize=${this.pageSize}` }
if(this.active === 'done'){ this.pageNum += 1;
url +=`&status=1` this.init().catch(() => {
}else{ this.pageNum -= 1
url +=`&status=0&status=2` })
} },
uni.showLoading() init() {
return listTicket(url).then(response=>{ //0:'待处理', 1:'已处理', 2:'处理中'
const data = JSON.parse(JSON.stringify(response?.rows || [])) let url = `/ticket/list?pageNum=${this.pageNum}&pageSize=${this.pageSize}`
this.list =this.list.concat(data) if (this.active === 'done') {
this.total = response?.total || 0 url += `&status=1`
}).finally(()=>{uni.hideLoading()}) } else {
}, url += `&status=0&status=2`
toDetail(id) { }
this.$tab.navigateTo(`/pages/ticket/index?id=${id}`) uni.showLoading()
}, return listTicket(url).then(response => {
reset(){ const data = JSON.parse(JSON.stringify(response?.rows || []))
this.list = [] this.list = this.list.concat(data)
this.total = 0 this.total = response?.total || 0
this.pageNum=1 }).finally(() => {
} uni.hideLoading()
}, })
onShow(){ },
this.reset() toDetail(id) {
this.init() this.$tab.navigateTo(`/pages/ticket/index?id=${id}`)
} },
} reset() {
</script> this.list = []
this.total = 0
<style scoped lang="scss"> this.pageNum = 1
.container{ }
position: relative; },
} onShow() {
uni-button:after{ this.reset()
border:none; this.init()
border-radius: 0; }
} }
.btn-list{ </script>
position: fixed;
top:0; <style scoped lang="scss">
left: 0; .container {
width:100%; position: relative;
z-index:2; }
.btns{
border-radius: 0; uni-button:after {
border:none; border: none;
border-bottom: 1px solid #eee; border-radius: 0;
width:100%; }
text-align: center;
font-size: 16px; .btn-list {
line-height: 50px; position: fixed;
background-color: #fff; top: 0;
&.active-btn{ left: 0;
background-color: #3a98ff; width: 100%;
color:#fff; z-index: 2;
}
} .btns {
} border-radius: 0;
.scroll-y{ border: none;
height: calc(100vh - var(--window-bottom) - var(--window-top)); border-bottom: 1px solid #eee;
z-index:1; width: 100%;
} text-align: center;
.content { font-size: 16px;
background-color: #ffffff; line-height: 50px;
padding:70px 20px 60px 20px; background-color: #fff;
}
.item-list{ &.active-btn {
border-radius: 7px; background-color: #3a98ff;
box-shadow: 0 0 10px rgba(0,0,0,.1),0 0 0 rgba(0,0,0,.5); color: #fff;
font-size: 16px; }
line-height: 24px; }
margin-bottom: 20px; }
border:1px solid #eee;
.item-title{ .scroll-y {
border-radius: 7px 7px 0 0; height: calc(100vh - var(--window-bottom) - var(--window-top));
font-size: 18px; z-index: 1;
border-bottom:1px solid #eee ; }
padding:10px 15px;
background-color: #FC6B69; .content {
color:#fff; background-color: #ffffff;
&.done{ padding: 70px 20px 60px 20px;
background-color: #05AEA3; }
}
} .item-list {
.item-content{ border-radius: 7px;
padding:15px 15px; box-shadow: 0 0 10px rgba(0, 0, 0, .1), 0 0 0 rgba(0, 0, 0, .5);
.item-info{ font-size: 14px;
margin-bottom:20px; line-height: 24px;
} margin-bottom: 20px;
} border: 1px solid #eee;
.item-content .item-info:last-child{ .item-title {
margin-bottom:0; border-radius: 7px 7px 0 0;
} font-size: 16px;
} border-bottom: 1px solid #eee;
.content .item-list:last-child{ padding: 10px 15px;
margin-bottom:0; background-color: #FC6B69;
} color: #fff;
&.done {
background-color: #05AEA3;
</style> }
}
.item-content {
padding: 15px 15px;
.item-info {
margin-bottom: 20px;
}
}
.item-content .item-info:last-child {
margin-bottom: 0;
}
}
.content .item-list:last-child {
margin-bottom: 0;
}
</style>

View File

@ -1,183 +1,195 @@
<template> <template>
<view class="container"> <view class="container">
<view class="item-lists"> <view class="item-lists">
<view class="title">工单号</view> <view class="title">工单号</view>
<view class="info">{{info.ticketNo || ''}}</view> <view class="info">{{info.ticketNo || ''}}</view>
</view> </view>
<view class="item-lists"> <view class="item-lists">
<view class="title">工单标题</view> <view class="title">工单标题</view>
<view class="info">{{info.title || ''}}</view> <view class="info">{{info.title || ''}}</view>
</view> </view>
<view class="item-lists"> <view class="item-lists">
<view class="title">提交用户</view> <view class="title">提交用户</view>
<view class="info">{{info.userName || '-'}}</view> <view class="info">{{info.userName || '-'}}</view>
</view> </view>
<view class="item-lists"> <view class="item-lists">
<view class="title">问题描述</view> <view class="title">问题描述</view>
<view class="info">{{info.content || ''}}</view> <view class="info">{{info.content || ''}}</view>
</view> </view>
<view class="item-lists"> <view class="item-lists">
<view class="title">工单状态</view> <view class="title">工单状态</view>
<view class="info">{{ticketStatusOptions[info.status] || ''}}</view> <view class="info">{{ticketStatusOptions[info.status] || ''}}</view>
</view> </view>
<view class="item-lists"> <view class="item-lists">
<view class="title">创建时间</view> <view class="title">创建时间</view>
<view class="info">{{info.createTime || '-'}}</view> <view class="info">{{info.createTime || '-'}}</view>
</view> </view>
<view class="item-lists"> <view class="item-lists">
<view class="title">预期完成时间</view> <view class="title">预期完成时间</view>
<view class="info">{{info.expectedCompleteTime || '-'}}</view> <view class="info">{{info.expectedCompleteTime || '-'}}</view>
</view> </view>
<view class="item-lists"> <view class="item-lists">
<view class="title">处理人</view> <view class="title">处理人</view>
<view class="info">{{info.workName || '-'}}</view> <view class="info">{{info.workName || '-'}}</view>
</view> </view>
<view class="item-lists"> <view class="item-lists">
<view class="title">上传图片</view> <view class="title">上传图片</view>
<view class="info"> <view class="info">
<uni-file-picker <uni-file-picker v-model="imgUrl" :auto-upload="false" :limit="1" file-mediatype="image"
v-model="imgUrl" file-extname="png,jpg" :image-styles="imageStyles" @select="select">
:auto-upload="false" </uni-file-picker>
:limit="1" </view>
file-mediatype="image" </view>
file-extname="png,jpg" <button class="button" type="primary" style="margin-top:30px;" :loading="loading" @click="submit">提交</button>
:image-styles="imageStyles" </view>
@select="select" </template>
>
</uni-file-picker> <script>
</view> import request from '@/utils/request'
</view> import {
<button class="button" type="primary" style="margin-top:30px;" :loading="loading" @click="submit">提交</button> getToken
</view> } from '@/utils/auth'
</template> import config from '@/config'
import {
<script> mapState
import request from '@/utils/request' } from 'vuex'
import { getToken } from '@/utils/auth' import {
import config from '@/config' getTicket,
import {mapState} from 'vuex' updateTicket
import {getTicket,updateTicket} from '@/api/ems/ticket' } from '@/api/ems/ticket'
export default{ export default {
computed:{ computed: {
...mapState({ ...mapState({
ticketStatusOptions:(state)=>state.ems.ticketStatusOptions ticketStatusOptions: (state) => state.ems.ticketStatusOptions
}) })
}, },
data(){ data() {
return { return {
imageStyles:{ imageStyles: {
width:150, width: 150,
height:100, height: 100,
}, },
loading:false, loading: false,
info:{}, info: {},
imgUrl:[], imgUrl: [],
} }
}, },
methods:{ methods: {
submit(){ submit() {
if(this.imgUrl.length === 0 || this.imgUrl[0].url === ''){ if (this.imgUrl.length === 0 || this.imgUrl[0].url === '') {
uni.showToast({ uni.showToast({
icon:'none', icon: 'none',
title: '请上传图片', title: '请上传图片',
duration: 2000 duration: 2000
}); });
return return
} }
this.loading = true this.loading = true
const images = this.imgUrl.map(item=>item.url) const images = this.imgUrl.map(item => item.url)
updateTicket({id:this.info.id,images:JSON.stringify(images)}).then(response=>{ updateTicket({
if(response.code === 200){ id: this.info.id,
uni.showToast({ images: JSON.stringify(images)
title: '提交成功', }).then(response => {
duration: 2000 if (response.code === 200) {
}); uni.showToast({
uni.switchTab({ title: '提交成功',
url: '/pages/index' duration: 2000
}); });
} uni.switchTab({
}).finally(()=>this.loading = false) url: '/pages/index'
});
}, }
// 获取上传状态 }).finally(() => this.loading = false)
select(e){
uni.uploadFile({ },
url: config.baseUrl+"/common/upload", // 获取上传状态
header: { select(e) {
Authorization: "Bearer " + getToken(), uni.uploadFile({
}, url: config.baseUrl + "/common/upload",
filePath: e.tempFilePaths[0], header: {
name: 'file',//对应接口的名称 Authorization: "Bearer " + getToken(),
complete: (res)=>{ },
console.log('返回数据',res); filePath: e.tempFilePaths[0],
if(res?.statusCode === 200 && res?.data){ name: 'file', //对应接口的名称
//图片上传成功 complete: (res) => {
if(res?.data){ console.log('返回数据', res);
const data=JSON.parse(res.data) if (res?.statusCode === 200 && res?.data) {
this.imgUrl = [ //图片上传成功
{name:data.newFileName || '',extname:data.originalFilename || '',url:data.url || ''} if (res?.data) {
] const data = JSON.parse(res.data)
}else{ this.imgUrl = [{
uni.showToast({ name: data.newFileName || '',
icon:'none', extname: data.originalFilename || '',
title: '图片上传失败', url: data.url || ''
duration: 2000 }]
}); } else {
this.imgUrl = [] uni.showToast({
} icon: 'none',
title: '图片上传失败',
}else{ duration: 2000
uni.showToast({ });
icon:'none', this.imgUrl = []
title: '图片上传失败', }
duration: 2000
}); } else {
} uni.showToast({
} icon: 'none',
}) title: '图片上传失败',
}, duration: 2000
}, });
mounted(){ }
uni.showLoading() }
getTicket(this.$route.query.id).then(response=>{ })
this.info = JSON.parse(JSON.stringify(response?.data || {})) },
const {images=''} = this.info },
this.info.images = JSON.parse(images) mounted() {
const imgList = this.info.images || [] uni.showLoading()
if(imgList.length>0){ getTicket(this.$route.query.id).then(response => {
this.imgUrl = imgList.map(item=>{ this.info = JSON.parse(JSON.stringify(response?.data || {}))
return {name:item || '',extname:item || '',url:item} const {
}) images = ''
} } = this.info
}).finally(()=>{ this.info.images = JSON.parse(images)
uni.hideLoading() const imgList = this.info.images || []
}) if (imgList.length > 0) {
} this.imgUrl = imgList.map(item => {
} return {
</script> name: item || '',
extname: item || '',
<style scoped lang="scss"> url: item
.container{ }
background-color: #ffffff; })
padding:20px 20px; }
} }).finally(() => {
.item-lists{ uni.hideLoading()
box-shadow: 0 0 10px rgba(0,0,0,.1),0 0 0 rgba(0,0,0,.5); })
border-radius: 5px; }
font-size: 16px; }
line-height: 20px; </script>
margin-bottom: 20px;
.title{ <style scoped lang="scss">
font-size: 18px; .container {
border-bottom:1px solid #eee ; background-color: #ffffff;
padding:10px 15px; padding: 20px 20px;
background-color: #e4e4e4; }
color:#333;
} .item-lists {
.info{ box-shadow: 0 0 10px rgba(0, 0, 0, .1), 0 0 0 rgba(0, 0, 0, .5);
padding:10px 15px; border-radius: 5px;
} font-size: 14px;
} line-height: 20px;
margin-bottom: 20px;
.title {
font-size: 16px;
border-bottom: 1px solid #eee;
padding: 10px 15px;
background-color: #e4e4e4;
color: #333;
}
.info {
padding: 10px 15px;
}
}
</style> </style>

238
pages/work/bmsdcc/index.vue Normal file
View File

@ -0,0 +1,238 @@
<template>
<view class="page-container">
<uni-collapse ref="collapse" accordion v-if="list.length > 0">
<uni-collapse-item v-for="(item,index) in list" :key="item.deviceId+'bmsdcc'" :open="index===0"
:title="`${index+1}#${item.deviceName}`" :class="item.workStatus === '0' ? 'running' :'danger'">
<view>
<uni-group mode="card" class="work-group">
<uni-grid :column="3" :showBorder="false">
<uni-grid-item>
<view class="grid-item-box">
<view class="title">工作状态</view>
<text class="text status">{{workStatusOptions[item.workStatus]}}</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<view class="title">与PCS通信</view>
<text
class="text">{{communicationStatusOptions[item.pcsCommunicationStatus]}}</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<view class="title">与EMS通信</view>
<text
class="text">{{communicationStatusOptions[item.emsCommunicationStatus]}}</text>
</view>
</uni-grid-item>
</uni-grid>
</uni-group>
<uni-group mode="card">
<uni-grid :column="3" :showBorder="false">
<uni-grid-item v-for="(infoDataItem,infoDataIndex) in infoData"
:key="infoDataIndex+'infoData'">
<view class="grid-item-box">
<view class="title">{{infoDataItem.label}}</view>
<text class="text">{{item[infoDataItem.attr]}}
<text v-if="infoDataItem.unit" v-html="infoDataItem.unit"></text>
</text>
</view>
</uni-grid-item>
</uni-grid>
</uni-group>
<uni-group mode="card" style="margin-bottom: 25px;">
<uni-table border stripe emptyText="暂无数据">
<!-- 表头行 -->
<uni-tr>
<uni-th align="center">名称</uni-th>
<uni-th align="center">单体平均值</uni-th>
<uni-th align="center">单体最小值</uni-th>
<uni-th align="center">单体最小值ID</uni-th>
<uni-th align="center">单体最大值</uni-th>
<uni-th align="center">单体最大值ID</uni-th>
</uni-tr>
<!-- 表格数据行 -->
<uni-tr v-for="(tableItem, tableIndex) in item.batteryDataList"
:key="tableIndex+'batteryDataList'">
<uni-td align="center"
v-html="`${tableItem.dataName}${unitObj[tableItem.dataName]}`"></uni-td>
<uni-td align="center">{{tableItem.avgData}}</uni-td>
<uni-td align="center">{{tableItem.minData}}</uni-td>
<uni-td align="center">{{tableItem.minDataID}}</uni-td>
<uni-td align="center">{{tableItem.maxData}}</uni-td>
<uni-td align="center">{{tableItem.maxDataID}}</uni-td>
</uni-tr>
</uni-table>
</uni-group>
</view>
</uni-collapse-item>
</uni-collapse>
<view class="no-data" v-else>
暂无数据
</view>
</view>
</template>
<script>
import {
getBMSBatteryCluster
} from '@/api/ems/site.js'
import {
mapState
} from 'vuex'
export default {
computed: {
...mapState({
workStatusOptions: (state) =>
state.ems.workStatusOptions,
communicationStatusOptions: (state) =>
state.ems.communicationStatusOptions,
})
},
data() {
return {
unitObj: {
'电压': 'V',
'温度': '&#8451;',
'SOC': '%'
},
list: [],
siteId: '',
infoData: [{
label: '簇电压',
attr: 'clusterVoltage',
unit: 'V'
},
{
label: '可充电量',
attr: 'chargeableCapacity',
unit: 'kWh'
},
{
label: '累计充电量',
attr: 'totalChargedCapacity',
unit: 'kWh'
},
{
label: '簇电流',
attr: 'clusterCurrent',
unit: 'A'
},
{
label: '可放电量',
attr: 'dischargeableCapacity',
unit: 'kWh'
},
{
label: '累计放电量',
attr: 'totalDischargedCapacity',
unit: 'kWh'
},
{
label: 'SOH',
attr: 'soh',
unit: '%'
},
{
label: '平均温度',
attr: 'averageTemperature',
unit: '&#8451;'
},
{
label: '绝缘电阻',
attr: 'insulationResistance',
unit: '&Omega;'
},
{
label: '当前SOC',
attr: 'currentSoc',
unit: '%'
},
]
}
},
mounted() {
uni.showLoading()
this.siteId = this.$route.query.siteId || ''
getBMSBatteryCluster({
siteId: this.siteId
}).then(response => {
this.list = response?.data || []
if (this.list.length > 0) {
this.$nextTick(() => {
setTimeout(() => {
this.$refs.collapse.resize()
uni.hideLoading()
}, 100)
})
} else {
uni.hideLoading()
}
}).catch(() => {
uni.hideLoading()
})
}
}
</script>
<style lang="scss" scoped>
.page-container {}
.grid-item-box {
flex: 1;
// position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10px;
background-color: #fff;
.title {
font-size: 14px;
color: #666;
}
.text {
margin-top: 10px;
font-size: 16px;
font-weight: 500;
color: #666;
overflow-wrap: anywhere;
}
}
::v-deep {
.uni-collapse-item__wrap {
background-color: #eee;
}
.running {
.uni-collapse-item__title-text {
color: #05AEA3;
}
.status {
color: #05AEA3;
}
}
.danger {
.uni-collapse-item__title-text {
color: #FC6B69;
}
.status {
color: #FC6B69;
}
}
}
</style>

234
pages/work/bmszl/index.vue Normal file
View File

@ -0,0 +1,234 @@
<template>
<view class="page-container">
<uni-collapse ref="collapse" accordion v-if="list.length > 0">
<uni-collapse-item v-for="(item,index) in list" :key="item.deviceId+'bmszl'" :open="index===0"
:title="`${index+1}#${item.deviceName}`" :class="item.workStatus === '0' ? 'running' :'danger'">
<view>
<uni-group mode="card" class="work-group">
<uni-grid :column="3" :showBorder="false">
<uni-grid-item>
<view class="grid-item-box">
<view class="title">工作状态</view>
<text class="text status">{{workStatusOptions[item.workStatus]}}</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<view class="title">与PCS通信</view>
<text
class="text">{{communicationStatusOptions[item.pcsCommunicationStatus]}}</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<view class="title">与EMS通信</view>
<text
class="text">{{communicationStatusOptions[item.emsCommunicationStatus]}}</text>
</view>
</uni-grid-item>
</uni-grid>
</uni-group>
<uni-group mode="card">
<uni-grid :column="3" :showBorder="false">
<uni-grid-item v-for="(infoDataItem,infoDataIndex) in infoData"
:key="infoDataIndex+'infoData'">
<view class="grid-item-box">
<view class="title">{{infoDataItem.label}}</view>
<text class="text">{{item[infoDataItem.attr]}}
<text v-if="infoDataItem.unit" v-html="infoDataItem.unit"></text>
</text>
</view>
</uni-grid-item>
</uni-grid>
</uni-group>
<uni-group mode="card" style="margin-bottom: 25px;">
<uni-table border stripe emptyText="暂无数据">
<!-- 表头行 -->
<uni-tr>
<uni-th align="center">簇号</uni-th>
<uni-th align="center">簇电压</uni-th>
<uni-th align="center">簇电流</uni-th>
<uni-th align="center">簇SOC</uni-th>
<uni-th align="center">单体最高电压</uni-th>
<uni-th align="center">单体最低电压</uni-th>
<uni-th align="center">单体最高温度</uni-th>
<uni-th align="center">单体最低温度</uni-th>
</uni-tr>
<!-- 表格数据行 -->
<uni-tr v-for="(tableItem, tableIndex) in item.batteryDataList"
:key="tableIndex+'batteryDataList'">
<uni-td align="center">{{tableItem.clusterId}}</uni-td>
<uni-td align="center">{{tableItem.clusterVoltage}}V</uni-td>
<uni-td align="center">{{tableItem.clusterCurrent}}A</uni-td>
<uni-td align="center">{{tableItem.currentSoc}}%</uni-td>
<uni-td align="center">{{tableItem.maxCellVoltage}}V</uni-td>
<uni-td align="center">{{tableItem.minCellVoltage}}V</uni-td>
<uni-td align="center">{{tableItem.maxCellTemp}}&#8451;</uni-td>
<uni-td align="center">{{tableItem.minCellTemp}}&#8451;</uni-td>
</uni-tr>
</uni-table>
</uni-group>
</view>
</uni-collapse-item>
</uni-collapse>
<view class="no-data" v-else>
暂无数据
</view>
</view>
</template>
<script>
import {
getBMSOverView
} from '@/api/ems/site.js'
import {
mapState
} from 'vuex'
export default {
computed: {
...mapState({
workStatusOptions: (state) =>
state.ems.workStatusOptions,
communicationStatusOptions: (state) =>
state.ems.communicationStatusOptions,
})
},
data() {
return {
list: [],
siteId: '',
infoData: [{
label: '电池堆总电压',
attr: 'stackVoltage',
unit: 'V'
},
{
label: '可充电量',
attr: 'availableChargeCapacity',
unit: 'kWh'
},
{
label: '累计充电量',
attr: 'totalChargeCapacity',
unit: 'kWh'
},
{
label: '电池堆总电流',
attr: 'stackCurrent',
unit: 'A'
},
{
label: '可放电量',
attr: 'availableDischargeCapacity',
unit: 'kWh'
},
{
label: '累计放电量',
attr: 'totalDischargeCapacity',
unit: 'kWh'
},
{
label: 'SOH',
attr: 'stackSoh',
unit: '%'
},
{
label: '平均温度',
attr: 'operatingTemp',
unit: '&#8451;'
},
{
label: '绝缘电阻',
attr: 'stackInsulationResistance',
unit: '&Omega;'
},
{
label: '当前SOC',
attr: 'stackSoc',
unit: '%'
},
]
}
},
mounted() {
uni.showLoading()
this.siteId = this.$route.query.siteId || ''
getBMSOverView({
siteId: this.siteId
}).then(response => {
this.list = response?.data || []
if (this.list.length > 0) {
this.$nextTick(() => {
setTimeout(() => {
this.$refs.collapse.resize()
uni.hideLoading()
}, 100)
})
} else {
uni.hideLoading()
}
}).catch(() => {
uni.hideLoading()
})
}
}
</script>
<style lang="scss" scoped>
.grid-item-box {
flex: 1;
// position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10px;
background-color: #fff;
.title {
font-size: 14px;
color: #666;
}
.text {
margin-top: 10px;
font-size: 16px;
font-weight: 500;
color: #666;
overflow-wrap: anywhere;
}
}
::v-deep {
.uni-collapse-item__wrap {
background-color: #eee;
}
.running {
.uni-collapse-item__title-text {
color: #05AEA3;
}
.status {
color: #05AEA3;
}
}
.danger {
.uni-collapse-item__title-text {
color: #FC6B69;
}
.status {
color: #FC6B69;
}
}
}
</style>

211
pages/work/db/index.vue Normal file
View File

@ -0,0 +1,211 @@
<template>
<view class="page-container">
<uni-collapse ref="collapse">
<!-- 总表 -->
<uni-collapse-item open :class="zbInfo.emsCommunicationStatus !== '0' ? 'danger' :'running'">
<template v-slot:title>
<view class="title-row">
<view class="title">{{`1#${zbInfo.deviceName || ''}`}}</view>
<view class="msg">
<view>{{communicationStatusOptions[zbInfo.emsCommunicationStatus] || ''}}</view>
<view>数据更新时间{{zbInfo.dataUpdateTime || ''}}</view>
</view>
</view>
</template>
<uni-group :title=" item.category" mode="card" v-for="(item,index) in zbInfo.loadDataDetailInfo"
:key="index+'zbInfo'">
<uni-row>
<uni-col :span="8">
<view>/kWh</view>
</uni-col>
<uni-col :span="16">
<view>{{item.totalKwh}}</view>
</uni-col>
</uni-row>
<uni-row>
<uni-col :span="8">
<view>/kWh</view>
</uni-col>
<uni-col :span="16">
<view>{{item.peakKwh}}</view>
</uni-col>
</uni-row>
<uni-row>
<uni-col :span="8">
<view>/kWh</view>
</uni-col>
<uni-col :span="16">
<view>{{item.highKwh}}</view>
</uni-col>
</uni-row>
<uni-row>
<uni-col :span="8">
<view>/kWh</view>
</uni-col>
<uni-col :span="16">
<view>{{item.flatKwh}}</view>
</uni-col>
</uni-row>
<uni-row>
<uni-col :span="8">
<view>/kWh</view>
</uni-col>
<uni-col :span="16">
<view>{{item.valleyKwh}}</view>
</uni-col>
</uni-row>
</uni-group>
</uni-collapse-item>
<!-- 储能表 -->
<uni-collapse-item open :class="cnbInfo.emsCommunicationStatus !== '0' ? 'danger' :'running'">
<template v-slot:title>
<view class="title-row">
<view class="title">{{`2#${cnbInfo.deviceName || ''}`}}</view>
<view class="msg">
<view>{{communicationStatusOptions[cnbInfo.emsCommunicationStatus] || ''}}</view>
<view>数据更新时间{{cnbInfo.dataUpdateTime || ''}}</view>
</view>
</view>
</template>
<uni-group :title="item.category" mode="card" v-for="(item,index) in cnbInfo.meteDataDetailInfo"
:key="index+'cnbInfo'">
<uni-row>
<uni-col :span="8">
<view>有功功率</view>
</uni-col>
<uni-col :span="16">
<view>{{item.activePower}}</view>
</uni-col>
</uni-row>
<uni-row>
<uni-col :span="8">
<view>无功功率</view>
</uni-col>
<uni-col :span="16">
<view>{{item.reactivePower}}</view>
</uni-col>
</uni-row>
</uni-group>
</uni-collapse-item>
</uni-collapse>
</view>
</template>
<script>
import {
getAmmeterDataList
} from '@/api/ems/site.js'
import {
mapState
} from 'vuex'
export default {
computed: {
...mapState({
communicationStatusOptions: (state) =>
state.ems.communicationStatusOptions,
})
},
data() {
return {
siteId: '',
zbInfo: {},
cnbInfo: {},
}
},
mounted() {
uni.showLoading()
this.siteId = this.$route.query.siteId || ''
getAmmeterDataList({
siteId: this.siteId
}).then(response => {
this.zbInfo = JSON.parse(JSON.stringify(response?.data?.ammeterLoadData || {}));
this.cnbInfo = JSON.parse(JSON.stringify(response?.data?.ammeterMeteData || {}));
this.$nextTick(() => {
setTimeout(() => {
this.$refs.collapse.resize()
uni.hideLoading()
}, 100)
})
}).catch(() => {
uni.hideLoading()
})
}
}
</script>
<style lang="scss" scoped>
.title-row {
padding: 0 15px;
position: relative;
height: 50px;
.title {
font-weight: 500;
line-height: 50px;
}
.msg {
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
text-align: right;
}
}
::v-deep {
.uni-group__title {
background-color: #959595;
.uni-group__title-text {
color: #fff;
}
}
.uni-collapse-item__wrap-content {
.uni-group--card:last-child {
margin-bottom: 25px;
}
}
// row-行样式
.uni-group__content {
padding: 10px 15px;
.uni-row {
padding: 5px 0;
}
}
// 折叠面板内容区域背景颜色
.uni-collapse-item__wrap {
background-color: #eee;
}
// 运行状态颜色区分
.running {
.uni-collapse-item__title-text {
color: #05AEA3;
}
.title-row {
color: #05AEA3;
}
}
.danger {
.uni-collapse-item__title-text {
color: #FC6B69;
}
.title-row {
color: #FC6B69;
}
}
}
</style>

290
pages/work/dtdc/index.vue Normal file
View File

@ -0,0 +1,290 @@
<template>
<view class="container">
<view class="uni-pa-5 search-container">
<uni-forms ref="form">
<uni-forms-item label="电池堆">
<uni-data-select :clear="false" v-model="search.stackId" :localdata="stackOptions"
@change="changeStackId"></uni-data-select>
</uni-forms-item>
<uni-forms-item label="电池簇">
<uni-data-select :clear="false" v-model="search.clusterId"
:localdata="clusterOptions"></uni-data-select>
</uni-forms-item>
</uni-forms>
<view class="button-group" style="text-align: center;">
<button type="default" size="mini" @click="onReset">重置</button>
<button type="primary" size="mini" @click="onSearch" style="margin-left: 20px;">搜索</button>
</view>
</view>
<view class="list-container">
<view class="no-data" v-if="list.length === 0">暂无数据</view>
<uni-list v-else>
<uni-list-item v-for="(item,index) in list" :key="index+'dtdc'">
<template v-slot:header>
<view class="list-header">
单体编号:{{item.deviceId}}
<button type="warn" size="mini" class="charts">图表</button>
</view>
</template>
<template v-slot:body>
<view class="list-body">
<uni-row>
<uni-col :span="8">
<view>簇号</view>
</uni-col>
<uni-col :span="14">
<view class="right">{{item.clusterDeviceId}}</view>
</uni-col>
</uni-row>
<uni-row>
<uni-col :span="8">
<view>电压V</view>
</uni-col>
<uni-col :span="14">
<view class="right color">{{item.voltage}}
</view>
</uni-col>
</uni-row>
<uni-row>
<uni-col :span="8">
<view>温度</view>
</uni-col>
<uni-col :span="14">
<view class="right color">
{{item.temperature}}
</view>
</uni-col>
</uni-row>
<uni-row>
<uni-col :span="8">
<view>SOC%</view>
</uni-col>
<uni-col :span="14">
<view class="right color">{{item.soc}}</view>
</uni-col>
</uni-row>
<uni-row>
<uni-col :span="8">
<view>SOH%</view>
</uni-col>
<uni-col :span="14">
<view class="right color">{{item.soh}}</view>
</uni-col>
</uni-row>
</view>
</template>
</uni-list-item>
</uni-list>
</view>
</view>
</template>
<script>
import {
getStackNameList,
getClusterNameList,
getClusterDataInfoList,
} from '@/api/ems/site.js'
import {
mapState
} from 'vuex'
export default {
computed: {
...mapState({
workStatusOptions: (state) =>
state.ems.workStatusOptions,
communicationStatusOptions: (state) =>
state.ems.communicationStatusOptions,
})
},
data() {
return {
pageNum: 1,
pageSize: 20,
total: 0,
stackOptions: [],
clusterOptions: [],
search: {
stackId: '',
clusterId: ''
},
list: [],
siteId: '',
}
},
methods: {
onReachBottom() {
console.log('触底了')
this.pageNum += 1 //每次搜索从1开始搜索
this.getTableData()
},
// 搜索
onSearch() {
this.pageNum = 1 //每次搜索从1开始搜索
this.getTableData(true)
},
// 重置
// 清空搜索栏选中数据
// 清空电池簇列表,保留电池堆列表
onReset() {
this.search = {
stackId: '',
clusterId: ''
}
this.clusterOptions = []
this.pageNum = 1
this.getTableData(true)
},
changeStackId(val) {
if (val) {
console.log('选择了电池堆,需要获取对应的电池簇', val, this.search.stackId)
this.search.clusterId = ''
this.getClusterList()
}
},
getStackList() {
getStackNameList({
siteId: this.siteId
}).then(response => {
this.stackOptions = JSON.parse(JSON.stringify(response?.data || [])).map(item => {
return {
text: item.deviceName,
value: item.id
}
})
})
},
getClusterList() {
getClusterNameList({
stackDeviceId: this.search.stackId,
siteId: this.siteId
}).then(response => {
this.clusterOptions = JSON.parse(JSON.stringify(response?.data || [])).map(item => {
return {
text: item.deviceName,
value: item.id
}
})
}).finally(() => {})
},
//表格数据
getTableData(reset = false) {
if (!reset && this.list.length === this.total) return
uni.showLoading()
if (reset) {
this.list = []
this.total = 0
}
const {
stackId: stackDeviceId,
clusterId: clusterDeviceId
} = this.search
const {
siteId,
pageNum,
pageSize
} = this
getClusterDataInfoList({
stackDeviceId,
clusterDeviceId,
siteId,
pageNum,
pageSize
}).then(response => {
this.list = this.list.concat(response?.rows || []);
this.total = response?.total || 0
}).finally(() => {
uni.hideLoading()
})
},
},
mounted() {
// uni.showLoading()
this.siteId = this.$route.query.siteId || ''
this.getStackList()
this.getTableData(true)
}
}
</script>
<style lang="scss" scoped>
.container {
position: relative;
// position: fixed;
// width: 100%;
// height: 100%;
// overflow-y: auto;
.search-container {
height: 170px;
background: #ffffff;
position: sticky;
z-index: 2;
top: 0;
left: 0;
width: 100%;
border-bottom: 1px solid #eee;
}
.list-container {
// z-index: 10;
padding-top: 20px;
padding-bottom: 50px;
background: #ffffff;
::v-deep {
.uni-list-item__container {
display: block;
}
.uni-list--border-top,
.uni-list--border-bottom,
.uni-list--border::after {
background-color: transparent;
}
}
.list-header {
background-color: #05AEA3;
color: #fff;
padding: 10px 15px;
border-radius: 5px 5px 0 0;
position: relative;
.charts {
position: absolute;
top: 50%;
right: 15px;
transform: translateY(-50%);
background-color: #ff7300;
}
}
.list-body {
padding: 10px 15px;
border: 1px solid #eee;
border-top: none;
border-radius: 0 0 5px 5px;
font-size: 14px;
color: #666;
.right {
color: #000;
}
.color {
color: #007aff;
}
.uni-row {
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
}
}
}
}
</style>

View File

@ -1,173 +1,134 @@
<template> <template>
<view class="work-container"> <view class="work-container">
<!-- 站点选择列表 -->
<uni-section title="站点选择" type="line" titleFontSize='16px' class="uni-pa-5">
<!-- 宫格组件 --> <uni-data-select :clear="false" v-model="siteId" :localdata="siteList"
<uni-section title="系统管理" type="line"></uni-section> @change="selectedSite"></uni-data-select>
<view class="grid-body"> </uni-section>
<uni-grid :column="4" :showBorder="false" @change="changeGrid"> <!-- 菜单 -->
<uni-grid-item> <!-- <uni-section title="工作台" type="line" titleFontSize='16px'></uni-section> -->
<view class="grid-item-box"> <view class="grid-body">
<uni-icons type="person-filled" size="30"></uni-icons> <uni-grid :column="4" :showBorder="false" @change="toDetail">
<text class="text">用户管理</text> <uni-grid-item v-for="(item,index) in gridList" :index="index" :key="index+'work'">
</view> <view class="grid-item-box">
</uni-grid-item> <uni-icons :type="item.icon" size="30"></uni-icons>
<uni-grid-item> <text class="text">{{item.text}}</text>
<view class="grid-item-box"> </view>
<uni-icons type="staff-filled" size="30"></uni-icons> </uni-grid-item>
<text class="text">角色管理</text>
</view> </uni-grid>
</uni-grid-item> </view>
<uni-grid-item> </view>
<view class="grid-item-box"> </template>
<uni-icons type="color" size="30"></uni-icons>
<text class="text">菜单管理</text> <script>
</view> import {
</uni-grid-item> getAllSites
<uni-grid-item> } from '@/api/ems/site.js'
<view class="grid-item-box"> export default {
<uni-icons type="settings-filled" size="30"></uni-icons> data() {
<text class="text">部门管理</text> return {
</view> siteList: [],
</uni-grid-item> siteId: '', //选择的站点ID
<uni-grid-item> gridList: [{
<view class="grid-item-box"> page: 'bmszl',
<uni-icons type="heart-filled" size="30"></uni-icons> icon: 'map-filled',
<text class="text">岗位管理</text> text: 'BMS总览',
</view> },
</uni-grid-item> {
<uni-grid-item> page: 'bmsdcc',
<view class="grid-item-box"> icon: 'map',
<uni-icons type="bars" size="30"></uni-icons> text: 'BMS电池簇',
<text class="text">字典管理</text> },
</view> {
</uni-grid-item> page: 'pcs',
<uni-grid-item> icon: 'flag-filled',
<view class="grid-item-box"> text: 'PCS',
<uni-icons type="gear-filled" size="30"></uni-icons> },
<text class="text">参数设置</text> {
</view> page: 'db',
</uni-grid-item> icon: 'smallcircle',
<uni-grid-item> text: '电表',
<view class="grid-item-box"> },
<uni-icons type="chat-filled" size="30"></uni-icons> {
<text class="text">通知公告</text> page: 'dtdc',
</view> icon: 'smallcircle-filled',
</uni-grid-item> text: '单体电池',
<uni-grid-item> }
<view class="grid-item-box"> ]
<uni-icons type="wallet-filled" size="30"></uni-icons> }
<text class="text">日志管理</text> },
</view> methods: {
</uni-grid-item> toDetail(e) {
</uni-grid> const {
</view> index
</view> } = e.detail
</template> this.$tab.navigateTo(`/pages/work/${this.gridList[index].page}/index?siteId=${this.siteId}`)
},
<script> selectedSite(id) {
export default { this.siteId = id
data() { }
return { },
current: 0, // 页面切换不会重新调用如果希望每次切换页面都重新调接口使用onShow
swiperDotIndex: 0, mounted() {
data: [{ getAllSites().then(response => {
image: '/static/images/banner/banner01.jpg' console.log('返回数据', response)
}, const data = response?.data || []
{ this.siteList = data.map(item => {
image: '/static/images/banner/banner02.jpg' return {
}, text: item.siteName,
{ value: item.siteId,
image: '/static/images/banner/banner03.jpg' id: item.id
} }
] })
} // 设置默认展示的站点
}, data.length > 0 && (this.siteId = data[0].siteId)
methods: { })
clickBannerItem(item) { }
console.info(item) }
}, </script>
changeSwiper(e) {
this.current = e.detail.current <style lang="scss" scoped>
}, /* #ifndef APP-NVUE */
changeGrid(e) { page {
this.$modal.showToast('模块建设中~') display: flex;
} flex-direction: column;
} box-sizing: border-box;
} background-color: #fff;
</script> min-height: 100%;
height: auto;
<style lang="scss" scoped> }
/* #ifndef APP-NVUE */
page { view {
display: flex; font-size: 14px;
flex-direction: column; line-height: inherit;
box-sizing: border-box; }
background-color: #fff;
min-height: 100%; /* #endif */
height: auto;
} .text {
text-align: center;
view { font-size: 26rpx;
font-size: 14px; margin-top: 10rpx;
line-height: inherit; }
}
/* #endif */ .grid-item-box {
flex: 1;
.text { /* #ifndef APP-NVUE */
text-align: center; display: flex;
font-size: 26rpx; /* #endif */
margin-top: 10rpx; flex-direction: column;
} align-items: center;
justify-content: center;
.grid-item-box { padding: 15px 0;
flex: 1; }
/* #ifndef APP-NVUE */
display: flex; .uni-margin-wrap {
/* #endif */ width: 690rpx;
flex-direction: column; width: 100%;
align-items: center; ;
justify-content: center; }
padding: 15px 0;
}
@media screen and (min-width: 500px) {}
.uni-margin-wrap { </style>
width: 690rpx;
width: 100%;
;
}
.swiper {
height: 300rpx;
}
.swiper-box {
height: 150px;
}
.swiper-item {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
justify-content: center;
align-items: center;
color: #fff;
height: 300rpx;
line-height: 300rpx;
}
@media screen and (min-width: 500px) {
.uni-swiper-dot-box {
width: 400px;
/* #ifndef APP-NVUE */
margin: 0 auto;
/* #endif */
margin-top: 8px;
}
.image {
width: 100%;
}
}
</style>

390
pages/work/pcs/index.vue Normal file
View File

@ -0,0 +1,390 @@
<template>
<view class="page-container">
<!-- 顶部6个数据 -->
<uni-grid class="info-grid" :column="2" :showBorder="false" style="margin-bottom: 10px;">
<uni-grid-item v-for="(item,index) in runningHeadData" :key="index+'head'">
<view class="grid-item-box">
<view class="title">{{item.title}}</view>
<text class="text">{{runningHeadInfo[item.attr] || '-'}}</text>
</view>
</uni-grid-item>
</uni-grid>
<uni-collapse ref="collapse" accordion v-if="list.length > 0">
<uni-collapse-item v-for="(item,index) in list" :key="item.deviceId+'pcs'" :open="index===0"
:class="item.workStatus === '1' ? 'danger' : item.workStatus === '2' ? 'close' : 'running'">
<template v-slot:title>
<view class="title-row">
<view class="title">{{index+1}}#{{item.deviceName || ''}}</view>
<view class="msg">
<view>{{communicationStatusOptions[item.communicationStatus] || ''}}</view>
<view>数据更新时间{{item.dataUpdateTime || ''}}</view>
</view>
</view>
</template>
<view>
<uni-group mode="card">
<uni-grid :column="4" :showBorder="false">
<uni-grid-item>
<view class="grid-item-box">
<view class="title">工作状态</view>
<text class="text"
:class="item.workStatus === '0' ? 'status-running' : 'status-danger'">{{workStatusOptions[item.workStatus]}}</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<view class="title">并网状态</view>
<text class="text">{{gridStatusOptions[item.gridStatus]}}</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<view class="title">设备状态</view>
<text class="text"
:class="item.deviceStatus === '0' ? 'status-running' : 'status-danger'">{{deviceStatusOptions[item.deviceStatus]}}</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<view class="title">控制模式</view>
<text class="text">{{controlModeOptions[item.controlMode]}}</text>
</view>
</uni-grid-item>
</uni-grid>
</uni-group>
<!-- infoData -->
<uni-group mode="card"
:style="{marginBottom:!item.pcsBranchInfoList || item.pcsBranchInfoList.length === 0 ?'25px' : ''}">
<uni-grid :column="2" showBorder class="info-grid">
<uni-grid-item v-for="(infoDataItem,infoDataIndex) in infoData"
:key="infoDataIndex+'infoData'">
<view class="grid-item-box">
<view class="title">{{infoDataItem.label}}</view>
<text class="text">{{item[infoDataItem.attr]}}
<text v-if="infoDataItem.unit" v-html="infoDataItem.unit"></text>
</text>
</view>
</uni-grid-item>
</uni-grid>
</uni-group>
<!-- 支路 -->
<uni-group class="pcs-branch-group" :title="`支路${pcsBranchIndex+1}`" mode="card"
v-for="(pcsBranchItem,pcsBranchIndex) in item.pcsBranchInfoList"
:key="pcsBranchIndex+'pcsBranchInfoList'">
<uni-grid :column="3" :showBorder="false" class="info-grid">
<uni-grid-item>
<view class="grid-item-box">
<view class="title">直流功率</view>
<text class="text">{{pcsBranchItem.dcPower}}kW</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<view class="title">直流电压</view>
<text class="text">{{pcsBranchItem.dcVoltage}}V</text>
</view>
</uni-grid-item>
<uni-grid-item>
<view class="grid-item-box">
<view class="title">直流电流</view>
<text class="text">{{pcsBranchItem.dcCurrent}}A</text>
</view>
</uni-grid-item>
</uni-grid>
</uni-group>
</view>
</uni-collapse-item>
</uni-collapse>
<view class="no-data" v-else>
暂无数据
</view>
</view>
</template>
<script>
import {
getRunningHeadInfo,
getPcsDetailInfo
} from '@/api/ems/site.js'
import {
mapState
} from 'vuex'
export default {
computed: {
...mapState({
workStatusOptions: (state) =>
state.ems.workStatusOptions,
communicationStatusOptions: (state) =>
state.ems.communicationStatusOptions,
deviceStatusOptions: (state) =>
state.ems.deviceStatusOptions,
gridStatusOptions: (state) =>
state.ems.gridStatusOptions,
controlModeOptions: (state) =>
state.ems.controlModeOptions,
})
},
data() {
return {
runningHeadData: [{
title: '实时有功功率kW',
bgColor: '#FFF2CB',
attr: 'totalActivePower'
}, {
title: '实时无功功率kVar',
bgColor: '#CBD6FF',
attr: 'totalReactivePower'
}, {
title: '电池堆SOC',
bgColor: '#DCCBFF',
attr: 'soc'
}, {
title: '电池堆SOH',
bgColor: '#FFD4CB',
attr: 'soh'
}, {
title: '今日充电量kWh',
bgColor: '#FFD6F8',
attr: 'dayChargedCap'
}, {
title: '今日放电量kWh',
bgColor: '#E1FFCA',
attr: 'dayDisChargedCap'
}],
runningHeadInfo: {},
list: [],
siteId: '',
infoData: [{
label: '总交流有功电率',
attr: 'totalActivePower',
unit: 'kW'
},
{
label: '总交流无功电率',
attr: 'totalReactivePower',
unit: 'kVar'
},
{
label: '当天交流充电量',
attr: 'dailyAcChargeEnergy',
unit: 'kWh'
},
{
label: '当天交流放电量',
attr: 'dailyAcDischargeEnergy',
unit: 'kWh'
},
{
label: '总交流视在功率',
attr: 'totalApparentPower',
unit: 'kVA'
},
{
label: '总交流功率因数',
attr: 'totalPowerFactor',
unit: ''
},
{
label: 'PCS模块温度',
attr: 'pcsModuleTemperature',
unit: '&#8451;'
},
{
label: 'PCS环境温度',
attr: 'pcsEnvironmentTemperature',
unit: '&#8451;'
},
{
label: 'A相电压',
attr: 'aPhaseVoltage',
unit: 'V'
},
{
label: 'A相电流',
attr: 'aPhaseCurrent',
unit: 'A'
},
{
label: 'B相电压',
attr: 'bPhaseVoltage',
unit: 'V'
},
{
label: 'B相电流',
attr: 'bPhaseCurrent',
unit: 'A'
},
{
label: 'C相电压',
attr: 'cPhaseVoltage',
unit: 'V'
},
{
label: 'C相电流',
attr: 'cPhaseCurrent',
unit: 'A'
},
{
label: '交流频率',
attr: 'acFrequency',
unit: 'Hz'
}
]
}
},
mounted() {
uni.showLoading()
this.siteId = this.$route.query.siteId || ''
getRunningHeadInfo({
siteId: this.siteId
}).then(response => {
this.runningHeadInfo = response?.data || {}
})
getPcsDetailInfo({
siteId: this.siteId
}).then(response => {
this.list = response?.data || []
if (this.list.length > 0) {
this.$nextTick(() => {
setTimeout(() => {
this.$refs.collapse.resize()
uni.hideLoading()
}, 100)
})
} else {
uni.hideLoading()
}
}).catch(() => {
uni.hideLoading()
})
}
}
</script>
<style lang="scss" scoped>
.title-row {
padding: 0 15px;
position: relative;
height: 50px;
.title {
font-weight: 500;
line-height: 50px;
}
.msg {
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
text-align: right;
}
}
.grid-item-box {
flex: 1;
// position: relative;
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
flex-direction: column;
align-items: center;
justify-content: center;
padding: 10px;
background-color: #fff;
.title {
font-size: 14px;
color: #666;
}
.text {
margin-top: 10px;
font-size: 16px;
font-weight: 500;
color: #666;
overflow-wrap: anywhere;
}
.status-danger {
color: #FC6B69;
}
.status-running {
color: #05AEA3;
}
}
::v-deep {
.info-grid {
.uni-grid-item {
height: 80px !important;
.grid-item-box {
padding: 0;
}
}
}
.uni-collapse-item__wrap {
background-color: #eee;
}
.running {
.uni-collapse-item__title-text {
color: #05AEA3;
}
.title-row {
color: #05AEA3;
}
}
.danger {
.uni-collapse-item__title-text {
color: #FC6B69;
}
.title-row {
color: #FC6B69;
}
}
.close {
.uni-collapse-item__title-text {
color: #666666;
}
.title-row {
color: #666666;
}
}
// 支路样式
.pcs-branch-group {
.uni-group__title {
background-color: #959595;
.uni-group__title-text {
color: #fff;
}
}
.uni-group__content {
padding: 0;
}
&.uni-group--card:last-child {
margin-bottom: 25px;
}
}
}
</style>

View File

@ -88,3 +88,15 @@
} }
} }
} }
// 暂无数据通用样式
.no-data{
color:#999;
text-align: center;
line-height: 100px;
height: 100px;
background-color: #fff;
font-size: 18px;
}

View File

@ -1,6 +1,69 @@
const ems={ const ems = {
state:{ state: {
ticketStatusOptions:{0:'待处理', 1:'已处理', 2:'处理中'},//工单处理状态 workStatusOptions: {
} '0': '正常',
} '1': '异常',
'2': '停止'
}, //工作状态
deviceStatusOptions: {
'0': '在线',
'1': '离线',
'2': '维修中'
}, //设备状态
gridStatusOptions: {
'0': '并网',
'1': '未并网'
}, //并网状态
controlModeOptions: {
'0': '远程',
'1': '本地'
}, //控制模式
warnOptions: {
0: '正常',
1: '中断',
2: '不在线',
3: '异常'
}, //告警状态
communicationStatusOptions: {
'0': '正常',
'1': '通讯中断',
'2': '异常'
}, //通讯状态
workModeOptions: {
'0': '正常',
'1': '停止'
}, //工作模式
alarmLevelOptions: {
'A': '提示',
'B': '一般',
'C': '严重',
'D': '紧急'
}, //告警等级
alarmStatusOptions: {
'0': '待处理',
'1': '已处理',
'2': '处理中'
}, //告警状态
deviceTypeOptions: {
'TCP': 'TCP',
'RTU': 'RTU'
}, //设备类型
ticketStatusOptions: {
0: '待处理',
1: '已处理',
2: '处理中'
}, //工单处理状态
strategyStatusOptions: {
'0': '未启用',
'1': '已运行',
'2': '已暂停',
'3': '禁用',
'4': '删除'
}, //策略状态
chargeStatusOptions: {
'1': '充电',
'2': '待机'
}, //冲放状态
}
}
export default ems export default ems