重构
This commit is contained in:
@ -181,6 +181,15 @@ export function createTicketNo(data) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 告警确认关闭
|
||||||
|
export function closeAlarm(data) {
|
||||||
|
return request({
|
||||||
|
url: `/ems/siteAlarm/closeAlarm`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function getFieldNameByCode(fieldCode) {
|
function getFieldNameByCode(fieldCode) {
|
||||||
const raw = String(fieldCode || '').trim()
|
const raw = String(fieldCode || '').trim()
|
||||||
if (!raw) return ''
|
if (!raw) return ''
|
||||||
|
|||||||
@ -100,6 +100,9 @@ import {mapGetters} from "vuex"
|
|||||||
onSubmit(){
|
onSubmit(){
|
||||||
this.$emit('submitSite',this.id)
|
this.$emit('submitSite',this.id)
|
||||||
},
|
},
|
||||||
|
emitSitesLoaded() {
|
||||||
|
this.$emit('sitesLoaded', this.siteList || [])
|
||||||
|
},
|
||||||
setDefaultSite(){
|
setDefaultSite(){
|
||||||
const defaultSite = this.defaultSiteId
|
const defaultSite = this.defaultSiteId
|
||||||
if(defaultSite && this.siteList.find(item=>item.siteId === defaultSite)){
|
if(defaultSite && this.siteList.find(item=>item.siteId === defaultSite)){
|
||||||
@ -112,6 +115,7 @@ import {mapGetters} from "vuex"
|
|||||||
getList(){
|
getList(){
|
||||||
return getAllSites().then(response => {
|
return getAllSites().then(response => {
|
||||||
this.siteList = response.data || []
|
this.siteList = response.data || []
|
||||||
|
this.emitSitesLoaded()
|
||||||
this.setDefaultSite()
|
this.setDefaultSite()
|
||||||
}).finally(() => {this.loading=false;this.searchLoading=false})
|
}).finally(() => {this.loading=false;this.searchLoading=false})
|
||||||
}
|
}
|
||||||
@ -127,6 +131,7 @@ import {mapGetters} from "vuex"
|
|||||||
})
|
})
|
||||||
}else{
|
}else{
|
||||||
this.siteList = this.zdList
|
this.siteList = this.zdList
|
||||||
|
this.emitSitesLoaded()
|
||||||
this.loading=false
|
this.loading=false
|
||||||
this.searchLoading=false
|
this.searchLoading=false
|
||||||
this.setDefaultSite()
|
this.setDefaultSite()
|
||||||
|
|||||||
@ -94,13 +94,21 @@
|
|||||||
<el-table-column
|
<el-table-column
|
||||||
label="工单"
|
label="工单"
|
||||||
fixed="right"
|
fixed="right"
|
||||||
width="250"
|
width="320"
|
||||||
>
|
>
|
||||||
<template slot-scope="scope">
|
<template slot-scope="scope">
|
||||||
<el-button type="text" size="mini" v-if="scope.row.ticketNo" @click="toTicket">
|
<el-button type="text" size="mini" v-if="scope.row.ticketNo" @click="toTicket">
|
||||||
已生成工单(工单号:{{ scope.row.ticketNo }})
|
已生成工单(工单号:{{ scope.row.ticketNo }})
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button type="primary" size="mini" v-else @click="createTicket(scope.row.id)">生成工单</el-button>
|
<el-button type="primary" size="mini" v-else @click="createTicket(scope.row.id)">生成工单</el-button>
|
||||||
|
<el-button
|
||||||
|
v-if="scope.row.status !== '1'"
|
||||||
|
type="success"
|
||||||
|
size="mini"
|
||||||
|
style="margin-left: 8px;"
|
||||||
|
@click="closeAlarmRecord(scope.row.id)">
|
||||||
|
确认关闭
|
||||||
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
@ -123,7 +131,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {createTicketNo, getAlarmDetailList} from '@/api/ems/dzjk'
|
import {closeAlarm, createTicketNo, getAlarmDetailList} from '@/api/ems/dzjk'
|
||||||
import {getDeviceList} from '@/api/ems/site'
|
import {getDeviceList} from '@/api/ems/site'
|
||||||
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
|
import getQuerySiteId from "@/mixins/ems/getQuerySiteId";
|
||||||
import {formatDate} from '@/filters/ems'
|
import {formatDate} from '@/filters/ems'
|
||||||
@ -169,6 +177,23 @@ export default {
|
|||||||
this.loading = false
|
this.loading = false
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
//确认关闭告警
|
||||||
|
closeAlarmRecord(id) {
|
||||||
|
this.$confirm('确认关闭该故障告警吗?', '提示', {
|
||||||
|
confirmButtonText: '确定',
|
||||||
|
cancelButtonText: '取消',
|
||||||
|
type: 'warning'
|
||||||
|
}).then(() => {
|
||||||
|
this.loading = true
|
||||||
|
closeAlarm({id}).then(() => {
|
||||||
|
this.$message.success('关闭成功')
|
||||||
|
this.getData()
|
||||||
|
}).finally(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
}).catch(() => {
|
||||||
|
})
|
||||||
|
},
|
||||||
// 判断是否是同一天
|
// 判断是否是同一天
|
||||||
isSameDay(day1, day2) {
|
isSameDay(day1, day2) {
|
||||||
const date1 = new Date(day1), date2 = new Date(day2)
|
const date1 = new Date(day1), date2 = new Date(day2)
|
||||||
@ -250,4 +275,3 @@ export default {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@ -89,95 +89,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<el-table
|
|
||||||
:data="baseInfo.batteryDataList"
|
|
||||||
class="common-table"
|
|
||||||
max-height="500"
|
|
||||||
stripe
|
|
||||||
style="width: 100%;margin-top:25px;">
|
|
||||||
<el-table-column
|
|
||||||
label="簇号"
|
|
||||||
prop="clusterId">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
label="簇电压"
|
|
||||||
>
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<span class="pointer"
|
|
||||||
@click="handleClusterFieldClick(scope.row, 'clusterVoltage', '簇电压')">{{ scope.row.clusterVoltage }} V</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
label="簇电流">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<span class="pointer"
|
|
||||||
@click="handleClusterFieldClick(scope.row, 'clusterCurrent', '簇电流')">{{ scope.row.clusterCurrent }} A</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
label="簇SOC">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<span class="pointer"
|
|
||||||
@click="handleClusterFieldClick(scope.row, 'currentSoc', '当前SOC')">{{ scope.row.currentSoc }} %</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
label="单体最高电压"
|
|
||||||
prop="maxVoltage">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<span class="pointer"
|
|
||||||
@click="handleClusterFieldClick(scope.row, 'maxCellVoltage', '最高单体电压')">{{
|
|
||||||
scope.row.maxCellVoltage
|
|
||||||
}} V</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
label="电池号码"
|
|
||||||
prop="maxCellVoltageId">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
label="单体最低电压"
|
|
||||||
prop="minVoltage">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<span class="pointer"
|
|
||||||
@click="handleClusterFieldClick(scope.row, 'minCellVoltage', '最低单体电压')">{{
|
|
||||||
scope.row.minCellVoltage
|
|
||||||
}} V</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
label="电池号码"
|
|
||||||
prop="minCellVoltageId">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
label="单体最高温度">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<span class="pointer"
|
|
||||||
@click="handleClusterFieldClick(scope.row, 'maxCellTemp', '最高单体温度')">{{
|
|
||||||
scope.row.maxCellTemp
|
|
||||||
}} ℃</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
label="电池号码"
|
|
||||||
prop="maxCellTempId">
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
label="单体最低温度"
|
|
||||||
prop="minTemperature">
|
|
||||||
<template slot-scope="scope">
|
|
||||||
<span class="pointer"
|
|
||||||
@click="handleClusterFieldClick(scope.row, 'minCellTemp', '最低单体温度')">{{
|
|
||||||
scope.row.minCellTemp
|
|
||||||
}} ℃</span>
|
|
||||||
</template>
|
|
||||||
</el-table-column>
|
|
||||||
<el-table-column
|
|
||||||
label="电池号码"
|
|
||||||
prop="minCellTempId">
|
|
||||||
</el-table-column>
|
|
||||||
|
|
||||||
</el-table>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
</div>
|
</div>
|
||||||
<el-dialog
|
<el-dialog
|
||||||
|
|||||||
@ -37,8 +37,8 @@
|
|||||||
>{{ pcsItem.deviceName }}</span
|
>{{ pcsItem.deviceName }}</span
|
||||||
>
|
>
|
||||||
<div class="info">
|
<div class="info">
|
||||||
<div>
|
<div v-if="(($store.state.ems && $store.state.ems.communicationStatusOptions) || {})[pcsItem.communicationStatus]">
|
||||||
{{ (($store.state.ems && $store.state.ems.communicationStatusOptions) || {})[pcsItem.communicationStatus] || '-' }}
|
{{ (($store.state.ems && $store.state.ems.communicationStatusOptions) || {})[pcsItem.communicationStatus] }}
|
||||||
</div>
|
</div>
|
||||||
<div>数据更新时间:{{ pcsItem.dataUpdateTime }}</div>
|
<div>数据更新时间:{{ pcsItem.dataUpdateTime }}</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -40,6 +40,10 @@
|
|||||||
prop="siteName"
|
prop="siteName"
|
||||||
label="站点名称">
|
label="站点名称">
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
|
<el-table-column
|
||||||
|
prop="siteShortName"
|
||||||
|
label="站点简称">
|
||||||
|
</el-table-column>
|
||||||
<el-table-column
|
<el-table-column
|
||||||
prop="siteAddress"
|
prop="siteAddress"
|
||||||
label="站点地址"
|
label="站点地址"
|
||||||
@ -98,6 +102,13 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
</el-row>
|
</el-row>
|
||||||
|
<el-row :gutter="16">
|
||||||
|
<el-col :span="12">
|
||||||
|
<el-form-item label="站点简称" prop="siteShortName">
|
||||||
|
<el-input v-model.trim="siteForm.siteShortName" placeholder="请输入站点简称" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
<el-row :gutter="16">
|
<el-row :gutter="16">
|
||||||
<el-col :span="12">
|
<el-col :span="12">
|
||||||
<el-form-item label="运营时间" prop="runningTime">
|
<el-form-item label="运营时间" prop="runningTime">
|
||||||
@ -160,6 +171,7 @@ const emptySiteForm = () => ({
|
|||||||
id: undefined,
|
id: undefined,
|
||||||
siteId: '',
|
siteId: '',
|
||||||
siteName: '',
|
siteName: '',
|
||||||
|
siteShortName: '',
|
||||||
siteAddress: '',
|
siteAddress: '',
|
||||||
runningTime: '',
|
runningTime: '',
|
||||||
installPower: '',
|
installPower: '',
|
||||||
@ -252,6 +264,7 @@ export default {
|
|||||||
id: row.id,
|
id: row.id,
|
||||||
siteId: row.siteId || '',
|
siteId: row.siteId || '',
|
||||||
siteName: row.siteName || '',
|
siteName: row.siteName || '',
|
||||||
|
siteShortName: row.siteShortName || '',
|
||||||
siteAddress: row.siteAddress || '',
|
siteAddress: row.siteAddress || '',
|
||||||
runningTime: row.runningTime || '',
|
runningTime: row.runningTime || '',
|
||||||
installPower: row.installPower || '',
|
installPower: row.installPower || '',
|
||||||
|
|||||||
@ -1,95 +1,163 @@
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div id="zddtChart" style="height: 100%;width:100%"></div>
|
<div class="map-wrapper">
|
||||||
|
<div ref="mapRef" class="map-canvas"></div>
|
||||||
|
<div v-if="!hasPoint" class="map-empty">暂无站点坐标</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import * as echarts from 'echarts'
|
const TDT_SCRIPT_ID = 'tianditu-js-sdk'
|
||||||
import resize from '@/mixins/ems/resize'
|
let tdtScriptLoading = null
|
||||||
import china from '@/data/ems/china.json'//中国地图数据
|
|
||||||
import 'echarts/lib/chart/map';
|
function loadTdtScript(tk) {
|
||||||
echarts.registerMap('china', { geoJSON: china }); //注册可用地图
|
if (window.T) return Promise.resolve(window.T)
|
||||||
|
if (tdtScriptLoading) return tdtScriptLoading
|
||||||
|
tdtScriptLoading = new Promise((resolve, reject) => {
|
||||||
|
const oldScript = document.getElementById(TDT_SCRIPT_ID)
|
||||||
|
if (oldScript) {
|
||||||
|
oldScript.addEventListener('load', () => resolve(window.T))
|
||||||
|
oldScript.addEventListener('error', () => reject(new Error('天地图脚本加载失败')))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.id = TDT_SCRIPT_ID
|
||||||
|
script.src = `https://api.tianditu.gov.cn/api?v=4.0&tk=${tk}`
|
||||||
|
script.async = true
|
||||||
|
script.onload = () => {
|
||||||
|
if (window.T) resolve(window.T)
|
||||||
|
else reject(new Error('天地图对象未初始化'))
|
||||||
|
}
|
||||||
|
script.onerror = () => reject(new Error('天地图脚本加载失败'))
|
||||||
|
document.body.appendChild(script)
|
||||||
|
})
|
||||||
|
return tdtScriptLoading
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [resize],
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
chart: null,
|
hasPoint: false,
|
||||||
|
map: null,
|
||||||
|
overlays: [],
|
||||||
|
pendingPayload: null,
|
||||||
|
mapConfig: {
|
||||||
|
zoom: 12,
|
||||||
|
tk: '01e99ab4472430e1c7dbfe4b5db99787'
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
this.$nextTick(() => {
|
this.initMap()
|
||||||
this.initChart()
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (!this.chart) {
|
this.clearOverlays()
|
||||||
return
|
this.map = null
|
||||||
}
|
|
||||||
this.chart.dispose()
|
|
||||||
this.chart = null
|
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
initChart() {
|
async initMap() {
|
||||||
// ECharts 默认有提供了一个简单的加载动画。只需要调用 showLoading 方法显示。数据加载完成后再调用 hideLoading 方法隐藏加载动画。
|
try {
|
||||||
this.chart = echarts.init(document.querySelector('#zddtChart'))
|
await loadTdtScript(this.mapConfig.tk)
|
||||||
|
if (!this.$refs.mapRef || !window.T) return
|
||||||
|
this.map = new window.T.Map(this.$refs.mapRef)
|
||||||
|
const defaultCenter = new window.T.LngLat(104.1, 35.9)
|
||||||
|
this.map.centerAndZoom(defaultCenter, 5)
|
||||||
|
if (this.pendingPayload) {
|
||||||
|
this.renderPayload(this.pendingPayload)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// 页面可继续使用,地图只显示空态
|
||||||
|
this.hasPoint = false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
setOption(data) {
|
normalizePoint(site = {}) {
|
||||||
this.chart.setOption({
|
const name = site.siteName || site.name || ''
|
||||||
color:['#FFBD00'],
|
const value = site.value || site.siteLocation || []
|
||||||
backgroundColor: 'transparent', //背景色
|
const lonSource = site.longitude !== undefined && site.longitude !== null ? site.longitude : value[0]
|
||||||
geo: { //地理坐标系组件 地理坐标系组件用于地图的绘制,支持在地理坐标系上绘制
|
const latSource = site.latitude !== undefined && site.latitude !== null ? site.latitude : value[1]
|
||||||
map: 'china', //地图类型 这儿展示的是中国地图
|
const lon = Number(lonSource)
|
||||||
aspectScale: 0.85,
|
const lat = Number(latSource)
|
||||||
selectedMode: "single",// 开启单选
|
if (!lon || !lat) return null
|
||||||
label: {
|
return { name, lon, lat }
|
||||||
show: true, //是否显示标签 此处指是否显示地图上的地区名字
|
},
|
||||||
color: '#ffffff',
|
clearOverlays() {
|
||||||
fontSize: 12
|
if (!this.map || !this.overlays.length) return
|
||||||
},
|
this.overlays.forEach(item => this.map.removeOverLay(item))
|
||||||
roam: true, //是否开启鼠标缩放和平移漫游
|
this.overlays = []
|
||||||
itemStyle: {
|
},
|
||||||
areaColor: "#03365b",
|
renderPayload(payload = {}) {
|
||||||
borderColor: "#4bf3f9",
|
const isArrayPayload = Array.isArray(payload)
|
||||||
shadowColor: '#03365b', //阴影颜色
|
const selectedRaw = isArrayPayload ? ((payload || [])[0] || {}) : (payload.selected || {})
|
||||||
shadowOffsetX: 0, //阴影偏移量
|
const sitesRaw = isArrayPayload ? [] : (payload.sites || [])
|
||||||
shadowOffsetY: 0, //阴影偏移量
|
const selected = this.normalizePoint(selectedRaw)
|
||||||
},
|
const points = (Array.isArray(sitesRaw) ? sitesRaw : [])
|
||||||
emphasis: {
|
.map(item => this.normalizePoint(item))
|
||||||
label: {
|
.filter(Boolean)
|
||||||
show: true,
|
if (selected && !points.find(item => item.lon === selected.lon && item.lat === selected.lat)) {
|
||||||
color: '#ffffff',
|
points.push(selected)
|
||||||
},
|
}
|
||||||
itemStyle: {
|
this.clearOverlays()
|
||||||
areaColor: "#0f5d9d",
|
this.hasPoint = points.length > 0
|
||||||
}
|
if (!this.map || !points.length || !window.T) return
|
||||||
}
|
|
||||||
},
|
const viewPoints = []
|
||||||
series: [
|
points.forEach(item => {
|
||||||
{
|
const lngLat = new window.T.LngLat(item.lon, item.lat)
|
||||||
type: "effectScatter",
|
const marker = new window.T.Marker(lngLat)
|
||||||
coordinateSystem: "geo",
|
this.map.addOverLay(marker)
|
||||||
showEffectOn: "render",
|
this.overlays.push(marker)
|
||||||
data,
|
viewPoints.push(lngLat)
|
||||||
rippleEffect: {
|
|
||||||
brushType: "stroke",
|
|
||||||
scale: 5,
|
|
||||||
period: 2, // 秒数
|
|
||||||
},
|
|
||||||
symbolSize: 12,
|
|
||||||
clickable: false,
|
|
||||||
zlevel: 1,
|
|
||||||
label: {
|
|
||||||
formatter: "{b}",
|
|
||||||
position: "right",
|
|
||||||
show: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (selected && selected.name) {
|
||||||
|
const label = new window.T.Label({
|
||||||
|
text: selected.name,
|
||||||
|
position: new window.T.LngLat(selected.lon, selected.lat),
|
||||||
|
offset: new window.T.Point(8, -34)
|
||||||
|
})
|
||||||
|
this.map.addOverLay(label)
|
||||||
|
this.overlays.push(label)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (viewPoints.length === 1) {
|
||||||
|
this.map.centerAndZoom(viewPoints[0], this.mapConfig.zoom)
|
||||||
|
} else {
|
||||||
|
this.map.setViewport(viewPoints)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setOption(payload = {}) {
|
||||||
|
this.pendingPayload = payload
|
||||||
|
if (!this.map) return
|
||||||
|
this.renderPayload(payload)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.map-wrapper {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 0;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
|
background: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-canvas {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.map-empty {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: #909399;
|
||||||
|
font-size: 14px;
|
||||||
|
background: rgba(245, 247, 250, 0.9);
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@ -1,33 +1,55 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="ems-dashboard-editor-container" v-loading="loading">
|
<div class="ems-dashboard-editor-container" v-loading="loading">
|
||||||
<zd-info></zd-info>
|
<zd-info></zd-info>
|
||||||
<div class="ems-content-container ">
|
<div class="ems-content-container">
|
||||||
<div class="map-container">
|
<div class="map-container">
|
||||||
<map-chart ref="mapChart"/>
|
<div class="site-cards-wrapper" v-if="allSites.length > 0">
|
||||||
</div>
|
<button
|
||||||
<div class="zd-msg-container">
|
class="site-cards-arrow site-cards-arrow--left"
|
||||||
<div class="zd-msg-top">
|
type="button"
|
||||||
<zd-select ref="zdSelect" @submitSite="submitSite"></zd-select>
|
:disabled="!canScrollLeft"
|
||||||
<el-card class="common-card-container">
|
@click="scrollSiteCards('left')"
|
||||||
<div slot="header">
|
>
|
||||||
<span class="card-title">基本信息</span>
|
<i class="el-icon-arrow-left"></i>
|
||||||
<el-button style="float: right; padding: 3px 0" type="text" size="small" @click="toDzjk">查看详情</el-button>
|
</button>
|
||||||
|
<div ref="siteCards" class="site-cards" @scroll="updateScrollButtons">
|
||||||
|
<div
|
||||||
|
v-for="item in allSites"
|
||||||
|
:key="item.siteId"
|
||||||
|
class="site-card"
|
||||||
|
:class="{ active: isSameSite(item.siteId, singleSiteId) }"
|
||||||
|
@click="submitSite(item.siteId)"
|
||||||
|
>
|
||||||
|
<div class="site-card-name">{{ item.siteName || '-' }}</div>
|
||||||
|
<div class="site-card-info-row">
|
||||||
|
<span class="site-card-label">电站位置</span>
|
||||||
|
<span class="site-card-value site-card-value--address">{{ formatSiteCardField(item.siteAddress) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="site-card-info-row">
|
||||||
|
<span class="site-card-label">投运时间</span>
|
||||||
|
<span class="site-card-value">{{ formatSiteCardDate(item.runningTime) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="site-card-info-row">
|
||||||
|
<span class="site-card-label">装机功率(MW)</span>
|
||||||
|
<span class="site-card-value">{{ formatSiteCardField(item.installPower) }}</span>
|
||||||
|
</div>
|
||||||
|
<div class="site-card-info-row">
|
||||||
|
<span class="site-card-label">装机容量(MW)</span>
|
||||||
|
<span class="site-card-value">{{ formatSiteCardField(item.installCapacity) }}</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="single-zd-name">{{singleSiteName}}</div>
|
</div>
|
||||||
<!-- 四个方块-->
|
<button
|
||||||
<el-row :gutter="14">
|
class="site-cards-arrow site-cards-arrow--right"
|
||||||
<el-col :span="12" class="single-square-box-container" v-for="(item,index) in singleZdSqaure" :key="index+'singleSquareBox'">
|
type="button"
|
||||||
<single-square-box :data="item"></single-square-box>
|
:disabled="!canScrollRight"
|
||||||
</el-col>
|
@click="scrollSiteCards('right')"
|
||||||
</el-row>
|
>
|
||||||
<!-- 基本信息 -->
|
<i class="el-icon-arrow-right"></i>
|
||||||
<el-descriptions class="single-zd-info-container" :column="1" >
|
</button>
|
||||||
<el-descriptions-item v-for="(item,index) in singleZdInfo" :key="index+'singleZdInfo'" :label="item.title">{{item.value | formatNumber }}</el-descriptions-item>
|
</div>
|
||||||
</el-descriptions>
|
<div class="map-view">
|
||||||
<!-- echarts柱状图-->
|
<map-chart ref="mapChart"/>
|
||||||
<bar-chart ref="barChart"></bar-chart>
|
|
||||||
</el-card>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -36,94 +58,101 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ZdInfo from '@/components/Ems/ZdBaseInfo/index.vue'
|
import ZdInfo from '@/components/Ems/ZdBaseInfo/index.vue'
|
||||||
import ZdSelect from '@/components/Ems/ZdSelect/index.vue'
|
|
||||||
import SingleSquareBox from '@/components/Ems/SingleSquareBox/index.vue'
|
|
||||||
import BarChart from './BarChart.vue'
|
|
||||||
import MapChart from './MapChart.vue'
|
import MapChart from './MapChart.vue'
|
||||||
import {getSingleSiteBaseInfo} from '@/api/ems/zddt'
|
import { getAllSites } from '@/api/ems/zddt'
|
||||||
export default {
|
export default {
|
||||||
components:{ZdSelect,ZdInfo,SingleSquareBox,BarChart,MapChart},
|
components: { ZdInfo, MapChart },
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
loading:false,
|
loading: false,
|
||||||
singleSiteId:'',
|
singleSiteId: '',
|
||||||
singleSiteName:'',
|
singleSiteName: '',
|
||||||
singleSiteLocation:[],
|
singleSiteLocation: [],
|
||||||
// 单个电站 四个方块数据
|
allSites: [],
|
||||||
singleZdSqaure:[
|
canScrollLeft: false,
|
||||||
{
|
canScrollRight: false
|
||||||
title:'今日充电(kWh)',
|
|
||||||
value:'',
|
|
||||||
bgColor:'#FFE5E5',
|
|
||||||
attr:'dayChargedCap'
|
|
||||||
},{
|
|
||||||
title:'累计充电(kWh)',
|
|
||||||
value:'',
|
|
||||||
bgColor:'#FFE5E5',
|
|
||||||
attr:'totalChargedCap'
|
|
||||||
},{
|
|
||||||
title:'今日放电(kWh)',
|
|
||||||
value:'',
|
|
||||||
bgColor:'#EEEBFF',
|
|
||||||
attr:'dayDisChargedCap'
|
|
||||||
},{
|
|
||||||
title:'累计放电(kWh)',
|
|
||||||
value:'',
|
|
||||||
bgColor:'#EEEBFF',
|
|
||||||
attr:'totalDisChargedCap'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
// 单个电站 基本信息
|
|
||||||
singleZdInfo:[{
|
|
||||||
title:'电站位置',
|
|
||||||
value:'',
|
|
||||||
attr:'siteAddress'
|
|
||||||
},{
|
|
||||||
title:'投运时间',
|
|
||||||
value:'',
|
|
||||||
attr:'runningTime'
|
|
||||||
},{
|
|
||||||
title:'装机功率(MW)',
|
|
||||||
value:'',
|
|
||||||
attr:'installPower'
|
|
||||||
},{
|
|
||||||
title:'装机容量(MW)',
|
|
||||||
value:'',
|
|
||||||
attr:'installCapacity',
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.loadSites()
|
||||||
|
window.addEventListener('resize', this.updateScrollButtons)
|
||||||
|
},
|
||||||
|
beforeDestroy() {
|
||||||
|
window.removeEventListener('resize', this.updateScrollButtons)
|
||||||
|
},
|
||||||
methods:{
|
methods:{
|
||||||
|
isSameSite(siteId, selectedId) {
|
||||||
|
return String(siteId) === String(selectedId)
|
||||||
|
},
|
||||||
|
formatSiteCardField(value) {
|
||||||
|
if (value === null || value === undefined || value === '') {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
return value
|
||||||
|
},
|
||||||
|
formatSiteCardDate(value) {
|
||||||
|
if (!value) {
|
||||||
|
return '-'
|
||||||
|
}
|
||||||
|
const text = String(value)
|
||||||
|
if (text.includes('T')) {
|
||||||
|
return text.slice(0, 10)
|
||||||
|
}
|
||||||
|
return text.length > 10 ? text.slice(0, 10) : text
|
||||||
|
},
|
||||||
|
loadSites() {
|
||||||
|
this.loading = true
|
||||||
|
getAllSites().then(response => {
|
||||||
|
this.allSites = response?.data || []
|
||||||
|
if (this.allSites.length > 0) {
|
||||||
|
this.submitSite(this.allSites[0].siteId)
|
||||||
|
} else {
|
||||||
|
this.updateMapMarkers()
|
||||||
|
}
|
||||||
|
this.$nextTick(() => {
|
||||||
|
this.updateScrollButtons()
|
||||||
|
})
|
||||||
|
}).finally(() => {
|
||||||
|
this.loading = false
|
||||||
|
})
|
||||||
|
},
|
||||||
|
updateScrollButtons() {
|
||||||
|
const container = this.$refs.siteCards
|
||||||
|
if (!container) {
|
||||||
|
this.canScrollLeft = false
|
||||||
|
this.canScrollRight = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const maxScrollLeft = container.scrollWidth - container.clientWidth
|
||||||
|
this.canScrollLeft = container.scrollLeft > 0
|
||||||
|
this.canScrollRight = maxScrollLeft > 0 && container.scrollLeft < maxScrollLeft - 1
|
||||||
|
},
|
||||||
|
scrollSiteCards(direction) {
|
||||||
|
const container = this.$refs.siteCards
|
||||||
|
if (!container) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const amount = Math.max(container.clientWidth * 0.8, 240)
|
||||||
|
const delta = direction === 'left' ? -amount : amount
|
||||||
|
container.scrollBy({ left: delta, behavior: 'smooth' })
|
||||||
|
},
|
||||||
|
updateMapMarkers(){
|
||||||
|
this.$refs.mapChart && this.$refs.mapChart.setOption({
|
||||||
|
selected: {name:this.singleSiteName,value:this.singleSiteLocation},
|
||||||
|
sites:this.allSites
|
||||||
|
})
|
||||||
|
},
|
||||||
// 站点选中
|
// 站点选中
|
||||||
submitSite(id){
|
submitSite(id){
|
||||||
if(this.singleSiteId === id){return console.log(`点击搜索按钮 搜索相同的站点id= ${id}不再调用获取基本信息接口`)}
|
|
||||||
this.loading=true
|
|
||||||
console.log('点击搜索按钮 选中的站点id',id)
|
|
||||||
this.singleSiteId = id
|
this.singleSiteId = id
|
||||||
this.$refs.zdSelect.searchLoading = true
|
const currentSite = this.allSites.find(item => this.isSameSite(item.siteId, id)) || {}
|
||||||
getSingleSiteBaseInfo(id).then(response => {
|
this.singleSiteName = currentSite.siteName || ''
|
||||||
console.log('单个站点详情数据',response)
|
this.singleSiteLocation = currentSite.siteLocation || []
|
||||||
const res = response?.data || {}
|
if (!this.singleSiteLocation.length) {
|
||||||
this.singleSiteName = res?.siteName || ''//站点名称
|
this.singleSiteLocation = [currentSite.longitude, currentSite.latitude].filter(item => item !== undefined && item !== null)
|
||||||
this.singleSiteLocation = res?.siteLocation || []//站点坐标
|
}
|
||||||
this.singleZdSqaure.forEach(item=>{
|
this.$nextTick(() => {
|
||||||
item.value =res[item.attr]
|
this.updateMapMarkers()
|
||||||
})
|
|
||||||
this.singleZdInfo.forEach(item=>{
|
|
||||||
item.value = res[item.attr]
|
|
||||||
})
|
|
||||||
this.$refs.barChart.setOption(res?.sevenDayDisChargeStats || [])
|
|
||||||
this.$refs.mapChart.setOption([{name:this.singleSiteName,value:this.singleSiteLocation}])
|
|
||||||
}).finally(() => {this.$refs.zdSelect.searchLoading = false;this.loading=false})
|
|
||||||
},
|
|
||||||
//跳转单站监控页面
|
|
||||||
toDzjk(){
|
|
||||||
this.$router.push({
|
|
||||||
path:'/dzjk',
|
|
||||||
query:{
|
|
||||||
siteId:this.singleSiteId,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -134,29 +163,119 @@ export default {
|
|||||||
.ems-content-container{
|
.ems-content-container{
|
||||||
display: flex;
|
display: flex;
|
||||||
padding:24px;
|
padding:24px;
|
||||||
padding-right: 0;
|
|
||||||
.map-container{
|
.map-container{
|
||||||
flex:auto;
|
flex:auto;
|
||||||
}
|
min-width: 0;
|
||||||
.zd-msg-container{
|
display: flex;
|
||||||
width: 500px;
|
flex-direction: column;
|
||||||
padding: 24px;
|
gap: 12px;
|
||||||
.single-zd-name{
|
.site-cards-wrapper{
|
||||||
font-weight: 500;
|
display: flex;
|
||||||
line-height: 23px;
|
align-items: center;
|
||||||
color: #FFBD00;
|
gap: 8px;
|
||||||
font-size: 16px;
|
.site-cards-arrow{
|
||||||
margin-bottom: 24px;
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 50%;
|
||||||
|
background: #ffffff;
|
||||||
|
box-shadow: 0 0 0 1px #dcdfe6 inset;
|
||||||
|
color: #606266;
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
transition: all .2s ease;
|
||||||
|
&:hover:not(:disabled){
|
||||||
|
color: #2b74ff;
|
||||||
|
box-shadow: 0 0 0 1px #2b74ff inset;
|
||||||
|
}
|
||||||
|
&:disabled{
|
||||||
|
cursor: not-allowed;
|
||||||
|
color: #c0c4cc;
|
||||||
|
box-shadow: 0 0 0 1px #ebeef5 inset;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.single-square-box-container{
|
.site-cards{
|
||||||
height: 78px;
|
display: flex;
|
||||||
box-sizing: border-box;
|
gap: 10px;
|
||||||
margin-bottom: 10px;
|
overflow-x: auto;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
scrollbar-width: none;
|
||||||
|
-ms-overflow-style: none;
|
||||||
|
&::-webkit-scrollbar{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.site-card{
|
||||||
|
flex: 0 0 360px;
|
||||||
|
height: 166px;
|
||||||
|
border-radius: 8px;
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #e4e7ed;
|
||||||
|
padding: 10px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all .2s ease;
|
||||||
|
.site-card-name{
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #303133;
|
||||||
|
line-height: 22px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.site-card-info-row{
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
gap: 8px;
|
||||||
|
margin-top: 6px;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
.site-card-label{
|
||||||
|
flex: 0 0 84px;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #909399;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
.site-card-value{
|
||||||
|
flex: 1;
|
||||||
|
color: #606266;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.site-card-value--address{
|
||||||
|
white-space: normal;
|
||||||
|
word-break: break-all;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
text-overflow: unset;
|
||||||
|
min-height: 36px;
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
border-color: #c0d3ff;
|
||||||
|
}
|
||||||
|
&.active{
|
||||||
|
border-color: #2b74ff;
|
||||||
|
box-shadow: 0 0 0 1px rgba(43,116,255,.15) inset;
|
||||||
|
background: #f5f9ff;
|
||||||
|
.site-card-name{
|
||||||
|
color: #2b74ff;
|
||||||
|
}
|
||||||
|
.site-card-value{
|
||||||
|
color: #5f8ee3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.single-zd-info-container{
|
.map-view{
|
||||||
font-size: 12px;
|
height: 70vh;
|
||||||
margin-top: 10px;
|
min-height: 520px;
|
||||||
color:#666666;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="login">
|
<div class="login">
|
||||||
<img :src="loginBg" alt="" srcset="" class="login-bg" />
|
<transition :name="bgTransitionName">
|
||||||
|
<img :key="bgNum" :src="loginBg" alt="" srcset="" class="login-bg" />
|
||||||
|
</transition>
|
||||||
<el-form
|
<el-form
|
||||||
ref="loginForm"
|
ref="loginForm"
|
||||||
:model="loginForm"
|
:model="loginForm"
|
||||||
@ -107,6 +109,8 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
bgNum: 1,
|
bgNum: 1,
|
||||||
|
bgTransitionName: "bg-slide",
|
||||||
|
bgTransitionNames: ["bg-slide", "bg-zoom", "bg-blur"],
|
||||||
codeUrl: "",
|
codeUrl: "",
|
||||||
loginForm: {
|
loginForm: {
|
||||||
username: "admin",
|
username: "admin",
|
||||||
@ -148,7 +152,12 @@ export default {
|
|||||||
this.updateInterval(this.updateBgNum, 5000);
|
this.updateInterval(this.updateBgNum, 5000);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
randomBgTransitionName() {
|
||||||
|
const index = Math.floor(Math.random() * this.bgTransitionNames.length);
|
||||||
|
return this.bgTransitionNames[index];
|
||||||
|
},
|
||||||
updateBgNum() {
|
updateBgNum() {
|
||||||
|
this.bgTransitionName = this.randomBgTransitionName();
|
||||||
if (this.bgNum >= 4) this.bgNum = 0;
|
if (this.bgNum >= 4) this.bgNum = 0;
|
||||||
this.bgNum += 1;
|
this.bgNum += 1;
|
||||||
},
|
},
|
||||||
@ -210,6 +219,10 @@ export default {
|
|||||||
|
|
||||||
<style rel="stylesheet/scss" lang="scss">
|
<style rel="stylesheet/scss" lang="scss">
|
||||||
.login {
|
.login {
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
padding-left: 180px;
|
padding-left: 180px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: left;
|
justify-content: left;
|
||||||
@ -224,6 +237,60 @@ export default {
|
|||||||
display: block;
|
display: block;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
object-fit: cover;
|
||||||
|
object-position: center;
|
||||||
|
backface-visibility: hidden;
|
||||||
|
will-change: opacity, transform, filter;
|
||||||
|
}
|
||||||
|
.bg-fade-enter-active,
|
||||||
|
.bg-fade-leave-active {
|
||||||
|
transition: opacity 0.9s ease, transform 0.9s ease;
|
||||||
|
}
|
||||||
|
.bg-fade-enter {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(1.04);
|
||||||
|
}
|
||||||
|
.bg-fade-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.98);
|
||||||
|
}
|
||||||
|
.bg-slide-enter-active,
|
||||||
|
.bg-slide-leave-active {
|
||||||
|
transition: opacity 0.85s ease, transform 0.85s ease;
|
||||||
|
}
|
||||||
|
.bg-slide-enter {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate3d(3.5%, 0, 0) scale(1.01);
|
||||||
|
}
|
||||||
|
.bg-slide-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translate3d(-3.5%, 0, 0) scale(0.99);
|
||||||
|
}
|
||||||
|
.bg-zoom-enter-active,
|
||||||
|
.bg-zoom-leave-active {
|
||||||
|
transition: opacity 1s ease, transform 1s ease;
|
||||||
|
}
|
||||||
|
.bg-zoom-enter {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(1.08);
|
||||||
|
}
|
||||||
|
.bg-zoom-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.94);
|
||||||
|
}
|
||||||
|
.bg-blur-enter-active,
|
||||||
|
.bg-blur-leave-active {
|
||||||
|
transition: opacity 0.9s ease, filter 0.9s ease, transform 0.9s ease;
|
||||||
|
}
|
||||||
|
.bg-blur-enter {
|
||||||
|
opacity: 0;
|
||||||
|
filter: blur(8px);
|
||||||
|
transform: scale(1.02);
|
||||||
|
}
|
||||||
|
.bg-blur-leave-to {
|
||||||
|
opacity: 0;
|
||||||
|
filter: blur(6px);
|
||||||
|
transform: scale(0.98);
|
||||||
}
|
}
|
||||||
.login-logo {
|
.login-logo {
|
||||||
display: block;
|
display: block;
|
||||||
|
|||||||
Reference in New Issue
Block a user