Compare commits
4 Commits
main-cloud
...
waibao
| Author | SHA1 | Date | |
|---|---|---|---|
| 1499085561 | |||
| 801d8eab1d | |||
| b73999bd23 | |||
| 20df411925 |
@ -1,6 +1,6 @@
|
|||||||
import request from '@/utils/request'
|
import request from '@/utils/request'
|
||||||
|
|
||||||
//获取单个站点的信息
|
//鑾峰彇鍗曚釜绔欑偣鐨勪俊鎭?
|
||||||
export function getDzjkHomeView(siteId) {
|
export function getDzjkHomeView(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/homeView?siteId=${siteId}`,
|
url: `/ems/siteMonitor/homeView?siteId=${siteId}`,
|
||||||
@ -8,7 +8,7 @@ export function getDzjkHomeView(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取单个站点总累计运行数据(基于日表)
|
//鑾峰彇鍗曚釜绔欑偣鎬荤疮璁¤繍琛屾暟鎹紙鍩轰簬鏃ヨ〃锛?
|
||||||
export function getDzjkHomeTotalView(siteId) {
|
export function getDzjkHomeTotalView(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/homeTotalView?siteId=${siteId}`,
|
url: `/ems/siteMonitor/homeTotalView?siteId=${siteId}`,
|
||||||
@ -16,7 +16,7 @@ export function getDzjkHomeTotalView(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单站监控项目点位配置(供单站监控功能查询)
|
// 鍗曠珯鐩戞帶椤圭洰鐐逛綅閰嶇疆锛堜緵鍗曠珯鐩戞帶鍔熻兘鏌ヨ锛?
|
||||||
export function getProjectPointMapping(siteId) {
|
export function getProjectPointMapping(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getProjectPointMapping?siteId=${siteId}`,
|
url: `/ems/siteMonitor/getProjectPointMapping?siteId=${siteId}`,
|
||||||
@ -24,7 +24,7 @@ export function getProjectPointMapping(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单站监控项目展示数据(字段配置 + 最新值)
|
// 鍗曠珯鐩戞帶椤圭洰灞曠ず鏁版嵁锛堝瓧娈甸厤缃?+ 鏈€鏂板€硷級
|
||||||
export function getProjectDisplayData(siteId) {
|
export function getProjectDisplayData(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getProjectDisplayData?siteId=${siteId}`,
|
url: `/ems/siteMonitor/getProjectDisplayData?siteId=${siteId}`,
|
||||||
@ -32,7 +32,7 @@ export function getProjectDisplayData(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单站监控项目展示数据写入(批量)
|
// 鍗曠珯鐩戞帶椤圭洰灞曠ず鏁版嵁鍐欏叆锛堟壒閲忥級
|
||||||
export function saveProjectDisplayData(data) {
|
export function saveProjectDisplayData(data) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/saveProjectDisplayData`,
|
url: `/ems/siteMonitor/saveProjectDisplayData`,
|
||||||
@ -41,7 +41,7 @@ export function saveProjectDisplayData(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//站点首页 冲放曲线
|
//绔欑偣棣栭〉 鍐叉斁鏇茬嚎
|
||||||
export function getSevenChargeData({siteId, startDate, endDate}) {
|
export function getSevenChargeData({siteId, startDate, endDate}) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMap/getSevenChargeData?siteId=${siteId}&startDate=${startDate}&endDate=${endDate}`,
|
url: `/ems/siteMap/getSevenChargeData?siteId=${siteId}&startDate=${startDate}&endDate=${endDate}`,
|
||||||
@ -49,7 +49,7 @@ export function getSevenChargeData({siteId, startDate, endDate}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取站点包含的设备种类 用来判断单站监控设备监控的菜单栏展示
|
// 鑾峰彇绔欑偣鍖呭惈鐨勮澶囩绫?鐢ㄦ潵鍒ゆ柇鍗曠珯鐩戞帶璁惧鐩戞帶鐨勮彍鍗曟爮灞曠ず
|
||||||
export function getSiteAllDeviceCategory(siteId) {
|
export function getSiteAllDeviceCategory(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteConfig/getSiteAllDeviceCategory?siteId=${siteId}`,
|
url: `/ems/siteConfig/getSiteAllDeviceCategory?siteId=${siteId}`,
|
||||||
@ -65,7 +65,7 @@ export function getEmsDataList(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取pcs、实时运行头部的设备信息
|
//鑾峰彇pcs銆佸疄鏃惰繍琛屽ご閮ㄧ殑璁惧淇℃伅
|
||||||
export function getRunningHeadInfo(siteId) {
|
export function getRunningHeadInfo(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/runningHeadInfo?siteId=${siteId}`,
|
url: `/ems/siteMonitor/runningHeadInfo?siteId=${siteId}`,
|
||||||
@ -73,7 +73,7 @@ export function getRunningHeadInfo(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取pcs列表
|
//鑾峰彇pcs鍒楄〃
|
||||||
export function getPcsDetailInfo(siteId) {
|
export function getPcsDetailInfo(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getPcsDetailInfo?siteId=${siteId}`,
|
url: `/ems/siteMonitor/getPcsDetailInfo?siteId=${siteId}`,
|
||||||
@ -81,7 +81,7 @@ export function getPcsDetailInfo(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取BMS总览数据
|
//鑾峰彇BMS鎬昏鏁版嵁
|
||||||
export function getBMSOverView(siteId) {
|
export function getBMSOverView(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getBMSOverView?siteId=${siteId}`,
|
url: `/ems/siteMonitor/getBMSOverView?siteId=${siteId}`,
|
||||||
@ -89,7 +89,7 @@ export function getBMSOverView(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取BMS电池簇总览数据
|
//鑾峰彇BMS鐢垫睜绨囨€昏鏁版嵁
|
||||||
export function getBMSBatteryCluster(siteId) {
|
export function getBMSBatteryCluster(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getBMSBatteryCluster?siteId=${siteId}`,
|
url: `/ems/siteMonitor/getBMSBatteryCluster?siteId=${siteId}`,
|
||||||
@ -97,7 +97,7 @@ export function getBMSBatteryCluster(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取单体电池 电池堆列表数据
|
//鑾峰彇鍗曚綋鐢垫睜 鐢垫睜鍫嗗垪琛ㄦ暟鎹?
|
||||||
export function getStackNameList(siteId) {
|
export function getStackNameList(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getStackNameList?siteId=${siteId}`,
|
url: `/ems/siteMonitor/getStackNameList?siteId=${siteId}`,
|
||||||
@ -105,7 +105,7 @@ export function getStackNameList(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取单体电池 电池簇列表数据
|
//鑾峰彇鍗曚綋鐢垫睜 鐢垫睜绨囧垪琛ㄦ暟鎹?
|
||||||
export function getClusterNameList({stackDeviceId, siteId}) {
|
export function getClusterNameList({stackDeviceId, siteId}) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getClusterNameList?stackDeviceId=${stackDeviceId}&siteId=${siteId}`,
|
url: `/ems/siteMonitor/getClusterNameList?stackDeviceId=${stackDeviceId}&siteId=${siteId}`,
|
||||||
@ -113,7 +113,7 @@ export function getClusterNameList({stackDeviceId, siteId}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//单体电池表格数据
|
//鍗曚綋鐢垫睜琛ㄦ牸鏁版嵁
|
||||||
export function getClusterDataInfoList({siteId, stackDeviceId, clusterDeviceId, batteryId, pageSize, pageNum}) {
|
export function getClusterDataInfoList({siteId, stackDeviceId, clusterDeviceId, batteryId, pageSize, pageNum}) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getClusterDataInfoList?clusterDeviceId=${clusterDeviceId}&siteId=${siteId}&stackDeviceId=${stackDeviceId}&batteryId=${batteryId}&pageSize=${pageSize}&pageNum=${pageNum}`,
|
url: `/ems/siteMonitor/getClusterDataInfoList?clusterDeviceId=${clusterDeviceId}&siteId=${siteId}&stackDeviceId=${stackDeviceId}&batteryId=${batteryId}&pageSize=${pageSize}&pageNum=${pageNum}`,
|
||||||
@ -121,7 +121,7 @@ export function getClusterDataInfoList({siteId, stackDeviceId, clusterDeviceId,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 单体电池图表
|
// 鍗曚綋鐢垫睜鍥捐〃
|
||||||
//http://localhost:8089/ems/siteMonitor/getSingleBatteryData?clusterDeviceId=BMSC01&siteId=021_FXX_01&deviceId=001&startDate=2025-07-11&endDate=2025-07-18
|
//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}) {
|
export function getSingleBatteryData({siteId, deviceId, clusterDeviceId, startDate, endDate}) {
|
||||||
return request({
|
return request({
|
||||||
@ -130,7 +130,7 @@ export function getSingleBatteryData({siteId, deviceId, clusterDeviceId, startDa
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取液冷列表数据
|
//鑾峰彇娑插喎鍒楄〃鏁版嵁
|
||||||
export function getCoolingDataList(siteId) {
|
export function getCoolingDataList(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getCoolingDataList?siteId=${siteId}`,
|
url: `/ems/siteMonitor/getCoolingDataList?siteId=${siteId}`,
|
||||||
@ -138,7 +138,7 @@ export function getCoolingDataList(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取动环数据
|
//鑾峰彇鍔ㄧ幆鏁版嵁
|
||||||
export function getDhDataList(siteId) {
|
export function getDhDataList(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getDhDataList?siteId=${siteId}`,
|
url: `/ems/siteMonitor/getDhDataList?siteId=${siteId}`,
|
||||||
@ -146,7 +146,7 @@ export function getDhDataList(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取消防数据
|
//鑾峰彇娑堥槻鏁版嵁
|
||||||
export function getXfDataList(siteId) {
|
export function getXfDataList(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getXfDataList?siteId=${siteId}`,
|
url: `/ems/siteMonitor/getXfDataList?siteId=${siteId}`,
|
||||||
@ -155,7 +155,7 @@ export function getXfDataList(siteId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//获取电表数据
|
//鑾峰彇鐢佃〃鏁版嵁
|
||||||
export function getAmmeterDataList(siteId) {
|
export function getAmmeterDataList(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getAmmeterDataList?siteId=${siteId}`,
|
url: `/ems/siteMonitor/getAmmeterDataList?siteId=${siteId}`,
|
||||||
@ -163,7 +163,7 @@ export function getAmmeterDataList(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 故障告警
|
// 鏁呴殰鍛婅
|
||||||
export function getAlarmDetailList({
|
export function getAlarmDetailList({
|
||||||
status,
|
status,
|
||||||
siteId,
|
siteId,
|
||||||
@ -180,7 +180,7 @@ export function getAlarmDetailList({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 告警生成工单
|
// 鍛婅鐢熸垚宸ュ崟
|
||||||
export function createTicketNo(data) {
|
export function createTicketNo(data) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteAlarm/createTicketNo`,
|
url: `/ems/siteAlarm/createTicketNo`,
|
||||||
@ -189,7 +189,7 @@ export function createTicketNo(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 告警确认关闭
|
// 鍛婅纭鍏抽棴
|
||||||
export function closeAlarm(data) {
|
export function closeAlarm(data) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteAlarm/closeAlarm`,
|
url: `/ems/siteAlarm/closeAlarm`,
|
||||||
@ -273,17 +273,17 @@ function normalizeDateInput(dateStr) {
|
|||||||
function resolveElectricUnit(startDate, endDate) {
|
function resolveElectricUnit(startDate, endDate) {
|
||||||
const start = new Date(`${normalizeDateInput(startDate)} 00:00:00`)
|
const start = new Date(`${normalizeDateInput(startDate)} 00:00:00`)
|
||||||
const end = new Date(`${normalizeDateInput(endDate)} 00:00:00`)
|
const end = new Date(`${normalizeDateInput(endDate)} 00:00:00`)
|
||||||
if (isNaN(start.getTime()) || isNaN(end.getTime())) return '日'
|
if (isNaN(start.getTime()) || isNaN(end.getTime())) return '\u65e5'
|
||||||
const diffDays = Math.floor((end.getTime() - start.getTime()) / (24 * 60 * 60 * 1000))
|
const diffDays = Math.floor((end.getTime() - start.getTime()) / (24 * 60 * 60 * 1000))
|
||||||
if (diffDays <= 0) return '时'
|
if (diffDays <= 0) return '\u65e5'
|
||||||
if (diffDays < 30) return '日'
|
if (diffDays < 30) return '\u65e5'
|
||||||
return '月'
|
return '\u6708'
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatByUnit(date, unit) {
|
function formatByUnit(date, unit) {
|
||||||
const p = (n) => String(n).padStart(2, '0')
|
const p = (n) => String(n).padStart(2, '0')
|
||||||
if (unit === '时') return `${p(date.getHours())}:${p(date.getMinutes())}`
|
if (unit === '\u65e5') return `${p(date.getHours())}:${p(date.getMinutes())}`
|
||||||
if (unit === '月') return `${date.getFullYear()}-${p(date.getMonth() + 1)}`
|
if (unit === '\u6708') return `${date.getFullYear()}-${p(date.getMonth() + 1)}`
|
||||||
return `${date.getFullYear()}-${p(date.getMonth() + 1)}-${p(date.getDate())}`
|
return `${date.getFullYear()}-${p(date.getMonth() + 1)}-${p(date.getDate())}`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,27 +363,20 @@ function resolveRangeKind(startDate, endDate) {
|
|||||||
const end = new Date(`${normalizeDateInput(endDate || startDate)} 00:00:00`)
|
const end = new Date(`${normalizeDateInput(endDate || startDate)} 00:00:00`)
|
||||||
if (isNaN(start.getTime()) || isNaN(end.getTime())) return 'day'
|
if (isNaN(start.getTime()) || isNaN(end.getTime())) return 'day'
|
||||||
const diffDays = Math.floor((end.getTime() - start.getTime()) / (24 * 60 * 60 * 1000))
|
const diffDays = Math.floor((end.getTime() - start.getTime()) / (24 * 60 * 60 * 1000))
|
||||||
if (diffDays <= 0) return 'minute'
|
if (diffDays < 31) return 'minute'
|
||||||
if (diffDays < 30) return 'day'
|
if (diffDays < 180) return 'day'
|
||||||
return 'month'
|
return 'month'
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatTimeLabelByKind(date, kind = 'day') {
|
function formatTimeLabelByKind(date, kind = 'day') {
|
||||||
const p = (n) => String(n).padStart(2, '0')
|
const p = (n) => String(n).padStart(2, '0')
|
||||||
if (kind === 'minute') return `${p(date.getHours())}:${p(date.getMinutes())}`
|
if (kind === 'minute') return `${date.getFullYear()}-${p(date.getMonth() + 1)}-${p(date.getDate())} ${p(date.getHours())}:${p(date.getMinutes())}`
|
||||||
if (kind === 'month') return `${date.getFullYear()}-${p(date.getMonth() + 1)}`
|
if (kind === 'month') return `${date.getFullYear()}-${p(date.getMonth() + 1)}`
|
||||||
return `${date.getFullYear()}-${p(date.getMonth() + 1)}-${p(date.getDate())}`
|
return `${date.getFullYear()}-${p(date.getMonth() + 1)}-${p(date.getDate())}`
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildSortedLabels(labelSet, kind = 'day') {
|
function buildSortedLabels(labelSet, kind = 'day') {
|
||||||
const labels = Array.from(labelSet || [])
|
const labels = Array.from(labelSet || [])
|
||||||
if (kind === 'minute') {
|
|
||||||
return labels.sort((a, b) => {
|
|
||||||
const [ah = 0, am = 0] = String(a || '').split(':').map(v => Number(v) || 0)
|
|
||||||
const [bh = 0, bm = 0] = String(b || '').split(':').map(v => Number(v) || 0)
|
|
||||||
return ah * 60 + am - (bh * 60 + bm)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return labels.sort()
|
return labels.sort()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -401,6 +394,39 @@ function resolveAliasByField(aliasMap, fieldName) {
|
|||||||
return aliasMap[withoutStat] || ''
|
return aliasMap[withoutStat] || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toFixedNumber(value, digits = 2) {
|
||||||
|
const num = toNumber(value)
|
||||||
|
if (num == null) return null
|
||||||
|
return Number(num.toFixed(digits))
|
||||||
|
}
|
||||||
|
|
||||||
|
function sortDailyAmmeterRows(rows = []) {
|
||||||
|
return [...(rows || [])].sort((a, b) => {
|
||||||
|
const ta = new Date(`${a?.dataTime || ''} 00:00:00`).getTime()
|
||||||
|
const tb = new Date(`${b?.dataTime || ''} 00:00:00`).getTime()
|
||||||
|
return (isNaN(ta) ? 0 : ta) - (isNaN(tb) ? 0 : tb)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function queryAllAmmeterDailyRows({siteId, startTime, endTime, pageSize = 500, pageNum = 1, rows = []}) {
|
||||||
|
return getAmmeterData({siteId, startTime, endTime, pageSize, pageNum}).then((response) => {
|
||||||
|
const currentRows = Array.isArray(response?.rows) ? response.rows : []
|
||||||
|
const allRows = rows.concat(currentRows)
|
||||||
|
const total = Number(response?.total) || 0
|
||||||
|
if (allRows.length >= total || currentRows.length < pageSize) {
|
||||||
|
return allRows
|
||||||
|
}
|
||||||
|
return queryAllAmmeterDailyRows({
|
||||||
|
siteId,
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
pageSize,
|
||||||
|
pageNum: pageNum + 1,
|
||||||
|
rows: allRows,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function queryMenuPointCurves({siteId, menuCode, startDate, endDate, mappingFilter}) {
|
function queryMenuPointCurves({siteId, menuCode, startDate, endDate, mappingFilter}) {
|
||||||
return getProjectPointMapping(siteId).then((mappingResp) => {
|
return getProjectPointMapping(siteId).then((mappingResp) => {
|
||||||
const allMappings = Array.isArray(mappingResp?.data) ? mappingResp.data : []
|
const allMappings = Array.isArray(mappingResp?.data) ? mappingResp.data : []
|
||||||
@ -427,94 +453,48 @@ function queryMenuPointCurves({siteId, menuCode, startDate, endDate, mappingFilt
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 电量指标
|
// 鐢甸噺鎸囨爣
|
||||||
export function getElectricData({siteId, startDate, endDate}) {
|
export function getElectricData({siteId, startDate, endDate}) {
|
||||||
return getProjectPointMapping(siteId).then((mappingResp) => {
|
return queryAllAmmeterDailyRows({
|
||||||
const allMappings = Array.isArray(mappingResp?.data) ? mappingResp.data : []
|
siteId,
|
||||||
const gltjMappings = allMappings.filter(item => item?.menuCode === 'TJBB_GLTJ')
|
startTime: startDate,
|
||||||
|
endTime: endDate,
|
||||||
const chargedMap = findMappingByField(gltjMappings, ['chargedCap_stat', 'chargedCap'])
|
}).then((rows) => {
|
||||||
const disChargedMap = findMappingByField(gltjMappings, ['disChargedCap_stat', 'disChargedCap'])
|
const sortedRows = sortDailyAmmeterRows(rows)
|
||||||
const dailyEfficiencyMap = findMappingByField(gltjMappings, ['dailyEfficiency'])
|
const sevenDayDisChargeStats = sortedRows.map((item) => {
|
||||||
const totalChargedMap = findMappingByField(gltjMappings, ['totalChargedCap_stat', 'totalChargedCap'])
|
const chargedCap = toNumber(item?.activeTotalKwh)
|
||||||
const totalDisChargedMap = findMappingByField(gltjMappings, ['totalDisChargedCap_stat', 'totalDisChargedCap'])
|
const disChargedCap = toNumber(item?.reActiveTotalKwh)
|
||||||
const totalEfficiencyMap = findMappingByField(gltjMappings, ['efficiency'])
|
const rowEffect = toNumber(item?.effect)
|
||||||
|
const dailyEfficiency = rowEffect != null
|
||||||
const pointMap = {
|
? rowEffect
|
||||||
charged: getDataPointFromMapping(chargedMap),
|
: (chargedCap > 0 && disChargedCap != null ? toFixedNumber((disChargedCap / chargedCap) * 100) : null)
|
||||||
disCharged: getDataPointFromMapping(disChargedMap),
|
|
||||||
dailyEfficiency: getDataPointFromMapping(dailyEfficiencyMap),
|
|
||||||
totalCharged: getDataPointFromMapping(totalChargedMap),
|
|
||||||
totalDisCharged: getDataPointFromMapping(totalDisChargedMap),
|
|
||||||
totalEfficiency: getDataPointFromMapping(totalEfficiencyMap),
|
|
||||||
}
|
|
||||||
|
|
||||||
const queryTasks = Object.keys(pointMap).map((key) => {
|
|
||||||
const pointId = pointMap[key]
|
|
||||||
return queryPointCurveByPointId({siteId, pointId, startDate, endDate})
|
|
||||||
.then(curve => ({key, curve}))
|
|
||||||
.catch(() => ({key, curve: []}))
|
|
||||||
})
|
|
||||||
|
|
||||||
return Promise.all(queryTasks).then((queryResult) => {
|
|
||||||
const curveMap = {}
|
|
||||||
queryResult.forEach(item => {
|
|
||||||
curveMap[item.key] = item.curve || []
|
|
||||||
})
|
|
||||||
|
|
||||||
const unit = resolveElectricUnit(startDate, endDate)
|
|
||||||
const chargedSeries = aggregateCurveByUnit(curveMap.charged, unit)
|
|
||||||
const disChargedSeries = aggregateCurveByUnit(curveMap.disCharged, unit)
|
|
||||||
const efficiencySeries = aggregateCurveByUnit(curveMap.dailyEfficiency, unit)
|
|
||||||
|
|
||||||
const labels = Array.from(new Set([
|
|
||||||
...chargedSeries.keys(),
|
|
||||||
...disChargedSeries.keys(),
|
|
||||||
...efficiencySeries.keys(),
|
|
||||||
])).sort()
|
|
||||||
|
|
||||||
const sevenDayDisChargeStats = labels.map((label) => {
|
|
||||||
const chargedCap = chargedSeries.get(label)
|
|
||||||
const disChargedCap = disChargedSeries.get(label)
|
|
||||||
let dailyEfficiency = efficiencySeries.get(label)
|
|
||||||
if (dailyEfficiency == null && chargedCap != null && chargedCap !== 0 && disChargedCap != null) {
|
|
||||||
dailyEfficiency = Number(((disChargedCap / chargedCap) * 100).toFixed(2))
|
|
||||||
}
|
|
||||||
return {
|
return {
|
||||||
ammeterDate: label,
|
ammeterDate: item?.dataTime || '',
|
||||||
chargedCap: chargedCap == null ? '' : chargedCap,
|
chargedCap: chargedCap == null ? '' : chargedCap,
|
||||||
disChargedCap: disChargedCap == null ? '' : disChargedCap,
|
disChargedCap: disChargedCap == null ? '' : disChargedCap,
|
||||||
dailyEfficiency: dailyEfficiency == null ? '' : dailyEfficiency,
|
dailyEfficiency: dailyEfficiency == null ? '' : dailyEfficiency,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const fallbackTotalCharged = sevenDayDisChargeStats.reduce((acc, item) => acc + (toNumber(item.chargedCap) || 0), 0)
|
const totalChargedCap = toFixedNumber(sevenDayDisChargeStats.reduce((acc, item) => acc + (toNumber(item.chargedCap) || 0), 0))
|
||||||
const fallbackTotalDisCharged = sevenDayDisChargeStats.reduce((acc, item) => acc + (toNumber(item.disChargedCap) || 0), 0)
|
const totalDisChargedCap = toFixedNumber(sevenDayDisChargeStats.reduce((acc, item) => acc + (toNumber(item.disChargedCap) || 0), 0))
|
||||||
|
const efficiency = totalChargedCap > 0
|
||||||
const totalChargedCap = getLatestCurveValue(curveMap.totalCharged)
|
? toFixedNumber((totalDisChargedCap / totalChargedCap) * 100)
|
||||||
const totalDisChargedCap = getLatestCurveValue(curveMap.totalDisCharged)
|
: 0
|
||||||
const totalEfficiency = getLatestCurveValue(curveMap.totalEfficiency)
|
|
||||||
|
|
||||||
const resultTotalCharged = totalChargedCap == null ? fallbackTotalCharged : totalChargedCap
|
|
||||||
const resultTotalDisCharged = totalDisChargedCap == null ? fallbackTotalDisCharged : totalDisChargedCap
|
|
||||||
const resultEfficiency = totalEfficiency == null
|
|
||||||
? (resultTotalCharged > 0 ? Number(((resultTotalDisCharged / resultTotalCharged) * 100).toFixed(2)) : 0)
|
|
||||||
: totalEfficiency
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
data: {
|
data: {
|
||||||
totalChargedCap: resultTotalCharged,
|
totalChargedCap: totalChargedCap == null ? 0 : totalChargedCap,
|
||||||
totalDisChargedCap: resultTotalDisCharged,
|
totalDisChargedCap: totalDisChargedCap == null ? 0 : totalDisChargedCap,
|
||||||
efficiency: resultEfficiency,
|
efficiency: efficiency == null ? 0 : efficiency,
|
||||||
unit,
|
unit: '\u65e5',
|
||||||
sevenDayDisChargeStats,
|
sevenDayDisChargeStats,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取pcs列表
|
//鑾峰彇pcs鍒楄〃
|
||||||
export function getPcsNameList(siteId) {
|
export function getPcsNameList(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getPcsNameList?siteId=${siteId}`,
|
url: `/ems/siteMonitor/getPcsNameList?siteId=${siteId}`,
|
||||||
@ -522,7 +502,7 @@ export function getPcsNameList(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// pcs曲线
|
// pcs鏇茬嚎
|
||||||
export function getPCSData({siteId, startTime, endTime}) {
|
export function getPCSData({siteId, startTime, endTime}) {
|
||||||
const kind = resolveRangeKind(startTime, endTime)
|
const kind = resolveRangeKind(startTime, endTime)
|
||||||
const aliasMap = {
|
const aliasMap = {
|
||||||
@ -567,7 +547,7 @@ export function getPCSData({siteId, startTime, endTime}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 电池堆曲线
|
// 鐢垫睜鍫嗘洸绾?
|
||||||
export function getStackData({siteId, startTime, endTime}) {
|
export function getStackData({siteId, startTime, endTime}) {
|
||||||
const kind = resolveRangeKind(startTime, endTime)
|
const kind = resolveRangeKind(startTime, endTime)
|
||||||
const aliasMap = {
|
const aliasMap = {
|
||||||
@ -611,7 +591,7 @@ export function getStackData({siteId, startTime, endTime}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 电池温度
|
// 鐢垫睜娓╁害
|
||||||
export function getClusterData({siteId, stackId, clusterId, dateTime, pageNum, pageSize}) {
|
export function getClusterData({siteId, stackId, clusterId, dateTime, pageNum, pageSize}) {
|
||||||
const startDate = dateTime || normalizeDateInput('')
|
const startDate = dateTime || normalizeDateInput('')
|
||||||
const endDate = dateTime || normalizeDateInput('')
|
const endDate = dateTime || normalizeDateInput('')
|
||||||
@ -667,8 +647,8 @@ export function getClusterData({siteId, stackId, clusterId, dateTime, pageNum, p
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 实时运行
|
// 瀹炴椂杩愯
|
||||||
//储能
|
//鍌ㄨ兘
|
||||||
export function storagePower(siteId, startTime, endTime) {
|
export function storagePower(siteId, startTime, endTime) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/runningGraph/storagePower?siteId=${siteId}&startDate=${startTime}&endDate=${endTime}`,
|
url: `/ems/siteMonitor/runningGraph/storagePower?siteId=${siteId}&startDate=${startTime}&endDate=${endTime}`,
|
||||||
@ -676,7 +656,7 @@ export function storagePower(siteId, startTime, endTime) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//poc温度
|
//poc娓╁害
|
||||||
export function pcsMaxTemp(siteId, startTime, endTime) {
|
export function pcsMaxTemp(siteId, startTime, endTime) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/runningGraph/pcsMaxTemp?siteId=${siteId}&startDate=${startTime}&endDate=${endTime}`,
|
url: `/ems/siteMonitor/runningGraph/pcsMaxTemp?siteId=${siteId}&startDate=${startTime}&endDate=${endTime}`,
|
||||||
@ -684,7 +664,7 @@ export function pcsMaxTemp(siteId, startTime, endTime) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 电池平均soc
|
// 鐢垫睜骞冲潎soc
|
||||||
export function batteryAveSoc(siteId, startTime, endTime) {
|
export function batteryAveSoc(siteId, startTime, endTime) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/runningGraph/batteryAveSoc?siteId=${siteId}&startDate=${startTime}&endDate=${endTime}`,
|
url: `/ems/siteMonitor/runningGraph/batteryAveSoc?siteId=${siteId}&startDate=${startTime}&endDate=${endTime}`,
|
||||||
@ -692,7 +672,7 @@ export function batteryAveSoc(siteId, startTime, endTime) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 电池平均温度
|
// 鐢垫睜骞冲潎娓╁害
|
||||||
export function batteryAveTemp(siteId, startTime, endTime) {
|
export function batteryAveTemp(siteId, startTime, endTime) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/runningGraph/batteryAveTemp?siteId=${siteId}&startDate=${startTime}&endDate=${endTime}`,
|
url: `/ems/siteMonitor/runningGraph/batteryAveTemp?siteId=${siteId}&startDate=${startTime}&endDate=${endTime}`,
|
||||||
@ -700,7 +680,7 @@ export function batteryAveTemp(siteId, startTime, endTime) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 功率曲线
|
// 鍔熺巼鏇茬嚎
|
||||||
export function getPowerData({siteId, startDate, endDate}) {
|
export function getPowerData({siteId, startDate, endDate}) {
|
||||||
const kind = resolveRangeKind(startDate, endDate)
|
const kind = resolveRangeKind(startDate, endDate)
|
||||||
const aliasMap = {
|
const aliasMap = {
|
||||||
@ -736,7 +716,7 @@ export function getPowerData({siteId, startDate, endDate}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//电表列表
|
//鐢佃〃鍒楄〃
|
||||||
export function getLoadNameList(siteId) {
|
export function getLoadNameList(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/statsReport/getLoadNameList?siteId=${siteId}`,
|
url: `/ems/statsReport/getLoadNameList?siteId=${siteId}`,
|
||||||
@ -744,7 +724,7 @@ export function getLoadNameList(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 电表报表
|
// 鐢佃〃鎶ヨ〃
|
||||||
export function getAmmeterData({siteId, startTime, endTime, pageSize, pageNum}) {
|
export function getAmmeterData({siteId, startTime, endTime, pageSize, pageNum}) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/statsReport/getAmmeterDataFromDaily`,
|
url: `/ems/statsReport/getAmmeterDataFromDaily`,
|
||||||
@ -759,7 +739,7 @@ export function getAmmeterData({siteId, startTime, endTime, pageSize, pageNum})
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 电价报表
|
// 鐢典环鎶ヨ〃
|
||||||
export function getAmmeterRevenueData(data) {
|
export function getAmmeterRevenueData(data) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/statsReport/getAmmeterRevenueData`,
|
url: `/ems/statsReport/getAmmeterRevenueData`,
|
||||||
@ -768,7 +748,23 @@ export function getAmmeterRevenueData(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//策略列表
|
export function batchGetBizRemark(data) {
|
||||||
|
return request({
|
||||||
|
url: `/system/bizRemark/batchGet`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveBizRemark(data) {
|
||||||
|
return request({
|
||||||
|
url: `/system/bizRemark/save`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//绛栫暐鍒楄〃
|
||||||
export function strategyRunningList(siteId) {
|
export function strategyRunningList(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/system/strategyRunning/list?siteId=${siteId}`,
|
url: `/system/strategyRunning/list?siteId=${siteId}`,
|
||||||
@ -776,7 +772,7 @@ export function strategyRunningList(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//停止策略
|
//鍋滄绛栫暐
|
||||||
export function stopStrategyRunning(id) {
|
export function stopStrategyRunning(id) {
|
||||||
return request({
|
return request({
|
||||||
url: `/system/strategyRunning/stop?id=${id}`,
|
url: `/system/strategyRunning/stop?id=${id}`,
|
||||||
@ -784,7 +780,7 @@ export function stopStrategyRunning(id) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取所有主策略
|
// 鑾峰彇鎵€鏈変富绛栫暐
|
||||||
export function getMainStrategyList() {
|
export function getMainStrategyList() {
|
||||||
return request({
|
return request({
|
||||||
url: `/system/strategyRunning/getMainStrategyList`,
|
url: `/system/strategyRunning/getMainStrategyList`,
|
||||||
@ -792,7 +788,7 @@ export function getMainStrategyList() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取所有辅助策略
|
//鑾峰彇鎵€鏈夎緟鍔╃瓥鐣?
|
||||||
export function getAuxStrategyList() {
|
export function getAuxStrategyList() {
|
||||||
return request({
|
return request({
|
||||||
url: `/system/strategyRunning/getAuxStrategyList`,
|
url: `/system/strategyRunning/getAuxStrategyList`,
|
||||||
@ -800,7 +796,7 @@ export function getAuxStrategyList() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//配置策略
|
//閰嶇疆绛栫暐
|
||||||
export function configStrategy(data) {
|
export function configStrategy(data) {
|
||||||
return request({
|
return request({
|
||||||
url: `/system/strategyRunning/configStrategy`,
|
url: `/system/strategyRunning/configStrategy`,
|
||||||
@ -809,7 +805,7 @@ export function configStrategy(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取策略运行参数配置(按站点)
|
// 鑾峰彇绛栫暐杩愯鍙傛暟閰嶇疆锛堟寜绔欑偣锛?
|
||||||
export function getStrategyRuntimeConfig(siteId) {
|
export function getStrategyRuntimeConfig(siteId) {
|
||||||
return request({
|
return request({
|
||||||
url: `/system/strategyRuntimeConfig/getBySiteId?siteId=${siteId}`,
|
url: `/system/strategyRuntimeConfig/getBySiteId?siteId=${siteId}`,
|
||||||
@ -817,7 +813,7 @@ export function getStrategyRuntimeConfig(siteId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存策略运行参数配置(按站点)
|
// 淇濆瓨绛栫暐杩愯鍙傛暟閰嶇疆锛堟寜绔欑偣锛?
|
||||||
export function saveStrategyRuntimeConfig(data) {
|
export function saveStrategyRuntimeConfig(data) {
|
||||||
return request({
|
return request({
|
||||||
url: `/system/strategyRuntimeConfig/save`,
|
url: `/system/strategyRuntimeConfig/save`,
|
||||||
@ -827,7 +823,7 @@ export function saveStrategyRuntimeConfig(data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//http://localhost:8089/strategy/temp/getTempNameList?strategyId=1&siteId=021_FXX_01
|
//http://localhost:8089/strategy/temp/getTempNameList?strategyId=1&siteId=021_FXX_01
|
||||||
//获取策略下的所有模板列表
|
//鑾峰彇绛栫暐涓嬬殑鎵€鏈夋ā鏉垮垪琛?
|
||||||
export function getTempNameList({siteId, strategyId}) {
|
export function getTempNameList({siteId, strategyId}) {
|
||||||
return request({
|
return request({
|
||||||
url: `/strategy/temp/getTempNameList?siteId=${siteId}&strategyId=${strategyId}`,
|
url: `/strategy/temp/getTempNameList?siteId=${siteId}&strategyId=${strategyId}`,
|
||||||
@ -835,7 +831,7 @@ export function getTempNameList({siteId, strategyId}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//获取模板详情
|
//鑾峰彇妯℃澘璇︽儏
|
||||||
///strategy/temp/list?templateId=1
|
///strategy/temp/list?templateId=1
|
||||||
export function getStrategyTempDetail(templateId) {
|
export function getStrategyTempDetail(templateId) {
|
||||||
return request({
|
return request({
|
||||||
@ -844,7 +840,7 @@ export function getStrategyTempDetail(templateId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//新增模板
|
//鏂板妯℃澘
|
||||||
export function addStrategyTemp(data) {
|
export function addStrategyTemp(data) {
|
||||||
return request({
|
return request({
|
||||||
url: `/strategy/temp`,
|
url: `/strategy/temp`,
|
||||||
@ -877,7 +873,7 @@ export function timeConfigList({siteId, strategyId}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//保存时间配置
|
//淇濆瓨鏃堕棿閰嶇疆
|
||||||
// http://localhost:8089/strategy/timeConfig
|
// http://localhost:8089/strategy/timeConfig
|
||||||
export function setTimeConfigList(data) {
|
export function setTimeConfigList(data) {
|
||||||
return request({
|
return request({
|
||||||
@ -887,7 +883,7 @@ export function setTimeConfigList(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 策略曲线图
|
// 绛栫暐鏇茬嚎鍥?
|
||||||
//http://localhost:8089/strategy/curve/curveList?strategyId=1&siteId=021_FXX_01
|
//http://localhost:8089/strategy/curve/curveList?strategyId=1&siteId=021_FXX_01
|
||||||
export function curveList({siteId, strategyId}) {
|
export function curveList({siteId, strategyId}) {
|
||||||
return request({
|
return request({
|
||||||
@ -896,7 +892,7 @@ export function curveList({siteId, strategyId}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//单站监控 首页 当日功率曲线
|
//鍗曠珯鐩戞帶 棣栭〉 褰撴棩鍔熺巼鏇茬嚎
|
||||||
export function getPointData({siteId, startDate, endDate}) {
|
export function getPointData({siteId, startDate, endDate}) {
|
||||||
return request({
|
return request({
|
||||||
url: `/ems/siteMonitor/getPointData?siteId=${siteId}&startDate=${startDate}&endDate=${endDate}`,
|
url: `/ems/siteMonitor/getPointData?siteId=${siteId}&startDate=${startDate}&endDate=${endDate}`,
|
||||||
|
|||||||
@ -260,6 +260,28 @@ export function getPointMatchList(params) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 下载单体电池导入模板
|
||||||
|
export function downloadSingleBatteryMonitorImportTemplate(siteId) {
|
||||||
|
return request({
|
||||||
|
url: `/ems/siteConfig/downloadSingleBatteryMonitorImportTemplate`,
|
||||||
|
method: 'get',
|
||||||
|
params: { siteId },
|
||||||
|
responseType: 'blob'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 导入单体电池与监控点位映射
|
||||||
|
export function importSingleBatteryMonitorMappings(data) {
|
||||||
|
return request({
|
||||||
|
url: `/ems/siteConfig/importSingleBatteryMonitorMappings`,
|
||||||
|
method: 'post',
|
||||||
|
data,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 点位配置详情
|
// 点位配置详情
|
||||||
export function getPointMatchDetail(id) {
|
export function getPointMatchDetail(id) {
|
||||||
return request({
|
return request({
|
||||||
@ -496,3 +518,11 @@ export function deleteMqtt(id) {
|
|||||||
method: 'delete',
|
method: 'delete',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function initializeSingleBatteryMonitorMappings(data) {
|
||||||
|
return request({
|
||||||
|
url: `/ems/siteConfig/initializeSingleBatteryMonitorMappings`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@ -4,7 +4,9 @@
|
|||||||
<span class="card-title">当日功率曲线</span>
|
<span class="card-title">当日功率曲线</span>
|
||||||
<date-range-select ref="dateRangeSelect" :showIcon="true" :mini-time-picker="true" @updateDate="updateDate"/>
|
<date-range-select ref="dateRangeSelect" :showIcon="true" :mini-time-picker="true" @updateDate="updateDate"/>
|
||||||
</div>
|
</div>
|
||||||
<div style="height: 310px" id="activeChart"></div>
|
<div class="card-main">
|
||||||
|
<div id="activeChart" class="active-chart-canvas"></div>
|
||||||
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -153,3 +155,13 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.card-main {
|
||||||
|
padding: 0 16px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-chart-canvas {
|
||||||
|
height: 310px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-card shadow="always" class="common-card-container common-card-container-body-no-padding time-range-card">
|
<el-card shadow="always" class="common-card-container common-card-container-body-no-padding time-range-card">
|
||||||
<div slot="header" class="time-range-header">
|
<div slot="header" class="time-range-header">
|
||||||
<span class="card-title">一周充放曲线</span>
|
<span class="card-title">{{ cardTitle }}</span>
|
||||||
<date-range-select ref="dateRangeSelect" :showIcon="true" :mini-time-picker="true" @updateDate="updateDate" />
|
<date-range-select ref="dateRangeSelect" :showIcon="true" :mini-time-picker="true" @updateDate="updateDate" />
|
||||||
</div>
|
</div>
|
||||||
<div style="height: 310px" id="weekChart"></div>
|
<div class="card-main">
|
||||||
|
<div ref="weekChartRef" class="week-chart-canvas"></div>
|
||||||
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -14,6 +16,26 @@ import resize from '@/mixins/ems/resize'
|
|||||||
import DateRangeSelect from '@/components/Ems/DateRangeSelect/index.vue'
|
import DateRangeSelect from '@/components/Ems/DateRangeSelect/index.vue'
|
||||||
import { getPointConfigCurve } from '@/api/ems/site'
|
import { getPointConfigCurve } from '@/api/ems/site'
|
||||||
|
|
||||||
|
const DAY = 24 * 60 * 60 * 1000
|
||||||
|
const TEXT = {
|
||||||
|
cardTitle: '\u4e00\u5468\u5145\u653e\u67f1\u72b6\u56fe',
|
||||||
|
sectionName: '\u4e00\u5468\u5145\u653e\u66f2\u7ebf',
|
||||||
|
empty: '\u6682\u65e0\u6570\u636e',
|
||||||
|
date: '\u65e5\u671f',
|
||||||
|
charge: '\u5145\u7535\u91cf',
|
||||||
|
discharge: '\u653e\u7535\u91cf',
|
||||||
|
yAxis: '\u5145\u7535\u91cf/\u653e\u7535\u91cf\uff08kWh\uff09',
|
||||||
|
xAxis: '\u5355\u4f4d\uff1a\u65e5'
|
||||||
|
}
|
||||||
|
|
||||||
|
function createEmptySummary() {
|
||||||
|
return {
|
||||||
|
totalChargedCap: '',
|
||||||
|
totalDisChargedCap: '',
|
||||||
|
efficiency: ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [resize],
|
mixins: [resize],
|
||||||
components: { DateRangeSelect },
|
components: { DateRangeSelect },
|
||||||
@ -27,7 +49,9 @@ export default {
|
|||||||
return {
|
return {
|
||||||
chart: null,
|
chart: null,
|
||||||
timeRange: [],
|
timeRange: [],
|
||||||
siteId: ''
|
siteId: '',
|
||||||
|
summary: createEmptySummary(),
|
||||||
|
cardTitle: TEXT.cardTitle
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -50,7 +74,6 @@ export default {
|
|||||||
this.chart = null
|
this.chart = null
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 更新时间范围 重置图表
|
|
||||||
updateDate(data) {
|
updateDate(data) {
|
||||||
this.timeRange = data
|
this.timeRange = data
|
||||||
this.getWeekKData()
|
this.getWeekKData()
|
||||||
@ -59,7 +82,7 @@ export default {
|
|||||||
const { siteId, timeRange } = this
|
const { siteId, timeRange } = this
|
||||||
const displayData = this.displayData || []
|
const displayData = this.displayData || []
|
||||||
const sectionRows = displayData.filter(item =>
|
const sectionRows = displayData.filter(item =>
|
||||||
item && item.sectionName === '一周充放曲线' && item.useFixedDisplay !== 1 && item.dataPoint
|
item && item.sectionName === TEXT.sectionName && item.useFixedDisplay !== 1 && item.dataPoint
|
||||||
)
|
)
|
||||||
const tasks = sectionRows.map(row => {
|
const tasks = sectionRows.map(row => {
|
||||||
const pointId = String(row.dataPoint || '').trim()
|
const pointId = String(row.dataPoint || '').trim()
|
||||||
@ -75,6 +98,7 @@ export default {
|
|||||||
const list = curveResponse?.data || []
|
const list = curveResponse?.data || []
|
||||||
return {
|
return {
|
||||||
name: row.fieldName || row.fieldCode || pointId,
|
name: row.fieldName || row.fieldCode || pointId,
|
||||||
|
fieldCode: row.fieldCode || '',
|
||||||
data: list
|
data: list
|
||||||
.map(item => [this.parseToTimestamp(item.dataTime), Number(item.pointValue)])
|
.map(item => [this.parseToTimestamp(item.dataTime), Number(item.pointValue)])
|
||||||
.filter(item => item[0] && !Number.isNaN(item[1]))
|
.filter(item => item[0] && !Number.isNaN(item[1]))
|
||||||
@ -86,14 +110,13 @@ export default {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
init(siteId) {
|
init(siteId) {
|
||||||
//初始化 清空数据
|
|
||||||
this.siteId = siteId
|
this.siteId = siteId
|
||||||
this.timeRange = []
|
this.timeRange = []
|
||||||
this.deviceId = ''
|
this.summary = createEmptySummary()
|
||||||
this.$refs.dateRangeSelect.init()
|
this.$refs.dateRangeSelect.init()
|
||||||
},
|
},
|
||||||
initChart() {
|
initChart() {
|
||||||
this.chart = echarts.init(document.querySelector('#weekChart'))
|
this.chart = echarts.init(this.$refs.weekChartRef)
|
||||||
},
|
},
|
||||||
normalizeDateTime(value, endOfDay) {
|
normalizeDateTime(value, endOfDay) {
|
||||||
const raw = String(value || '').trim()
|
const raw = String(value || '').trim()
|
||||||
@ -106,41 +129,243 @@ export default {
|
|||||||
const t = new Date(value).getTime()
|
const t = new Date(value).getTime()
|
||||||
return Number.isNaN(t) ? null : t
|
return Number.isNaN(t) ? null : t
|
||||||
},
|
},
|
||||||
|
startOfDay(timestamp) {
|
||||||
|
const date = new Date(timestamp)
|
||||||
|
date.setHours(0, 0, 0, 0)
|
||||||
|
return date.getTime()
|
||||||
|
},
|
||||||
|
formatNumber(value) {
|
||||||
|
const num = Number(value)
|
||||||
|
if (Number.isNaN(num)) return '--'
|
||||||
|
return num.toLocaleString('zh-CN', {
|
||||||
|
minimumFractionDigits: 0,
|
||||||
|
maximumFractionDigits: 2
|
||||||
|
})
|
||||||
|
},
|
||||||
|
formatDateLabel(timestamp) {
|
||||||
|
const date = new Date(timestamp)
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(date.getDate()).padStart(2, '0')
|
||||||
|
return `${month}-${day}`
|
||||||
|
},
|
||||||
|
formatTooltipDate(timestamp) {
|
||||||
|
const date = new Date(timestamp)
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(date.getDate()).padStart(2, '0')
|
||||||
|
return `${year}-${month}-${day}`
|
||||||
|
},
|
||||||
|
buildDatasetSource(labels = [], chargeData = [], dischargeData = []) {
|
||||||
|
const source = [[TEXT.date, TEXT.charge, TEXT.discharge]]
|
||||||
|
labels.forEach((label, index) => {
|
||||||
|
source.push([
|
||||||
|
label,
|
||||||
|
Number(chargeData[index]?.value || 0),
|
||||||
|
Number(dischargeData[index]?.value || 0)
|
||||||
|
])
|
||||||
|
})
|
||||||
|
return source
|
||||||
|
},
|
||||||
|
resolveSeriesType(item = {}) {
|
||||||
|
const text = `${item?.name || ''} ${item?.fieldCode || ''}`.toLowerCase()
|
||||||
|
if (text.includes('\u653e') || text.includes('discharge') || text.includes('discharged')) {
|
||||||
|
return 'discharge'
|
||||||
|
}
|
||||||
|
if (text.includes('\u5145') || text.includes('charge') || text.includes('charged')) {
|
||||||
|
return 'charge'
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
},
|
||||||
|
buildDailyChartData(seriesData = []) {
|
||||||
|
const normalizedRange = this.timeRange || []
|
||||||
|
const startTime = this.parseToTimestamp(this.normalizeDateTime(normalizedRange[0], false))
|
||||||
|
const endTime = this.parseToTimestamp(this.normalizeDateTime(normalizedRange[1], true))
|
||||||
|
if (!startTime || !endTime || endTime < startTime) {
|
||||||
|
return {
|
||||||
|
labels: [],
|
||||||
|
chargeData: [],
|
||||||
|
dischargeData: [],
|
||||||
|
summary: createEmptySummary()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bucketStarts = []
|
||||||
|
for (let cursor = this.startOfDay(startTime); cursor <= this.startOfDay(endTime); cursor += DAY) {
|
||||||
|
bucketStarts.push(cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
const chargeMap = {}
|
||||||
|
const dischargeMap = {}
|
||||||
|
|
||||||
|
;(seriesData || []).forEach(item => {
|
||||||
|
const seriesType = this.resolveSeriesType(item)
|
||||||
|
if (!seriesType) return
|
||||||
|
|
||||||
|
;(item?.data || []).forEach(([timestamp, pointValue]) => {
|
||||||
|
if (!timestamp || Number.isNaN(pointValue)) return
|
||||||
|
if (timestamp < startTime || timestamp > endTime) return
|
||||||
|
|
||||||
|
const bucketStart = this.startOfDay(timestamp)
|
||||||
|
const normalizedValue = Math.abs(Number(pointValue) || 0)
|
||||||
|
if (seriesType === 'charge') {
|
||||||
|
chargeMap[bucketStart] = (chargeMap[bucketStart] || 0) + normalizedValue
|
||||||
|
} else if (seriesType === 'discharge') {
|
||||||
|
dischargeMap[bucketStart] = (dischargeMap[bucketStart] || 0) + normalizedValue
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const labels = []
|
||||||
|
const chargeData = []
|
||||||
|
const dischargeData = []
|
||||||
|
|
||||||
|
bucketStarts.forEach(bucketStart => {
|
||||||
|
const chargedCap = Number(chargeMap[bucketStart] || 0)
|
||||||
|
const disChargedCap = Number(dischargeMap[bucketStart] || 0)
|
||||||
|
|
||||||
|
labels.push(this.formatDateLabel(bucketStart))
|
||||||
|
chargeData.push({
|
||||||
|
value: chargedCap,
|
||||||
|
bucketStart
|
||||||
|
})
|
||||||
|
dischargeData.push({
|
||||||
|
value: disChargedCap,
|
||||||
|
bucketStart
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const totalChargedCap = chargeData.reduce((sum, item) => sum + Number(item.value || 0), 0)
|
||||||
|
const totalDisChargedCap = dischargeData.reduce((sum, item) => sum + Number(item.value || 0), 0)
|
||||||
|
const efficiency = totalChargedCap > 0
|
||||||
|
? Number(((totalDisChargedCap / totalChargedCap) * 100).toFixed(2))
|
||||||
|
: 0
|
||||||
|
|
||||||
|
return {
|
||||||
|
labels,
|
||||||
|
chargeData,
|
||||||
|
dischargeData,
|
||||||
|
summary: {
|
||||||
|
totalChargedCap,
|
||||||
|
totalDisChargedCap,
|
||||||
|
efficiency
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
renderEmptyState(message = TEXT.empty) {
|
||||||
|
if (!this.chart) return
|
||||||
|
this.chart.clear()
|
||||||
|
this.chart.setOption({
|
||||||
|
graphic: {
|
||||||
|
type: 'text',
|
||||||
|
left: 'center',
|
||||||
|
top: 'middle',
|
||||||
|
style: {
|
||||||
|
text: message,
|
||||||
|
fill: '#909399',
|
||||||
|
fontSize: 14
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
setOption(seriesData = []) {
|
setOption(seriesData = []) {
|
||||||
this.chart && this.chart.setOption({
|
if (!this.chart) return
|
||||||
color: ['#4472c4', '#70ad47'],//所有充放电颜色保持统一
|
|
||||||
|
const { labels, chargeData, dischargeData, summary } = this.buildDailyChartData(seriesData)
|
||||||
|
const hasValue = chargeData.some(item => Number(item?.value || 0) > 0) || dischargeData.some(item => Number(item?.value || 0) > 0)
|
||||||
|
|
||||||
|
if (!labels.length || !hasValue) {
|
||||||
|
this.summary = createEmptySummary()
|
||||||
|
this.renderEmptyState()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.summary = summary
|
||||||
|
const source = this.buildDatasetSource(labels, chargeData, dischargeData)
|
||||||
|
|
||||||
|
this.chart.clear()
|
||||||
|
this.chart.setOption({
|
||||||
|
color: ['#4472c4', '#70ad47'],
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'axis',
|
trigger: 'axis',
|
||||||
axisPointer: { type: 'cross' }
|
axisPointer: {
|
||||||
|
type: 'shadow'
|
||||||
},
|
},
|
||||||
grid: {
|
formatter: (params = []) => {
|
||||||
containLabel: true
|
if (!params.length) return ''
|
||||||
|
const dataIndex = Number(params[0]?.dataIndex)
|
||||||
|
const bucketStart = chargeData[dataIndex]?.bucketStart
|
||||||
|
const lines = [this.formatTooltipDate(bucketStart)]
|
||||||
|
params.forEach(item => {
|
||||||
|
const rawValue = Array.isArray(item?.value) ? item.value[item.seriesIndex + 1] : item?.value
|
||||||
|
const value = Number(rawValue || 0)
|
||||||
|
lines.push(`${item.marker}${item.seriesName}: ${this.formatNumber(value)}kWh`)
|
||||||
|
})
|
||||||
|
return lines.join('<br/>')
|
||||||
|
},
|
||||||
|
extraCssText: 'max-width: 420px; white-space: normal;'
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
left: 'center',
|
left: 'center',
|
||||||
bottom: '15',
|
bottom: 15
|
||||||
},
|
},
|
||||||
xAxis: {
|
grid: {
|
||||||
type: 'time'
|
top: 40,
|
||||||
|
containLabel: true,
|
||||||
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
bottom: 60
|
||||||
},
|
},
|
||||||
yAxis: [{
|
yAxis: [{
|
||||||
type: 'value',
|
type: 'value',
|
||||||
name: '充电量/放电量kWh',
|
name: TEXT.yAxis,
|
||||||
axisLine: {
|
axisLine: {
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
color: '#333333',
|
color: '#333333'
|
||||||
},
|
},
|
||||||
onZero: false
|
onZero: false
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
series: seriesData.map(item => ({
|
xAxis: [{
|
||||||
name: item.name,
|
type: 'category',
|
||||||
yAxisIndex: 0,
|
name: TEXT.xAxis,
|
||||||
|
nameLocation: 'center',
|
||||||
|
nameGap: 30,
|
||||||
|
axisTick: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
interval: 0
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
dataset: {
|
||||||
|
source
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: TEXT.charge,
|
||||||
type: 'bar',
|
type: 'bar',
|
||||||
data: item.data
|
color: '#4472c4',
|
||||||
}))
|
barMaxWidth: 22
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: TEXT.discharge,
|
||||||
|
type: 'bar',
|
||||||
|
color: '#70ad47',
|
||||||
|
barMaxWidth: 22
|
||||||
|
}
|
||||||
|
]
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.card-main {
|
||||||
|
padding: 0 16px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.week-chart-canvas {
|
||||||
|
height: 310px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -151,7 +151,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import * as echarts from "echarts";
|
import * as echarts from "echarts";
|
||||||
import {getSingleSiteBaseInfo} from "@/api/ems/zddt";
|
import {getSingleSiteBaseInfo} from "@/api/ems/zddt";
|
||||||
import {getDzjkHomeTotalView, getProjectDisplayData} from "@/api/ems/dzjk";
|
import {getAmmeterData, getDzjkHomeTotalView, getProjectDisplayData} from "@/api/ems/dzjk";
|
||||||
import {getPointConfigCurve} from "@/api/ems/site";
|
import {getPointConfigCurve} from "@/api/ems/site";
|
||||||
import WeekChart from "./WeekChart.vue";
|
import WeekChart from "./WeekChart.vue";
|
||||||
import ActiveChart from "./ActiveChart.vue";
|
import ActiveChart from "./ActiveChart.vue";
|
||||||
@ -229,6 +229,7 @@ export default {
|
|||||||
info: {}, //基本信息
|
info: {}, //基本信息
|
||||||
runningInfo: {}, //总累计运行数据+报警表格
|
runningInfo: {}, //总累计运行数据+报警表格
|
||||||
runningDisplayData: [], //单站监控项目配置展示数据
|
runningDisplayData: [], //单站监控项目配置展示数据
|
||||||
|
ammeterDailySummary: {},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -264,7 +265,7 @@ export default {
|
|||||||
.filter(item => item.fieldCode !== revenueFieldCode)
|
.filter(item => item.fieldCode !== revenueFieldCode)
|
||||||
.map((item, index) => ({
|
.map((item, index) => ({
|
||||||
title: item.fieldName,
|
title: item.fieldName,
|
||||||
value: item.fieldValue,
|
value: this.getRunningCardValue(item),
|
||||||
color: this.getCardColor(index),
|
color: this.getCardColor(index),
|
||||||
loading: this.isRunningInfoLoading,
|
loading: this.isRunningInfoLoading,
|
||||||
raw: item,
|
raw: item,
|
||||||
@ -272,7 +273,7 @@ export default {
|
|||||||
}
|
}
|
||||||
return this.fallbackSjglData.map(item => ({
|
return this.fallbackSjglData.map(item => ({
|
||||||
title: item.title,
|
title: item.title,
|
||||||
value: this.runningInfo[item.attr],
|
value: this.getRunningCardValue(item),
|
||||||
color: item.color,
|
color: item.color,
|
||||||
loading: this.isRunningInfoLoading,
|
loading: this.isRunningInfoLoading,
|
||||||
raw: item,
|
raw: item,
|
||||||
@ -468,6 +469,131 @@ export default {
|
|||||||
const colors = ['#4472c4', '#70ad47', '#4472c4', '#f67438', '#4472c4', '#70ad47', '#70ad47', '#f67438'];
|
const colors = ['#4472c4', '#70ad47', '#4472c4', '#f67438', '#4472c4', '#70ad47', '#70ad47', '#f67438'];
|
||||||
return colors[index % colors.length];
|
return colors[index % colors.length];
|
||||||
},
|
},
|
||||||
|
formatDateOnly(date) {
|
||||||
|
const value = new Date(date);
|
||||||
|
if (isNaN(value.getTime())) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
const pad = (num) => String(num).padStart(2, "0");
|
||||||
|
return `${value.getFullYear()}-${pad(value.getMonth() + 1)}-${pad(value.getDate())}`;
|
||||||
|
},
|
||||||
|
normalizeDateOnly(value) {
|
||||||
|
if (!value) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
const raw = String(value).trim();
|
||||||
|
const matched = raw.match(/\d{4}-\d{2}-\d{2}/);
|
||||||
|
if (matched) {
|
||||||
|
return matched[0];
|
||||||
|
}
|
||||||
|
return this.formatDateOnly(raw);
|
||||||
|
},
|
||||||
|
toDisplayNumber(value) {
|
||||||
|
if (value === null || value === undefined || value === "") {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
const num = Number(value);
|
||||||
|
return Number.isNaN(num) ? value : num;
|
||||||
|
},
|
||||||
|
getAmmeterSummaryAttr(item) {
|
||||||
|
const fieldCode = String(item?.fieldCode || item?.attr || "").trim();
|
||||||
|
const fieldName = String(item?.fieldName || item?.title || "").trim();
|
||||||
|
if (["dayChargedCap", "今日充电量(kWh)"].includes(fieldCode) || fieldName === "今日充电量(kWh)") {
|
||||||
|
return "dayChargedCap";
|
||||||
|
}
|
||||||
|
if (["dayDisChargedCap", "今日放电量(kWh)"].includes(fieldCode) || fieldName === "今日放电量(kWh)") {
|
||||||
|
return "dayDisChargedCap";
|
||||||
|
}
|
||||||
|
if (["yesterdayChargedCap", "昨日充电量(kWh)"].includes(fieldCode) || fieldName === "昨日充电量(kWh)") {
|
||||||
|
return "yesterdayChargedCap";
|
||||||
|
}
|
||||||
|
if (["yesterdayDisChargedCap", "昨日放电量(kWh)"].includes(fieldCode) || fieldName === "昨日放电量(kWh)") {
|
||||||
|
return "yesterdayDisChargedCap";
|
||||||
|
}
|
||||||
|
if (["totalChargedCap", "总充电量(kWh)"].includes(fieldCode) || fieldName === "总充电量(kWh)") {
|
||||||
|
return "totalChargedCap";
|
||||||
|
}
|
||||||
|
if (["totalDischargedCap", "总放电量(kWh)"].includes(fieldCode) || fieldName === "总放电量(kWh)") {
|
||||||
|
return "totalDischargedCap";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
getRunningCardValue(item) {
|
||||||
|
const summaryAttr = this.getAmmeterSummaryAttr(item);
|
||||||
|
if (summaryAttr) {
|
||||||
|
const summaryValue = this.ammeterDailySummary?.[summaryAttr];
|
||||||
|
if (summaryValue !== undefined && summaryValue !== null && summaryValue !== "") {
|
||||||
|
return summaryValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const rawValue = item?.fieldValue !== undefined ? item.fieldValue : this.runningInfo?.[item?.attr];
|
||||||
|
return this.toDisplayNumber(rawValue);
|
||||||
|
},
|
||||||
|
queryAllAmmeterDailyRows({ startTime = "", endTime = "", pageSize = 500, pageNum = 1, rows = [] } = {}) {
|
||||||
|
return getAmmeterData({
|
||||||
|
siteId: this.siteId,
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
pageSize,
|
||||||
|
pageNum,
|
||||||
|
}).then((response) => {
|
||||||
|
const currentRows = Array.isArray(response?.rows) ? response.rows : [];
|
||||||
|
const allRows = rows.concat(currentRows);
|
||||||
|
const total = Number(response?.total) || 0;
|
||||||
|
if (allRows.length >= total || currentRows.length < pageSize) {
|
||||||
|
return allRows;
|
||||||
|
}
|
||||||
|
return this.queryAllAmmeterDailyRows({
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
pageSize,
|
||||||
|
pageNum: pageNum + 1,
|
||||||
|
rows: allRows,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getAmmeterDailySummary() {
|
||||||
|
const today = new Date();
|
||||||
|
const yesterday = new Date(today);
|
||||||
|
yesterday.setDate(yesterday.getDate() - 1);
|
||||||
|
const startTime = this.formatDateOnly(yesterday);
|
||||||
|
const endTime = this.formatDateOnly(today);
|
||||||
|
return Promise.all([
|
||||||
|
this.queryAllAmmeterDailyRows({
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
pageSize: 20,
|
||||||
|
pageNum: 1,
|
||||||
|
}),
|
||||||
|
this.queryAllAmmeterDailyRows(),
|
||||||
|
]).then(([recentRows, allRows]) => {
|
||||||
|
const rowMap = recentRows.reduce((result, row) => {
|
||||||
|
const dateKey = this.normalizeDateOnly(row?.dataTime);
|
||||||
|
if (dateKey) {
|
||||||
|
result[dateKey] = row;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}, {});
|
||||||
|
const todayKey = this.formatDateOnly(today);
|
||||||
|
const yesterdayKey = this.formatDateOnly(yesterday);
|
||||||
|
const todayRow = rowMap[todayKey] || {};
|
||||||
|
const yesterdayRow = rowMap[yesterdayKey] || {};
|
||||||
|
const totalChargedCap = allRows.reduce((result, row) => {
|
||||||
|
return result + (Number(row?.activeTotalKwh) || 0);
|
||||||
|
}, 0);
|
||||||
|
const totalDischargedCap = allRows.reduce((result, row) => {
|
||||||
|
return result + (Number(row?.reActiveTotalKwh) || 0);
|
||||||
|
}, 0);
|
||||||
|
return {
|
||||||
|
dayChargedCap: this.toDisplayNumber(todayRow.activeTotalKwh),
|
||||||
|
dayDisChargedCap: this.toDisplayNumber(todayRow.reActiveTotalKwh),
|
||||||
|
yesterdayChargedCap: this.toDisplayNumber(yesterdayRow.activeTotalKwh),
|
||||||
|
yesterdayDisChargedCap: this.toDisplayNumber(yesterdayRow.reActiveTotalKwh),
|
||||||
|
totalChargedCap: this.toDisplayNumber(totalChargedCap),
|
||||||
|
totalDischargedCap: this.toDisplayNumber(totalDischargedCap),
|
||||||
|
};
|
||||||
|
}).catch(() => ({}));
|
||||||
|
},
|
||||||
toAlarm() {
|
toAlarm() {
|
||||||
this.$router.push({path: "/dzjk/gzgj", query: this.$route.query});
|
this.$router.push({path: "/dzjk/gzgj", query: this.$route.query});
|
||||||
},
|
},
|
||||||
@ -484,12 +610,14 @@ export default {
|
|||||||
return Promise.all([
|
return Promise.all([
|
||||||
getDzjkHomeTotalView(this.siteId),
|
getDzjkHomeTotalView(this.siteId),
|
||||||
getProjectDisplayData(this.siteId),
|
getProjectDisplayData(this.siteId),
|
||||||
]).then(([homeResponse, displayResponse]) => {
|
this.getAmmeterDailySummary(),
|
||||||
|
]).then(([homeResponse, displayResponse, ammeterDailySummary]) => {
|
||||||
const nextRunningInfo = homeResponse?.data || {};
|
const nextRunningInfo = homeResponse?.data || {};
|
||||||
const nextRunningDisplayData = displayResponse?.data || [];
|
const nextRunningDisplayData = displayResponse?.data || [];
|
||||||
const changed = hasOldData && this.hasTotalRunningChanged(nextRunningInfo, nextRunningDisplayData);
|
const changed = hasOldData && this.hasTotalRunningChanged(nextRunningInfo, nextRunningDisplayData, ammeterDailySummary || {});
|
||||||
this.runningInfo = nextRunningInfo;
|
this.runningInfo = nextRunningInfo;
|
||||||
this.runningDisplayData = nextRunningDisplayData;
|
this.runningDisplayData = nextRunningDisplayData;
|
||||||
|
this.ammeterDailySummary = ammeterDailySummary || {};
|
||||||
if (changed) {
|
if (changed) {
|
||||||
this.triggerRunningUpdateSpinner();
|
this.triggerRunningUpdateSpinner();
|
||||||
}
|
}
|
||||||
@ -509,24 +637,30 @@ export default {
|
|||||||
this.runningUpdateTimer = null;
|
this.runningUpdateTimer = null;
|
||||||
}, 800);
|
}, 800);
|
||||||
},
|
},
|
||||||
hasTotalRunningChanged(nextRunningInfo, nextRunningDisplayData) {
|
hasTotalRunningChanged(nextRunningInfo, nextRunningDisplayData, nextAmmeterDailySummary = {}) {
|
||||||
const oldSnapshot = this.getTotalRunningSnapshot(this.runningInfo, this.runningDisplayData);
|
const oldSnapshot = this.getTotalRunningSnapshot(this.runningInfo, this.runningDisplayData, this.ammeterDailySummary || {});
|
||||||
const newSnapshot = this.getTotalRunningSnapshot(nextRunningInfo, nextRunningDisplayData);
|
const newSnapshot = this.getTotalRunningSnapshot(nextRunningInfo, nextRunningDisplayData, nextAmmeterDailySummary);
|
||||||
return JSON.stringify(oldSnapshot) !== JSON.stringify(newSnapshot);
|
return JSON.stringify(oldSnapshot) !== JSON.stringify(newSnapshot);
|
||||||
},
|
},
|
||||||
getTotalRunningSnapshot(runningInfo, runningDisplayData) {
|
getTotalRunningSnapshot(runningInfo, runningDisplayData, ammeterDailySummary = {}) {
|
||||||
const snapshot = {};
|
const snapshot = {};
|
||||||
const sectionData = (runningDisplayData || []).filter(item => item.sectionName === "总累计运行数据");
|
const sectionData = (runningDisplayData || []).filter(item => item.sectionName === "总累计运行数据");
|
||||||
if (sectionData.length > 0) {
|
if (sectionData.length > 0) {
|
||||||
sectionData.forEach(item => {
|
sectionData.forEach(item => {
|
||||||
const key = item.fieldCode || item.fieldName;
|
const key = item.fieldCode || item.fieldName;
|
||||||
if (!key) return;
|
if (!key) return;
|
||||||
snapshot[`cfg:${key}`] = this.normalizeRunningCompareValue(item.fieldValue);
|
const summaryAttr = this.getAmmeterSummaryAttr(item);
|
||||||
|
const value = summaryAttr ? ammeterDailySummary?.[summaryAttr] : item.fieldValue;
|
||||||
|
snapshot[`cfg:${key}`] = this.normalizeRunningCompareValue(value);
|
||||||
});
|
});
|
||||||
return snapshot;
|
return snapshot;
|
||||||
}
|
}
|
||||||
this.fallbackSjglData.forEach(item => {
|
this.fallbackSjglData.forEach(item => {
|
||||||
snapshot[`fallback:${item.attr}`] = this.normalizeRunningCompareValue(runningInfo?.[item.attr]);
|
const summaryAttr = this.getAmmeterSummaryAttr(item);
|
||||||
|
const value = summaryAttr
|
||||||
|
? ammeterDailySummary?.[summaryAttr]
|
||||||
|
: runningInfo?.[item.attr];
|
||||||
|
snapshot[`fallback:${item.attr}`] = this.normalizeRunningCompareValue(value);
|
||||||
});
|
});
|
||||||
snapshot["fallback:totalRevenue"] = this.normalizeRunningCompareValue(runningInfo?.totalRevenue);
|
snapshot["fallback:totalRevenue"] = this.normalizeRunningCompareValue(runningInfo?.totalRevenue);
|
||||||
return snapshot;
|
return snapshot;
|
||||||
|
|||||||
@ -56,7 +56,7 @@
|
|||||||
:class="{ 'field-disabled': !hasFieldPointId(baseInfo, 'workStatus') }"
|
:class="{ 'field-disabled': !hasFieldPointId(baseInfo, 'workStatus') }"
|
||||||
@click="handleFieldClick(baseInfo, 'workStatus', '工作状态')"
|
@click="handleFieldClick(baseInfo, 'workStatus', '工作状态')"
|
||||||
>
|
>
|
||||||
{{ CLUSTERWorkStatusOptions[baseInfo.workStatus] || '-' }}
|
{{ formatDictValue(clusterWorkStatusOptions, baseInfo.workStatus) }}
|
||||||
</span>
|
</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item contentClassName="descriptions-direction"
|
<el-descriptions-item contentClassName="descriptions-direction"
|
||||||
@ -66,7 +66,7 @@
|
|||||||
:class="{ 'field-disabled': !hasFieldPointId(baseInfo, 'pcsCommunicationStatus') }"
|
:class="{ 'field-disabled': !hasFieldPointId(baseInfo, 'pcsCommunicationStatus') }"
|
||||||
@click="handleFieldClick(baseInfo, 'pcsCommunicationStatus', '与PCS通信')"
|
@click="handleFieldClick(baseInfo, 'pcsCommunicationStatus', '与PCS通信')"
|
||||||
>
|
>
|
||||||
{{ (($store.state.ems && $store.state.ems.communicationStatusOptions) || {})[baseInfo.pcsCommunicationStatus] || '-' }}
|
{{ formatDictValue(clusterPcsCommunicationStatusOptions, baseInfo.pcsCommunicationStatus) }}
|
||||||
</span>
|
</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item contentClassName="descriptions-direction"
|
<el-descriptions-item contentClassName="descriptions-direction"
|
||||||
@ -76,7 +76,7 @@
|
|||||||
:class="{ 'field-disabled': !hasFieldPointId(baseInfo, 'emsCommunicationStatus') }"
|
:class="{ 'field-disabled': !hasFieldPointId(baseInfo, 'emsCommunicationStatus') }"
|
||||||
@click="handleFieldClick(baseInfo, 'emsCommunicationStatus', '与EMS通信')"
|
@click="handleFieldClick(baseInfo, 'emsCommunicationStatus', '与EMS通信')"
|
||||||
>
|
>
|
||||||
{{ (($store.state.ems && $store.state.ems.communicationStatusOptions) || {})[baseInfo.emsCommunicationStatus] || '-' }}
|
{{ formatDictValue(clusterEmsCommunicationStatusOptions, baseInfo.emsCommunicationStatus) }}
|
||||||
</span>
|
</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
@ -205,7 +205,7 @@ import {getProjectDisplayData, getStackNameList, getClusterNameList} from '@/api
|
|||||||
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
|
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
|
||||||
import intervalUpdate from "@/mixins/ems/intervalUpdate";
|
import intervalUpdate from "@/mixins/ems/intervalUpdate";
|
||||||
import {mapState} from "vuex";
|
import {mapState} from "vuex";
|
||||||
import {getPointConfigCurve} from "@/api/ems/site";
|
import {getPointConfigCurve, getSingleMonitorWorkStatusEnumMappings} from "@/api/ems/site";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DzjkSbjkBmsdcc',
|
name: 'DzjkSbjkBmsdcc',
|
||||||
@ -215,6 +215,15 @@ export default {
|
|||||||
...mapState({
|
...mapState({
|
||||||
CLUSTERWorkStatusOptions: state => state?.ems?.CLUSTERWorkStatusOptions || {},
|
CLUSTERWorkStatusOptions: state => state?.ems?.CLUSTERWorkStatusOptions || {},
|
||||||
}),
|
}),
|
||||||
|
clusterWorkStatusOptions() {
|
||||||
|
return this.getEnumOptions("CLUSTER", "workStatus", this.CLUSTERWorkStatusOptions || {});
|
||||||
|
},
|
||||||
|
clusterPcsCommunicationStatusOptions() {
|
||||||
|
return this.getEnumOptions("CLUSTER", "pcsCommunicationStatus", (this.$store.state.ems && this.$store.state.ems.communicationStatusOptions) || {});
|
||||||
|
},
|
||||||
|
clusterEmsCommunicationStatusOptions() {
|
||||||
|
return this.getEnumOptions("CLUSTER", "emsCommunicationStatus", (this.$store.state.ems && this.$store.state.ems.communicationStatusOptions) || {});
|
||||||
|
},
|
||||||
filteredBaseInfoList() {
|
filteredBaseInfoList() {
|
||||||
if (!this.selectedClusterId) {
|
if (!this.selectedClusterId) {
|
||||||
return this.baseInfoList || [];
|
return this.baseInfoList || [];
|
||||||
@ -227,6 +236,7 @@ export default {
|
|||||||
loading: false,
|
loading: false,
|
||||||
displayData: [],
|
displayData: [],
|
||||||
clusterDeviceList: [],
|
clusterDeviceList: [],
|
||||||
|
siteEnumOptionMap: {},
|
||||||
selectedClusterId: "",
|
selectedClusterId: "",
|
||||||
curveDialogVisible: false,
|
curveDialogVisible: false,
|
||||||
curveDialogTitle: "点位曲线",
|
curveDialogTitle: "点位曲线",
|
||||||
@ -286,9 +296,69 @@ export default {
|
|||||||
isPointLoading(value) {
|
isPointLoading(value) {
|
||||||
return this.loading && (value === undefined || value === null || value === "" || value === "-");
|
return this.loading && (value === undefined || value === null || value === "" || value === "-");
|
||||||
},
|
},
|
||||||
|
normalizeDictKey(value) {
|
||||||
|
const raw = String(value == null ? "" : value).trim();
|
||||||
|
if (!raw) return "";
|
||||||
|
if (/^-?\d+(\.0+)?$/.test(raw)) {
|
||||||
|
return String(parseInt(raw, 10));
|
||||||
|
}
|
||||||
|
return raw;
|
||||||
|
},
|
||||||
|
formatDictValue(options, value) {
|
||||||
|
const dict = (options && typeof options === "object") ? options : {};
|
||||||
|
const key = this.normalizeDictKey(value);
|
||||||
|
if (!key) return "-";
|
||||||
|
return dict[key] || key;
|
||||||
|
},
|
||||||
|
buildEnumScopeKey(deviceCategory, matchField) {
|
||||||
|
return `${String(deviceCategory || "").trim()}|${String(matchField || "").trim()}`;
|
||||||
|
},
|
||||||
|
buildSiteEnumOptionMap(mappings = []) {
|
||||||
|
return (mappings || []).reduce((acc, item) => {
|
||||||
|
const scopeKey = this.buildEnumScopeKey(item?.deviceCategory, item?.matchField);
|
||||||
|
const dataEnumCode = this.normalizeDictKey(item?.dataEnumCode);
|
||||||
|
const enumCode = this.normalizeDictKey(item?.enumCode);
|
||||||
|
const enumName = String(item?.enumName || "").trim();
|
||||||
|
const optionKey = dataEnumCode || enumCode;
|
||||||
|
if (!scopeKey || !optionKey || !enumName) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
if (!acc[scopeKey]) {
|
||||||
|
acc[scopeKey] = {};
|
||||||
|
}
|
||||||
|
acc[scopeKey][optionKey] = enumName;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
},
|
||||||
|
loadSiteEnumOptions() {
|
||||||
|
if (!this.siteId) {
|
||||||
|
this.siteEnumOptionMap = {};
|
||||||
|
return Promise.resolve({});
|
||||||
|
}
|
||||||
|
return getSingleMonitorWorkStatusEnumMappings(this.siteId).then(response => {
|
||||||
|
const optionMap = this.buildSiteEnumOptionMap(response?.data || []);
|
||||||
|
this.siteEnumOptionMap = optionMap;
|
||||||
|
return optionMap;
|
||||||
|
}).catch(() => {
|
||||||
|
this.siteEnumOptionMap = {};
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getEnumOptions(deviceCategory, matchField, fallback = {}) {
|
||||||
|
const scopeKey = this.buildEnumScopeKey(deviceCategory, matchField);
|
||||||
|
const siteOptions = this.siteEnumOptionMap[scopeKey];
|
||||||
|
if (siteOptions && Object.keys(siteOptions).length > 0) {
|
||||||
|
return siteOptions;
|
||||||
|
}
|
||||||
|
return fallback || {};
|
||||||
|
},
|
||||||
handleCardClass(item) {
|
handleCardClass(item) {
|
||||||
const {workStatus = ''} = item
|
const workStatus = this.normalizeDictKey((item && item.workStatus) || "");
|
||||||
return !(Object.keys(this.CLUSTERWorkStatusOptions).includes(item.workStatus)) ? "timing-card-container" : workStatus === '9' ? 'warning-card-container' : 'running-card-container'
|
const statusOptions = (this.clusterWorkStatusOptions && typeof this.clusterWorkStatusOptions === "object")
|
||||||
|
? this.clusterWorkStatusOptions
|
||||||
|
: {};
|
||||||
|
const hasStatus = Object.prototype.hasOwnProperty.call(statusOptions, workStatus);
|
||||||
|
return !hasStatus ? "timing-card-container" : workStatus === '9' ? 'warning-card-container' : 'running-card-container';
|
||||||
},
|
},
|
||||||
// 查看设备电位表格
|
// 查看设备电位表格
|
||||||
pointDetail(row, dataType) {
|
pointDetail(row, dataType) {
|
||||||
@ -596,6 +666,7 @@ export default {
|
|||||||
Promise.all([
|
Promise.all([
|
||||||
getProjectDisplayData(this.siteId),
|
getProjectDisplayData(this.siteId),
|
||||||
this.getClusterDeviceList(),
|
this.getClusterDeviceList(),
|
||||||
|
this.loadSiteEnumOptions(),
|
||||||
]).then(([response]) => {
|
]).then(([response]) => {
|
||||||
this.displayData = response?.data || [];
|
this.displayData = response?.data || [];
|
||||||
this.buildBaseInfoList();
|
this.buildBaseInfoList();
|
||||||
|
|||||||
@ -50,19 +50,19 @@
|
|||||||
contentClassName="descriptions-direction work-status"
|
contentClassName="descriptions-direction work-status"
|
||||||
label="工作状态" labelClassName="descriptions-label">
|
label="工作状态" labelClassName="descriptions-label">
|
||||||
<span class="pointer" @click="handleStatusFieldClick(baseInfo, 'workStatus', '工作状态')">
|
<span class="pointer" @click="handleStatusFieldClick(baseInfo, 'workStatus', '工作状态')">
|
||||||
{{ STACKWorkStatusOptions[baseInfo.workStatus] || '-' }}
|
{{ formatDictValue(stackWorkStatusOptions, baseInfo.workStatus) }}
|
||||||
</span>
|
</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item :span="1" contentClassName="descriptions-direction" label="与PCS通信"
|
<el-descriptions-item :span="1" contentClassName="descriptions-direction" label="与PCS通信"
|
||||||
labelClassName="descriptions-label">
|
labelClassName="descriptions-label">
|
||||||
<span class="pointer" @click="handleStatusFieldClick(baseInfo, 'pcsCommunicationStatus', '与PCS通信')">
|
<span class="pointer" @click="handleStatusFieldClick(baseInfo, 'pcsCommunicationStatus', '与PCS通信')">
|
||||||
{{ (($store.state.ems && $store.state.ems.communicationStatusOptions) || {})[baseInfo.pcsCommunicationStatus] || '-' }}
|
{{ formatDictValue(stackPcsCommunicationStatusOptions, baseInfo.pcsCommunicationStatus) }}
|
||||||
</span>
|
</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
<el-descriptions-item :span="1" contentClassName="descriptions-direction" label="与EMS通信"
|
<el-descriptions-item :span="1" contentClassName="descriptions-direction" label="与EMS通信"
|
||||||
labelClassName="descriptions-label">
|
labelClassName="descriptions-label">
|
||||||
<span class="pointer" @click="handleStatusFieldClick(baseInfo, 'emsCommunicationStatus', '与EMS通信')">
|
<span class="pointer" @click="handleStatusFieldClick(baseInfo, 'emsCommunicationStatus', '与EMS通信')">
|
||||||
{{ (($store.state.ems && $store.state.ems.communicationStatusOptions) || {})[baseInfo.emsCommunicationStatus] || '-' }}
|
{{ formatDictValue(stackEmsCommunicationStatusOptions, baseInfo.emsCommunicationStatus) }}
|
||||||
</span>
|
</span>
|
||||||
</el-descriptions-item>
|
</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
@ -123,7 +123,7 @@
|
|||||||
<script>
|
<script>
|
||||||
import * as echarts from "echarts";
|
import * as echarts from "echarts";
|
||||||
import {getProjectDisplayData, getStackNameList} from '@/api/ems/dzjk'
|
import {getProjectDisplayData, getStackNameList} from '@/api/ems/dzjk'
|
||||||
import {getPointConfigCurve} from "@/api/ems/site";
|
import {getPointConfigCurve, getSingleMonitorWorkStatusEnumMappings} from "@/api/ems/site";
|
||||||
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
|
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
|
||||||
import intervalUpdate from "@/mixins/ems/intervalUpdate";
|
import intervalUpdate from "@/mixins/ems/intervalUpdate";
|
||||||
import PointTable from "@/views/ems/site/sblb/PointTable.vue";
|
import PointTable from "@/views/ems/site/sblb/PointTable.vue";
|
||||||
@ -137,6 +137,15 @@ export default {
|
|||||||
...mapState({
|
...mapState({
|
||||||
STACKWorkStatusOptions: state => state?.ems?.STACKWorkStatusOptions || {},
|
STACKWorkStatusOptions: state => state?.ems?.STACKWorkStatusOptions || {},
|
||||||
}),
|
}),
|
||||||
|
stackWorkStatusOptions() {
|
||||||
|
return this.getEnumOptions("STACK", "workStatus", this.STACKWorkStatusOptions || {});
|
||||||
|
},
|
||||||
|
stackPcsCommunicationStatusOptions() {
|
||||||
|
return this.getEnumOptions("STACK", "pcsCommunicationStatus", (this.$store.state.ems && this.$store.state.ems.communicationStatusOptions) || {});
|
||||||
|
},
|
||||||
|
stackEmsCommunicationStatusOptions() {
|
||||||
|
return this.getEnumOptions("STACK", "emsCommunicationStatus", (this.$store.state.ems && this.$store.state.ems.communicationStatusOptions) || {});
|
||||||
|
},
|
||||||
filteredBaseInfoList() {
|
filteredBaseInfoList() {
|
||||||
if (!this.selectedStackId) {
|
if (!this.selectedStackId) {
|
||||||
return this.baseInfoList || [];
|
return this.baseInfoList || [];
|
||||||
@ -149,6 +158,7 @@ export default {
|
|||||||
loading: false,
|
loading: false,
|
||||||
displayData: [],
|
displayData: [],
|
||||||
stackDeviceList: [],
|
stackDeviceList: [],
|
||||||
|
siteEnumOptionMap: {},
|
||||||
selectedStackId: "",
|
selectedStackId: "",
|
||||||
curveDialogVisible: false,
|
curveDialogVisible: false,
|
||||||
curveDialogTitle: "点位曲线",
|
curveDialogTitle: "点位曲线",
|
||||||
@ -191,9 +201,69 @@ export default {
|
|||||||
isPointLoading(value) {
|
isPointLoading(value) {
|
||||||
return this.loading && (value === undefined || value === null || value === "" || value === "-");
|
return this.loading && (value === undefined || value === null || value === "" || value === "-");
|
||||||
},
|
},
|
||||||
|
normalizeDictKey(value) {
|
||||||
|
const raw = String(value == null ? "" : value).trim();
|
||||||
|
if (!raw) return "";
|
||||||
|
if (/^-?\d+(\.0+)?$/.test(raw)) {
|
||||||
|
return String(parseInt(raw, 10));
|
||||||
|
}
|
||||||
|
return raw;
|
||||||
|
},
|
||||||
|
formatDictValue(options, value) {
|
||||||
|
const dict = (options && typeof options === "object") ? options : {};
|
||||||
|
const key = this.normalizeDictKey(value);
|
||||||
|
if (!key) return "-";
|
||||||
|
return dict[key] || key;
|
||||||
|
},
|
||||||
|
buildEnumScopeKey(deviceCategory, matchField) {
|
||||||
|
return `${String(deviceCategory || "").trim()}|${String(matchField || "").trim()}`;
|
||||||
|
},
|
||||||
|
buildSiteEnumOptionMap(mappings = []) {
|
||||||
|
return (mappings || []).reduce((acc, item) => {
|
||||||
|
const scopeKey = this.buildEnumScopeKey(item?.deviceCategory, item?.matchField);
|
||||||
|
const dataEnumCode = this.normalizeDictKey(item?.dataEnumCode);
|
||||||
|
const enumCode = this.normalizeDictKey(item?.enumCode);
|
||||||
|
const enumName = String(item?.enumName || "").trim();
|
||||||
|
const optionKey = dataEnumCode || enumCode;
|
||||||
|
if (!scopeKey || !optionKey || !enumName) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
if (!acc[scopeKey]) {
|
||||||
|
acc[scopeKey] = {};
|
||||||
|
}
|
||||||
|
acc[scopeKey][optionKey] = enumName;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
},
|
||||||
|
loadSiteEnumOptions() {
|
||||||
|
if (!this.siteId) {
|
||||||
|
this.siteEnumOptionMap = {};
|
||||||
|
return Promise.resolve({});
|
||||||
|
}
|
||||||
|
return getSingleMonitorWorkStatusEnumMappings(this.siteId).then(response => {
|
||||||
|
const optionMap = this.buildSiteEnumOptionMap(response?.data || []);
|
||||||
|
this.siteEnumOptionMap = optionMap;
|
||||||
|
return optionMap;
|
||||||
|
}).catch(() => {
|
||||||
|
this.siteEnumOptionMap = {};
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getEnumOptions(deviceCategory, matchField, fallback = {}) {
|
||||||
|
const scopeKey = this.buildEnumScopeKey(deviceCategory, matchField);
|
||||||
|
const siteOptions = this.siteEnumOptionMap[scopeKey];
|
||||||
|
if (siteOptions && Object.keys(siteOptions).length > 0) {
|
||||||
|
return siteOptions;
|
||||||
|
}
|
||||||
|
return fallback || {};
|
||||||
|
},
|
||||||
handleCardClass(item) {
|
handleCardClass(item) {
|
||||||
const {workStatus = ''} = item
|
const workStatus = this.normalizeDictKey((item && item.workStatus) || "");
|
||||||
return !Object.keys(this.STACKWorkStatusOptions).find(i => i === workStatus) ? "timing-card-container" : workStatus === '9' ? 'warning-card-container' : 'running-card-container'
|
const statusOptions = (this.stackWorkStatusOptions && typeof this.stackWorkStatusOptions === "object")
|
||||||
|
? this.stackWorkStatusOptions
|
||||||
|
: {};
|
||||||
|
const hasStatus = Object.prototype.hasOwnProperty.call(statusOptions, workStatus);
|
||||||
|
return !hasStatus ? "timing-card-container" : workStatus === '9' ? 'warning-card-container' : 'running-card-container';
|
||||||
},
|
},
|
||||||
|
|
||||||
// 查看设备电位表格
|
// 查看设备电位表格
|
||||||
@ -487,6 +557,7 @@ export default {
|
|||||||
Promise.all([
|
Promise.all([
|
||||||
getProjectDisplayData(this.siteId),
|
getProjectDisplayData(this.siteId),
|
||||||
this.getStackDeviceList(),
|
this.getStackDeviceList(),
|
||||||
|
this.loadSiteEnumOptions(),
|
||||||
]).then(([displayResponse]) => {
|
]).then(([displayResponse]) => {
|
||||||
this.displayData = displayResponse?.data || [];
|
this.displayData = displayResponse?.data || [];
|
||||||
this.buildBaseInfoList();
|
this.buildBaseInfoList();
|
||||||
|
|||||||
@ -64,7 +64,7 @@
|
|||||||
:class="{ 'field-disabled': !hasFieldPointId(pcsItem, 'workStatus') }"
|
:class="{ 'field-disabled': !hasFieldPointId(pcsItem, 'workStatus') }"
|
||||||
@click="handlePcsFieldClick(pcsItem, 'workStatus', '工作状态')"
|
@click="handlePcsFieldClick(pcsItem, 'workStatus', '工作状态')"
|
||||||
>
|
>
|
||||||
{{ formatDictValue((PCSWorkStatusOptions || {}), pcsItem.workStatus) }}
|
{{ formatDictValue(pcsWorkStatusOptions, pcsItem.workStatus) }}
|
||||||
</span>
|
</span>
|
||||||
</el-descriptions-item
|
</el-descriptions-item
|
||||||
>
|
>
|
||||||
@ -79,7 +79,7 @@
|
|||||||
:class="{ 'field-disabled': !hasFieldPointId(pcsItem, 'gridStatus') }"
|
:class="{ 'field-disabled': !hasFieldPointId(pcsItem, 'gridStatus') }"
|
||||||
@click="handlePcsFieldClick(pcsItem, 'gridStatus', '并网状态')"
|
@click="handlePcsFieldClick(pcsItem, 'gridStatus', '并网状态')"
|
||||||
>
|
>
|
||||||
{{ formatDictValue((($store.state.ems && $store.state.ems.gridStatusOptions) || {}), pcsItem.gridStatus) }}
|
{{ formatDictValue(pcsGridStatusOptions, pcsItem.gridStatus) }}
|
||||||
</span>
|
</span>
|
||||||
</el-descriptions-item
|
</el-descriptions-item
|
||||||
>
|
>
|
||||||
@ -96,7 +96,7 @@
|
|||||||
:class="{ 'field-disabled': !hasFieldPointId(pcsItem, 'deviceStatus') }"
|
:class="{ 'field-disabled': !hasFieldPointId(pcsItem, 'deviceStatus') }"
|
||||||
@click="handlePcsFieldClick(pcsItem, 'deviceStatus', '设备状态')"
|
@click="handlePcsFieldClick(pcsItem, 'deviceStatus', '设备状态')"
|
||||||
>
|
>
|
||||||
{{ formatDictValue((($store.state.ems && $store.state.ems.deviceStatusOptions) || {}), pcsItem.deviceStatus) }}
|
{{ formatDictValue(pcsDeviceStatusOptions, pcsItem.deviceStatus) }}
|
||||||
</span>
|
</span>
|
||||||
</el-descriptions-item
|
</el-descriptions-item
|
||||||
>
|
>
|
||||||
@ -111,7 +111,7 @@
|
|||||||
:class="{ 'field-disabled': !hasFieldPointId(pcsItem, 'controlMode') }"
|
:class="{ 'field-disabled': !hasFieldPointId(pcsItem, 'controlMode') }"
|
||||||
@click="handlePcsFieldClick(pcsItem, 'controlMode', '控制模式')"
|
@click="handlePcsFieldClick(pcsItem, 'controlMode', '控制模式')"
|
||||||
>
|
>
|
||||||
{{ formatDictValue((($store.state.ems && $store.state.ems.controlModeOptions) || {}), pcsItem.controlMode) }}
|
{{ formatDictValue(pcsControlModeOptions, pcsItem.controlMode) }}
|
||||||
</span>
|
</span>
|
||||||
</el-descriptions-item
|
</el-descriptions-item
|
||||||
>
|
>
|
||||||
@ -242,7 +242,7 @@ import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
|
|||||||
import {getPcsNameList, getProjectDisplayData} from "@/api/ems/dzjk";
|
import {getPcsNameList, getProjectDisplayData} from "@/api/ems/dzjk";
|
||||||
import intervalUpdate from "@/mixins/ems/intervalUpdate";
|
import intervalUpdate from "@/mixins/ems/intervalUpdate";
|
||||||
import {mapState} from "vuex";
|
import {mapState} from "vuex";
|
||||||
import {getPointConfigCurve} from "@/api/ems/site";
|
import {getPointConfigCurve, getSingleMonitorWorkStatusEnumMappings} from "@/api/ems/site";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "DzjkSbjkPcs",
|
name: "DzjkSbjkPcs",
|
||||||
@ -252,6 +252,18 @@ export default {
|
|||||||
...mapState({
|
...mapState({
|
||||||
PCSWorkStatusOptions: state => state?.ems?.PCSWorkStatusOptions || {},
|
PCSWorkStatusOptions: state => state?.ems?.PCSWorkStatusOptions || {},
|
||||||
}),
|
}),
|
||||||
|
pcsWorkStatusOptions() {
|
||||||
|
return this.getEnumOptions("PCS", "workStatus", this.PCSWorkStatusOptions || {});
|
||||||
|
},
|
||||||
|
pcsGridStatusOptions() {
|
||||||
|
return this.getEnumOptions("PCS", "gridStatus", (this.$store.state.ems && this.$store.state.ems.gridStatusOptions) || {});
|
||||||
|
},
|
||||||
|
pcsDeviceStatusOptions() {
|
||||||
|
return this.getEnumOptions("PCS", "deviceStatus", (this.$store.state.ems && this.$store.state.ems.deviceStatusOptions) || {});
|
||||||
|
},
|
||||||
|
pcsControlModeOptions() {
|
||||||
|
return this.getEnumOptions("PCS", "controlMode", (this.$store.state.ems && this.$store.state.ems.controlModeOptions) || {});
|
||||||
|
},
|
||||||
filteredPcsList() {
|
filteredPcsList() {
|
||||||
if (!this.selectedPcsId) {
|
if (!this.selectedPcsId) {
|
||||||
return this.pcsList || [];
|
return this.pcsList || [];
|
||||||
@ -264,6 +276,7 @@ export default {
|
|||||||
loading: false,
|
loading: false,
|
||||||
displayData: [],
|
displayData: [],
|
||||||
pcsDeviceList: [],
|
pcsDeviceList: [],
|
||||||
|
siteEnumOptionMap: {},
|
||||||
selectedPcsId: "",
|
selectedPcsId: "",
|
||||||
curveDialogVisible: false,
|
curveDialogVisible: false,
|
||||||
curveDialogTitle: "点位曲线",
|
curveDialogTitle: "点位曲线",
|
||||||
@ -388,10 +401,52 @@ export default {
|
|||||||
normalizeDeviceId(value) {
|
normalizeDeviceId(value) {
|
||||||
return String(value == null ? "" : value).trim().toUpperCase();
|
return String(value == null ? "" : value).trim().toUpperCase();
|
||||||
},
|
},
|
||||||
|
buildEnumScopeKey(deviceCategory, matchField) {
|
||||||
|
return `${String(deviceCategory || "").trim()}|${String(matchField || "").trim()}`;
|
||||||
|
},
|
||||||
|
buildSiteEnumOptionMap(mappings = []) {
|
||||||
|
return (mappings || []).reduce((acc, item) => {
|
||||||
|
const scopeKey = this.buildEnumScopeKey(item?.deviceCategory, item?.matchField);
|
||||||
|
const dataEnumCode = this.normalizeDictKey(item?.dataEnumCode);
|
||||||
|
const enumCode = this.normalizeDictKey(item?.enumCode);
|
||||||
|
const enumName = String(item?.enumName || "").trim();
|
||||||
|
const optionKey = dataEnumCode || enumCode;
|
||||||
|
if (!scopeKey || !optionKey || !enumName) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
if (!acc[scopeKey]) {
|
||||||
|
acc[scopeKey] = {};
|
||||||
|
}
|
||||||
|
acc[scopeKey][optionKey] = enumName;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
},
|
||||||
|
loadSiteEnumOptions() {
|
||||||
|
if (!this.siteId) {
|
||||||
|
this.siteEnumOptionMap = {};
|
||||||
|
return Promise.resolve({});
|
||||||
|
}
|
||||||
|
return getSingleMonitorWorkStatusEnumMappings(this.siteId).then(response => {
|
||||||
|
const optionMap = this.buildSiteEnumOptionMap(response?.data || []);
|
||||||
|
this.siteEnumOptionMap = optionMap;
|
||||||
|
return optionMap;
|
||||||
|
}).catch(() => {
|
||||||
|
this.siteEnumOptionMap = {};
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getEnumOptions(deviceCategory, matchField, fallback = {}) {
|
||||||
|
const scopeKey = this.buildEnumScopeKey(deviceCategory, matchField);
|
||||||
|
const siteOptions = this.siteEnumOptionMap[scopeKey];
|
||||||
|
if (siteOptions && Object.keys(siteOptions).length > 0) {
|
||||||
|
return siteOptions;
|
||||||
|
}
|
||||||
|
return fallback || {};
|
||||||
|
},
|
||||||
handleCardClass(item) {
|
handleCardClass(item) {
|
||||||
const workStatus = this.normalizeDictKey((item && item.workStatus) || "");
|
const workStatus = this.normalizeDictKey((item && item.workStatus) || "");
|
||||||
const statusOptions = (this.PCSWorkStatusOptions && typeof this.PCSWorkStatusOptions === 'object')
|
const statusOptions = (this.pcsWorkStatusOptions && typeof this.pcsWorkStatusOptions === 'object')
|
||||||
? this.PCSWorkStatusOptions
|
? this.pcsWorkStatusOptions
|
||||||
: {};
|
: {};
|
||||||
const hasStatus = Object.prototype.hasOwnProperty.call(statusOptions, workStatus);
|
const hasStatus = Object.prototype.hasOwnProperty.call(statusOptions, workStatus);
|
||||||
return workStatus === '1' || !hasStatus
|
return workStatus === '1' || !hasStatus
|
||||||
@ -651,6 +706,7 @@ export default {
|
|||||||
Promise.all([
|
Promise.all([
|
||||||
getProjectDisplayData(this.siteId),
|
getProjectDisplayData(this.siteId),
|
||||||
this.getPcsDeviceList(),
|
this.getPcsDeviceList(),
|
||||||
|
this.loadSiteEnumOptions(),
|
||||||
]).then(([displayResponse]) => {
|
]).then(([displayResponse]) => {
|
||||||
this.displayData = displayResponse?.data || [];
|
this.displayData = displayResponse?.data || [];
|
||||||
this.buildPcsList();
|
this.buildPcsList();
|
||||||
|
|||||||
@ -68,7 +68,7 @@ export default {
|
|||||||
.then((response) => {
|
.then((response) => {
|
||||||
const list = response?.data || [];
|
const list = response?.data || [];
|
||||||
return {
|
return {
|
||||||
name: row.fieldName || row.fieldCode || pointId,
|
name: (row.deviceName || "") + (row.fieldName || row.fieldCode || pointId),
|
||||||
data: list
|
data: list
|
||||||
.map((item) => [
|
.map((item) => [
|
||||||
this.parseToTimestamp(item.dataTime),
|
this.parseToTimestamp(item.dataTime),
|
||||||
|
|||||||
@ -41,32 +41,37 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
init(siteId,timeRange) {
|
init(siteId,timeRange) {
|
||||||
const [startTime='', endTime=''] = timeRange;
|
const [startTime='', endTime=''] = timeRange;
|
||||||
const row = (this.displayData || []).find(
|
const query = {
|
||||||
|
siteId,
|
||||||
|
rangeType: "custom",
|
||||||
|
startTime: this.normalizeDateTime(startTime, false),
|
||||||
|
endTime: this.normalizeDateTime(endTime, true)
|
||||||
|
};
|
||||||
|
const rows = (this.displayData || []).filter(
|
||||||
(item) =>
|
(item) =>
|
||||||
item &&
|
item &&
|
||||||
item.fieldCode === "SBJK_SSYX__curveBatteryAveSoc" &&
|
item.fieldCode === "SBJK_SSYX__curveBatteryAveSoc" &&
|
||||||
item.useFixedDisplay !== 1 &&
|
item.useFixedDisplay !== 1 &&
|
||||||
item.dataPoint
|
item.dataPoint
|
||||||
);
|
);
|
||||||
const pointId = String(row?.dataPoint || "").trim();
|
const tasks = rows.map((row) => {
|
||||||
if (!pointId) {
|
const pointId = String(row.dataPoint || "").trim();
|
||||||
this.setOption([]);
|
if(!pointId) return Promise.resolve(null);
|
||||||
return;
|
return getPointConfigCurve({
|
||||||
}
|
...query,
|
||||||
getPointConfigCurve({
|
pointId
|
||||||
siteId,
|
}).then((response) => {
|
||||||
pointId,
|
|
||||||
rangeType: "custom",
|
|
||||||
startTime: this.normalizeDateTime(startTime, false),
|
|
||||||
endTime: this.normalizeDateTime(endTime, true)
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
const list = response?.data || [];
|
const list = response?.data || [];
|
||||||
this.setOption(
|
return {
|
||||||
list
|
name: (row.deviceName || "") + (row.fieldName || row.fieldCode || pointId),
|
||||||
|
data: list
|
||||||
.map((item) => [this.parseToTimestamp(item.dataTime), Number(item.pointValue)])
|
.map((item) => [this.parseToTimestamp(item.dataTime), Number(item.pointValue)])
|
||||||
.filter((item) => item[0] && !Number.isNaN(item[1]))
|
.filter((item) => item[0] && !Number.isNaN(item[1]))
|
||||||
);
|
};
|
||||||
|
}).catch(() => null);
|
||||||
|
});
|
||||||
|
Promise.all(tasks).then((series) => {
|
||||||
|
this.setOption((series || []).filter(Boolean));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
normalizeDateTime(value, endOfDay) {
|
normalizeDateTime(value, endOfDay) {
|
||||||
@ -80,7 +85,7 @@ export default {
|
|||||||
const t = new Date(value).getTime();
|
const t = new Date(value).getTime();
|
||||||
return Number.isNaN(t) ? null : t;
|
return Number.isNaN(t) ? null : t;
|
||||||
},
|
},
|
||||||
setOption(data = []) {
|
setOption(seriesData = []) {
|
||||||
this.chart && this.chart.setOption({
|
this.chart && this.chart.setOption({
|
||||||
legend: {
|
legend: {
|
||||||
left: "center",
|
left: "center",
|
||||||
@ -119,18 +124,16 @@ export default {
|
|||||||
end: 100,
|
end: 100,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
series: [
|
series: seriesData.map(item => ({
|
||||||
{
|
|
||||||
type: "line",
|
type: "line",
|
||||||
name: `平均SOC`,
|
name: item.name,
|
||||||
showSymbol: false,
|
showSymbol: false,
|
||||||
smooth: true,
|
smooth: true,
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
opacity: 0.35
|
opacity: 0.35
|
||||||
},
|
},
|
||||||
data,
|
data: item.data
|
||||||
},
|
})),
|
||||||
],
|
|
||||||
},true);
|
},true);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -42,32 +42,37 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
init(siteId,timeRange) {
|
init(siteId,timeRange) {
|
||||||
const [startTime='', endTime=''] = timeRange;
|
const [startTime='', endTime=''] = timeRange;
|
||||||
const row = (this.displayData || []).find(
|
const query = {
|
||||||
|
siteId,
|
||||||
|
rangeType: "custom",
|
||||||
|
startTime: this.normalizeDateTime(startTime, false),
|
||||||
|
endTime: this.normalizeDateTime(endTime, true)
|
||||||
|
};
|
||||||
|
const rows = (this.displayData || []).filter(
|
||||||
(item) =>
|
(item) =>
|
||||||
item &&
|
item &&
|
||||||
item.fieldCode === "SBJK_SSYX__curveBatteryAveTemp" &&
|
item.fieldCode === "SBJK_SSYX__curveBatteryAveTemp" &&
|
||||||
item.useFixedDisplay !== 1 &&
|
item.useFixedDisplay !== 1 &&
|
||||||
item.dataPoint
|
item.dataPoint
|
||||||
);
|
);
|
||||||
const pointId = String(row?.dataPoint || "").trim();
|
const tasks = rows.map((row) => {
|
||||||
if (!pointId) {
|
const pointId = String(row.dataPoint || "").trim();
|
||||||
this.setOption([]);
|
if(!pointId) return Promise.resolve(null);
|
||||||
return;
|
return getPointConfigCurve({
|
||||||
}
|
...query,
|
||||||
getPointConfigCurve({
|
pointId
|
||||||
siteId,
|
}).then((response) => {
|
||||||
pointId,
|
|
||||||
rangeType: "custom",
|
|
||||||
startTime: this.normalizeDateTime(startTime, false),
|
|
||||||
endTime: this.normalizeDateTime(endTime, true)
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
const list = response?.data || [];
|
const list = response?.data || [];
|
||||||
this.setOption(
|
return {
|
||||||
list
|
name: (row.deviceName || "") + (row.fieldName || row.fieldCode || pointId),
|
||||||
|
data: list
|
||||||
.map((item) => [this.parseToTimestamp(item.dataTime), Number(item.pointValue)])
|
.map((item) => [this.parseToTimestamp(item.dataTime), Number(item.pointValue)])
|
||||||
.filter((item) => item[0] && !Number.isNaN(item[1]))
|
.filter((item) => item[0] && !Number.isNaN(item[1]))
|
||||||
);
|
};
|
||||||
|
}).catch(() => null);
|
||||||
|
});
|
||||||
|
Promise.all(tasks).then((series) => {
|
||||||
|
this.setOption((series || []).filter(Boolean));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
normalizeDateTime(value, endOfDay) {
|
normalizeDateTime(value, endOfDay) {
|
||||||
@ -81,7 +86,7 @@ export default {
|
|||||||
const t = new Date(value).getTime();
|
const t = new Date(value).getTime();
|
||||||
return Number.isNaN(t) ? null : t;
|
return Number.isNaN(t) ? null : t;
|
||||||
},
|
},
|
||||||
setOption(data = []) {
|
setOption(seriesData = []) {
|
||||||
this.chart && this.chart.setOption({
|
this.chart && this.chart.setOption({
|
||||||
legend: {
|
legend: {
|
||||||
left: "center",
|
left: "center",
|
||||||
@ -120,18 +125,16 @@ export default {
|
|||||||
end: 100,
|
end: 100,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
series: [
|
series: seriesData.map(item => ({
|
||||||
{
|
|
||||||
type: "line",
|
type: "line",
|
||||||
name: `电池平均温度`,
|
name: item.name,
|
||||||
showSymbol: false,
|
showSymbol: false,
|
||||||
smooth: true,
|
smooth: true,
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
opacity: 0.35
|
opacity: 0.35
|
||||||
},
|
},
|
||||||
data,
|
data: item.data
|
||||||
},
|
})),
|
||||||
],
|
|
||||||
},true);
|
},true);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -27,7 +27,6 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
chart: null,
|
chart: null,
|
||||||
seriesName: "PCS最高温度"
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
@ -43,33 +42,37 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
init(siteId,timeRange) {
|
init(siteId,timeRange) {
|
||||||
const [startTime='', endTime=''] = timeRange;
|
const [startTime='', endTime=''] = timeRange;
|
||||||
const row = (this.displayData || []).find(
|
const query = {
|
||||||
|
siteId,
|
||||||
|
rangeType: "custom",
|
||||||
|
startTime: this.normalizeDateTime(startTime, false),
|
||||||
|
endTime: this.normalizeDateTime(endTime, true)
|
||||||
|
};
|
||||||
|
const rows = (this.displayData || []).filter(
|
||||||
(item) =>
|
(item) =>
|
||||||
item &&
|
item &&
|
||||||
item.fieldCode === "SBJK_SSYX__curvePcsMaxTemp" &&
|
item.fieldCode === "SBJK_SSYX__curvePcsMaxTemp" &&
|
||||||
item.useFixedDisplay !== 1 &&
|
item.useFixedDisplay !== 1 &&
|
||||||
item.dataPoint
|
item.dataPoint
|
||||||
);
|
);
|
||||||
const pointId = String(row?.dataPoint || "").trim();
|
const tasks = rows.map((row) => {
|
||||||
this.seriesName = row?.fieldName || "PCS最高温度";
|
const pointId = String(row.dataPoint || "").trim();
|
||||||
if (!pointId) {
|
if(!pointId) return Promise.resolve(null);
|
||||||
this.setOption([]);
|
return getPointConfigCurve({
|
||||||
return;
|
...query,
|
||||||
}
|
pointId
|
||||||
getPointConfigCurve({
|
}).then((response) => {
|
||||||
siteId,
|
|
||||||
pointId,
|
|
||||||
rangeType: "custom",
|
|
||||||
startTime: this.normalizeDateTime(startTime, false),
|
|
||||||
endTime: this.normalizeDateTime(endTime, true)
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
const list = response?.data || [];
|
const list = response?.data || [];
|
||||||
this.setOption(
|
return {
|
||||||
list
|
name: (row.deviceName || "") + (row.fieldName || row.fieldCode || pointId),
|
||||||
|
data: list
|
||||||
.map((item) => [this.parseToTimestamp(item.dataTime), Number(item.pointValue)])
|
.map((item) => [this.parseToTimestamp(item.dataTime), Number(item.pointValue)])
|
||||||
.filter((item) => item[0] && !Number.isNaN(item[1]))
|
.filter((item) => item[0] && !Number.isNaN(item[1]))
|
||||||
);
|
};
|
||||||
|
}).catch(() => null);
|
||||||
|
});
|
||||||
|
Promise.all(tasks).then((series) => {
|
||||||
|
this.setOption((series || []).filter(Boolean));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
normalizeDateTime(value, endOfDay) {
|
normalizeDateTime(value, endOfDay) {
|
||||||
@ -83,7 +86,7 @@ export default {
|
|||||||
const t = new Date(value).getTime();
|
const t = new Date(value).getTime();
|
||||||
return Number.isNaN(t) ? null : t;
|
return Number.isNaN(t) ? null : t;
|
||||||
},
|
},
|
||||||
setOption(data = []) {
|
setOption(seriesData = []) {
|
||||||
this.chart && this.chart.setOption({
|
this.chart && this.chart.setOption({
|
||||||
legend: {
|
legend: {
|
||||||
left: "center",
|
left: "center",
|
||||||
@ -122,18 +125,16 @@ export default {
|
|||||||
end: 100,
|
end: 100,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
series: [
|
series: seriesData.map(item => ({
|
||||||
{
|
|
||||||
type: "line",
|
type: "line",
|
||||||
name: this.seriesName,
|
name: item.name,
|
||||||
showSymbol: false,
|
showSymbol: false,
|
||||||
smooth: true,
|
smooth: true,
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
opacity: 0.35
|
opacity: 0.35
|
||||||
},
|
},
|
||||||
data
|
data: item.data
|
||||||
}
|
})),
|
||||||
],
|
|
||||||
},true);
|
},true);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="width:100%" v-loading="loading">
|
<div style="width:100%" v-loading="loading">
|
||||||
<!-- 搜索栏-->
|
|
||||||
<el-form :inline="true" class="select-container">
|
<el-form :inline="true" class="select-container">
|
||||||
<el-form-item label="时间选择">
|
<el-form-item label="时间选择">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
@ -25,84 +24,47 @@
|
|||||||
<el-button type="primary" @click="exportTable" native-type="button">导出</el-button>
|
<el-button type="primary" @click="exportTable" native-type="button">导出</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<!--表格-->
|
|
||||||
<el-table
|
<el-table
|
||||||
class="common-table"
|
class="common-table"
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
stripe
|
stripe
|
||||||
style="width: 100%;margin-top:25px;">
|
style="width: 100%; margin-top: 25px;"
|
||||||
<!-- 汇总列-->
|
>
|
||||||
<el-table-column label="汇总">
|
<el-table-column label="汇总">
|
||||||
<el-table-column
|
<el-table-column prop="dataTime" label="日期" width="120"></el-table-column>
|
||||||
prop="dataTime"
|
|
||||||
label="日期"
|
|
||||||
width="120">
|
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table-column>
|
|
||||||
<!--充电量列-->
|
|
||||||
<el-table-column label="充电量" align="center">
|
<el-table-column label="充电量" align="center">
|
||||||
<el-table-column
|
<el-table-column align="center" prop="activePeakKwh" label="尖"></el-table-column>
|
||||||
align="center"
|
<el-table-column align="center" prop="activeHighKwh" label="峰"></el-table-column>
|
||||||
prop="activePeakKwh"
|
<el-table-column align="center" prop="activeFlatKwh" label="平"></el-table-column>
|
||||||
label="尖">
|
<el-table-column align="center" prop="activeValleyKwh" label="谷"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="activeTotalKwh" label="总"></el-table-column>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="activeHighKwh"
|
|
||||||
label="峰">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="activeFlatKwh"
|
|
||||||
label="平">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="activeValleyKwh"
|
|
||||||
label="谷">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="activeTotalKwh"
|
|
||||||
label="总">
|
|
||||||
</el-table-column>
|
|
||||||
</el-table-column>
|
|
||||||
<!--充电量列-->
|
|
||||||
<el-table-column label="放电量" align="center">
|
<el-table-column label="放电量" align="center">
|
||||||
<el-table-column
|
<el-table-column align="center" prop="reActivePeakKwh" label="尖"></el-table-column>
|
||||||
align="center"
|
<el-table-column align="center" prop="reActiveHighKwh" label="峰"></el-table-column>
|
||||||
prop="reActivePeakKwh"
|
<el-table-column align="center" prop="reActiveFlatKwh" label="平"></el-table-column>
|
||||||
label="尖">
|
<el-table-column align="center" prop="reActiveValleyKwh" label="谷"></el-table-column>
|
||||||
|
<el-table-column align="center" prop="reActiveTotalKwh" label="总"></el-table-column>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="reActiveHighKwh"
|
|
||||||
label="峰">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="reActiveFlatKwh"
|
|
||||||
label="平">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="reActiveValleyKwh"
|
|
||||||
label="谷">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
align="center"
|
|
||||||
prop="reActiveTotalKwh"
|
|
||||||
label="总">
|
|
||||||
</el-table-column>
|
|
||||||
</el-table-column>
|
|
||||||
<!-- 效率-->
|
|
||||||
<el-table-column label="效率(%)" align="center">
|
<el-table-column label="效率(%)" align="center">
|
||||||
<el-table-column
|
<el-table-column align="center" prop="effect"></el-table-column>
|
||||||
align="center"
|
|
||||||
prop="effect">
|
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
|
||||||
|
<el-table-column label="备注" align="center" fixed="right" min-width="260">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div class="remark-cell">
|
||||||
|
<span class="remark-text">{{ scope.row.remark || "-" }}</span>
|
||||||
|
<el-button type="text" @click="editRemark(scope.row)">编辑</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<el-pagination
|
<el-pagination
|
||||||
v-show="tableData.length > 0"
|
v-show="tableData.length > 0"
|
||||||
background
|
background
|
||||||
@ -119,14 +81,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
|
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
|
||||||
import {getAmmeterData} from '@/api/ems/dzjk'
|
import { batchGetBizRemark, getAmmeterData, saveBizRemark } from "@/api/ems/dzjk";
|
||||||
import { formatDate } from "@/filters/ems";
|
import { formatDate } from "@/filters/ems";
|
||||||
|
|
||||||
|
const BIZ_TYPE = "stats_report";
|
||||||
|
const REPORT_KEY = "DBBB";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DzjkTjbbDbbb',
|
name: "DzjkTjbbDbbb",
|
||||||
mixins: [getQuerySiteId],
|
mixins: [getQuerySiteId],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -136,81 +100,141 @@ export default {
|
|||||||
return time.getTime() > Date.now();
|
return time.getTime() > Date.now();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultDateRange: [],//默认展示的时间
|
defaultDateRange: [],
|
||||||
dateRange: [],
|
dateRange: [],
|
||||||
tableData: [],
|
tableData: [],
|
||||||
pageSize: 10,//分页栏当前每个数据总数
|
pageSize: 10,
|
||||||
pageNum: 1,//分页栏当前页数
|
pageNum: 1,
|
||||||
totalSize: 0,//table表格数据总数
|
totalSize: 0,
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 导出表格
|
buildRemarkKey(dataTime) {
|
||||||
|
return `${this.siteId}_${dataTime || ""}`;
|
||||||
|
},
|
||||||
|
loadRemarks(rows) {
|
||||||
|
if (!rows.length) return Promise.resolve({});
|
||||||
|
return batchGetBizRemark({
|
||||||
|
bizType: BIZ_TYPE,
|
||||||
|
bizKey1: REPORT_KEY,
|
||||||
|
bizKey2List: rows.map(row => this.buildRemarkKey(row.dataTime)),
|
||||||
|
}).then(response => response?.data || {});
|
||||||
|
},
|
||||||
|
applyRemarks(rows, remarkMap) {
|
||||||
|
rows.forEach(row => {
|
||||||
|
this.$set(row, "remark", remarkMap[this.buildRemarkKey(row.dataTime)] || "");
|
||||||
|
});
|
||||||
|
},
|
||||||
exportTable() {
|
exportTable() {
|
||||||
if (!this.dateRange?.length) return
|
if (!this.dateRange?.length) return;
|
||||||
const [startTime, endTime] = this.dateRange
|
const [startTime, endTime] = this.dateRange;
|
||||||
this.download('ems/statsReport/exportAmmeterDataFromDaily', {
|
this.download(
|
||||||
|
"ems/statsReport/exportAmmeterDataFromDaily",
|
||||||
|
{
|
||||||
siteId: this.siteId,
|
siteId: this.siteId,
|
||||||
startTime,
|
startTime,
|
||||||
endTime,
|
endTime,
|
||||||
}, `电表报表_${startTime}-${endTime}.xlsx`)
|
|
||||||
},
|
},
|
||||||
// 搜索
|
`电表报表_${startTime}-${endTime}.xlsx`
|
||||||
|
);
|
||||||
|
},
|
||||||
onSearch() {
|
onSearch() {
|
||||||
this.pageNum = 1//每次搜索从1开始搜索
|
this.pageNum = 1;
|
||||||
this.getData()
|
this.getData();
|
||||||
},
|
},
|
||||||
// 重置
|
|
||||||
onReset() {
|
onReset() {
|
||||||
this.dateRange = this.defaultDateRange
|
this.dateRange = this.defaultDateRange;
|
||||||
this.pageNum = 1//每次搜索从1开始搜索
|
this.pageNum = 1;
|
||||||
this.getData()
|
this.getData();
|
||||||
},
|
},
|
||||||
// 分页
|
|
||||||
handleSizeChange(val) {
|
handleSizeChange(val) {
|
||||||
this.pageSize = val;
|
this.pageSize = val;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.getData()
|
this.getData();
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
handleCurrentChange(val) {
|
handleCurrentChange(val) {
|
||||||
this.pageNum = val
|
this.pageNum = val;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.getData()
|
this.getData();
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
// 获取数据
|
editRemark(row) {
|
||||||
getData() {
|
this.$prompt("请输入备注", "编辑备注", {
|
||||||
this.loading = true
|
inputValue: row.remark || "",
|
||||||
const {siteId, pageNum, pageSize} = this
|
inputType: "textarea",
|
||||||
const [startTime = '', endTime = ''] = (this.dateRange || [])
|
inputPlaceholder: "可输入该日报表备注",
|
||||||
getAmmeterData({siteId: siteId, startTime, endTime, pageSize, pageNum}).then(response => {
|
confirmButtonText: "保存",
|
||||||
this.tableData = response?.rows || [];
|
cancelButtonText: "取消",
|
||||||
this.totalSize = response?.total || 0
|
|
||||||
}).finally(() => {
|
|
||||||
this.loading = false
|
|
||||||
})
|
})
|
||||||
|
.then(({ value }) => {
|
||||||
|
return saveBizRemark({
|
||||||
|
bizType: BIZ_TYPE,
|
||||||
|
bizKey1: REPORT_KEY,
|
||||||
|
bizKey2: this.buildRemarkKey(row.dataTime),
|
||||||
|
remark: value || "",
|
||||||
|
}).then(() => {
|
||||||
|
this.$set(row, "remark", value || "");
|
||||||
|
this.$message.success("备注保存成功");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
},
|
||||||
|
getData() {
|
||||||
|
this.loading = true;
|
||||||
|
const { siteId, pageNum, pageSize } = this;
|
||||||
|
const [startTime = "", endTime = ""] = this.dateRange || [];
|
||||||
|
getAmmeterData({ siteId, startTime, endTime, pageSize, pageNum })
|
||||||
|
.then(response => {
|
||||||
|
const rows = response?.rows || [];
|
||||||
|
this.tableData = rows;
|
||||||
|
this.totalSize = response?.total || 0;
|
||||||
|
return this.loadRemarks(rows);
|
||||||
|
})
|
||||||
|
.then(remarkMap => {
|
||||||
|
this.applyRemarks(this.tableData, remarkMap || {});
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
init() {
|
init() {
|
||||||
this.dateRange = []
|
this.dateRange = [];
|
||||||
this.tableData = []
|
this.tableData = [];
|
||||||
this.totalSize = 0
|
this.totalSize = 0;
|
||||||
this.pageSize = 10
|
this.pageSize = 10;
|
||||||
this.pageNum = 1
|
this.pageNum = 1;
|
||||||
let now = new Date(), lastDay = now.getTime(), firstDay = new Date(now.setDate(1)).getTime();
|
const now = new Date();
|
||||||
|
const lastDay = now.getTime();
|
||||||
|
const firstDay = new Date(new Date().setDate(1)).getTime();
|
||||||
this.defaultDateRange = [formatDate(firstDay), formatDate(lastDay)];
|
this.defaultDateRange = [formatDate(firstDay), formatDate(lastDay)];
|
||||||
this.dateRange = [formatDate(firstDay), formatDate(lastDay)];
|
this.dateRange = [formatDate(firstDay), formatDate(lastDay)];
|
||||||
this.getData()
|
this.getData();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
::v-deep {
|
::v-deep {
|
||||||
.common-table.el-table .el-table__header-wrapper th, .common-table.el-table .el-table__fixed-header-wrapper th {
|
.common-table.el-table .el-table__header-wrapper th,
|
||||||
|
.common-table.el-table .el-table__fixed-header-wrapper th {
|
||||||
border-bottom: 1px solid #dfe6ec;
|
border-bottom: 1px solid #dfe6ec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.remark-cell {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remark-text {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -178,6 +178,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
type: "line",
|
type: "line",
|
||||||
smooth: true,
|
smooth: true,
|
||||||
|
connectNulls: true,
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
opacity: 0.7,
|
opacity: 0.7,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -103,11 +103,11 @@ export default {
|
|||||||
dataZoom: [
|
dataZoom: [
|
||||||
{
|
{
|
||||||
type: "inside",
|
type: "inside",
|
||||||
start: 0,
|
start: data.length > 500 ? 90 : 0,
|
||||||
end: 100,
|
end: 100,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
start: 0,
|
start: data.length > 500 ? 90 : 0,
|
||||||
end: 100,
|
end: 100,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -115,6 +115,7 @@ export default {
|
|||||||
{
|
{
|
||||||
type: "line",
|
type: "line",
|
||||||
smooth: true,
|
smooth: true,
|
||||||
|
connectNulls: true,
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
opacity: 0.7,
|
opacity: 0.7,
|
||||||
},
|
},
|
||||||
@ -122,6 +123,7 @@ export default {
|
|||||||
{
|
{
|
||||||
type: "line",
|
type: "line",
|
||||||
smooth: true,
|
smooth: true,
|
||||||
|
connectNulls: true,
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
opacity: 0.7,
|
opacity: 0.7,
|
||||||
},
|
},
|
||||||
@ -129,6 +131,7 @@ export default {
|
|||||||
{
|
{
|
||||||
type: "line",
|
type: "line",
|
||||||
smooth: true,
|
smooth: true,
|
||||||
|
connectNulls: true,
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
opacity: 0.7,
|
opacity: 0.7,
|
||||||
},
|
},
|
||||||
@ -136,6 +139,7 @@ export default {
|
|||||||
{
|
{
|
||||||
type: "line",
|
type: "line",
|
||||||
smooth: true,
|
smooth: true,
|
||||||
|
connectNulls: true,
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
opacity: 0.7,
|
opacity: 0.7,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -194,6 +194,7 @@ export default {
|
|||||||
return {
|
return {
|
||||||
type: "line",
|
type: "line",
|
||||||
smooth: true,
|
smooth: true,
|
||||||
|
connectNulls: true,
|
||||||
areaStyle: {
|
areaStyle: {
|
||||||
opacity: 0.7,
|
opacity: 0.7,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="width:100%" v-loading="loading">
|
<div style="width:100%" v-loading="loading">
|
||||||
<!-- 搜索栏-->
|
|
||||||
<el-form :inline="true" class="select-container">
|
<el-form :inline="true" class="select-container">
|
||||||
<el-form-item label="时间选择">
|
<el-form-item label="时间选择">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
@ -25,97 +24,51 @@
|
|||||||
<el-button type="primary" @click="exportTable" native-type="button">导出</el-button>
|
<el-button type="primary" @click="exportTable" native-type="button">导出</el-button>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-form>
|
</el-form>
|
||||||
<!--表格-->
|
|
||||||
<el-table
|
<el-table
|
||||||
class="common-table"
|
class="common-table"
|
||||||
:data="tableData"
|
:data="tableData"
|
||||||
|
:summary-method="getSummaries"
|
||||||
show-summary
|
show-summary
|
||||||
stripe
|
stripe
|
||||||
style="width: 100%;margin-top:25px;">
|
style="width: 100%; margin-top: 25px;"
|
||||||
<!-- 汇总列-->
|
>
|
||||||
<el-table-column label="汇总" min-width="100px" align="center">
|
<el-table-column label="汇总" min-width="100px" align="center">
|
||||||
<el-table-column
|
<el-table-column prop="dataTime" label="日期" min-width="100px" align="center"></el-table-column>
|
||||||
prop="dataTime"
|
<el-table-column prop="dayType" label="日期类型" min-width="100px" align="center"></el-table-column>
|
||||||
label="日期"
|
<el-table-column prop="weatherDesc" label="天气情况" min-width="180px" align="center"></el-table-column>
|
||||||
min-width="100px" align="center">
|
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column
|
|
||||||
prop="dayType"
|
|
||||||
label="日期类型"
|
|
||||||
min-width="100px" align="center">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
prop="weatherDesc"
|
|
||||||
label="天气情况"
|
|
||||||
min-width="180px"
|
|
||||||
align="center">
|
|
||||||
</el-table-column>
|
|
||||||
</el-table-column>
|
|
||||||
<!--充电量列-->
|
|
||||||
<el-table-column label="充电价格" align="center">
|
<el-table-column label="充电价格" align="center">
|
||||||
<el-table-column
|
<el-table-column align="center" prop="activePeakPrice" label="尖"></el-table-column>
|
||||||
align="center"
|
<el-table-column align="center" prop="activeHighPrice" label="峰"></el-table-column>
|
||||||
prop="activePeakPrice"
|
<el-table-column align="center" prop="activeFlatPrice" label="平"></el-table-column>
|
||||||
label="尖">
|
<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>
|
||||||
<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 label="放电价格" align="center">
|
||||||
<el-table-column
|
<el-table-column align="center" prop="reActivePeakPrice" label="尖"></el-table-column>
|
||||||
align="center"
|
<el-table-column align="center" prop="reActiveHighPrice" label="峰"></el-table-column>
|
||||||
prop="reActivePeakPrice"
|
<el-table-column align="center" prop="reActiveFlatPrice" label="平"></el-table-column>
|
||||||
label="尖">
|
<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>
|
||||||
<el-table-column
|
|
||||||
align="center"
|
<el-table-column label="" align="center">
|
||||||
prop="reActiveHighPrice"
|
<el-table-column prop="actualRevenue" label="实际收益" align="center"></el-table-column>
|
||||||
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-column label="备注" align="center" fixed="right" min-width="260">
|
||||||
|
<template slot-scope="scope">
|
||||||
|
<div class="remark-cell">
|
||||||
|
<span class="remark-text">{{ scope.row.remark || "-" }}</span>
|
||||||
|
<el-button type="text" @click="editRemark(scope.row)">编辑</el-button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
|
|
||||||
<el-pagination
|
<el-pagination
|
||||||
v-show="tableData.length > 0"
|
v-show="tableData.length > 0"
|
||||||
background
|
background
|
||||||
@ -132,14 +85,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
|
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
|
||||||
import {getAmmeterRevenueData} from '@/api/ems/dzjk'
|
import { batchGetBizRemark, getAmmeterRevenueData, saveBizRemark } from "@/api/ems/dzjk";
|
||||||
import { formatDate } from "@/filters/ems";
|
import { formatDate } from "@/filters/ems";
|
||||||
|
|
||||||
|
const BIZ_TYPE = "stats_report";
|
||||||
|
const REPORT_KEY = "SYBB";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'DzjkTjbbSybb',
|
name: "DzjkTjbbSybb",
|
||||||
mixins: [getQuerySiteId],
|
mixins: [getQuerySiteId],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
@ -149,81 +104,189 @@ export default {
|
|||||||
return time.getTime() > Date.now();
|
return time.getTime() > Date.now();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
defaultDateRange: [],//默认展示的时间
|
defaultDateRange: [],
|
||||||
dateRange: [],
|
dateRange: [],
|
||||||
tableData: [],
|
tableData: [],
|
||||||
pageSize: 10,//分页栏当前每个数据总数
|
summaryTotals: {},
|
||||||
pageNum: 1,//分页栏当前页数
|
pageSize: 10,
|
||||||
totalSize: 0,//table表格数据总数
|
pageNum: 1,
|
||||||
}
|
totalSize: 0,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 导出表格
|
buildRemarkKey(dataTime) {
|
||||||
|
return `${this.siteId}_${dataTime || ""}`;
|
||||||
|
},
|
||||||
|
loadRemarks(rows) {
|
||||||
|
if (!rows.length) return Promise.resolve({});
|
||||||
|
return batchGetBizRemark({
|
||||||
|
bizType: BIZ_TYPE,
|
||||||
|
bizKey1: REPORT_KEY,
|
||||||
|
bizKey2List: rows.map(row => this.buildRemarkKey(row.dataTime)),
|
||||||
|
}).then(response => response?.data || {});
|
||||||
|
},
|
||||||
|
applyRemarks(rows, remarkMap) {
|
||||||
|
rows.forEach(row => {
|
||||||
|
this.$set(row, "remark", remarkMap[this.buildRemarkKey(row.dataTime)] || "");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
toScaledInt(value) {
|
||||||
|
const num = Number(value);
|
||||||
|
return Number.isFinite(num) ? Math.round(num * 1000) : 0;
|
||||||
|
},
|
||||||
|
sumRowsByProp(rows, prop) {
|
||||||
|
const total = (rows || []).reduce((sum, row) => sum + this.toScaledInt(row?.[prop]), 0);
|
||||||
|
return total / 1000;
|
||||||
|
},
|
||||||
|
formatSummaryNumber(value) {
|
||||||
|
const num = Number(value);
|
||||||
|
if (!Number.isFinite(num)) return "";
|
||||||
|
return num.toFixed(3).replace(/\.?0+$/, "");
|
||||||
|
},
|
||||||
|
buildSummaryTotals(rows) {
|
||||||
|
const numericProps = [
|
||||||
|
"activePeakPrice",
|
||||||
|
"activeHighPrice",
|
||||||
|
"activeFlatPrice",
|
||||||
|
"activeValleyPrice",
|
||||||
|
"activeTotalPrice",
|
||||||
|
"reActivePeakPrice",
|
||||||
|
"reActiveHighPrice",
|
||||||
|
"reActiveFlatPrice",
|
||||||
|
"reActiveValleyPrice",
|
||||||
|
"reActiveTotalPrice",
|
||||||
|
"actualRevenue",
|
||||||
|
];
|
||||||
|
return numericProps.reduce((result, prop) => {
|
||||||
|
result[prop] = this.sumRowsByProp(rows, prop);
|
||||||
|
return result;
|
||||||
|
}, {});
|
||||||
|
},
|
||||||
|
getSummaries({ columns, data }) {
|
||||||
|
return columns.map((column, index) => {
|
||||||
|
if (index === 0) return "合计";
|
||||||
|
const prop = column.property;
|
||||||
|
if (!prop) return "";
|
||||||
|
if (Object.prototype.hasOwnProperty.call(this.summaryTotals, prop)) {
|
||||||
|
return this.formatSummaryNumber(this.summaryTotals[prop]);
|
||||||
|
}
|
||||||
|
const hasNumericValue = (data || []).some(item => Number.isFinite(Number(item?.[prop])));
|
||||||
|
return hasNumericValue ? this.formatSummaryNumber(this.sumRowsByProp(data, prop)) : "";
|
||||||
|
});
|
||||||
|
},
|
||||||
exportTable() {
|
exportTable() {
|
||||||
if (!this.dateRange?.length) return
|
if (!this.dateRange?.length) return;
|
||||||
const [startTime, endTime] = this.dateRange
|
const [startTime, endTime] = this.dateRange;
|
||||||
this.download('ems/statsReport/exportAmmeterRevenueData', {
|
this.download(
|
||||||
|
"ems/statsReport/exportAmmeterRevenueData",
|
||||||
|
{
|
||||||
siteId: this.siteId,
|
siteId: this.siteId,
|
||||||
startTime,
|
startTime,
|
||||||
endTime,
|
endTime,
|
||||||
}, `收益报表_${startTime}-${endTime}.xlsx`)
|
|
||||||
},
|
},
|
||||||
// 搜索
|
`收益报表_${startTime}-${endTime}.xlsx`
|
||||||
|
);
|
||||||
|
},
|
||||||
onSearch() {
|
onSearch() {
|
||||||
this.pageNum = 1//每次搜索从1开始搜索
|
this.pageNum = 1;
|
||||||
this.getData()
|
this.getData();
|
||||||
},
|
},
|
||||||
// 重置
|
|
||||||
onReset() {
|
onReset() {
|
||||||
this.dateRange = this.defaultDateRange
|
this.dateRange = this.defaultDateRange;
|
||||||
this.pageNum = 1//每次搜索从1开始搜索
|
this.pageNum = 1;
|
||||||
this.getData()
|
this.getData();
|
||||||
},
|
},
|
||||||
// 分页
|
|
||||||
handleSizeChange(val) {
|
handleSizeChange(val) {
|
||||||
this.pageSize = val;
|
this.pageSize = val;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.getData()
|
this.getData();
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
handleCurrentChange(val) {
|
handleCurrentChange(val) {
|
||||||
this.pageNum = val
|
this.pageNum = val;
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.getData()
|
this.getData();
|
||||||
})
|
});
|
||||||
},
|
},
|
||||||
// 获取数据
|
editRemark(row) {
|
||||||
getData() {
|
this.$prompt("请输入备注", "编辑备注", {
|
||||||
this.loading = true
|
inputValue: row.remark || "",
|
||||||
const {siteId, pageNum, pageSize} = this
|
inputType: "textarea",
|
||||||
const [startTime = '', endTime = ''] = (this.dateRange || [])
|
inputPlaceholder: "可输入该日报表备注",
|
||||||
getAmmeterRevenueData({siteId: siteId, startTime, endTime, pageSize, pageNum}).then(response => {
|
confirmButtonText: "保存",
|
||||||
const rows = response?.rows || [];
|
cancelButtonText: "取消",
|
||||||
this.totalSize = response?.total || 0
|
|
||||||
this.tableData = rows
|
|
||||||
}).finally(() => {
|
|
||||||
this.loading = false
|
|
||||||
})
|
})
|
||||||
|
.then(({ value }) => {
|
||||||
|
return saveBizRemark({
|
||||||
|
bizType: BIZ_TYPE,
|
||||||
|
bizKey1: REPORT_KEY,
|
||||||
|
bizKey2: this.buildRemarkKey(row.dataTime),
|
||||||
|
remark: value || "",
|
||||||
|
}).then(() => {
|
||||||
|
this.$set(row, "remark", value || "");
|
||||||
|
this.$message.success("备注保存成功");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
},
|
||||||
|
getData() {
|
||||||
|
this.loading = true;
|
||||||
|
const { siteId, pageNum, pageSize } = this;
|
||||||
|
const [startTime = "", endTime = ""] = this.dateRange || [];
|
||||||
|
|
||||||
|
getAmmeterRevenueData({ siteId, startTime, endTime, pageSize, pageNum })
|
||||||
|
.then(pageResponse => {
|
||||||
|
const rows = pageResponse?.rows || [];
|
||||||
|
const total = Number(pageResponse?.total || 0);
|
||||||
|
this.totalSize = total;
|
||||||
|
this.tableData = rows;
|
||||||
|
|
||||||
|
const tasks = [this.loadRemarks(rows)];
|
||||||
|
if (total > 0) {
|
||||||
|
tasks.push(
|
||||||
|
getAmmeterRevenueData({
|
||||||
|
siteId,
|
||||||
|
startTime,
|
||||||
|
endTime,
|
||||||
|
pageNum: 1,
|
||||||
|
pageSize: total,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return Promise.all(tasks);
|
||||||
|
})
|
||||||
|
.then(([remarkMap, allResponse]) => {
|
||||||
|
this.applyRemarks(this.tableData, remarkMap || {});
|
||||||
|
const allRows = allResponse?.rows || allResponse?.data || [];
|
||||||
|
this.summaryTotals = this.buildSummaryTotals(allRows);
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.loading = false;
|
||||||
|
});
|
||||||
},
|
},
|
||||||
init() {
|
init() {
|
||||||
this.dateRange = []
|
this.dateRange = [];
|
||||||
this.tableData = []
|
this.tableData = [];
|
||||||
this.totalSize = 0
|
this.summaryTotals = {};
|
||||||
this.pageSize = 10
|
this.totalSize = 0;
|
||||||
this.pageNum = 1
|
this.pageSize = 10;
|
||||||
let now = new Date(), lastDay = now.getTime(), firstDay = new Date(now.setDate(1)).getTime();
|
this.pageNum = 1;
|
||||||
|
const now = new Date();
|
||||||
|
const lastDay = now.getTime();
|
||||||
|
const firstDay = new Date(new Date().setDate(1)).getTime();
|
||||||
this.defaultDateRange = [formatDate(firstDay), formatDate(lastDay)];
|
this.defaultDateRange = [formatDate(firstDay), formatDate(lastDay)];
|
||||||
this.dateRange = [formatDate(firstDay), formatDate(lastDay)];
|
this.dateRange = [formatDate(firstDay), formatDate(lastDay)];
|
||||||
this.getData()
|
this.getData();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
::v-deep {
|
::v-deep {
|
||||||
.common-table.el-table {
|
.common-table.el-table {
|
||||||
.el-table__header-wrapper th, .common-table.el-table .el-table__fixed-header-wrapper th {
|
.el-table__header-wrapper th,
|
||||||
|
.common-table.el-table .el-table__fixed-header-wrapper th {
|
||||||
border-bottom: 1px solid #dfe6ec;
|
border-bottom: 1px solid #dfe6ec;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,7 +297,20 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.remark-cell {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remark-text {
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@ -85,6 +85,7 @@
|
|||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="latestValue" label="最新值" min-width="120" />
|
<el-table-column prop="latestValue" label="最新值" min-width="120" />
|
||||||
<el-table-column prop="dataUnit" label="单位" min-width="80" />
|
<el-table-column prop="dataUnit" label="单位" min-width="80" />
|
||||||
|
<el-table-column prop="decimalScale" label="小数位数" min-width="80" />
|
||||||
<el-table-column label="操作" width="220" fixed="right">
|
<el-table-column label="操作" width="220" fixed="right">
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button type="text" @click="openCurveDialog(scope.row)">曲线</el-button>
|
<el-button type="text" @click="openCurveDialog(scope.row)">曲线</el-button>
|
||||||
@ -192,6 +193,11 @@
|
|||||||
<el-input v-model.trim="form.dataUnit" placeholder="请输入单位" />
|
<el-input v-model.trim="form.dataUnit" placeholder="请输入单位" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="小数位数">
|
||||||
|
<el-input-number v-model="form.decimalScale" :min="0" :precision="0" placeholder="不填则不限制" style="width: 100%;" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :span="24" v-if="form.pointType === 'calc'">
|
<el-col :span="24" v-if="form.pointType === 'calc'">
|
||||||
@ -412,6 +418,7 @@ export default {
|
|||||||
dataKey: '',
|
dataKey: '',
|
||||||
pointDesc: '',
|
pointDesc: '',
|
||||||
dataUnit: '',
|
dataUnit: '',
|
||||||
|
decimalScale: null,
|
||||||
dataA: '',
|
dataA: '',
|
||||||
dataK: '',
|
dataK: '',
|
||||||
dataB: '',
|
dataB: '',
|
||||||
@ -1209,7 +1216,8 @@ export default {
|
|||||||
'类型',
|
'类型',
|
||||||
'计算表达式',
|
'计算表达式',
|
||||||
'最新值',
|
'最新值',
|
||||||
'单位'
|
'单位',
|
||||||
|
'小数位数'
|
||||||
]
|
]
|
||||||
const rows = this.tableData.map(item => {
|
const rows = this.tableData.map(item => {
|
||||||
return [
|
return [
|
||||||
@ -1228,7 +1236,8 @@ export default {
|
|||||||
item.pointType === 'calc' ? '计算点' : '数据点',
|
item.pointType === 'calc' ? '计算点' : '数据点',
|
||||||
item.pointType === 'calc' ? (item.calcExpression || '') : '',
|
item.pointType === 'calc' ? (item.calcExpression || '') : '',
|
||||||
item.latestValue === undefined || item.latestValue === null ? '' : item.latestValue,
|
item.latestValue === undefined || item.latestValue === null ? '' : item.latestValue,
|
||||||
item.dataUnit || ''
|
item.dataUnit || '',
|
||||||
|
item.decimalScale === undefined || item.decimalScale === null ? '' : item.decimalScale
|
||||||
].map(cell => this.escapeCsvCell(cell))
|
].map(cell => this.escapeCsvCell(cell))
|
||||||
})
|
})
|
||||||
const csvText = [headers.map(cell => this.escapeCsvCell(cell)).join(','), ...rows.map(row => row.join(','))].join('\n')
|
const csvText = [headers.map(cell => this.escapeCsvCell(cell)).join(','), ...rows.map(row => row.join(','))].join('\n')
|
||||||
@ -1258,6 +1267,7 @@ export default {
|
|||||||
dataKey: '',
|
dataKey: '',
|
||||||
pointDesc: '',
|
pointDesc: '',
|
||||||
dataUnit: '',
|
dataUnit: '',
|
||||||
|
decimalScale: null,
|
||||||
dataA: '',
|
dataA: '',
|
||||||
dataK: '',
|
dataK: '',
|
||||||
dataB: '',
|
dataB: '',
|
||||||
@ -1645,6 +1655,7 @@ export default {
|
|||||||
pointDesc: this.form.pointDesc,
|
pointDesc: this.form.pointDesc,
|
||||||
dataUnit: this.form.dataUnit,
|
dataUnit: this.form.dataUnit,
|
||||||
calcExpression: this.form.calcExpression,
|
calcExpression: this.form.calcExpression,
|
||||||
|
decimalScale: this.form.decimalScale,
|
||||||
remark: this.form.remark
|
remark: this.form.remark
|
||||||
}
|
}
|
||||||
request(calcData).then(() => {
|
request(calcData).then(() => {
|
||||||
|
|||||||
@ -33,9 +33,12 @@
|
|||||||
class="quick-filter-input"
|
class="quick-filter-input"
|
||||||
placeholder="按字段名/展示名/设备名筛选"
|
placeholder="按字段名/展示名/设备名筛选"
|
||||||
/>
|
/>
|
||||||
<div class="filter-actions">
|
<div class="filter-actions" :class="{ 'single-battery-actions-visible': showSingleBatteryImportActions }">
|
||||||
<el-button size="small" :disabled="!siteId" @click="openImportConfigDialog">导入配置</el-button>
|
<el-button size="small" :disabled="!siteId" @click="openImportConfigDialog">导入配置</el-button>
|
||||||
<el-button size="small" type="primary" :disabled="!siteId" @click="exportConfig">导出配置</el-button>
|
<el-button size="small" type="primary" :disabled="!siteId" @click="exportConfig">导出配置</el-button>
|
||||||
|
<el-button v-if="showSingleBatteryImportActions" size="small" type="success" :disabled="!siteId || singleBatteryInitLoading" @click="openSingleBatteryInitDialog">
|
||||||
|
{{ singleBatteryInitLoading ? '初始化中...' : '初始化单体电池配置' }}
|
||||||
|
</el-button>
|
||||||
<input
|
<input
|
||||||
ref="configInput"
|
ref="configInput"
|
||||||
type="file"
|
type="file"
|
||||||
@ -459,6 +462,61 @@
|
|||||||
@current-change="handlePointSelectorPageChange"
|
@current-change="handlePointSelectorPageChange"
|
||||||
/>
|
/>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
title="初始化单体电池配置"
|
||||||
|
:visible.sync="singleBatteryInitDialogVisible"
|
||||||
|
width="560px"
|
||||||
|
append-to-body
|
||||||
|
class="ems-dialog"
|
||||||
|
>
|
||||||
|
<el-form label-width="110px" size="small">
|
||||||
|
<el-form-item label="电池堆">
|
||||||
|
<el-select v-model="singleBatteryInitForm.stackDeviceId" placeholder="请选择电池堆" style="width: 100%" @change="handleSingleBatteryStackChange">
|
||||||
|
<el-option v-for="item in singleBatteryStackOptions" :key="item.id || item.deviceId || item" :label="item.name || item.deviceName || item.id || item.deviceId || item" :value="item.id || item.deviceId || item" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="电池簇">
|
||||||
|
<el-select v-model="singleBatteryInitForm.clusterDeviceId" placeholder="请选择电池簇" style="width: 100%">
|
||||||
|
<el-option v-for="item in singleBatteryClusterOptions" :key="item.id || item.deviceId || item" :label="item.name || item.deviceName || item.id || item.deviceId || item" :value="item.id || item.deviceId || item" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="目标数量">
|
||||||
|
<el-input-number v-model="singleBatteryInitForm.targetCount" :min="1" :precision="0" controls-position="right" style="width: 220px" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<div slot="footer" class="dialog-footer">
|
||||||
|
<el-button @click="singleBatteryInitDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" :loading="singleBatteryInitLoading" @click="submitSingleBatteryInit">确定初始化</el-button>
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
<el-dialog
|
||||||
|
title="初始化结果"
|
||||||
|
:visible.sync="singleBatteryInitResultVisible"
|
||||||
|
width="980px"
|
||||||
|
append-to-body
|
||||||
|
class="ems-dialog"
|
||||||
|
>
|
||||||
|
<el-alert
|
||||||
|
:title="singleBatteryInitResult.message || '初始化完成'"
|
||||||
|
:type="singleBatteryInitResult.committed ? 'success' : 'warning'"
|
||||||
|
:closable="false"
|
||||||
|
style="margin-bottom: 16px;"
|
||||||
|
/>
|
||||||
|
<el-descriptions :column="3" border size="small">
|
||||||
|
<el-descriptions-item label="站点ID">{{ singleBatteryInitResult.siteId || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="初始化范围">{{ singleBatteryInitResult.scopeType === 'stack' ? '电池堆' : '电池簇' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="范围设备ID">{{ singleBatteryInitResult.scopeDeviceId || '-' }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="目标数量">{{ singleBatteryInitResult.targetCount || 0 }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="现有单体">{{ singleBatteryInitResult.existingBatteryCount || 0 }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="已初始化单体">{{ singleBatteryInitResult.initializedBatteryCount || 0 }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="新增单体">{{ singleBatteryInitResult.insertedBatteryCount || 0 }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="命中点位">{{ singleBatteryInitResult.pointHitCount || 0 }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="固定值回填">{{ singleBatteryInitResult.fixedValueFallbackCount || 0 }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="新增映射">{{ singleBatteryInitResult.insertedMappingCount || 0 }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="更新映射">{{ singleBatteryInitResult.updatedMappingCount || 0 }}</el-descriptions-item>
|
||||||
|
<el-descriptions-item label="是否成功">{{ singleBatteryInitResult.committed ? '是' : '否' }}</el-descriptions-item>
|
||||||
|
</el-descriptions>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -467,9 +525,11 @@ import {
|
|||||||
getPointMatchList,
|
getPointMatchList,
|
||||||
getSingleMonitorProjectPointMapping,
|
getSingleMonitorProjectPointMapping,
|
||||||
getSingleMonitorWorkStatusEnumMappings,
|
getSingleMonitorWorkStatusEnumMappings,
|
||||||
|
initializeSingleBatteryMonitorMappings,
|
||||||
saveSingleMonitorProjectPointMapping,
|
saveSingleMonitorProjectPointMapping,
|
||||||
saveSingleMonitorWorkStatusEnumMappings
|
saveSingleMonitorWorkStatusEnumMappings
|
||||||
} from '@/api/ems/site'
|
} from '@/api/ems/site'
|
||||||
|
import { getClusterNameList, getStackNameList } from '@/api/ems/dzjk'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'MonitorPointMapping',
|
name: 'MonitorPointMapping',
|
||||||
@ -519,6 +579,31 @@ export default {
|
|||||||
suppressAutoSave: false,
|
suppressAutoSave: false,
|
||||||
isSaving: false,
|
isSaving: false,
|
||||||
saveStatusText: '自动保存已开启',
|
saveStatusText: '自动保存已开启',
|
||||||
|
singleBatteryInitLoading: false,
|
||||||
|
singleBatteryInitDialogVisible: false,
|
||||||
|
singleBatteryInitResultVisible: false,
|
||||||
|
singleBatteryStackOptions: [],
|
||||||
|
singleBatteryClusterOptions: [],
|
||||||
|
singleBatteryInitForm: {
|
||||||
|
stackDeviceId: '',
|
||||||
|
clusterDeviceId: '',
|
||||||
|
targetCount: 1
|
||||||
|
},
|
||||||
|
singleBatteryInitResult: {
|
||||||
|
committed: false,
|
||||||
|
siteId: '',
|
||||||
|
scopeType: 'stack',
|
||||||
|
scopeDeviceId: '',
|
||||||
|
targetCount: 0,
|
||||||
|
existingBatteryCount: 0,
|
||||||
|
initializedBatteryCount: 0,
|
||||||
|
insertedBatteryCount: 0,
|
||||||
|
pointHitCount: 0,
|
||||||
|
fixedValueFallbackCount: 0,
|
||||||
|
insertedMappingCount: 0,
|
||||||
|
updatedMappingCount: 0,
|
||||||
|
message: ''
|
||||||
|
},
|
||||||
lastSavedPointSignature: '',
|
lastSavedPointSignature: '',
|
||||||
lastSavedEnumSignature: '',
|
lastSavedEnumSignature: '',
|
||||||
workStatusEnumMappings: []
|
workStatusEnumMappings: []
|
||||||
@ -561,6 +646,19 @@ export default {
|
|||||||
this.schedulePointSelectorSearch()
|
this.schedulePointSelectorSearch()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
showSingleBatteryImportActions() {
|
||||||
|
const currentTopMenu = this.topMenuList.find(item => item.code === this.activeTopMenu)
|
||||||
|
if (!currentTopMenu) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (currentTopMenu.code === 'SBJK_DTDC') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
const activeChildCode = this.activeChildMap[this.activeTopMenu] || ''
|
||||||
|
return activeChildCode === 'SBJK_DTDC'
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
async initMenuStructure() {
|
async initMenuStructure() {
|
||||||
if (!this.siteId) {
|
if (!this.siteId) {
|
||||||
@ -716,6 +814,87 @@ export default {
|
|||||||
this.$refs.configInput.click()
|
this.$refs.configInput.click()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async openSingleBatteryInitDialog() {
|
||||||
|
if (!this.siteId) {
|
||||||
|
this.$message.warning('请先选择站点')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.singleBatteryInitDialogVisible = true
|
||||||
|
this.singleBatteryInitForm.stackDeviceId = ''
|
||||||
|
this.singleBatteryInitForm.clusterDeviceId = ''
|
||||||
|
this.singleBatteryInitForm.targetCount = 1
|
||||||
|
await this.loadSingleBatteryStackOptions()
|
||||||
|
this.singleBatteryClusterOptions = []
|
||||||
|
},
|
||||||
|
async loadSingleBatteryStackOptions() {
|
||||||
|
const response = await getStackNameList(this.siteId)
|
||||||
|
this.singleBatteryStackOptions = Array.isArray(response?.data) ? response.data : []
|
||||||
|
},
|
||||||
|
async handleSingleBatteryStackChange(stackDeviceId) {
|
||||||
|
this.singleBatteryInitForm.clusterDeviceId = ''
|
||||||
|
if (!stackDeviceId) {
|
||||||
|
this.singleBatteryClusterOptions = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const response = await getClusterNameList({ stackDeviceId, siteId: this.siteId })
|
||||||
|
this.singleBatteryClusterOptions = Array.isArray(response?.data) ? response.data : []
|
||||||
|
},
|
||||||
|
normalizeSingleBatteryInitResult(result) {
|
||||||
|
const source = result || {}
|
||||||
|
return {
|
||||||
|
committed: !!source.committed,
|
||||||
|
siteId: source.siteId || '',
|
||||||
|
scopeType: source.scopeType || 'stack',
|
||||||
|
scopeDeviceId: source.scopeDeviceId || '',
|
||||||
|
targetCount: Number(source.targetCount || 0),
|
||||||
|
existingBatteryCount: Number(source.existingBatteryCount || 0),
|
||||||
|
initializedBatteryCount: Number(source.initializedBatteryCount || 0),
|
||||||
|
insertedBatteryCount: Number(source.insertedBatteryCount || 0),
|
||||||
|
pointHitCount: Number(source.pointHitCount || 0),
|
||||||
|
fixedValueFallbackCount: Number(source.fixedValueFallbackCount || 0),
|
||||||
|
insertedMappingCount: Number(source.insertedMappingCount || 0),
|
||||||
|
updatedMappingCount: Number(source.updatedMappingCount || 0),
|
||||||
|
message: source.message || ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async submitSingleBatteryInit() {
|
||||||
|
if (!this.siteId) {
|
||||||
|
this.$message.warning('请先选择站点')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.singleBatteryInitForm.stackDeviceId) {
|
||||||
|
this.$message.warning('请选择电池堆')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!this.singleBatteryInitForm.clusterDeviceId) {
|
||||||
|
this.$message.warning('请选择电池簇')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const scopeType = 'cluster'
|
||||||
|
const scopeDeviceId = this.singleBatteryInitForm.clusterDeviceId
|
||||||
|
this.singleBatteryInitLoading = true
|
||||||
|
try {
|
||||||
|
const response = await initializeSingleBatteryMonitorMappings({
|
||||||
|
siteId: this.siteId,
|
||||||
|
scopeType,
|
||||||
|
scopeDeviceId,
|
||||||
|
targetCount: this.singleBatteryInitForm.targetCount
|
||||||
|
})
|
||||||
|
this.singleBatteryInitResult = this.normalizeSingleBatteryInitResult(response?.data || {})
|
||||||
|
this.singleBatteryInitDialogVisible = false
|
||||||
|
this.singleBatteryInitResultVisible = true
|
||||||
|
if (this.singleBatteryInitResult.committed) {
|
||||||
|
await this.initMenuStructure()
|
||||||
|
this.$message.success('初始化单体电池配置成功')
|
||||||
|
} else {
|
||||||
|
this.$message.warning(this.singleBatteryInitResult.message || '初始化未完成')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.$message.error(error?.message || '初始化失败,请稍后重试')
|
||||||
|
} finally {
|
||||||
|
this.singleBatteryInitLoading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
handleConfigFileChange(event) {
|
handleConfigFileChange(event) {
|
||||||
const file = event && event.target && event.target.files && event.target.files[0]
|
const file = event && event.target && event.target.files && event.target.files[0]
|
||||||
if (!file) {
|
if (!file) {
|
||||||
@ -1570,6 +1749,18 @@ export default {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.filter-actions:not(.single-battery-actions-visible) > .el-button:nth-of-type(3),
|
||||||
|
.filter-actions:not(.single-battery-actions-visible) > .el-button:nth-of-type(4) {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.import-result-title {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
.quick-wrapper {
|
.quick-wrapper {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||||
|
|||||||
Reference in New Issue
Block a user