修改策略管理

This commit is contained in:
lixiaoyuan
2026-03-17 15:21:28 +08:00
parent f7419a63fa
commit 3e36135f11
4 changed files with 222 additions and 101 deletions

View File

@@ -686,6 +686,7 @@ Errcode HttpEntity::updateStation(const httplib::Request& req, njson& json, std:
}
}
}
// 发送指令到网关
if (params.contains("station_id") && params.contains("work_mode"))
{
int stationId = params.get<int>("station_id");
@@ -694,6 +695,53 @@ Errcode HttpEntity::updateStation(const httplib::Request& req, njson& json, std:
if (station)
{
station->setGarewayWorkMode();
// 根据 work_mode 到数据库查询策略信息
std::string sql = std::format("select * from policy where `type`='{}'", workmode);
std::vector<Fields> result;
int ret = DaoEntity::execOnce(sql, result);
if (result.size() > 0)
{
auto& item = result[0];
std::string valJson = item.value("value");
njson json = njson::parse(valJson);
if (json.is_object())
{
// 设置 station 的网关参数,然后调用 setGarewayParams 向网关发送指令
if (workmode == 6)
{
if (json.contains("soc_min")) { station->gatewayParam.socMin = Utils::toFloat(json["soc_min"])*100; }
if (json.contains("soc_max")) { station->gatewayParam.socMax = Utils::toFloat(json["soc_max"])*100; }
}
else if (workmode == 7)
{
//if (json.contains("charge")) { station->gatewayParam.powerCharge = json["charge"].get<float>(); }
//if (json.contains("discharge")) { station->gatewayParam.powerDischarge = json["discharge"].get<float>(); }
}
else if (workmode == 8)
{
if (json.contains("charge")) { station->gatewayParam.powerCharge = Utils::toInt(json["charge"]); }
if (json.contains("discharge")) { station->gatewayParam.powerDischarge = Utils::toInt(json["discharge"]); }
if (json.contains("power_reverse")) { station->gatewayParam.backflow = Utils::toInt(json["power_reverse"]); }
}
else if (workmode == 9)
{
if (json.contains("charge")) { station->gatewayParam.powerCharge = Utils::toInt(json["charge"]); }
if (json.contains("discharge")) { station->gatewayParam.powerDischarge = Utils::toInt(json["discharge"]); }
}
}
//station->setGarewayParams();
}
////params.get("work_mode", station->workMode);
//ps.get("soc_min", station->gatewayParam.socMin); // 储能放电下限值 SOC 40038 (%, 0-99)
//ps.get("soc_max", station->gatewayParam.socMax); // 储能充电上限值 SOC 40039 (%:1-100)
//ps.get("capacity", station->gatewayParam.capacity); // 台区变压器容量 40040 (KVA 160-1600)
//ps.get("power_safe", station->gatewayParam.powerSafe); // 安全输入功率 40041 (KW 0-400)
//ps.get("power_discharge", station->gatewayParam.powerDischarge); // 储能最大放电功率 40042 (1KW 0-150)
//ps.get("power_charge", station->gatewayParam.powerCharge); // 储能最大充电功率 40043 (1KW 0-150)
//ps.get("backflow", station->gatewayParam.backflow); // 防逆流回差 40058(1KW 10-300)
//ps.get("overload", station->gatewayParam.overload); // 防过载回差 40059(1KW 10-300)
}
}
return err;

View File

@@ -51,6 +51,8 @@ public:
Errcode queryStationList(const httplib::Request& req, njson& json, std::string& errmsg);
Errcode insertStation(const httplib::Request& req, njson& json, std::string& errmsg);
// 参数中有work_mode时发送指令到网关
Errcode updateStation(const httplib::Request& req, njson& json, std::string& errmsg);
Errcode deleteStation(const httplib::Request& req, njson& json, std::string& errmsg);
@@ -125,6 +127,7 @@ public:
Errcode updateServiceApi(const httplib::Request& req, njson& json, std::string& errmsg);
Errcode deleteServiceApi(const httplib::Request& req, njson& json, std::string& errmsg);
// 更新网关参数
Errcode updateGatewayParams(const httplib::Request& req, njson& json, std::string& errmsg);
/// ===========================================================================================

View File

@@ -12,10 +12,11 @@
:rules="rules"
ref="formRef"
>
<a-form-item label="名称" class="col2" name="name">
<a-input v-model:value="formData.name" :disabled="formStatus == 'read'" />
<a-form-item label="策略名称" :label-col="{ span: 6 }" class="col2" name="name">
<a-input v-model:value="formData.name" :disabled="formStatus == 'read'" readonly/>
</a-form-item>
<a-form-item class="col2"></a-form-item>
<!--
<a-form-item label="类型" class="col2" name="type">
<a-select v-model:value="formData.type" placeholder="" :disabled="formStatus == 'read'">
<a-select-option v-for="item in policyTypes" :value="item.value">{{
@@ -23,87 +24,52 @@
}}</a-select-option>
</a-select>
</a-form-item>
<a-form-item label="低谷电价" class="col2" required>
<a-input-number
:precision="2"
v-model:value="formData.price[0]"
suffix="元/kWh"
:disabled="formStatus == 'read'"
:min="0"
addon-after="/kWh"
/>
-->
<a-row v-if="formData.type == 1">
<a-form-item label="低谷电价" :label-col="{ span: 6 }" class="col2" required>
<a-input-number :precision="2" v-model:value="formData.price[0]" suffix="元/kWh"
:disabled="formStatus == 'read'" :min="0" addon-after="/kWh" />
</a-form-item>
<a-form-item label="平段电价" :label-col="{ span: 6 }" class="col2" required>
<a-input-number :precision="2" v-model:value="formData.price[1]" suffix="元/kWh"
:disabled="formStatus == 'read'" :min="0" addon-after="/kWh" />
</a-form-item>
</a-row>
<a-row v-if="formData.type == 1">
<a-form-item label="高峰电价" :label-col="{ span: 6 }" class="col2" required>
<a-input-number :precision="2" v-model:value="formData.price[2]" suffix="元/kWh" :disabled="formStatus == 'read'"
:min="0" addon-after="/kWh" />
</a-form-item>
<a-form-item label="平段电价" class="col2" required>
<a-input-number
:precision="2"
v-model:value="formData.price[1]"
suffix="元/kWh"
:disabled="formStatus == 'read'"
:min="0"
addon-after="/kWh"
/>
<a-form-item label="尖峰电价" :label-col="{ span: 6 }" class="col2" required>
<a-input-number :precision="2" v-model:value="formData.price[3]" suffix="元/kWh" :disabled="formStatus == 'read'"
:min="0" addon-after="/kWh" />
</a-form-item>
<a-form-item label="高峰电价" class="col2" required>
<a-input-number
:precision="2"
v-model:value="formData.price[2]"
suffix="元/kWh"
:disabled="formStatus == 'read'"
:min="0"
addon-after="/kWh"
/>
</a-form-item>
<a-form-item label="尖峰电价" class="col2" required>
<a-input-number
:precision="2"
v-model:value="formData.price[3]"
suffix="元/kWh"
:disabled="formStatus == 'read'"
:min="0"
addon-after="/kWh"
/>
</a-form-item>
<a-form-item label="时段表" class="col1" v-if="formData.type == '1'">
<a-table
:columns="columns"
:data-source="formData.period1"
size="small"
:scroll="{ y: 200 }"
:pagination="false"
row-class-name="no-hover-row"
row-key="month"
:expanded-row-keys="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]"
>
<template #headerCell="{ column }">
<template v-if="column.key === 'action'">
<span>
<PlusOutlined
@click="handleAdd"
:style="{ cursor: formStatus == 'read' ? 'not-allowed' : 'pointer' }"
/>
</span>
</a-row>
<a-row v-if="formData.type == 1">
<a-form-item label="时段表" class="col1" v-if="formData.type == '1'">
<a-table :columns="columns" :data-source="formData.period1" size="small" :scroll="{ y: 200 }"
:pagination="false" row-class-name="no-hover-row" row-key="month"
:expanded-row-keys="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]">
<template #headerCell="{ column }">
<template v-if="column.key === 'action'">
<span>
<PlusOutlined @click="handleAdd"
:style="{ cursor: formStatus == 'read' ? 'not-allowed' : 'pointer' }" />
</span>
</template>
</template>
</template>
<template #bodyCell="{ column, index }">
<template v-if="column.dataIndex === 'action'">
<span>
<a
@click="delPeriod(index)"
:style="{ cursor: formStatus == 'read' ? 'not-allowed' : 'pointer' }"
>删除</a
>
</span>
<template #bodyCell="{ column, index }">
<template v-if="column.dataIndex === 'action'">
<span>
<a @click="delPeriod(index)"
:style="{ cursor: formStatus == 'read' ? 'not-allowed' : 'pointer' }">删除</a>
</span>
</template>
</template>
</template>
</a-table>
</a-form-item>
<div v-if="formData.type == 5">
</a-table>
</a-form-item>
</a-row>
<div v-if="formData.type == 5">
<a-form-item label="充放策略" class="col1" name="chargePolicy">
<a-radio-group
v-model:value="formData.chargePolicy"
@@ -186,10 +152,57 @@
</a-form-item>
</div>
<a-form-item label="策略描述" class="col1">
<a-textarea v-model:value="formData.describe" :disabled="formStatus == 'read'" />
<a-row v-if="formData.type == 6" desc="自发自用余电存储">
<a-form-item label="放电最小SOC:" :label-col="{ span: 6 }" class="col2" name="参数名">
<a-input-number :precision="0" v-model:value="formData.soc_min" suffix="%"
:disabled="formStatus == 'read'" :min="0" addon-after="%" />
</a-form-item>
<a-form-item label="充电最大SOC:" :label-col="{ span: 6 }" class="col2" name="参数名">
<a-input-number :precision="0" v-model:value="formData.soc_max" suffix="%"
:disabled="formStatus == 'read'" :min="0" addon-after="%" />
</a-form-item>
</a-row>
<a-row v-if="formData.type == 7" desc="功率平衡策略">
<a-form-item label="储能充电阈值:" :label-col="{ span: 6 }" class="col2" name="参数名">
<a-input-number :precision="2" v-model:value="formData.charge" suffix="kW"
:disabled="formStatus == 'read'" :min="0" addon-after="kW" />
</a-form-item>
<a-form-item label="储能放电阈值:" :label-col="{ span: 6 }" class="col2" name="参数名">
<a-input-number :precision="2" v-model:value="formData.discharge" suffix="kW"
:disabled="formStatus == 'read'" :min="0" addon-after="kW" />
</a-form-item>
</a-row>
<a-row v-if="formData.type == 8" desc="光伏优先消纳">
<a-form-item label="储能充电功率:" :label-col="{ span: 6 }" class="col2" name="参数名">
<a-input-number :precision="0" v-model:value="formData.charge" suffix="kW"
:disabled="formStatus == 'read'" :min="0" addon-after="kW" />
</a-form-item>
<a-form-item label="储能放电功率:" :label-col="{ span: 6 }" class="col2" name="参数名">
<a-input-number :precision="0" v-model:value="formData.discharge" suffix="kW"
:disabled="formStatus == 'read'" :min="0" addon-after="kW" />
</a-form-item>
<a-form-item label="防逆流功率:" :label-col="{ span: 6 }" class="col2" name="参数名">
<a-input-number :precision="0" v-model:value="formData.power_reverse" suffix="kW"
:disabled="formStatus == 'read'" :min="0" addon-after="kW" />
</a-form-item>
</a-row>
<a-row v-if="formData.type == 9" desc="离网运行">
<a-form-item label="充电功率:" :label-col="{ span: 6 }" class="col2" name="参数名">
<a-input-number :precision="0" v-model:value="formData.charge" suffix="kW"
:disabled="formStatus == 'read'" :min="0" addon-after="kW" />
</a-form-item>
<a-form-item label="放电功率:" :label-col="{ span: 6 }" class="col2" name="参数名">
<a-input-number :precision="0" v-model:value="formData.discharge" suffix="kW"
:disabled="formStatus == 'read'" :min="0" addon-after="kW" />
</a-form-item>
</a-row>
<a-form-item label="策略描述" :label-col="{ span: 3 }" class="col1" >
<a-textarea v-model:value="formData.describe" :disabled="formStatus == 'read'" style="height: 120px" />
</a-form-item>
<a-form-item label="是否启用" class="col2">
<a-form-item label="是否启用" :label-col="{ span: 6 }" class="col2">
<a-switch v-model:checked="formData['is_open']" :disabled="formStatus == 'read'" />
</a-form-item>
<a-form-item class="col1">
@@ -420,12 +433,12 @@ export default {
},
//提交表单
async handleOk() {
const { type, price, is_open, chargePolicy } = this.formData
const { type, price, is_open, chargePolicy, soc_min, soc_max, charge, discharge, power_reverse } = this.formData
const periodKey = `period${type}`
const period = this.formData[periodKey] // 正确使用 period
const newForm = { ...this.formData, is_open: Number(is_open) }
if (type == 1) {
if (type == 1) { // 峰谷套利
const data = {
period: this.getPeriodJson(type, period),
price: price.map((item) => Number(item).toFixed(2))
@@ -433,17 +446,44 @@ export default {
newForm.value = JSON.stringify(data)
delete newForm.period1
} else {
} else if (type == 5) { // 自定时段
const data = {
period: this.getPeriodJson(type, period.slice(0, chargePolicy)),
price: price.map((item) => Number(item).toFixed(2))
}
newForm.value = JSON.stringify(data)
delete newForm.period5
} else if (type == 6) { // 自发自用余电存储
const data = {
soc_min: (soc_min/100).toFixed(2),
soc_max: (soc_max/100).toFixed(2)
}
newForm.value = JSON.stringify(data)
delete newForm.period5
} else if (type == 7) { // 功率平衡
const data = {
charge: charge.toFixed(2),
discharge: discharge.toFixed(2)
}
newForm.value = JSON.stringify(data)
delete newForm.period5
} else if (type == 8) { // 光伏优先消纳
const data = {
charge: charge.toFixed(0),
discharge: discharge.toFixed(0),
power_reverse: power_reverse.toFixed(0)
}
newForm.value = JSON.stringify(data)
delete newForm.period5
} else if (type == 9) { // 离网运行
const data = {
charge: charge.toFixed(0),
discharge: discharge.toFixed(0)
}
newForm.value = JSON.stringify(data)
delete newForm.period5
}
delete newForm.price
this.validateform(newForm)
},
async validateform(newForm) {
@@ -502,14 +542,20 @@ export default {
const { value, type } = newVal
const jsonValue = JSON.parse(value)
const { price, period } = jsonValue
const { price, period, soc_min, soc_max, charge, discharge, power_reverse } = jsonValue
this.formData = {
...newVal,
is_open: Boolean(newVal['is_open']),
price
}
this.formData[`period${type}`] = this.getPeriod(type, period)
if (period) { this.formData[`period${type}`] = this.getPeriod(type, period) }
if (soc_min) { this.formData['soc_min'] = Number(soc_min*100) }
if (soc_max) { this.formData['soc_max'] = Number(soc_max*100) }
if (charge) { this.formData['charge'] = Number(charge) }
if (discharge) { this.formData['discharge'] = Number(discharge) }
if (power_reverse) { this.formData['power_reverse'] = Number(power_reverse) }
},
handleAdd() {
if (this.formStatus == 'read') return
@@ -586,7 +632,7 @@ export default {
})
}
})
} else {
} else if (type == 5) {
this.formData.chargePolicy = list.length
list.forEach((item, index) => {
const ele = {
@@ -668,6 +714,7 @@ export default {
.ant-form-item {
margin-inline-end: 0 !important;
margin-top: 15px;
margin-bottom:0px;
:deep(.ant-form-item-label) {
margin-left: 10px;
}

View File

@@ -1,6 +1,16 @@
<template>
<div class="policy" ref="policy">
<searchBox :btn-option-list="btnOptionList" @onSearch="onSearch" @operateForm="operateForm" />
<!-- <div>
<a-select style="width: 200px" :dropdown-match-select-width="false" v-model:value="policyId" allow-clear
@change="changeStation">
<a-select-option :value="option.value" v-for="option in policyList" :key="option.value">
{{ option.label }}
</a-select-option>
</a-select>
</div> -->
<div class="content-table">
<ComTable
:columns="columns"
@@ -50,6 +60,15 @@ export default {
data() {
return {
policyId: 2,
policyList: [
{label:"自发自用余电存储", value: 1},
{label:"峰谷套利", value: 2},
{label:"后备电源模式", value: 3},
{label:"功率平衡", value: 5},
{label:"光伏优先消纳", value: 6},
],
formModal: false,
btnOptionList: [
],
@@ -58,38 +77,41 @@ export default {
title: '策略ID',
dataIndex: 'policy_id',
key: 'policyId',
width: 100,
ellipsis: true
},
{
title: '策略名称',
dataIndex: 'name',
key: 'name',
width: 150,
ellipsis: true
},
{
title: '策略类型',
dataIndex: 'type', //策略类型1削峰套利2需求响应3自发自用
key: 'type',
ellipsis: true,
scopedSlots: { customRender: 'type' }
},
// {
// title: '策略类型',
// dataIndex: 'type', //策略类型1削峰套利2需求响应3自发自用
// key: 'type',
// ellipsis: true,
// scopedSlots: { customRender: 'type' }
// },
{
title: '策略描述',
dataIndex: 'describe',
key: 'describe',
width: 600,
ellipsis: true
},
{
title: '策略参数',
dataIndex: 'value',
key: 'value',
width: 200,
ellipsis: true
},
{
title: '是否启用',
dataIndex: 'is_open',
key: 'isOpen',
width: 120,
ellipsis: true,
scopedSlots: { customRender: 'isOpen' }
},
@@ -118,7 +140,7 @@ export default {
}
},
mounted() {
this.operateList = this.$getBtns(['查看', '修改', '删除'])
this.operateList = this.$getBtns(['查看', '修改'])
// this.btnOptionList = this.$getBtns(['新增'])
this.getTableList()
},
@@ -156,6 +178,7 @@ export default {
case 'read':
this.formModal = true
this.formState = record
break
case 'del':
this.handleDelete(record.policy_id)