86 Commits

Author SHA1 Message Date
2765bcab10 故障告警,搜索栏 告警等级宽度调整 2026-01-29 20:08:33 +08:00
b55d9e2d5c Merge branch 'develop' into single-develop 2026-01-29 20:07:34 +08:00
29ab53056a 故障告警,搜索栏 告警等级宽度调整 2026-01-29 19:57:10 +08:00
0c32439146 Merge branch 'develop' into single-develop 2026-01-28 21:45:43 +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
058879ec45 Merge branch 'develop' into single-develop 2026-01-26 23:36:47 +08:00
4d29de93a1 大数据图片更新 2026-01-26 23:30:01 +08:00
445e9dfc9f 大数据图片改为切换模式 2026-01-26 22:40:57 +08:00
3a26f6312b 更新注释 2026-01-25 17:02:21 +08:00
138b0753af Merge branch 'develop' into single-develop 2026-01-25 16:56:29 +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
085f6fd252 Merge branch 'develop' into single-develop 2026-01-24 21:19:27 +08:00
142de3102b 大数据图片更新 2026-01-24 21:14:43 +08:00
d3e51322ab Merge branch 'develop' into single-develop 2026-01-24 10:37:31 +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
81f8f75d7e pcs开关机状态判断更新 2026-01-23 20:06:47 +08:00
fccddab04a Merge branch 'develop' into single-develop 2026-01-23 19:52:13 +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
1b712a70f6 Merge branch 'develop' into single-develop 2026-01-21 14:42:02 +08:00
c1c411e48a 用户归属站点 2026-01-21 14:37:39 +08:00
43153a791d 用户归属站点 2026-01-21 14:05:09 +08:00
5d84972b8a 菜单 2026-01-16 16:08:54 +08:00
b122ab35ab Merge branch 'develop' into single-develop
# Conflicts:
#	src/router/ems.js
2026-01-16 15:59:17 +08:00
11111d035b 优化 2026-01-13 16:38:21 +08:00
80f07876c6 Merge branch 'develop' into single-develop 2026-01-12 14:17:32 +08:00
ab9bb1e85d pcs\bmszl\bmsdcc 标题颜色规则更新 2026-01-12 14:15:21 +08:00
bef8f01d0d pcs开关机接口参数更新 2026-01-08 17:14:57 +08:00
b469190d9f Merge branch 'develop' into single-develop 2026-01-08 16:59:47 +08:00
4079c40e5d workStatus、deviceStatus枚举更新,pcs开关机接口参数更新 2026-01-08 16:59:15 +08:00
e98b4ed287 Merge branch 'develop' into single-develop 2025-12-31 17:25:47 +08:00
4ebd5f0988 样式优化 2025-12-31 17:23:08 +08:00
a0095b4054 pcs设备类型,新增pcs设备配置选项,策略配置时间问题修复 2025-12-31 17:15:26 +08:00
6140ca8f14 Merge branch 'develop' into single-develop 2025-12-26 21:01:54 +08:00
84bc29410a 新增设备:TCP设备新增从站地址
策略配置:新增放电状态、可输入负数、开始、结束时间组件更换
2025-12-26 20:19:20 +08:00
a3d6cf7c55 Merge branch 'develop' into single-develop 2025-12-19 21:51:51 +08:00
f3fda19c64 保护方案 2025-12-19 21:49:19 +08:00
6fb706b528 云下展示pcs开关机按钮 2025-12-18 16:37:59 +08:00
579920e007 Merge branch 'develop' into single-develop 2025-12-18 16:35:34 +08:00
9a8247f833 云上隐藏pcs开关机按钮 2025-12-18 16:26:57 +08:00
d9eeee106f Merge branch 'develop' into single-develop 2025-12-16 13:48:09 +08:00
c4c79aaa64 设备列表顶部下载按钮展示 2025-12-16 13:44:48 +08:00
c90f4f5766 Merge branch 'develop' into single-develop 2025-12-16 11:14:50 +08:00
0966813c25 设备列表,隐藏顶部上传、下载按钮,pcs开机关机按钮显示条件优化 2025-12-16 11:03:59 +08:00
4a4d26f018 生产、云下环境变量配置 2025-12-15 17:41:29 +08:00
1a11c67aad test 环境变量配置 2025-12-15 14:42:27 +08:00
71fd48918d Merge branch 'develop' into single-develop
# Conflicts:
#	src/assets/styles/common.scss
2025-12-12 17:47:57 +08:00
dd4fa36597 优化 2025-12-12 17:38:26 +08:00
9b14d96e24 pcs开关机,设备列表上传、下载 2025-12-11 17:59:34 +08:00
34d9e038e6 合并代码 2025-12-10 15:09:33 +08:00
ac54ce999e ems、箱型图 2025-12-10 15:00:12 +08:00
f49efb5edd ems接口、综合查询 2025-12-09 18:25:36 +08:00
97f9b3ff0e ems 2025-12-08 17:00:18 +08:00
674a0c6c33 ems、收益报表 2025-12-08 16:58:43 +08:00
b4c49c3e58 Merge branch 'develop' into single-develop 2025-12-05 09:49:54 +08:00
7f3d02b8fb 点位、报警点位 2025-12-05 09:46:31 +08:00
9cfce671a6 Merge branch 'develop' into single-develop 2025-12-05 09:16:54 +08:00
cd8871d45a 点位上传、下载 2025-12-04 17:46:11 +08:00
11d44de513 表格内容fong-size调小1px 2025-11-28 17:53:34 +08:00
87e3db9f0f 云下使用深色主题区分云上 2025-11-28 15:21:42 +08:00
4132d8e539 合并develop最新代码 2025-11-28 15:18:27 +08:00
78eb81549b 设备列表上传 2025-11-28 15:11:34 +08:00
65f0e92296 2025-11-20紧急优化内容修复 2025-11-27 15:58:23 +08:00
9a585e97db 2025-11-20紧急优化内容-动环、消防 2025-11-27 15:51:13 +08:00
7fb6d1aa47 2025-11-20紧急优化内容 2025-11-26 17:50:06 +08:00
1378947a9e 设备监控-点位清单 2025-11-25 17:56:12 +08:00
28176ce052 Merge branch 'develop' into single-develop 2025-11-13 16:53:19 +08:00
0b2e7d9b86 mqtt新增站点、qos 2025-11-13 16:49:39 +08:00
54 changed files with 5737 additions and 4357 deletions

View File

@ -5,8 +5,9 @@ VUE_APP_TITLE = 上动新能源-EMS管理系统
NODE_ENV = 'production'
# EMS管理系统/生产环境
VUE_APP_BASE_API= 'http://1.15.120.242:8089'
VUE_APP_BASE_API= 'http://127.0.0.1:8089'
# EMS管理系统/生产环境 图片拼接地址
VUE_APP_IMG_URL = 'http://1.15.120.242:8089'
VUE_APP_IMG_URL = 'http://127.0.0.1:8089'

View File

