mirror of
https://gitee.com/js-yhsec/energy_storage.git
synced 2026-05-28 03:09:24 +08:00
搭建PVB架构,实现前端的基础布局、菜单、表格、图示等功能
This commit is contained in:
219
src/pv/#/PvPop.cpp
Normal file
219
src/pv/#/PvPop.cpp
Normal file
@@ -0,0 +1,219 @@
|
||||
#include "PvPop.h"
|
||||
#include "PvInstance.h"
|
||||
#include "common/Logger.h"
|
||||
|
||||
static const string STYLE_LAB = "color:white;font:bold 18px;border:1px solid rgba(120,120,120,0);";
|
||||
|
||||
string PvPop::POP_DEFAULT = "";
|
||||
|
||||
//PanelPop::PanelPop(PARAM* p, int parent, string title, int w, int h)
|
||||
//
|
||||
//{
|
||||
//
|
||||
//}
|
||||
|
||||
void PvPop::update(PARAM* p)
|
||||
{
|
||||
}
|
||||
|
||||
void PvPop::set_pop_cb(std::function<void(PARAM* p, int status)> cb)
|
||||
{
|
||||
cb_pop_ = cb;
|
||||
};
|
||||
|
||||
void PvPop::set_enabled(string title, bool b)
|
||||
{
|
||||
if (!title.empty())
|
||||
{
|
||||
if (map_w_.find(title) != map_w_.end())
|
||||
{
|
||||
pvSetEnabled(p_, map_w_[title].pvid, b);
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (auto it = map_w_.begin(); it != map_w_.end(); it++)
|
||||
{
|
||||
pvSetEnabled(p_, it->second.pvid, b);
|
||||
}
|
||||
}
|
||||
|
||||
void PvPop::on_click_ok()
|
||||
{
|
||||
};
|
||||
|
||||
void PvPop::set_status(string status)
|
||||
{
|
||||
status_ = status;
|
||||
string s = title_;
|
||||
if (!status_.empty())
|
||||
{
|
||||
s += (":" + status_);
|
||||
}
|
||||
pvSetText(p_, lab_title_, s.c_str());
|
||||
}
|
||||
|
||||
string PvPop::status()
|
||||
{
|
||||
return status_;
|
||||
}
|
||||
|
||||
void PvPop::set_err(PARAM* p, string err)
|
||||
{
|
||||
err_ = err;
|
||||
pvSetText(p, id_err_, err.c_str());
|
||||
}
|
||||
|
||||
string PvPop::err()
|
||||
{
|
||||
return err_;
|
||||
}
|
||||
|
||||
void PvPop::reset(PARAM* p)
|
||||
{
|
||||
}
|
||||
|
||||
PvPop::PvPop(PARAM* p, int parent, string title, int w /*= 900*/, int h /*= 700*/)
|
||||
: PvWidget(p, parent, PvRect(0, 0, 1920, 1080)), width_(w), height_(h), title_(title)
|
||||
{
|
||||
// 半透全屏背景,遮盖后面的控件,禁止操作底层控件
|
||||
PvManager::label(p, pvid_, "", PvRect(0, 0, 1920, 1080), "background-color:rgba(50,50,50,0);");
|
||||
|
||||
// 弹框的有效工作区域
|
||||
rt_pop_.set((1920 - w) * 0.5, (1080 - h) * 0.5, w, h);
|
||||
// 工作区(包含顶部标题和底部按钮)
|
||||
w_main_ = PvManager::widget(p, pvid_, rt_pop_);
|
||||
// 工作区背景
|
||||
PvManager::label(p, w_main_, "", PvRect(0, 0, w, h), "border:1px solid #26dcac;border-radius:10;background-color:rgb(21,68,94);");
|
||||
|
||||
// 顶部标题
|
||||
lab_title_ = PvManager::label(p, w_main_, title, PvRect(1, 1, w - 2, 48), "border-radius:10;background-color:rgb(49,132,149);font:bold 20px;color:rgb(255,255,255);");
|
||||
pvSetAlignment(p, lab_title_, AlignCenter);
|
||||
|
||||
// 用户工作区
|
||||
w_worksace_ = PvManager::widget(p, w_main_, PvRect(1, 48, w - 2, (h - 120)));
|
||||
|
||||
// 关闭按钮
|
||||
PvManager::button_image(p, w_main_, "resource/pv.btn.close.png", "", "", PvRect(w - 40, 10, 29, 29), [=](string s)
|
||||
{
|
||||
this->set_status("");
|
||||
this->hide();
|
||||
});
|
||||
|
||||
static string style_btn_ok =
|
||||
"QPushButton{background-color:rgb(38,220,172);font:bold 20px;color:white;border-radius:8;}"
|
||||
"QPushButton:hover{border:2px solid red;}"
|
||||
"QPushButton:pressed{border-width:3px 0 0 3px;border-style:inset;}"
|
||||
"QPushButton:disabled{color:rgb(150,150,150);}";
|
||||
static string style_btn_cannel =
|
||||
"QPushButton{background-color:rgb(200,207,216);font:bold 20px;color:black;border-radius:8;}"
|
||||
"QPushButton:hover{border:2px solid red;}"
|
||||
"QPushButton:pressed{border-width:3px 0 0 3px;border-style:inset;}"
|
||||
"QPushButton:disabled{color:rgb(150,150,150);}";
|
||||
|
||||
int btn_ok = PvManager::button(p, w_main_, "确定", PvRect(w * 0.5 - 120 - 20, h - 60, 120, 40), style_btn_ok);
|
||||
int btn_cancel = PvManager::button(p, w_main_, "取消", PvRect(w * 0.5 + 20, h - 60, 120, 40), style_btn_cannel);
|
||||
PvInstance::bind_event(p, PvEvent::BUTTON_EVENT, btn_ok, [=](string e)
|
||||
{
|
||||
this->on_click_ok();
|
||||
if (cb_pop_)
|
||||
{
|
||||
cb_pop_(p, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->hide();
|
||||
}
|
||||
});
|
||||
PvInstance::bind_event(p, PvEvent::BUTTON_EVENT, btn_cancel, [=](string e)
|
||||
{
|
||||
this->set_status("");
|
||||
this->hide();
|
||||
});
|
||||
|
||||
// 错误提示栏
|
||||
id_err_ = PvManager::label(p, w_main_, "", PvRect(50, h - 60 - 30, 700, 30), "background-color:rgba(50,50,50,30);color:red;font:bold 16px;");
|
||||
|
||||
// 默认不显示
|
||||
this->set_visible(false);
|
||||
|
||||
w_param_ = make_shared<PanelParam>(p, w_worksace_, PvRect(0, 0, w, h));
|
||||
w_param_->set_line_callback([=](shared_ptr<PvLineParam> line, string old_v, string v)
|
||||
{
|
||||
string id = line->get_id();
|
||||
data_.set(id, v);
|
||||
if (cb_line_changed_)
|
||||
{
|
||||
cb_line_changed_(line);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void PvPop::set_data(DataFields& data)
|
||||
{
|
||||
for (auto& it : data.fields())
|
||||
{
|
||||
this->set_data(it.first, it.second);
|
||||
}
|
||||
};
|
||||
|
||||
void PvPop::set_data(string id, string v)
|
||||
{
|
||||
data_.set(id, v);
|
||||
if (w_param_)
|
||||
{
|
||||
w_param_->set_line_data(id, v);
|
||||
}
|
||||
}
|
||||
|
||||
string PvPop::get_data(string k)
|
||||
{
|
||||
return data_.get_str(k);
|
||||
}
|
||||
|
||||
DataFields& PvPop::get_data()
|
||||
{
|
||||
return data_;
|
||||
};
|
||||
|
||||
void PvPop::set_line_callback(function<void(shared_ptr<PvLineParam>)> cb)
|
||||
{
|
||||
cb_line_changed_ = cb;
|
||||
}
|
||||
|
||||
void PvPop::on_show()
|
||||
{
|
||||
}
|
||||
|
||||
void PvPop::on_hide()
|
||||
{
|
||||
//w_param_->clear();
|
||||
this->do_cleanup();
|
||||
}
|
||||
|
||||
void PvPop::do_cleanup()
|
||||
{
|
||||
};
|
||||
|
||||
void PvPop::foreach_line(std::function<void(string k, string v)> cb)
|
||||
{
|
||||
for (auto& item : data_.fields())
|
||||
{
|
||||
if (cb)
|
||||
{
|
||||
cb(item.first, item.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PvPop::clear()
|
||||
{
|
||||
data_.clear();
|
||||
w_param_->clear();
|
||||
}
|
||||
|
||||
PvPopConfirm::PvPopConfirm(PARAM* p, int parent, string title, int w, int h)
|
||||
: PvPop(p, parent, title, w, h)
|
||||
{
|
||||
std::string style = "color:rgb(255,255,255);font:bold 20px;padding-left:10;";
|
||||
PvManager::label(p, w_worksace_, "是否确定操作?", PvRect(20, 30, w, 40), style);
|
||||
}
|
||||
87
src/pv/#/PvPop.h
Normal file
87
src/pv/#/PvPop.h
Normal file
@@ -0,0 +1,87 @@
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include "DataFields.h"
|
||||
#include "PvApp.h"
|
||||
|
||||
struct PopLineInfo
|
||||
{
|
||||
string title; // 控件名称标题
|
||||
string type; // 控件类型
|
||||
int pvid; // 值的控件ID
|
||||
//PopLineInfo(string s, string t, int id) : title(s), type(t), pvid(id) {}
|
||||
};
|
||||
|
||||
class PvPop : public PvObject
|
||||
{
|
||||
public:
|
||||
PvPop(PARAM* p, int parent, string title, int w = 900, int h = 700);
|
||||
|
||||
void set_data(DataFields& data);
|
||||
void set_data(string k, string v);
|
||||
string get_data(string k);
|
||||
DataFields& get_data();
|
||||
|
||||
void set_line_callback(function<void(shared_ptr<PvLineParam>)> cb);
|
||||
|
||||
void on_show() override;
|
||||
void on_hide() override;
|
||||
virtual void do_cleanup();
|
||||
|
||||
void foreach_line(std::function<void(string k, string v)>);
|
||||
|
||||
void set_status(string status);
|
||||
string status();
|
||||
|
||||
void update(PARAM* p);
|
||||
|
||||
void set_pop_cb(std::function<void(PARAM* p, int status)> cb);
|
||||
|
||||
void set_err(PARAM* p, string err);
|
||||
string err();
|
||||
|
||||
void reset(PARAM* p);
|
||||
|
||||
void set_enabled(string title, bool b);
|
||||
virtual void on_click_ok();
|
||||
|
||||
void clear();
|
||||
|
||||
public:
|
||||
static string POP_DEFAULT;
|
||||
|
||||
protected:
|
||||
shared_ptr<PanelParam> w_param_;
|
||||
|
||||
// 原始数据
|
||||
DataFields data_;
|
||||
|
||||
function<void(shared_ptr<PvLineParam>)> cb_line_changed_ = nullptr;
|
||||
|
||||
int w_main_;
|
||||
int w_worksace_;
|
||||
int lab_title_;
|
||||
int id_err_;
|
||||
|
||||
int width_;
|
||||
int height_;
|
||||
PvRect rt_pop_;
|
||||
|
||||
string title_;
|
||||
string status_;
|
||||
string err_;
|
||||
|
||||
// 弹出窗口的行控件信息
|
||||
unordered_map<string, PopLineInfo> map_w_;
|
||||
|
||||
std::function<void(PARAM* p, int status)> cb_pop_ = nullptr;
|
||||
};
|
||||
|
||||
|
||||
class PvPopConfirm : public PvPop
|
||||
{
|
||||
public:
|
||||
PvPopConfirm(PARAM* p, int parent, string title, int w = 900, int h = 700);
|
||||
|
||||
int lab_text_ = PV_INVALID_ID;
|
||||
};
|
||||
119
src/pv/MaskMain.cpp
Normal file
119
src/pv/MaskMain.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "MaskMain.h"
|
||||
#include "pv/pages/MaskPageHome.h"
|
||||
#include "pv/pages/MaskPageRunning.h"
|
||||
#include "pv/pages/MaskPageForecast.h"
|
||||
#include "pv/pages/MaskPageStat.h"
|
||||
#include "pv/pages/MaskPageSysmgr.h"
|
||||
|
||||
#include "common/DataFields.h"
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <ctime>
|
||||
#include <sstream>
|
||||
std::string GetDateTimeWeekday()
|
||||
{
|
||||
static std::vector<std::string> wdaysStr = {"星期天", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
|
||||
std::time_t now = std::time(nullptr);
|
||||
std::tm tm = *std::localtime(&now);
|
||||
std::stringstream ss;
|
||||
ss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S ") << wdaysStr[tm.tm_wday];
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int MaskMain::initUI()
|
||||
{
|
||||
pvSetStyleSheet(p, PV_ID_MAIN, "color: white; font: normal 14px \"微软雅黑\";");
|
||||
ui.bkg = PvApp::pvid(p);
|
||||
PvApp::image(p, 0, 0, 0, 1920, 1080, "bkg.png");
|
||||
|
||||
ui.datetime = PvApp::label(p, PV_ID_MAIN, 10, 30, 420, 30, GetDateTimeWeekday(), "font: bold 18px;");
|
||||
pvSetAlignment(p, ui.datetime, AlignCenter);
|
||||
|
||||
int idStationTitle = PvApp::label(p, 0, 620, 0, 660, 90, "能源站监控与运行管理系统", "font:bold 48px \"Microsoft YaHei\"; color:white");
|
||||
pvSetAlignment(p, idStationTitle, AlignCenter);
|
||||
|
||||
// 初始化子页面
|
||||
int menuActive = PV_ID_NUL;
|
||||
switch (pvcode_)
|
||||
{
|
||||
case EPvCode::NUL:
|
||||
case EPvCode::MASK_LOGIN: {}
|
||||
case EPvCode::MASK_HOME: { maskPage_ = std::make_shared<MaskPageHome>(p); }
|
||||
break;
|
||||
case EPvCode::MASK_RUNNING: { maskPage_ = std::make_shared<MaskPageRunning>(p); }
|
||||
break;
|
||||
case EPvCode::MASK_FORECAST_STORAGE:
|
||||
case EPvCode::MASK_FORECAST_SOLAR:
|
||||
case EPvCode::MASK_FORECAST_CHARGE:
|
||||
case EPvCode::MASK_FORECAST: { maskPage_ = std::make_shared<MaskPageForecast>(p); }
|
||||
break;
|
||||
case EPvCode::MASK_STAT_STORAGE:
|
||||
case EPvCode::MASK_STAT_SOLAR:
|
||||
case EPvCode::MASK_STAT_CHARGE:
|
||||
case EPvCode::MASK_STAT: { maskPage_ = std::make_shared<MaskPageStat>(p); }
|
||||
break;
|
||||
case EPvCode::MASK_SYSMGR:
|
||||
case EPvCode::MASK_MGR_USER:
|
||||
case EPvCode::MASK_MGR_ROLE:
|
||||
case EPvCode::MASK_MGR_PERMISSION:
|
||||
case EPvCode::MASK_MGR_STATION:
|
||||
case EPvCode::MASK_MGR_DEVICE:
|
||||
case EPvCode::MASK_MGR_POLICY:
|
||||
case EPvCode::MASK_MGR_SYSLOG:
|
||||
case EPvCode::MASK_MGR_ALERTLOG: { maskPage_ = std::make_shared<MaskPageSysmgr>(p); }
|
||||
break;
|
||||
default: { maskPage_ = std::make_shared<MaskPageHome>(p); }
|
||||
break;
|
||||
}
|
||||
if (maskPage_)
|
||||
{
|
||||
maskPage_->initUI(pvcode_);
|
||||
}
|
||||
|
||||
std::vector<std::string> vecMenuItems = {"系统总览", "运行监控", "预测管理", "统计分析", "系统管理"};
|
||||
{
|
||||
int n = vecMenuItems.size();
|
||||
int y=980, w = 100, margin = 10, h=40;
|
||||
int x0 = (1920 - (w*n + margin*(n-1))) * 0.5;
|
||||
for (int i = 0; i<vecMenuItems.size(); ++i)
|
||||
{
|
||||
std::string& title = vecMenuItems[i];
|
||||
EPvCode statusTmp = PvApp::getPvCode(title);
|
||||
int x = x0 + (w+margin)*i;
|
||||
int id = PvApp::button(p, 0, x, y, w, h, title, (statusTmp == pvcode_) ? STYLE_BTN_ACTIVE : STYLE_BTN);
|
||||
mapMenuInfo_[id] = std::make_pair(title, statusTmp);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::shared_ptr<PvMask> MaskMain::createSubPage(int pvid)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EPvCode MaskMain::onEventNull(int pvid)
|
||||
{
|
||||
pvSetText(p, ui.datetime, GetDateTimeWeekday().c_str());
|
||||
return EPvCode::NUL;
|
||||
}
|
||||
|
||||
EPvCode MaskMain::onEventButton(int pvid)
|
||||
{
|
||||
EPvCode pvcode = EPvCode::NUL;
|
||||
auto iter = mapMenuInfo_.find(pvid);
|
||||
if (iter != mapMenuInfo_.end())
|
||||
{
|
||||
return iter->second.second;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (maskPage_)
|
||||
{
|
||||
pvcode = maskPage_->onEventButton(pvid);
|
||||
}
|
||||
}
|
||||
return pvcode;
|
||||
}
|
||||
34
src/pv/MaskMain.h
Normal file
34
src/pv/MaskMain.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "pvapp.h"
|
||||
|
||||
static const std::string STYLE_BKG =
|
||||
"border-width:1 1 1 1px;"
|
||||
"border-style:outset solid;"
|
||||
"border-color:rgba(180,180,180,255);"
|
||||
"background-color:rgba(80,80,80,80);";
|
||||
|
||||
class MaskMain : public PvMask
|
||||
{
|
||||
public:
|
||||
struct {
|
||||
int bkg = PV_ID_NUL;
|
||||
int widgetMenu = PV_ID_NUL;
|
||||
int datetime = PV_ID_NUL;
|
||||
} ui;
|
||||
|
||||
std::map<int, std::pair<std::string, EPvCode>> mapMenuInfo_;
|
||||
|
||||
EPvCode pvcode_;
|
||||
std::shared_ptr<PvMask> maskPage_;
|
||||
|
||||
MaskMain(PARAM* p, EPvCode pvcode) : PvMask(p), pvcode_(pvcode) {}
|
||||
|
||||
int initUI();
|
||||
|
||||
std::shared_ptr<PvMask> createSubPage(int pvid);
|
||||
|
||||
EPvCode onEventNull(int pvid) override;
|
||||
EPvCode onEventButton(int pvid) override;
|
||||
|
||||
};
|
||||
226
src/pv/PvApp.cpp
Normal file
226
src/pv/PvApp.cpp
Normal file
@@ -0,0 +1,226 @@
|
||||
#include "PvApp.h"
|
||||
#include "PvUser.h"
|
||||
#include "TimeUtils.h"
|
||||
|
||||
|
||||
#define FONT_NAME "微软雅黑"
|
||||
|
||||
void PvApp::setPvUser(PARAM* p, PvUser* pvuser)
|
||||
{
|
||||
p->user = pvuser;
|
||||
}
|
||||
|
||||
PvUser* PvApp::getPvUser(PARAM* p)
|
||||
{
|
||||
return static_cast<PvUser*>(p->user);
|
||||
}
|
||||
|
||||
int PvApp::pvid(PARAM* p)
|
||||
{
|
||||
auto pvuser = PvApp::getPvUser(p);
|
||||
return (++pvuser->pvidIndex);
|
||||
}
|
||||
|
||||
void PvApp::reset(PARAM* p)
|
||||
{
|
||||
// 清理event回调
|
||||
auto pvuser = PvApp::getPvUser(p);
|
||||
pvuser->mapEventCallback.clear();
|
||||
pvuser->pvidIndex = 0;
|
||||
}
|
||||
|
||||
EPvCode PvApp::getPvCode(std::string name)
|
||||
{
|
||||
static std::map<std::string, EPvCode> mapPvCode =
|
||||
{
|
||||
{"系统总览", EPvCode::MASK_HOME},
|
||||
{"运行监控", EPvCode::MASK_RUNNING},
|
||||
{"预测管理", EPvCode::MASK_FORECAST},
|
||||
{"储能充放电预测", EPvCode::MASK_FORECAST_STORAGE},
|
||||
{"光伏发电预测", EPvCode::MASK_FORECAST_SOLAR},
|
||||
{"充电负荷预测", EPvCode::MASK_FORECAST_CHARGE},
|
||||
{"统计分析", EPvCode::MASK_STAT},
|
||||
{"储能设备运行分析", EPvCode::MASK_STAT_STORAGE},
|
||||
{"光伏设备运行分析", EPvCode::MASK_STAT_SOLAR},
|
||||
{"充电设备运行分析", EPvCode::MASK_STAT_CHARGE},
|
||||
{"系统管理", EPvCode::MASK_SYSMGR},
|
||||
{"用户管理", EPvCode::MASK_MGR_USER},
|
||||
{"角色管理", EPvCode::MASK_MGR_ROLE},
|
||||
{"权限管理", EPvCode::MASK_MGR_PERMISSION},
|
||||
{"场站管理", EPvCode::MASK_MGR_STATION},
|
||||
{"设备管理", EPvCode::MASK_MGR_DEVICE},
|
||||
{"策略管理", EPvCode::MASK_MGR_POLICY},
|
||||
{"系统日志", EPvCode::MASK_MGR_SYSLOG},
|
||||
{"告警日志", EPvCode::MASK_MGR_ALERTLOG},
|
||||
};
|
||||
auto iter = mapPvCode.find(name);
|
||||
if (iter != mapPvCode.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EPvCode::NUL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PvApp::bind(PARAM* p, PvEvent eid, int pvid, std::function<void(std::string text)> cb)
|
||||
{
|
||||
auto pvuser = PvApp::getPvUser(p);
|
||||
if (pvuser)
|
||||
{
|
||||
std::string event = std::to_string((int)eid) + ":" + std::to_string((int)pvid);
|
||||
pvuser->mapEventCallback[event] = cb;
|
||||
}
|
||||
}
|
||||
|
||||
void PvApp::dispatch(PARAM* p, PvEvent eid, int pvid, std::string text)
|
||||
{
|
||||
auto pvuser = PvApp::getPvUser(p);
|
||||
if (pvuser)
|
||||
{
|
||||
std::string event = std::to_string((int)eid) + ":" + std::to_string((int)pvid);
|
||||
auto iter = pvuser->mapEventCallback.find(event);
|
||||
if (iter != pvuser->mapEventCallback.end())
|
||||
{
|
||||
(iter->second)(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int PvApp::widget(PARAM* p, int parent, int x, int y, int w, int h)
|
||||
{
|
||||
int id = PvApp::pvid(p);
|
||||
pvQWidget(p, id, parent);
|
||||
pvSetGeometry(p, id, x, y, w, h);
|
||||
return id;
|
||||
}
|
||||
|
||||
int PvApp::label(PARAM* p, int parent, int x, int y, int w, int h, std::string text, std::string qss)
|
||||
{
|
||||
int id = PvApp::pvid(p);
|
||||
pvQLabel(p, id, parent);
|
||||
pvSetGeometry(p, id, x, y, w, h);
|
||||
pvSetFont(p, id, FONT_NAME, 14, 1, 0, 0, 0);
|
||||
pvSetFontColor(p, id, 255, 255, 255);
|
||||
if (!text.empty()) { pvSetText(p, id, text.c_str()); }
|
||||
if (!qss.empty()) { pvSetStyleSheet(p, id, qss.c_str()); }
|
||||
return id;
|
||||
}
|
||||
int PvApp::labelAlignCenter(PARAM* p, int parent, int x, int y, int w, int h, std::string text, std::string qss)
|
||||
{
|
||||
int id = PvApp::label(p, parent, x, y, w, h, text, qss);
|
||||
pvSetAlignment(p, id, AlignCenter);
|
||||
return id;
|
||||
}
|
||||
|
||||
int PvApp::button(PARAM* p, int parent, int x, int y, int w, int h, std::string text, std::string qss)
|
||||
{
|
||||
int id = PvApp::pvid(p);
|
||||
pvQPushButton(p, id, parent);
|
||||
pvSetGeometry(p, id, x, y, w, h);
|
||||
pvSetFont(p, id, FONT_NAME, 14, 1, 0, 0, 0);
|
||||
pvSetFontColor(p, id, 255, 255, 255);
|
||||
if (!text.empty()) { pvSetText(p, id, text.c_str()); }
|
||||
if (!qss.empty()) { pvSetStyleSheet(p, id, qss.c_str()); }
|
||||
return id;
|
||||
}
|
||||
|
||||
int PvApp::image(PARAM* p, int parent, int x, int y, int w, int h, const char* filename)
|
||||
{
|
||||
int id = PvApp::pvid(p);
|
||||
pvQImage(p, id, parent, filename);
|
||||
pvSetGeometry(p, id, x, y, w, h);
|
||||
//if (!qss.empty()) { pvSetStyleSheet(p, id, qss.c_str()); }
|
||||
return id;
|
||||
}
|
||||
|
||||
int PvApp::combox(PARAM* p, int parent, int x, int y, int w, int h, const std::vector<std::string>& vecItems)
|
||||
{
|
||||
int id = PvApp::pvid(p);
|
||||
pvQComboBox(p, id, parent, 0, 0);
|
||||
pvSetGeometry(p, id, x, y, w, h);
|
||||
pvSetStyleSheet(p, id, QSS_COMBOX_14.c_str());
|
||||
for (int i=0; i<vecItems.size(); ++i)
|
||||
{
|
||||
pvInsertItem(p, id, i, NULL, vecItems[i].c_str());
|
||||
}
|
||||
PvApp::image(p, id, w-h, 0, h, h, "downFill.png");
|
||||
return id;
|
||||
}
|
||||
|
||||
int PvApp::lineEdit(PARAM* p, int parent, int x, int y, int w, int h, std::string text, std::string qss)
|
||||
{
|
||||
int id = PvApp::pvid(p);
|
||||
pvQLineEdit(p, id, parent);
|
||||
pvSetGeometry(p, id, x, y, w, h);
|
||||
pvSetStyleSheet(p, id, QSS_LINEEDIT.c_str());
|
||||
if (!text.empty()) { pvSetText(p, id, text.c_str()); }
|
||||
return id;
|
||||
}
|
||||
|
||||
PvRect::PvRect()
|
||||
{
|
||||
}
|
||||
|
||||
PvRect::PvRect(int ix, int iy, int width, int height)
|
||||
: x(ix), y(iy), w(width), h(height)
|
||||
{
|
||||
}
|
||||
|
||||
PvRect& PvRect::set(int ix, int iy, int width, int height)
|
||||
{
|
||||
x = ix;
|
||||
y = iy;
|
||||
w = width;
|
||||
h = height;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PvRect& PvRect::set_x(int ix)
|
||||
{
|
||||
x = ix;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PvRect& PvRect::set_y(int iy)
|
||||
{
|
||||
y = iy;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PvRect& PvRect::set_w(int iw)
|
||||
{
|
||||
w = iw;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PvRect& PvRect::set_h(int ih)
|
||||
{
|
||||
h = ih;
|
||||
return *this;
|
||||
}
|
||||
PvRect& PvRect::shift_x(int ix)
|
||||
{
|
||||
x += ix;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PvRect& PvRect::shift_y(int iy)
|
||||
{
|
||||
y += iy;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PvRect& PvRect::shift_w(int iw)
|
||||
{
|
||||
w += iw;
|
||||
return *this;
|
||||
}
|
||||
|
||||
PvRect& PvRect::shift_h(int ih)
|
||||
{
|
||||
h += ih;
|
||||
return *this;
|
||||
}
|
||||
151
src/pv/PvApp.h
Normal file
151
src/pv/PvApp.h
Normal file
@@ -0,0 +1,151 @@
|
||||
#pragma once
|
||||
|
||||
#include "processviewserver.h"
|
||||
#include "rleventlogserver.h"
|
||||
#include "rltime.h"
|
||||
#include "rlcutil.h"
|
||||
#include "rlsvganimator.h"
|
||||
#include <math.h>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
#include "PvStyle.h"
|
||||
#include "common/Logger.h"
|
||||
|
||||
// 主窗口的 id 是 0,其它创建的控件都是主窗口的子控件,在创建子控件时,id 从 1 开始累加
|
||||
#define PV_ID_MAIN 0
|
||||
#define PV_ID_NUL -999
|
||||
|
||||
enum class EPvMaskID
|
||||
{
|
||||
NUL = 0,
|
||||
LOGIN,
|
||||
HOME,
|
||||
Running,
|
||||
SysManage,
|
||||
Statistics,
|
||||
};
|
||||
|
||||
enum class EPvCode
|
||||
{
|
||||
NUL = 0,
|
||||
MASK_LOGIN,
|
||||
MASK_HOME,
|
||||
MASK_RUNNING,
|
||||
MASK_FORECAST,
|
||||
MASK_FORECAST_STORAGE,
|
||||
MASK_FORECAST_SOLAR,
|
||||
MASK_FORECAST_CHARGE,
|
||||
MASK_STAT,
|
||||
MASK_STAT_STORAGE,
|
||||
MASK_STAT_SOLAR,
|
||||
MASK_STAT_CHARGE,
|
||||
MASK_SYSMGR,
|
||||
MASK_MGR_USER,
|
||||
MASK_MGR_ROLE,
|
||||
MASK_MGR_PERMISSION,
|
||||
MASK_MGR_STATION,
|
||||
MASK_MGR_DEVICE,
|
||||
MASK_MGR_POLICY,
|
||||
MASK_MGR_SYSLOG,
|
||||
MASK_MGR_ALERTLOG,
|
||||
};
|
||||
|
||||
class PvObject
|
||||
{
|
||||
public:
|
||||
PARAM* p = NULL;
|
||||
int pvid = PV_ID_NUL;
|
||||
PvObject(PARAM* p) : p(p) {}
|
||||
void show(bool v) { if (p && pvid != PV_ID_NUL) { v ? pvShow(p, pvid) : pvHide(p, pvid); } }
|
||||
virtual EPvCode onEventNull(int pvid) { return EPvCode::NUL; }
|
||||
virtual EPvCode onEventButton(int pvid) { return EPvCode::NUL; }
|
||||
virtual EPvCode onEventText() { return EPvCode::NUL; }
|
||||
};
|
||||
|
||||
class PvMask : public PvObject
|
||||
{
|
||||
public:
|
||||
PvMask(PARAM* p) : PvObject(p) {};
|
||||
|
||||
virtual int initUI(EPvCode pvcode) { return 0; };
|
||||
};
|
||||
|
||||
class PvUser;
|
||||
|
||||
class PvApp
|
||||
{
|
||||
public:
|
||||
static void setPvUser(PARAM* p, PvUser* pvuser);
|
||||
static PvUser* getPvUser(PARAM* p);
|
||||
|
||||
static int pvid(PARAM* p);
|
||||
static void reset(PARAM* p);
|
||||
|
||||
static EPvCode getPvCode(std::string name);
|
||||
|
||||
static void bind(PARAM* p, PvEvent eid, int pvid, std::function<void(std::string text)> cb);
|
||||
static void dispatch(PARAM* p, PvEvent eid, int pvid, std::string text);
|
||||
|
||||
static int widget(PARAM* p, int parent, int x, int y, int w, int h);
|
||||
|
||||
static int label(PARAM* p, int parent, int x, int y, int w, int h, std::string text, std::string qss = "");
|
||||
|
||||
static int labelAlignCenter(PARAM* p, int parent, int x, int y, int w, int h, std::string text, std::string qss = "");
|
||||
|
||||
static int button(PARAM* p, int parent, int x, int y, int w, int h, std::string text, std::string qss = "");
|
||||
|
||||
static int image(PARAM* p, int parent, int x, int y, int w, int h, const char* filename);
|
||||
|
||||
static int combox(PARAM* p, int parent, int x, int y, int w, int h, const std::vector<std::string>& vecItems);
|
||||
|
||||
static int lineEdit(PARAM* p, int parent, int x, int y, int w, int h, std::string text, std::string qss = "");
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// === PvRect
|
||||
class PvRect
|
||||
{
|
||||
public:
|
||||
PvRect();
|
||||
|
||||
PvRect(int ix, int iy, int width, int height);
|
||||
|
||||
PvRect& set(int ix, int iy, int width, int height);
|
||||
|
||||
PvRect& set_x(int ix);
|
||||
PvRect& set_y(int iy);
|
||||
PvRect& set_w(int iw);
|
||||
PvRect& set_h(int ih);
|
||||
|
||||
PvRect& shift_x(int ix);
|
||||
PvRect& shift_y(int iy);
|
||||
PvRect& shift_w(int iw);
|
||||
PvRect& shift_h(int ih);
|
||||
|
||||
public:
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int w = 100;
|
||||
int h = 32;
|
||||
};
|
||||
|
||||
struct PvColor
|
||||
{
|
||||
int r;
|
||||
int g;
|
||||
int b;
|
||||
int a;
|
||||
|
||||
PvColor(int r, int g, int b, int a = 255) : r(r), g(g), b(b), a(a) {}
|
||||
std::string rgb()
|
||||
{
|
||||
return "rgb(" + std::to_string(r) + "," + std::to_string(g) + "," + std::to_string(b) + ")";
|
||||
}
|
||||
std::string rgba()
|
||||
{
|
||||
return "rgb(" + std::to_string(r) + "," + std::to_string(g) + "," + std::to_string(b) + "," + std::to_string(a) + ")";
|
||||
}
|
||||
};
|
||||
409
src/pv/PvChart.cpp
Normal file
409
src/pv/PvChart.cpp
Normal file
@@ -0,0 +1,409 @@
|
||||
#include "PvChart.h"
|
||||
#include "TimeUtils.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// === PvChartBar
|
||||
|
||||
PvChartBar::PvChartBar(PARAM* p, int parentId, int x, int y, int w, int h)
|
||||
: PvObject(p)
|
||||
{
|
||||
pvid_ = PvApp::label(p, parentId, x, y, w, h, "", "border: none; border-radius: 0px; background-color: transparent; color:white; font: normal 12px;");
|
||||
|
||||
boxBar_.x = 40;
|
||||
boxBar_.y = 56;
|
||||
boxBar_.w = w - boxBar_.x * 2;
|
||||
boxBar_.h = h - boxBar_.y - 38;
|
||||
boxBar_.id = PvApp::label(p, pvid_, boxBar_.x, boxBar_.y, boxBar_.w+1, boxBar_.h+1, "", "border: none; background-color: transparent;");
|
||||
|
||||
|
||||
int hMargin = 5;
|
||||
{
|
||||
// 左侧X轴
|
||||
yAxisLeft_.widget = PvApp::label(p, pvid_, 0, 0, boxBar_.x, h, "", "");
|
||||
PvApp::label(p, yAxisLeft_.widget, boxBar_.x-1, boxBar_.y, 1, boxBar_.h, "", "border: 1px solid white;");
|
||||
}
|
||||
{
|
||||
yAxisRight_.widget = PvApp::label(p, pvid_, boxBar_.x + boxBar_.w, 0, boxBar_.x, h, "", "");
|
||||
PvApp::label(p, yAxisRight_.widget, 0, boxBar_.y, 1, boxBar_.h, "", "border: 1px solid white;");
|
||||
}
|
||||
|
||||
yLabelLeft_ = PvApp::label(p, pvid_, 0, 0, boxBar_.x*2, boxBar_.y-10, "", "font: bold 14px; color: white;");
|
||||
pvSetAlignment(p, yLabelLeft_, AlignHCenter | AlignBottom);
|
||||
yLabelRight_ = PvApp::label(p, pvid_, boxBar_.w, 0, boxBar_.x*2, boxBar_.y-5, "", "font: bold 14px; color: white;");
|
||||
pvSetAlignment(p, yLabelRight_, AlignHCenter | AlignBottom);
|
||||
|
||||
// Y轴分成5段
|
||||
setTickX(7);
|
||||
setTickY(5);
|
||||
}
|
||||
|
||||
void PvChartBar::setTickX(int n)
|
||||
{
|
||||
vecTickX_.resize(n);
|
||||
// 每一段的长度:
|
||||
int len = int(float(boxBar_.w)/float(n));
|
||||
int y = boxBar_.y + boxBar_.h;
|
||||
// X轴分成 n 段,共有 n 条刻度线
|
||||
for (int i = 0; i<n; ++i)
|
||||
{
|
||||
int x = boxBar_.x + float(boxBar_.w) * float(i)/float(n);
|
||||
PvApp::label(p, pvid_, x+len*0.5, y+5, 1, 10, "", "border: 1px solid white;");
|
||||
int id = PvApp::label(p, pvid_, x, y+12, len, 28, std::to_string(n-i+1), "font: normal 12px;");
|
||||
pvSetAlignment(p, id, AlignCenter);
|
||||
vecTickX_[i] = id;
|
||||
}
|
||||
PvApp::label(p, pvid_, boxBar_.x, y+5, boxBar_.w, 1, "", "border: 1px solid white;");
|
||||
}
|
||||
|
||||
void PvChartBar::setTickY(int n)
|
||||
{
|
||||
yAxisLeft_.vecTick_.resize(n+1);
|
||||
yAxisRight_.vecTick_.resize(n+1);
|
||||
|
||||
// 每一段的长度:
|
||||
int len = int(float(boxBar_.h)/float(n));
|
||||
// 刻度文字label的高度
|
||||
int hLabel = 20;
|
||||
// 刻度线的长度
|
||||
int wLine = 8;
|
||||
// Y轴分成 n 段,共有 n+1 条刻度线
|
||||
for (int i = 0; i<=n; ++i)
|
||||
{
|
||||
// 刻度线的位置
|
||||
int y = boxBar_.y + float(boxBar_.h) * float(n-i)/float(n);
|
||||
{
|
||||
// 左侧刻度线
|
||||
PvApp::label(p, yAxisLeft_.widget, boxBar_.x-wLine, y, wLine, 1, "", "border: 1px solid white;");
|
||||
// 左侧刻度text
|
||||
int id = PvApp::label(p, yAxisLeft_.widget, 0, y-hLabel*0.5, boxBar_.x-wLine-3, hLabel, std::to_string(i), "");
|
||||
pvSetAlignment(p, id, AlignRight | AlignVCenter);
|
||||
yAxisLeft_.vecTick_[i] = id;
|
||||
}
|
||||
{
|
||||
// 右侧刻度线
|
||||
PvApp::label(p, yAxisRight_.widget, 0, y, wLine, 1, "", "border: 1px solid white;");
|
||||
// 右侧刻度text
|
||||
int id = PvApp::label(p, yAxisRight_.widget, 8+3, y-hLabel*0.5, boxBar_.x-wLine-3, hLabel, std::to_string(i), "");
|
||||
pvSetAlignment(p, id, AlignLeft | AlignVCenter);
|
||||
yAxisRight_.vecTick_[i] = id;
|
||||
}
|
||||
// Y轴的网格线
|
||||
PvApp::label(p, pvid_, boxBar_.x, y, boxBar_.w, 1, "", "border: none; border-top: 1px dashed white; background-color: rgb(80,80,80,0); color:white;");
|
||||
}
|
||||
setRangeY(0, n);
|
||||
}
|
||||
|
||||
void PvChartBar::setRangeY(double vmin, double vmax)
|
||||
{
|
||||
int n = yAxisLeft_.vecTick_.size();
|
||||
int step = std::ceil((vmax - vmin)/double(n-1));
|
||||
yLeftMin = vmin;
|
||||
yLeftMax = vmin + step * (n-1);
|
||||
for (int i = 0; i<n; ++i)
|
||||
{
|
||||
pvSetText(p, yAxisLeft_.vecTick_[i], std::to_string(int(yLeftMin + i* step)).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void PvChartBar::setLabelYLeft(std::string name)
|
||||
{
|
||||
if (yLabelLeft_ != PV_ID_NUL) { pvSetText(p, yLabelLeft_, name.c_str()); }
|
||||
|
||||
}
|
||||
void PvChartBar::setLabelYRight(std::string name)
|
||||
{
|
||||
if (yLabelRight_ != PV_ID_NUL) { pvSetText(p, yLabelRight_, name.c_str()); }
|
||||
}
|
||||
|
||||
static std::vector<std::string> vecSeriesColor =
|
||||
{
|
||||
"rgb(84, 112, 198);", "rgb(169, 223, 150);", "rgb(246, 220, 125);", "rgb(84, 112, 198);", "rgb(169, 223, 150);", "rgb(246, 220, 125);"
|
||||
};
|
||||
|
||||
void PvChartBar::insertItem(std::string text)
|
||||
{
|
||||
int index = vecItems_.size();
|
||||
int nItem = index+1;
|
||||
|
||||
// 根据 X 轴的分段数量创建 bar
|
||||
int n = vecTickX_.size();
|
||||
// 每一段的绘制区域的长度,左右保留间距 5px, 计算每一个柱体的宽度
|
||||
int wBar = (int(float(boxBar_.w)/float(n)) - margin) / nItem;
|
||||
|
||||
// 如果不是第一个序列项,需要重新计算前面序列的宽度
|
||||
for (int i = 0; i<index; ++i)
|
||||
{
|
||||
auto& bar = vecItems_[i].bar_;
|
||||
for (int pos = 0; pos<bar.size(); ++pos)
|
||||
{
|
||||
int h = 0; // bar 初始高度设置为0
|
||||
int x = boxBar_.x + float(boxBar_.w) * float(pos)/float(n) + margin + wBar*i;
|
||||
int y = boxBar_.y + boxBar_.h -h;
|
||||
pvSetGeometry(p, bar[pos], x, y, wBar-5, h);
|
||||
}
|
||||
}
|
||||
|
||||
BarItem barItem;
|
||||
barItem.name = text;
|
||||
int labelWidth = text.size()*12*0.4 + 18;
|
||||
barItem.idItem = PvApp::label(p, pvid_, itemLabelPos, 10, labelWidth, 18, text, "border: none; font: normal 12px; border-left: 18px solid " + vecSeriesColor[index]);
|
||||
itemLabelPos += (labelWidth + 10);
|
||||
barItem.bar_.resize(n);
|
||||
for (int pos = 0; pos<n; ++pos)
|
||||
{
|
||||
int h = 0; // bar 初始高度设置为0
|
||||
int x = boxBar_.x + float(boxBar_.w) * float(pos)/float(n) + margin + wBar*index;
|
||||
int y = boxBar_.y + boxBar_.h -h;
|
||||
barItem.bar_[pos] = PvApp::label(p, pvid_, x, y, wBar-5, h, "", "border:0px; background-color: " + vecSeriesColor[index]);
|
||||
}
|
||||
vecItems_.push_back(barItem);
|
||||
}
|
||||
|
||||
|
||||
void PvChartBar::updateItem(int index, std::vector<std::pair<std::string, double>> vd)
|
||||
{
|
||||
int nItems = vecItems_.size();
|
||||
if (index >= nItems)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
double vmax = yLeftMax;
|
||||
// 计算Y轴的范围, 获取数据中的最大值 (先不考虑最小值,最小值使用0)
|
||||
for (int i = 0; i<vd.size(); ++i)
|
||||
{
|
||||
auto& val = vd[i].second;
|
||||
if (val > vmax) { vmax = val; }
|
||||
}
|
||||
setRangeY(0, vmax);
|
||||
|
||||
// 计算和重绘 bar
|
||||
// Y轴差值
|
||||
double delta = double(yLeftMax - yLeftMin);
|
||||
auto& bar = vecItems_[index].bar_;
|
||||
|
||||
// 根据 X 轴的分段数量创建 bar
|
||||
int n = vecTickX_.size();
|
||||
// 每一段的绘制区域的长度,左右保留间距 5px, 计算每一个柱体的宽度
|
||||
int wBar = (int(float(boxBar_.w)/float(n)) - margin) / vecItems_.size();
|
||||
|
||||
for (int pos = 0; pos<bar.size(); ++pos)
|
||||
{
|
||||
if (pos < vd.size())
|
||||
{
|
||||
double v = vd[pos].second;
|
||||
int h = double(boxBar_.h)*v/delta;
|
||||
int x = boxBar_.x + float(boxBar_.w) * float(pos)/float(n) + margin + wBar*index;
|
||||
int y = boxBar_.y + boxBar_.h -h;
|
||||
pvSetGeometry(p, bar[pos], x, y, wBar-5, h);
|
||||
// 设置X轴
|
||||
pvSetText(p, vecTickX_[pos], vd[pos].first.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// === PvChartCurve
|
||||
PvChartCurve::PvChartCurve(PARAM* p, int parent, int x, int y, int w, int h) : PvObject(p)
|
||||
{
|
||||
rect_.set(x, y, w, h);
|
||||
pvid_ = PvApp::label(p, parent, x, y, w, h, "", "border: none; border-radius: 0px; background-color: transparent;");
|
||||
plotId_ = PvApp::pvid(p);
|
||||
pvQwtPlotWidget(p, plotId_, pvid_, 100, 100);
|
||||
pvSetGeometry(p, plotId_, 10, 50, w - 20, h - 58);
|
||||
pvSetFont(p, plotId_, "微软雅黑", 16, 0, 0, 0, 0);
|
||||
|
||||
// 设置标题
|
||||
//qpwSetTitle(p,id_,"30日曲线");
|
||||
// 设置背景色
|
||||
qpwSetCanvasBackground(p, plotId_, 64, 102, 124);
|
||||
// 设置横轴网格线 // NoPen, SolidLine, DashLine, DotLine, DashDotLine, DashDotDotLine, MPenStyle
|
||||
qpwSetGridMajPen(p, plotId_, 175, 196, 211, DotLine);
|
||||
|
||||
qpwEnableOutline(p, plotId_, 1);
|
||||
qpwSetOutlinePen(p, plotId_, 255, 0, 0);
|
||||
|
||||
// 设置坐标轴位置:左侧,底部 // yLeft,yRight,xBottom,xTop,axisCnt
|
||||
//qpwEnableAxis(p, plot_id_, yLeft);
|
||||
//qpwSetAxisTitle(p, plot_id_, yLeft, "Y轴说明");
|
||||
//qpwEnableAxis(p, plot_id_, yRight);
|
||||
//qpwSetAxisTitle(p, plot_id_, yRight, "Y轴说明");
|
||||
qpwEnableAxis(p, plotId_, xBottom);
|
||||
//qpwSetAxisTitle(p, id_, xBottom, "X轴说明");
|
||||
//
|
||||
qpwSetAxisScale(p, plotId_, xBottom, 0, 15 * 60 * 7, 15 * 60);
|
||||
qpwSetAxisScale(p, plotId_, yLeft, 0, 100, 20);
|
||||
|
||||
// 不知道效果
|
||||
qpwSetAxisOptions(p, plotId_, xBottom, Inverted); // pvNone = 0,IncludeRef = 1,Symmetric = 2,Floating = 4,Logarithmic = 8,InvertedInverted = 16
|
||||
|
||||
//this->mark(p, 0, 10, 100);
|
||||
//this->mark(p, 1, 11, 100);
|
||||
|
||||
yLabelLeft = PvApp::label(p, pvid_, 10, 24, 100, 20, "", "border:none;color:white;font-size:14px;font-weight:bold;");
|
||||
pvSetAlignment(p, yLabelLeft, AlignLeft);
|
||||
yLabelRight = PvApp::label(p, pvid_, rect_.w - 100 - 10, 24, 100, 20, "", "border:none;color:white;font-size:14px;font-weight:bold;");
|
||||
pvSetAlignment(p, yLabelRight, AlignRight);
|
||||
}
|
||||
|
||||
void PvChartCurve::setBackground(PARAM* p, int r, int g, int b)
|
||||
{
|
||||
qpwSetCanvasBackground(p, plotId_, r, g, b);
|
||||
std::string qss = "border: none; border-radius: 0px; background-color: " + PvColor(r, g, b).rgb() + ";";
|
||||
pvSetStyleSheet(p, pvid_, qss.c_str());
|
||||
}
|
||||
|
||||
void PvChartCurve::setLabelYLeft(std::string title, float min, float max, float step)
|
||||
{
|
||||
yLeftMin_ = min;
|
||||
yLeftMax_ = max;
|
||||
yLeftStep_ = step;
|
||||
qpwSetAxisScale(p, plotId_, yLeft, min, max, step);
|
||||
qpwEnableAxis(p, plotId_, yLeft);
|
||||
//qpwSetAxisTitle(p, id_, yLeft, "Y轴说明");
|
||||
pvSetText(p, yLabelLeft, title.c_str());
|
||||
}
|
||||
|
||||
void PvChartCurve::setLabelYRight(std::string title, float min, float max, float step)
|
||||
{
|
||||
yRightMin_ = min;
|
||||
yRightMax_ = max;
|
||||
yRightStep_ = step;
|
||||
qpwSetAxisScale(p, plotId_, yRight, min, max, step);
|
||||
qpwEnableAxis(p, plotId_, yRight);
|
||||
//qpwSetAxisTitle(p, id_, yRight, "Y轴说明");
|
||||
|
||||
pvSetText(p, yLabelRight, title.c_str());
|
||||
}
|
||||
|
||||
void PvChartCurve::setXBottom(float min, float max, float step)
|
||||
{
|
||||
qpwSetAxisScale(p, plotId_, xBottom, min, max, step);
|
||||
qpwReplot(p, plotId_);
|
||||
}
|
||||
void PvChartCurve::setXBottomFormat(std::string fmt)
|
||||
{
|
||||
// 设置时间轴 "yyyy-MM-dd hh:mm:ss"
|
||||
qpwSetAxisScaleDraw(p, plotId_, xBottom, fmt.c_str());
|
||||
}
|
||||
|
||||
static std::vector<PvColor> g_mapSeriesColor =
|
||||
{
|
||||
PvColor(84, 112, 198), PvColor(169, 223, 150), PvColor(246, 220, 125), PvColor(84, 112, 198), PvColor(169, 223, 150), PvColor(246, 220, 125)
|
||||
};
|
||||
|
||||
int PvChartCurve::insertItem(int pos, std::string name, int x, int y, int w)
|
||||
{
|
||||
int index = vecItems_.size();
|
||||
|
||||
auto& color = g_mapSeriesColor[index];
|
||||
PvApp::label(p, pvid_, x, y + 3, 14, 14, "", "background-color:" + color.rgb() + ";border-radius:7px;");
|
||||
PvApp::label(p, pvid_, x + 16, y, w - 16, 18, name, "color:white;font:normal 12px;border:0px solid #ff0000;");
|
||||
|
||||
// 添加数据曲线
|
||||
qpwInsertCurve(p, plotId_, index, name.c_str());
|
||||
// 设置曲线颜色和类型 // NoPen,SolidLine,DashLine,DotLine,DashDotLine,DashDotDotLine,MPenStyle = 0x0f
|
||||
qpwSetCurvePen(p, plotId_, index, color.r, color.g, color.b, 2, SolidLine);
|
||||
//qpwSetCurveSymbol(p_, plot_id_, index, MarkerNone, col.r, col.g, col.b, WHITE, 4, 4);
|
||||
|
||||
// 设置数据对应的Y轴(LEFT或RIGHT)
|
||||
qpwSetCurveYAxis(p, plotId_, index, (pos == 0) ? yLeft : yRight);
|
||||
|
||||
CurveItem item;
|
||||
item.name = name;
|
||||
item.pos = pos;
|
||||
vecItems_.push_back(item);
|
||||
return index;
|
||||
}
|
||||
|
||||
void PvChartCurve::updateItem(int index, const std::vector<std::pair<double, double>>& data)
|
||||
{
|
||||
if (index >= vecItems_.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto& item = vecItems_[index];
|
||||
|
||||
int64_t tCurrent = TimeUtils::now();
|
||||
int yMax = 0;
|
||||
int size = (int)data.size();
|
||||
std::vector<double> vx(size, 0);
|
||||
std::vector<double> vy(size, 0);
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
{
|
||||
vx[i] = data[i].first;
|
||||
vy[i] = data[i].second;
|
||||
if (yMax < data[i].second) { yMax = data[i].second; }
|
||||
}
|
||||
this->reviseYMax(item.pos, yMax);
|
||||
qpwSetCurveData(p, plotId_, index, size, &vx[0], &vy[0]);
|
||||
qpwReplot(p, plotId_);
|
||||
}
|
||||
|
||||
|
||||
int64_t PvChartCurve::set_range_x_days(int n)
|
||||
{
|
||||
this->setXBottomFormat("MM/dd");
|
||||
int step = 3600 * 24;
|
||||
auto t_end = TimeUtils::datetime2ts(TimeUtils::now_date() + " 08:00:00");
|
||||
auto t_start = t_end - step * (n - 1);
|
||||
this->setXBottom(t_start, t_end, step);
|
||||
return t_start;
|
||||
}
|
||||
|
||||
int64_t PvChartCurve::set_range_x_day_by_hour(int n)
|
||||
{
|
||||
this->setXBottomFormat("hh:mm");
|
||||
auto t_start = TimeUtils::datetime2ts(TimeUtils::now_date() + " 00:00:00");
|
||||
auto t_end = t_start + 86400;
|
||||
this->setXBottom(t_start, t_end, 86400 / n);
|
||||
return t_start;
|
||||
}
|
||||
|
||||
|
||||
void PvChartCurve::reviseYMax(int pos, double v)
|
||||
{
|
||||
bool isLeft = (pos == 0);
|
||||
|
||||
int min = (isLeft ? yLeftMin_ : yRightMin_);
|
||||
int max = (isLeft ? yLeftMax_ : yRightMax_);
|
||||
int step = (isLeft ? yLeftStep_ : yRightStep_);
|
||||
|
||||
while (v > max)
|
||||
{
|
||||
max += (max-min);
|
||||
step *= 2;
|
||||
}
|
||||
qpwSetAxisScale(p, plotId_, yLeft, min, max, step);
|
||||
qpwSetAxisScale(p, plotId_, yRight, min, max, step);
|
||||
}
|
||||
|
||||
void PvChartCurve::update_days_test(int n)
|
||||
{
|
||||
int step = 3600*24/n;
|
||||
auto t_start = TimeUtils::datetime2ts(TimeUtils::now_date() + " 00:00:00");
|
||||
auto t_end = t_start+3600*24;
|
||||
|
||||
std::vector<std::pair<double, double>> vd(n);
|
||||
double v = 100;
|
||||
for (int index = 0; index < vecItems_.size(); ++index)
|
||||
{
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
vd[i].first = static_cast<double>(t_start + i * step);
|
||||
vd[i].second = v += 2;// (v += (Utils::random(0, 10)-5));
|
||||
};
|
||||
this->updateItem(index, vd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PvChartCurve::mark(PARAM* p, int index, float x, float y, std::string text)
|
||||
{
|
||||
qpwInsertMarker(p, plotId_, 0);
|
||||
qpwSetMarkerPos(p, plotId_, index, x, y);
|
||||
//MarkerNone,MarkerEllipse,MarkerRect,MarkerDiamond,MarkerTriangle,MarkerDTriangle,MarkerUTriangle,MarkerLTriangle,MarkerRTriangle,MarkerCross,MarkerXCross,MarkerStyleCnt
|
||||
qpwSetMarkerSymbol(p, plotId_, 0, MarkerEllipse, RED, GREEN, 10, 10);
|
||||
qpwSetMarkerFont(p, plotId_, 0, "微软雅黑", 14, 1);
|
||||
qpwSetMarkerLabel(p, plotId_, 0, text.c_str());
|
||||
}
|
||||
119
src/pv/PvChart.h
Normal file
119
src/pv/PvChart.h
Normal file
@@ -0,0 +1,119 @@
|
||||
#include "PvApp.h"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// === PvChartBar
|
||||
class PvChartBar : public PvObject
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<PvChartBar> create(PARAM* p, int parentId, int x, int y, int w, int h)
|
||||
{
|
||||
return std::make_shared<PvChartBar>(p, parentId, x, y, w, h);
|
||||
}
|
||||
|
||||
PvChartBar(PARAM* p, int parentId, int x, int y, int w, int h);
|
||||
|
||||
void setTickX(int n);
|
||||
void setTickY(int n);
|
||||
|
||||
void insertItem(std::string text);
|
||||
void updateItem(int index, std::vector<std::pair<std::string, double>> vd);
|
||||
|
||||
void setRangeY(double vmin, double vmax);
|
||||
void setLabelYLeft(std::string name);
|
||||
void setLabelYRight(std::string name);
|
||||
|
||||
int pvid_;
|
||||
|
||||
struct {
|
||||
int x;
|
||||
int y;
|
||||
int w;
|
||||
int h;
|
||||
int id;
|
||||
} boxBar_;
|
||||
|
||||
struct AxisTick {
|
||||
int widget = PV_ID_NUL;
|
||||
std::vector<int> vecTick_;
|
||||
};
|
||||
|
||||
AxisTick yAxisLeft_;
|
||||
AxisTick yAxisRight_;
|
||||
AxisTick xAxis_;
|
||||
|
||||
int yLabelLeft_ = PV_ID_NUL;
|
||||
int yLabelRight_ = PV_ID_NUL;
|
||||
|
||||
std::vector<int> vecTickX_;
|
||||
|
||||
struct BarItem {
|
||||
std::string name;
|
||||
int idItem;
|
||||
std::vector<int> bar_;
|
||||
};
|
||||
|
||||
std::vector<BarItem> vecItems_;
|
||||
int itemLabelPos = 100;
|
||||
|
||||
|
||||
int yLeftMin = 0;
|
||||
int yLeftMax = 0;
|
||||
int yMinRight = 0;
|
||||
int yMaxRight = 0;
|
||||
|
||||
// 绘制区域的间距、柱体的间距
|
||||
int margin = 5;
|
||||
};
|
||||
|
||||
//****************************************************************************************************
|
||||
// 曲线图
|
||||
//
|
||||
class PvChartCurve : public PvObject
|
||||
{
|
||||
public:
|
||||
PvChartCurve(PARAM* p, int parent, int x, int y, int w, int h);
|
||||
|
||||
void setBackground(PARAM* p, int r, int g, int b);
|
||||
|
||||
void setLabelYLeft(std::string name, float min = 0, float max = 100, float step = 20);
|
||||
void setLabelYRight(std::string name, float min = 0, float max = 100, float step = 20);
|
||||
|
||||
void setXBottom(float min, float max, float step);
|
||||
void setXBottomFormat(std::string fmt);
|
||||
|
||||
int insertItem(int pos, std::string name, int x, int y, int w);
|
||||
void updateItem(int index, const std::vector<std::pair<double, double>>& data);
|
||||
|
||||
int64_t set_range_x_days(int n);
|
||||
int64_t set_range_x_day_by_hour(int n);
|
||||
|
||||
void update_days_test(int n);
|
||||
void mark(PARAM* p, int index, float x, float y, std::string text);
|
||||
void reviseYMax(int pos, double v);
|
||||
|
||||
private:
|
||||
PvRect rect_;
|
||||
int pvid_;
|
||||
int plotId_;
|
||||
int start_num_ = 0;
|
||||
|
||||
int labTimeLine_;
|
||||
std::vector<std::pair<int, int>> vecTimeAxisId_;
|
||||
|
||||
struct CurveItem
|
||||
{
|
||||
std::string name;
|
||||
int pos;
|
||||
};
|
||||
std::vector<CurveItem> vecItems_;
|
||||
|
||||
int yLabelLeft = PV_ID_NUL;
|
||||
int yLabelRight = PV_ID_NUL;
|
||||
|
||||
int yLeftMin_ = 0;
|
||||
int yLeftMax_ = 0;
|
||||
int yLeftStep_ = 0;
|
||||
int yRightMin_ = 0;
|
||||
int yRightMax_ = 0;
|
||||
int yRightStep_ = 0;
|
||||
};
|
||||
113
src/pv/PvPopWidget.cpp
Normal file
113
src/pv/PvPopWidget.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "PvPopWidget.h"
|
||||
|
||||
PvPopWidget::PvPopWidget(PARAM* p, int width, int height) : PvObject(p), width(width), height(height)
|
||||
{
|
||||
pvid = PvApp::widget(p, PV_ID_MAIN, 0, 0, 1920, 1080);
|
||||
PvApp::label(p, pvid, 0, 0, 1920, 1080, "", "background-color: rgba(30,30,30,180);");
|
||||
|
||||
int x = (1920-width) *0.5;
|
||||
int y = (1080-height) *0.5;
|
||||
ui.widget = PvApp::widget(p, pvid, x, y, width, height);
|
||||
PvApp::label(p, ui.widget, 2, 2, width-4, height-4, "", "background-color: rgb(12,39,58); border: 1px solid rgb(31,145,156);");
|
||||
PvApp::label(p, ui.widget, 0, 0, 60, height, "", "background-color: transparent; border: 0 solid rgb(42, 149, 245); border-width: 5px 0 5px 5px;");
|
||||
PvApp::label(p, ui.widget, width-60, 0, 60, height, "", "background-color: transparent; border: 0 solid rgb(42, 149, 245); border-width: 5px 5px 5px 0;");
|
||||
|
||||
ui.title = PvApp::label(p, ui.widget, 20, 10, width-20, 30, "", "font: bold 20px;");
|
||||
PvApp::label(p, ui.widget, 20, 40, width*0.5-20, 3, "", QSS_UNDERLINE);
|
||||
{
|
||||
int w = 100, h = 40, offset = 50;
|
||||
int x = (width- w*2 - offset) *0.5;
|
||||
int y = height - h - 40;
|
||||
|
||||
int btnOk = PvApp::button(p, ui.widget, x, y, w, h, "确定", QSS_BTN_CONFIRM);
|
||||
PvApp::bind(p, PvEvent::BUTTON_EVENT, btnOk, [=](std::string) {
|
||||
this->show(false);
|
||||
if (callbackConfirm) { callbackConfirm(); }
|
||||
});
|
||||
int btnCancel = PvApp::button(p, ui.widget, x+w+offset, y, w, h, "取消", QSS_BTN_CANCEL);
|
||||
PvApp::bind(p, PvEvent::BUTTON_EVENT, btnCancel, [=](std::string) {
|
||||
this->show(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void PvPopWidget::addParamLineEdit(std::string key, std::string title, int x, int y, bool editable/*= true*/)
|
||||
{
|
||||
auto line = std::make_shared<ParamLine>("lineEdit", key);
|
||||
PvApp::label(p, ui.widget, x, y, lineKeyWidth, lineHeight, title, "font: bold 14px;");
|
||||
line->widget = PvApp::lineEdit(p, ui.widget, x+lineKeyWidth, y, lineValWidth, lineHeight, "");
|
||||
if (!editable) { pvSetEnabled(p, line->widget, 0); }
|
||||
mapLines[key] = line;
|
||||
PvApp::bind(p, PvEvent::TEXT_EVENT, line->widget, [=](std::string text) {
|
||||
line->val = text;
|
||||
});
|
||||
}
|
||||
|
||||
void PvPopWidget::addParamCombox(std::string key, std::string title, int x, int y, std::vector<std::string> items)
|
||||
{
|
||||
auto line = std::make_shared<ParamLine>("combox", key);
|
||||
PvApp::label(p, ui.widget, x, y, lineKeyWidth, lineHeight, title, "font: bold 14px;");
|
||||
line->widget = PvApp::combox(p, ui.widget, x+lineKeyWidth, y, lineValWidth, lineHeight, items);
|
||||
mapLines[key] = line;
|
||||
PvApp::bind(p, PvEvent::TEXT_EVENT, line->widget, [=](std::string text) {
|
||||
line->val = text;
|
||||
});
|
||||
}
|
||||
|
||||
void PvPopWidget::setParamText(std::shared_ptr<ParamLine> line, std::string text)
|
||||
{
|
||||
if (line->type == "lineEdit")
|
||||
{
|
||||
pvSetText(p, line->widget, text.c_str());
|
||||
}
|
||||
else if (line->type == "combox")
|
||||
{
|
||||
int index = 0;
|
||||
for (int i = 0; i<line->items.size(); ++i)
|
||||
{
|
||||
if (line->items[i] == text) { index = i; break; }
|
||||
}
|
||||
pvSetCurrentItem(p, line->widget, index);
|
||||
}
|
||||
}
|
||||
|
||||
void PvPopWidget::setParamText(std::string key, std::string text)
|
||||
{
|
||||
auto iter = mapLines.find(key);
|
||||
if (iter != mapLines.end())
|
||||
{
|
||||
this->setParamText(iter->second, text);
|
||||
}
|
||||
}
|
||||
|
||||
void PvPopWidget::setTitle(std::string title)
|
||||
{
|
||||
pvSetText(p, ui.title, title.c_str());
|
||||
}
|
||||
|
||||
void PvPopWidget::setData(DataFields fields)
|
||||
{
|
||||
for (auto iter = mapLines.begin(); iter != mapLines.end(); ++iter)
|
||||
{
|
||||
auto& line = iter->second;
|
||||
this->setParamText(line, fields.getStr(line->key));
|
||||
}
|
||||
}
|
||||
|
||||
DataFields PvPopWidget::getData()
|
||||
{
|
||||
DataFields fields;
|
||||
for (auto iter = mapLines.begin(); iter!=mapLines.end(); ++iter)
|
||||
{
|
||||
auto& line = iter->second;
|
||||
fields.set(line->key, line->val);
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
void PvPopWidget::setLineGeometry(int wKey, int wVal, int h)
|
||||
{
|
||||
lineKeyWidth = wKey;
|
||||
lineValWidth = wVal;
|
||||
lineHeight = h;
|
||||
}
|
||||
53
src/pv/PvPopWidget.h
Normal file
53
src/pv/PvPopWidget.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "PvApp.h"
|
||||
#include "DataFields.h"
|
||||
|
||||
class PvPopWidget : public PvObject
|
||||
{
|
||||
public:
|
||||
struct ParamLine
|
||||
{
|
||||
std::string key;
|
||||
std::string type;
|
||||
std::string val;
|
||||
int widget;
|
||||
std::vector<std::string> items;
|
||||
ParamLine(std::string type, std::string key) : type(type), key(key) {}
|
||||
};
|
||||
|
||||
PvPopWidget(PARAM* p, int width, int height);
|
||||
|
||||
void addParamLineEdit(std::string key, std::string title, int x, int y, bool editable=true);
|
||||
|
||||
void addParamCombox(std::string key, std::string title, int x, int y, std::vector<std::string> items);
|
||||
|
||||
void setParamText(std::shared_ptr<ParamLine> line, std::string text);
|
||||
void setParamText(std::string key, std::string text);
|
||||
|
||||
void setCallbackConfirm(std::function<void()> callback) { callbackConfirm = callback; };
|
||||
|
||||
void setTitle(std::string title);
|
||||
|
||||
void setData(DataFields fields);
|
||||
DataFields getData();
|
||||
|
||||
void setLineGeometry(int wKey, int wVal, int h);
|
||||
|
||||
int width {800};
|
||||
int height {600};
|
||||
|
||||
int lineKeyWidth {70};
|
||||
int lineValWidth {180};
|
||||
int lineHeight {30};
|
||||
|
||||
struct {
|
||||
int widget;
|
||||
int title;
|
||||
} ui;
|
||||
|
||||
std::map<std::string, std::shared_ptr<ParamLine>> mapLines;
|
||||
DataFields data;
|
||||
|
||||
std::function<void()> callbackConfirm = nullptr;
|
||||
};
|
||||
136
src/pv/PvStyle.h
Normal file
136
src/pv/PvStyle.h
Normal file
@@ -0,0 +1,136 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
static std::string QSS_BTN_CONFIRM =
|
||||
"QPushButton { background-color:rgb(28, 145, 138); border-radius:10px; border: none; color:white; font:bold 18px \"Microsoft YaHei\";}"
|
||||
"QPushButton:hover { background-color:rgb(10,125,215);border:2px solid rgb(1,239,255);color:rgb(1,239,255)}"
|
||||
"QPushButton:pressed { border-width:3px 0 0 3px;background-color:rgb(150,150,150);border-style:inset;}"
|
||||
"QPushButton:disabled { color:rgb(150,150,150);}";
|
||||
|
||||
static std::string QSS_BTN_CANCEL =
|
||||
"QPushButton { background-color:rgb(200, 200, 200);border-radius:10px;border:0px solid rgb(10,120,215);color:white;font:bold 18px \"Microsoft YaHei\";}"
|
||||
"QPushButton:hover { background-color:rgb(10,125,215);border:2px solid rgb(1,239,255);color:rgb(1,239,255)}"
|
||||
"QPushButton:pressed { border-width:3px 0 0 3px;background-color:rgb(150,150,150);border-style:inset;}"
|
||||
"QPushButton:disabled { color:rgb(150,150,150);}";
|
||||
|
||||
static std::string QSS_COMBOX =
|
||||
"QComboBox {border: 1px solid rgb(18, 251, 255); background-color: rgb(5, 47, 77); border-radius: 5px; color:white; font: bold 16px;}"
|
||||
"QComboBox QAbstractItemView { border: 1px solid gray; background-color: rgba(8, 54, 91); border-radius: 5px;}"
|
||||
"QComboBox::drop-down { border-radius: 5px; width: 30px; }"
|
||||
"QComboBox:disabled { color:rgb(150,150,150);}";
|
||||
|
||||
static std::string QSS_COMBOX_14 =
|
||||
"QComboBox {border: 1px solid rgb(18, 251, 255); background-color: rgb(5, 47, 77); border-radius: 5px; color:white; font: bold 14px;}"
|
||||
"QComboBox QAbstractItemView { border: 1px solid gray; background-color: rgba(8, 54, 91); border-radius: 5px;}"
|
||||
"QComboBox::drop-down { border-radius: 5px; width: 30px; }"
|
||||
"QComboBox:disabled { color:rgb(150,150,150);}";
|
||||
|
||||
static std::string QSS_LINEEDIT =
|
||||
"QLineEdit { background-color: rgb(12, 39, 58); border: 1px solid rgb(18, 251, 255); border-radius: 5px; color:white; font: bold 14px;}"
|
||||
"QLineEdit:disabled { border: 1px solid gray; color:rgb(150,150,150);}";
|
||||
|
||||
static std::string STYLE_BTN =
|
||||
"QPushButton { background-color:rgb(4, 96, 142);border-radius:10px;border:0px solid rgb(10,120,215);color:white;font:bold 18px \"Microsoft YaHei\";}"
|
||||
"QPushButton:hover { background-color:rgb(10,125,215);border:2px solid rgb(1,239,255);color:rgb(1,239,255)}"
|
||||
"QPushButton:pressed { border-width:3px 0 0 3px;background-color:rgb(150,150,150);border-style:inset;}"
|
||||
"QPushButton:disabled { color:rgb(150,150,150);}";
|
||||
|
||||
static std::string STYLE_BTN_ACTIVE =
|
||||
"QPushButton { background-color:rgb(4, 96, 142);border-radius:10px;border:2px solid rgb(1,239,255);color:rgb(1,239,255);font:bold 18px \"Microsoft YaHei\";}"
|
||||
"QPushButton:hover { background-color:rgb(10,125,215);border:2px solid rgb(1,239,255);color:rgb(1,239,255)}"
|
||||
"QPushButton:pressed { border-width:3px 0 0 3px;background-color:rgb(150,150,150);border-style:inset;}"
|
||||
"QPushButton:disabled { color:rgb(150,150,150);}";
|
||||
|
||||
static std::string QSS_LABEL_BKG_1 =
|
||||
"QLabel { background-color:rgb(5, 47, 77); border:none; border-radius:5px; }"
|
||||
"QLabel:disabled { color:rgb(150,150,150);}";
|
||||
|
||||
static std::string QSS_LABEL_BKG_2 =
|
||||
"QLabel { background-color:rgb(8, 54, 91); border:none; border-radius:5px; }"
|
||||
"QLabel:disabled { color:rgb(150,150,150);}";
|
||||
|
||||
static std::string QSS_BOX =
|
||||
"QLabel { background-color:rgba(200,200,200,20); border:0px solid;border-color:rgb(5,255,255);border-radius:2px;font:bold 16px;color:white; }"
|
||||
"QLabel:hover {border: 1px solid rgb(1, 183, 209);}"
|
||||
"QLabel:disabled { color:rgb(150,150,150);}";
|
||||
|
||||
static std::string QSS_BOX_ACTIVE =
|
||||
"QLabel { background-color:rgb(7, 72, 111); border:2px solid;border-color:rgb(1, 183, 209); border-radius:2px;font:bold 16px;color:white; }"
|
||||
"QLabel:hover {border: 1px solid rgb(1, 183, 209);}"
|
||||
"QLabel:disabled { color:rgb(150,150,150);}";
|
||||
|
||||
static std::string QSS_TITLE =
|
||||
"QLabel { background:transparent; color: rgb(99, 196, 216); font: bold 16px; border: none; padding-top: 0px;}"
|
||||
"QLabel:disabled { color:rgb(150,150,150);}";
|
||||
|
||||
static std::string STYLE_TITLE_ICON =
|
||||
"padding-top: 0px;"
|
||||
"background-color: qlineargradient(x1:0, y1:1, x2:0, y2:0, stop:0 rgba(0, 71, 105, 255),stop:1 rgba(0, 71, 105, 0));"
|
||||
"border-radius: 0px; color:white; font: bold 16px; border-left: 8px solid rgba(33,255,210);";
|
||||
|
||||
static std::string QSS_UNDERLINE =
|
||||
"background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0,stop:0 rgba(9,194,207,200),stop:1 rgba(9,194,207,0));";
|
||||
|
||||
const std::string QSS_BTN_MGR =
|
||||
"QPushButton { background-color:rgb(10, 34, 63); border-radius:5px; border:1px solid rgb(33, 105, 195); color:white; font:bold 18px \"Microsoft YaHei\";}"
|
||||
"QPushButton:hover { background-color:rgb(10,125,215); border:2px solid rgb(1,239,255); color:rgb(1,239,255)}"
|
||||
//"QPushButton:pressed{border-width:3px 0 0 3px;background-color:rgb(150,150,150);border-style:inset;}"
|
||||
"QPushButton:pressed { border-width:3px 0 0 3px;border-style:inset; }"
|
||||
"QPushButton:disabled{color:rgb(150,150,150);}";
|
||||
|
||||
const std::string QSS_BTN_MGR_ACTIVE =
|
||||
"QPushButton { background-color:rgb(33, 105, 195);border-radius:5px; border:1px solid rgb(68, 167, 252);color:white;font:bold 18px \"Microsoft YaHei\"; }"
|
||||
"QPushButton:hover { background-color:rgb(10,125,215); border:2px solid rgb(1,239,255); color:rgb(1,239,255)}"
|
||||
"QPushButton:pressed { border-width:3px 0 0 3px;border-style:inset; }"
|
||||
"QPushButton:disabled { color:rgb(150,150,150); }";
|
||||
|
||||
//"background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 transparent, stop:%1 red, stop:1 blue);"
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// === 表格
|
||||
static const std::string QSS_TABLE =
|
||||
"border: 1px solid rgb(28, 121, 122); background-color:rgb(7, 46, 74);";
|
||||
|
||||
// 表头
|
||||
static const std::string QSS_TABLE_HEAD =
|
||||
"background-color: rgb(18, 93, 113); color:rgb(255, 255, 255); font:bold 16px;"
|
||||
"border-width:1 1 1 1px; border-style:inset solid; border-color:rgb(120, 120, 120);";
|
||||
|
||||
// 单元格
|
||||
static const std::string QSS_TABLE_CELL =
|
||||
"background-color:transparent; color:rgb(255,255,255); font:bold 15px;padding-left:1;"
|
||||
"border-width:0 0 0 0px; border-style:inset solid; border-color:rgba(180,180,180,200);";
|
||||
|
||||
static const std::string QSS_TABLE_BTN_VIEW =
|
||||
"QPushButton { background-color: rgb(28, 145, 138); color:white; border-radius:2px; border:none; font:bold 14px;}"
|
||||
"QPushButton:hover { border: 1px solid white;}"
|
||||
"QPushButton:pressed { border-width:3px 0 0 3px;border-style:inset;}"
|
||||
"QPushButton:disabled { color:rgb(150,150,150);}";
|
||||
|
||||
const std::string BTN_NEW = // 78, 149, 143
|
||||
"QPushButton{background-color:rgb(38,233,233);color:white;border-radius:5px;border:2px solid rgb(10,120,215);font:bold 18px;}"
|
||||
"QPushButton:hover{background-color:rgb(10,125,215);}"
|
||||
"QPushButton:pressed{border-width:3px 0 0 3px;background-color:rgb(150,150,150);border-style:inset;}"
|
||||
"QPushButton:disabled{color:rgb(150,150,150);}";
|
||||
|
||||
const std::string BTN_EDIT =
|
||||
"QPushButton{background-color:rgb(248,147,45);color:white;border-radius:5px;border:2px solid rgb(10,120,215);font:bold 15px;}"
|
||||
"QPushButton:hover{background-color:rgb(10,125,215);}"
|
||||
"QPushButton:pressed{border-width:3px 0 0 3px;background-color:rgb(150,150,150);border-style:inset;}"
|
||||
"QPushButton:disabled{color:rgb(150,150,150);}";
|
||||
|
||||
const std::string BTN_DELETE =
|
||||
"QPushButton{background-color:rgb(252,83,83);color:white;border-radius:5px;border:2px solid rgb(10,120,215);font:bold 15px;}"
|
||||
"QPushButton:hover{background-color:rgb(10,125,215);}"
|
||||
"QPushButton:pressed{border-width:3px 0 0 3px;background-color:rgb(150,150,150);border-style:inset;}"
|
||||
"QPushButton:disabled{color:rgb(150,150,150);}";
|
||||
|
||||
// 表格行的斑马色0
|
||||
static const std::string QSS_TABLE_ROW_0 =
|
||||
"background-color:rgb(7, 46, 74); border-width:0 0 1 0px; border-style:inset solid; border-color:rgba(120,120,120, 100);";
|
||||
// 表格行的斑马色1
|
||||
static const std::string QSS_TABLE_ROW_1 =
|
||||
"background-color:rgb(7, 46, 74); border-width:0 0 1 0px; border-style:inset solid; border-color:rgba(120,120,120, 100);";
|
||||
// 表格行的高亮显示
|
||||
static const std::string QSS_TABLE_ROW_HIGHLIGHT =
|
||||
"background-color:rgba(14,45,60,200);border:1px solid rgba(255,0,0,100);";
|
||||
476
src/pv/PvTable.cpp
Normal file
476
src/pv/PvTable.cpp
Normal file
@@ -0,0 +1,476 @@
|
||||
#include "PvTable.h"
|
||||
#include "PvStyle.h"
|
||||
|
||||
static const string STYLE_BKG =
|
||||
"border-width:1 1 1 1px; border-style:outset solid; border-color:rgba(180,180,180,255);"
|
||||
"background-color:rgba(80,80,80,0);";
|
||||
|
||||
//*********************************************************************************************************************
|
||||
// PvTable
|
||||
PvTable::PvTable(PARAM* p, int parent, int x, int y, int w, int row, Options& opts)
|
||||
//: PvWidget(p, parent, PvRect(x, y, w, opts.item_height* row + (opts.show_header ? (opts.header_height) : 0))),
|
||||
: PvObject(p), option_(opts), nRow_(row), nCol_(0)
|
||||
{
|
||||
// 计算表格的显示区域
|
||||
int h = opts.row_height* row + (opts.show_header ? (opts.head_height) : 0);
|
||||
rect_.set(x, y, w, h);
|
||||
// 表格的主窗体(QWidget设置样式无效)
|
||||
pvid_ = PvApp::widget(p, parent, x, y, w, h+1);
|
||||
// 表格的背景色和边框样式
|
||||
PvApp::label(p, pvid_, 0, 0, w, h+1, "", QSS_TABLE);
|
||||
|
||||
vecHead_.resize(0);
|
||||
vecRows_.resize(nRow_);
|
||||
vecData_.resize(nRow_);
|
||||
|
||||
// 创建行高亮显示背景
|
||||
for (int row = 0; row < nRow_; row++)
|
||||
{
|
||||
int y = item_posy(row);
|
||||
string qss = (row % 2 != 0) ? QSS_TABLE_ROW_0 : QSS_TABLE_ROW_1;
|
||||
int rowBkg = PvApp::label(p, pvid_, 1, y, rect_.w-2, option_.row_height, "", qss);
|
||||
pvHide(p, rowBkg);
|
||||
vecRows_[row].bkg = rowBkg;
|
||||
}
|
||||
}
|
||||
|
||||
void PvTable::addHead(string id, string text, int width, vector<pair<string, string>> mapping)
|
||||
{
|
||||
vecHead_.push_back(Head(id, text, width, mapping));
|
||||
nCol_ = vecHead_.size();
|
||||
|
||||
if (width <= -1)
|
||||
{
|
||||
width = rect_.w-1 - posCol_;
|
||||
}
|
||||
int col = nCol_ - 1;
|
||||
|
||||
// 创建表头的标签
|
||||
if (option_.show_header)
|
||||
{
|
||||
vecHead_[col].pvid = PvApp::label(p, pvid_, posCol_, 0, width, option_.head_height, text, QSS_TABLE_HEAD);
|
||||
}
|
||||
|
||||
// 创建列的单元格
|
||||
for (int row = 0; row < nRow_; ++row)
|
||||
{
|
||||
int y = item_posy(row);
|
||||
int pvid = PvApp::label(p, pvid_, posCol_, y, width, option_.row_height, "", QSS_TABLE_CELL);
|
||||
vecRows_[row].vecCells.push_back(pvid);
|
||||
PvApp::bind(p, MOUSE_OVER_EVENT, pvid, [=](string s) { highlight(row, (s == "1")); });
|
||||
}
|
||||
posCol_ += width;
|
||||
}
|
||||
|
||||
void PvTable::addHead(vector<string> vec_text)
|
||||
{
|
||||
int colSize = vec_text.size();
|
||||
int x = 0;
|
||||
for (int i = 0; i < vec_text.size(); ++i)
|
||||
{
|
||||
int w = float(rect_.w-1) * float(i+1) / float(colSize);
|
||||
string text = vec_text[i];
|
||||
this->addHead(text, text, w-x);
|
||||
x = w;
|
||||
}
|
||||
}
|
||||
|
||||
void PvTable::setRowVisible(int row, bool v)
|
||||
{
|
||||
if (row < 0 || row >= vecRows_.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
auto& rowItem = vecRows_[row];
|
||||
if (rowItem.visible != v)
|
||||
{
|
||||
rowItem.visible = v;
|
||||
rowItem.visible ? pvShow(p, rowItem.bkg) : pvHide(p, rowItem.bkg);
|
||||
if (!v)
|
||||
{
|
||||
for (int col = 0; col<rowItem.vecCells.size(); ++col)
|
||||
{
|
||||
pvSetText(p, rowItem.vecCells[col], "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PvTable::highlight(int row, bool v)
|
||||
{
|
||||
string qss = ((row % 2 != 0) ? QSS_TABLE_ROW_0 : QSS_TABLE_ROW_1);
|
||||
if (vecRows_.size() > 0 && row <= vecRows_.size())
|
||||
{
|
||||
if (v) { qss = "background-color:rgba(14,45,60,200);border:1px solid rgba(255,0,0,100);"; }
|
||||
pvSetStyleSheet(p, vecRows_[row].bkg, qss.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void PvTable::addOperate(vector<string> vecOpt)
|
||||
{
|
||||
// 创建表头的标签
|
||||
if (option_.show_header)
|
||||
{
|
||||
PvApp::label(p, pvid_, posCol_, 0, rect_.w - posCol_, option_.head_height, "操作", QSS_TABLE_HEAD);
|
||||
}
|
||||
for (int row = 0; row < nRow_; ++row)
|
||||
{
|
||||
int y = item_posy(row);
|
||||
int btn_opt = PvApp::label(p, pvid_, posCol_, y, rect_.w - posCol_, option_.row_height, "", QSS_TABLE_CELL);
|
||||
//PvInstance::bind_event(p, MOUSE_OVER_EVENT, btn_opt, [=](string s) { highlight(row, (s == "1")); });
|
||||
vecOpt_.push_back({ btn_opt, vector<int>() });
|
||||
auto& vec_opt_btn_ = vecOpt_.back().second;
|
||||
|
||||
int x = 5, w = 60;
|
||||
for (int i = 0; i < vecOpt.size(); i++)
|
||||
{
|
||||
auto& title = vecOpt[i];
|
||||
w = 20 + 15 * title.size() / 3;
|
||||
int btn = PvApp::button(p, btn_opt, x, 4, w, 24, title, QSS_TABLE_BTN_VIEW);
|
||||
PvApp::bind(p, PvEvent::BUTTON_EVENT, btn, [=](std::string) {
|
||||
if (cbOperate_) { cbOperate_(row, 0, title); }
|
||||
});
|
||||
vec_opt_btn_.push_back(btn);
|
||||
x += (w + 5);
|
||||
}
|
||||
pvHide(p, btn_opt);
|
||||
}
|
||||
}
|
||||
|
||||
void PvTable::setOperateCallback(CallbackTableOpt cb)
|
||||
{
|
||||
cbOperate_ = cb;
|
||||
};
|
||||
|
||||
void PvTable::set_text(PARAM* p, int row, int col, string text, string style)
|
||||
{
|
||||
if (row < nRow_ && col < nCol_)
|
||||
{
|
||||
pvSetText(p, vecRows_[row].vecCells[col], text.c_str());
|
||||
if (!style.empty())
|
||||
{
|
||||
int idx = row + 1;
|
||||
if (idx % 2 != 0)
|
||||
{
|
||||
style = item_base_style_ + style;
|
||||
}
|
||||
else
|
||||
{
|
||||
style = item_base_style_ + style;
|
||||
}
|
||||
|
||||
//style = "qproperty-alignment:AlignCenter;" + style + "}";
|
||||
string s = "QLabel{" + style + "} QLabel:disabled{color:rgb(150,150,150)}";
|
||||
pvSetStyleSheet(p, vecRows_[row].vecCells[col], s.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PvTable::setRowData(int row, DataFields& d)
|
||||
{
|
||||
if (row >= nRow_) { return; }
|
||||
|
||||
vecData_[row] = d;
|
||||
for (int col = 0; col < vecHead_.size(); ++col)
|
||||
{
|
||||
auto& head = vecHead_[col];
|
||||
string text = d.getStr(head.id);
|
||||
text = head.getMapping(text);
|
||||
pvSetText(p, vecRows_[row].vecCells[col], text.c_str());
|
||||
}
|
||||
setRowVisible(row, true);
|
||||
this->setOperateVisible(row, d.size() > 0);
|
||||
}
|
||||
|
||||
void PvTable::setRowData(int row, std::vector<std::string> vd)
|
||||
{
|
||||
if (row >= nRow_) { return; }
|
||||
pvShow(p, vecRows_[row].bkg);
|
||||
for (int col = 0; col < vecHead_.size(); ++col)
|
||||
{
|
||||
if (col < vd.size()) {
|
||||
auto& head = vecHead_[col];
|
||||
string text = head.getMapping(vd[col]);
|
||||
pvSetText(p, vecRows_[row].vecCells[col], text.c_str());
|
||||
}
|
||||
}
|
||||
setRowVisible(row, true);
|
||||
this->setOperateVisible(row, vd.size() > 0);
|
||||
}
|
||||
|
||||
DataFields& PvTable::getRowdata(int row)
|
||||
{
|
||||
static DataFields tmp;
|
||||
return (row >= 0 && row < vecData_.size()) ? vecData_[row] : tmp;
|
||||
}
|
||||
|
||||
void PvTable::set_border_visible(PARAM* p, bool v)
|
||||
{
|
||||
v ? pvShow(p, border_id_) : pvHide(p, border_id_);
|
||||
}
|
||||
|
||||
int PvTable::item_posy(int row)
|
||||
{
|
||||
return option_.show_header ? row * option_.row_height + option_.head_height : row * option_.row_height;
|
||||
}
|
||||
|
||||
//void PvTable::set_item_btn_callback(CallbackTableOpt cb)
|
||||
//{
|
||||
// //cb_opt_ = cb;
|
||||
//}
|
||||
|
||||
void PvTable::add_col_button(PARAM* p, int col, string title, PvRect& rt, string style)
|
||||
{
|
||||
if (col >= nCol_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (int row = 0; row < nRow_; ++row)
|
||||
{
|
||||
int id = PvApp::button(p, vecRows_[row].vecCells[col], rt.x, rt.y, rt.w, rt.h, title, style);
|
||||
pvHide(p, id);
|
||||
vec_col_item_btn_[row].push_back(id);
|
||||
//PvInstance::bind_event(p, PvEvent::BUTTON_EVENT, id, [=](string s)
|
||||
//{
|
||||
// if (cb_operate_)
|
||||
// {
|
||||
// cb_operate_(row, col, title);
|
||||
// }
|
||||
//});
|
||||
}
|
||||
}
|
||||
|
||||
string GetTableItemButtonStyle(string title)
|
||||
{
|
||||
static unordered_map<string, string> map_style =
|
||||
{
|
||||
//{PV::OPT_NEW, PvStyle::BTN_NEW},
|
||||
//{PV::OPT_EDIT, PvStyle::BTN_EDIT},
|
||||
//{PV::OPT_DEL, PvStyle::BTN_DELETE}
|
||||
};
|
||||
string style = map_style[title];
|
||||
if (style.empty())
|
||||
{
|
||||
style = BTN_EDIT;
|
||||
}
|
||||
return style;
|
||||
}
|
||||
|
||||
void PvTable::add_col_button(PARAM* p, int col, vector<string> vec_title)
|
||||
{
|
||||
int x = 5;
|
||||
int w = 0;
|
||||
for (int i = 0; i < vec_title.size(); i++)
|
||||
{
|
||||
auto& title = vec_title[i];
|
||||
w = 20 + 20 * title.size() / 3;
|
||||
this->add_col_button(p, col, title, PvRect(x, 3, w, 28), BTN_EDIT);
|
||||
x += (w + 5);
|
||||
}
|
||||
}
|
||||
|
||||
void PvTable::setOperateVisible(int row, bool v, int id)
|
||||
{
|
||||
if (row < vecOpt_.size())
|
||||
{
|
||||
auto& vec_opt_btn = vecOpt_[row].second;
|
||||
int pvid = id < 0 ? vecOpt_[row].first : ((id < vec_opt_btn.size()) ? vec_opt_btn[id] : PV_ID_NUL);
|
||||
v ? pvShow(p, pvid) : pvHide(p, pvid);
|
||||
}
|
||||
}
|
||||
|
||||
int PvTable::border_id()
|
||||
{
|
||||
return border_id_;
|
||||
}
|
||||
|
||||
int PvTable::rows()
|
||||
{
|
||||
return nRow_;
|
||||
}
|
||||
int PvTable::colums()
|
||||
{
|
||||
return nCol_;
|
||||
}
|
||||
|
||||
vector<DataFields> PvTable::data()
|
||||
{
|
||||
return vecData_;
|
||||
}
|
||||
|
||||
PvTable::Head& PvTable::header(int col)
|
||||
{
|
||||
return vecHead_[col];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static const string STYLE_NORMAL =
|
||||
"QPushButton{background-color:rgba(255,255,255,30);border-radius:0px;font:bold 16px;color:white;border:1px solid #20a481;}"
|
||||
"QPushButton:hover{background-color:rgba(32,164,128,255);color:white;}"
|
||||
"QPushButton:pressed{border-width:3px 0 0 3px;border-style:inset;color:white;}";
|
||||
|
||||
static const string STYLE_ACTIVE =
|
||||
"QPushButton{background-color:rgba(32,164,128,255);border-radius:0px;font:bold 16px;color:white;border:1px solid #20a481;}"
|
||||
"QPushButton:hover{background-color:rgba(32,164,128,255);color:white;}"
|
||||
"QPushButton:pressed{border-width:3px 0 0 3px;border-style:inset;color:white;}";
|
||||
|
||||
|
||||
PvPagination::PvPagination(PARAM* p, int parent, const PvRect& rt)
|
||||
: PvObject(p)
|
||||
{
|
||||
pvid_ = PvApp::label(p, parent, rt.x, rt.y, rt.w, rt.h, "", "");
|
||||
// 分页控件
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
btn_prev_ = PvApp::button(p, pvid_, x, y, 30, 30, "<", STYLE_NORMAL);
|
||||
for (int i = 1; i <= 7; i++)
|
||||
{
|
||||
int id = PvApp::button(p, pvid_, x += 32, y, 30, 30, std::to_string(i), STYLE_NORMAL);
|
||||
vec_btn_page_.push_back({id, 0});
|
||||
//PvInstance::bind_event(p, PvEvent::BUTTON_EVENT, id, [=](string s) { this->on_click_page(id); });
|
||||
}
|
||||
btn_next_ = PvApp::button(p, pvid_, x += 32, y, 30, 30, ">", STYLE_NORMAL);
|
||||
|
||||
//PvInstance::bind_event(p, PvEvent::BUTTON_EVENT, btn_prev_, [=](string e) { this->on_click_prev(); });
|
||||
//PvInstance::bind_event(p, PvEvent::BUTTON_EVENT, btn_next_, [=](string e) { this->on_click_next(); });
|
||||
|
||||
this->set_page(0, 0);
|
||||
}
|
||||
|
||||
void PvPagination::set_page(int page_id, int max_page)
|
||||
{
|
||||
this->active_page_button(p, page_id, page_id_);
|
||||
|
||||
page_id_ = page_id;
|
||||
page_count_ = max_page;
|
||||
|
||||
int x = 32;
|
||||
int y = 0;// table_->rect().h + 16;
|
||||
for (int i = 0; i < vec_btn_page_.size(); ++i)
|
||||
{
|
||||
auto& btn_info = vec_btn_page_[i];
|
||||
auto btnid = btn_info.first;
|
||||
int idx = i + 1;
|
||||
if (idx > page_count_)
|
||||
{
|
||||
pvHide(p, btnid);
|
||||
}
|
||||
else
|
||||
{
|
||||
pvShow(p, btnid);
|
||||
if (page_count_ > 7)
|
||||
{
|
||||
if (idx == 4)
|
||||
{
|
||||
idx = 0;
|
||||
}
|
||||
else if (idx > 4)
|
||||
{
|
||||
idx = page_count_ - (7 - idx);
|
||||
}
|
||||
}
|
||||
btn_info.second = idx;
|
||||
|
||||
string text = to_string(idx);
|
||||
if (text.empty() || text == "0")
|
||||
{
|
||||
text = "...";
|
||||
pvSetEnabled(p, btnid, false);
|
||||
}
|
||||
pvMove(p, btnid, x, y);
|
||||
pvSetText(p, btnid, text.c_str());
|
||||
if (page_id == idx)
|
||||
{
|
||||
this->active_page_button(p, page_id, page_id_);
|
||||
page_id_ = page_id;
|
||||
}
|
||||
x += (32);
|
||||
}
|
||||
}
|
||||
pvMove(p, btn_next_, x, y);
|
||||
}
|
||||
|
||||
int PvPagination::pageid()
|
||||
{
|
||||
return page_id_;
|
||||
};
|
||||
|
||||
void PvPagination::active_page_button(PARAM* p, int new_pageid, int old_pageid)
|
||||
{
|
||||
for (int i = 0; i < vec_btn_page_.size(); i++)
|
||||
{
|
||||
auto& item = vec_btn_page_[i];
|
||||
if (item.second != 0)
|
||||
{
|
||||
if (item.second == old_pageid)
|
||||
{
|
||||
pvSetStyleSheet(p, item.first, STYLE_NORMAL.c_str());
|
||||
}
|
||||
if (item.second == new_pageid)
|
||||
{
|
||||
pvSetStyleSheet(p, item.first, STYLE_ACTIVE.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PvPagination::set_goto_page_callback(std::function<void(int pageidx)> cb)
|
||||
{
|
||||
cb_goto_ = cb;
|
||||
}
|
||||
|
||||
void PvPagination::on_click_page(int btnid)
|
||||
{
|
||||
for (int i = 0; i < vec_btn_page_.size(); ++i)
|
||||
{
|
||||
auto& item = vec_btn_page_[i];
|
||||
if (btnid == item.first)
|
||||
{
|
||||
int page_id = item.second;
|
||||
if (cb_goto_) { cb_goto_(page_id); }
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PvPagination::on_click_prev()
|
||||
{
|
||||
if (page_id_ <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (cb_goto_)
|
||||
{
|
||||
cb_goto_(page_id_ - 1);
|
||||
}
|
||||
}
|
||||
|
||||
void PvPagination::on_click_next()
|
||||
{
|
||||
if (page_id_ >= page_count_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (cb_goto_)
|
||||
{
|
||||
cb_goto_(page_id_ + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PvPageTable::PvPageTable(PARAM* p, int parent, int x, int y, int w, int rows, PvTable::Options& opts)
|
||||
//: PvWidget(p, parent, PvRect(x, y, w, opts.item_height* rows + (opts.show_header ? (opts.header_height) : 0)))
|
||||
: PvObject(p)
|
||||
{
|
||||
int h = opts.row_height* rows + (opts.show_header ? (opts.head_height) : 0);
|
||||
int pvid_ = PvApp::widget(p, parent, x, y, w, h);
|
||||
table_ = make_shared<PvTable>(p, pvid_, 0, 0, w, rows, opts);
|
||||
}
|
||||
|
||||
shared_ptr<PvTable> PvPageTable::getTable()
|
||||
{
|
||||
return table_;
|
||||
}
|
||||
174
src/pv/PvTable.h
Normal file
174
src/pv/PvTable.h
Normal file
@@ -0,0 +1,174 @@
|
||||
#ifndef _PvTable_H_
|
||||
#define _PvTable_H_
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "PvApp.h"
|
||||
#include "DataFields.h"
|
||||
|
||||
using CallbackTableOpt = std::function<void(int row, int col, std::string text)>;
|
||||
|
||||
class PvTable : public PvObject
|
||||
{
|
||||
public:
|
||||
struct Options
|
||||
{
|
||||
bool show_header = true;
|
||||
bool show_border = true;
|
||||
int head_height = 40;
|
||||
int row_height = 35;
|
||||
int page_size = 10;
|
||||
int width = 500;
|
||||
};
|
||||
|
||||
struct Head
|
||||
{
|
||||
Head() {}
|
||||
Head(std::string hid, std::string htext, int w, std::vector<std::pair<std::string, std::string>> mapping)
|
||||
: id(hid), text(htext), width(w), vecMaping(mapping) {}
|
||||
|
||||
std::string id;
|
||||
std::string text;
|
||||
int width = 80;
|
||||
int pvid = PV_ID_NUL;
|
||||
vector<pair<string, string>> vecMaping;
|
||||
|
||||
std::string getMapping(std::string s)
|
||||
{
|
||||
std::string v = s;
|
||||
for (auto& item : vecMaping)
|
||||
{
|
||||
if (v == item.first) { v = item.second; }
|
||||
else if (v == item.second) { v = item.first; }
|
||||
}
|
||||
return v;
|
||||
}
|
||||
};
|
||||
|
||||
struct Row
|
||||
{
|
||||
bool visible = false;
|
||||
int bkg {PV_ID_NUL};
|
||||
std::vector<int> vecCells {};
|
||||
};
|
||||
|
||||
public:
|
||||
PvTable(PARAM* p, int parent, int x, int y, int w, int rows, Options& option);
|
||||
|
||||
void addHead(std::string id, std::string text, int width, std::vector<std::pair<std::string, std::string>> mapping = {});
|
||||
void addHead(std::vector<std::string> vecText);
|
||||
|
||||
void setRowVisible(int row, bool v);
|
||||
void highlight(int row, bool v);
|
||||
|
||||
void addOperate(std::vector<std::string> vecOpt);
|
||||
void setOperateCallback(CallbackTableOpt cb);
|
||||
|
||||
void set_text(PARAM* p, int row, int col, std::string text, std::string style = "");
|
||||
|
||||
void setRowData(int row, DataFields& d);
|
||||
void setRowData(int row, std::vector<std::string> vd);
|
||||
|
||||
DataFields& getRowdata(int row);
|
||||
|
||||
void set_border_visible(PARAM* p, bool v);
|
||||
|
||||
void add_col_button(PARAM* p, int col, std::string title, PvRect& rt, std::string style);
|
||||
void add_col_button(PARAM* p, int col, std::vector<std::string> vec_title);
|
||||
void setOperateVisible(int row, bool v, int id = -1);
|
||||
|
||||
int item_posy(int row);
|
||||
|
||||
int border_id();
|
||||
|
||||
int rows();
|
||||
|
||||
int colums();
|
||||
|
||||
std::vector<DataFields> data();
|
||||
|
||||
PvTable::Head& header(int col);
|
||||
|
||||
private:
|
||||
int pvid_;
|
||||
PvRect rect_;
|
||||
|
||||
int border_id_;
|
||||
|
||||
std::vector<PvTable::Head> vecHead_;
|
||||
std::vector<PvTable::Row> vecRows_;
|
||||
|
||||
std::vector<DataFields> vecData_;
|
||||
|
||||
vector<pair<int, vector<int>>> vecOpt_;
|
||||
int nRow_;
|
||||
int nCol_;
|
||||
|
||||
string item_base_style_;
|
||||
|
||||
Options option_;
|
||||
|
||||
unordered_map<int, vector<int>> vec_col_item_btn_;
|
||||
|
||||
CallbackTableOpt cbOperate_ = nullptr;
|
||||
|
||||
int posCol_ = 0;
|
||||
};
|
||||
|
||||
|
||||
class PvPagination : public PvObject
|
||||
{
|
||||
public:
|
||||
PvPagination(PARAM* p, int parent, const PvRect& rt);
|
||||
|
||||
void set_page(int page_id, int max_page);
|
||||
|
||||
int pageid();
|
||||
|
||||
void set_goto_page_callback(std::function<void(int pageid)> cb);
|
||||
|
||||
private:
|
||||
void on_click_page(int btnid);
|
||||
void on_click_prev();
|
||||
void on_click_next();
|
||||
|
||||
void active_page_button(PARAM* p, int new_pageid, int old_pageid);
|
||||
|
||||
private:
|
||||
int pvid_ = PV_ID_NUL;
|
||||
|
||||
// 当前显示的页码索引, 从1开始
|
||||
int page_id_ = 1;
|
||||
|
||||
// 总页数
|
||||
int page_count_ = 0;
|
||||
|
||||
// 上一页按钮
|
||||
int btn_prev_ = PV_ID_NUL;
|
||||
|
||||
// 下一页按钮
|
||||
int btn_next_ = PV_ID_NUL;
|
||||
|
||||
// 页面跳转按钮
|
||||
int btn_gopage_ = PV_ID_NUL;
|
||||
|
||||
// 页码列表(最多显示6个页码按钮,前3页和后3页) <按钮ID, 页码>
|
||||
std::vector<pair<int, int>> vec_btn_page_;
|
||||
|
||||
function<void(int)> cb_goto_ = nullptr;
|
||||
};
|
||||
|
||||
|
||||
class PvPageTable :public PvObject
|
||||
{
|
||||
public:
|
||||
PvPageTable(PARAM* p, int parent, int x, int y, int w, int rows, PvTable::Options& opts);
|
||||
|
||||
shared_ptr<PvTable> getTable();
|
||||
|
||||
private:
|
||||
shared_ptr<PvTable> table_ = nullptr;
|
||||
shared_ptr<PvPagination> page_ctrl_ = nullptr;
|
||||
};
|
||||
|
||||
#endif // ! _PvTable_H_
|
||||
0
src/pv/PvUser.cpp
Normal file
0
src/pv/PvUser.cpp
Normal file
11
src/pv/PvUser.h
Normal file
11
src/pv/PvUser.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
class PvUser
|
||||
{
|
||||
public:
|
||||
int pvidIndex = 0;
|
||||
std::map<std::string, std::function<void(std::string text)>> mapEventCallback;
|
||||
};
|
||||
44
src/pv/pages/MaskPageForecast.cpp
Normal file
44
src/pv/pages/MaskPageForecast.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include "MaskPageForecast.h"
|
||||
|
||||
#include "pv/PvChart.h"
|
||||
|
||||
static int CreatePanel(PARAM* p, int parentId, int x, int y, int w, int h, std::string title)
|
||||
{
|
||||
int id = PvApp::label(p, parentId, x, y, w, h, "", QSS_LABEL_BKG_2);
|
||||
PvApp::label(p, id, 10, 10, w, 20, title, STYLE_TITLE_ICON);
|
||||
PvApp::label(p, id, 20, 30, w, 2, "", QSS_UNDERLINE);
|
||||
return id;
|
||||
}
|
||||
|
||||
MaskPageForecast::MaskPageForecast(PARAM* p) : PvMask(p)
|
||||
{
|
||||
}
|
||||
|
||||
int MaskPageForecast::initUI(EPvCode pvcode)
|
||||
{
|
||||
int x = 10, y = 100, w = 1900, h = 420;
|
||||
int delta = 40;
|
||||
{
|
||||
int panel = CreatePanel(p, 0, x, y, w, h, "储能充放电预测");
|
||||
chart1_ = std::make_shared<PvChartCurve>(p, panel, 0, delta, w, h-delta);
|
||||
chart1_->setBackground(p, 8, 54, 91);
|
||||
chart1_->setLabelYLeft("电量(kWh)", 0, 10, 2);
|
||||
chart1_->insertItem(0, "充电电量", 120, 10, 80);
|
||||
chart1_->insertItem(0, "放电电量", 200, 10, 80);
|
||||
}
|
||||
{
|
||||
int panel = CreatePanel(p, 0, x, y+=(h+10), w = 945, h, "光伏发电预测");
|
||||
chart2_ = std::make_shared<PvChartCurve>(p, panel, 0, delta, w, h-delta);
|
||||
chart2_->setBackground(p, 8, 54, 91);
|
||||
chart2_->setLabelYLeft("电量(kWh)", 0, 10, 2);
|
||||
chart2_->insertItem(0, "发电电量", 120, 10, 80);
|
||||
}
|
||||
{
|
||||
int panel = CreatePanel(p, 0, x+=(w+10), y, w, h, "充电负荷预测");
|
||||
chart3_ = std::make_shared<PvChartCurve>(p, panel, 0, delta, w, h-delta);
|
||||
chart3_->setBackground(p, 8, 54, 91);
|
||||
chart3_->setLabelYLeft("电量(kWh)", 0, 10, 2);
|
||||
chart3_->insertItem(0, "充电电量", 120, 10, 80);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
16
src/pv/pages/MaskPageForecast.h
Normal file
16
src/pv/pages/MaskPageForecast.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "pv/PvApp.h"
|
||||
|
||||
class PvChartCurve;
|
||||
|
||||
class MaskPageForecast : public PvMask
|
||||
{
|
||||
public:
|
||||
MaskPageForecast(PARAM* p);
|
||||
int initUI(EPvCode pvcode);
|
||||
|
||||
std::shared_ptr<PvChartCurve> chart1_;
|
||||
std::shared_ptr<PvChartCurve> chart2_;
|
||||
std::shared_ptr<PvChartCurve> chart3_;
|
||||
};
|
||||
329
src/pv/pages/MaskPageHome.cpp
Normal file
329
src/pv/pages/MaskPageHome.cpp
Normal file
@@ -0,0 +1,329 @@
|
||||
#include "MaskPageHome.h"
|
||||
#include "common/Utils.h"
|
||||
#include "app/Application.h"
|
||||
#include "app/Station.h"
|
||||
|
||||
#include "pv/PvTable.h"
|
||||
#include "pv/PvChart.h"
|
||||
|
||||
static int CreatePanel(PARAM* p, int parent, int x, int y, int w, int h, std::string title)
|
||||
{
|
||||
int panelId = PvApp::label(p, parent, x, y, w, h, "", QSS_LABEL_BKG_1);
|
||||
int titleId = PvApp::label(p, panelId, 10, 8, w, 22, title, STYLE_TITLE_ICON);
|
||||
PvApp::label(p, panelId, 20, 28, w, 2, "", QSS_UNDERLINE);
|
||||
return panelId;
|
||||
}
|
||||
|
||||
static int CreatePanel1(PARAM* p, int parent, int x, int y, int w, int h, std::string title)
|
||||
{
|
||||
int panelId = PvApp::label(p, parent, x, y, w, h, "", "border: none; background-color: transparent;");
|
||||
PvApp::image(p, panelId, 0, 13, 500, 17, "bkgBox.png");
|
||||
PvApp::label(p, panelId, 20, 0, w-20, 30, title, "background-color: transparent; font: bold 18px;");
|
||||
return panelId;
|
||||
}
|
||||
|
||||
static int CreateCard1(PARAM* p, int parentId, int x, int y, int w, int h, std::string title, std::string val)
|
||||
{
|
||||
int id = PvApp::label(p, parentId, x, y, w, h, "", QSS_LABEL_BKG_1);
|
||||
int idTitle = PvApp::label(p, id, 0, h*0.5, w, h*0.5, title, "background:transparent; font: bold 28px;");
|
||||
int idVal = PvApp::label(p, id, 0, 0, w, h*0.5, val, "background:transparent; font: bold 28px; color:rgb(77,215,240);");
|
||||
pvSetAlignment(p, idTitle, AlignCenter);
|
||||
pvSetAlignment(p, idVal, AlignHCenter | AlignBottom);
|
||||
return id;
|
||||
}
|
||||
|
||||
static int CreateCard2(PARAM* p, int parent, int x, int y, int w, int h, std::string title, std::string val)
|
||||
{
|
||||
int id = PvApp::label(p, parent, x, y, w, h, "", QSS_LABEL_BKG_1);
|
||||
|
||||
int idTitle = PvApp::label(p, id, 0, 0, w, h*0.5, title, "background:transparent; font: bold 16px;");
|
||||
int idVal = PvApp::label(p, id, 0, h*0.5, w, h*0.5, val, "background:transparent; font: bold 16px; color:rgb(77,215,240);");
|
||||
pvSetAlignment(p, idTitle, AlignCenter);
|
||||
pvSetAlignment(p, idVal, AlignCenter);
|
||||
return id;
|
||||
}
|
||||
|
||||
static int CreateBox(PARAM* p, int parent, int x, int y, int w, int h, std::string k, std::string val="")
|
||||
{
|
||||
int id = PvApp::label(p, parent, x, y, w, h, "", "border-radius:0px; background-color: rgb(7, 45, 66); border: 1px solid rgb(27, 88, 105);");
|
||||
{
|
||||
int len = 10;
|
||||
std::string qss = "background-color: transparent; border: 1px solid rgb(0, 218, 216);";
|
||||
PvApp::label(p, id, 0, 0, len, len, "", qss + "border-width: 2px 0 0 2px");
|
||||
PvApp::label(p, id, w-len, 0, len, len, "", qss + "border-width: 2px 2px 0 0");
|
||||
PvApp::label(p, id, w-len, h-len, len, len, "", qss + "border-width: 0 2px 2px 0");
|
||||
PvApp::label(p, id, 0, h-len, len, len, "", qss + "border-width: 0 0 2px 2px");
|
||||
}
|
||||
int titleId = PvApp::label(p, id, 0, 0, w, h*0.5, k, "border:none; background-color: transparent; font: bold 14px; padding-bottom: 0px;");
|
||||
int valId = PvApp::label(p, id, 0, h*0.5, w, h*0.5, val, "border:none; background-color: transparent; font: bold 16px; color:rgb(77, 215, 240);");
|
||||
pvSetAlignment(p, titleId, AlignHCenter | AlignBottom);
|
||||
pvSetAlignment(p, valId, AlignHCenter | AlignTop);
|
||||
return valId;
|
||||
}
|
||||
|
||||
static int CreateIconBox(PARAM* p, int parent, int x, int y, std::string k, std::string val, std::string icon)
|
||||
{
|
||||
//PvApp::label(p, parent, x, y, 50, 50, "", "background-color: rgb(2, 41, 60); border: 1px solid rgb(61, 254, 250);");
|
||||
//PvApp::label(p, parent, x+3, y+3, 44, 44, "", "background-color: transparent; border: 2px solid rgb(31, 91, 139);");
|
||||
PvApp::image(p, parent, x, y, 50, 50, icon.c_str());
|
||||
PvApp::label(p, parent, x+52, y, 100, 20, k, "background-color: transparent; border: none; font: bold 14px;");
|
||||
int valId = PvApp::label(p, parent, x+52, y+25, 100, 20, val, "background-color: transparent; border: none; font: bold 14px;");
|
||||
return valId;
|
||||
}
|
||||
|
||||
class PopStation
|
||||
{
|
||||
public:
|
||||
PARAM* p {};
|
||||
int widget = PV_ID_NUL;
|
||||
int width = 1100;
|
||||
int height = 800;
|
||||
int labelTitle = PV_ID_NUL;
|
||||
|
||||
PopStation(PARAM* p) : p(p)
|
||||
{
|
||||
int wMask = 1920, hMask = 960;
|
||||
widget = PvApp::widget(p, PV_ID_MAIN, 0, 0, wMask, hMask);
|
||||
PvApp::label(p, widget, 0, 0, 1920, 960, "", "background-color: rgb(1, 32, 54);");
|
||||
|
||||
// 站名称Title
|
||||
labelTitle = PvApp::label(p, widget, 0, 40, wMask, 30, "", "border: none; background-color: transparent; font: bold 20px;");
|
||||
pvSetAlignment(p, labelTitle, AlignCenter);
|
||||
|
||||
{
|
||||
int pid = PvApp::label(p, widget, (wMask-width)*0.5, (hMask-height)*0.5, width, height, "", "background-color: rgb(2, 58, 87); border: 1px solid rgb(31, 198, 255);");
|
||||
PvApp::label(p, pid, 0, 0, 80, height, "", "background-color: transparent; border: 3px solid rgb(31, 198, 255); border-width: 3px 0 3px 3px;");
|
||||
PvApp::label(p, pid, width-80, 0, 80, height, "", "background-color: transparent; border: 3px solid rgb(31, 198, 255); border-width: 3px 3px 3px 0;");
|
||||
|
||||
int btnClose = PvApp::button(p, pid, width-40, 5, 30, 30, "✕", "background-color: white; border: none; border-radius: 15px; color: rgb(2, 59, 87); font: bold 20px;");
|
||||
PvApp::bind(p, PvEvent::BUTTON_EVENT, btnClose, [=](std::string) {
|
||||
pvHide(p, widget);
|
||||
});
|
||||
|
||||
int x = 20, y = 40, w = 500, h = 240;
|
||||
{
|
||||
int box = CreatePanel1(p, pid, x, y, w, h, "预制舱信息");
|
||||
int x0 = 50, y0 = 40, w0 = 150, h0 = 60;
|
||||
CreateBox(p, box, x0 = 60, y0, w0, h0, "电池类型", "磷酸铁锂电池");
|
||||
CreateBox(p, box, w-x0-w0, y0, w0, h0, "冷却模式", "风冷");
|
||||
CreateBox(p, box, x0 = 20, y0 += (h0+5), w0, h0, "运行模式", "最优经济化");
|
||||
CreateBox(p, box, w-x0-w0, y0, w0, h0, "电池额定电压", "300 V");
|
||||
CreateBox(p, box, x0 = 60, y0 += (h0+5), w0, h0, "PCS额定功率", "100 kW");
|
||||
CreateBox(p, box, w-x0-w0, y0, w0, h0, "电池储能容量", "100 kWh");
|
||||
}
|
||||
{
|
||||
y += (h+10);
|
||||
int box = CreatePanel1(p, pid, x, y, w, h, "运行与统计信息");
|
||||
|
||||
CreateIconBox(p, box, 40, 40, "舱内温度", "20 ℃", "icon1.png");
|
||||
CreateIconBox(p, box, 40+160, 40, "舱内湿度", "30 %", "icon2.png");
|
||||
CreateIconBox(p, box, 40+160*2, 40, "电压", "200 V", "icon3.png");
|
||||
CreateIconBox(p, box, 40, 90, "电流", "30 A", "icon4.png");
|
||||
CreateIconBox(p, box, 40+160, 90, "功率", "6 kW", "icon5.png");
|
||||
CreateIconBox(p, box, 40+160*2, 90, "功率因数", "1.0", "icon5.png");
|
||||
|
||||
int x0 = 10, y0 = 160, w0 = 90, h0 = 60;
|
||||
CreateBox(p, box, x0, y0, w0, h0, "场站运行天数", "365 天");
|
||||
CreateBox(p, box, x0 += (w0+10), y0, w0, h0, "储能充电电量", "22 kWh");
|
||||
CreateBox(p, box, x0 += (w0+10), y0, w0, h0, "储能放电电量", "11 kWh");
|
||||
CreateBox(p, box, x0 += (w0+10), y0, w0, h0, "场站累计收益", "123.12 元");
|
||||
CreateBox(p, box, x0 += (w0+10), y0, w0, h0, "设备利用率", "10 %");
|
||||
}
|
||||
{
|
||||
y += (h+10);
|
||||
int box = CreatePanel1(p, pid, x, y, w, h, "环境信息");
|
||||
|
||||
CreateIconBox(p, box, 80, 50, "光照强度", "27.1 Lux", "icon1.png");
|
||||
CreateIconBox(p, box, 80+200*1, 50, "风速", "1.2 m/s", "icon2.png");
|
||||
CreateIconBox(p, box, 80, 120, "环境温度", "35.7 ℃", "icon1.png");
|
||||
CreateIconBox(p, box, 80+200*1, 120, "环境湿度", "31.3 %", "icon2.png");
|
||||
}
|
||||
|
||||
{
|
||||
x = 580; y = 40; h = 240;
|
||||
int box = CreatePanel1(p, pid, x, y, w, h, "储能充放电量");
|
||||
PvChartCurve chart(p, box, 0, 40, 500, 200);
|
||||
chart.setBackground(p, 2, 58, 87);
|
||||
chart.setLabelYLeft("电量(kWh)");
|
||||
chart.insertItem(0, "充电电量", 120, 10, 80);
|
||||
chart.insertItem(0, "放电电量", 200, 10, 80);
|
||||
}
|
||||
{
|
||||
y += (h+10);
|
||||
int box = CreatePanel1(p, pid, x, y, w, h, "场站收益");
|
||||
PvChartCurve chart(p, box, 0, 40, 500, 200);
|
||||
chart.setBackground(p, 2, 58, 87);
|
||||
chart.setLabelYLeft("电量(元)");
|
||||
chart.insertItem(0, "收益", 120, 10, 80);
|
||||
}
|
||||
{
|
||||
y += (h+10);
|
||||
int box = CreatePanel1(p, pid, x, y, w, h, "设备利用率");
|
||||
PvChartCurve chart(p, box, 0, 40, 500, 200);
|
||||
chart.setBackground(p, 2, 58, 87);
|
||||
chart.setLabelYLeft("利用率(%)");
|
||||
chart.insertItem(0, "利用率", 120, 10, 80);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void setTitle(std::string title)
|
||||
{
|
||||
pvSetText(p, labelTitle, title.c_str());
|
||||
}
|
||||
void show(int v)
|
||||
{
|
||||
v ? pvShow(p, widget) : pvHide(p, widget);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0,stop:1 rgba(0,255,240,200),stop:0 rgba(0,255,240,0));
|
||||
int MaskPageHome::initUI(EPvCode pvcode)
|
||||
{
|
||||
int x = 10, y = 100, w = 500, h1 = 260, h2=290, h3=290;
|
||||
|
||||
// 左侧区域: 上
|
||||
{
|
||||
int x0 = 0, y0=40, w0=160, h0=64;
|
||||
int panel = CreatePanel(p, 0, x, y, w, h1, "运行总览");
|
||||
ui.labelRunDays = CreateBox(p, panel, x0 = 50, y0, w0, h0, "运行时间");
|
||||
ui.labelStationNum = CreateBox(p, panel, w-10-w0-x0, y0, w0, h0, "能源站数量");
|
||||
ui.labelEnergyCapacity = CreateBox(p, panel, x0 = 10, y0+=(h0+10), w0, h0, "储能总容量");
|
||||
ui.labelIncome = CreateBox(p, panel, w-10-w0-x0, y0, w0, h0, "累计收益");
|
||||
ui.labelStorageIn = CreateBox(p, panel, x0 = 50, y0 += (h0+10), w0, h0, "累计储能充电量");
|
||||
ui.labelStorageOut = CreateBox(p, panel, w-10-w0-x0, y0, w0, h0, "累计储能放电量");
|
||||
}
|
||||
|
||||
// 左侧区域: 中
|
||||
{
|
||||
int panel = CreatePanel(p, 0, x, y+h1+10, w, h2, "储能设备");
|
||||
|
||||
int x1 = 10;
|
||||
CreateCard2(p, panel, x1, 40, 235, 50, "今日充电电量", "0 kWh");
|
||||
CreateCard2(p, panel, x1+=245, 40, 235, 50, "今日放电电量", "0 kWh");
|
||||
|
||||
auto bar = PvChartBar::create(p, panel, 10, 100, w-20, h2-100);
|
||||
bar->setLabelYLeft("电量(kWh)");
|
||||
bar->insertItem("日充电电量");
|
||||
bar->insertItem("日放电电量");
|
||||
bar->updateItem(0, {{"08/01", 10}, {"08/02", 20}, {"08/03", 30}, {"08/04", 40}, {"08/05", 50}, {"08/06", 60}, {"08/07", 70}});
|
||||
bar->updateItem(1, {{"08/01", 1}, {"08/02", 2}, {"08/03", 3}, {"08/04", 4}, {"08/05", 5}, {"08/06", 6}, {"08/07", 7}});
|
||||
}
|
||||
|
||||
// 左侧区域: 下
|
||||
{
|
||||
int panel = CreatePanel(p, 0, x, y+h1+h2+20, w, h3, "光伏设备");
|
||||
|
||||
int x1 = 10;
|
||||
CreateCard2(p, panel, x1, 40, 235, 50, "今日发电电量", "0 kWh");
|
||||
CreateCard2(p, panel, x1 += 245, 40, 235, 50, "今日入网电量", "0 kWh");
|
||||
|
||||
auto bar = PvChartBar::create(p, panel, 10, 100, w-20, h3-100);
|
||||
bar->setLabelYLeft("电量(kWh)");
|
||||
bar->insertItem("日发电电量");
|
||||
bar->insertItem("日入网电量");
|
||||
bar->updateItem(0, {{"08/01", 10}, {"08/02", 20}, {"08/03", 30}, {"08/04", 40}, {"08/05", 50}, {"08/06", 60}, {"08/07", 70}});
|
||||
}
|
||||
|
||||
// 右侧区域:上
|
||||
{
|
||||
int panel = CreatePanel(p, 0, x += (880+10+500+10), y, w = 500, h1, "运行分析");
|
||||
|
||||
}
|
||||
// 右侧区域:中
|
||||
{
|
||||
int panel = CreatePanel(p, 0, x, y+h1+10, w = 500, h2, "充电设备");
|
||||
|
||||
int x1 = 10;
|
||||
CreateCard2(p, panel, x1, 40, 235, 50, "今日充电电量", "0 kWh");
|
||||
CreateCard2(p, panel, x1 += 245, 40, 235, 50, "今日充电次数", "0 次");
|
||||
|
||||
auto bar = PvChartBar::create(p, panel, 10, 100, w-20, h2-100);
|
||||
bar->setLabelYLeft("电量(kWh)");
|
||||
bar->insertItem("日充电电量");
|
||||
bar->insertItem("日充电次数");
|
||||
bar->updateItem(0, {{"08/01", 10}, {"08/02", 20}, {"08/03", 30}, {"08/04", 40}, {"08/05", 50}, {"08/06", 60}, {"08/07", 70}});
|
||||
|
||||
}
|
||||
// 右侧区域:下
|
||||
{
|
||||
int panel = CreatePanel(p, 0, x, y+h1+h2+20, w = 500, h3, "告警分析");
|
||||
|
||||
int x1 = 10;
|
||||
CreateCard2(p, panel, x1, 40, 153, 50, "今日储能告警", "0 次");
|
||||
CreateCard2(p, panel, x1 += 163, 40, 153, 50, "今日光伏告警", "0 次");
|
||||
CreateCard2(p, panel, x1 += 163, 40, 153, 50, "今日充电告警", "0 次");
|
||||
|
||||
auto bar = PvChartBar::create(p, panel, 10, 100, w-20, h3-100);
|
||||
bar->setLabelYLeft("次数");
|
||||
bar->insertItem("日储能告警");
|
||||
bar->insertItem("日光伏告警");
|
||||
bar->insertItem("日充电告警");
|
||||
bar->updateItem(0, {{"08/01", 10}, {"08/02", 20}, {"08/03", 30}, {"08/04", 40}, {"08/05", 50}, {"08/06", 60}, {"08/07", 70}});
|
||||
}
|
||||
|
||||
// 中间区域
|
||||
{
|
||||
int panel = PvApp::label(p, 0, x = 10+500+10, y, w = 880, h1+h2+h3+20, "", QSS_LABEL_BKG_1);
|
||||
|
||||
////// 饼图
|
||||
//int left = PvApp::widget(p, panel, 100, 100, 100, 100);
|
||||
//pvSetStyleSheet(p, left, "border: 1px solid gray; border-radius:50px;");
|
||||
|
||||
//int id = PvApp::pvid();
|
||||
//pvDownloadFile(p, "red.png");
|
||||
//pvQImage(p, id, left, "");
|
||||
//pvSetGeometry(p, id, 10, 10, 100, 100);
|
||||
//pvSetImage(p, id, "red.png", 0);
|
||||
////pvSetStyleSheet(p, id, "border-radius: 50px;");
|
||||
|
||||
//int right = PvApp::label(p, panel, 200, 100, 100, 200, "", "border: 1px solid gray;");
|
||||
//std::string qss = "background: qlineargradient(x1:0, y1 : 0, x2 : 1, y2 : 1, stop : 0 red, stop:1 blue); border-radius: 50px;";
|
||||
//std::string qss1 = "width: 200px;height: 200px;background: red;transform: rotate(45deg); border-radius: 100px;";
|
||||
//PvApp::label(p, left, 0, 0, 200, 200, "", qss1);
|
||||
|
||||
PvApp::image(p, panel, 0, 20, 880, 800, "map.png");
|
||||
|
||||
auto popStation = new PopStation(p);
|
||||
popStation->show(0);
|
||||
int btn = PvApp::button(p, panel, 10, 20, 100, 30, "场站一", STYLE_BTN);
|
||||
PvApp::bind(p, PvEvent::BUTTON_EVENT, btn, [=](std::string) {
|
||||
popStation->setTitle("场站一");
|
||||
pvShow(p, popStation->widget);
|
||||
});
|
||||
|
||||
PvApp::image(p, panel, 500, 420, 50, 50, "mapMarker.png");
|
||||
PvApp::image(p, panel, 420, 500, 50, 50, "mapMarker.png");
|
||||
PvApp::image(p, panel, 520, 532, 50, 50, "mapMarker.png");
|
||||
PvApp::image(p, panel, 363, 380, 50, 50, "mapMarker.png");
|
||||
PvApp::image(p, panel, 545, 564, 50, 50, "mapMarker.png");
|
||||
}
|
||||
|
||||
this->updateUI();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MaskPageHome::updateUI()
|
||||
{
|
||||
auto& appdata = Application::instance().getAppData();
|
||||
|
||||
int stationNum = appdata.mapStation.size(); // 场站数量
|
||||
double energyCapacity {}; // 储能容量
|
||||
double incomeTotal {}; // 累计收益
|
||||
double electStorageIn {}; // 储能充电电量
|
||||
double electStorageOut {}; // 储能放电电量
|
||||
for (auto& item : appdata.mapStation)
|
||||
{
|
||||
auto& station = item.second;
|
||||
energyCapacity += station->energyCapacity;
|
||||
incomeTotal += station->incomeTotal;
|
||||
}
|
||||
|
||||
pvSetText(p, ui.labelRunDays, "100 天");
|
||||
pvSetText(p, ui.labelRunDays, (Utils::toStr(stationNum) + " 个").c_str());
|
||||
pvSetText(p, ui.labelEnergyCapacity, (Utils::toStr(energyCapacity) + " kWh").c_str());
|
||||
pvSetText(p, ui.labelIncome, (Utils::toStr(incomeTotal) + " 元").c_str());
|
||||
pvSetText(p, ui.labelStorageIn, (Utils::toStr(electStorageIn) + " kWh").c_str());
|
||||
pvSetText(p, ui.labelStorageOut, (Utils::toStr(electStorageOut) + " kWh").c_str());
|
||||
}
|
||||
37
src/pv/pages/MaskPageHome.h
Normal file
37
src/pv/pages/MaskPageHome.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "pv/PvApp.h"
|
||||
|
||||
class MaskPageHome : public PvMask
|
||||
{
|
||||
public:
|
||||
// 控件ID的数量,需要在创建控件之前确定值和数量
|
||||
int idCount = 100;
|
||||
|
||||
int iconView1;
|
||||
int welcomeLabel;
|
||||
int helpLabel;
|
||||
int buttonRestroom;
|
||||
|
||||
public:
|
||||
MaskPageHome(PARAM* p) : PvMask(p)
|
||||
{
|
||||
iconView1 = PvApp::pvid(p);
|
||||
welcomeLabel = PvApp::pvid(p);
|
||||
helpLabel = PvApp::pvid(p);
|
||||
buttonRestroom = PvApp::pvid(p);
|
||||
}
|
||||
|
||||
int initUI(EPvCode pvcode);
|
||||
void updateUI();
|
||||
|
||||
struct {
|
||||
int labelRunDays;
|
||||
int labelStationNum;
|
||||
int labelEnergyCapacity;
|
||||
int labelIncome;
|
||||
int labelStorageIn;
|
||||
int labelStorageOut;
|
||||
} ui;
|
||||
|
||||
};
|
||||
253
src/pv/pages/MaskPageRunning.cpp
Normal file
253
src/pv/pages/MaskPageRunning.cpp
Normal file
@@ -0,0 +1,253 @@
|
||||
#include "MaskPageRunning.h"
|
||||
#include "app/Application.h"
|
||||
|
||||
static std::string QSS_CARD_DEVICE =
|
||||
"QLabel { background-color:rgb(8, 54, 91); border:0px solid rgb(120, 120, 120); border-radius:5px; font:bold 14px; color:white; }"
|
||||
"QLabel:hover {border: 2px solid rgb(79, 129, 255); border-radius:2px;}"
|
||||
"QLabel:disabled { color:rgb(150,150,150);}";
|
||||
|
||||
static std::string QSS_PARAM_K = "border:none; background-color: transparent; color: rgb(180,180,180); font: bold 13px;";
|
||||
static std::string QSS_PARAM_V = "border:none; background-color: transparent; color: white; font: bold 14px;";
|
||||
|
||||
static int CreateParamLabel(PARAM* p, int parent, int x, int y, std::string k, std::string v)
|
||||
{
|
||||
PvApp::label(p, parent, x, y, 70, 30, k, QSS_PARAM_K);
|
||||
return PvApp::label(p, parent, x += 70, y, 120, 30, v, QSS_PARAM_V);
|
||||
}
|
||||
|
||||
class BoxCard : PvObject
|
||||
{
|
||||
public:
|
||||
static std::shared_ptr<BoxCard> create(PARAM* p, int parent, int x, int y)
|
||||
{
|
||||
return std::make_shared<BoxCard>(p, parent, x, y);
|
||||
}
|
||||
|
||||
BoxCard(PARAM* p, int parent, int x, int y) : PvObject(p)
|
||||
{
|
||||
card_ = PvApp::label(p, parent, x, y, 400, 250, "", QSS_CARD_DEVICE);
|
||||
|
||||
PvApp::label(p, card_, 10, 10, 60, 60, "", "border:none; background-color: rgb(39, 158, 145);");
|
||||
ui.code = PvApp::label(p, card_, 80, 10, 100, 20, "", "border:none; background-color: transparent;");
|
||||
ui.name = PvApp::label(p, card_, 80, 30, 100, 20, "", "border:none; background-color: transparent;");
|
||||
ui.type = PvApp::label(p, card_, 80, 50, 100, 20, "", "border:none; background-color: transparent; color: rgb(8, 161, 249);");
|
||||
|
||||
int x1 = 190;
|
||||
ui.online = PvApp::labelAlignCenter(p, card_, x1, 10, 70, 30, "在线", QSS_PARAM_V);
|
||||
ui.running = PvApp::labelAlignCenter(p, card_, x1 += 70, 10, 70, 30, "空闲", QSS_PARAM_V);
|
||||
ui.err = PvApp::labelAlignCenter(p, card_, x1 += 70, 10, 70, 30, "正常", QSS_PARAM_V);
|
||||
|
||||
PvApp::labelAlignCenter(p, card_, x1 = 190, 40, 70, 30, "在线状态", QSS_PARAM_K);
|
||||
PvApp::labelAlignCenter(p, card_, x1 += 70, 40, 70, 30, "工作状态", QSS_PARAM_K);
|
||||
PvApp::labelAlignCenter(p, card_, x1 += 70, 40, 70, 30, "故障状态", QSS_PARAM_K);
|
||||
|
||||
|
||||
PvApp::label(p, card_, 10, 80, 80, 30, "运行分析:", QSS_PARAM_K);
|
||||
PvApp::button(p, card_, 80, 83, 60, 24, "查看", "border:none; border-radius: 5px; background-color: rgb(28, 145, 138); color:white; font: bold 14px;");
|
||||
|
||||
// 默认创建 10 个参数标签:
|
||||
int n = 10;
|
||||
vecParamLabel_.resize(n);
|
||||
for (int i = 0; i<n; i++)
|
||||
{
|
||||
int row = i/2;
|
||||
int col = i%2;
|
||||
int h = 25;
|
||||
vecParamLabel_[i].first = PvApp::label(p, card_, 10 + 200*col, 115 + h*row, 70, h, "参数"+std::to_string(i) + ":", QSS_PARAM_K);
|
||||
vecParamLabel_[i].second = PvApp::label(p, card_, 10 + 200*col + 70, 115 + h*row, 120, h, "---", QSS_PARAM_V);
|
||||
}
|
||||
}
|
||||
|
||||
void setCard(std::string type, std::string name, std::string code)
|
||||
{
|
||||
if (ui.code != PV_ID_NUL) { pvSetText(p, ui.code, code.c_str()); }
|
||||
if (ui.name != PV_ID_NUL) { pvSetText(p, ui.name, name.c_str()); }
|
||||
if (ui.type != PV_ID_NUL) { pvSetText(p, ui.type, type.c_str()); }
|
||||
}
|
||||
|
||||
void setParamkeys(std::vector<std::string> vecKeys)
|
||||
{
|
||||
for (int i = 0; i<vecParamLabel_.size(); i++)
|
||||
{
|
||||
auto& labelKey = vecParamLabel_[i].first;
|
||||
auto& labelVal = vecParamLabel_[i].second;
|
||||
if (i<vecKeys.size())
|
||||
{
|
||||
std::string& title = vecKeys[i] + ":";
|
||||
pvSetText(p, labelKey, title.c_str());
|
||||
pvSetText(p, labelVal, "---");
|
||||
pvShow(p, labelKey);
|
||||
pvShow(p, labelVal);
|
||||
}
|
||||
else
|
||||
{
|
||||
pvHide(p, labelKey);
|
||||
pvHide(p, labelVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void show(int visible)
|
||||
{
|
||||
visible ? pvShow(p, card_) : pvHide(p, card_);
|
||||
}
|
||||
|
||||
struct {
|
||||
int code = PV_ID_NUL;
|
||||
int name = PV_ID_NUL;
|
||||
int type = PV_ID_NUL;
|
||||
int online = PV_ID_NUL;
|
||||
int running = PV_ID_NUL;
|
||||
int err = PV_ID_NUL;
|
||||
} ui;
|
||||
|
||||
int card_;
|
||||
|
||||
std::vector<std::pair<int, int>> vecParamLabel_;
|
||||
std::map<std::string, int> mapParam_;
|
||||
};
|
||||
|
||||
MaskPageRunning::MaskPageRunning(PARAM* p) : PvMask(p)
|
||||
{
|
||||
}
|
||||
|
||||
int MaskPageRunning::initUI(EPvCode pvcode)
|
||||
{
|
||||
PvApp::label(p, 0, 10, 100, 1900, 850, "", "background-color: rgb(5, 47, 77); border-radius: 10px;");
|
||||
PvApp::label(p, 0, 10, 150, 220, 790, "", "background-color: rgb(8, 54, 91); border-radius: 10px;");
|
||||
int workspace = PvApp::label(p, 0, 240, 150, 1670, 790, "", "background-color: rgba(8, 54, 91, 0); border-radius: 10px;");
|
||||
|
||||
std::vector<std::string> vecStationNames;
|
||||
Application::instance().getAppData().getStationNames(vecStationNames);
|
||||
PvApp::label(p, 0, 20, 110, 80, 30, "场站切换", "color:white; font: bold 16px;");
|
||||
PvApp::combox(p, 0, 100, 110, 150, 30, vecStationNames);
|
||||
if (vecStationNames.size() > 0)
|
||||
{
|
||||
station_ = Application::instance().getAppData().getStationByName(vecStationNames[0]);
|
||||
}
|
||||
|
||||
PvApp::label(p, 0, 320, 110, 80, 30, "运行模式", "color:white; font: bold 16px;");
|
||||
PvApp::combox(p, 0, 400, 110, 200, 30, {"最优经济化运行模式", "最优经济化运行模式", "自定义"});
|
||||
|
||||
PvApp::label(p, 0, 670, 110, 80, 30, "策略名称", "color:white; font: bold 16px;");
|
||||
PvApp::combox(p, 0, 750, 110, 200, 30, {"峰谷套利策略", "需求响应策略", "自发自用上网策略"});
|
||||
|
||||
int x = 20, y = 160, w = 200, h = 180;
|
||||
// 储能设备
|
||||
{
|
||||
ui.storage.name = "储能设备";
|
||||
int pid = ui.storage.box = PvApp::label(p, 0, x, y, w, h, "", QSS_BOX);
|
||||
PvApp::label(p, pid, 10, 0, w-10, 30, ui.storage.name, QSS_TITLE);
|
||||
|
||||
ui.storage.btn = PvApp::button(p, pid, 0, 0, w, h, "", "background-color: transparent;");
|
||||
ui.storage.workspace = PvApp::widget(p, workspace, 0, 0, 1670, 790);
|
||||
pvHide(p, ui.storage.workspace);
|
||||
|
||||
// 创建信息卡片
|
||||
{
|
||||
vecCard_.resize(12);
|
||||
for (int i=0; i<vecCard_.size(); ++i)
|
||||
{
|
||||
vecCard_[i] = BoxCard::create(p, ui.storage.workspace, (i%4)*410, (i/4)*260);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 光伏设备
|
||||
{
|
||||
ui.solar.name = "光伏设备";
|
||||
int pid = ui.solar.box = PvApp::label(p, 0, x, y += (h+10), w, h, "", QSS_BOX);
|
||||
PvApp::label(p, pid, 10, 0, w-10, 30, ui.solar.name, QSS_TITLE);
|
||||
|
||||
ui.solar.btn = PvApp::button(p, pid, 0, 0, w, h, "", "background-color: transparent;");
|
||||
ui.solar.workspace = ui.storage.workspace;
|
||||
pvHide(p, ui.solar.workspace);
|
||||
}
|
||||
// 充电设备
|
||||
{
|
||||
ui.charge.name = "充电设备";
|
||||
int pid = ui.charge.box = PvApp::label(p, 0, x, y += (h+10), w, h, "", QSS_BOX);
|
||||
PvApp::label(p, pid, 10, 0, w-10, 30, ui.solar.name, QSS_TITLE);
|
||||
|
||||
ui.charge.btn = PvApp::button(p, pid, 0, 0, w, h, "", "background-color: transparent;");
|
||||
ui.charge.workspace = ui.storage.workspace;
|
||||
pvHide(p, ui.charge.workspace);
|
||||
}
|
||||
// 环境与安防设备
|
||||
{
|
||||
ui.security.name = "环境与安防设备";
|
||||
int pid = ui.security.box = PvApp::label(p, 0, x, y += (h+10), w, h, "", QSS_BOX);
|
||||
PvApp::label(p, pid, 10, 0, w-10, 30, ui.security.name, QSS_TITLE);
|
||||
|
||||
ui.security.btn = PvApp::button(p, pid, 0, 0, w, h, "", "background-color: transparent;");
|
||||
ui.security.workspace = PvApp::widget(p, workspace, 0, 0, 1670, 790);
|
||||
pvHide(p, ui.security.workspace);
|
||||
}
|
||||
|
||||
activeBoxPanel(ui.storage);
|
||||
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EPvCode MaskPageRunning::onEventButton(int pvid)
|
||||
{
|
||||
if (pvid == ui.storage.btn) { activeBoxPanel(ui.storage); }
|
||||
else if (pvid == ui.solar.btn) { activeBoxPanel(ui.solar); }
|
||||
else if (pvid == ui.charge.btn) { activeBoxPanel(ui.charge); }
|
||||
else if (pvid == ui.security.btn) { activeBoxPanel(ui.security); }
|
||||
|
||||
return EPvCode::NUL;
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<std::string>> mapDeviceTypes =
|
||||
{
|
||||
{"储能设备", {"储能预制舱", "储能电池", "储能电池", "储能电池"}},
|
||||
{"光伏设备", {"光伏板", "光伏板", "光伏板", "光伏板", "光伏板", "光伏板", "光伏板", "光伏板"}},
|
||||
{"充电设备", {"充电桩", "充电桩", "充电桩", "充电桩", "充电桩", "充电桩", "充电桩", "充电桩", "充电桩", "充电桩"}},
|
||||
};
|
||||
std::map<std::string, std::vector<std::string>> mapDeviceParams =
|
||||
{
|
||||
{"储能预制舱", {"运行模式", "冷却方式", "实时电压", "额定电压", "实时电流", "额定电流", "实时功率", "额定功率", "功率因数", "电池容量"}},
|
||||
{"储能电池", {"实时电压", "额定电压", "实时电流", "额定电流", "实时功率", "额定功率", "功率因数", "电池容量"}},
|
||||
{"逆变器", {"实时电压", "额定电压", "实时电流", "额定电流", "实时功率", "额定功率", "功率因数"}},
|
||||
{"光伏板", {"实时电压", "额定电压", "实时电流", "额定电流", "实时功率", "额定功率", "功率因数"}},
|
||||
{"充电桩", {"实时电压", "额定电压", "实时电流", "额定电流", "实时功率", "额定功率", "功率因数"}},
|
||||
};
|
||||
|
||||
void MaskPageRunning::activeBoxPanel(BoxPanel& panel)
|
||||
{
|
||||
static int activeBox = PV_ID_NUL;
|
||||
static int activeWorkspace = PV_ID_NUL;
|
||||
if (activeBox != PV_ID_NUL) { pvSetStyleSheet(p, activeBox, QSS_BOX.c_str()); }
|
||||
if (activeBox = panel.box) { pvSetStyleSheet(p, activeBox, QSS_BOX_ACTIVE.c_str()); }
|
||||
|
||||
if (activeWorkspace != PV_ID_NUL) { pvHide(p, activeWorkspace); }
|
||||
if (activeWorkspace = panel.workspace) { pvShow(p, activeWorkspace); }
|
||||
|
||||
|
||||
if (panel.workspace != ui.security.workspace)
|
||||
{
|
||||
std::vector<std::string> vecDeviceInfo = mapDeviceTypes[panel.name];
|
||||
|
||||
// 读取储能设备信息
|
||||
for (int i = 0; i<vecCard_.size(); ++i)
|
||||
{
|
||||
auto& card = vecCard_[i];
|
||||
if (i < vecDeviceInfo.size())
|
||||
{
|
||||
std::string type = vecDeviceInfo[i];
|
||||
card->show(1);
|
||||
card->setCard(type, type+"-"+std::to_string(i), type+"-"+std::to_string(i));
|
||||
card->setParamkeys(mapDeviceParams[type]);
|
||||
}
|
||||
else
|
||||
{
|
||||
card->show(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
src/pv/pages/MaskPageRunning.h
Normal file
35
src/pv/pages/MaskPageRunning.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "pv/PvApp.h"
|
||||
|
||||
class BoxCard;
|
||||
class Station;
|
||||
|
||||
class MaskPageRunning : public PvMask
|
||||
{
|
||||
public:
|
||||
struct BoxPanel {
|
||||
std::string name;
|
||||
int box;
|
||||
int btn;
|
||||
int workspace;
|
||||
};
|
||||
|
||||
MaskPageRunning(PARAM* p);
|
||||
int initUI(EPvCode pvcode);
|
||||
|
||||
virtual EPvCode onEventButton(int pvid);
|
||||
|
||||
void activeBoxPanel(BoxPanel& panel);
|
||||
|
||||
|
||||
struct {
|
||||
BoxPanel storage;
|
||||
BoxPanel solar;
|
||||
BoxPanel charge;
|
||||
BoxPanel security;
|
||||
} ui;
|
||||
|
||||
std::vector<std::shared_ptr<BoxCard>> vecCard_;
|
||||
std::shared_ptr<Station> station_ = nullptr;
|
||||
};
|
||||
167
src/pv/pages/MaskPageStat.cpp
Normal file
167
src/pv/pages/MaskPageStat.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
#include "MaskPageStat.h"
|
||||
#include "pv/PvTable.h"
|
||||
#include "pv/PvChart.h"
|
||||
|
||||
static int CreatePanel(PARAM* p, int parentId, int x, int y, int w, int h, std::string title)
|
||||
{
|
||||
int id = PvApp::label(p, parentId, x, y, w, h, "", QSS_LABEL_BKG_2);
|
||||
PvApp::label(p, id, 10, 10, w, 20, title, STYLE_TITLE_ICON);
|
||||
PvApp::label(p, id, 20, 30, w, 2, "", QSS_UNDERLINE);
|
||||
return id;
|
||||
}
|
||||
|
||||
MaskPageStat::MaskPageStat(PARAM* p) : PvMask(p)
|
||||
{
|
||||
}
|
||||
|
||||
struct StatChartInfo
|
||||
{
|
||||
std::string name;
|
||||
std::vector<std::string> vecAxis;
|
||||
std::vector<std::pair<std::string, int>> vecItems;
|
||||
StatChartInfo(std::string name, std::vector<std::string> axis, std::vector<std::pair<std::string, int>> items) : name(name), vecAxis(axis), vecItems(items) {};
|
||||
};
|
||||
using VecChartDef = std::vector<StatChartInfo>;
|
||||
static VecChartDef chartStorageDef =
|
||||
{
|
||||
StatChartInfo {"充放电分析", {"电量(kWh)"}, {{"充电电量", 0}, { "放电电量", 0 }}},
|
||||
StatChartInfo {"运行状态分析", {"时长(h)", "次数"}, {{"充电时长", 0}, {"放电时长", 0}, {"故障次数", 0}}},
|
||||
StatChartInfo {"电压/电流分析", {"电压(V)", "电流(A)"}, {{"电压", 0}, {"电流", 0}}},
|
||||
StatChartInfo {"功率分析", {"功率(kW)"}, {{"功率", 0}}}
|
||||
};
|
||||
static VecChartDef chartSolarDef =
|
||||
{
|
||||
StatChartInfo {"发电电量分析", {"电量(kWh)"}, {{"发电电量", 0}}},
|
||||
StatChartInfo {"运行状态分析", {"时长(h)", "次数"}, {{"发电时长", 0}, {"故障次数", 0}}},
|
||||
StatChartInfo {"电压/电流分析", {"电压(V)", "电流(A)"}, {{"电压", 0}, {"电流", 0}}},
|
||||
StatChartInfo {"功率分析", {"功率(kW)"}, {{"功率", 0}}}
|
||||
};
|
||||
static VecChartDef chartChargeDef =
|
||||
{
|
||||
StatChartInfo {"充电分析", {"电量(kWh)"}, {{"充电电量", 0}}},
|
||||
StatChartInfo {"运行状态分析", {"时长(h)", "次数"}, {{"充电时长", 0}, {"充电次数", 0}, {"故障次数", 0}}},
|
||||
StatChartInfo {"电压/电流分析", {"电压(V)", "电流(A)"}, {{"电压", 0}, {"电流", 0}}},
|
||||
StatChartInfo {"功率分析", {"功率(kW)"}, {{"功率", 0}}}
|
||||
};
|
||||
using VecStatDef = std::vector<std::pair<std::string, VecChartDef>>;
|
||||
static VecStatDef statDef = {
|
||||
{"储能设备运行分析", chartStorageDef},
|
||||
{"光伏设备运行分析", chartSolarDef},
|
||||
{"充电设备运行分析", chartChargeDef}
|
||||
};
|
||||
|
||||
int MaskPageStat::initUI(EPvCode pvcode)
|
||||
{
|
||||
PvApp::label(p, PV_ID_MAIN, 10, 100, 1900, 850, "", QSS_LABEL_BKG_1);
|
||||
|
||||
if (pvcode == EPvCode::MASK_STAT) { pvcode = EPvCode::MASK_STAT_STORAGE; }
|
||||
std::string curModuleName;
|
||||
VecChartDef chartDef {};
|
||||
|
||||
for (int i = 0; i<statDef.size(); ++i)
|
||||
{
|
||||
std::string moduleName = statDef[i].first;
|
||||
// 创建按钮
|
||||
bool isActive = (PvApp::getPvCode(moduleName) == pvcode);
|
||||
int pageBtn = PvApp::button(p, PV_ID_MAIN, 10+(i*190), 110, 180, 40, moduleName, isActive ? QSS_BTN_MGR_ACTIVE : QSS_BTN_MGR);
|
||||
mapSubpage_[pageBtn] = moduleName;
|
||||
if (isActive)
|
||||
{
|
||||
curModuleName = moduleName;
|
||||
chartDef = statDef[i].second;
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化统计图表
|
||||
if (!chartDef.empty())
|
||||
{
|
||||
int x=10, y=160, w=467, h=300, delta = 32;
|
||||
for (int i = 0; i<chartDef.size(); ++i)
|
||||
{
|
||||
auto& chartInfo = chartDef[i];
|
||||
std::string title = chartInfo.name;
|
||||
auto& vecAxis = chartInfo.vecAxis;
|
||||
auto& vecItems = chartInfo.vecItems;
|
||||
|
||||
int panel = CreatePanel(p, 0, x+(w+10)*i, y, w, h, title);
|
||||
if (i == 0)
|
||||
{
|
||||
chart1 = std::make_shared<PvChartBar>(p, panel, 0, delta, w, h-delta);
|
||||
this->initChartBar(chart1, vecAxis, vecItems);
|
||||
}
|
||||
else if (i == 1)
|
||||
{
|
||||
chart2 = std::make_shared<PvChartBar>(p, panel, 0, delta, w, h-delta);
|
||||
this->initChartBar(chart2, vecAxis, vecItems);
|
||||
}
|
||||
else if (i == 2)
|
||||
{
|
||||
chart3 = std::make_shared<PvChartCurve>(p, panel, 0, delta, w, h-delta);
|
||||
chart3->setBackground(p, 8, 54, 91);
|
||||
this->initChartCurve(chart3, vecAxis, vecItems);
|
||||
}
|
||||
else if (i == 3)
|
||||
{
|
||||
chart4 = std::make_shared<PvChartCurve>(p, panel, 0, delta, w, h-delta);
|
||||
chart4->setBackground(p, 8, 54, 91);
|
||||
this->initChartCurve(chart4, vecAxis, vecItems);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化表格
|
||||
{
|
||||
PvTable::Options option;
|
||||
auto table = new PvTable(p, 0, 10, 480, 1900, 12, option);
|
||||
table->addHead({"日期", "设备ID", "设备名称", "设备类型", "充电次数", "放电次数", "故障次数"});
|
||||
}
|
||||
|
||||
//
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MaskPageStat::initChartBar(std::shared_ptr<PvChartBar> chart, std::vector<std::string>& vecAxis, std::vector<std::pair<std::string, int>>& vecItems)
|
||||
{
|
||||
if (!chart) { return; }
|
||||
for (int pos = 0; pos<vecAxis.size(); ++pos)
|
||||
{
|
||||
auto text = vecAxis[pos];
|
||||
if (pos == 0) chart->setLabelYLeft(text);
|
||||
if (pos == 1) chart->setLabelYRight(text);
|
||||
}
|
||||
for (int index = 0; index<vecItems.size(); ++index)
|
||||
{
|
||||
chart->insertItem(vecItems[index].first);
|
||||
}
|
||||
}
|
||||
|
||||
void MaskPageStat::initChartCurve(std::shared_ptr<PvChartCurve> chart, std::vector<std::string>& vecAxis, std::vector<std::pair<std::string, int>>& vecItems)
|
||||
{
|
||||
if (!chart) { return; }
|
||||
for (int pos = 0; pos<vecAxis.size(); ++pos)
|
||||
{
|
||||
auto text = vecAxis[pos];
|
||||
if (pos == 0) chart->setLabelYLeft(text);
|
||||
if (pos == 1) chart->setLabelYRight(text);
|
||||
}
|
||||
for (int index = 0; index<vecItems.size(); ++index)
|
||||
{
|
||||
chart->insertItem(vecItems[index].second, vecItems[index].first, 100+80*index, 10, 80);
|
||||
}
|
||||
}
|
||||
|
||||
EPvCode MaskPageStat::onEventButton(int pvid)
|
||||
{
|
||||
std::string title;
|
||||
auto iter = mapSubpage_.find(pvid);
|
||||
if (iter != mapSubpage_.end())
|
||||
{
|
||||
title = iter->second;
|
||||
return PvApp::getPvCode(title);
|
||||
}
|
||||
return EPvCode::NUL;
|
||||
}
|
||||
26
src/pv/pages/MaskPageStat.h
Normal file
26
src/pv/pages/MaskPageStat.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "pv/PvApp.h"
|
||||
|
||||
class PvChartBar;
|
||||
class PvChartCurve;
|
||||
|
||||
class MaskPageStat : public PvMask
|
||||
{
|
||||
public:
|
||||
MaskPageStat(PARAM* p);
|
||||
|
||||
int initUI(EPvCode pvcode);
|
||||
|
||||
void initChartBar(std::shared_ptr<PvChartBar> chart, std::vector<std::string>& vecAxis, std::vector<std::pair<std::string, int>>& vecItems);
|
||||
void initChartCurve(std::shared_ptr<PvChartCurve> chart, std::vector<std::string>& vecAxis, std::vector<std::pair<std::string, int>>& vecItems);
|
||||
|
||||
EPvCode onEventButton(int pvid) override;
|
||||
|
||||
std::map<int, std::string> mapSubpage_;
|
||||
|
||||
std::shared_ptr<PvChartBar> chart1;
|
||||
std::shared_ptr<PvChartBar> chart2;
|
||||
std::shared_ptr<PvChartCurve> chart3;
|
||||
std::shared_ptr<PvChartCurve> chart4;
|
||||
};
|
||||
355
src/pv/pages/MaskPageSysmgr.cpp
Normal file
355
src/pv/pages/MaskPageSysmgr.cpp
Normal file
@@ -0,0 +1,355 @@
|
||||
#include "MaskPageSysmgr.h"
|
||||
#include "pv/PvTable.h"
|
||||
#include <thread>
|
||||
#include "database/Dao.h"
|
||||
#include "pv/PvPopWidget.h"
|
||||
|
||||
static void createPvTable(PARAM* p)
|
||||
{
|
||||
int nRow = 20, nCol = 10;
|
||||
int id = PvApp::pvid(p);
|
||||
pvQTable(p, id, 0, nRow, nCol);
|
||||
pvSetGeometry(p, id, 10, 200, 1900, 700);
|
||||
|
||||
//pvSetWhatsThis()
|
||||
//pvWhatsThisPrintf()
|
||||
//pvToolTip()
|
||||
//pvSetGeometry()
|
||||
//pvSetMinSize()
|
||||
//pvSetMaxSize()
|
||||
//pvMove();
|
||||
//pvResize();
|
||||
//pvHide();
|
||||
//pvShow();
|
||||
//pvSetStyleSheet()
|
||||
//pvPrintfStyleSheet();
|
||||
pvSetPaletteBackgroundColor(p, id, 1, 32, 54);
|
||||
pvSetPaletteForegroundColor(p, id, 0, 255, 0);
|
||||
//pvSetFontColor()
|
||||
//pvSetFont()
|
||||
//pvSetEnabled()
|
||||
//pvSetFocus()
|
||||
//pvCopyToClipboard()
|
||||
//pvSaveAsBmp()
|
||||
|
||||
//pvTablePrintf()
|
||||
//pvClear();
|
||||
//pvSetColumnWidth()
|
||||
//pvSetRowHeight()
|
||||
//pvSetWordWrap()
|
||||
//pvSetTablePixmap()
|
||||
//pvEnsureCellVisible()
|
||||
pvSetEditable(p, id, 0);
|
||||
pvTableSetEnabled(p, id, 1, 0, 0);
|
||||
|
||||
// 设置垂直(vertical)方向表头不可 resize
|
||||
for (int i = 0; i<nRow; ++i) { pvTableSetHeaderResizeEnabled(p, id, 0, 0, i); }
|
||||
// 设置水平(horizontal)方向表头不可 resize
|
||||
for (int i = 0; i<nCol; ++i) { pvTableSetHeaderResizeEnabled(p, id, 1, 0, i); }
|
||||
|
||||
pvSetTableText(p, id, -1, -1, "A");
|
||||
//pvSetTableCheckBox()
|
||||
|
||||
//pvSetTableLabel()
|
||||
pvSetTableButton(p, id, 1, 1, "HelloWorld");
|
||||
pvSetTableComboBox(p, id, 1, 2, 1, "choice1,#choice2,choice3");
|
||||
|
||||
//pvSetNumRows()
|
||||
//pvSetNumCols()
|
||||
//pvInsertRows()
|
||||
//pvInsertColumns()
|
||||
//pvRemoveRow()
|
||||
//pvRemoveColumn()
|
||||
//pvSetTableTextAlignment();
|
||||
//pvSave()
|
||||
//pvMysqldump()
|
||||
//pvCSVcreate()
|
||||
//pvCSVdump()
|
||||
//pvCSV()
|
||||
}
|
||||
|
||||
|
||||
class PageTable : public PvMask
|
||||
{
|
||||
public:
|
||||
PageTable(PARAM* p) : PvMask(p)
|
||||
{
|
||||
table = std::make_shared<PvTable>(p, 0, 10, 160, 1900, 20, option);
|
||||
table->setOperateCallback([=](int row, int col, std::string text) { this->onCallbackOperate(row, col, text); });
|
||||
};
|
||||
|
||||
void setPage(int pageIndex, int pageSize, int count) {}
|
||||
|
||||
void updateDataFromDB()
|
||||
{
|
||||
std::vector<DataFields> result;
|
||||
PageInfo pageInfo;
|
||||
this->queryTable(pageInfo, result);
|
||||
for (int i = 0; i<table->rows(); ++i)
|
||||
{
|
||||
if (i<result.size())
|
||||
{
|
||||
auto& fields = result[i];
|
||||
table->setRowData(i, result[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
table->setRowVisible(i, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void queryTable(PageInfo& pageInfo, std::vector<DataFields>& result) {}
|
||||
virtual void onCallbackOperate(int row, int col, std::string text) {};
|
||||
|
||||
int pageIndex {0};
|
||||
PvTable::Options option;
|
||||
std::shared_ptr<PvTable> table;
|
||||
std::shared_ptr<PvPopWidget> pop;
|
||||
};
|
||||
|
||||
class PageUser : public PageTable
|
||||
{
|
||||
public:
|
||||
PageUser(PARAM* p, EPvCode pvcode) :PageTable(p)
|
||||
{
|
||||
table->addHead(DMUser::USER_ID, "用户编号", 180, {});
|
||||
table->addHead(DMUser::ACCOUNT, "用户名", 180, {});
|
||||
table->addHead(DMUser::NAME, "姓名", 180, {});
|
||||
table->addHead(DMUser::GENDER, "性别", 180, {{"1", "男"}, {"0","女"}});
|
||||
table->addHead(DMUser::AGE, "年龄", 180, {});
|
||||
table->addHead(DMUser::PHONE, "手机号", 180, {});
|
||||
table->addHead(DMUser::EMAIL, "邮箱", 180, {});
|
||||
table->addHead("role_id", "角色", 180, {});
|
||||
table->addHead(DMUser::LOGINTIME, "上次登录时间", 200, {});
|
||||
table->addOperate({"编辑"});
|
||||
|
||||
pop = std::make_shared<PvPopWidget>(p, 700, 500);
|
||||
pop->show(0);
|
||||
pop->setCallbackConfirm([=]() {
|
||||
auto fields = pop->getData();
|
||||
XLOGD() << fields.toStr();
|
||||
// 保存数据:
|
||||
DAO::updateUserById(fields);
|
||||
});
|
||||
|
||||
int x = 50, y = 100, w=350, h=60;
|
||||
pop->addParamLineEdit(DMUser::USER_ID, "用户编号", x, y, false);
|
||||
pop->addParamCombox(DMRole::ROLE_ID, "角 色", x+w, y, {"系统管理员", "运营管理员", "运营人员"});
|
||||
pop->addParamLineEdit(DMUser::ACCOUNT, "用 户 名", x, y+=h);
|
||||
pop->addParamLineEdit(DMUser::NAME, "姓 名", x+w, y);
|
||||
pop->addParamLineEdit(DMUser::GENDER, "性 别", x, y+=h);
|
||||
pop->addParamLineEdit(DMUser::AGE, "年 龄", x+w, y);
|
||||
pop->addParamLineEdit(DMUser::PHONE, "手 机 号", x, y += h);
|
||||
pop->addParamLineEdit(DMUser::EMAIL, "邮 箱", x+w, y);
|
||||
}
|
||||
void queryTable(PageInfo& pageInfo, std::vector<DataFields>& result)
|
||||
{
|
||||
DAO::queryUserList(pageInfo, result);
|
||||
}
|
||||
void onCallbackOperate(int row, int col, std::string text)
|
||||
{
|
||||
if (text == "编辑")
|
||||
{
|
||||
pop->show(1);
|
||||
pop->setTitle("编辑用户信息");
|
||||
DataFields fields = table->getRowdata(row);
|
||||
pop->setData(fields);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
class PageRole : public PageTable
|
||||
{
|
||||
public:
|
||||
PageRole(PARAM* p, EPvCode pvcode) : PageTable(p)
|
||||
{
|
||||
table->addHead(DMRole::ROLE_ID, "角色编号", 200, {});
|
||||
table->addHead(DMRole::NAME, "角色名称", 200, {});
|
||||
table->addHead(DMRole::DESCRIBE, "角色描述", 900, {});
|
||||
table->addHead(DMRole::IS_OPEN, "是否启用", 200, {{"1", "是"}, {"0", "否"}});
|
||||
table->addOperate({"编辑", "设置权限"});
|
||||
}
|
||||
void queryTable(PageInfo& pageInfo, std::vector<DataFields>& result)
|
||||
{
|
||||
DAO::queryRoleList(pageInfo, result);
|
||||
}
|
||||
};
|
||||
|
||||
class PagePermission : public PageTable
|
||||
{
|
||||
public:
|
||||
PagePermission(PARAM* p, EPvCode pvcode) : PageTable(p)
|
||||
{
|
||||
table->addHead(DMPermission::PERMISSION_ID,"权限编号", 200, {});
|
||||
table->addHead(DMPermission::NAME, "权限名称", 200, {});
|
||||
table->addHead(DMPermission::DESCRIBE, "权限描述", 900, {});
|
||||
table->addHead(DMPermission::IS_OPEN, "是否启用", 200, {{"1", "是"}, {"0", "否"}});
|
||||
table->addOperate({"查看"});
|
||||
}
|
||||
void queryTable(PageInfo& pageInfo, std::vector<DataFields>& result)
|
||||
{
|
||||
DAO::queryPermissionList(pageInfo, result);
|
||||
}
|
||||
};
|
||||
|
||||
class PageStation : public PageTable
|
||||
{
|
||||
public:
|
||||
PageStation(PARAM* p, EPvCode pvcode) : PageTable(p)
|
||||
{
|
||||
table->addHead(DMStation::STATION_ID, "场站编号", 200, {});
|
||||
table->addHead(DMStation::NAME, "场站名称", 200, {});
|
||||
table->addHead(DMStation::ADDRESS, "地址", 200, {});
|
||||
table->addHead(DMStation::LONGITUDE, "经度", 200, {});
|
||||
table->addHead(DMStation::LATITUDE, "维度", 200, {});
|
||||
table->addHead(DMStation::TEL, "电话", 200, {});
|
||||
table->addHead(DMStation::STATUS, "状态", 200, {{"0","未启用"}, {"1", "启用"}});
|
||||
table->addOperate({"查看", "编辑"});
|
||||
}
|
||||
void queryTable(PageInfo& pageInfo, std::vector<DataFields>& result)
|
||||
{
|
||||
DAO::queryStationList(pageInfo, result);
|
||||
}
|
||||
};
|
||||
|
||||
class PageDevice: public PageTable
|
||||
{
|
||||
public:
|
||||
PageDevice(PARAM* p, EPvCode pvcode) : PageTable(p)
|
||||
{
|
||||
table->addHead(DMDevice::DEVICE_ID, "设备编号", 120, {});
|
||||
table->addHead(DMDevice::TYPE, "设备类型", 120, {});
|
||||
table->addHead(DMDevice::NAME, "设备名称", 180, {});
|
||||
table->addHead(DMDevice::CODE, "设备编码", 160, {});
|
||||
table->addHead(DMDevice::MODEL, "设备型号", 160, {});
|
||||
table->addHead(DMDevice::FACTORY, "厂家", 160, {});
|
||||
table->addHead(DMDevice::TEL, "厂家电话", 160, {});
|
||||
table->addHead(DMDevice::ATTRS, "设备参数", 460, {});
|
||||
table->addHead(DMDevice::IS_OPEN, "是否启用", 120, {{"1", "是"}, {"0", "否"}});
|
||||
table->addOperate({"查看", "编辑"});
|
||||
}
|
||||
void queryTable(PageInfo& pageInfo, std::vector<DataFields>& result)
|
||||
{
|
||||
DAO::queryDeviceList(pageInfo, result);
|
||||
}
|
||||
};
|
||||
|
||||
class PagePolicy : public PageTable
|
||||
{
|
||||
public:
|
||||
PagePolicy(PARAM* p, EPvCode pvcode) : PageTable(p)
|
||||
{
|
||||
table->addHead(DMPolicy::POLICY_ID, "策略编号", 200, {});
|
||||
table->addHead(DMPolicy::TYPE, "策略类型", 200, {});
|
||||
table->addHead(DMPolicy::NAME, "策略名称", 200, {});
|
||||
table->addHead(DMPolicy::DESCRIBE, "策略描述", 400, {});
|
||||
table->addHead(DMPolicy::VALUE, "策略参数", 400, {});
|
||||
table->addHead(DMPolicy::IS_OPEN, "是否启用", 200, {{"1", "是"}, {"0", "否"}});
|
||||
table->addOperate({"查看", "编辑"});
|
||||
}
|
||||
void queryTable(PageInfo& pageInfo, std::vector<DataFields>& result)
|
||||
{
|
||||
DAO::queryPolicyList(pageInfo, result);
|
||||
}
|
||||
};
|
||||
|
||||
class PageSyslog : public PageTable
|
||||
{
|
||||
public:
|
||||
PageSyslog(PARAM* p, EPvCode pvcode) : PageTable(p)
|
||||
{
|
||||
table->addHead(DMSystemLog::LOG_ID, "日志编号", 160, {});
|
||||
table->addHead(DMSystemLog::TYPE, "日志类型", 160, {});
|
||||
table->addHead(DMSystemLog::USER_ACCOUNT, "用户", 160, {});
|
||||
table->addHead(DMSystemLog::CONTENT, "日志详情", 800, {});
|
||||
table->addHead(DMSystemLog::STATUS, "状态", 160, {});
|
||||
table->addHead(DMSystemLog::CREATE_TIME, "记录时间", 200, {});
|
||||
table->addOperate({"查看"});
|
||||
}
|
||||
void queryTable(PageInfo& pageInfo, std::vector<DataFields>& result)
|
||||
{
|
||||
DAO::querySystemLogList(pageInfo, result);
|
||||
}
|
||||
};
|
||||
|
||||
class PageAlertlog : public PageTable
|
||||
{
|
||||
public:
|
||||
PageAlertlog(PARAM* p, EPvCode pvcode) : PageTable(p)
|
||||
{
|
||||
table->addHead(DMAlertLog::LOG_ID, "日志编号", 160, {});
|
||||
table->addHead(DMAlertLog::TYPE, "日志类型", 160, {});
|
||||
table->addHead(DMAlertLog::DEVICE_ID, "设备ID", 160, {});
|
||||
table->addHead(DMAlertLog::CONTENT, "日志详情", 800, {});
|
||||
table->addHead(DMAlertLog::STATUS, "状态", 160, {});
|
||||
table->addHead(DMAlertLog::CREATE_TIME, "记录时间", 200, {});
|
||||
table->addOperate({"查看"});
|
||||
}
|
||||
void queryTable(PageInfo& pageInfo, std::vector<DataFields>& result)
|
||||
{
|
||||
//DAO::queryAlertLogList(pageInfo, result);
|
||||
}
|
||||
};
|
||||
|
||||
MaskPageSysmgr::MaskPageSysmgr(PARAM* p) : PvMask(p)
|
||||
{
|
||||
}
|
||||
|
||||
int MaskPageSysmgr::initUI(EPvCode pvcode)
|
||||
{
|
||||
PvApp::label(p, PV_ID_MAIN, 10, 100, 1900, 850, "", QSS_LABEL_BKG_1);
|
||||
|
||||
if (pvcode == EPvCode::MASK_SYSMGR) { pvcode = EPvCode::MASK_MGR_USER; }
|
||||
|
||||
static std::vector<std::string> vecPageNames = {"用户管理", "角色管理", "权限管理", "场站管理", "设备管理", "策略管理", "系统日志", "告警日志"};
|
||||
for (int i = 0; i<vecPageNames.size(); ++i)
|
||||
{
|
||||
std::string& title = vecPageNames[i];
|
||||
bool isActive = (PvApp::getPvCode(title) == pvcode);
|
||||
int idPageBtn = PvApp::button(p, PV_ID_MAIN, 10+(i*110), 110, 100, 40, title, isActive ? QSS_BTN_MGR_ACTIVE : QSS_BTN_MGR);
|
||||
mapSubpage_[idPageBtn] = title;
|
||||
}
|
||||
|
||||
switch (pvcode)
|
||||
{
|
||||
case EPvCode::MASK_MGR_USER: { subpage_ = std::make_shared<PageUser>(p, pvcode); }
|
||||
break;
|
||||
case EPvCode::MASK_MGR_ROLE: { subpage_ = std::make_shared<PageRole>(p, pvcode); }
|
||||
break;
|
||||
case EPvCode::MASK_MGR_PERMISSION: { subpage_ = std::make_shared<PagePermission>(p, pvcode); }
|
||||
break;
|
||||
case EPvCode::MASK_MGR_STATION: { subpage_ = std::make_shared<PageStation>(p, pvcode); }
|
||||
break;
|
||||
case EPvCode::MASK_MGR_DEVICE: { subpage_ = std::make_shared<PageDevice>(p, pvcode); }
|
||||
break;
|
||||
case EPvCode::MASK_MGR_POLICY: { subpage_ = std::make_shared<PagePolicy>(p, pvcode); }
|
||||
break;
|
||||
case EPvCode::MASK_MGR_SYSLOG: { subpage_ = std::make_shared<PageSyslog>(p, pvcode); }
|
||||
break;
|
||||
case EPvCode::MASK_MGR_ALERTLOG: { subpage_ = std::make_shared<PageAlertlog>(p, pvcode); }
|
||||
break;
|
||||
default:
|
||||
{
|
||||
subpage_ = std::make_shared<PageUser>(p, pvcode);
|
||||
} break;
|
||||
}
|
||||
|
||||
std::thread([=]() {
|
||||
if (subpage_) { subpage_->updateDataFromDB(); }
|
||||
}).detach();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EPvCode MaskPageSysmgr::onEventButton(int pvid)
|
||||
{
|
||||
std::string title;
|
||||
auto iter = mapSubpage_.find(pvid);
|
||||
if (iter != mapSubpage_.end())
|
||||
{
|
||||
title = iter->second;
|
||||
return PvApp::getPvCode(title);
|
||||
}
|
||||
return EPvCode::NUL;
|
||||
}
|
||||
30
src/pv/pages/MaskPageSysmgr.h
Normal file
30
src/pv/pages/MaskPageSysmgr.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "pv/PvApp.h"
|
||||
|
||||
class PageTable;
|
||||
|
||||
class MaskPageSysmgr : public PvMask
|
||||
{
|
||||
public:
|
||||
MaskPageSysmgr(PARAM* p);
|
||||
int initUI(EPvCode pvcode);
|
||||
|
||||
virtual EPvCode onEventButton(int pvid) override;
|
||||
|
||||
struct {
|
||||
int activePage = PV_ID_NUL;
|
||||
int pageUser = PV_ID_NUL;
|
||||
int pageRole = PV_ID_NUL;
|
||||
int pagePermission = PV_ID_NUL;
|
||||
int pageStation = PV_ID_NUL;
|
||||
int pageDevice = PV_ID_NUL;
|
||||
int pagePolicy = PV_ID_NUL;
|
||||
int pageSyslog = PV_ID_NUL;
|
||||
int pageAlertlog = PV_ID_NUL;
|
||||
} ui;
|
||||
|
||||
std::shared_ptr<PageTable> subpage_;
|
||||
|
||||
std::map<int, std::string> mapSubpage_;
|
||||
};
|
||||
112
src/pv/pvmain.cpp
Normal file
112
src/pv/pvmain.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#include "pv/PvApp.h"
|
||||
#include "pv/PvUser.h"
|
||||
#include "pv/MaskMain.h"
|
||||
|
||||
void pvInitResource(PARAM* p)
|
||||
{
|
||||
pvDownloadFile(p, "assets/pv/bkg.png");
|
||||
pvDownloadFile(p, "assets/pv/icon1.png");
|
||||
pvDownloadFile(p, "assets/pv/icon2.png");
|
||||
pvDownloadFile(p, "assets/pv/icon3.png");
|
||||
pvDownloadFile(p, "assets/pv/icon4.png");
|
||||
pvDownloadFile(p, "assets/pv/icon5.png");
|
||||
pvDownloadFile(p, "assets/pv/bkgBox.png");
|
||||
pvDownloadFile(p, "assets/pv/map.png");
|
||||
pvDownloadFile(p, "assets/pv/mapMarker.png");
|
||||
pvDownloadFile(p, "assets/pv/downFill.png");
|
||||
}
|
||||
|
||||
int onPvThreadCleanup(void* ptr)
|
||||
{
|
||||
PARAM* p = (PARAM*)ptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pvMain(PARAM* p)
|
||||
{
|
||||
p->sleep = 100;
|
||||
|
||||
// 管理客户端的连接信息
|
||||
PvUser pvuser;
|
||||
PvApp::setPvUser(p, &pvuser);
|
||||
|
||||
// 客户端断开时回调
|
||||
pvSetCleanup(p, onPvThreadCleanup, p);
|
||||
|
||||
pvInitResource(p);
|
||||
EPvCode pvcode = EPvCode::NUL;
|
||||
|
||||
while (1)
|
||||
{
|
||||
// 重置控件的ID值
|
||||
PvApp::reset(p);
|
||||
|
||||
std::shared_ptr<MaskMain> mask;
|
||||
mask = std::make_shared<MaskMain>(p, pvcode);
|
||||
|
||||
// 超过设定数量值的控件将不会显示
|
||||
pvStartDefinition(p, 1024);
|
||||
if (mask)
|
||||
{
|
||||
mask->initUI();
|
||||
}
|
||||
pvQLayoutVbox(p, 0, -1);
|
||||
pvEndDefinition(p);
|
||||
XLOGD() << "===>>> pvidIndex=" << PvApp::pvid(p);
|
||||
|
||||
|
||||
char event[MAX_EVENT_LENGTH];
|
||||
char text[MAX_EVENT_LENGTH];
|
||||
int pvid;
|
||||
pvClearMessageQueue(p);
|
||||
while (1)
|
||||
{
|
||||
pvcode = EPvCode::NUL;
|
||||
pvPollEvent(p, event);
|
||||
PvEvent pvEventId = static_cast<PvEvent>(pvParseEvent(event, &pvid, text));
|
||||
if (mask)
|
||||
{
|
||||
PvApp::dispatch(p, pvEventId, pvid, text);
|
||||
|
||||
switch (pvEventId)
|
||||
{
|
||||
case NULL_EVENT: {
|
||||
pvcode = mask->onEventNull(pvid);
|
||||
} break;
|
||||
case BUTTON_EVENT: {
|
||||
pvcode = mask->onEventButton(pvid); std::cout << "EVENT: BUTTON\n";
|
||||
} break;
|
||||
case TEXT_EVENT: {} break;
|
||||
case SLIDER_EVENT: {} break;
|
||||
case CHECKBOX_EVENT: {} break;
|
||||
case RADIOBUTTON_EVENT: {} break;
|
||||
case GL_IDLE_EVENT: {} break;
|
||||
case GL_PAINT_EVENT: {} break;
|
||||
case GL_INITIALIZE_EVENT: {} break;
|
||||
case GL_RESIZE_EVENT: {} break;
|
||||
case TAB_EVENT: {} break;
|
||||
case TABLE_CLICKED_EVENT: {} break;
|
||||
case TABLE_TEXT_EVENT: {} break;
|
||||
case SELECTION_EVENT: {} break;
|
||||
case CLIPBOARD_EVENT: {} break;
|
||||
case BUTTON_PRESSED_EVENT: {} break;
|
||||
case BUTTON_RELEASED_EVENT: {} break;
|
||||
case RIGHT_MOUSE_EVENT: {} break;
|
||||
case KEYBOARD_EVENT: {} break;
|
||||
case PLOT_MOUSE_MOVED_EVENT: {} break;
|
||||
case PLOT_MOUSE_PRESSED_EVENT: {} break;
|
||||
case PLOT_MOUSE_RELEASED_EVENT: {} break;
|
||||
case USER_EVENT: {} break;
|
||||
case MOUSE_OVER_EVENT: {} break;
|
||||
default: {} break;
|
||||
}
|
||||
}
|
||||
|
||||
if (pvcode != EPvCode::NUL)
|
||||
{
|
||||
std::cout << "mask status: " << (int)pvcode << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user