实现削峰套利策略的编辑页面

This commit is contained in:
lixiaoyuan
2025-08-26 18:36:25 +08:00
parent 7fe51ea362
commit 8f6c83147b
37 changed files with 1506 additions and 729 deletions

View File

@@ -0,0 +1,366 @@
#include "PanelPolicy.h"
#include "app/Application.h"
#include "app/AppData.h"
#include "common/JsonN.h"
const std::string QSS_COMBOX_1 =
"QComboBox {border: 1px solid rgb(18, 251, 255); background-color: rgb(255, 89, 0); border-radius: 3px; color: rgb(30,30,30); font: bold 14px;}"
"QComboBox QAbstractItemView { border: 1px solid gray; background-color: rgba(8, 54, 91); border-radius: 5px; color:white;}"
"QComboBox::drop-down { border-radius: 5px; width: 30px; }"
"QComboBox:disabled { color:rgb(150,150,150);}";
const std::string QSS_COMBOX_2 =
"QComboBox {border: 1px solid rgb(18, 251, 255); background-color: rgb(255, 255, 0); border-radius: 3px; color: rgb(30,30,30); font: bold 14px;}"
"QComboBox QAbstractItemView { border: 1px solid gray; background-color: rgba(8, 54, 91); border-radius: 5px; color:white;}"
"QComboBox::drop-down { border-radius: 5px; width: 30px; }"
"QComboBox:disabled { color:rgb(150,150,150);}";
const std::string QSS_COMBOX_3 =
"QComboBox {border: 1px solid rgb(18, 251, 255); background-color: rgb(121, 191, 226); border-radius: 3px; color: rgb(30,30,30); font: bold 14px;}"
"QComboBox QAbstractItemView { border: 1px solid gray; background-color: rgba(8, 54, 91); border-radius: 5px; color:white;}"
"QComboBox::drop-down { border-radius: 5px; width: 30px; }"
"QComboBox:disabled { color:rgb(150,150,150);}";
const std::string QSS_COMBOX_4 =
"QComboBox {border: 1px solid rgb(18, 251, 255); background-color: rgb(0, 255, 58); border-radius: 3px; color: rgb(30,30,30); font: bold 14px;}"
"QComboBox QAbstractItemView { border: 1px solid gray; background-color: rgba(8, 54, 91); border-radius: 5px; color:white;}"
"QComboBox::drop-down { border-radius: 5px; width: 30px; }"
"QComboBox:disabled { color:rgb(150,150,150);}";
static std::string GetPeriodQss(int v)
{
if (v == 1) { return QSS_COMBOX_1; }
else if (v == 2) { return QSS_COMBOX_2; }
else if (v == 3) { return QSS_COMBOX_3; }
else if (v == 4) { return QSS_COMBOX_4; }
else { return QSS_COMBOX_1; }
}
static std::string GetPeriodQss(std::string text)
{
if (text == "尖峰") { return QSS_COMBOX_1; }
else if (text == "高峰") { return QSS_COMBOX_2; }
else if (text == "平段") { return QSS_COMBOX_3; }
else if (text == "低谷") { return QSS_COMBOX_4; }
else { return QSS_COMBOX_1; }
}
static int GetPeriod(std::string text)
{
if (text == "尖峰") { return 1; }
else if (text == "高峰") { return 2; }
else if (text == "平段") { return 3; }
else if (text == "低谷") { return 4; }
else { return 3; }
}
PanelPolicyPeak::PanelPolicyPeak(PARAM* p, int parent, int x, int y, int w, int h) : PvObject(p)
{
data.vecPeriods.resize(12, std::vector<int>(24, 3));
ui.parent = parent;
ui.widget = PvApp::widget(p, parent, x, y, w, h);
auto& appdata = Application::data();
std::vector<std::string> vecPeriods = {"尖峰", "高峰", "平段", "低谷"};
ui.vecComboxs.resize(12, std::vector<int>(24, PV_ID_NUL));
{
int parent = ui.widget;
int x = 10, y = 180, w = 64, h = 30;
for (int row = 0; row<=12; row++)
{
for (int col = 0; col<=24; ++col)
{
std::string text;
if (row == 0)
{
text = (col == 0) ? "月份" : std::to_string(col-1) + "-" + std::to_string(col) + "";
}
else
{
text = (col == 0) ? std::to_string(row) : "";
}
if (row == 0 || col == 0)
{
std::string qssLabel = (row==0) ? qss::label(14, "", "rgb(19, 93, 114)") : "";
int label = PvApp::label(p, parent, x+w*col, y+h*row, w, h, text, qssLabel);
pvSetAlignment(p, label, AlignCenter);
}
else
{
int periodVal = data.vecPeriods[row-1][col-1];
int combox = PvApp::combox(p, parent, x+w*col, y+h*row+3, w-3, 24, vecPeriods, periodVal);
pvSetStyleSheet(p, combox, GetPeriodQss(periodVal).c_str());
ui.vecComboxs[row-1][col-1] = combox;
PvApp::bind(p, PvEvent::TEXT_EVENT, combox, [=](std::string text) {
pvSetStyleSheet(p, combox, GetPeriodQss(text).c_str());
data.vecPeriods[row-1][col-1] = GetPeriod(text);
});
}
}
}
const int H = 24;
int labelPolicy = PvApp::label(p, parent, 20, 600, 300, H, "充电策略");
ui.radioPolicy1 = PvApp::radioButton(p, labelPolicy, 80, 0, 80, H, "一充一放");
ui.radioPolicy2 = PvApp::radioButton(p, labelPolicy, 170, 0, 80, H, "两充两放");
ui.label1 = PvApp::label(p, parent, 10, 640, 610, 90, "第一次充放电过程", qss::label(14, "", "", "1px solid rgb(49, 130, 141)"));
pvSetAlignment(p, ui.label1, AlignLeft | AlignTop);
{
int y0 = 70;
int labelChargeT = PvApp::label(p, ui.label1, 10, 30, 300, H, "充电时间");
ui.attr1TimeCharge0 = PvApp::timeEdit(p, labelChargeT, y0, 0, 60, H);
PvApp::label(p, labelChargeT, 150, 0, 10, H, "--");
ui.attr1TimeCharge1 = PvApp::timeEdit(p, labelChargeT, 170, 0, 60, H);
int labelDischargeT = PvApp::label(p, ui.label1, 320, 30, 300, H, "放电时间");
ui.attr1TimeDischarge0 = PvApp::timeEdit(p, labelDischargeT, y0 = 70, 0, 60, H);
PvApp::label(p, labelDischargeT, y0+=70, 0, 10, H, "--");
ui.attr1TimeDischarge1 = PvApp::timeEdit(p, labelDischargeT, y0+=20, 0, 60, H);
int labelPowerIn = PvApp::label(p, ui.label1, 10, 60, 300, H, "充电功率");
ui.attr1RadioPowerInAuto = PvApp::radioButton(p, labelPowerIn, y0 = 70, 0, 60, H, "自动");
ui.attr1RadioPowerIn = PvApp::radioButton(p, labelPowerIn, y0 += 60, 0, 64, H, "自定义");
ui.arrt1LabelPowerIn = PvApp::lineEdit(p, labelPowerIn, y0 += 70, 0, 80, H, "");
int labelPowerOut = PvApp::label(p, ui.label1, 320, 60, 300, H, "放电功率");
ui.attr1RadioPowerOutAuto = PvApp::radioButton(p, labelPowerOut, y0 = 70, 0, 60, H, "自动");
ui.attr1RadioPowerOut = PvApp::radioButton(p, labelPowerOut, y0 += 60, 0, 64, H, "自定义");
ui.arrt1LabelPowerOut = PvApp::lineEdit(p, labelPowerOut, y0 += 70, 0, 80, H, "");
}
ui.label2 = PvApp::label(p, parent, 630, 640, 610, 90, "第二次充放电过程", qss::label(14, "", "", "1px solid rgb(49, 130, 141)"));
pvSetAlignment(p, ui.label2, AlignLeft | AlignTop);
{
int y0 = 70;
int labelChargeT = PvApp::label(p, ui.label2, 10, 30, 300, H, "充电时间");
XLOGD() << "labelChargeT=" << labelChargeT;
ui.attr2TimeCharge0 = PvApp::timeEdit(p, labelChargeT, y0, 0, 60, H);
PvApp::label(p, labelChargeT, 150, 0, 10, H, "--");
ui.attr2TimeCharge1 = PvApp::timeEdit(p, labelChargeT, 170, 0, 60, H);
int labelDischargeT = PvApp::label(p, ui.label2, 320, 30, 300, H, "放电时间");
ui.attr2TimeDischarge0 = PvApp::timeEdit(p, labelDischargeT, y0 = 70, 0, 60, H);
PvApp::label(p, labelDischargeT, y0 += 70, 0, 10, H, "--");
ui.attr2TimeDischarge1 = PvApp::timeEdit(p, labelDischargeT, y0 += 20, 0, 60, H);
int labelPowerIn = PvApp::label(p, ui.label2, 10, 60, 300, H, "充电功率");
ui.attr2RadioPowerInAuto = PvApp::radioButton(p, labelPowerIn, y0 = 70, 0, 60, H, "自动");
ui.attr2RadioPowerIn = PvApp::radioButton(p, labelPowerIn, y0 += 60, 0, 64, H, "自定义");
ui.arrt2LabelPowerIn = PvApp::lineEdit(p, labelPowerIn, y0 += 70, 0, 80, H, "");
int labelPowerOut = PvApp::label(p, ui.label2, 320, 60, 300, H, "放电功率");
ui.attr2RadioPowerOutAuto = PvApp::radioButton(p, labelPowerOut, y0 = 70, 0, 60, H, "自动");
ui.attr2RadioPowerOut = PvApp::radioButton(p, labelPowerOut, y0 += 60, 0, 64, H, "自定义");
ui.arrt2LabelPowerOut = PvApp::lineEdit(p, labelPowerOut, y0 += 70, 0, 80, H, "");
}
PvApp::bind(p, PvEvent::RADIOBUTTON_EVENT, ui.radioPolicy1, [=](std::string s) {
this->data.times = 1;
pvHide(p, ui.label2);
//setTimeText(ui.attr2TimeCharge0, "");
//setTimeText(ui.attr2TimeCharge1, "");
//setTimeText(ui.attr2TimeDischarge0, "");
//setTimeText(ui.attr2TimeDischarge1, "");
//pvSetChecked(p, ui.attr2RadioPowerInAuto, 1);
//pvSetChecked(p, ui.attr2RadioPowerOutAuto, 1);
//pvSetText(p, ui.arrt2LabelPowerOut, "");
//data.attr2.chargePower = data.attr2.dischargePower = 0.0;
//data.attr2.chargeTimeStart = data.attr2.chargeTimeEnd = data.attr2.dischargeTimeStart = data.attr2.dischargeTimeEnd = "";
});
PvApp::bind(p, PvEvent::RADIOBUTTON_EVENT, ui.radioPolicy2, [=](std::string s) {
this->data.times = 2;
pvShow(p, ui.label2);
});
PvApp::bind(p, PvEvent::TEXT_EVENT, ui.attr1TimeCharge0, [=](std::string s) {
data.attr1.chargeTimeStart = s.substr(0, 8);
});
PvApp::bind(p, PvEvent::TEXT_EVENT, ui.attr1TimeCharge1, [=](std::string s) {
data.attr1.chargeTimeEnd = s.substr(0, 8);
});
PvApp::bind(p, PvEvent::TEXT_EVENT, ui.attr1TimeDischarge0, [=](std::string s) {
data.attr1.dischargeTimeStart = s.substr(0, 8);
});
PvApp::bind(p, PvEvent::TEXT_EVENT, ui.attr1TimeDischarge1, [=](std::string s) {
data.attr1.dischargeTimeEnd = s.substr(0, 8);
});
PvApp::bind(p, PvEvent::TEXT_EVENT, ui.attr2TimeCharge0, [=](std::string s) {
data.attr2.chargeTimeStart = s.substr(0, 8);
});
PvApp::bind(p, PvEvent::TEXT_EVENT, ui.attr2TimeCharge1, [=](std::string s) {
data.attr2.chargeTimeEnd = s.substr(0, 8);
});
PvApp::bind(p, PvEvent::TEXT_EVENT, ui.attr2TimeDischarge0, [=](std::string s) {
data.attr2.dischargeTimeStart = s.substr(0, 8);
});
PvApp::bind(p, PvEvent::TEXT_EVENT, ui.attr2TimeDischarge1, [=](std::string s) {
data.attr2.dischargeTimeEnd = s.substr(0, 8);
});
{
int btn = PvApp::button(p, ui.widget, 10, 750, 100, 30, "DUMP");
PvApp::bind(p, PvEvent::BUTTON_EVENT, btn, [=](std::string) {
XLOGD() << dumpAttr();
});
}
{
int btn = PvApp::button(p, ui.widget, 110, 750, 100, 30, "PARSE1");
PvApp::bind(p, PvEvent::BUTTON_EVENT, btn, [=](std::string) {
std::string s = R"({"cycle":[{"charge_end":"","charge_power":0.0,"charge_start":"","discharge_end":"","discharge_power":0.0,"discharge_start":""}],
"period":[[1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]],
"times":1})";
parseAttr(s);
});
}
{
int btn = PvApp::button(p, ui.widget, 210, 750, 100, 30, "PARSE2");
PvApp::bind(p, PvEvent::BUTTON_EVENT, btn, [=](std::string) {
std::string s = R"({"cycle":[{"charge_end":"09:00:00","charge_power":0.0,"charge_start":"00:00:00","discharge_end":"","discharge_power":0.0,"discharge_start":""}],
"period":[[1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[1,1,1,1,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3],[3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3]],
"times":2})";
parseAttr(s);
});
}
}
}
void PanelPolicyPeak::updateUI()
{
}
void PanelPolicyPeak::setTimeText(int id, std::string s)
{
int hour {0}, minute {0}, second {0};
sscanf_s(s.c_str(), "%d:%d:%d", &hour, &minute, &second);
pvSetTime(p, id, hour, minute, second);
}
void PanelPolicyPeak::parseAttr(std::string str)
{
NJsonNode jsonroot;
bool ret = NJson::parse(str, jsonroot);
if (!ret)
{
return;
}
NJson::read(jsonroot, "times", data.times);
// 更新UI (充电策略)
if (data.times == 2)
{
pvSetChecked(p, ui.radioPolicy2, 1);
pvShow(p, ui.label2);
}
else
{
pvSetChecked(p, ui.radioPolicy1, 1);
pvHide(p, ui.label2);
}
std::vector<std::vector<int>> vecTmp;
NJson::read<std::vector<std::vector<int>>>(jsonroot, "period", vecTmp);
for (int row = 0; row < data.vecPeriods.size(); ++row)
{
auto& vecRows = data.vecPeriods[row];
for (int col = 0; col < vecRows.size(); ++col)
{
auto& periodVal = vecRows[col];
int tmpVal {};
if (row < vecTmp.size())
{
tmpVal = (col < vecTmp[row].size() ? vecTmp[row][col] : 3);
}
else
{
tmpVal = 3;
}
if (periodVal != tmpVal)
{
periodVal = tmpVal;
// 更新UI (时段下拉列表)
auto combox = ui.vecComboxs[row][col];
pvSetCurrentItem(p, combox, periodVal);
pvSetStyleSheet(p, combox, GetPeriodQss(periodVal).c_str());
}
}
}
if (jsonroot.contains("cycle"))
{
auto& jsonCycle = jsonroot["cycle"];
if (jsonCycle.is_array())
{
auto size = jsonCycle.size();
if (size >= 1)
{
data.attr1.chargeTimeStart = jsonCycle[0]["charge_start"];
data.attr1.chargeTimeEnd = jsonCycle[0]["charge_end"];
data.attr1.chargePower = jsonCycle[0]["charge_power"];
data.attr1.dischargeTimeStart = jsonCycle[0]["discharge_start"];
data.attr1.dischargeTimeEnd = jsonCycle[0]["discharge_end"];
data.attr1.dischargePower = jsonCycle[0]["discharge_power"];
// 更新UI (一放一充)
setTimeText(ui.attr1TimeCharge0, data.attr1.chargeTimeStart);
setTimeText(ui.attr1TimeCharge1, data.attr1.chargeTimeEnd);
//setTimeText(ui.attr1TimeCharge1, data.attr1.chargeTimeEnd);
setTimeText(ui.attr1TimeDischarge0, data.attr1.dischargeTimeStart);
setTimeText(ui.attr1TimeDischarge1, data.attr1.dischargeTimeEnd);
//setTimeText(ui.attr1TimeCharge1, data.attr1.chargeTimeEnd);
}
if (size >= 2)
{
data.attr2.chargeTimeStart = jsonCycle[1]["charge_start"];
data.attr2.chargeTimeEnd = jsonCycle[1]["charge_end"];
data.attr2.chargePower = jsonCycle[1]["charge_power"];
data.attr2.dischargeTimeStart = jsonCycle[1]["discharge_start"];
data.attr2.dischargeTimeEnd = jsonCycle[1]["discharge_end"];
data.attr2.dischargePower = jsonCycle[1]["discharge_power"];
// 更新UI (两放两充)
setTimeText(ui.attr2TimeCharge0, data.attr2.chargeTimeStart);
setTimeText(ui.attr2TimeCharge1, data.attr2.chargeTimeEnd);
//setTimeText(ui.attr2TimeCharge1, data.attr2.chargeTimeEnd);
setTimeText(ui.attr2TimeDischarge0, data.attr2.dischargeTimeStart);
setTimeText(ui.attr2TimeDischarge1, data.attr2.dischargeTimeEnd);
//setTimeText(ui.attr2TimeCharge1, data.attr2.chargeTimeEnd);
}
}
}
// 更新UI
}
std::string PanelPolicyPeak::dumpAttr()
{
NJsonNode jsonroot;
jsonroot["period"] = data.vecPeriods;
jsonroot["times"] = data.times;
NJsonNode nodeCycle = NJsonNode::array();
NJsonNode nodeAttr1;
nodeAttr1["charge_start"] = data.attr1.chargeTimeStart;
nodeAttr1["charge_end"] = data.attr1.chargeTimeEnd;
nodeAttr1["charge_power"] = data.attr1.chargePower;
nodeAttr1["discharge_start"] = data.attr1.dischargeTimeStart;
nodeAttr1["discharge_end"] = data.attr1.dischargeTimeEnd;
nodeAttr1["discharge_power"] = data.attr1.dischargePower;
nodeCycle.push_back(nodeAttr1);
if (data.times > 1)
{
NJsonNode nodeAttr2;
nodeAttr2["charge_start"] = data.attr2.chargeTimeStart;
nodeAttr2["charge_end"] = data.attr2.chargeTimeEnd;
nodeAttr2["charge_power"] = data.attr2.chargePower;
nodeAttr2["discharge_start"] = data.attr2.dischargeTimeStart;
nodeAttr2["discharge_end"] = data.attr2.dischargeTimeEnd;
nodeAttr2["discharge_power"] = data.attr2.dischargePower;
nodeCycle.push_back(nodeAttr2);
}
jsonroot["cycle"] = nodeCycle;
return jsonroot.dump();
}