@ -7,6 +7,7 @@ export function getDzjkHomeView(siteId) {
method: 'get'
})
}
//站点首页 冲放曲线
export function getSevenChargeData({siteId, startDate, endDate}) {
return request({
@ -14,6 +15,7 @@ export function getSevenChargeData({siteId,startDate,endDate}) {
method: 'get'
})
}
// 获取站点包含的设备种类 用来判断单站监控设备监控的菜单栏展示
export function getSiteAllDeviceCategory(siteId) {
return request({
@ -21,6 +23,15 @@ export function getSiteAllDeviceCategory(siteId) {
method: 'get'
})
}
//EMS
export function getEmsDataList(siteId) {
return request({
url: `/ems/siteMonitor/getEmsDataList?siteId=${siteId}`,
method: 'get',
})
}
//获取pcs、实时运行头部的设备信息
export function getRunningHeadInfo(siteId) {
return request({
@ -28,6 +39,7 @@ export function getRunningHeadInfo(siteId) {
method: 'get'
})
}
//获取pcs列表
export function getPcsDetailInfo(siteId) {
return request({
@ -59,6 +71,7 @@ export function getStackNameList(siteId) {
method: 'get'
})
}
//获取单体电池 电池簇列表数据
export function getClusterNameList({stackDeviceId, siteId}) {
return request({
@ -66,6 +79,7 @@ export function getClusterNameList({stackDeviceId,siteId}) {
method: 'get'
})
}
//单体电池表格数据
export function getClusterDataInfoList({siteId, stackDeviceId, clusterDeviceId, batteryId, pageSize, pageNum}) {
return request({
@ -73,6 +87,7 @@ export function getClusterDataInfoList({siteId, stackDeviceId, clusterDeviceId,b
method: 'get'
})
}
// 单体电池图表
//http://localhost:8089/ems/siteMonitor/getSingleBatteryData?clusterDeviceId=BMSC01&siteId=021_FXX_01&deviceId=001&startDate=2025-07-11&endDate=2025-07-18
export function getSingleBatteryData({siteId, deviceId, clusterDeviceId, startDate, endDate}) {
@ -90,6 +105,23 @@ export function getCoolingDataList(siteId) {
})
}
//获取动环数据
export function getDhDataList(siteId) {
return request({
url: `/ems/siteMonitor/getDhDataList?siteId=${siteId}`,
method: 'get'
})
}
//获取消防数据
export function getXfDataList(siteId) {
return request({
url: `/ems/siteMonitor/getXfDataList?siteId=${siteId}`,
method: 'get'
})
}
//获取电表数据
export function getAmmeterDataList(siteId) {
return request({
@ -99,7 +131,16 @@ export function getAmmeterDataList(siteId) {
}
// 故障告警
export function getAlarmDetailList({status,siteId, deviceId, alarmLevel, alarmStartTime, alarmEndTime,pageSize,pageNum}) {
export function getAlarmDetailList({
status,
siteId,
deviceId,
alarmLevel,
alarmStartTime,
alarmEndTime,
pageSize,
pageNum
}) {
return request({
url: `/ems/siteAlarm/getAlarmDetailList?siteId=${siteId}&status=${status}&deviceId=${deviceId}&alarmLevel=${alarmLevel}&alarmStartTime=${alarmStartTime}&alarmEndTime=${alarmEndTime}&pageSize=${pageSize}&pageNum=${pageNum}`,
method: 'get'
@ -114,6 +155,7 @@ export function createTicketNo(data) {
data
})
}
// 概率统计
//获取概率统计 电量指标接口
export function getElectricData({siteId, startDate, endDate}) {
@ -122,6 +164,7 @@ export function getElectricData({siteId,startDate,endDate}) {
method: 'get'
})
}
//获取pcs列表
export function getPcsNameList(siteId) {
return request({
@ -129,6 +172,7 @@ export function getPcsNameList(siteId) {
method: 'get'
})
}
//pcs曲线
export function getPCSData({siteId, startTime, endTime, dataType}) {
return request({
@ -136,6 +180,7 @@ export function getPCSData({siteId,startTime,endTime,dataType}) {
method: 'get'
})
}
//电池堆曲线
export function getStackData({siteId, startTime, endTime, dataType}) {
return request({
@ -143,6 +188,7 @@ export function getStackData({siteId,startTime,endTime,dataType}) {
method: 'get'
})
}
//电池温度
export function getClusterData({siteId, stackId, clusterId, dateTime, pageNum, pageSize}) {
return request({
@ -154,33 +200,37 @@ export function getClusterData({siteId,stackId,clusterId,dateTime,pageNum,pageSi
// 实时运行
//储能
export function storagePower(siteId) {
export function storagePower(siteId, startTime, endTime) {
return request({
url: `/ems/siteMonitor/runningGraph/storagePower?siteId=${siteId}`,
url: `/ems/siteMonitor/runningGraph/storagePower?siteId=${siteId}&startDate=${startTime}&endDate=${endTime}`,
method: 'get'
})
}
//poc温度
export function pcsMaxTemp(siteId) {
export function pcsMaxTemp(siteId, startTime, endTime) {
return request({
url: `/ems/siteMonitor/runningGraph/pcsMaxTemp?siteId=${siteId}`,
url: `/ems/siteMonitor/runningGraph/pcsMaxTemp?siteId=${siteId}&startDate=${startTime}&endDate=${endTime}`,
method: 'get'
})
}
// 电池平均soc
export function batteryAveSoc(siteId) {
export function batteryAveSoc(siteId, startTime, endTime) {
return request({
url: `/ems/siteMonitor/runningGraph/batteryAveSoc?siteId=${siteId}`,
url: `/ems/siteMonitor/runningGraph/batteryAveSoc?siteId=${siteId}&startDate=${startTime}&endDate=${endTime}`,
method: 'get'
})
}
// 电池平均温度
export function batteryAveTemp(siteId) {
export function batteryAveTemp(siteId, startTime, endTime) {
return request({
url: `/ems/siteMonitor/runningGraph/batteryAveTemp?siteId=${siteId}`,
url: `/ems/siteMonitor/runningGraph/batteryAveTemp?siteId=${siteId}&startDate=${startTime}&endDate=${endTime}`,
method: 'get'
})
}
// 功率曲线
export function getPowerData({siteId, startDate, endDate}) {
return request({
@ -196,6 +246,7 @@ export function getLoadNameList(siteId) {
method: 'get'
})
}
// 电表报表
export function getAmmeterData({siteId, startTime, endTime, pageSize, pageNum}) {
return request({
@ -204,6 +255,14 @@ export function getAmmeterData({siteId,startTime,endTime, pageSize, pageNum}) {
})
}
// 电价报表
export function getAmmeterRevenueData(data) {
return request({
url: `/ems/statsReport/getAmmeterRevenueData`,
method: 'get',
params: data
})
}
//策略列表
export function strategyRunningList(siteId) {
@ -212,6 +271,7 @@ export function strategyRunningList(siteId) {
method: 'get'
})
}
//停止策略
export function stopStrategyRunning(id) {
return request({
@ -219,6 +279,7 @@ export function stopStrategyRunning(id) {
method: 'get'
})
}
// 获取所有主策略
export function getMainStrategyList() {
return request({
@ -226,6 +287,7 @@ export function getMainStrategyList() {
method: 'get'
})
}
//获取所有辅助策略
export function getAuxStrategyList() {
return request({
@ -233,6 +295,7 @@ export function getAuxStrategyList() {
method: 'get'
})
}
//配置策略
export function configStrategy(data) {
return request({
@ -250,6 +313,7 @@ export function getTempNameList({siteId,strategyId}) {
method: 'get',
})
}
//获取模板详情
///strategy/temp/list?templateId=1
export function getStrategyTempDetail(templateId) {
@ -258,6 +322,7 @@ export function getStrategyTempDetail(templateId) {
method: 'get',
})
}
//新增模板
export function addStrategyTemp(data) {
return request({
@ -266,6 +331,7 @@ export function addStrategyTemp(data) {
data
})
}
export function editStrategyTemp(data) {
return request({
url: `/strategy/temp`,
@ -273,6 +339,7 @@ export function editStrategyTemp(data) {
data
})
}
//http://localhost:8089/strategy/temp/{id}
export function deleteStrategyTemp(id) {
return request({
@ -288,6 +355,7 @@ export function timeConfigList({siteId,strategyId}) {
method: 'get',
})
}
//保存时间配置
// http://localhost:8089/strategy/timeConfig
export function setTimeConfigList(data) {
@ -297,6 +365,7 @@ export function setTimeConfigList(data) {
data
})
}
// 策略曲线图
//http://localhost:8089/strategy/curve/curveList?strategyId=1&siteId=021_FXX_01
export function curveList({siteId, strategyId}) {

View File

@ -1,4 +1,5 @@
import request from '@/utils/request'
// 站点列表
export function getSiteInfoList({siteName, startTime, endTime, pageSize, pageNum}) {
return request({
@ -8,10 +9,11 @@ export function getSiteInfoList({siteName,startTime, endTime,pageSize,pageNum})
}
// 设备列表
export function getDeviceInfoList({siteId,pageSize,pageNum}) {
export function getDeviceInfoList(data) {
return request({
url: `/ems/siteConfig/getDeviceInfoList?siteId=${siteId}&pageSize=${pageSize}&pageNum=${pageNum}`,
method: 'get'
url: `/ems/siteConfig/getDeviceInfoList`,
method: 'get',
params: data
})
}
@ -39,6 +41,7 @@ export function addDevice(data) {
data
})
}
// 编辑设备
export function updateDevice(data) {
return request({
@ -47,6 +50,7 @@ export function updateDevice(data) {
data
})
}
// 删除设备
export function deleteService(id) {
return request({
@ -54,6 +58,16 @@ export function deleteService(id) {
method: 'delete',
})
}
//pcs开、关机
export function updateDeviceStatus(data) {
return request({
url: `/ems/siteConfig/updateDeviceStatus`,
method: 'post',
data
})
}
// 获取上级设备id列表
export function getParentDeviceId({siteId, deviceCategory}) {
return request({
@ -61,6 +75,7 @@ export function getParentDeviceId({siteId,deviceCategory}) {
method: 'get',
})
}
//获取所有设备
export function getDeviceList(siteId) {
return request({
@ -70,10 +85,11 @@ export function getDeviceList(siteId) {
}
//获取设备点位table
export function getDevicePointList({siteId,deviceId,deviceCategory,parentId,pageNum,pageSize,dataPointName='',sortMethod,sortData,dataPoint,lower,upper,ipAddress,ipPort}) {
export function getDevicePointList(data) {
return request({
url: `/ems/siteConfig/getDevicePointList?siteId=${siteId}&deviceId=${deviceId}&pageNum=${pageNum}&pageSize=${pageSize}&deviceCategory=${deviceCategory}&dataPointName=${dataPointName}&parentId=${parentId}&dataPoint=${dataPoint}&lower=${lower}&upper=${upper}&pageNum=${pageNum}&sortMethod=${sortMethod}&sortData=${sortData}&ipAddress=${ipAddress}&ipPort=${ipPort}`,
url: `/ems/siteConfig/getDevicePointList`,
method: 'get',
params: data
})
}
@ -137,6 +153,7 @@ export function exportPointList(data) {
data
})
}
// 点位导入
export function importPointList(data) {
return request({
@ -147,20 +164,21 @@ export function importPointList(data) {
}
//mqtt
export function getMqttList({pageSize,pageNum,mqttTopic,topicName}) {
export function getMqttList({pageSize, pageNum, mqttTopic, topicName, siteId}) {
return request({
url: `/ems/mqttConfig/list?pageSize=${pageSize}&pageNum=${pageNum}&mqttTopic=${mqttTopic}&topicName=${topicName}`,
url: `/ems/mqttConfig/list?pageSize=${pageSize}&pageNum=${pageNum}&mqttTopic=${mqttTopic}&topicName=${topicName}&siteId=${siteId}`,
method: 'get',
})
}
export function getMqttDetail(id) {
return request({
url: `/ems/mqttConfig/${id}`,
method: 'get',
})
}
export function addMqtt(data) {
return request({
url: `/ems/mqttConfig`,
@ -168,6 +186,7 @@ export function addMqtt(data) {
data
})
}
export function editMqtt(data) {
return request({
url: `/ems/mqttConfig`,
@ -175,6 +194,7 @@ export function editMqtt(data) {
data
})
}
export function deleteMqtt(id) {
return request({
url: `/ems/mqttConfig/${id}`,

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

@ -9,11 +9,13 @@
padding: 24px;
font-size: 12px;
}
//除去顶部信息(如搜索栏、站点基本信息等)外的 白色背景内容区域
.ems-content-container {
background-color: #ffffff;
margin-top: 24px;
}
//需要设置内padding的白色背景区域
.ems-content-container-padding {
padding: 24px;
@ -27,42 +29,49 @@
font-size: 12px;
background: #F1F5FB;
position: relative;
.card-title {
font-weight: 500;
color: #333333;
}
.el-button--text {
color: #666666;
}
}
}
.common-card-container-body-no-padding {
.el-card__body {
padding: 0;
}
}
.common-card-container-no-title-bg {
.el-card__header {
background-color: transparent;
}
}
//单站监控 设备监控card公共样式
.sbjk-card-container {
.el-card__header {
background-color: transparent;
padding: 10px 14px;
padding: 5px 14px;
color: #ffffff;
position: relative;
border-radius: 5px 5px 0 0;
.large-title {
font-size: 20px;
font-size: 18px;
font-weight: 500;
line-height: 40px;
padding: 0 50px 0 11px;
display: inline-block;
vertical-align: middle;
}
.info {
display: inline-block;
vertical-align: middle;
@ -70,33 +79,57 @@
font-size: 12px;
line-height: 20px;
}
.el-button--text {
color: #666666;
}
.alarm {
position: absolute;
right: 25px;
top: 50%;
transform: translateY(-50%);
.alarm-icon {
font-size: 22px;
color: #fff;
display: block;
cursor: pointer;
}
}
}
//红色背景颜色标题
&.warning-card-container {
.el-card__header {
background-color: #fc6b69;
background-color: #b64040; //#fc6b69;
}
.work-status {
color: #b64040 !important;;
}
}
//绿色背景颜色标题
&.running-card-container {
.el-card__header {
background-color: #05aea3;
background-color: #40b6a5; //#05aea3;
}
.work-status {
color: #40b6a5 !important;
}
}
//灰色背景颜色标题
&.timing-card-container {
.el-card__header {
background-color: #666666;
}
.work-status {
color: #666666 !important;;
}
}
}
@ -105,11 +138,13 @@
&.common-card-container .el-card__header {
padding-top: 0;
padding-bottom: 0;
.time-range-header {
height: 40px;
display: flex;
justify-content: space-between;
align-items: center;
.card-title {
line-height: 40px;
}
@ -118,22 +153,23 @@
}
//描述样式 PCS、BMS总览、BMS电池簇页面公共样式
.descriptions-main {
padding: 24px;
position: relative;
&.descriptions-main-bg-color {
background-color: #f1f5fc;
.el-descriptions__body {
background-color: #f1f5fc;
}
}
.el-descriptions-item__cell[colspan='1'] {
width: 25%
}
.el-descriptions__body .el-descriptions__table {
.descriptions-direction {
line-height: 19px;
@ -141,35 +177,76 @@
font-size: 16px;
font-weight: 500;
}
.descriptions-label {
line-height: 14px;
color: #666666;
font-size: 12px;
}
.danger {
color: #FC6B69;
}
.save {
color: #09ADA3;
}
.keep {
color: #3C81FF;
}
}
}
//电表、液冷公共样式
.device-info-row {
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
border-left: 1px solid #eee;
border-top: 1px solid #eee;
.device-info-col {
padding: 10px 0;
text-align: center;
font-size: 12px;
color: #666666;
line-height: 14px;
border-bottom: 1px solid #eee;
border-right: 1px solid #eee;
.left {
}
.right {
display: block;
font-weight: 500;
font-size: 16px;
line-height: 18px;
margin-top: 10px;
}
}
}
//公共表格样式
.el-table {
font-size: 13px;
}
.common-table.el-table {
color: #333333;
.el-table__header-wrapper th, .el-table__fixed-header-wrapper th {
background: #f1f5fc;
border-bottom: none;
.table-head {
color: #515a6e;
}
}
.warning-status {
color: #FC6B69;
&.circle::before {
content: "";
display: inline-block;
@ -185,22 +262,27 @@
//二、三级菜单栏样式
.ems-second-menu {
width: fit-content;
.el-menu-item {
line-height: 40px;
height: 40px;
padding: 0;
}
&.el-menu--horizontal > .el-menu-item.is-active, &.el-menu--horizontal > .el-menu-item {
border-bottom: none !important;
}
.el-menu-item.is-active {
background: #0366c1 !important;
}
}
.ems-third-menu-container {
position: relative;
padding-left: 160px;
background-color: #ffffff;
.ems-third-menu {
border-right: none;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
@ -215,10 +297,12 @@
width: 125px;
text-align: center;
}
.el-menu-item:hover {
background: #67b1ff !important;
color: #ffffff !important;
}
.el-menu-item.is-active {
background: #409eff !important;
}
@ -227,7 +311,6 @@
}
//按钮栏 选中样式
.ems-btns-group {
.activeBtn {
@ -242,6 +325,7 @@
.select-container.el-form--inline .el-form-item {
margin-right: 15px;
}
//红色背景颜色按钮
.alarm-btn, .alarm-btn:hover, .alarm-btn:focus {
background-color: #FC6B69;

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

@ -2,6 +2,7 @@
<div class="time-range">
<el-date-picker
v-model="dateRange"
:class="miniTimePicker ? 'mini-date-picker' : ''"
type="daterange"
range-separator=""
start-placeholder="开始时间"
@ -10,16 +11,47 @@
: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>
<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 {
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])
@ -63,7 +95,8 @@ export default {
},
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 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
@ -82,19 +115,35 @@ export default {
<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;
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;
}
}
}

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,12 +1,17 @@
<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"/>
<div class="right-menu">
<template v-if="device!=='mobile'">
<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"/>
@ -32,11 +37,11 @@
</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"/>
</div>
</div>
<BigDataPopup ref="bigDataPopup"/>
</div>
</template>
@ -48,6 +53,7 @@ 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(() => {
})
}
}
}
@ -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;
}

View File

@ -37,49 +37,130 @@ export const dzjk=[
component: () => import('@/views/ems/dzjk/sbjk/ssyx/index.vue'),
name: 'DzjkSbjkSsyx',
hidden: true,
meta: { title: '实时运行',breadcrumb: false,activeMenu: '/dzjk/sbjk',activeSecondMenuName:'DzjkSbjk',deviceCategory:'SSYX'},
meta: {
title: '实时运行',
breadcrumb: false,
activeMenu: '/dzjk/sbjk',
activeSecondMenuName: 'DzjkSbjk',
deviceCategory: 'SSYX'
},
},
{
path: 'ems',
component: () => import('@/views/ems/dzjk/sbjk/ems/index.vue'),
name: 'DzjkSbjkEms',
hidden: true,
meta: {
title: 'EMS',
breadcrumb: false,
activeMenu: '/dzjk/sbjk',
activeSecondMenuName: 'DzjkSbjk',
deviceCategory: 'EMS'
},
},
{
path: 'pcs',
component: () => import('@/views/ems/dzjk/sbjk/pcs/index.vue'),
name: 'DzjkSbjkPcs',
hidden: true,
meta: { title: 'PCS',breadcrumb: false,activeMenu: '/dzjk/sbjk',activeSecondMenuName:'DzjkSbjk',deviceCategory:'PCS'},
meta: {
title: 'PCS',
breadcrumb: false,
activeMenu: '/dzjk/sbjk',
activeSecondMenuName: 'DzjkSbjk',
deviceCategory: 'PCS'
},
},
{
path: 'bmszl',
component: () => import('@/views/ems/dzjk/sbjk/bmszl/index.vue'),
name: 'DzjkSbjkBmszl',
hidden: true,
meta: { title: 'BMS总览',breadcrumb: false,activeMenu: '/dzjk/sbjk',activeSecondMenuName:'DzjkSbjk', deviceCategory:'STACK'},
meta: {
title: 'BMS总览',
breadcrumb: false,
activeMenu: '/dzjk/sbjk',
activeSecondMenuName: 'DzjkSbjk',
deviceCategory: 'STACK'
},
},
{
path: 'bmsdcc',
component: () => import('@/views/ems/dzjk/sbjk/bmsdcc/index.vue'),
name: 'DzjkSbjkBmsdcc',
hidden: true,
meta: { title: 'BMS电池簇',breadcrumb: false,activeMenu: '/dzjk/sbjk',activeSecondMenuName:'DzjkSbjk',deviceCategory:'CLUSTER'},
meta: {
title: 'BMS电池簇',
breadcrumb: false,
activeMenu: '/dzjk/sbjk',
activeSecondMenuName: 'DzjkSbjk',
deviceCategory: 'CLUSTER'
},
},
{
path: 'dtdc',
component: () => import('@/views/ems/dzjk/sbjk/dtdc/index.vue'),
name: 'DzjkSbjkDtdc',
hidden: true,
meta: { title: '单体电池',breadcrumb: false,activeMenu: '/dzjk/sbjk',activeSecondMenuName:'DzjkSbjk',deviceCategory:'BATTERY'},
meta: {
title: '单体电池',
breadcrumb: false,
activeMenu: '/dzjk/sbjk',
activeSecondMenuName: 'DzjkSbjk',
deviceCategory: 'BATTERY'
},
},
{
path: 'db',
component: () => import('@/views/ems/dzjk/sbjk/db/index.vue'),
name: 'DzjkSbjkDb',
hidden: true,
meta: { title: '电表',breadcrumb: false,activeMenu: '/dzjk/sbjk',activeSecondMenuName:'DzjkSbjk',deviceCategory:'AMMETER'},
meta: {
title: '电表',
breadcrumb: false,
activeMenu: '/dzjk/sbjk',
activeSecondMenuName: 'DzjkSbjk',
deviceCategory: 'AMMETER'
},
},
{
path: 'yl',
component: () => import('@/views/ems/dzjk/sbjk/yl/index.vue'),
name: 'DzjkSbjkYl',
hidden: true,
meta: { title: '液冷',breadcrumb: false,activeMenu: '/dzjk/sbjk',activeSecondMenuName:'DzjkSbjk',deviceCategory:'COOLING'},
meta: {
title: '液冷',
breadcrumb: false,
activeMenu: '/dzjk/sbjk',
activeSecondMenuName: 'DzjkSbjk',
deviceCategory: 'COOLING'
},
},
{
path: 'dh',
component: () => import('@/views/ems/dzjk/sbjk/dh/index.vue'),
name: 'DzjkSbjkDh',
hidden: true,
meta: {
title: '动环',
breadcrumb: false,
activeMenu: '/dzjk',
activeSecondMenuName: 'DzjkSbjk',
deviceCategory: 'DH'
},
},
{
path: 'xf',
component: () => import('@/views/ems/dzjk/sbjk/xf/index.vue'),
name: 'DzjkSbjkXf',
hidden: true,
meta: {
title: '消防',
breadcrumb: false,
activeMenu: '/dzjk',
activeSecondMenuName: 'DzjkSbjk',
deviceCategory: 'XF'
},
}
]
},
@ -103,42 +184,72 @@ export const dzjk=[
component: () => import('@/views/ems/dzjk/tjbb/gltj/index.vue'),
name: 'DzjkTjbbGltj',
hidden: true,
meta: { title: '概率统计',breadcrumb: false,activeMenu: '/dzjk/tjbb',activeSecondMenuName:'DzjkTjbb'},
meta: {
title: '运行统计',
breadcrumb: false,
activeMenu: '/dzjk/tjbb',
activeSecondMenuName: 'DzjkTjbb'
},
},
{
path: 'glqx',
component: () => import('@/views/ems/dzjk/tjbb/glqx/index.vue'),
name: 'DzjkTjbbGlqx',
hidden: true,
meta: { title: '功率曲线',breadcrumb: false,activeMenu: '/dzjk/tjbb',activeSecondMenuName:'DzjkTjbb'},
meta: {
title: '功率曲线',
breadcrumb: false,
activeMenu: '/dzjk/tjbb',
activeSecondMenuName: 'DzjkTjbb'
},
},
{
path: 'pcsqx',
component: () => import('@/views/ems/dzjk/tjbb/pcsqx/index.vue'),
name: 'DzjkTjbbPcsqx',
hidden: true,
meta: { title: 'PCS曲线',breadcrumb: false,activeMenu: '/dzjk/tjbb',activeSecondMenuName:'DzjkTjbb'},
meta: {
title: 'PCS曲线',
breadcrumb: false,
activeMenu: '/dzjk/tjbb',
activeSecondMenuName: 'DzjkTjbb'
},
},
{
path: 'dcdqx',
component: () => import('@/views/ems/dzjk/tjbb/dcdqx/index.vue'),
name: 'DzjkTjbbDcdqx',
hidden: true,
meta: { title: '电池堆曲线',breadcrumb: false,activeMenu: '/dzjk/tjbb',activeSecondMenuName:'DzjkTjbb'},
meta: {
title: '电池堆曲线',
breadcrumb: false,
activeMenu: '/dzjk/tjbb',
activeSecondMenuName: 'DzjkTjbb'
},
},
{
path: 'dcwd',
component: () => import('@/views/ems/dzjk/tjbb/dcwd/index.vue'),
name: 'DzjkTjbbDcwd',
hidden: true,
meta: { title: '电池温度',breadcrumb: false,activeMenu: '/dzjk/tjbb',activeSecondMenuName:'DzjkTjbb'},
meta: {
title: '电池温度',
breadcrumb: false,
activeMenu: '/dzjk/tjbb',
activeSecondMenuName: 'DzjkTjbb'
},
},
{
path: 'dbbb',
component: () => import('@/views/ems/dzjk/tjbb/dbbb/index.vue'),
name: 'DzjkTjbbDbbb',
hidden: true,
meta: { title: '电表报表',breadcrumb: false,activeMenu: '/dzjk/tjbb',activeSecondMenuName:'DzjkTjbb'},
meta: {
title: '电表报表',
breadcrumb: false,
activeMenu: '/dzjk/tjbb',
activeSecondMenuName: 'DzjkTjbb'
},
}
]
},

View File

@ -7,7 +7,7 @@ module.exports = {
/**
* 侧边栏主题 深色主题theme-dark浅色主题theme-light
*/
sideTheme: 'theme-light',
sideTheme: 'theme-dark',
/**
* 系统布局配置

View File

@ -1,12 +1,23 @@
import {getAllSites} from '@/api/ems/zddt'
import {getAlarmDetailList, getSiteAllDeviceCategory} from '@/api/ems/dzjk'
const ems = {
state: {
dzjkAlarmLighting: false,//单站监控 告警统计红点标志
zdList: [],
zdDeviceCategoryOptions: {},//站点各个站点包含的设备种类 {021_DDS_01:["BATTERY","CLUSTER","STACK", "DH", "AMMETER", "PCS", "XF"],021_DDS_02:[]...}
workStatusOptions:{'0':'正常','1':'异常','2':'停止'},//工作状态
deviceStatusOptions:{'0':'离线','1':'机','2':'运行','3':'故障','4':'停机'},//设备状态
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': '本地'},//控制模式
warnOptions: {0: '正常', 1: '中断', 2: '不在线', 3: '异常'},//告警状态
@ -17,8 +28,7 @@ const ems = {
deviceTypeOptions: {'TCP': 'TCP', 'RTU': 'RTU'},//设备类型
ticketStatusOptions: {1: '待处理', 2: '处理中', 3: '已处理'},//工单处理状态
strategyStatusOptions: {'0': '未启用', '1': '已运行', '2': '已暂停', '3': '禁用', '4': '删除'},//策略状态
chargeStatusOptions:{'1':'充电','2':'待机'},//冲放状态
deviceCategoryOptions:{'PCS':'PCS','STACK':'电池堆','CLUSTER':'电池簇','COOLING':'液冷','BATTERY':'单体电池','AMMETER':'电表'},//设备类别
chargeStatusOptions: {'1': '充电', '2': '待机', '3': '放电'},//冲放状态
comparisonOperatorOptions: {'>': '>', '<': '<', '=': '=', '>=': '>=', '<=': '<='},
relationWithPoint: {'||': '||', '&&': '&&'}
},
@ -44,7 +54,16 @@ const ems = {
},
//查询站点的所有待处理0的告警 存在展示红点标志
getSiteAlarmNum({state, commit}, siteId) {
getAlarmDetailList({status:0,siteId,pageSize:10,pageNum:1,deviceId:'',alarmLevel:'',alarmStartTime:'',alarmEndTime:''}).then(response=>{
getAlarmDetailList({
status: 0,
siteId,
pageSize: 10,
pageNum: 1,
deviceId: '',
alarmLevel: '',
alarmStartTime: '',
alarmEndTime: ''
}).then(response => {
commit('SET_DZJK_ALARM_LIGHTING', !!response?.total || false)
})
},

View File

@ -1,5 +1,6 @@
<template>
<el-dialog :visible.sync="dialogTableVisible" class="ems-dialog" :title="mode === 'add'?'新增模板':`编辑模板` ">
<el-dialog :visible.sync="dialogTableVisible" class="ems-dialog add-template-dialog"
:title="mode === 'add'?'新增模板':`编辑模板` ">
<el-form ref="addTempForm" :model="formData" :rules="rules" size="medium" label-width="100px">
<el-form-item label="模板名称" prop="templateName">
<el-input v-model="formData.templateName" placeholder="请输入" clearable :style="{width: '100%'}">
@ -21,36 +22,52 @@
<!-- 新增时间段表单-->
<el-collapse-transition>
<el-card v-show="showAddTime" shadow="always" class="common-card-container" style="margin-top:25px;">
<el-form class="add-time-form transition-box" ref="addTimeForm" :model="formInline" :rules="formInlineRule" label-width="100px" style="margin-top:25px">
<el-form-item label="开始时间" prop="startTime">
<el-time-select
placeholder="开始时间"
v-model="formInline.startTime"
:picker-options="{
start: '00:00',
step: '01:00',
end: '23:00',
}">
</el-time-select>
</el-form-item>
<el-form-item label="结束时间" prop="endTime">
<el-time-select
placeholder="结束时间"
v-model="formInline.endTime"
:picker-options="{
start: '00:00',
step: '01:00',
end: '23:00',
minTime: formInline.startTime
}">
</el-time-select>
<el-form class="add-time-form transition-box" ref="addTimeForm" :model="formInline" :rules="formInlineRule"
label-width="100px" style="margin-top:25px">
<!-- <el-form-item label="开始时间" prop="startTime">-->
<!-- <el-time-select-->
<!-- placeholder="开始时间"-->
<!-- v-model="formInline.startTime"-->
<!-- :picker-options="{-->
<!-- start: '00:00',-->
<!-- step: '00:01',-->
<!-- end: '23:00',-->
<!-- }">-->
<!-- </el-time-select>-->
<!-- </el-form-item>-->
<!-- <el-form-item label="结束时间" prop="endTime">-->
<!-- <el-time-select-->
<!-- placeholder="结束时间"-->
<!-- v-model="formInline.endTime"-->
<!-- :picker-options="{-->
<!-- start: '00:00',-->
<!-- step: '00:01',-->
<!-- end: '23:00',-->
<!-- minTime: formInline.startTime-->
<!-- }">-->
<!-- </el-time-select>-->
<!-- </el-form-item>-->
<el-form-item label="时间范围" prop="timeRange">
<el-time-picker
is-range
v-model="formInline.timeRange"
range-separator=""
start-placeholder="开始时间"
end-placeholder="结束时间"
placeholder="选择时间范围"
format="HH:mm"
value-format="HH:mm"
:style="{width: '100%'}">
</el-time-picker>
</el-form-item>
<el-form-item label="冲放功率" prop="chargeDischargePower">
<el-input v-model="formInline.chargeDischargePower" placeholder="请输入"></el-input>
<el-input v-model="formInline.chargeDischargePower" placeholder="请输入"
:style="{width: '100%'}"></el-input>
</el-form-item>
<el-form-item label="充电状态" prop="chargeStatus">
<el-select v-model="formInline.chargeStatus" placeholder="请选择">
<el-option v-for="(value,key) in chargeStatusOptions" :key="key+'chargeStatusOptions'" :label="value" :value="key"></el-option>
<el-select v-model="formInline.chargeStatus" placeholder="请选择" :style="{width: '100%'}">
<el-option v-for="(value,key) in chargeStatusOptions" :key="key+'chargeStatusOptions'" :label="value"
:value="key"></el-option>
</el-select>
</el-form-item>
<el-form-item>
@ -64,7 +81,6 @@
:data="tableData"
border
style="width: 100%;margin-top:25px">
<!-- todo 如果要在span-method中使用column.property 在表格中必须定义prop="xxx"属性-->
<el-table-column
prop="startTime"
label="开始时间">
@ -107,13 +123,18 @@
<script>
import {mapState} from 'vuex'
import {addStrategyTemp, editStrategyTemp, getStrategyTempDetail} from '@/api/ems/dzjk'
export default {
inject: ['$home'],
data() {
const now = new Date()
const year = now.getFullYear(), month = now.getMonth(), day = now.getDate()
const range = [new Date(year, month, day, 0), new Date(year, month, day, 23)]
return {
mode: '',
editTempId: '',
dialogTableVisible: false,
secondRange: range,
formData: {
templateName: '',
sdcLimit: false,
@ -137,17 +158,14 @@ export default {
},
showAddTime: false,
formInline: {
startTime:'',endTime:'',chargeDischargePower:'',chargeStatus:''
timeRange: range,
chargeDischargePower: '',
chargeStatus: ''
},
formInlineRule: {
startTime: [{
timeRange: [{
required: true,
message: '请选择开始时间',
trigger: 'change'
}],
endTime: [{
required: true,
message: '请选择结束时间',
message: '请选择时间范围',
trigger: 'change'
}],
chargeDischargePower: [{
@ -155,7 +173,7 @@ export default {
message: '请输入冲放功率',
trigger: 'blur'
},
{ pattern: /^(0|[1-9]\d*)(\.\d+)?$/, message: '请输入合法数字或小数' }
{pattern: /^-?\d*\.?\d*$/, message: '请输入合法数字或小数'}
],
chargeStatus: [{
required: true,
@ -172,20 +190,6 @@ export default {
chargeStatusOptions: state => state?.ems?.chargeStatusOptions || {},
})
},
watch: {
"formInline.startTime":{
handler(newVal){
if(newVal && this.formInline.endTime){
const endTime = parseInt((this.formInline.endTime).split(':')[0] || 0)
const startTime =parseInt(newVal.split(':')[0])
if(endTime<=startTime){
this.formInline.endTime = `${startTime+1 <=9 ? '0'+(startTime+1) : startTime+1}:00`
}
}
},
deep:true
},
},
methods: {
changeSiteId() {
this.dialogTableVisible = false
@ -198,8 +202,8 @@ export default {
sdcUp: '',
}
this.formInline = {
startTime:'',endTime:'',chargeDischargePower:'',chargeStatus:''
}
timeRange: this.secondRange, chargeDischargePower: '', chargeStatus: ''
}//startTime: '', endTime: '',
this.showAddTime = false
this.tableData = []
},
@ -238,14 +242,18 @@ export default {
cancelAddTime() {
this.$refs.addTimeForm.resetFields()
this.showAddTime = false
this.formInline = {startTime:'',endTime:'',chargeDischargePower:'',chargeStatus:''}
this.formInline = {timeRange: this.secondRange, chargeDischargePower: '', chargeStatus: ''}//startTime: '', endTime: '',
},
saveTime() {
//表单校验校验成功添加到tableData里
this.$refs.addTimeForm.validate(valid => {
if (!valid) return
this.tableData.push(JSON.parse(JSON.stringify(this.formInline)));
this.$nextTick(() => {this.cancelAddTime()})
const {timeRange: [startTime, endTime], chargeDischargePower, chargeStatus} = this.formInline
this.tableData.push({startTime, endTime, chargeDischargePower, chargeStatus})
this.$nextTick(() => {
this.cancelAddTime()
})
})
},
deleteRow(index) {
@ -254,33 +262,20 @@ export default {
saveDialog() {
this.$refs.addTempForm.validate(valid => {
if (!valid) return
//校验时间选择范围是否冲突
let status = true
this.tableData.forEach((outer,outerIndex)=>{
const {startTime, endTime}=outer
const outerStart = parseInt(startTime),outerEnd = parseInt(endTime)
if(outerStart>outerEnd){
status = false
}else{
this.tableData.forEach((inner,innerIndex)=>{
if(innerIndex !== outerIndex){
const {startTime:innerStartTime, endTime:innerEndTime}=inner
const innerStart = parseInt(innerStartTime),innerEnd = parseInt(innerEndTime)
if((innerStart<outerStart && innerEnd>outerEnd) || !((innerStart<outerStart && innerEnd<=outerStart) || (innerStart>=outerEnd && innerEnd>outerEnd))){
status=false
}
}
})
}
})
if(!status){
return this.$message.error('时间选择范围冲突');
}
const {templateName, sdcLimit, sdcDown, sdcUp} = this.formData
const {siteId, updateStrategyId} = this.$home
const {tableData} = this
if (this.mode === 'edit') {
editStrategyTemp({siteId,strategyId:updateStrategyId,templateId:this.editTempId,templateName,sdcLimit,sdcDown,sdcUp,timeConfigList:tableData}).then(response=>{
editStrategyTemp({
siteId,
strategyId: updateStrategyId,
templateId: this.editTempId,
templateName,
sdcLimit,
sdcDown,
sdcUp,
timeConfigList: tableData
}).then(response => {
if (response?.code === 200) {
this.closeDialog()
this.$emit('update')
@ -288,7 +283,15 @@ export default {
}
})
} else {
addStrategyTemp({siteId,strategyId:updateStrategyId,templateName,sdcLimit,sdcDown,sdcUp,timeConfigList:tableData}).then(response=>{
addStrategyTemp({
siteId,
strategyId: updateStrategyId,
templateName,
sdcLimit,
sdcDown,
sdcUp,
timeConfigList: tableData
}).then(response => {
if (response?.code === 200) {
this.closeDialog()
this.$emit('update')
@ -314,3 +317,9 @@ export default {
}
</script>
<style lang="scss" scoped>
.add-template-dialog {
max-height: 90vh;
overflow-y: auto;
}
</style>

View File

@ -1,16 +1,19 @@
<template>
<div v-loading="loading" class="ems-dashboard-editor-container ems-content-container-padding">
<!-- 搜索栏-->
<el-form :inline="true" class="select-container">
<el-form-item label="设备清单">
<el-select v-model="search.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="时间选择">
@ -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>
@ -80,7 +85,8 @@
<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>
<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
@ -89,7 +95,9 @@
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="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>
@ -113,10 +121,11 @@
<script>
import {getAlarmDetailList,createTicketNo} from'@/api/ems/dzjk'
import {createTicketNo, getAlarmDetailList} from '@/api/ems/dzjk'
import {getDeviceList} from '@/api/ems/site'
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import {formatDate} from '@/filters/ems'
export default {
name: 'DzjkGzgj',
mixins: [getQuerySiteId],
@ -154,7 +163,9 @@ export default {
this.loading = true
createTicketNo({id}).then(response => {
response?.data && this.toTicket()
}).finally(()=>{this.loading = false})
}).finally(() => {
this.loading = false
})
},
// 判断是否是同一天
isSameDay(day1, day2) {
@ -204,10 +215,21 @@ export default {
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 => {
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() {
getDeviceList(this.siteId).then(response => {

View File

@ -1,9 +1,8 @@
<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"/>
<date-range-select ref="dateRangeSelect" :showIcon="true" :mini-time-picker="true" @updateDate="updateDate"/>
</div>
<div style="height: 310px" id="activeChart"></div>
</el-card>
@ -108,7 +107,13 @@ export default {
dataset: {source},
series: source[0].slice(1).map((item, index) => {
return {
type: 'line',
type: 'line',//index === 5 ? 'bar' : 'line',
showSymbol: false,
symbolSize: 2,
smooth: true,
areaStyle: {
opacity: 0.5,
},
yAxisIndex: index <= 4 ? 0 : 1
}
})

View File

@ -1,9 +1,8 @@
<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"/>
<date-range-select ref="dateRangeSelect" :showIcon="true" :mini-time-picker="true" @updateDate="updateDate"/>
</div>
<div style="height: 310px" id="weekChart"></div>
</el-card>
@ -14,6 +13,7 @@ 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},
@ -45,7 +45,6 @@ export default {
getWeekKData() {
this.showLoading()
const {siteId, timeRange} = this
this.hideLoading()
getSevenChargeData({siteId, startDate: timeRange[0], endDate: timeRange[1]}).then(response => {
this.setOption(response?.data || [])
}).finally(() => this.hideLoading())

View File

@ -4,66 +4,101 @@
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"
>
<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 class="site-info site-info-address">
<div class="title">
<i class="el-icon-location"></i>
</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 class="value">{{ info.siteAddress }}</div>
</div>
<div
style="box-sizing: border-box; height: 250px; padding: 20px 15px"
>
<el-row :gutter="20">
<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"
class="sjgl-col power-col"
>
<div class="sjgl-title">{{ item.title }}</div>
<div class="sjgl-wrapper">
<div class="sjgl-title">装机功率(MW)</div>
<div class="sjgl-value">
{{ runningInfo[item.attr] | formatNumber }}
{{ 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-col :xs="24" :sm="24" :lg="24">
</el-row>
</div>
</el-card>
</el-col>
<el-col :xs="24" :sm="24" :lg="12">
<week-chart ref="weekChart"/>
</el-col>
<el-col :xs="24" :sm="24" :lg="24">
<el-col :xs="24" :sm="24" :lg="12">
<active-chart ref="activeChart"/>
</el-col>
</el-row>
@ -79,6 +114,7 @@ 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},
@ -86,48 +122,46 @@ export default {
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: {}, //基本信息
@ -136,14 +170,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 || {};
@ -173,6 +206,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;
@ -180,25 +280,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>
@ -206,10 +328,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

@ -68,6 +68,7 @@ export default {
<style scoped lang="scss">
.dzjk-ems-content-container{
margin-top:0;
min-height: 60vh;
}
.lighting{
position: relative;

View File

@ -39,6 +39,7 @@ import resize from "@/mixins/ems/resize";
import DateTimeSelect from "@/views/ems/search/DateTimeSelect.vue";
import {getPointValueList} from "@/api/ems/search";
import DateRangeSelect from "@/components/Ems/DateRangeSelect/index.vue";
export default {
components: {DateRangeSelect, DateTimeSelect},
mixins: [resize],
@ -163,8 +164,21 @@ export default {
if (!this.chart) return;
this.chart.clear();
console.log("返回的数据", data);
if (!data || data.length <= 0) {
this.$message.warning("暂无数据");
}
console.log('展示的图表类型chartType', data[0].chartType)
if (data[0].chartType === 2) {
// 箱型图
this.setBoxOption(data)
} else {
//折线图
this.setLineOption(data)
}
},
setLineOption(data) {
let dataset = [];
if (data.length > 0) {
data.forEach((item, index) => {
item.deviceList.forEach((inner) => {
dataset.push({
@ -226,10 +240,7 @@ export default {
});
});
});
} else {
this.$message.warning("暂无数据");
}
console.log("图表数据", dataset);
console.log("折线图图表数据", dataset);
this.chart.setOption({
legend: {
// left: 'center',
@ -241,9 +252,12 @@ export default {
tooltip: {
trigger: "axis",
axisPointer: {
// 坐标轴指示器,坐标轴触发有效
type: "cross", // 默认为直线,可选为:'line' | 'shadow'
type: 'cross',
},
// axisPointer: {
// // 坐标轴指示器,坐标轴触发有效
// type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
// },
},
textStyle: {
color: "#333333",
@ -266,6 +280,122 @@ export default {
series: dataset,
});
},
setBoxOption(data) {
let dataset = [];
data.forEach((item, index) => {
item.deviceList.forEach((inner) => {
dataset.push({
name: `${
this.isDtdc
? `${inner.parentDeviceId ? inner.parentDeviceId + "-" : ""}${inner.deviceId}`
: `${inner.deviceId}`
}`,
type: "boxplot",
// markPoint: {
// symbolSize: 30,
// emphasis: {
// disabled: false//打开 鼠标高亮
// },
// data: [//最大值、最小值
// {
// // type: 'max',
// name: `最大值`,
// coord: [inner.maxDate, inner.maxValue],
// relativeTo: 'coordinate',
// label: {
// position: "top",
// formatter: item.dataType === 2 ? ([
// `最大值:${inner.maxValue}`,
// // `平均值:${inner.avgValue}`,
// `差值:${inner.diffValue}`,
// ]).join('\n') : ([
// `最大值:${inner.maxValue}`,
// // `平均值:${inner.avgValue}`,
// ]).join('\n'),
// },
// },
// {
// // type: 'min',
// name: `最小值`,
// coord: [inner.minDate, inner.minValue],
// relativeTo: 'coordinate',
// label: {
// position: "top",
// formatter: item.dataType === 2 ? ([
// `最小值:${inner.minValue}`,
// // `平均值:${inner.avgValue}`,
// `差值:${inner.diffValue}`,
// ]).join('\n') : ([
// `最小值:${inner.minValue}`,
// // `平均值:${inner.avgValue}`,
// ]).join('\n'),
// }
// }
// ]
// },
xdata: [],
data: [],
});
const length = dataset.length;
inner.pointValueList.forEach((value) => {
const {valueDate, min, q1, median, q3, max} = value
// const mid = (max - min) / 2, minLine = min + Math.abs(median / 2),
// maxLine = max - Math.abs(median / 2)
dataset[length - 1].xdata.push(valueDate);
dataset[length - 1].data.push([min, q1, median, q3, max]);
});
});
});
console.log("箱型图图表数据", dataset);
this.chart.setOption({
legend: {
// left: 'center',
// top: '10',
},
grid: {
containLabel: true,
},
tooltip: {
trigger: 'item',
formatter: function (params) {
let data = params.data;
let result = params.marker + params.name + ' ' + params.seriesName + '<br/>';
result += '最小值: ' + data[1] + '<br/>';
result += '平均值: ' + data[3] + '<br/>';
result += '最大值: ' + data[5];
return result;
}
// trigger: "axis",
// axisPointer: {
// type: 'cross',
// },
// axisPointer: {
// // 坐标轴指示器,坐标轴触发有效
// type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
// },
},
textStyle: {
color: "#333333",
},
xAxis: {type: "category", data: dataset?.[0]?.xdata || []},
yAxis: {
type: "value",
},
dataZoom: [
{
type: "inside",
start: 0,
end: 100,
},
{
start: 0,
end: 100,
},
],
series: dataset,
});
},
updateDate(val) {
this.dataRange = val || [];
this.getDate();

View File

@ -1,25 +1,51 @@
<template>
<div v-loading="loading">
<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="{
'warning-card-container':baseInfo.workStatus && baseInfo.workStatus !== '0',
'running-card-container':baseInfo.workStatus === '0'
}">
<el-card shadow="always"
class="sbjk-card-container common-card-container-body-no-padding common-card-container-no-title-bg"
:class="handleCardClass(baseInfo)">
<div slot="header">
<span class="large-title">{{index+1}}#{{baseInfo.parentDeviceName?`${baseInfo.parentDeviceName} —> ` : ''}}{{baseInfo.deviceName}}</span>
<span
class="large-title">{{
baseInfo.parentDeviceName ? `${baseInfo.parentDeviceName} -> ` : ''
}}{{ baseInfo.deviceName }}</span>
<div class="info">
<div>数据更新时间{{ baseInfo.dataUpdateTime || '-' }}</div>
</div>
<div class="alarm">
<el-button type="primary" round size="small" style="margin-right:20px;"
@click="pointDetail(baseInfo,'point')">详细
</el-button>
<el-badge :hidden="!baseInfo.alarmNum" :value="baseInfo.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(baseInfo,'alarmPoint')"
></i>
</el-badge>
</div>
</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>
<el-descriptions-item labelClassName="descriptions-label" 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" :span="1" label="与EMS通信">{{$store.state.ems.communicationStatusOptions[baseInfo.emsCommunicationStatus]}}</el-descriptions-item>
<el-descriptions-item
contentClassName="descriptions-direction work-status"
:span="1" label="工作状态">
{{ CLUSTERWorkStatusOptions[baseInfo.workStatus] }}
</el-descriptions-item>
<el-descriptions-item contentClassName="descriptions-direction"
:span="1" label="与PCS通信">
{{ $store.state.ems.communicationStatusOptions[baseInfo.pcsCommunicationStatus] }}
</el-descriptions-item>
<el-descriptions-item contentClassName="descriptions-direction"
:span="1" label="与EMS通信">
{{ $store.state.ems.communicationStatusOptions[baseInfo.emsCommunicationStatus] }}
</el-descriptions-item>
</el-descriptions>
</div>
<div class="descriptions-main descriptions-main-bg-color">
<el-descriptions direction="vertical" :column="3" :colon="false">
<el-descriptions-item labelClassName="descriptions-label" contentClassName="descriptions-direction" v-for="(item,index) in infoData" :key="index+'pcsInfoData'" :span="1" :label="item.label">
<el-descriptions-item labelClassName="descriptions-label" contentClassName="descriptions-direction"
v-for="(item,index) in infoData" :key="index+'pcsInfoData'" :span="1"
:label="item.label">
<span class="pointer" @click="showChart(item.pointName || '',baseInfo.deviceId)">
{{ baseInfo[item.attr] | formatNumber }} <span v-if="item.unit" v-html="item.unit"></span>
</span>
@ -30,7 +56,9 @@
<div class="process-line-bg">
<div class="process-line" :style="{height:baseInfo.currentSoc+'%'}"></div>
</div>
<div class="process pointer" @click="showChart( '当前SOC',baseInfo.deviceId)">当前SOC : {{baseInfo.currentSoc}}%</div>
<div class="process pointer" @click="showChart( '当前SOC',baseInfo.deviceId)">当前SOC :
{{ baseInfo.currentSoc }}%
</div>
</div>
</div>
<el-table
@ -50,14 +78,20 @@
label="单体平均值"
>
<template slot-scope="scope">
<span class="pointer" @click="showChart( tablePointNameMap[scope.row.dataName+scope.column.label],baseInfo.deviceId)">{{scope.row.avgData}}</span>
<span class="pointer"
@click="showChart( tablePointNameMap[scope.row.dataName+scope.column.label],baseInfo.deviceId)">{{
scope.row.avgData
}}</span>
</template>
</el-table-column>
<el-table-column
prop="minData"
label="单体最小值">
<template slot-scope="scope">
<span class="pointer" @click="showChart( tablePointNameMap[scope.row.dataName+scope.column.label],baseInfo.deviceId)">{{scope.row.minData}}</span>
<span class="pointer"
@click="showChart( tablePointNameMap[scope.row.dataName+scope.column.label],baseInfo.deviceId)">{{
scope.row.minData
}}</span>
</template>
</el-table-column>
<el-table-column
@ -68,7 +102,10 @@
prop="maxData"
label="单体最大值">
<template slot-scope="scope">
<span class="pointer " @click="showChart( tablePointNameMap[scope.row.dataName+scope.column.label],baseInfo.deviceId)">{{scope.row.maxData}}</span>
<span class="pointer "
@click="showChart( tablePointNameMap[scope.row.dataName+scope.column.label],baseInfo.deviceId)">{{
scope.row.maxData
}}</span>
</template>
</el-table-column>
<el-table-column
@ -80,19 +117,28 @@
</div>
<el-empty v-show="baseInfoList.length<=0" :image-size="200"></el-empty>
<point-chart ref="pointChart" :site-id="siteId"/>
<point-table ref="pointTable"/>
</div>
</template>
<script>
import pointChart from "./../PointChart.vue";
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:{pointChart},
components: {PointTable, pointChart},
computed: {
...mapState({
CLUSTERWorkStatusOptions: state => state?.ems?.CLUSTERWorkStatusOptions || {},
})
},
data() {
return {
loading: false,
@ -127,6 +173,15 @@ 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
this.$refs.pointTable.showTable({siteId, deviceId, deviceCategory: 'CLUSTER'}, dataType)
},
showChart(pointName, deviceId) {
pointName && this.$refs.pointChart.showChart({pointName, deviceCategory: 'CLUSTER', deviceId})
},
@ -134,7 +189,9 @@ export default {
this.loading = true
getBMSBatteryCluster(this.siteId).then(response => {
this.baseInfoList = JSON.parse(JSON.stringify(response?.data || []));
}).finally(() => {this.loading = false})
}).finally(() => {
this.loading = false
})
},
init() {
this.updateData()
@ -150,10 +207,12 @@ export default {
.descriptions-main {
padding: 24px 300px 24px 24px;
}
.descriptions-main-bottom {
padding: 14px 300px 14px 24px;
}
}
// 进度条样式
.process-container {
width: 100px;
@ -161,6 +220,7 @@ export default {
right: 70px;
top: 50%;
transform: translateY(-50%);
.process-line-bg {
position: relative;
width: 100%;
@ -168,6 +228,7 @@ export default {
background-color: #fff2cb;
border-radius: 6px;
box-shadow: 0 0 10px #fff2cb, 0 0 0 rgba(255, 242, 203, 0.5);
.process-line {
position: absolute;
left: 0;
@ -179,6 +240,7 @@ export default {
box-shadow: 0 0 10px #ffbf14, 0 0 0 rgba(255, 191, 20, 0.5);
}
}
.process {
margin-top: 15px;
color: #666666;

View File

@ -1,25 +1,49 @@
<template>
<div v-loading="loading">
<div v-for="(baseInfo,index) in baseInfoList" :key="index+'bmszlContainer'" style="margin-bottom:25px;">
<el-card :class="{
'warning-card-container':baseInfo.workStatus && baseInfo.workStatus !== '0',
'running-card-container':baseInfo.workStatus === '0'
}" class="sbjk-card-container common-card-container-body-no-padding common-card-container-no-title-bg"
<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">{{index+1}}#{{baseInfo.deviceName}}</span>
<span class="large-title">{{ baseInfo.deviceName }}</span>
<div class="info">
<div>数据更新时间{{ baseInfo.dataUpdateTime || '-' }}</div>
</div>
<div class="alarm">
<el-button type="primary" round size="small" style="margin-right:20px;"
@click="pointDetail(baseInfo,'point')">详细
</el-button>
<el-badge :hidden="!baseInfo.alarmNum" :value="baseInfo.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(baseInfo,'alarmPoint')"
></i>
</el-badge>
</div>
</div>
<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" label="工作状态" labelClassName="descriptions-label" >{{$store.state.ems.workStatusOptions[baseInfo.workStatus]}}</el-descriptions-item>
<el-descriptions-item :span="1" contentClassName="descriptions-direction" label="与PCS通信" labelClassName="descriptions-label">{{$store.state.ems.communicationStatusOptions[baseInfo.pcsCommunicationStatus]}}</el-descriptions-item>
<el-descriptions-item :span="1" contentClassName="descriptions-direction" label="与EMS通信" labelClassName="descriptions-label">{{$store.state.ems.communicationStatusOptions[baseInfo.emsCommunicationStatus]}}</el-descriptions-item>
<el-descriptions-item
contentClassName="descriptions-direction work-status"
label="工作状态" labelClassName="descriptions-label">
{{ STACKWorkStatusOptions[baseInfo.workStatus] }}
</el-descriptions-item>
<el-descriptions-item :span="1" contentClassName="descriptions-direction" label="与PCS通信"
labelClassName="descriptions-label">
{{ $store.state.ems.communicationStatusOptions[baseInfo.pcsCommunicationStatus] }}
</el-descriptions-item>
<el-descriptions-item :span="1" contentClassName="descriptions-direction" label="与EMS通信"
labelClassName="descriptions-label">
{{ $store.state.ems.communicationStatusOptions[baseInfo.emsCommunicationStatus] }}
</el-descriptions-item>
</el-descriptions>
</div>
<div class="descriptions-main descriptions-main-bg-color">
<el-descriptions :colon="false" :column="3" direction="vertical">
<el-descriptions-item v-for="(item,index) in infoData" :key="index+'pcsInfoData'" :label="item.label" :span="1" contentClassName="descriptions-direction" labelClassName="descriptions-label">
<el-descriptions-item v-for="(item,index) in infoData" :key="index+'pcsInfoData'" :label="item.label"
:span="1" contentClassName="descriptions-direction"
labelClassName="descriptions-label">
<span class="pointer" @click="showChart(item.pointName || '',baseInfo.deviceId)">
{{ baseInfo[item.attr] | formatNumber }}<span v-if="item.unit" v-html="item.unit"></span>
</span>
@ -30,7 +54,9 @@
<div class="process-line-bg">
<div :style="{height:baseInfo.stackSoc+'%'}" class="process-line"></div>
</div>
<div class="process pointer" @click="showChart('当前SOC',baseInfo.deviceId)">当前SOC : {{baseInfo.stackSoc}}%</div>
<div class="process pointer" @click="showChart('当前SOC',baseInfo.deviceId)">当前SOC :
{{ baseInfo.stackSoc }}%
</div>
</div>
</div>
<el-table
@ -47,26 +73,32 @@
label="簇电压"
>
<template slot-scope="scope">
<span class="pointer" @click="showChart('簇电压',scope.row.clusterId,'CLUSTER')">{{scope.row.clusterVoltage}} V</span>
<span class="pointer"
@click="showChart('簇电压',scope.row.clusterId,'CLUSTER')">{{ 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,'CLUSTER')">{{scope.row.clusterCurrent}} A</span>
<span class="pointer"
@click="showChart('簇电流',scope.row.clusterId,'CLUSTER')">{{ scope.row.clusterCurrent }} A</span>
</template>
</el-table-column>
<el-table-column
label="簇SOC">
<template slot-scope="scope">
<span class="pointer" @click="showChart('当前SOC',scope.row.clusterId,'CLUSTER')">{{scope.row.currentSoc}} %</span>
<span class="pointer"
@click="showChart('当前SOC',scope.row.clusterId,'CLUSTER')">{{ scope.row.currentSoc }} %</span>
</template>
</el-table-column>
<el-table-column
label="单体最高电压"
prop="maxVoltage">
<template slot-scope="scope">
<span class="pointer" @click="showChart('最高单体电压',scope.row.clusterId,'CLUSTER')">{{scope.row.maxCellVoltage}} V</span>
<span class="pointer"
@click="showChart('最高单体电压',scope.row.clusterId,'CLUSTER')">{{
scope.row.maxCellVoltage
}} V</span>
</template>
</el-table-column>
<el-table-column
@ -77,7 +109,10 @@
label="单体最低电压"
prop="minVoltage">
<template slot-scope="scope">
<span class="pointer" @click="showChart('最低单体电压',scope.row.clusterId,'CLUSTER')">{{scope.row.minCellVoltage}} V</span>
<span class="pointer"
@click="showChart('最低单体电压',scope.row.clusterId,'CLUSTER')">{{
scope.row.minCellVoltage
}} V</span>
</template>
</el-table-column>
<el-table-column
@ -87,7 +122,10 @@
<el-table-column
label="单体最高温度">
<template slot-scope="scope">
<span class="pointer" @click="showChart('最高单体温度',scope.row.clusterId,'CLUSTER')">{{scope.row.maxCellTemp}} &#8451;</span>
<span class="pointer"
@click="showChart('最高单体温度',scope.row.clusterId,'CLUSTER')">{{
scope.row.maxCellTemp
}} &#8451;</span>
</template>
</el-table-column>
<el-table-column
@ -98,7 +136,10 @@
label="单体最低温度"
prop="minTemperature">
<template slot-scope="scope">
<span class="pointer" @click="showChart('最低单体温度',scope.row.clusterId,'CLUSTER')">{{scope.row.minCellTemp}} &#8451;</span>
<span class="pointer"
@click="showChart('最低单体温度',scope.row.clusterId,'CLUSTER')">{{
scope.row.minCellTemp
}} &#8451;</span>
</template>
</el-table-column>
<el-table-column
@ -111,6 +152,7 @@
</div>
<el-empty v-show="baseInfoList.length<=0" :image-size="200"></el-empty>
<point-chart ref="pointChart" :site-id="siteId"/>
<point-table ref="pointTable"/>
</div>
</template>
@ -119,10 +161,18 @@ import {getBMSOverView} from '@/api/ems/dzjk'
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,},
components: {pointChart, PointTable},
mixins: [getQuerySiteId, intervalUpdate],
computed: {
...mapState({
STACKWorkStatusOptions: state => state?.ems?.STACKWorkStatusOptions || {},
})
},
data() {
return {
loading: false,
@ -141,6 +191,16 @@ 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
this.$refs.pointTable.showTable({siteId, deviceId, deviceCategory: 'STACK'}, dataType)
},
showChart(pointName, deviceId, deviceCategory = 'STACK') {
pointName && this.$refs.pointChart.showChart({pointName, deviceCategory, deviceId})
},
@ -148,7 +208,9 @@ export default {
this.loading = true
getBMSOverView(this.siteId).then(response => {
this.baseInfoList = JSON.parse(JSON.stringify(response?.data || []));
}).finally(() => {this.loading = false})
}).finally(() => {
this.loading = false
})
},
init() {
this.updateData()
@ -170,6 +232,7 @@ export default {
}
}
}
// 进度条样式
.process-container {
width: 100px;
@ -177,6 +240,7 @@ export default {
right: 70px;
top: 50%;
transform: translateY(-50%);
.process-line-bg {
position: relative;
width: 100%;
@ -184,6 +248,7 @@ export default {
background-color: #fff2cb;
border-radius: 6px;
box-shadow: 0 0 10px #fff2cb, 0 0 0 rgba(255, 242, 203, 0.5);
.process-line {
position: absolute;
left: 0;
@ -195,6 +260,7 @@ export default {
box-shadow: 0 0 10px rgb(252 108 108), 0 0 0 rgba(252, 108, 108, 0.5);
}
}
.process {
margin-top: 15px;
color: #666666;

View File

@ -6,33 +6,47 @@
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'
}"
>
<div slot="header">
<span class="large-title">{{index+1}}#{{ item.deviceName }}</span>
<span class="large-title">{{ item.deviceName }}</span>
<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 :hidden="!item.alarmNum" :value="item.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(item,'alarmPoint')"
></i>
</el-badge>
</div>
</div>
<el-row>
<el-col v-for="(tempDataItem,tempDataIndex) in deviceIdTypeMsg[item.deviceId]" :key="tempDataIndex+'dbTempData'" :span="8">
<el-row class="device-info-row">
<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)">
{{tempDataItem.name}}{{item[tempDataItem.attr]}}<span v-html="tempDataItem.unit"></span>
<span class="left">{{ tempDataItem.name }}</span> <span class="right">{{ item[tempDataItem.attr] || '-' }}<span
v-html="tempDataItem.unit"></span></span>
</span>
</el-col>
</el-row>
</el-card>
<el-empty v-show="list.length<=0" :image-size="200"></el-empty>
<point-chart ref="pointChart" :site-id="siteId"/>
<point-table ref="pointTable"/>
</div>
</template>
@ -41,10 +55,19 @@ import pointChart from "./../PointChart.vue";
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:{pointChart},
components: {PointTable, pointChart},
computed: {
...mapState({
communicationStatusOptions: state => state?.ems?.communicationStatusOptions || {},
})
},
data() {
return {
loading: false,
@ -54,92 +77,133 @@ 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: {
// 查看设备电位表格
pointDetail(row, dataType) {
const {deviceId} = row
this.$refs.pointTable.showTable({siteId: this.siteId, deviceId, deviceCategory: 'AMMETER'}, dataType)
},
showChart(pointName, deviceId) {
pointName && this.$refs.pointChart.showChart({pointName, deviceCategory: 'AMMETER', deviceId})
},
@ -158,7 +222,8 @@ export default {
this.updateInterval(this.updateData)
},
},
mounted() {},
mounted() {
},
};
</script>
@ -167,24 +232,6 @@ export default {
&.list:not(:last-child) {
margin-bottom: 25px;
}
.el-row{
background-color: #ffffff;
border:1px solid #eeeeee;
font-size: 14px;
line-height: 16px;
color: #333333;
.el-col{
padding:12px 0;
text-align: center;
position: relative;
}
.el-col{
border-bottom: 1px solid #eeeeee;
}
.el-col:not(:nth-child(3n)){
border-right: 1px solid #eeeeee;
}
}
}
</style>

View File

@ -0,0 +1,120 @@
<template>
<div v-loading="loading">
<el-card
v-for="(item,index) in list"
:key="index+'ylLise'"
class="sbjk-card-container running-card-container"
shadow="always">
<div slot="header">
<span class="large-title">{{ item.deviceName }}</span>
<div class="info">
<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 :hidden="!item.alarmNum" :value="item.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(item,'alarmPoint')"
></i>
</el-badge>
</div>
</div>
<el-row class="device-info-row">
<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>
</el-col>
</el-row>
</el-card>
<el-empty v-show="list.length<=0" :image-size="200"></el-empty>
<point-chart ref="pointChart" :site-id="siteId"/>
<point-table ref="pointTable"/>
</div>
</template>
<script>
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import {getDhDataList} from '@/api/ems/dzjk'
import intervalUpdate from "@/mixins/ems/intervalUpdate";
import pointChart from "./../PointChart.vue";
import PointTable from "@/views/ems/site/sblb/PointTable.vue";
export default {
name: 'DzjkSbjkDh',
mixins: [getQuerySiteId, intervalUpdate],
components: {pointChart, PointTable},
data() {
return {
loading: false,
list: [],
tempData: [
{title: '湿度', attr: 'humidity', unit: ''},
{title: '温度', attr: 'temperature', unit: '&#8451;'},
]
}
},
methods: {
// 查看设备电位表格
pointDetail(row, dataType) {
const {deviceId} = row
this.$refs.pointTable.showTable({siteId: this.siteId, deviceId, deviceCategory: 'DH'}, dataType)
},
showChart(pointName, deviceId) {
pointName && this.$refs.pointChart.showChart({pointName, deviceCategory: 'DH', deviceId})
},
updateData() {
this.loading = true
getDhDataList(this.siteId).then(response => {
this.list = JSON.parse(JSON.stringify(response?.data || []));
}).finally(() => {
this.loading = false
})
},
init() {
this.updateData()
this.updateInterval(this.updateData)
}
},
mounted() {
}
}
</script>
<style scoped lang="scss">
.sbjk-card-container {
&:not(:last-child) {
margin-bottom: 25px;
}
.el-row {
background-color: #ffffff;
border: 1px solid #eeeeee;
font-size: 14px;
line-height: 16px;
color: #333333;
.el-col {
padding: 12px 0;
text-align: center;
position: relative;
}
.el-col {
border-bottom: 1px solid #eeeeee;
}
.el-col:not(:nth-child(3n)) {
border-right: 1px solid #eeeeee;
}
}
}
</style>

View File

@ -52,13 +52,16 @@
</el-button>
</template>
</el-table-column>
<!-- <el-table-column label="曲线图">
<el-table-column label="操作" width="160">
<template slot-scope="scope">
<el-button @click="chartDetail(scope.row)" type="text" size="small">
展示
<el-button @click="$emit('pointDetail',scope.row,'point')" type="text" size="small">
详细
</el-button>
<el-button @click="$emit('pointDetail',scope.row,'alarmPoint')" type="text" size="small">
报警点位详细
</el-button>
</template>
</el-table-column> -->
</el-table-column>
</el-table>
<!-- <el-pagination
v-show="tableData.length > 0"
@ -115,7 +118,6 @@ export default {
methods: {
//查看表格行图表
chartDetail(row, dataType = "") {
const { clusterDeviceId, deviceId } = row;
this.$emit("chart", {...row, dataType});
},
},

View File

@ -88,6 +88,7 @@
:totalSize="totalSize"
:pointIdList="pointIdList"
@chart="chartDetail"
@pointDetail="pointDetail"
></component>
<el-pagination
v-show="tableData.length > 0"
@ -104,6 +105,7 @@
</el-pagination>
<chart-detail ref="chartDetail" />
<point-chart ref="pointChart" :site-id="siteId" />
<point-table ref="pointTable"/>
</el-card>
</template>
@ -119,10 +121,12 @@ import ChartDetail from "./ChartDetail.vue";
import Table from "./Table.vue";
import List from "./List.vue";
import pointChart from "./../PointChart.vue";
import PointTable from "@/views/ems/site/sblb/PointTable.vue";
export default {
name: "DzjkSbjkDtdc",
mixins: [getQuerySiteId],
components: {
PointTable,
BarChart,
ChartDetail,
DtdcTable: Table,
@ -165,6 +169,11 @@ export default {
};
},
methods: {
// 查看设备电位表格
pointDetail(row,dataType){
const {deviceId,clusterDeviceId} = row
this.$refs.pointTable.showTable({siteId:this.siteId,deviceId,deviceCategory:'BATTERY',parentId:clusterDeviceId},dataType)
},
changeMenu(menu) {
const { activeBtn } = this;
activeBtn !== menu && (this.activeBtn = menu);

View File

@ -0,0 +1,133 @@
<template>
<div v-loading="loading" class="ems">
<el-card
v-for="(item,index) in list"
:key="index+'emsList'"
class="sbjk-card-container list running-card-container"
shadow="always"
>
<div slot="header">
<span class="large-title">{{ item.deviceName }}</span>
<div class="info">
<div>
EMS控制模式: {{
item.emsStatus === 0 ? '自动' : '手动'
}}
</div>
<div>数据更新时间{{ item.dataUpdateTime }}</div>
</div>
<div class="alarm">
<el-button size="small" round style="margin-right:20px;" type="primary" @click="pointDetail(item,'point')">详细
</el-button>
<el-badge :hidden="!item.alarmNum" :value="item.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(item,'alarmPoint')"
></i>
</el-badge>
</div>
</div>
<el-row class="device-info-row">
<el-col v-for="(tempDataItem,tempDataIndex) in bmsDataList" :key="tempDataIndex+'bmsTempData'"
:span="6" class="device-info-col">
<span class="pointer" @click="showChart(tempDataItem.name,item.deviceId)">
<span class="left">{{ tempDataItem.name }}</span> <span class="right">{{ item[tempDataItem.attr] }}<span
v-html="tempDataItem.unit"></span></span>
</span>
</el-col>
<el-col v-for="(tempDataItem,tempDataIndex) in pcsDataList" :key="tempDataIndex+'pcsTempData'"
:span="6" class="device-info-col">
<span class="pointer" @click="showChart(tempDataItem.name,item.deviceId)">
<span class="left">{{ tempDataItem.name }}</span> <span class="right">{{ item[tempDataItem.attr] }}<span
v-html="tempDataItem.unit"></span></span>
</span>
</el-col>
</el-row>
</el-card>
<el-empty v-show="list.length <= 0" :image-size="200"></el-empty>
<point-chart ref="pointChart" :site-id="siteId"/>
<point-table ref="pointTable"/>
</div>
</template>
<script>
import pointChart from "./../PointChart.vue";
import PointTable from "@/views/ems/site/sblb/PointTable.vue";
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import {getEmsDataList} from "@/api/ems/dzjk";
import intervalUpdate from "@/mixins/ems/intervalUpdate";
export default {
name: "DzjkSbjkEms",
components: {pointChart, PointTable},
mixins: [getQuerySiteId, intervalUpdate],
data() {
return {
loading: false,
list: [],
bmsDataList: [{
name: 'BMS1SOC',
attr: 'bms1Soc'
},
{
name: 'BMS2SOC',
attr: 'bms2Soc'
},
{
name: 'BMS3SOC',
attr: 'bms3Soc'
},
{
name: 'BMS4SOC',
attr: 'bms4Soc'
}],
pcsDataList: [{
name: 'PCS-1有功功率',
attr: 'pcs1Yggl'
},
{
name: 'PCS-2有功功率',
attr: 'pcs2Yggl'
},
{
name: 'PCS-3有功功率',
attr: 'pcs3Yggl'
},
{
name: 'PCS-4有功功率',
attr: 'pcs4Yggl'
}]
};
},
methods: {
// 查看设备电位表格
pointDetail(row, dataType) {
const {deviceId} = row
this.$refs.pointTable.showTable({siteId: this.siteId, deviceId, deviceCategory: 'EMS'}, dataType)
},
showChart(pointName, deviceId) {
pointName &&
this.$refs.pointChart.showChart({pointName, deviceCategory: 'EMS', deviceId});
},
getData() {
this.loading = true;
getEmsDataList(this.siteId)
.then((response) => {
const data = response?.data || {};
this.list = JSON.parse(JSON.stringify(data));
})
.finally(() => (this.loading = false));
},
updateData() {
this.getData();
},
init() {
this.updateData();
this.updateInterval(this.updateData);
},
},
};
</script>
<style lang="scss" scoped></style>

View File

@ -8,17 +8,13 @@
style="margin-bottom: 25px"
>
<el-card
:class="{
'warning-card-container': pcsItem.workStatus === '1',
'timing-card-container': pcsItem.workStatus === '2',
'running-card-container': !['1', '2'].includes(pcsItem.workStatus),
}"
:class="handleCardClass(pcsItem)"
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"
>{{ pcsIndex + 1 }}#{{ pcsItem.deviceName }}</span
>{{ pcsItem.deviceName }}</span
>
<div class="info">
<div>
@ -31,10 +27,20 @@
<div>数据更新时间{{ pcsItem.dataUpdateTime }}</div>
</div>
<div class="alarm">
<el-badge :value="pcsItem.alarmNum || 0" class="item">
<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 :hidden="!pcsItem.alarmNum" :value="pcsItem.alarmNum || 0" class="item">
<i
class="el-icon-message-solid"
style="font-size: 26px; color: #fff; display: block"
class="el-icon-message-solid alarm-icon"
@click="pointDetail(pcsItem,'alarmPoint')"
></i>
</el-badge>
</div>
@ -42,15 +48,14 @@
<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]
}}</el-descriptions-item
PCSWorkStatusOptions[pcsItem.workStatus]
}}
</el-descriptions-item
>
<el-descriptions-item
:span="1"
@ -59,18 +64,20 @@
labelClassName="descriptions-label"
>{{
$store.state.ems.gridStatusOptions[pcsItem.gridStatus]
}}</el-descriptions-item
}}
</el-descriptions-item
>
<el-descriptions-item
:contentClassName="`descriptions-direction ${
pcsItem.deviceStatus === '2' ? 'save' : 'danger'
pcsItem.deviceStatus === '1' ? 'save' : 'danger'
}`"
:span="1"
label="设备状态"
labelClassName="descriptions-label"
>{{
$store.state.ems.deviceStatusOptions[pcsItem.deviceStatus]
}}</el-descriptions-item
}}
</el-descriptions-item
>
<el-descriptions-item
:span="1"
@ -79,7 +86,8 @@
labelClassName="descriptions-label"
>{{
$store.state.ems.controlModeOptions[pcsItem.controlMode]
}}</el-descriptions-item
}}
</el-descriptions-item
>
</el-descriptions>
</div>
@ -126,7 +134,8 @@
:span="4"
contentClassName="descriptions-direction keep"
labelClassName="descriptions-label"
>{{ item.dischargeStatus }}</el-descriptions-item
>{{ item.dischargeStatus }}
</el-descriptions-item
>
<el-descriptions-item
:span="1"
@ -170,19 +179,29 @@
</div>
<el-empty v-show="pcsList.length <= 0" :image-size="200"></el-empty>
<point-chart ref="pointChart" :site-id="siteId"/>
<point-table ref="pointTable"/>
</div>
</template>
<script>
import pointChart from "./../PointChart.vue";
import PointTable from "@/views/ems/site/sblb/PointTable.vue";
import RealTimeBaseInfo from "./../RealTimeBaseInfo.vue";
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import { getRunningHeadInfo, getPcsDetailInfo } from "@/api/ems/dzjk";
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 },
components: {RealTimeBaseInfo, pointChart, PointTable, PcsSwitch},
mixins: [getQuerySiteId, intervalUpdate],
computed: {
...mapState({
PCSWorkStatusOptions: state => state?.ems?.PCSWorkStatusOptions || {},
})
},
data() {
return {
loading: false,
@ -190,10 +209,10 @@ export default {
pcsList: [],
infoData: [
{
label: "总交流有功率",
label: "总交流有功率",
attr: "totalActivePower",
unit: "kW",
pointName: "总交流有功率",
pointName: "总交流有功率",
},
{
label: "当天交流充电量",
@ -209,10 +228,10 @@ export default {
pointName: "A相电流",
},
{
label: "总交流无功率",
label: "总交流无功率",
attr: "totalReactivePower",
unit: "kVar",
pointName: "总交流无功率",
pointName: "总交流无功率",
},
{
label: "当天交流放电量",
@ -269,6 +288,15 @@ 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
this.$refs.pointTable.showTable({siteId: this.siteId, deviceId, deviceCategory: 'PCS'}, dataType)
},
showChart(pointName, deviceId, isBranch = false) {
pointName &&
this.$refs.pointChart.showChart({pointName, deviceCategory: isBranch ? 'BRANCH' : 'PCS', deviceId});

View File

@ -14,7 +14,6 @@
<script>
import * as echarts from "echarts";
import resize from "@/mixins/ems/resize";
import { formatDate } from "@/filters/ems";
import {storagePower} from "@/api/ems/dzjk";
export default {
@ -35,12 +34,10 @@ export default {
this.chart = null;
},
methods: {
init(siteId) {
init(siteId, timeRange) {
this.chart.showLoading();
const x = [];
const data1 = [],
data2 = [];
storagePower(siteId)
const [startTime = '', endTime = ''] = timeRange;
storagePower(siteId, startTime, endTime)
.then((response) => {
this.setOption(response?.data?.pcsPowerList || []);
})
@ -49,7 +46,6 @@ export default {
});
},
setOption(data) {
// data=[{deviceId:'pcs1',energyStoragePowList:[{createDate,deviceId,pcsTotalActPower,pcsTotalReactivePower}]}]
let xdata = [],
series = [];
data.forEach((element, index) => {
@ -64,8 +60,13 @@ export default {
// color:'#FFBD00'
},
data: (element.energyStoragePowList || []).map(
(i) => i.pcsTotalActPower
),
(i) => {
return {
value: i.pcsTotalActPower,
year: i.dateDay || ''
}
}
)
},
{
type: "line",
@ -74,12 +75,17 @@ export default {
// color:'#FFBD00'
},
data: (element.energyStoragePowList || []).map(
(i) => i.pcsTotalReactivePower
(i) => {
return {
value: i.pcsTotalReactivePower,
year: i.dateDay || ''
}
}
),
}
);
});
this.chart.setOption({
this.chart && this.chart.setOption({
legend: {
left: "center",
top: "5",
@ -93,11 +99,24 @@ export default {
containLabel: true,
},
tooltip: {
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;">
<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>'
return result
}
},
textStyle: {
color: "#333333",
@ -118,7 +137,7 @@ export default {
},
],
series,
});
}, true);
},
},
};

View File

@ -14,7 +14,6 @@
<script>
import * as echarts from "echarts";
import resize from "@/mixins/ems/resize";
import { formatDate } from "@/filters/ems";
import { batteryAveSoc } from "@/api/ems/dzjk";
export default {
mixins: [resize],
@ -34,9 +33,10 @@ export default {
this.chart = null;
},
methods: {
init(siteId) {
init(siteId,timeRange) {
this.chart.showLoading();
batteryAveSoc(siteId)
const [startTime='', endTime=''] = timeRange;
batteryAveSoc(siteId,startTime,endTime)
.then((response) => {
this.setOption(response?.data?.batteryAveSOCList || []);
})
@ -49,9 +49,12 @@ export default {
ydata = [];
data.forEach((element) => {
xdata.push(element.createDate);
ydata.push(element.batterySOC);
ydata.push({
value:element.batterySOC,
year:element.dateDay,
});
xdata = this.chart.setOption({
});
this.chart && this.chart.setOption({
legend: {
left: "center",
top: "5",
@ -65,11 +68,24 @@ export default {
containLabel: true,
},
tooltip: {
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;">
<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>'
return result
}
},
textStyle: {
color: "#333333",
@ -99,7 +115,7 @@ export default {
data: ydata,
},
],
});
},true);
},
},
};

View File

@ -14,7 +14,6 @@
<script>
import * as echarts from "echarts";
import resize from "@/mixins/ems/resize";
import { formatDate } from "@/filters/ems";
import { batteryAveTemp } from "@/api/ems/dzjk";
export default {
@ -35,12 +34,10 @@ export default {
this.chart = null;
},
methods: {
init(siteId) {
init(siteId,timeRange) {
this.chart.showLoading();
const x = [];
const data1 = [],
data2 = [];
batteryAveTemp(siteId)
const [startTime='', endTime=''] = timeRange;
batteryAveTemp(siteId,startTime,endTime)
.then((response) => {
this.setOption(response?.data?.batteryAveTempList || []);
})
@ -53,9 +50,14 @@ export default {
ydata = [];
data.forEach((element) => {
xdata.push(element.createDate);
ydata.push(element.batteryTemp);
ydata.push(
{
value: element.batteryTemp,
year: element.dateDay
}
);
});
xdata = this.chart.setOption({
this.chart && this.chart.setOption({
legend: {
left: "center",
top: "5",
@ -69,11 +71,24 @@ export default {
containLabel: true,
},
tooltip: {
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;">
<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>'
return result
}
},
textStyle: {
color: "#333333",
@ -103,7 +118,7 @@ export default {
data: ydata,
},
],
});
},true);
},
},
};

View File

@ -14,7 +14,6 @@
<script>
import * as echarts from "echarts";
import resize from "@/mixins/ems/resize";
import { formatDate } from "@/filters/ems";
import { pcsMaxTemp } from "@/api/ems/dzjk";
export default {
@ -35,11 +34,10 @@ export default {
this.chart = null;
},
methods: {
init(siteId) {
init(siteId,timeRange) {
this.chart.showLoading();
const x = [];
const data = [];
pcsMaxTemp(siteId)
const [startTime='', endTime=''] = timeRange;
pcsMaxTemp(siteId,startTime,endTime)
.then((response) => {
this.setOption(response?.data?.pcsMaxTempList || []);
})
@ -60,10 +58,15 @@ export default {
areaStyle: {
// color:'#FFBD00'
},
data: (element.maxTempVoList || []).map((i) => i.temp),
data: (element.maxTempVoList || []).map((i) => {
return {
value: i.temp,
year: i.dateDay
}
}),
});
});
this.chart.setOption({
this.chart && this.chart.setOption({
legend: {
left: "center",
top: "5",
@ -77,11 +80,24 @@ export default {
containLabel: true,
},
tooltip: {
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;">
<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>'
return result
}
},
textStyle: {
color: "#333333",
@ -102,7 +118,7 @@ export default {
},
],
series,
});
},true);
},
},
};

View File

@ -3,6 +3,8 @@
<div class="ssyx-ems-dashboard-editor-container">
<!-- 6个方块-->
<real-time-base-info :data="runningHeadData"/>
<!-- 时间选择 -->
<date-range-select ref="dateRangeSelect" @updateDate="updateDate" style="margin-top:20px;"/>
<!-- echart图表-->
<el-row :gutter="32" style="background:#fff;margin:30px 0;">
<el-col :xs="24" :sm="12" :lg="12">
@ -27,6 +29,7 @@
</style>
<script>
import DateRangeSelect from '@/components/Ems/DateRangeSelect/index.vue'
import RealTimeBaseInfo from "./../RealTimeBaseInfo.vue";
import CnglqxChart from './CnglqxChart.vue'
import PocpjwdChart from './PocpjwdChart.vue'
@ -38,11 +41,13 @@ import intervalUpdate from "@/mixins/ems/intervalUpdate";
export default {
name:'DzjkSbjkSsyx',
components:{RealTimeBaseInfo,CnglqxChart,PocpjwdChart,DcpjwdChart,DcpjsocChart},
components:{RealTimeBaseInfo,CnglqxChart,PocpjwdChart,DcpjwdChart,DcpjsocChart,DateRangeSelect},
mixins:[getQuerySiteId,intervalUpdate],
data() {
return {
runningHeadData:{},//运行信息
timeRange:[],
isInit:true
}
},
methods:{
@ -52,17 +57,27 @@ export default {
this.runningHeadData = response?.data || {}
})
},
// 更新时间范围 重置图表
updateDate(data){
this.timeRange=data
!this.isInit && this.updateChart()
this.isInit = false
},
updateChart(){
this.$refs.cnglqx.init(this.siteId,this.timeRange||[])
this.$refs.pocpjwd.init(this.siteId,this.timeRange||[])
this.$refs.dcpjsoc.init(this.siteId,this.timeRange||[])
this.$refs.dcpjwd.init(this.siteId,this.timeRange||[])
this.updateInterval(this.updateData)
},
updateData(){
this.getRunningHeadData()
this.$refs.cnglqx.init(this.siteId)
this.$refs.pocpjwd.init(this.siteId)
this.$refs.dcpjsoc.init(this.siteId)
this.$refs.dcpjwd.init(this.siteId)
this.updateChart()
},
init(){
this.$refs.dateRangeSelect.init(true)
this.$nextTick(()=>{
this.updateData()
this.updateInterval(this.updateData)
})
}
}

View File

@ -0,0 +1,134 @@
<template>
<div v-loading="loading">
<el-card
v-for="(item,index) in list"
:key="index+'ylLise'"
class="sbjk-card-container running-card-container"
:class="{
'warning-card-container':item.emsCommunicationStatus && item.emsCommunicationStatus !== '0',
'running-card-container':item.emsCommunicationStatus === '0'
}"
shadow="always">
<div slot="header">
<span class="large-title">{{ item.deviceName }}</span>
<div class="info">
<div>
{{
$store.state.ems.communicationStatusOptions[
item.emsCommunicationStatus
]
}}
</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 :hidden="!item.alarmNum" :value="item.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(item,'alarmPoint')"
></i>
</el-badge>
</div>
</div>
<el-row class="device-info-row">
<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>
</el-col>
</el-row>
</el-card>
<el-empty v-show="list.length<=0" :image-size="200"></el-empty>
<point-chart ref="pointChart" :site-id="siteId"/>
<point-table ref="pointTable"/>
</div>
</template>
<script>
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import {getXfDataList} from '@/api/ems/dzjk'
import intervalUpdate from "@/mixins/ems/intervalUpdate";
import pointChart from "./../PointChart.vue";
import PointTable from "@/views/ems/site/sblb/PointTable.vue";
export default {
name: 'DzjkSbjkXf',
mixins: [getQuerySiteId, intervalUpdate],
components: {pointChart, PointTable},
data() {
return {
loading: false,
list: [],
tempData: [
{title: '主电源备用电池状态', attr: 'dczt', unit: ''},
{title: '手自动状态延时状态', attr: 'yszt', unit: ''},
{title: '启动喷洒气体喷洒状态', attr: 'pszt', unit: ''},
{title: '压力开关状态电磁阀状态', attr: 'dcfzt', unit: ''},
]
}
},
methods: {
// 查看设备电位表格
pointDetail(row, dataType) {
const {deviceId} = row
this.$refs.pointTable.showTable({siteId: this.siteId, deviceId, deviceCategory: 'XF'}, dataType)
},
showChart(pointName, deviceId) {
pointName && this.$refs.pointChart.showChart({pointName, deviceCategory: 'XF', deviceId})
},
updateData() {
this.loading = true
getXfDataList(this.siteId).then(response => {
this.list = JSON.parse(JSON.stringify(response?.data || []));
}).finally(() => {
this.loading = false
})
},
init() {
this.updateData()
this.updateInterval(this.updateData)
}
},
mounted() {
}
}
</script>
<style scoped lang="scss">
.sbjk-card-container {
&:not(:last-child) {
margin-bottom: 25px;
}
.el-row {
background-color: #ffffff;
border: 1px solid #eeeeee;
font-size: 14px;
line-height: 16px;
color: #333333;
.el-col {
padding: 12px 0;
text-align: center;
position: relative;
}
.el-col {
border-bottom: 1px solid #eeeeee;
}
.el-col:not(:nth-child(3n)) {
border-right: 1px solid #eeeeee;
}
}
}
</style>

View File

@ -1,4 +1,3 @@
<template>
<div v-loading="loading">
<el-card
@ -7,18 +6,36 @@
class="sbjk-card-container running-card-container"
shadow="always">
<div slot="header">
<span class="large-title">{{index+1}}#{{item.deviceName}}</span>
<span class="large-title">{{ item.deviceName }}</span>
<div class="info">
<div>数据更新时间{{ item.dataUpdateTime || '-' }}</div>
</div>
<el-row>
<el-col v-for="(tempDataItem,tempDataIndex) in tempData" :key="tempDataIndex+'ylTempData'" :span="8">
<div class="alarm">
<el-button type="primary" round size="small" style="margin-right:20px;" @click="pointDetail(item,'point')">
详细
</el-button>
<el-badge :hidden="!item.alarmNum" :value="item.alarmNum || 0" class="item">
<i
class="el-icon-message-solid alarm-icon"
@click="pointDetail(item,'alarmPoint')"
></i>
</el-badge>
</div>
</div>
<el-row class="device-info-row">
<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)">
{{tempDataItem.title}}{{item[tempDataItem.attr]}}<span v-html="tempDataItem.unit"></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>
</el-card>
<el-empty v-show="list.length<=0" :image-size="200"></el-empty>
<point-chart ref="pointChart" :site-id="siteId"/>
<point-table ref="pointTable"/>
</div>
</template>
@ -28,10 +45,12 @@ import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import {getCoolingDataList} from '@/api/ems/dzjk'
import intervalUpdate from "@/mixins/ems/intervalUpdate";
import pointChart from "./../PointChart.vue";
import PointTable from "@/views/ems/site/sblb/PointTable.vue";
export default {
name: 'DzjkSbjkYl',
mixins: [getQuerySiteId, intervalUpdate],
components:{pointChart},
components: {pointChart, PointTable},
data() {
return {
loading: false,
@ -48,6 +67,11 @@ export default {
}
},
methods: {
// 查看设备电位表格
pointDetail(row, dataType) {
const {deviceId} = row
this.$refs.pointTable.showTable({siteId: this.siteId, deviceId, deviceCategory: 'COOLING'}, dataType)
},
showChart(pointName, deviceId) {
pointName && this.$refs.pointChart.showChart({pointName, deviceCategory: 'COOLING', deviceId})
},
@ -55,7 +79,9 @@ export default {
this.loading = true
getCoolingDataList(this.siteId).then(response => {
this.list = JSON.parse(JSON.stringify(response?.data || []));
}).finally(() => {this.loading = false})
}).finally(() => {
this.loading = false
})
},
init() {
this.updateData()
@ -73,23 +99,5 @@ export default {
&:not(:last-child) {
margin-bottom: 25px;
}
.el-row{
background-color: #ffffff;
border:1px solid #eeeeee;
font-size: 14px;
line-height: 16px;
color: #333333;
.el-col{
padding:12px 0;
text-align: center;
position: relative;
}
.el-col{
border-bottom: 1px solid #eeeeee;
}
.el-col:not(:nth-child(3n)){
border-right: 1px solid #eeeeee;
}
}
}
</style>

View File

@ -1,4 +1,3 @@
<template>
<div style="width:100%" v-loading="loading">
<!-- 搜索栏-->
@ -22,6 +21,9 @@
<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
@ -122,6 +124,7 @@
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import {getAmmeterData} from '@/api/ems/dzjk'
import {formatDate} from "@/filters/ems";
export default {
name: 'DzjkTjbbDbbb',
mixins: [getQuerySiteId],
@ -142,6 +145,16 @@ export default {
}
},
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开始搜索
@ -184,10 +197,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()
},
},

View File

@ -16,7 +16,8 @@
size="mini"
:class="{ activeBtn: activeBtn === item.id }"
@click="changeDataType(item.id)"
>{{ item.name }}</el-button
>{{ item.name }}
</el-button
>
</el-button-group>
<div id="dcdEchart" style="height: 310px"></div>
@ -28,9 +29,10 @@
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 {getStackData} from "@/api/ems/dzjk";
import {formatDate} from "@/filters/ems";
import DateRangeSelect from "@/components/Ems/DateRangeSelect/index.vue";
export default {
name: "DzjkTjbbDcdqx",
components: {DateRangeSelect},
@ -142,7 +144,7 @@ export default {
},
legend: {
left: "center",
bottom: "15",
top: "10",
},
tooltip: {
trigger: "axis",
@ -160,10 +162,25 @@ export default {
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,
},
};
}),
},
@ -176,7 +193,7 @@ export default {
init() {
this.$nextTick(() => {
this.initChart();
this.$refs.dateRangeSelect.init();
this.$refs.dateRangeSelect.init(true);
});
},
},

View File

@ -8,7 +8,6 @@
<span class="card-title">功率曲线</span>
<date-range-select
ref="dateRangeSelect"
@reset="resetTime"
@updateDate="updateDate"
/>
</div>
@ -22,9 +21,10 @@
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 {getPowerData} from "@/api/ems/dzjk";
import {formatDate} from "@/filters/ems";
import DateRangeSelect from "@/components/Ems/DateRangeSelect/index.vue";
export default {
name: "DzjkTjbbGlqx",
components: {DateRangeSelect},
@ -38,7 +38,6 @@ export default {
},
dateRange: [],
loading: false,
dateRangeInit: true,
};
},
methods: {
@ -47,19 +46,11 @@ export default {
this.dateRange = data || [];
this.getData();
},
resetTime() {
this.dateRangeInit = true;
},
getData() {
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),
@ -90,7 +81,7 @@ export default {
},
legend: {
left: "center",
bottom: "15",
top: "10",
},
tooltip: {
trigger: "axis",
@ -109,18 +100,45 @@ export default {
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,
},
},
],
},
@ -133,7 +151,6 @@ export default {
},
init() {
this.$nextTick(() => {
this.dateRangeInit = true;
this.initChart();
this.$refs.dateRangeSelect.init();
});

View File

@ -16,7 +16,8 @@
size="mini"
:class="{ activeBtn: activeBtn === item.id }"
@click="changeDataType(item.id)"
>{{ item.name }}</el-button
>{{ item.name }}
</el-button
>
</el-button-group>
<div id="pcsEchart" style="height: 310px"></div>
@ -28,9 +29,10 @@
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 {getPCSData} from "@/api/ems/dzjk";
import {formatDate} from "@/filters/ems";
import DateRangeSelect from "@/components/Ems/DateRangeSelect/index.vue";
export default {
name: "DzjkTjbbPcsqx",
components: {DateRangeSelect},
@ -158,7 +160,7 @@ export default {
},
legend: {
left: "center",
bottom: "15",
top: "10",
},
tooltip: {
trigger: "axis",
@ -176,10 +178,25 @@ export default {
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,
},
};
}),
},
@ -192,7 +209,7 @@ export default {
init() {
this.$nextTick(() => {
this.initChart();
this.$refs.dateRangeSelect.init();
this.$refs.dateRangeSelect.init(true);
});
},
},

View File

@ -0,0 +1,228 @@
<template>
<div style="width:100%" v-loading="loading">
<!-- 搜索栏-->
<el-form :inline="true" class="select-container">
<el-form-item label="时间选择">
<el-date-picker
v-model="dateRange"
type="daterange"
range-separator=""
start-placeholder="开始日期"
end-placeholder="结束日期"
value-format="yyyy-MM-dd"
:clearable="false"
:picker-options="pickerOptions"
:default-value="defaultDateRange"
></el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="onSearch" native-type="button">搜索</el-button>
</el-form-item>
<el-form-item>
<el-button @click="onReset" native-type="button">重置</el-button>
</el-form-item>
<el-form-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="汇总" min-width="100px" align="center">
<el-table-column
prop="dataTime"
label="日期"
min-width="100px" align="center">
</el-table-column>
</el-table-column>
<!--充电量列-->
<el-table-column label="充电价格" align="center">
<el-table-column
align="center"
prop="activePeakPrice"
label="尖">
</el-table-column>
<el-table-column
align="center"
prop="activeHighPrice"
label="峰">
</el-table-column>
<el-table-column
align="center"
prop="activeFlatPrice"
label="平">
</el-table-column>
<el-table-column
align="center"
prop="activeValleyPrice"
label="谷">
</el-table-column>
<el-table-column
align="center"
prop="activeTotalPrice"
label="总">
</el-table-column>
</el-table-column>
<!--充电量列-->
<el-table-column label="放电价格" align="center">
<el-table-column
align="center"
prop="reActivePeakPrice"
label="尖">
</el-table-column>
<el-table-column
align="center"
prop="reActiveHighPrice"
label="峰">
</el-table-column>
<el-table-column
align="center"
prop="reActiveFlatPrice"
label="平">
</el-table-column>
<el-table-column
align="center"
prop="reActiveValleyPrice"
label="谷">
</el-table-column>
<el-table-column
align="center"
prop="reActiveTotalPrice"
label="总">
</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"
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 {getAmmeterRevenueData} from '@/api/ems/dzjk'
import {formatDate} from "@/filters/ems";
export default {
name: 'DzjkTjbbSybb',
mixins: [getQuerySiteId],
data() {
return {
loading: false,
pickerOptions: {
disabledDate(time) {
return time.getTime() > Date.now();
},
},
defaultDateRange: [],//默认展示的时间
dateRange: [],
tableData: [],
pageSize: 10,//分页栏当前每个数据总数
pageNum: 1,//分页栏当前页数
totalSize: 0,//table表格数据总数
}
},
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开始搜索
this.getData()
},
// 重置
onReset() {
this.dateRange = this.defaultDateRange
this.pageNum = 1//每次搜索从1开始搜索
this.getData()
},
// 分页
handleSizeChange(val) {
this.pageSize = val;
this.$nextTick(() => {
this.getData()
})
},
handleCurrentChange(val) {
this.pageNum = val
this.$nextTick(() => {
this.getData()
})
},
// 获取数据
getData() {
this.loading = true
const {siteId, pageNum, pageSize} = this
const [startTime = '', endTime = ''] = (this.dateRange || [])
getAmmeterRevenueData({siteId: siteId, startTime, endTime, pageSize, pageNum}).then(response => {
this.tableData = response?.rows || [];
this.totalSize = response?.total || 0
}).finally(() => {
this.loading = false
})
},
init() {
this.dateRange = []
this.tableData = []
this.totalSize = 0
this.pageSize = 10
this.pageNum = 1
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()
},
},
}
</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 {
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

@ -34,10 +34,10 @@
<div
class="status"
:class="
item.runningStatus === '2' ? 'status-running' : ''
item.deviceStatus === '1' ? 'status-running' : ''
"
>
{{ deviceStatusOptions[item.runningStatus] }}
{{ deviceStatusOptions[item.deviceStatus] }}
</div>
<div class="row-items-img">
<img
@ -68,10 +68,10 @@
<div
class="status"
:class="
item.runningStatus === '2' ? 'status-running' : ''
item.deviceStatus === '1' ? 'status-running' : ''
"
>
{{ deviceStatusOptions[item.runningStatus] }}
{{ deviceStatusOptions[item.deviceStatus] }}
</div>
<div class="row-items-img">
<img
@ -107,10 +107,10 @@
<div
class="status"
:class="
item.runningStatus === '2' ? 'status-running' : ''
item.deviceStatus === '1' ? 'status-running' : ''
"
>
{{ deviceStatusOptions[item.runningStatus] }}
{{ deviceStatusOptions[item.deviceStatus] }}
</div>
<div class="row-items-img row-items-img-bms">
<div style="position:relative;">
@ -150,10 +150,10 @@
<div
class="status"
:class="
item.runningStatus === '2' ? 'status-running' : ''
item.deviceStatus === '1' ? 'status-running' : ''
"
>
{{ deviceStatusOptions[item.runningStatus] }}
{{ deviceStatusOptions[item.deviceStatus] }}
</div>
<div class="row-items-img">
<img
@ -171,14 +171,14 @@
<div
class="status"
:class="
item.children[0].runningStatus === '2'
item.children[0].deviceStatus === '1'
? 'status-running'
: ''
"
>
{{
deviceStatusOptions[
item.children[0].runningStatus
item.children[0].deviceStatus
]
}}
</div>
@ -207,6 +207,7 @@
import {getDeviceList} from "@/api/ems/site";
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
import {mapState} from "vuex";
export default {
name: "DzjkZxlt",
mixins: [getQuerySiteId],
@ -329,6 +330,7 @@ $lineColor: #86bcc7;
display: flex;
position: relative;
}
//云 、计算机 、箭头
.top {
z-index: 2;
@ -343,6 +345,7 @@ $lineColor: #86bcc7;
//云 样式
.cloud-container {
margin: 0 auto;
.cloud {
width: 60px;
height: 26px;
@ -354,6 +357,7 @@ $lineColor: #86bcc7;
font-size: 14px;
line-height: 26px;
}
.cloud:before,
.cloud:after {
content: "";
@ -363,20 +367,24 @@ $lineColor: #86bcc7;
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;
@ -384,6 +392,7 @@ $lineColor: #86bcc7;
background-color: #5ea9df;
margin: 0 10px;
position: relative;
&::after {
content: "";
position: absolute;
@ -392,9 +401,11 @@ $lineColor: #86bcc7;
height: 0;
}
}
.top-arrows {
vertical-align: super;
}
.top-arrows::after {
top: -4px;
border-bottom: 6px solid transparent;
@ -403,8 +414,10 @@ $lineColor: #86bcc7;
border-top: 6px solid transparent;
left: -11px;
}
.bottom-arrows {
margin-top: 8px;
&::after {
top: -4px;
border-top: 6px solid transparent;
@ -425,6 +438,7 @@ $lineColor: #86bcc7;
font-weight: bold;
position: relative;
background: #fff;
img {
width: 80px;
height: auto;
@ -432,6 +446,7 @@ $lineColor: #86bcc7;
}
}
}
.outer-border {
position: relative;
width: fit-content;
@ -467,8 +482,10 @@ $lineColor: #86bcc7;
color: #000;
font-weight: bolder;
}
.row-lists {
position: relative;
.row-items {
position: relative;
padding: 5px 0;
@ -503,16 +520,20 @@ $lineColor: #86bcc7;
border-radius: 2px;
background: #aaaaaa;
color: #ffffff;
&.status-running {
background: #00c69c;
}
}
// 图片+设备名称
.row-items-img {
position: relative;
padding-top: 12px;
&.row-items-img-bms {
padding-top: 14px;
.num {
position: absolute;
top: -2px;
@ -526,21 +547,26 @@ $lineColor: #86bcc7;
color: #fff;
}
}
img {
width: 80px;
height: auto;
display: block;
position: relative;
&.img-lq {
width: 50px;
}
&.img-pcs {
width: 50px;
}
&.img-db {
width: 56px;
}
}
.name {
position: absolute;
top: 1px;
@ -559,19 +585,24 @@ $lineColor: #86bcc7;
&:not(:last-child) {
margin-right: 30px;
}
.row-items {
display: flex;
&::after {
display: none;
}
.parent-dash {
position: relative;
z-index: 2;
background-color: #fff;
> div {
z-index: 2;
position: inherit;
}
&::after {
z-index: 1;
content: "";
@ -585,16 +616,19 @@ $lineColor: #86bcc7;
transform: scale(0.4, 1);
}
}
.children-dash {
position: relative;
z-index: 2;
background-color: #fff;
margin: -20px 0 0 26px;
height: fit-content;
> div {
z-index: 2;
position: inherit;
}
&::after {
z-index: 1;
content: "";

View File

@ -98,13 +98,9 @@
import * as echarts from "echarts";
import resize from "@/mixins/ems/resize";
import {getAllSites} from "@/api/ems/zddt";
import {
getAllDeviceCategory,
getPointValueList,
pointFuzzyQuery,
getAllBatteryIdsBySites,
} from "@/api/ems/search";
import {getAllBatteryIdsBySites, getAllDeviceCategory, getPointValueList, pointFuzzyQuery,} from "@/api/ems/search";
import DateTimeSelect from "./DateTimeSelect.vue";
export default {
name: "Search",
mixins: [resize],
@ -214,11 +210,26 @@ export default {
this.getDate();
},
setOption(data) {
// 点位类型 dataType 1-瞬时值 2-累计值 仅当值为2展示差值
// 图表类型 chartType 1-曲线图2-箱线图
if (!this.chart) return;
this.chart.clear();
console.log("返回的数据", data);
if (!data || data.length <= 0) {
this.$message.warning("暂无数据");
}
console.log('展示的图表类型chartType', data[0].chartType)
if (data[0].chartType === 2) {
// 箱型图
this.setBoxOption(data)
} else {
//折线图
this.setLineOption(data)
}
},
setLineOption(data) {
let dataset = [];
if (data.length > 0) {
data.forEach((item, index) => {
item.deviceList.forEach((inner) => {
dataset.push({
@ -280,10 +291,7 @@ export default {
});
});
});
} else {
this.$message.warning("暂无数据");
}
console.log("图表数据", dataset);
console.log("折线图图表数据", dataset);
this.chart.setOption({
legend: {
// left: 'center',
@ -323,6 +331,119 @@ export default {
series: dataset,
});
},
setBoxOption(data) {
let dataset = [];
data.forEach((item, index) => {
item.deviceList.forEach((inner) => {
dataset.push({
name: `${
this.isDtdc
? `${inner.parentDeviceId ? inner.parentDeviceId + "-" : ""}`
: ""
}${inner.deviceId}`,
type: "boxplot",
// markPoint: {
// symbolSize: 30,
// emphasis: {
// disabled: false//打开 鼠标高亮
// },
// data: [//最大值、最小值
// {
// // type: 'max',
// name: `最大值`,
// coord: [inner.maxDate, inner.maxValue],
// relativeTo: 'coordinate',
// label: {
// position: "top",
// formatter: item.dataType === 2 ? ([
// `最大值:${inner.maxValue}`,
// // `平均值:${inner.avgValue}`,
// `差值:${inner.diffValue}`,
// ]).join('\n') : ([
// `最大值:${inner.maxValue}`,
// // `平均值:${inner.avgValue}`,
// ]).join('\n'),
// },
// },
// {
// // type: 'min',
// name: `最小值`,
// coord: [inner.minDate, inner.minValue],
// relativeTo: 'coordinate',
// label: {
// position: "top",
// formatter: item.dataType === 2 ? ([
// `最小值:${inner.minValue}`,
// // `平均值:${inner.avgValue}`,
// `差值:${inner.diffValue}`,
// ]).join('\n') : ([
// `最小值:${inner.minValue}`,
// // `平均值:${inner.avgValue}`,
// ]).join('\n'),
// }
// }
// ]
// },
xdata: [],
data: [],
});
const length = dataset.length;
inner.pointValueList.forEach((value) => {
const {valueDate, min, q1, median, q3, max} = value
dataset[length - 1].xdata.push(valueDate);
dataset[length - 1].data.push([min, q1, median, q3, max]);
});
});
});
console.log("箱型图图表数据", dataset);
this.chart.setOption({
legend: {
// left: 'center',
// top: '10',
},
grid: {
containLabel: true,
},
tooltip: {
trigger: 'item',
formatter: function (params) {
let data = params.data;
let result = params.marker + params.name + ' ' + params.seriesName + '<br/>';
result += '最小值: ' + data[1] + '<br/>';
result += '平均值: ' + data[3] + '<br/>';
result += '最大值: ' + data[5];
return result;
}
// trigger: "axis",
// axisPointer: {
// type: 'cross',
// },
// axisPointer: {
// // 坐标轴指示器,坐标轴触发有效
// type: "shadow", // 默认为直线,可选为:'line' | 'shadow'
// },
},
textStyle: {
color: "#333333",
},
xAxis: {type: "category", data: dataset?.[0]?.xdata || []},
yAxis: {
type: "value",
},
dataZoom: [
{
type: "inside",
start: 0,
end: 100,
},
{
start: 0,
end: 100,
},
],
series: dataset,
});
},
submitForm() {
this.getDate();
},
@ -362,7 +483,8 @@ export default {
.then((response) => {
this.siteList = response.data || [];
})
.finally(() => {});
.finally(() => {
});
},
getDate() {
this.$refs.form.validate((valid) => {

View File

@ -1,11 +1,23 @@
<template>
<el-dialog :visible.sync="dialogTableVisible" :close-on-press-escape="false" :close-on-click-modal="false" :show-close="false" destroy-on-close lock-scroll append-to-body width="400px" class="ems-dialog" :title="mode === 'add'?'新增配置':`编辑配置` " >
<el-form v-loading="loading>0" ref="addTempForm" :model="formData" :rules="rules" size="medium" label-width="140px">
<el-form-item label="订阅topic" prop="deviceName">
<el-form-item label="站点" prop="siteId">
<el-select v-model="formData.siteId" :disabled="mode === 'edit'" placeholder="请选择站点" :loading="searchLoading" loading-text="正在加载数据">
<el-option v-for="(item,index) in siteList" :key="index+'zdxeSelect'" :label="item.siteName" :value="item.siteId" ></el-option>
</el-select>
</el-form-item>
<el-form-item label="消息等级" prop="qos">
<el-select v-model="formData.qos" placeholder="请选择消息等级">
<el-option :value="1">1</el-option>
<el-option :value="2">2</el-option>
<el-option :value="3">3</el-option>
</el-select>
</el-form-item>
<el-form-item label="订阅topic" prop="mqttTopic">
<el-input v-model="formData.mqttTopic" placeholder="请输入" clearable :style="{width: '100%'}">
</el-input>
</el-form-item>
<el-form-item label="topic描述" prop="description">
<el-form-item label="topic描述" prop="topicName">
<el-input v-model="formData.topicName" type="textarea" placeholder="请输入" clearable :style="{width: '100%'}">
</el-input>
</el-form-item>
@ -18,18 +30,29 @@
</template>
<script>
import {editMqtt,addMqtt,getMqttDetail} from "@/api/ems/site";
import {getAllSites} from '@/api/ems/zddt'
export default {
data() {
return {
loading:0,
siteList:[],
searchLoading:false,
dialogTableVisible:false,
mode:'',
formData: {
id:'',//设备唯一标识
siteId:'',
qos:'',
topicName:'',
mqttTopic:''
},
rules: {
siteId:[
{ required: true, message: '请选择站点', trigger: 'blur'},
],
qos:[
{ required: true, message: '请选择消息等级', trigger: 'blur'},
],
mqttTopic:[
{ required: true, message: '请输入订阅topic', trigger: 'blur'},
],
@ -42,6 +65,7 @@ export default {
methods: {
showDialog(id){
this.dialogTableVisible = true
this.getZdList()
if(id){
this.mode = 'edit'
this.formData.id = id
@ -49,12 +73,21 @@ export default {
}else{
this.mode = 'add'
}
},
//获取站点列表
getZdList(){
this.searchLoading=true
getAllSites().then(response => {
this.siteList = response?.data || []
}).finally(() => {this.searchLoading=false})
},
getDetail(id){
getMqttDetail(id).then(response => {
const {topicName='',mqttTopic=''} = JSON.parse(JSON.stringify(response?.data || {}));
const {topicName='',mqttTopic='',qos='',siteId=''} = JSON.parse(JSON.stringify(response?.data || {}));
this.formData.mqttTopic=mqttTopic;
this.formData.topicName=topicName;
this.formData.qos=qos;
this.formData.siteId=siteId;
})
},
saveDialog() {
@ -63,11 +96,13 @@ export default {
this.loading+=1
const {
id='',
siteId='',
qos='',
mqttTopic='',//站点ID
topicName='',//设备id
}= this.formData;
if(this.mode === 'add'){
addMqtt( {mqttTopic,topicName}).then(response => {
addMqtt( {mqttTopic,topicName,siteId,qos}).then(response => {
if(response.code === 200){
//新增成功
// 关闭弹窗 更新表格
@ -78,7 +113,7 @@ export default {
this.loading-=1
})
}else{
editMqtt({mqttTopic,topicName,id}).then(response => {
editMqtt({mqttTopic,topicName,id,siteId,qos}).then(response => {
if(response.code === 200){
//新增成功
// 关闭弹窗 更新表格

View File

@ -1,6 +1,11 @@
<template>
<div class="ems-dashboard-editor-container" style="background-color: #ffffff" v-loading="loading">
<el-form :inline="true" class="select-container">
<el-form-item label="站点选择">
<el-select v-model="form.siteId" placeholder="请选择换电站名称" :loading="searchLoading" loading-text="正在加载数据" clearable>
<el-option :label="item.siteName" :value="item.siteId" v-for="(item,index) in siteList" :key="index+'zdxeSelect'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="订阅topic">
<el-input
v-model="form.mqttTopic"
@ -29,6 +34,14 @@
max-height="600px"
stripe
style="width: 100%;margin-top: 25px">
<el-table-column
label="站点"
prop="siteId">
</el-table-column>
<el-table-column
label="消息等级"
prop="qos">
</el-table-column>
<el-table-column
label="订阅topic"
prop="mqttTopic">
@ -77,6 +90,7 @@
<script>
import {deleteMqtt,getMqttList} from '@/api/ems/site'
import {getAllSites} from '@/api/ems/zddt'
import AddMqtt from './AddMqtt.vue'
export default {
name: "Mqtt",
@ -85,9 +99,12 @@ export default {
data() {
return {
form:{
siteId:"",
topicName:'',
mqttTopic:''
},
siteList:[],
searchLoading:false,
loading:false,
tableData:[],
pageSize:10,//分页栏当前每个数据总数
@ -116,17 +133,26 @@ export default {
},
onReset(){
this.form={
siteId:'',
topicName:'',
mqttTopic:''
}
this.pageNum =1//每次搜索从1开始搜索
this.getData()
},
//获取站点列表
getZdList(){
this.searchLoading=true
return getAllSites().then(response => {
this.siteList = response?.data || []
// if( this.siteList.length>0 ) this.siteId = this.siteList[0].siteId
}).finally(() => {this.searchLoading=false})
},
getData(){
this.loading=true;
const {mqttTopic,topicName} = this.form;
const {mqttTopic,topicName,siteId} = this.form;
const {pageNum,pageSize} = this;
getMqttList({pageNum,pageSize,mqttTopic,topicName}).then(response => {
getMqttList({pageNum,pageSize,mqttTopic,topicName,siteId}).then(response => {
this.tableData=response?.rows || [];
this.totalSize = response?.total || 0
}).finally(() => {this.loading=false})
@ -168,6 +194,7 @@ export default {
},
mounted() {
this.loading=true
this.getZdList()
this.getData()
}
}

View File

@ -111,7 +111,9 @@
<el-cascader
v-model="item.deviceId"
:options="childOptions"
:props="props"
:show-all-levels="false"
:ref="'protectionSettings'+index"
@change="(v)=>handleChange(v,'protectionSettings',index)"
></el-cascader>
</div>
@ -226,6 +228,8 @@
v-model="item.deviceId"
:show-all-levels="false"
:options="childOptions"
:props="props"
:ref="'protectionPlan'+index"
@change="(v)=>handleChange(v,'protectionPlan',index)"
></el-cascader>
</div>
@ -270,13 +274,9 @@
import {mapState} from "vuex";
import {getAllSites} from "@/api/ems/zddt";
import {validText} from "@/utils/validate";
import {
updateProtectPlan,
addProtectPlan,
getProtectPlan,
getDeviceListBySiteAndCategory
} from "@/api/ems/site";
import {addProtectPlan, getDeviceListBySiteAndCategory, getProtectPlan, updateProtectPlan} from "@/api/ems/site";
import {getAllDeviceCategory, pointFuzzyQuery} from "@/api/ems/search";
export default {
data() {
const validateText = (rule, value, callback) => {
@ -287,6 +287,14 @@ export default {
}
};
return {
props: {
// emitPath: false,//在选中节点改变时,是否返回由该节点所在的各级菜单的值所组成的数组,若设置 false则只返回该节点的值
lazy: true,
lazyLoad: (node, resolve) => {
console.log('---------node', node)
this.getDeviceList(node, resolve)
}
},
mode: '',
loading: 0,
childOptions: [],
@ -349,8 +357,8 @@ export default {
this.getZdList();
this.getDeviceCategoryList().then(() => {
if (id && siteId) {
this.getDeviceList('PCS',siteId)
this.getDeviceList('STACK',siteId)
// this.getDeviceList('PCS', siteId)
// this.getDeviceList('STACK', siteId)
}
});
if (id) {
@ -369,20 +377,39 @@ export default {
description: data?.description || '',//方案描述
}
const plan = (JSON.parse(data?.protectionPlan || [])).map(item => {
const index = this.childOptions.findIndex(i => i.value === item.deviceCategory)
if (index > -1) {
!this.childOptions[index].children.find(i => i.value === item.deviceId) && this.childOptions[index].children.push({
value: item.deviceId,
label: item.deviceName,
leaf: true
})
}
return Object.assign({}, item, {
deviceId: [item.deviceCategory || '', item.deviceId || ''],
deviceName: [item.categoryName || '', item.deviceName || ''],
})
})
const settings = (JSON.parse(data?.protectionSettings || [])).map(item => {
const index = this.childOptions.findIndex(i => i.value === item.deviceCategory)
if (index > -1) {
!this.childOptions[index].children.find(i => i.value === item.deviceId) && this.childOptions[index].children.push({
value: item.deviceId,
label: item.deviceName,
leaf: true
})
}
return Object.assign({}, item, {
deviceId: [item.deviceCategory || '', item.deviceId || ''],
deviceName: [item.categoryName || '', item.deviceName || ''],
})
})
this.$nextTick(() => {
this.protectionPlan.splice(0, 0, ...plan)
this.protectionSettings.splice(0, 0, ...settings)
})
console.log('获取设备保护详情并初始化',this.formData,this.protectionPlan,this.protectionSettings)
console.log('获取设备保护详情并初始化', this.formData, this.protectionPlan, this.protectionSettings, this.childOptions)
})
} else {
this.mode = 'add'
@ -392,6 +419,7 @@ export default {
addRow(type) {
const item = type === 'protectionSettings' ? {
deviceId: [],//设备ID
deviceName: [],
deviceCategory: "",//设备类型 英文
categoryName: '',//设备类型名称 中文
point: "",//点位 英文
@ -403,6 +431,7 @@ export default {
relationNext: "",//与下一个点位的关系
} : {
deviceId: [],
deviceName: [],
deviceCategory: "",//设备类型 英文
categoryName: '',//设备类型名称 中文
point: "",
@ -461,14 +490,14 @@ export default {
this.loading += 1;
return getAllDeviceCategory()
.then((response) => {
const data = (response?.data || []).filter(item => ['PCS','STACK'].includes(item.code));
// this.childOptions=[]
const data = (response?.data || []);
this.$set(this, 'childOptions', [])
let arr = []
data.forEach((item) => {
arr.push({
value: item.code,
label: item.name,
leaf: false,
children: []
})
})
@ -480,21 +509,28 @@ export default {
});
},
//获取设备列表-区分站点
getDeviceList(deviceCategory,siteId){
this.$nextTick(()=>{
getDeviceListBySiteAndCategory({siteId:siteId || this.formData.siteId,deviceCategory}).then((response) => {
getDeviceList(node, resolve) {
if (!this.formData.siteId) {
this.$message({
type: "warning",
message: "请先选择站点",
});
return resolve([])
}
getDeviceListBySiteAndCategory({
siteId: this.formData.siteId,
deviceCategory: node.value
}).then((response) => {
const data = (response?.data || []).map(item => {
return {
label: item.deviceName,
value: item.id,
leaf: true
}
})
const index = this.childOptions.findIndex(item=>item.value === deviceCategory)
if(index>-1){
const length = this.childOptions[index].children.length
this.childOptions[index].children.splice(0,length,...data)
}
})
resolve(data)
}).catch(() => {
resolve([])
})
},
//更新站点下面的设备列表
@ -503,17 +539,17 @@ export default {
const length = item.children.length
item.children.splice(0, length)
})
this.getDeviceList('PCS')
this.getDeviceList('STACK')
},
//选中设备类型、设备
handleChange(data, type, index) {
const deviceCategory = data[0],deviceId=data[1]
console.log('设置选中设备类型、设备',deviceCategory,deviceId,type,index)
console.log('设置选中设备类型、设备', data, type, index)
const {label = '', parent = {}} = this.$refs[type + index][0].getCheckedNodes()[0]
console.log('选中设备的名称', parent.label, label)
const item = Object.assign({}, this[type][index], {
deviceId: data,
deviceCategory,
categoryName : this.childOptions.find(i=>i.value === deviceCategory).label,
deviceName: [parent.label, label],
deviceCategory: data[0],
categoryName: parent.label,
pointName: '',
point: ''
})
@ -547,6 +583,7 @@ export default {
item.point = ""
item.pointName = ""
item.deviceId = []
item.deviceName = []
item.categoryName = ''
item.deviceCategory = ''
});
@ -561,6 +598,7 @@ export default {
item.point = ""
item.pointName = ""
item.deviceId = []
item.deviceName = []
item.categoryName = ''
item.deviceCategory = ''
});
@ -597,6 +635,7 @@ export default {
}
}[type][name]
}
this.$refs.addTempForm.validate((valid) => {
if (!valid) return;
const {
@ -659,11 +698,13 @@ export default {
const settings = protectionSettings.map(item => {
return Object.assign({}, item, {
deviceId: item.deviceId[1],
deviceName: item.deviceName[1],
})
})
const plan = protectionPlan.map(item => {
return Object.assign({}, item, {
deviceId: item.deviceId[1],
deviceName: item.deviceName[1],
})
})
this.loading += 1;
@ -727,35 +768,43 @@ export default {
.items-container {
margin-top: 40px;
margin-bottom: 20px;
.item-title {
line-height: 16px;
padding: 10px 0;
color: #000;
}
}
.time-lists-container {
width: 100%;
border: 1px solid #eee;
.time-lists {
&:not(:last-child) {
border-bottom: 1px solid #eee;
}
display: flex;
& > div {
width: 16%;
box-sizing: border-box;
text-align: center;
padding: 10px 15px;
&:not(:last-child) {
width: 28%;
border-right: 1px solid #eee;
}
.el-date-editor.el-input,
.el-date-editor.el-input__inner {
width: 100%;
}
}
}
.time-lists-title {
color: #000;
font-size: 12px;

View File

@ -1,9 +1,14 @@
<template>
<el-dialog :visible.sync="dialogTableVisible" :close-on-press-escape="false" :close-on-click-modal="false" :show-close="false" destroy-on-close lock-scroll append-to-body width="600px" class="ems-dialog" :title="mode === 'add'?'新增设备':`编辑设备` " >
<el-form v-loading="loading>0" ref="addTempForm" :model="formData" :rules="rules" size="medium" label-width="140px">
<el-dialog :visible.sync="dialogTableVisible" :close-on-press-escape="false" :close-on-click-modal="false"
:show-close="false" destroy-on-close lock-scroll append-to-body width="800px" class="ems-dialog"
:title="mode === 'add'?'新增设备':`编辑设备` ">
<div v-loading="loading>0">
<el-form v-loading="loading>0" ref="addTempForm" inline :model="formData" :rules="rules" size="medium"
label-width="120px" class="device-form">
<el-form-item label="站点" prop="siteId">
<el-select v-model="formData.siteId" placeholder="请选择" :style="{width: '100%'}" @change="changeType">
<el-option :label="item.siteName" :value="item.siteId" v-for="(item,index) in siteList" :key="index+'siteOptions'"></el-option>
<el-option :label="item.siteName" :value="item.siteId" v-for="(item,index) in siteList"
:key="index+'siteOptions'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="设备id" prop="deviceId">
@ -15,27 +20,35 @@
</el-input>
</el-form-item>
<el-form-item label="设备描述" prop="description">
<el-input v-model="formData.description" type="textarea" placeholder="请输入" clearable :style="{width: '100%'}">
<el-input v-model="formData.description" type="textarea" placeholder="请输入" clearable
:style="{width: '100%'}">
</el-input>
</el-form-item>
<el-form-item label="工作状态" prop="communicationStatus">
<el-select v-model="formData.communicationStatus" placeholder="请选择" :style="{width: '100%'}">
<el-option :label="value" :value="key" v-for="(value,key) in communicationStatusOptions" :key="key+'communicationStatusOptions'"></el-option>
<el-option :label="value" :value="key" v-for="(value,key) in communicationStatusOptions"
:key="key+'communicationStatusOptions'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="设备类型" prop="deviceType">
<el-select v-model="formData.deviceType" placeholder="请选择" :style="{width: '100%'}">
<el-option :label="value" :value="key" v-for="(value,key) in deviceTypeOptions" :key="key+'deviceTypeOptions'"></el-option>
<el-option :label="value" :value="key" v-for="(value,key) in deviceTypeOptions"
:key="key+'deviceTypeOptions'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="设备类别" prop="deviceCategory">
<el-select v-model="formData.deviceCategory" placeholder="请选择" :style="{width: '100%'}" @change="changeType">
<el-option :label="item.name" :value="item.code" v-for="(item,index) in deviceCategoryList" :key="index+'deviceCategoryList'"></el-option>
<el-select v-model="formData.deviceCategory" placeholder="请选择" :style="{width: '100%'}"
@change="changeType">
<el-option :label="item.name" :value="item.code" v-for="(item,index) in deviceCategoryList"
:key="index+'deviceCategoryList'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="上级设备" prop="parentId" v-if="dccDeviceCategoryList.includes(formData.deviceCategory)">
<el-select v-model="formData.parentId" :placeholder="parentDeviceList.length === 0 && !formData.siteId ? '请先选择站点' : '请选择'" :style="{width: '100%'}">
<el-option :label="item.deviceName" :value="item.id" v-for="(item,index) in parentDeviceList" :key="index+'parentDeviceList'" ></el-option>
<el-select v-model="formData.parentId"
:placeholder="parentDeviceList.length === 0 && !formData.siteId ? '请先选择站点' : '请选择'"
:style="{width: '100%'}">
<el-option :label="item.deviceName" :value="item.id" v-for="(item,index) in parentDeviceList"
:key="index+'parentDeviceList'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="TCP设备的ip地址" prop="ipAddress" v-if="formData.deviceType === 'TCP'">
@ -46,7 +59,10 @@
<el-input v-model="formData.ipPort" placeholder="请输入" clearable :style="{width: '100%'}">
</el-input>
</el-form-item>
<el-form-item label="从站地址" prop="slaveId" v-if="formData.deviceType === 'TCP'">
<el-input v-model="formData.slaveId" placeholder="请输入" clearable :style="{width: '100%'}">
</el-input>
</el-form-item>
<el-form-item label="串口路径" prop="serialPort">
<el-input v-model="formData.serialPort" placeholder="请输入" clearable :style="{width: '100%'}">
</el-input>
@ -72,6 +88,49 @@
</el-form-item>
</el-form>
<!-- pcs配置-->
<el-form v-if="isPcs" ref="pcsSettingForm" inline :model="pcsSetting" size="medium"
label-width="120px" class="device-form" :rules="pcsSettingRules">
<div style="font-size: 14px;padding: 10px 0 20px;font-weight: 600;">PCS配置</div>
<el-form-item label="开关机地址" prop="pointAddress">
<el-input v-model="pcsSetting.pointAddress" placeholder="请输入" clearable :style="{width: '100%'}">
</el-input>
</el-form-item>
<el-form-item label="功率地址" prop="powerAddress">
<el-input v-model="pcsSetting.powerAddress" placeholder="请输入" clearable :style="{width: '100%'}">
</el-input>
</el-form-item>
<el-form-item label="开机指令" prop="startCommand">
<el-input v-model="pcsSetting.startCommand" placeholder="请输入" clearable :style="{width: '100%'}">
</el-input>
</el-form-item>
<el-form-item label="开机目标功率" prop="startPower">
<el-input v-model="pcsSetting.startPower" placeholder="请输入" clearable :style="{width: '100%'}">
</el-input>
</el-form-item>
<el-form-item label="关机指令" prop="stopCommand">
<el-input v-model="pcsSetting.stopCommand" placeholder="请输入" clearable :style="{width: '100%'}">
</el-input>
</el-form-item>
<el-form-item label="关机目标功率" prop="stopPower">
<el-input v-model="pcsSetting.stopPower" placeholder="请输入" clearable :style="{width: '100%'}">
</el-input>
</el-form-item>
<el-form-item label="电池簇数" prop="clusterNum">
<el-input v-model="pcsSetting.clusterNum" placeholder="请输入" clearable :style="{width: '100%'}">
</el-input>
</el-form-item>
<br>
<template v-for="index in parseInt(pcsSetting.clusterNum) || 0">
<el-form-item :label="'电池簇'+(index)+'地址'"
prop="clusterPointAddress">
<el-input v-model="pcsSetting.clusterPointAddress[index-1]" placeholder="请输入" clearable
:style="{width: '100%'}">
</el-input>
</el-form-item>
</template>
</el-form>
</div>
<div slot="footer">
<el-button @click="closeDialog">取消</el-button>
<el-button type="primary" @click="saveDialog">确定</el-button>
@ -82,8 +141,9 @@
import {mapState} from "vuex";
import {getAllSites} from '@/api/ems/zddt'
import {validText} from '@/utils/validate'
import {getDeviceDetailInfo,updateDevice,addDevice,getParentDeviceId} from "@/api/ems/site";
import {addDevice, getDeviceDetailInfo, getParentDeviceId, updateDevice} from "@/api/ems/site";
import {getAllDeviceCategory} from '@/api/ems/search'
export default {
props: {
mode: {
@ -110,6 +170,13 @@ export default {
callback();
}
}
const validateNumber = (rule, value, callback) => {
if (value !== '' && !/^[0-9]+$/.test(value)) {
callback(new Error('只能输入数字!'));
} else {
callback();
}
}
return {
loading: 0,
dccDeviceCategoryList: ['CLUSTER', 'BATTERY'],//需要展示上级设备的设备类型
@ -135,6 +202,18 @@ export default {
stopBits: '',//停止位
parity: '',//校验位
pictureUrl: '',//设备图片
slaveId: '',//从站地址
},
pcsSetting: {
deviceSettingId: '',
powerAddress: '',//功率地址
pointAddress: "",//开关机地址
startCommand: "",//开机指令
stopCommand: "",//关机指令
startPower: '',//开机目标功率
stopPower: '',//关机目标功率
clusterNum: '',//电池簇数
clusterPointAddress: []//电池簇地址
},
rules: {
siteId: [
@ -167,6 +246,9 @@ export default {
ipPort: [
{validator: validateText, trigger: 'blur'}
],
slaveId: [
{validator: validateNumber, trigger: 'blur'}
],
serialPort: [
{validator: validateText, trigger: 'blur'}
],
@ -186,13 +268,47 @@ export default {
// { required: true, message: '请上传图片', trigger: ['blur', 'change']}
// ],
},
pcsSettingRules: {
pointAddress: [
{required: true, message: '请输入开关机地址', trigger: 'blur'},
{validator: validateText, trigger: 'blur'}
],
powerAddress: [
{validator: validateText, trigger: 'blur'}
],
startCommand: [
{required: true, message: '请输入开机指令', trigger: 'blur'},
{validator: validateText, trigger: 'blur'}
],
startPower: [
{validator: validateText, trigger: 'blur'}
],
stopCommand: [
{required: true, message: '请输入关机指令', trigger: 'blur'},
{validator: validateText, trigger: 'blur'}
],
stopPower: [
{validator: validateText, trigger: 'blur'}
],
clusterNum: [
{required: true, message: '请输入电池簇数', trigger: 'blur'},
{validator: validateNumber, trigger: 'blur'}
],
clusterPointAddress: [
{required: true, message: '请输入电池簇地址', trigger: 'blur'},
{validator: validateText, trigger: 'blur'}
]
}
}
},
computed: {
...mapState({
communicationStatusOptions: state => state?.ems?.communicationStatusOptions || {},
deviceTypeOptions: state => state?.ems?.deviceTypeOptions || {}
})
}),
isPcs() {
return this.formData.deviceCategory === 'PCS'
}
},
watch: {
dialogTableVisible: {
@ -210,11 +326,20 @@ export default {
if ((newVal || newVal === 0) && this.mode !== 'add') {
this.loading += 1
getDeviceDetailInfo(newVal).then(response => {
this.formData = JSON.parse(JSON.stringify(response?.data || {}));
const {pcsSetting, ...data} = JSON.parse(JSON.stringify(response?.data || {}))
this.formData = data;
if (pcsSetting && JSON.stringify(pcsSetting) !== '{}') {
this.pcsSetting = JSON.parse(JSON.stringify({
...pcsSetting,
clusterPointAddress: JSON.parse(pcsSetting.clusterPointAddress || [])
}));
}
if (this.dccDeviceCategoryList.includes(this.formData.deviceCategory)) {
this.getParentDeviceList(true)
}
}).finally(() => {this.loading-=1})
}).finally(() => {
this.loading -= 1
})
}
},
immediate: true,
@ -234,14 +359,18 @@ export default {
this.loading += 1
getAllSites().then(response => {
this.siteList = response?.data || []
}).finally(() => {this.loading-=1})
}).finally(() => {
this.loading -= 1
})
},
// 获取设备类别
getDeviceCategoryList() {
this.loading += 1
getAllDeviceCategory().then(response => {
this.deviceCategoryList = response?.data || []
}).finally(() => {this.loading-=1})
}).finally(() => {
this.loading -= 1
})
},
//获取上级id列表
getParentDeviceList(init = false) {
@ -256,9 +385,7 @@ export default {
this.loading = this.loading - 1
})
},
saveDialog() {
this.$refs.addTempForm.validate(valid => {
if (!valid) return
saveData() {
this.loading += 1
const {
id = '',
@ -278,9 +405,52 @@ export default {
stopBits = '',//停止位
parity = '',//校验位
pictureUrl = '',//设备图片
slaveId = '',//从站地址
} = this.formData;
const {
deviceSettingId,
powerAddress,
pointAddress,
startCommand,
stopCommand,
startPower,
stopPower,
clusterNum,
clusterPointAddress
} = this.pcsSetting
let params = {
siteId,
deviceId,
deviceName,
description,
communicationStatus,
deviceType,
deviceCategory,
parentId,
ipAddress,
ipPort,
serialPort,
baudRate,
dataBits,
stopBits,
parity,
pictureUrl,
slaveId,
}
if (this.isPcs) {
params.pcsSetting = {
powerAddress,
pointAddress,
startCommand,
stopCommand,
startPower,
stopPower,
clusterNum,
clusterPointAddress: JSON.stringify(!clusterNum ? [] : (clusterPointAddress || []).slice(0, clusterNum))
}
}
if (this.mode === 'add') {
addDevice({siteId,deviceId,deviceName,description,communicationStatus,deviceType,deviceCategory,parentId,ipAddress,ipPort,serialPort,baudRate,dataBits,stopBits,parity,pictureUrl}).then(response => {
addDevice(params).then(response => {
if (response.code === 200) {
//新增成功
// 关闭弹窗 更新表格
@ -291,7 +461,9 @@ export default {
this.loading -= 1
})
} else {
updateDevice({id,siteId,deviceId,deviceName,description,communicationStatus,deviceType,deviceCategory,parentId,ipAddress,ipPort,serialPort,baudRate,dataBits,stopBits,parity,pictureUrl}).then(response => {
params.id = id
params.pcsSetting && (params.pcsSetting.deviceSettingId = deviceSettingId)
updateDevice(params).then(response => {
if (response.code === 200) {
//新增成功
// 关闭弹窗 更新表格
@ -302,7 +474,18 @@ export default {
this.loading -= 1
})
}
},
saveDialog() {
this.$refs.addTempForm.validate(valid => {
if (!valid) return
if (this.isPcs) {
this.$refs.pcsSettingForm.validate(pcsValidate => {
if (!pcsValidate) return
this.saveData()
})
} else {
this.saveData()
}
})
},
closeDialog() {
@ -326,13 +509,36 @@ export default {
stopBits: '',//停止位
parity: '',//校验位
pictureUrl: '',//设备图片
slaveId: '',//从站地址
}
this.pcsSetting = {
deviceSettingId: '',
powerAddress: '',//功率地址
pointAddress: "",//开关机地址
startCommand: "",//开机指令
stopCommand: "",//关机指令
startPower: '',//开机目标功率
stopPower: '',//关机目标功率
clusterNum: '',//电池簇数
clusterPointAddress: []//电池簇地址
}
this.$refs.addTempForm.resetFields()
this.$refs?.pcsSettingForm?.resetFields()
this.dialogTableVisible = false
}
}
}
</script>
<style scoped>
<style scoped lang="scss">
.device-form {
::v-deep .el-form-item--medium .el-form-item__content {
width: 260px;
}
.el-form-item {
width: 50%;
margin-right: 0;
}
}
</style>

View File

@ -0,0 +1,98 @@
<template>
<el-button :size="size" :type="type" :round="round" @click="switchStatus"
>
{{ label }}
</el-button>
</template>
<style scoped lang="scss">
</style>
<script>
import {updateDeviceStatus} from "@/api/ems/site";
export default {
props: {
size: {
type: String,
default: 'mini',
required: false
},
round: {
type: Boolean,
default: false,
required: false
},
type: {
type: String,
default: 'primary',
required: false
},
data: {
type: Object,
default: () => {
return {
workStatus: null,
deviceId: null,
deviceName: null,
}
},
required: true
}
},
data() {
return {
runningStatusMap: ['0', '3', '4', '6']
}
},
computed: {
label() {
return this.runningStatusMap.includes(this.data.workStatus) ? '关机' : '开机'
}
},
methods: {
switchStatus() {
const {workStatus, deviceId, deviceName, siteId} = this.data
this.$confirm(`确认要${this.label}设备${deviceName || ''}吗?`, {
confirmButtonText: "确定",
cancelButtonText: "取消",
showClose: false,
closeOnClickModal: false,
type: "warning",
beforeClose: (action, instance, done) => {
if (action === "confirm") {
instance.confirmButtonLoading = true;
//做开关机操作,更新成功后刷新表格
updateDeviceStatus({
siteId,
workStatus: this.runningStatusMap.includes(workStatus) ? "1" : '0',//1 关机 0开机
deviceId
})
.then((response) => {
response.code === 200 && done();
})
.finally(() => {
instance.confirmButtonLoading = false;
});
} else {
done();
}
},
})
.then(() => {
//只有在废弃成功的情况下会走到这里
this.$message({
type: "success",
message: `${deviceName}${this.label}成功!`,
});
this.$emit('updateSuccess')
//调用接口 更新表格数据
})
.catch(() => {
//取消关机
});
}
}
}
</script>

View File

@ -10,7 +10,7 @@
destroy-on-close
lock-scroll
show-close
title="点位清单"
:title="dataType === 'point' ? '点位清单' : '报警点位'"
width="950px"
>
<el-form :inline="true" label-width="100px">
@ -30,14 +30,15 @@
style="width: 150px"
></el-input>
</el-form-item>
<el-form-item label="modbus ip">
<el-input
v-model="form.ipAddress"
clearable
placeholder="请输入ip"
style="width: 150px"
></el-input>
</el-form-item>
<!-- <el-form-item label="modbus ip">-->
<!-- <el-input-->
<!-- v-model="form.ipAddress"-->
<!-- clearable-->
<!-- placeholder="请输入ip"-->
<!-- style="width: 150px"-->
<!-- ></el-input>-->
<!-- </el-form-item>-->
<br>
<el-form-item label="最小值">
<el-input
v-model="form.lower"
@ -54,14 +55,14 @@
style="width: 150px"
></el-input>
</el-form-item>
<el-form-item label="modbus 端口">
<el-input
v-model="form.ipPort"
clearable
placeholder="请输入端口"
style="width: 150px"
></el-input>
</el-form-item>
<!-- <el-form-item label="modbus 端口">-->
<!-- <el-input-->
<!-- v-model="form.ipPort"-->
<!-- clearable-->
<!-- placeholder="请输入端口"-->
<!-- style="width: 150px"-->
<!-- ></el-input>-->
<!-- </el-form-item>-->
<el-form-item style="margin-left: 20px">
<el-button type="primary" @click="search">搜索</el-button>
</el-form-item>
@ -77,14 +78,18 @@
@sort-change="handleSortChange"
>
<el-table-column label="数据点位" prop="dataPoint"></el-table-column>
<el-table-column label="数据点位名称" prop="pointName"></el-table-column>
<el-table-column
label="modbus地址"
>
<template slot-scope="scope">
<span>{{`${scope.row.ipAddress || ''} ${scope.row.ipPort || ''}`}}</span>
</template>
</el-table-column>
label="数据点位名称"
prop="dataPointName"
></el-table-column>
<!-- <el-table-column label="modbus地址">-->
<!-- <template slot-scope="scope">-->
<!-- <span>{{-->
<!-- `${scope.row.ipAddress || ""} ${scope.row.ipPort || ""}`-->
<!-- }}</span>-->
<!-- </template>-->
<!-- </el-table-column>
<el-table-column label="寄存器地址" prop="寄存器地址"></el-table-column>-->
<el-table-column
label="最新值"
prop="pointValue"
@ -92,19 +97,18 @@
sortable="custom"
>
<template slot-scope="scope">
<span
class="pointer"
@click="
showChart(
scope.row
)
"
>{{ scope.row.pointValue }}</span
>
<span class="pointer" @click="showChart(scope.row)">{{
scope.row.pointValue
}}</span>
</template>
</el-table-column>
<el-table-column label="单位" prop="dataUnit"></el-table-column>
<el-table-column label="更新时间" min-width="160px" prop="updateTime" sortable="custom">
<el-table-column
label="更新时间"
min-width="160px"
prop="updateTime"
sortable="custom"
>
</el-table-column>
</el-table>
<el-pagination
@ -137,11 +141,12 @@ export default {
if (!val) {
this.tableData = [];
this.deviceId = "";
this.parentId='';
this.parentId = "";
this.siteId = "";
this.pageSize = 10;
this.pageNum = 1;
this.totalSize = 0;
this.dataType = '';
this.form = {
sortMethod: "desc", //升序不传或者asc、降序desc
sortData: this.defaultSort.prop,
@ -149,8 +154,8 @@ export default {
dataPoint: "", //点位名称
lower: "", //
upper: "", //
ipAddress:'',
ipPort:''
// ipAddress: "",
// ipPort: "",
};
this.loading = false;
}
@ -158,8 +163,8 @@ export default {
},
computed: {
isDtdc() {
return this.deviceCategory === 'BATTERY'
}
return this.deviceCategory === "BATTERY";
},
},
data() {
return {
@ -167,6 +172,7 @@ export default {
defaultSort: {prop: "updateTime", order: "descending"},
show: false,
loading: false,
dataType: '',//展示的数据类型 point点位/alarmPoint报警点位
form: {
sortData: "updateTime", //最新值升序不传或者asc、降序desc
sortMethod: "desc", //升序不传或者asc、降序desc
@ -174,12 +180,12 @@ export default {
dataPoint: "", //点位名称
lower: "", //
upper: "", //
ipAddress:'',
ipPort:''
// ipAddress: "",
// ipPort: "",
},
deviceCategory: "",
deviceId: "",
parentId:'',
parentId: "",
siteId: "",
tableData: [],
pageSize: 10, //分页栏当前每个数据总数
@ -190,31 +196,55 @@ export default {
methods: {
showChart({pointName}) {
if (pointName) {
const {deviceCategory,deviceId}=this
if(this.isDtdc) this.$refs.pointChart.showChart({ pointName, deviceCategory, deviceId:this.parentId,child:[deviceId] });
else this.$refs.pointChart.showChart({ pointName, deviceCategory, deviceId });
const {deviceCategory, deviceId} = this;
if (this.isDtdc)
this.$refs.pointChart.showChart({
pointName,
deviceCategory,
deviceId: this.parentId,
child: [deviceId],
});
else
this.$refs.pointChart.showChart({
pointName,
deviceCategory,
deviceId,
});
}
},
handleSortChange(column) {
this.form.sortData = column.prop
this.form.sortData = column.prop;
this.form.sortMethod = column.order === "descending" ? "desc" : "asc";
console.log("切换排序方式", column, this.form);
this.getData();
this.getData()
},
search() {
this.pageNum = 1;
this.getData();
this.getData()
},
showTable({ deviceCategory, siteId, deviceId ,parentId=''}) {
// 分页
handleSizeChange(val) {
this.pageSize = val;
this.$nextTick(() => {
this.getData()
});
},
handleCurrentChange(val) {
this.pageNum = val;
this.$nextTick(() => {
this.getData()
});
},
showTable({deviceCategory, siteId, deviceId, parentId = ""}, dataType) {
this.dataType = dataType;
this.deviceCategory = deviceCategory;
this.siteId = siteId;
this.deviceId = deviceId;
this.parentId=deviceCategory === 'BATTERY' ? parentId : ''//只有单体电池需要这个值
this.parentId = deviceCategory === "BATTERY" ? parentId : ""; //只有单体电池需要这个值
this.show = true;
this.getData();
this.getData()
},
getData() {
this.loading = true;
const {
siteId,
deviceId,
@ -229,11 +259,11 @@ export default {
dataPoint,
lower,
upper,
ipAddress,
ipPort
// ipAddress,
// ipPort,
},
} = this;
getDevicePointList({
const params = {
siteId,
deviceId,
deviceCategory,
@ -246,9 +276,12 @@ export default {
dataPoint,
lower,
upper,
ipAddress,
ipPort
})
// ipAddress: '',
// ipPort: '',
}
params.isAlarm = this.dataType === 'point' ? 0 : 1
this.loading = true;
getDevicePointList(params)
.then((response) => {
this.tableData = response?.rows || [];
this.totalSize = response?.total || 0;
@ -257,19 +290,6 @@ export default {
this.loading = false;
});
},
// 分页
handleSizeChange(val) {
this.pageSize = val;
this.$nextTick(() => {
this.getData();
});
},
handleCurrentChange(val) {
this.pageNum = val;
this.$nextTick(() => {
this.getData();
});
},
},
};
</script>

View File

@ -1,7 +1,10 @@
<template>
<el-dialog :visible.sync="show" class="ems-dialog" title="点位上传" width="400px" append-to-body :close-on-click-modal="false" :close-on-press-escape="false">
<el-dialog :visible.sync="show" class="ems-dialog" title="点位上传" width="400px" append-to-body
:close-on-click-modal="false" :close-on-press-escape="false">
<!-- <file-upload :fileType='["xls", "xlsx"]' value="String" :limit="1" :drag="false" @input="updateFile"/>-->
<el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url" :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"
:data="upload.data" :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">
@ -21,28 +24,32 @@
</style>
<script>
import {getToken} from "@/utils/auth"
export default {
data() {
return {
show: false,
// 用户导入参数
upload: {
data: {},
// 是否禁用上传
isUploading: false,
// 设置上传的请求头部
headers: {Authorization: "Bearer " + getToken()},
// 上传的地址
url: process.env.VUE_APP_BASE_API + "/ems/pointMatch/importData"
url: process.env.VUE_APP_BASE_API + "/ems/pointMatch/importDataByDevice"
},
}
},
methods: {
showDialog(){
showDialog({siteId, deviceCategory, deviceId}) {
this.upload.data = {siteId, deviceCategory, deviceId}
this.show = true;
},
//关闭弹窗 重置数据
handleClosed() {
this.$refs.upload.clearFiles()//写在before-closed无效
this.upload.data = {}
this.show = false
},
// updateFile(data){
@ -51,12 +58,12 @@ export default {
// saveDialog(){
// this.show=true
// },
// 文件上传中处理
handleFileUploadProgress(event, file, fileList) {
// 文件上传中处理 返回参数event, file, fileList
handleFileUploadProgress() {
this.upload.isUploading = true
},
// 文件上传成功处理
handleFileSuccess(response, file, fileList) {
// 文件上传成功处理 返回参数response, file, fileList
handleFileSuccess(response) {
console.log('上传文件结果', response)
this.upload.isUploading = false
if (response.code === 500 && !response.msg) response.msg = '上传失败'

View File

@ -1,10 +1,21 @@
<template>
<div class="ems-dashboard-editor-container" style="background-color: #ffffff" v-loading="loading">
<el-form :inline="true" class="select-container">
<el-form-item label="站点选择">
<el-select v-model="siteId" placeholder="请选择换电站名称" :loading="searchLoading" loading-text="正在加载数据" @change="onSearch" clearable>
<el-option :label="item.siteName" :value="item.siteId" v-for="(item,index) in siteList" :key="index+'zdxeSelect'"></el-option>
<el-select v-model="siteId" placeholder="请选择换电站名称" :loading="searchLoading" loading-text="正在加载数据"
@change="onSearch" clearable>
<el-option :label="item.siteName" :value="item.siteId" v-for="(item,index) in siteList"
:key="index+'zdxeSelect'"></el-option>
</el-select>
</el-form-item>
<el-form-item label="设备类型">
<el-select v-model="deviceCategory" placeholder="请选择设备类型" @change="onSearch" clearable>
<el-option
v-for="(item,index) in deviceCategoryList"
:key="index+'deviceCategorySelect'"
:label="item.name"
:value="item.code">
</el-option>
</el-select>
</el-form-item>
<el-form-item>
@ -13,12 +24,34 @@
</el-form-item>
</el-form>
<el-button type="primary" @click="addDevice" native-type="button">新增设备</el-button>
<el-dropdown @command="(val)=>downloadPointDetail(val,false)">
<el-button
@click="uploadPointDetail"
type="success"
style="margin-left:10px;"
type="primary"
plain>
上传点位清单
下载点位清单
</el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="(item,index) in deviceCategoryList" :key="index+'deviceCategoryList'"
:command="item">
{{ item.name }}
</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
<!-- <el-dropdown @command="(val)=>uploadPointDetail(val,false)">-->
<!-- <el-button-->
<!-- style="margin-left:10px;"-->
<!-- type="success"-->
<!-- plain>-->
<!-- 上传点位清单-->
<!-- </el-button>-->
<!-- <el-dropdown-menu slot="dropdown">-->
<!-- <el-dropdown-item v-for="(item,index) in deviceCategoryList" :key="index+'deviceCategoryList'"-->
<!-- :command="item">-->
<!-- {{ item.name }}-->
<!-- </el-dropdown-item>-->
<!-- </el-dropdown-menu>-->
<!-- </el-dropdown>-->
<el-table
class="common-table"
:data="tableData"
@ -47,10 +80,14 @@
label="设备类别">
</el-table-column>
<el-table-column
prop="runningStatus"
prop="deviceStatus"
label="在线状态">
<template slot-scope="scope">
<span>{{$store.state.ems.deviceStatusOptions[scope.row.runningStatus]}}</span>
<span>{{ $store.state.ems.deviceStatusOptions[scope.row.deviceStatus] }}</span>
<pcs-switch v-if="scope.row.deviceCategory === 'PCS' && ![null,'',undefined].includes(scope.row.workStatus)"
style="margin-left:5px;"
:data="{siteId:scope.row.siteId,workStatus:scope.row.workStatus,deviceId:scope.row.deviceId,deviceName:scope.row.deviceName}"
@updateSuccess="getData"/>
</template>
</el-table-column>
<el-table-column
@ -59,18 +96,34 @@
width="250">
<template slot-scope="scope">
<el-button
@click="pointDetail(scope.row)"
@click="pointDetail(scope.row,'point')"
type="primary"
size="mini">
点位清单
</el-button>
<el-button
@click="downloadPointDetail(scope.row)"
@click="pointDetail(scope.row,'alarmPoint')"
type="primary"
size="mini">
报警点位清单
</el-button>
<br>
<el-button
@click="downloadPointDetail(scope.row,true)"
style="margin-top:10px;"
type="primary"
plain
size="mini">
下载点位清单
</el-button>
<el-button
@click="uploadPointDetail(scope.row,true)"
style="margin-top:10px;"
type="success"
plain
size="mini">
上传点位清单
</el-button>
<br>
<el-button
@click="editDevice(scope.row)"
@ -102,10 +155,14 @@
style="margin-top:15px;text-align: center"
>
</el-pagination>
<el-dialog :visible.sync="dialogTableVisible" class="ems-dialog" title=" 详细信息" :close-on-click-modal="false" :before-close="handleClosed">
<el-dialog :visible.sync="dialogTableVisible" class="ems-dialog" title="详细信息" :close-on-click-modal="false"
:before-close="handleClosed">
<div class="descriptions-main" style="padding: 0">
<el-descriptions direction="vertical" :column="2" :colon="false" border>
<el-descriptions-item v-for="(item,index) in detailData" :key="index+'descriptions'" labelClassName="descriptions-label" contentClassName="descriptions-direction" :span="1" :label="item.label">{{item.value}}</el-descriptions-item>
<el-descriptions-item v-for="(item,index) in detailData" :key="index+'descriptions'"
labelClassName="descriptions-label" contentClassName="descriptions-direction" :span="1"
:label="item.label">{{ item.value }}
</el-descriptions-item>
</el-descriptions>
</div>
</el-dialog>
@ -116,16 +173,18 @@
</template>
<script>
import {getDeviceInfoList,getDeviceDetailInfo,deleteService,exportPointList,importPointList} from'@/api/ems/site'
import {deleteService, getDeviceDetailInfo, getDeviceInfoList} from '@/api/ems/site'
import {getAllSites} from '@/api/ems/zddt'
import {formatNumber} from "@/filters/ems";
import {getAllDeviceCategory} from '@/api/ems/search'
import PointTable from './PointTable.vue'
import AddDevice from "./AddDevice.vue";
import PointUpload from "./PointUpload.vue";
import {download} from "@/utils/request";
import PcsSwitch from "./PcsSwitch.vue";
export default {
name: "Sblb",
components:{AddDevice,PointTable,PointUpload},
components: {AddDevice, PointTable, PointUpload, PcsSwitch},
data() {
return {
loading: false,
@ -134,6 +193,8 @@ export default {
editDeviceId: '',//编辑设备id
siteId: '',
siteList: [],
deviceCategory: '',//搜索栏设备类型
deviceCategoryList: [],//设备类别
tableData: [],
pageSize: 10,//分页栏当前每个数据总数
pageNum: 1,//分页栏当前页数
@ -163,20 +224,37 @@ export default {
}
},
methods: {
// 获取设备类别
getDeviceCategoryList() {
getAllDeviceCategory().then(response => {
this.deviceCategoryList = response?.data || []
})
},
// 查看设备电位表格
pointDetail(row){
this.$refs.pointTable.showTable(row)
pointDetail(row, dataType) {
this.$refs.pointTable.showTable(row, dataType)
},
// 下载点位清单
downloadPointDetail({siteId,deviceCategory,deviceName}){
downloadPointDetail(command, isDetail = false) {
const siteId = isDetail ? command.siteId : this.siteId
const deviceCategory = isDetail ? command.deviceCategory : command.code
const categoryName = isDetail ? command.categoryName : command.name
const deviceId = isDetail ? command.deviceId : null
console.log('下载', command, isDetail)
this.download('ems/pointMatch/export', {
siteId,
deviceCategory
}, `点位清单_${deviceName}_${new Date().getTime()}.xlsx`)
deviceCategory,
deviceId,
}, `点位清单_${categoryName}_${new Date().getTime()}.xlsx`)
},
// 上传点位清单
uploadPointDetail(){
this.$refs.pointUpload.showDialog()
uploadPointDetail(command, isDetail = false) {
const siteId = isDetail ? command.siteId : this.siteId
const deviceCategory = isDetail ? command.deviceCategory : command.code
const categoryName = isDetail ? command.categoryName : command.name
const deviceId = isDetail ? command.deviceId : ''
console.log('上传', command, isDetail)
this.$refs.pointUpload.showDialog({siteId, deviceCategory, categoryName, deviceId})
},
clearEditDeviceData() {
this.mode = '';
@ -226,7 +304,9 @@ export default {
});
},
handleClosed(done) {
this.detailData.forEach((item)=>{item.value = ''})
this.detailData.forEach((item) => {
item.value = ''
})
done()
},
toDetail(id) {
@ -242,7 +322,9 @@ export default {
})
this.dialogTableVisible = true
}).finally(() => {this.loading = false})
}).finally(() => {
this.loading = false
})
},
// 分页
@ -272,11 +354,13 @@ export default {
// 获取数据
getData() {
this.loading = true
const {siteId,pageNum,pageSize} =this
getDeviceInfoList({siteId,pageNum,pageSize}).then(response => {
const {siteId, deviceCategory, pageNum, pageSize} = this
getDeviceInfoList({siteId, deviceCategory, pageNum, pageSize}).then(response => {
this.tableData = response?.rows || [];
this.totalSize = response?.total || 0
}).finally(() => {this.loading=false})
}).finally(() => {
this.loading = false
})
},
//获取站点列表
getZdList() {
@ -284,13 +368,16 @@ export default {
return getAllSites().then(response => {
this.siteList = response?.data || []
if (this.siteList.length > 0) this.siteId = this.siteList[0].siteId
}).finally(() => {this.searchLoading=false})
}).finally(() => {
this.searchLoading = false
})
}
},
mounted() {
this.loading = true
this.siteId = ''
this.pageNum = 1//每次搜索从1开始搜索
this.getDeviceCategoryList()
this.getZdList().then(() => {
this.getData()
})

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,19 +48,29 @@
<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>
@ -59,13 +78,18 @@
<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 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>
@ -105,7 +139,8 @@
</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>
@ -129,7 +164,8 @@
</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,11 +264,21 @@
</template>
<script>
import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user"
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 {
@ -228,6 +301,8 @@ export default {
total: 0,
// 用户表格数据
userList: null,
// 站点列表数据
siteList: [],
// 弹出层标题
title: "",
// 所有部门树选项
@ -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,6 +408,29 @@ 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
@ -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
@ -479,7 +581,8 @@ export default {
resetUserPwd(row.userId, value).then(response => {
this.$modal.msgSuccess("修改成功,新密码是:" + value)
})
}).catch(() => {})
}).catch(() => {
})
},
/** 分配角色操作 */
handleAuthRole: function (row) {
@ -491,13 +594,13 @@ export default {
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()
@ -514,7 +617,8 @@ export default {
}).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) {