重构
This commit is contained in:
@ -50,4 +50,3 @@ export default {
|
||||
flex: 1;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
137
src/views/ems/dzjk/clpz/runtimeParam/index.vue
Normal file
137
src/views/ems/dzjk/clpz/runtimeParam/index.vue
Normal file
@ -0,0 +1,137 @@
|
||||
<template>
|
||||
<div class="ems-dashboard-editor-container" v-loading="loading">
|
||||
<el-card shadow="always" class="common-card-container">
|
||||
<div slot="header" class="clearfix">
|
||||
<span class="card-title">运行参数配置</span>
|
||||
<span class="site-tag">站点:{{ siteId || '-' }}</span>
|
||||
</div>
|
||||
<el-form ref="form" :model="form" :rules="rules" label-width="180px" style="max-width: 760px;">
|
||||
<el-form-item label="SOC下限(%)" prop="socDown">
|
||||
<el-input-number v-model="form.socDown" :min="0" :max="100" :step="1" :precision="2" controls-position="right" style="width: 220px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="SOC上限(%)" prop="socUp">
|
||||
<el-input-number v-model="form.socUp" :min="0" :max="100" :step="1" :precision="2" controls-position="right" style="width: 220px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="防逆流阈值(kW)" prop="antiReverseThreshold">
|
||||
<el-input-number v-model="form.antiReverseThreshold" :min="0" :step="1" :precision="2" controls-position="right" style="width: 220px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="防逆流阈值上浮比例(%)" prop="antiReverseRangePercent">
|
||||
<el-input-number v-model="form.antiReverseRangePercent" :min="0" :step="1" :precision="2" controls-position="right" style="width: 220px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="防逆流恢复上限(kW)" prop="antiReverseUp">
|
||||
<el-input-number v-model="form.antiReverseUp" :min="0" :step="1" :precision="2" controls-position="right" style="width: 220px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="防逆流降功率比例(%)" prop="antiReversePowerDownPercent">
|
||||
<el-input-number v-model="form.antiReversePowerDownPercent" :min="0" :max="100" :step="1" :precision="2" controls-position="right" style="width: 220px;" />
|
||||
</el-form-item>
|
||||
<el-form-item label="防逆流硬停阈值(kW)" prop="antiReverseHardStopThreshold">
|
||||
<el-input-number v-model="form.antiReverseHardStopThreshold" :min="0" :step="1" :precision="2" controls-position="right" style="width: 220px;" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" :loading="saveLoading" @click="handleSave">保存</el-button>
|
||||
<el-button @click="init">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import getQuerySiteId from '@/mixins/ems/getQuerySiteId'
|
||||
import { getStrategyRuntimeConfig, saveStrategyRuntimeConfig } from '@/api/ems/dzjk'
|
||||
|
||||
const emptyForm = () => ({
|
||||
siteId: '',
|
||||
socDown: 0,
|
||||
socUp: 100,
|
||||
antiReverseThreshold: 30,
|
||||
antiReverseRangePercent: 20,
|
||||
antiReverseUp: 100,
|
||||
antiReversePowerDownPercent: 10,
|
||||
antiReverseHardStopThreshold: 20
|
||||
})
|
||||
|
||||
export default {
|
||||
name: 'DzjkClpzRuntimeParam',
|
||||
mixins: [getQuerySiteId],
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
saveLoading: false,
|
||||
form: emptyForm(),
|
||||
rules: {
|
||||
socDown: [
|
||||
{ required: true, message: '请输入SOC下限', trigger: 'change' }
|
||||
],
|
||||
socUp: [
|
||||
{ required: true, message: '请输入SOC上限', trigger: 'change' }
|
||||
],
|
||||
antiReverseThreshold: [
|
||||
{ required: true, message: '请输入防逆流阈值', trigger: 'change' }
|
||||
],
|
||||
antiReverseRangePercent: [
|
||||
{ required: true, message: '请输入防逆流阈值上浮比例', trigger: 'change' }
|
||||
],
|
||||
antiReverseUp: [
|
||||
{ required: true, message: '请输入防逆流恢复上限', trigger: 'change' }
|
||||
],
|
||||
antiReversePowerDownPercent: [
|
||||
{ required: true, message: '请输入防逆流降功率比例', trigger: 'change' }
|
||||
],
|
||||
antiReverseHardStopThreshold: [
|
||||
{ required: true, message: '请输入防逆流硬停阈值', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
init() {
|
||||
if (!this.siteId) {
|
||||
this.form = emptyForm()
|
||||
return
|
||||
}
|
||||
this.loading = true
|
||||
getStrategyRuntimeConfig(this.siteId).then(response => {
|
||||
const data = response?.data || {}
|
||||
this.form = {
|
||||
...emptyForm(),
|
||||
...data,
|
||||
siteId: this.siteId
|
||||
}
|
||||
}).finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
handleSave() {
|
||||
if (!this.siteId) {
|
||||
this.$message.error('缺少站点ID')
|
||||
return
|
||||
}
|
||||
this.$refs.form.validate(valid => {
|
||||
if (!valid) return
|
||||
if (Number(this.form.socDown) > Number(this.form.socUp)) {
|
||||
this.$message.error('SOC下限不能大于SOC上限')
|
||||
return
|
||||
}
|
||||
this.saveLoading = true
|
||||
saveStrategyRuntimeConfig({ ...this.form, siteId: this.siteId }).then(response => {
|
||||
if (response?.code === 200) {
|
||||
this.$message.success('保存成功')
|
||||
this.init()
|
||||
}
|
||||
}).finally(() => {
|
||||
this.saveLoading = false
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.site-tag {
|
||||
float: right;
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
}
|
||||
</style>
|
||||
@ -9,14 +9,6 @@
|
||||
<el-form-item label="soc限制" prop="sdcLimit" required>
|
||||
<el-switch :active-value="1" :inactive-value="0" v-model="formData.sdcLimit"></el-switch>
|
||||
</el-form-item>
|
||||
<!-- <template v-if="formData.sdcLimit === 1">-->
|
||||
<el-form-item label="soc下限" prop="sdcDown">
|
||||
<el-input v-model="formData.sdcDown" placeholder="请输入" clearable :style="{width: '100%'}"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="soc上限" prop="sdcUp">
|
||||
<el-input v-model="formData.sdcUp" placeholder="请输入" clearable :style="{width: '100%'}"></el-input>
|
||||
</el-form-item>
|
||||
<!-- </template>-->
|
||||
</el-form>
|
||||
<el-button type="primary" size="mini" @click="addTime">新增</el-button>
|
||||
<!-- 新增时间段表单-->
|
||||
@ -64,6 +56,12 @@
|
||||
<el-input v-model="formInline.chargeDischargePower" placeholder="请输入"
|
||||
:style="{width: '100%'}"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="soc下限" prop="sdcDown">
|
||||
<el-input v-model="formInline.sdcDown" placeholder="请输入" clearable :style="{width: '100%'}"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="soc上限" prop="sdcUp">
|
||||
<el-input v-model="formInline.sdcUp" placeholder="请输入" clearable :style="{width: '100%'}"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="充电状态" prop="chargeStatus">
|
||||
<el-select v-model="formInline.chargeStatus" placeholder="请选择" :style="{width: '100%'}">
|
||||
<el-option v-for="(value,key) in chargeStatusOptions" :key="key+'chargeStatusOptions'" :label="value"
|
||||
@ -84,20 +82,100 @@
|
||||
<el-table-column
|
||||
prop="startTime"
|
||||
label="开始时间">
|
||||
<template slot-scope="scope">
|
||||
<el-time-select
|
||||
v-if="mode === 'edit'"
|
||||
v-model="scope.row.startTime"
|
||||
placeholder="开始时间"
|
||||
:picker-options="{
|
||||
start: '00:00',
|
||||
step: '00:01',
|
||||
end: '23:59'
|
||||
}"
|
||||
:style="{width: '100%'}"
|
||||
/>
|
||||
<span v-else>{{ scope.row.startTime || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="endTime"
|
||||
label="结束时间">
|
||||
<template slot-scope="scope">
|
||||
<el-time-select
|
||||
v-if="mode === 'edit'"
|
||||
v-model="scope.row.endTime"
|
||||
placeholder="结束时间"
|
||||
:picker-options="{
|
||||
start: '00:00',
|
||||
step: '00:01',
|
||||
end: '23:59',
|
||||
minTime: scope.row.startTime
|
||||
}"
|
||||
:style="{width: '100%'}"
|
||||
/>
|
||||
<span v-else>{{ scope.row.endTime || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="chargeDischargePower"
|
||||
label="充放功率(kW)">
|
||||
<template slot-scope="scope">
|
||||
<el-input
|
||||
v-if="mode === 'edit'"
|
||||
v-model.trim="scope.row.chargeDischargePower"
|
||||
placeholder="请输入"
|
||||
clearable
|
||||
:style="{width: '100%'}"
|
||||
/>
|
||||
<span v-else>{{ scope.row.chargeDischargePower || '-' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="sdcDown"
|
||||
label="SOC下限">
|
||||
<template slot-scope="scope">
|
||||
<el-input
|
||||
v-if="mode === 'edit'"
|
||||
v-model.trim="scope.row.sdcDown"
|
||||
placeholder="请输入"
|
||||
clearable
|
||||
:style="{width: '100%'}"
|
||||
/>
|
||||
<span v-else>{{ scope.row.sdcDown === null || scope.row.sdcDown === undefined || scope.row.sdcDown === '' ? '-' : scope.row.sdcDown + '%' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="sdcUp"
|
||||
label="SOC上限">
|
||||
<template slot-scope="scope">
|
||||
<el-input
|
||||
v-if="mode === 'edit'"
|
||||
v-model.trim="scope.row.sdcUp"
|
||||
placeholder="请输入"
|
||||
clearable
|
||||
:style="{width: '100%'}"
|
||||
/>
|
||||
<span v-else>{{ scope.row.sdcUp === null || scope.row.sdcUp === undefined || scope.row.sdcUp === '' ? '-' : scope.row.sdcUp + '%' }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="chargeStatus"
|
||||
label="充电状态">
|
||||
<template slot-scope="scope">
|
||||
{{ chargeStatusOptions[scope.row.chargeStatus] }}
|
||||
<el-select
|
||||
v-if="mode === 'edit'"
|
||||
v-model="scope.row.chargeStatus"
|
||||
placeholder="请选择"
|
||||
:style="{width: '100%'}"
|
||||
>
|
||||
<el-option
|
||||
v-for="(value,key) in chargeStatusOptions"
|
||||
:key="key+'chargeStatusEditOptions'"
|
||||
:label="value"
|
||||
:value="key"
|
||||
/>
|
||||
</el-select>
|
||||
<span v-else>{{ chargeStatusOptions[scope.row.chargeStatus] }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
@ -138,8 +216,6 @@ export default {
|
||||
formData: {
|
||||
templateName: '',
|
||||
sdcLimit: false,
|
||||
sdcDown: '',
|
||||
sdcUp: '',
|
||||
},
|
||||
rules: {
|
||||
templateName: [{
|
||||
@ -147,19 +223,13 @@ export default {
|
||||
message: '请输入',
|
||||
trigger: 'blur'
|
||||
}],
|
||||
sdcDown: [
|
||||
{required: true, message: '请输入', trigger: 'blur'},
|
||||
{pattern: /^(0|[1-9]\d*)(\.\d+)?$/, message: '请输入合法数字或小数'}
|
||||
],
|
||||
sdcUp: [
|
||||
{required: true, message: '请输入', trigger: 'blur'},
|
||||
{pattern: /^(0|[1-9]\d*)(\.\d+)?$/, message: '请输入合法数字或小数'}
|
||||
],
|
||||
},
|
||||
showAddTime: false,
|
||||
formInline: {
|
||||
timeRange: range,
|
||||
chargeDischargePower: '',
|
||||
sdcDown: '',
|
||||
sdcUp: '',
|
||||
chargeStatus: ''
|
||||
},
|
||||
formInlineRule: {
|
||||
@ -175,6 +245,14 @@ export default {
|
||||
},
|
||||
{pattern: /^-?\d*\.?\d*$/, message: '请输入合法数字或小数'}
|
||||
],
|
||||
sdcDown: [
|
||||
{required: true, message: '请输入', trigger: 'blur'},
|
||||
{pattern: /^(0|[1-9]\d*)(\.\d+)?$/, message: '请输入合法数字或小数'}
|
||||
],
|
||||
sdcUp: [
|
||||
{required: true, message: '请输入', trigger: 'blur'},
|
||||
{pattern: /^(0|[1-9]\d*)(\.\d+)?$/, message: '请输入合法数字或小数'}
|
||||
],
|
||||
chargeStatus: [{
|
||||
required: true,
|
||||
message: '请选择充放状态',
|
||||
@ -198,11 +276,9 @@ export default {
|
||||
this.formData = {
|
||||
templateName: '',
|
||||
sdcLimit: false,
|
||||
sdcDown: '',
|
||||
sdcUp: '',
|
||||
}
|
||||
this.formInline = {
|
||||
timeRange: this.secondRange, chargeDischargePower: '', chargeStatus: ''
|
||||
timeRange: this.secondRange, chargeDischargePower: '', sdcDown: '', sdcUp: '', chargeStatus: ''
|
||||
}//startTime: '', endTime: '',
|
||||
this.showAddTime = false
|
||||
this.tableData = []
|
||||
@ -216,14 +292,12 @@ export default {
|
||||
getStrategyTempDetail(this.editTempId).then(response => {
|
||||
const data = JSON.parse(JSON.stringify(response?.data || []));
|
||||
if (data.length > 0) {
|
||||
const {templateName, sdcLimit, sdcDown, sdcUp} = JSON.parse(JSON.stringify(data[0]));
|
||||
const {templateName, sdcLimit} = JSON.parse(JSON.stringify(data[0]));
|
||||
this.formData.templateName = templateName
|
||||
this.formData.sdcLimit = sdcLimit
|
||||
this.formData.sdcDown = sdcDown
|
||||
this.formData.sdcUp = sdcUp
|
||||
}
|
||||
if (data.length === 1) {
|
||||
const {startTime, endTime} = data;
|
||||
const {startTime, endTime} = data[0];
|
||||
if (!startTime || !endTime) {
|
||||
this.tableData = []
|
||||
} else {
|
||||
@ -242,15 +316,15 @@ export default {
|
||||
cancelAddTime() {
|
||||
this.$refs.addTimeForm.resetFields()
|
||||
this.showAddTime = false
|
||||
this.formInline = {timeRange: this.secondRange, chargeDischargePower: '', chargeStatus: ''}//startTime: '', endTime: '',
|
||||
this.formInline = {timeRange: this.secondRange, chargeDischargePower: '', sdcDown: '', sdcUp: '', chargeStatus: ''}//startTime: '', endTime: '',
|
||||
},
|
||||
saveTime() {
|
||||
//表单校验,校验成功,添加到tableData里
|
||||
this.$refs.addTimeForm.validate(valid => {
|
||||
if (!valid) return
|
||||
const {timeRange: [startTime, endTime], chargeDischargePower, chargeStatus} = this.formInline
|
||||
const {timeRange: [startTime, endTime], chargeDischargePower, sdcDown, sdcUp, chargeStatus} = this.formInline
|
||||
|
||||
this.tableData.push({startTime, endTime, chargeDischargePower, chargeStatus})
|
||||
this.tableData.push({startTime, endTime, chargeDischargePower, sdcDown, sdcUp, chargeStatus})
|
||||
this.$nextTick(() => {
|
||||
this.cancelAddTime()
|
||||
})
|
||||
@ -262,9 +336,14 @@ export default {
|
||||
saveDialog() {
|
||||
this.$refs.addTempForm.validate(valid => {
|
||||
if (!valid) return
|
||||
const {templateName, sdcLimit, sdcDown, sdcUp} = this.formData
|
||||
const {templateName, sdcLimit} = this.formData
|
||||
const {siteId, updateStrategyId} = this.$home
|
||||
const {tableData} = this
|
||||
const tableData = this.tableData.map(item => ({
|
||||
...item,
|
||||
sdcDown: this.normalizeSocValue(item.sdcDown),
|
||||
sdcUp: this.normalizeSocValue(item.sdcUp)
|
||||
}))
|
||||
if (!this.validateTableData(tableData)) return
|
||||
if (this.mode === 'edit') {
|
||||
editStrategyTemp({
|
||||
siteId,
|
||||
@ -272,8 +351,6 @@ export default {
|
||||
templateId: this.editTempId,
|
||||
templateName,
|
||||
sdcLimit,
|
||||
sdcDown,
|
||||
sdcUp,
|
||||
timeConfigList: tableData
|
||||
}).then(response => {
|
||||
if (response?.code === 200) {
|
||||
@ -288,8 +365,6 @@ export default {
|
||||
strategyId: updateStrategyId,
|
||||
templateName,
|
||||
sdcLimit,
|
||||
sdcDown,
|
||||
sdcUp,
|
||||
timeConfigList: tableData
|
||||
}).then(response => {
|
||||
if (response?.code === 200) {
|
||||
@ -300,14 +375,64 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
normalizeSocValue(value) {
|
||||
if (value === null || value === undefined) return null
|
||||
const normalized = String(value).replace('%', '').trim()
|
||||
return normalized === '' ? null : normalized
|
||||
},
|
||||
toMinutes(timeValue) {
|
||||
if (!timeValue || String(timeValue).indexOf(':') < 0) return -1
|
||||
const [h, m] = String(timeValue).split(':')
|
||||
const hour = Number(h), minute = Number(m)
|
||||
if (!Number.isInteger(hour) || !Number.isInteger(minute)) return -1
|
||||
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) return -1
|
||||
return hour * 60 + minute
|
||||
},
|
||||
validateTableData(list = []) {
|
||||
const numberPattern = /^-?\d+(\.\d+)?$/
|
||||
const socPattern = /^(0|[1-9]\d*)(\.\d+)?$/
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const row = list[i]
|
||||
const rowNo = i + 1
|
||||
if (!row.startTime || !row.endTime) {
|
||||
this.$message.error(`第${rowNo}行:开始时间和结束时间不能为空`)
|
||||
return false
|
||||
}
|
||||
const startMinute = this.toMinutes(row.startTime)
|
||||
const endMinute = this.toMinutes(row.endTime)
|
||||
if (startMinute < 0 || endMinute < 0 || startMinute >= endMinute) {
|
||||
this.$message.error(`第${rowNo}行:时间范围不合法`)
|
||||
return false
|
||||
}
|
||||
if (!numberPattern.test(String(row.chargeDischargePower ?? '').trim())) {
|
||||
this.$message.error(`第${rowNo}行:充放功率格式不正确`)
|
||||
return false
|
||||
}
|
||||
if (!socPattern.test(String(row.sdcDown ?? '').trim())) {
|
||||
this.$message.error(`第${rowNo}行:SOC下限格式不正确`)
|
||||
return false
|
||||
}
|
||||
if (!socPattern.test(String(row.sdcUp ?? '').trim())) {
|
||||
this.$message.error(`第${rowNo}行:SOC上限格式不正确`)
|
||||
return false
|
||||
}
|
||||
if (Number(row.sdcDown) > Number(row.sdcUp)) {
|
||||
this.$message.error(`第${rowNo}行:SOC下限不能大于SOC上限`)
|
||||
return false
|
||||
}
|
||||
if (row.chargeStatus === undefined || row.chargeStatus === null || row.chargeStatus === '') {
|
||||
this.$message.error(`第${rowNo}行:请选择充电状态`)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
},
|
||||
closeDialog() {
|
||||
// 清空所有数据
|
||||
this.$refs.addTempForm.resetFields()
|
||||
this.formData = {
|
||||
templateName: '',
|
||||
sdcLimit: 0,
|
||||
sdcDown: '',
|
||||
sdcUp: '',
|
||||
}
|
||||
this.tableData = []
|
||||
this.cancelAddTime()
|
||||
@ -322,4 +447,4 @@ export default {
|
||||
max-height: 90vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@ -39,14 +39,14 @@
|
||||
prop="sdcDown"
|
||||
label="SOC下限">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.sdcDown ? scope.row. sdcDown + '%' : '-'}}
|
||||
{{scope.row.sdcDown === null || scope.row.sdcDown === undefined || scope.row.sdcDown === '' ? '-' : scope.row.sdcDown + '%'}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
prop="sdcUp"
|
||||
label="SOC上限">
|
||||
<template slot-scope="scope">
|
||||
{{scope.row.sdcUp ? scope.row.sdcUp + '%' : '-'}}
|
||||
{{scope.row.sdcUp === null || scope.row.sdcUp === undefined || scope.row.sdcUp === '' ? '-' : scope.row.sdcUp + '%'}}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
@ -92,7 +92,7 @@ export default {
|
||||
activeBtn:'',
|
||||
tempList:[],
|
||||
tableData:[],
|
||||
mixinPrototype:['templateName','sdcLimit','sdcDown','sdcUp']
|
||||
mixinPrototype:['templateName','sdcLimit']
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
|
||||
@ -12,7 +12,8 @@
|
||||
import * as echarts from 'echarts'
|
||||
import resize from '@/mixins/ems/resize'
|
||||
import DateRangeSelect from '@/components/Ems/DateRangeSelect/index.vue'
|
||||
import {getPointData} from '@/api/ems/dzjk'
|
||||
import {getProjectDisplayData} from '@/api/ems/dzjk'
|
||||
import {getPointConfigCurve} from '@/api/ems/site'
|
||||
import intervalUpdate from "@/mixins/ems/intervalUpdate";
|
||||
|
||||
export default {
|
||||
@ -48,8 +49,34 @@ export default {
|
||||
getGVQXData() {
|
||||
this.showLoading()
|
||||
const {siteId, timeRange} = this
|
||||
getPointData({siteId, startDate: timeRange[0], endDate: timeRange[1]}).then(response => {
|
||||
this.setOption(response?.data || [])
|
||||
getProjectDisplayData(siteId).then(response => {
|
||||
const displayData = response?.data || []
|
||||
const sectionRows = displayData.filter(item =>
|
||||
item && item.sectionName === '当日功率曲线' && item.useFixedDisplay !== 1 && item.dataPoint
|
||||
)
|
||||
const tasks = sectionRows.map(row => {
|
||||
const pointId = String(row.dataPoint || '').trim()
|
||||
if (!pointId) return Promise.resolve(null)
|
||||
return getPointConfigCurve({
|
||||
siteId,
|
||||
pointId,
|
||||
pointType: 'data',
|
||||
rangeType: 'custom',
|
||||
startTime: this.normalizeDateTime(timeRange[0], false),
|
||||
endTime: this.normalizeDateTime(timeRange[1], true)
|
||||
}).then(curveResponse => {
|
||||
const list = curveResponse?.data || []
|
||||
return {
|
||||
name: row.fieldName || row.fieldCode || pointId,
|
||||
data: list
|
||||
.map(item => [this.parseToTimestamp(item.dataTime), Number(item.pointValue)])
|
||||
.filter(item => item[0] && !Number.isNaN(item[1]))
|
||||
}
|
||||
}).catch(() => null)
|
||||
})
|
||||
return Promise.all(tasks)
|
||||
}).then(series => {
|
||||
this.setOption((series || []).filter(Boolean))
|
||||
}).finally(() => this.hideLoading())
|
||||
},
|
||||
init(siteId) {
|
||||
@ -70,12 +97,18 @@ export default {
|
||||
hideLoading() {
|
||||
this.chart && this.chart.hideLoading()
|
||||
},
|
||||
setOption(data) {
|
||||
const source = [['日期', '电网功率', '负载功率', '储能功率', '光伏功率', 'soc平均值', 'soh平均值', '电池平均温度平均值']]
|
||||
console.log('source.slice(1)', source[0].slice(1))
|
||||
this.chart && data.forEach((item) => {
|
||||
source.push([item.statisDate, item.gridPower, item.loadPower, item.storagePower, item.pvPower, item.avgSoc, item.avgSoh, item.avgTemp])
|
||||
})
|
||||
normalizeDateTime(value, endOfDay) {
|
||||
const raw = String(value || '').trim()
|
||||
if (!raw) return ''
|
||||
if (raw.includes(' ')) return raw
|
||||
return `${raw} ${endOfDay ? '23:59:59' : '00:00:00'}`
|
||||
},
|
||||
parseToTimestamp(value) {
|
||||
if (!value) return null
|
||||
const t = new Date(value).getTime()
|
||||
return Number.isNaN(t) ? null : t
|
||||
},
|
||||
setOption(seriesData = []) {
|
||||
this.chart.setOption({
|
||||
grid: {
|
||||
containLabel: true
|
||||
@ -86,35 +119,28 @@ export default {
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { // 坐标轴指示器,坐标轴触发有效
|
||||
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
|
||||
}
|
||||
axisPointer: { type: 'cross' }
|
||||
},
|
||||
textStyle: {
|
||||
color: "#333333",
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
type: 'time',
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
},
|
||||
],
|
||||
dataset: {source},
|
||||
series: source[0].slice(1).map((item, index) => {
|
||||
yAxis: [{
|
||||
type: 'value',
|
||||
}],
|
||||
series: seriesData.map((item) => {
|
||||
return {
|
||||
type: 'line',//index === 5 ? 'bar' : 'line',
|
||||
name: item.name,
|
||||
type: 'line',
|
||||
showSymbol: false,
|
||||
symbolSize: 2,
|
||||
smooth: true,
|
||||
areaStyle: {
|
||||
opacity: 0.5,
|
||||
},
|
||||
yAxisIndex: index <= 4 ? 0 : 1
|
||||
data: item.data
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -124,4 +150,3 @@ export default {
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@ -12,7 +12,8 @@
|
||||
import * as echarts from 'echarts'
|
||||
import resize from '@/mixins/ems/resize'
|
||||
import DateRangeSelect from '@/components/Ems/DateRangeSelect/index.vue'
|
||||
import {getSevenChargeData} from '@/api/ems/dzjk'
|
||||
import {getProjectDisplayData} from '@/api/ems/dzjk'
|
||||
import {getPointConfigCurve} from '@/api/ems/site'
|
||||
|
||||
export default {
|
||||
mixins: [resize],
|
||||
@ -45,8 +46,34 @@ export default {
|
||||
getWeekKData() {
|
||||
this.showLoading()
|
||||
const {siteId, timeRange} = this
|
||||
getSevenChargeData({siteId, startDate: timeRange[0], endDate: timeRange[1]}).then(response => {
|
||||
this.setOption(response?.data || [])
|
||||
getProjectDisplayData(siteId).then(response => {
|
||||
const displayData = response?.data || []
|
||||
const sectionRows = displayData.filter(item =>
|
||||
item && item.sectionName === '一周充放曲线' && item.useFixedDisplay !== 1 && item.dataPoint
|
||||
)
|
||||
const tasks = sectionRows.map(row => {
|
||||
const pointId = String(row.dataPoint || '').trim()
|
||||
if (!pointId) return Promise.resolve(null)
|
||||
return getPointConfigCurve({
|
||||
siteId,
|
||||
pointId,
|
||||
pointType: 'data',
|
||||
rangeType: 'custom',
|
||||
startTime: this.normalizeDateTime(timeRange[0], false),
|
||||
endTime: this.normalizeDateTime(timeRange[1], true)
|
||||
}).then(curveResponse => {
|
||||
const list = curveResponse?.data || []
|
||||
return {
|
||||
name: row.fieldName || row.fieldCode || pointId,
|
||||
data: list
|
||||
.map(item => [this.parseToTimestamp(item.dataTime), Number(item.pointValue)])
|
||||
.filter(item => item[0] && !Number.isNaN(item[1]))
|
||||
}
|
||||
}).catch(() => null)
|
||||
})
|
||||
return Promise.all(tasks)
|
||||
}).then(series => {
|
||||
this.setOption((series || []).filter(Boolean))
|
||||
}).finally(() => this.hideLoading())
|
||||
},
|
||||
init(siteId) {
|
||||
@ -65,18 +92,23 @@ export default {
|
||||
hideLoading() {
|
||||
this.chart && this.chart.hideLoading()
|
||||
},
|
||||
setOption(data, unit) {
|
||||
const source = [['日期', '充电量', '放电量']]
|
||||
data.forEach(item => {
|
||||
source.push([item.ammeterDate, item.chargedCap, item.disChargedCap])
|
||||
})
|
||||
normalizeDateTime(value, endOfDay) {
|
||||
const raw = String(value || '').trim()
|
||||
if (!raw) return ''
|
||||
if (raw.includes(' ')) return raw
|
||||
return `${raw} ${endOfDay ? '23:59:59' : '00:00:00'}`
|
||||
},
|
||||
parseToTimestamp(value) {
|
||||
if (!value) return null
|
||||
const t = new Date(value).getTime()
|
||||
return Number.isNaN(t) ? null : t
|
||||
},
|
||||
setOption(seriesData = []) {
|
||||
this.chart && this.chart.setOption({
|
||||
color: ['#4472c4', '#70ad47'],//所有充放电颜色保持统一
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { // 坐标轴指示器,坐标轴触发有效
|
||||
type: 'shadow' // 默认为直线,可选为:'line' | 'shadow'
|
||||
}
|
||||
axisPointer: { type: 'cross' }
|
||||
},
|
||||
grid: {
|
||||
containLabel: true
|
||||
@ -86,9 +118,7 @@ export default {
|
||||
bottom: '15',
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
name: unit,
|
||||
nameLocation: 'center'
|
||||
type: 'time'
|
||||
},
|
||||
yAxis: [{
|
||||
type: 'value',
|
||||
@ -100,19 +130,12 @@ export default {
|
||||
onZero: false
|
||||
}
|
||||
}],
|
||||
dataset: {
|
||||
source
|
||||
},
|
||||
series: [
|
||||
{
|
||||
yAxisIndex: 0,
|
||||
type: 'bar',
|
||||
},
|
||||
{
|
||||
yAxisIndex: 0,
|
||||
type: 'bar',
|
||||
},
|
||||
]
|
||||
series: seriesData.map(item => ({
|
||||
name: item.name,
|
||||
yAxisIndex: 0,
|
||||
type: 'bar',
|
||||
data: item.data
|
||||
}))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div v-loading="loading">
|
||||
<div>
|
||||
<el-row style="background: #fff" class="row-container" :gutter="15">
|
||||
<el-col :xs="24" :sm="24" :lg="5">
|
||||
<!-- 站点信息-->
|
||||
@ -21,13 +21,19 @@
|
||||
<div class="title">
|
||||
<i class="el-icon-location"></i>
|
||||
</div>
|
||||
<div class="value">{{ info.siteAddress }}</div>
|
||||
<div class="value">
|
||||
<i v-if="isBaseInfoLoading" class="el-icon-loading"></i>
|
||||
<span v-else>{{ info.siteAddress || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="site-info">
|
||||
<div class="title">
|
||||
<i class="el-icon-date"></i>
|
||||
</div>
|
||||
<div class="value">{{ info.runningTime || '-' }}</div>
|
||||
<div class="value">
|
||||
<i v-if="isBaseInfoLoading" class="el-icon-loading"></i>
|
||||
<span v-else>{{ info.runningTime || '-' }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 装机功率、容量 -->
|
||||
<el-row :gutter="10" style="margin-top:20px;">
|
||||
@ -38,7 +44,8 @@
|
||||
<div class="sjgl-wrapper">
|
||||
<div class="sjgl-title">装机功率(MW)</div>
|
||||
<div class="sjgl-value">
|
||||
{{ info.installPower | formatNumber }}
|
||||
<i v-if="isBaseInfoLoading" class="el-icon-loading"></i>
|
||||
<span v-else>{{ info.installPower | formatNumber }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
@ -49,7 +56,8 @@
|
||||
<div class="sjgl-wrapper">
|
||||
<div class="sjgl-title">装机容量(MW)</div>
|
||||
<div class="sjgl-value">
|
||||
{{ info.installCapacity | formatNumber }}
|
||||
<i v-if="isBaseInfoLoading" class="el-icon-loading"></i>
|
||||
<span v-else>{{ info.installCapacity | formatNumber }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
@ -67,7 +75,10 @@
|
||||
<span class="card-title">总累计运行数据</span>
|
||||
<div class="total-count">
|
||||
<span class="title">总收入</span>
|
||||
<span class="value">{{ runningInfo.totalRevenue | formatNumber }}</span>
|
||||
<span class="value">
|
||||
<i v-if="isRunningInfoLoading" class="el-icon-loading"></i>
|
||||
<span v-else>{{ totalRevenueDisplayValue | formatNumber }}</span>
|
||||
</span>
|
||||
<span class="unit">元</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -77,14 +88,15 @@
|
||||
<el-row :gutter="10">
|
||||
<el-col
|
||||
:span="6"
|
||||
v-for="(item, index) in sjglData"
|
||||
v-for="(item, index) in runningDataCards"
|
||||
:key="index + 'sjglData'"
|
||||
class="sjgl-col"
|
||||
>
|
||||
<div class="sjgl-wrapper">
|
||||
<div class="sjgl-title">{{ item.title }}</div>
|
||||
<div class="sjgl-value" :style="{color:item.color}">
|
||||
{{ runningInfo[item.attr] | formatNumber }}
|
||||
<i v-if="item.loading" class="el-icon-loading"></i>
|
||||
<span v-else>{{ item.value | formatNumber }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</el-col>
|
||||
@ -104,7 +116,7 @@
|
||||
|
||||
<script>
|
||||
import {getSingleSiteBaseInfo} from "@/api/ems/zddt";
|
||||
import {getDzjkHomeView} from "@/api/ems/dzjk";
|
||||
import {getDzjkHomeView, getProjectDisplayData} from "@/api/ems/dzjk";
|
||||
import WeekChart from "./WeekChart.vue";
|
||||
import ActiveChart from "./ActiveChart.vue";
|
||||
import AlarmTable from "./AlarmTable.vue";
|
||||
@ -119,7 +131,9 @@ export default {
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
sjglData: [
|
||||
baseInfoLoading: false,
|
||||
runningInfoLoading: false,
|
||||
fallbackSjglData: [
|
||||
{
|
||||
title: "今日充电量(kWh)",
|
||||
attr: "dayChargedCap",
|
||||
@ -163,38 +177,106 @@ export default {
|
||||
],
|
||||
info: {}, //基本信息
|
||||
runningInfo: {}, //总累计运行数据+报警表格
|
||||
runningDisplayData: [], //单站监控项目配置展示数据
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isBaseInfoLoading() {
|
||||
const state = this.$data || {};
|
||||
return !!(state.baseInfoLoading || state.loading);
|
||||
},
|
||||
isRunningInfoLoading() {
|
||||
const state = this.$data || {};
|
||||
return !!(state.runningInfoLoading || state.loading);
|
||||
},
|
||||
tableData() {
|
||||
return this.runningInfo?.siteMonitorHomeAlarmVo || [];
|
||||
},
|
||||
totalRunningSectionData() {
|
||||
return (this.runningDisplayData || []).filter(item => item.sectionName === "总累计运行数据");
|
||||
},
|
||||
totalRevenueDisplayItem() {
|
||||
const sectionData = this.totalRunningSectionData || [];
|
||||
const byFieldCode = sectionData.find(item => item.fieldCode === "totalRevenue");
|
||||
if (byFieldCode) {
|
||||
return byFieldCode;
|
||||
}
|
||||
return sectionData.find(item => item.fieldName === "总收入");
|
||||
},
|
||||
totalRevenueDisplayValue() {
|
||||
return this.totalRevenueDisplayItem ? this.totalRevenueDisplayItem.fieldValue : this.runningInfo.totalRevenue;
|
||||
},
|
||||
runningDataCards() {
|
||||
const sectionData = this.totalRunningSectionData || [];
|
||||
if (sectionData.length > 0) {
|
||||
const revenueFieldCode = this.totalRevenueDisplayItem ? this.totalRevenueDisplayItem.fieldCode : "";
|
||||
return sectionData
|
||||
.filter(item => item.fieldCode !== revenueFieldCode)
|
||||
.map((item, index) => ({
|
||||
title: item.fieldName,
|
||||
value: item.fieldValue,
|
||||
color: this.getCardColor(index),
|
||||
loading: this.isRunningInfoLoading,
|
||||
}));
|
||||
}
|
||||
return this.fallbackSjglData.map(item => ({
|
||||
title: item.title,
|
||||
value: this.runningInfo[item.attr],
|
||||
color: item.color,
|
||||
loading: this.isRunningInfoLoading,
|
||||
}));
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
setBaseInfoLoading(loading) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.$data, "baseInfoLoading")) {
|
||||
this.baseInfoLoading = loading;
|
||||
return;
|
||||
}
|
||||
this.$set(this.$data, "baseInfoLoading", loading);
|
||||
},
|
||||
setRunningInfoLoading(loading) {
|
||||
if (Object.prototype.hasOwnProperty.call(this.$data, "runningInfoLoading")) {
|
||||
this.runningInfoLoading = loading;
|
||||
return;
|
||||
}
|
||||
this.$set(this.$data, "runningInfoLoading", loading);
|
||||
},
|
||||
getCardColor(index) {
|
||||
const colors = ['#4472c4', '#70ad47', '#4472c4', '#f67438', '#4472c4', '#70ad47', '#70ad47', '#f67438'];
|
||||
return colors[index % colors.length];
|
||||
},
|
||||
toAlarm() {
|
||||
this.$router.push({path: "/dzjk/gzgj", query: this.$route.query});
|
||||
},
|
||||
getBaseInfo() {
|
||||
this.setBaseInfoLoading(true);
|
||||
return getSingleSiteBaseInfo(this.siteId).then((response) => {
|
||||
this.info = response?.data || {};
|
||||
}).finally(() => {
|
||||
this.setBaseInfoLoading(false);
|
||||
});
|
||||
},
|
||||
getRunningInfo() {
|
||||
return getDzjkHomeView(this.siteId).then((response) => {
|
||||
this.runningInfo = response?.data || {};
|
||||
this.setRunningInfoLoading(true);
|
||||
return Promise.all([
|
||||
getDzjkHomeView(this.siteId),
|
||||
getProjectDisplayData(this.siteId),
|
||||
]).then(([homeResponse, displayResponse]) => {
|
||||
this.runningInfo = homeResponse?.data || {};
|
||||
this.runningDisplayData = displayResponse?.data || [];
|
||||
}).finally(() => {
|
||||
this.setRunningInfoLoading(false);
|
||||
});
|
||||
},
|
||||
init() {
|
||||
this.loading = true;
|
||||
// 功率曲线
|
||||
this.$refs.activeChart.init(this.siteId);
|
||||
// 一周冲放曲线
|
||||
this.$refs.weekChart.init(this.siteId);
|
||||
// 静态信息 this.getBaseInfo()
|
||||
// 总累计运行数据+故障告警 this.getRunningInfo()
|
||||
Promise.all([this.getBaseInfo(), this.getRunningInfo()]).finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
Promise.all([this.getBaseInfo(), this.getRunningInfo()]);
|
||||
// 一分钟循环一次总累计运行数据
|
||||
this.updateInterval(this.getRunningInfo);
|
||||
},
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
|
||||
<template>
|
||||
<div class="ems-dashboard-editor-container">
|
||||
<zd-select :get-list-by-store="true" :default-site-id="$route.query.siteId" @submitSite="submitSite"/>
|
||||
<el-menu
|
||||
class="ems-second-menu"
|
||||
:default-active="$route.meta.activeSecondMenuName"
|
||||
@ -28,11 +27,8 @@
|
||||
<script>
|
||||
import { dzjk } from '@/router/ems'
|
||||
const childrenRoute = dzjk[0].children[0].children//获取到单站监控下面的字路由
|
||||
console.log('childrenRoute',childrenRoute)
|
||||
import ZdSelect from '@/components/Ems/ZdSelect/index.vue'
|
||||
import {mapState} from "vuex";
|
||||
export default {
|
||||
components:{ZdSelect},
|
||||
data(){
|
||||
return {
|
||||
childrenRoute,
|
||||
@ -44,18 +40,6 @@ export default {
|
||||
dzjkAlarmLighting:state=>state.ems.dzjkAlarmLighting
|
||||
})
|
||||
},
|
||||
methods:{
|
||||
submitSite(id){
|
||||
if(id !== this.$route.query.siteId){
|
||||
// console.log('单站监控选择了其他的站点id=',id,'并更新页面地址参数')
|
||||
this.$router.push({query:{...this.$route.query,siteId:id}})
|
||||
}else{
|
||||
// console.log('单站监控选择了相同的其他的站点id=',id,'页面地址不发生改变')
|
||||
}
|
||||
//获取告警列表数据
|
||||
this.$store.dispatch('getSiteAlarmNum',id)
|
||||
}
|
||||
},
|
||||
beforeRouteLeave(to,from, next){
|
||||
//从单站监控下面的所有子页面跳出时会触发
|
||||
// 清空store中的zdList 保障下次进入到单站监控会重新调用接口获取数据
|
||||
@ -66,6 +50,9 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.ems-dashboard-editor-container{
|
||||
padding-top: 12px;
|
||||
}
|
||||
.dzjk-ems-content-container{
|
||||
margin-top:0;
|
||||
min-height: 60vh;
|
||||
|
||||
Reference in New Issue
Block a user