From 454310262bfc2b6acf2e7317404de7bc04f07681 Mon Sep 17 00:00:00 2001 From: lixiaoyuan Date: Mon, 29 Sep 2025 18:31:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=AE=BE=E5=A4=87=E6=98=BE?= =?UTF-8?q?=E7=A4=BA=E4=BF=A1=E6=81=AF=E7=9A=84=E5=AF=84=E5=AD=98=E5=99=A8?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6=EF=BC=8C?= =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=9C=8D=E5=8A=A1=E7=AB=AF=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/Release/assets/config/app.json | 7 +- bin/Release/assets/config/regaddrsShow.json | 45 +++- bin/Release/assets/config/regaddrsValStr.json | 47 ++++ src/app/AppData.cpp | 23 +- src/app/AppData.h | 10 +- src/app/Application.cpp | 2 +- src/app/DataStruct.cpp | 108 ++++++++- src/app/DataStruct.h | 32 +++ src/app/Device.cpp | 135 ++--------- src/app/Device.h | 27 +-- src/app/Policy.cpp | 8 +- src/app/Station.cpp | 96 ++++++-- src/app/Station.h | 14 +- src/protocol/HttpEntity.cpp | 62 ++++- src/protocol/HttpEntity.h | 4 +- src/qt/MainApp.cpp | 129 +++++++---- src/qt/MainApp.h | 16 +- src/qt/MyQUI.cpp | 80 ++++++- src/qt/MyQUI.h | 22 +- src/qt/widgets/QWHome.cpp | 161 +++++++------ src/qt/widgets/QWHome.h | 37 ++- src/qt/widgets/QWMonitor.cpp | 218 ++++++++++++++++++ src/qt/widgets/QWMonitor.h | 51 ++++ 23 files changed, 1000 insertions(+), 334 deletions(-) create mode 100644 bin/Release/assets/config/regaddrsValStr.json diff --git a/bin/Release/assets/config/app.json b/bin/Release/assets/config/app.json index 8b270a7..2de1fdd 100644 --- a/bin/Release/assets/config/app.json +++ b/bin/Release/assets/config/app.json @@ -29,8 +29,9 @@ "Charger_YC": {"deviceType":106, "polling":0, "enabled": 1} }, "view": {"latitude":0,"longitude":0,"altitude":0}, - "video": { - "1":{"host":"", "port":9000, "user":"", "passwd":""} + "video": { + "1":{"host":"", "port":9000, "user":"", "passwd":""} }, - "statistics": {"enabled": 1, "interval": 60} + "statistics": {"enabled": 1, "interval": 60}, + "alert": { "interval":"1800"} } \ No newline at end of file diff --git a/bin/Release/assets/config/regaddrsShow.json b/bin/Release/assets/config/regaddrsShow.json index f81afd0..25f5e39 100644 --- a/bin/Release/assets/config/regaddrsShow.json +++ b/bin/Release/assets/config/regaddrsShow.json @@ -2,6 +2,15 @@ "EMS":{ "deviceType":101, "addrYC":[ + ["BCU总通信状态", "0x2018", "--", ""], + ["PCU总通信状态", "0x2019", "--", ""], + ["电表总通信状态", "0x201A", "--", ""], + ["消防总通信状态", "0x201B", "--", ""], + ["UPS总通信状态", "0x201C", "--", ""], + ["温湿度总通信状态", "0x201D", "--", ""], + ["空调总通信状态", "0x201E", "--", ""], + ["EMU通信状态", "0x201F", "--", ""], + ["冷机总通信状态", "0x2020", "--", ""], ["A相电压", "0x107E", "0.0", " V", "1"], ["A相电流", "0x1084", "0.0", " A"], ["B相电压", "0x1080", "0.0", " V", "1"], @@ -11,7 +20,18 @@ ["总有功功率", "0x1096", "0.0", " kW"] ], - "addrCurve": ["0x107E", "0x1084", "0x1096"] + "addrCurve": ["0x107E", "0x1084", "0x1096"], + "valstr": { + "0x2018": {"0":"正常", "1":"告警", "2":"故障"}, + "0x2019": {"0":"正常", "1":"告警", "2":"故障"}, + "0x201A": {"0":"正常", "1":"告警", "2":"故障"}, + "0x201B": {"0":"正常", "1":"告警", "2":"故障"}, + "0x201C": {"0":"正常", "1":"告警", "2":"故障"}, + "0x201D": {"0":"正常", "1":"告警", "2":"故障"}, + "0x201E": {"0":"正常", "1":"告警", "2":"故障"}, + "0x201F": {"0":"正常", "1":"告警", "2":"故障"}, + "0x2020": {"0":"正常", "1":"告警", "2":"故障"} + } }, "PCS":{ "deviceType":102, @@ -26,7 +46,11 @@ ["C相电流", "0x001B", "0.0", " A"], ["总有功功率", "0x0025", "0.0", " kW"] ], - "addrCurve": ["0x0010", "0x0019", "0x0025"] + "addrCurve": ["0x0010", "0x0019", "0x0025"], + "valstr": { + "0x1009": {"0":"待机","1":"充电","2":"放电","3":"搁置"}, + "0x100A": {"1":"离网","0":"并网"} + } }, "PCU":{ "deviceType":103, @@ -43,7 +67,11 @@ ["C相电流", "0x001E", "0.0", " A"], ["总有功功率", "0x0028", "0.0", " kW"] ], - "addrCurve": ["0x0013", "0x001C", "0x0028"] + "addrCurve": ["0x0013", "0x001C", "0x0028"], + "valstr": { + "0x1007": {"1":"离网","0":"并网"}, + "0x1008": {"1":"开机","0":"关机"} + } }, "BMS":{ "deviceType":104, @@ -59,7 +87,10 @@ ["单体最大温度", "0x0029", "0.0", " ℃", "0.1"], ["单体最小温度", "0x002C", "0.0", " ℃", "0.1"] ], - "addrCurve": ["0x0003", "0x0005", ""] + "addrCurve": ["0x0003", "0x0005", ""], + "valstr": { + "0x004A": {"0":"待机","1":"充电","2":"放电"} + } }, "BCU":{ "deviceType":105, @@ -73,7 +104,11 @@ ["簇电压", "0x0003", "0.0", " V", "0.1"], ["簇电流", "0x0005", "0", " A", "0.1"] ], - "addrCurve": ["0x0003", "0x0005", ""] + "addrCurve": ["0x0003", "0x0005", ""], + "valstr": { + "0xA003": {"17":"开路","34":"待机","51":"充电","68":"放电"}, + "0xA004": {"17":"跳机","34":"待机","51":"放空","68":"充满","85":"预警","102":"正常"} + } }, "MEM":{ "deviceType":3, diff --git a/bin/Release/assets/config/regaddrsValStr.json b/bin/Release/assets/config/regaddrsValStr.json new file mode 100644 index 0000000..b0b3d35 --- /dev/null +++ b/bin/Release/assets/config/regaddrsValStr.json @@ -0,0 +1,47 @@ +[ + { + "name": "EMS", + "devicetype": 101, + "valstr": [ + {"addr": "0x2018", "val": {"0":"正常", "1":"告警", "2":"故障"}}, + {"addr": "0x2019", "val": {"0":"正常", "1":"告警", "2":"故障"}}, + {"addr": "0x201A", "val": {"0":"正常", "1":"告警", "2":"故障"}}, + {"addr": "0x201A", "val": {"0":"正常", "1":"告警", "2":"故障"}}, + ] + }, + { + "name": "PCS", + "devicetype": 102, + "valstr": [ + {""} + ] + }, + { + "name": "PCU", + "devicetype": 103, + "valstr": [ + {} + ] + }, + { + "name": "BMS", + "devicetype": 104, + "valstr": [ + {} + ] + }, + { + "name": "BCU", + "devicetype": 105, + "valstr": [ + {} + ] + }, + { + "name": "CHARGER", + "devicetype": 106, + "valstr": [ + {} + ] + }, +] \ No newline at end of file diff --git a/src/app/AppData.cpp b/src/app/AppData.cpp index 29c3b92..3151769 100644 --- a/src/app/AppData.cpp +++ b/src/app/AppData.cpp @@ -149,10 +149,7 @@ bool AppData::initFromDB() for (auto& fields: result) { auto policy = std::make_shared(); - policy->policyId = fields.get(DMPolicy::POLICY_ID); - policy->type = fields.get(DMPolicy::TYPE); - policy->name = fields.value(DMPolicy::NAME); - policy->value = fields.value(DMPolicy::VALUE); + policy->setFields(fields); this->mapPolicy[policy->policyId] = policy; } } @@ -452,13 +449,23 @@ std::vector AppData::getPolicyNames() return vec; } -int AppData::getPolicyTypeId(std::string name) +std::shared_ptr AppData::getPolicyByType(int typeId) { - for (auto iter = mapPolicyType.begin(); iter != mapPolicyType.end(); ++iter) + for (auto iter = mapPolicy.begin(); iter != mapPolicy.end(); ++iter) { - if (iter->second == name) { return iter->first; } + if (iter->second->type == typeId) { return iter->second; } } - return 0; + return nullptr; +} + +std::shared_ptr AppData::getPolicyById(int policyId) +{ + auto iter = mapPolicy.find(policyId); + if (iter != mapPolicy.end()) + { + return iter->second; + } + return nullptr; } diff --git a/src/app/AppData.h b/src/app/AppData.h index 09a1f35..0ef3ae6 100644 --- a/src/app/AppData.h +++ b/src/app/AppData.h @@ -95,9 +95,11 @@ public: std::vector getPolicyTypeNames(); // 获取策略名称 std::vector getPolicyNames(); - // 根据策略类型ID获取策略类型名称 - // 根据策略类型名称获取策略类型ID - int getPolicyTypeId(std::string name); + // 根据策略类型ID获取策略信息 + std::shared_ptr getPolicyByType(int typeId); + + std::shared_ptr getPolicyById(int policyId); + //std::vector getElectPreiodVals(int month); //std::string getElectPreiodVal(int month, int hour); @@ -158,8 +160,6 @@ public: // 策略信息 std::unordered_map> mapPolicy; - - std::map mapDataDay; }; diff --git a/src/app/Application.cpp b/src/app/Application.cpp index a516b09..e844e73 100644 --- a/src/app/Application.cpp +++ b/src/app/Application.cpp @@ -25,7 +25,7 @@ void Application::init() // MQTT 数据结构 REGAddr::load("assets/config/regaddrs.json"); // 设备读取寄存器的地址定义 - Device::loadParamAddr("assets/config/regaddrsShow.json"); + REGAddr::loadParamAddr("assets/config/regaddrsShow.json"); // 设置数据库配置 DaoEntity::setOption(Config::option.database.host, diff --git a/src/app/DataStruct.cpp b/src/app/DataStruct.cpp index 9ba79e7..b932d29 100644 --- a/src/app/DataStruct.cpp +++ b/src/app/DataStruct.cpp @@ -2,8 +2,33 @@ #include "common/JsonN.h" #include "common/Utils.h" +static map g_mapTopicDeviceType = +{ + {"EMS_YT", 101}, {"EMS_YX", 101}, {"EMS_YC", 101}, + {"PCU_YC", 103}, {"PCU_YX", 103}, + {"PCS_YC", 102}, {"PCS_YX", 102}, + {"BMS_YC", 104}, + {"BCU_YC", 105}, {"BCU_YX", 105}, + {"MEM_YC", 3}, + {"TH_YC", 10}, + {"Fire40_YX", 7}, + {"Cooling_YC", 14}, + {"Cooling_YX", 14}, + {"Gateway_YC", 15}, + {"Gateway_YX", 15}, + {"Charger_YC", 106} +}; + +// key: tpoic, 子key: addr std::map> REGAddr::s_mapReg; +std::map> REGAddr::s_mapDeviceAddrParam; +std::map> REGAddr::s_mapDeviceAddrCurve; +std::map>> REGAddr::g_mapRegAddrValStr; + +// key: 设备类型, 子key: addr +std::map> REGAddr::g_mapRegDeviceType; + void REGAddr::load(std::string filename) { njson json; @@ -12,7 +37,9 @@ void REGAddr::load(std::string filename) // 遍历 JSON 对象 for (auto& jsonitem : json.items()) { - std::string name = jsonitem.key(); + std::string name = jsonitem.key(); // topic名称 + int deviceType = g_mapTopicDeviceType[name]; + auto& jsonnodeItem = jsonitem.value(); //int count = jsonnodeItem["count"]; auto jsonaddrs = jsonnodeItem["addr"]; @@ -28,12 +55,68 @@ void REGAddr::load(std::string filename) std::string remark = JSON::read(item, "remark"); std::string name = JSON::read(item, "name"); int alert = JSON::read(item, "alert"); - mapItem[addr] = RegAddrUnit(addr, datatype, alert, name, remark); + g_mapRegDeviceType[deviceType][addr] = mapItem[addr] = RegAddrUnit(addr, datatype, alert, name, remark); } } } } + +void REGAddr::loadParamAddr(std::string filename) +{ + try + { + njson json; + if (!JSON::load(filename, json)) + { + spdlog::error("[device] json load param addr error, filename={}", filename); + } + for (auto& jsonitem : json.items()) + { + std::string key = jsonitem.key(); + auto& jsonnodeItem = jsonitem.value(); + + int deviceType = jsonnodeItem["deviceType"]; + auto& vec = s_mapDeviceAddrParam[deviceType]; + for (auto& v : jsonnodeItem["addrYC"]) + { + std::string name = JSON::get(v[0]); + std::string addr = JSON::get(v[1]); + std::string defaultVal = JSON::get(v[2]); + std::string unit = JSON::get(v[3]); + float ratio = Utils::toFloat(JSON::get(v[4])); + vec.push_back(DeviceParamAddr(name, addr, defaultVal, unit, ratio)); + } + if (jsonnodeItem.contains("addrCurve")) + { + auto& vec = s_mapDeviceAddrCurve[deviceType]; + for (auto& v : jsonnodeItem["addrCurve"]) + { + vec.push_back(v.get()); + } + } + if (jsonnodeItem.contains("valstr")) + { + auto& mapDT = g_mapRegAddrValStr[deviceType]; + for (auto& itemaddr : jsonnodeItem["valstr"].items()) + { + string addr = itemaddr.key(); + auto& mapAddr = mapDT[addr]; + for (auto& itemval: itemaddr.value().items()) + { + string key = itemval.key(); + mapAddr[key] = itemval.value().get(); + } + } + } + } + } + catch (nlohmann::json::parse_error& e) + { + spdlog::error("[device] parse [{}] error: ", filename, e.what()); + } +} + std::map* REGAddr::getRegMap(std::string name) { auto iter = s_mapReg.find(name); @@ -42,4 +125,25 @@ std::map* REGAddr::getRegMap(std::string name) return &(iter->second); } return nullptr; +} + +std::map* REGAddr::getRegMapByDeviceType(int deviceType) +{ + auto iter = g_mapRegDeviceType.find(deviceType); + if (iter != g_mapRegDeviceType.end()) + { + return &(iter->second); + } + return nullptr; +} + +std::vector& REGAddr::GetDeviceParamAddrs(int deviceType) +{ + static std::vector vecAddrs = {}; + auto iter = s_mapDeviceAddrParam.find(deviceType); + if (iter != s_mapDeviceAddrParam.end()) + { + return iter->second; + } + return vecAddrs; } \ No newline at end of file diff --git a/src/app/DataStruct.h b/src/app/DataStruct.h index 701fc23..daa02ab 100644 --- a/src/app/DataStruct.h +++ b/src/app/DataStruct.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include enum class EAlertType { @@ -56,12 +57,43 @@ struct RegAddrUnit } }; + +// 需要在前端展示的设备参数 +struct DeviceParamAddr +{ + std::string name; + std::string addr; + std::string defaultVal; + std::string unit; + float ratio {1.0}; + DeviceParamAddr() {}; + DeviceParamAddr(std::string name, std::string addr, std::string defaultVal, std::string unit, float ratio = 1.0f) + : name(name), addr(addr), defaultVal(defaultVal), unit(unit), ratio(ratio) + { + if (this->ratio == 0.0) + { + this->ratio = 1.0f; + } + }; +}; + class REGAddr { public: + // key: 寄存器地址 static std::map> s_mapReg; + static std::map> s_mapDeviceAddrParam; + static std::map> s_mapDeviceAddrCurve; + static std::map>> g_mapRegAddrValStr; + static std::map> g_mapRegDeviceType; + static void load(std::string filename); + static void loadParamAddr(std::string filename); static std::map* getRegMap(std::string name); + + static std::map* getRegMapByDeviceType(int deviceType); + + static std::vector& GetDeviceParamAddrs(int deviceType); }; \ No newline at end of file diff --git a/src/app/Device.cpp b/src/app/Device.cpp index cccb8a9..8ea6aeb 100644 --- a/src/app/Device.cpp +++ b/src/app/Device.cpp @@ -7,19 +7,8 @@ #include "app/DataStruct.h" #include -std::map> Device::s_mapDeviceAddrParam; -std::map> Device::s_mapDeviceAddrCurve; -static std::vector& GetDeviceParamAddrs(int deviceType) -{ - static std::vector vecAddrs = {}; - auto iter = Device::s_mapDeviceAddrParam.find(deviceType); - if (iter != Device::s_mapDeviceAddrParam.end()) - { - return iter->second; - } - return vecAddrs; -} + static std::unordered_set g_setCacheDeviceType = {3, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110}; static bool CheckCacheType(int type) @@ -35,46 +24,6 @@ std::shared_ptr Device::create(Fields& fields) } -void Device::loadParamAddr(std::string filename) -{ - try - { - njson json; - if (!JSON::load(filename, json)) - { - spdlog::error("[device] json load param addr error, filename={}", filename); - } - for (auto& jsonitem : json.items()) - { - std::string key = jsonitem.key(); - auto& jsonnodeItem = jsonitem.value(); - - int type = jsonnodeItem["deviceType"]; - auto& vec = s_mapDeviceAddrParam[type]; - for (auto& v : jsonnodeItem["addrYC"]) - { - std::string name = JSON::get(v[0]); - std::string addr = JSON::get(v[1]); - std::string defaultVal = JSON::get(v[2]); - std::string unit = JSON::get(v[3]); - float ratio = Utils::toFloat(JSON::get(v[4])); - vec.push_back(DeviceParamAddr(name, addr, defaultVal, unit, ratio)); - } - if (jsonnodeItem.contains("addrCurve")) - { - auto& vec = s_mapDeviceAddrCurve[type]; - for (auto& v : jsonnodeItem["addrCurve"]) - { - vec.push_back(v.get()); - } - } - } - } - catch (nlohmann::json::parse_error& e) - { - spdlog::error("[device] parse [{}] error: ", filename, e.what()); - } -} static const int BCU_UNIT_SIZE = 256; @@ -119,7 +68,7 @@ void Device::setFields(Fields& fields) } } - auto& vecAddrs = GetDeviceParamAddrs(this->type); + auto& vecAddrs = REGAddr::GetDeviceParamAddrs(this->type); for (auto& item: vecAddrs) { this->mapMyParams[item.addr] = &item; @@ -224,8 +173,8 @@ bool Device::cache(int npos) std::string addrV; std::string addrI; std::string addrP; - auto iter = s_mapDeviceAddrCurve.find(this->type); - if (iter != s_mapDeviceAddrCurve.end()) + auto iter = REGAddr::s_mapDeviceAddrCurve.find(this->type); + if (iter != REGAddr::s_mapDeviceAddrCurve.end()) { auto& vecAddr = iter->second; auto size = vecAddr.size(); @@ -340,79 +289,23 @@ std::string Device::getParam(std::string k, std::string defaultVal) return defaultVal; } +static map> g_mapAddrValStr = +{ + +}; + void Device::getRuntimeParams(std::vector>& params) { - // 3 电表 - // 101 EMS - // 102 PCS - // 103 PCU - // 104 BMS - // 105 BCU - // 106 充电桩 - // 109 光伏板 - auto& vecAddr = s_mapDeviceAddrParam[this->type]; + auto& vecAddr = REGAddr::s_mapDeviceAddrParam[this->type]; for (auto& item: vecAddr) { std::string v = getParam(item.addr, item.defaultVal); - if (type == int(EDeviceType::BCU) ) + auto& mapValStr = REGAddr::g_mapRegAddrValStr[type][item.addr]; + auto iter = mapValStr.find(v); + if (iter != mapValStr.end()) { - if (item.addr == "0xA003") //"0x11开路,0x22待机,0x33充电,0x44放电" - { - if (v == "17") v = "开路"; - else if (v == "34") v = "待机"; - else if (v == "51") v = "充电"; - else if (v == "68") v = "放电"; - } - else if (item.addr == "0xA004") //"0x11跳机 ,0x22待机,0x33放空,0x44充满,0x55预警,0x66正常" - { - if (v == "17") v = "跳机"; - else if (v == "34") v = "待机"; - else if (v == "51") v = "放空"; - else if (v == "68") v = "充满"; - else if (v == "85") v = "预警"; - else if (v == "102") v = "正常"; - } + v = iter->second; } - else if (type == int(EDeviceType::BMS)) - { - if (item.addr == "0x004A") // 0-待机 1-充电 2-放电 - { - if (v == "0") v = "待机"; - else if (v == "1") v = "充电"; - else if (v == "2") v = "放电"; - } - } - else if (type == int(EDeviceType::PCU)) - { - if (item.addr == "0x1007") // 电网状态 R uint16 1离网,0并网 0x1007 - { - if (v == "0") v = "并网"; - else if (v == "1") v = "离网"; - } - if (item.addr == "0x1006") // 启停状态 R uint16 1开机,0关机 0x1008 - { - if (v == "1") v = "开机"; - else if (v == "0") v = "关机"; - } - } - else if (type == int(EDeviceType::PCS)) - { - if (item.addr == "0x1009") //充放状态 R uint16 0:待机, 1:充电, 2:放电, 3:搁置 0x1009 - { - if (v == "0") v = "待机"; - else if (v == "1") v = "充电"; - else if (v == "2") v = "放电"; - else if (v == "3") v = "搁置"; - } - else if (item.addr == "0x100A") //电网状态 R uint16 1离网,0并网 0x100A - { - if (v == "0") v = "并网"; - else if (v == "1") v = "离网"; - } - } - - //if (this->online) { } - //else { v = "--"; } params.push_back({item.name, v + item.unit}); } } diff --git a/src/app/Device.h b/src/app/Device.h index 82e5586..ba640ea 100644 --- a/src/app/Device.h +++ b/src/app/Device.h @@ -8,33 +8,14 @@ #include #include "common/Fields.h" +#include "app/DataStruct.h" class CommEntity; -// 需要在前端展示的设备参数 -struct DeviceParamAddr -{ - std::string name; - std::string addr; - std::string defaultVal; - std::string unit; - float ratio {1.0}; - DeviceParamAddr() {}; - DeviceParamAddr(std::string name, std::string addr, std::string defaultVal, std::string unit, float ratio=1.0f) - : name(name), addr(addr), defaultVal(defaultVal), unit(unit), ratio(ratio) - { - if (this->ratio == 0.0) - { - this->ratio = 1.0f; - } - }; -}; - class Device { public: static std::shared_ptr create(Fields& fields); - static void loadParamAddr(std::string filename); Device(); @@ -61,8 +42,7 @@ public: void setBCUUnit(std::string k, int pos, int v, int count); public: - static std::map> s_mapDeviceAddrParam; - static std::map> s_mapDeviceAddrCurve; + int stationId = {0}; int deviceId = {0}; @@ -90,8 +70,11 @@ public: std::map mapCacheVoltage; std::map mapCacheCurrent; std::map mapCachePower; + + // 参数值(保存从设备读取的参数值) std::map mapParams; + // 参数定义(定义参数的基础信息,包括寄存器地址,名称,单位,倍率) std::map mapMyParams; std::vector> vecBCUUnit; diff --git a/src/app/Policy.cpp b/src/app/Policy.cpp index 5a88460..0febba8 100644 --- a/src/app/Policy.cpp +++ b/src/app/Policy.cpp @@ -5,8 +5,8 @@ void SysPolicy::setFields(Fields& fields) { this->policyId = fields.get("policy_id"); - this->type = fields.get("policy_type"); - this->name = fields.value("policy_name"); + this->type = fields.get("type"); // policy_type + this->name = fields.value("name"); // policy_name this->value = fields.value("value"); this->parseValue(value); @@ -146,6 +146,7 @@ void SysPolicy::getGatewayJsonPeriods(njson& json) { if (vecPeriods1.size()>0) { + njson jsonArray = njson::array(); for (auto& item: vecPeriods1[0]) { int h = 0; int m = 0; @@ -156,8 +157,9 @@ void SysPolicy::getGatewayJsonPeriods(njson& json) else if (item.second == "峰") p = 3; else if (item.second == "尖") p = 4; else p = 0; - json.push_back({h, m, p}); + jsonArray.push_back({h, m, p}); } + json.push_back(jsonArray); } } } \ No newline at end of file diff --git a/src/app/Station.cpp b/src/app/Station.cpp index 8ded1d9..14f642e 100644 --- a/src/app/Station.cpp +++ b/src/app/Station.cpp @@ -10,6 +10,7 @@ #include "app/Config.h" #include "common/Snowflake.h" #include "app/DataStruct.h" +#include "app/Application.h" Station::Station() : stationId(0) { @@ -27,7 +28,7 @@ void Station::setFields(Fields& fields) this->operationDate = fields.value(DMStation::OPERATION_DATE); this->launchDate = fields.value("operation_date"); - this->policy.setFields(fields); + //this->policy.setFields(fields); } void Station::addDevice(int deviceId, std::shared_ptr device) @@ -133,17 +134,7 @@ void Station::setWorkMode(int modeId) } } -void Station::setPolicy(int policyId) -{ - std::string sql = SQL(SQL::TYPE::update).table(DMStation::TABLENAME) - .update(DMStation::POLICY_ID, std::to_string(policyId)) - .where(DMStation::STATION_ID + "=" + std::to_string(stationId)).str(); - Errcode err = DAO::exec(NULL, sql); - if (err != Errcode::OK) - { - spdlog::error("set station policy failed."); - } -} + void Station::initMqtt() { @@ -181,23 +172,30 @@ void Station::setGarewayWorkMode() { return; } + auto policy = Application::data().getPolicyByType(this->workMode); njson json; json["ts"] = Utils::time(); json["no"] = 1; // 设备编号 json["40001"] = this->workMode; - if (policy.type == 1) + if (policy) { - json["40002"] = njson::array(); // 峰谷套利 - policy.getGatewayJsonPeriods(json["40002"]); - } - else if (policy.type == 5) - { - json["40021"] = njson::array(); // 自定时段 - policy.getGatewayJsonPeriods(json["40021"]); + if (policy->type == 1) + { + json["40002"] = njson::array(); // 峰谷套利 + policy->getGatewayJsonPeriods(json["40002"]); + } + else if (policy->type == 5) + { + json["40021"] = njson::array(); // 自定时段 + policy->getGatewayJsonPeriods(json["40021"]); + } } + json["40038"] = {gatewayParam.socMin, gatewayParam.socMax, gatewayParam.capacity, gatewayParam.powerSafe, gatewayParam.powerDischarge, gatewayParam.powerCharge}; + json["40058"] = {gatewayParam.backflow, gatewayParam.overload}; + std::string text = json.dump(); spdlog::info(text); mqttCli->publish("Gateway_YT", text); @@ -229,7 +227,6 @@ string Station::getGatewayParam() { stringstream ss; std::string str1 = "峰谷套利时段:
"; - std::string str2 = "自定时段:
"; { njson json; if (JSON::parse(gatewayParam.param1, json)) @@ -249,6 +246,7 @@ string Station::getGatewayParam() } } } + std::string str2 = "自定时段:
"; { njson json; if (JSON::parse(gatewayParam.param2, json)) @@ -267,7 +265,35 @@ string Station::getGatewayParam() } } } - return str1 + "
" + str2; + std::string str3 = "其它参数:
"; + { + njson json; + if (JSON::parse(gatewayParam.param3, json)) + { + for (int i = 0; i(); + if (i==0) { str3 += "    储能放电下限值SOC: " + std::to_string(val) + "
"; } //储能放电下限值 SOC : 40038 (%:0-99 且小于充电上限值) + else if (i==1) { str3 += "    储能充电上限值SOC: " + std::to_string(val) + "
"; }//储能充电上限值 SOC : 40039 (%:1-100 且大于放电下限值) + else if (i==2) { str3 += "    台区变压器容量: " + std::to_string(val) + "
"; }//台区变压器容量 : 40040 (KVVA 160-1600) + else if (i==3) { str3 += "    安全输入功率: " + std::to_string(val) + "
"; }//安全输入功率 : 40041 (KW 0-400) + else if (i==4) { str3 += "    储能最大放电功率: " + std::to_string(val) + "
"; }//储能最大放电功率 : 40042 (1KW0-150) + else if (i==5) { str3 += "    储能最大充电功率: " + std::to_string(val) + "
"; }//储能最大充电功率::40043 (1KW0-150) + else if (i==6) { str3 += "    运行状态: " + std::to_string(val) + "
"; }//运行状态 : 40044 (只读不写,0:无 1:高峰放电 2:低谷充电) + else if (i==7) { str3 += "    台区电表变比: " + std::to_string(val) + "
"; }//台区电表变比:40045 + //else if (i==8) { str3 += "    对时(年): " + std::to_string(val) + "
"; }//对时(年) : 40051 + //else if (i==9) { str3 += "    对时(月): " + std::to_string(val) + "
"; }//对时(月) : 40052 + //else if (i==10) { str3 += "    对时(日): " + std::to_string(val) + "
"; }//对时(日) : 40053 + //else if (i==11) { str3 += "    对时(时): " + std::to_string(val) + "
"; }//对时(时) : 40054 + //else if (i==12) { str3 += "    对时(分): " + std::to_string(val) + "
"; }//对时(分) : 40055 + //else if (i==13) { str3 += "    对时(秒): " + std::to_string(val) + "
"; }//对时(秒) : 40056 + //else if (i==19) { str3 += "    时间段月份: " + std::to_string(val) + "
"; }//时间段月份 : 40057(1-12 对应1月-12月) + else if (i==20) { str3 += "    防逆流回差: " + std::to_string(val) + "
"; }//防逆流回差 : 40058(1KW 10-300) + else if (i==21) { str3 += "    防过载回差: " + std::to_string(val) + "
"; }//防过载回差 : 40059(1KW 10-300) + } + } + } + return str1 + "
" + str2 + "
" + str3; } void Station::checkDevice() @@ -290,7 +316,7 @@ void Station::readAlert(std::shared_ptr device, std::string addr, int v, int64_t ts = Utils::time(); std::string alertId = std::to_string(device->deviceId) + "_" + addr; int tsCache = mapAlertCache[alertId]; - if (ts - tsCache > 60*5) + if (ts - tsCache > 60*30) { Fields fields; fields.set("log_id", Snowflake::instance().getIdStr()); @@ -419,6 +445,14 @@ void Station::readCoolingData(int deviceNo, string addr, int val) else if (addr == "0x100E") { ; }// 出水压力传感器 R uint16 0:正常,1:告警 0x100E } +static void JSONReadArrayItem(njson& json, int i, int& v) +{ + if (json.is_array() && i < json.size()) + { + v = json[i].get(); + } +} + void Station::readGatewayMode(int mode, string p1, string p2, string p3) { this->gatewayParam.mode = mode; @@ -429,6 +463,22 @@ void Station::readGatewayMode(int mode, string p1, string p2, string p3) { //this->setGarewayWorkMode(); } + + + njson json; + if (JSON::parse(gatewayParam.param3, json)) + { + JSONReadArrayItem(json, 0, gatewayParam.socMin); //储能放电下限值 SOC : 40038 (%:0-99 且小于充电上限值) + JSONReadArrayItem(json, 1, gatewayParam.socMax); //储能充电上限值 SOC : 40039 (%:1-100 且大于放电下限值) + JSONReadArrayItem(json, 2, gatewayParam.capacity); //台区变压器容量 : 40040 (KVVA 160-1600) + JSONReadArrayItem(json, 3, gatewayParam.powerSafe); //安全输入功率 : 40041 (KW 0-400) + JSONReadArrayItem(json, 4, gatewayParam.powerDischarge); //储能最大放电功率 : 40042 (1KW0-150) + JSONReadArrayItem(json, 5, gatewayParam.powerCharge); //储能最大充电功率::40043 (1KW0-150) + JSONReadArrayItem(json, 6, gatewayParam.status); //运行状态 : 40044 (只读不写,0:无 1:高峰放电 2:低谷充电) + JSONReadArrayItem(json, 7, gatewayParam.vtRatio); //台区电表变比:40045 + JSONReadArrayItem(json, 20, gatewayParam.backflow); //防逆流回差 : 40058(1KW 10-300) + JSONReadArrayItem(json, 21, gatewayParam.overload); //防过载回差 : 40059(1KW 10-300) + } } void Station::readGatewayStatus(int cdzStatus, int emuStatus) diff --git a/src/app/Station.h b/src/app/Station.h index 30d72c6..0b82854 100644 --- a/src/app/Station.h +++ b/src/app/Station.h @@ -107,7 +107,6 @@ public: void getDeviceByCategory(int category, std::vector>& res); void setWorkMode(int modeId); - void setPolicy(int policyId); void initMqtt(); void polling(); @@ -139,7 +138,7 @@ public: std::string code; int status {0}; std::string operationDate; - SysPolicy policy; + //SysPolicy policy; std::string launchDate {}; bool isConnected {false}; @@ -153,6 +152,17 @@ public: std::string param1; std::string param2; std::string param3; + + int socMin {}; // 储能放电下限值 SOC 40038 (%, 0-99) + int socMax {}; // 储能充电上限值 SOC 40039 (%:1-100) + int capacity {}; // 台区变压器容量 40040 (KVA 160-1600) + int powerSafe {}; // 安全输入功率 40041 (KW 0-400) + int powerDischarge {}; // 储能最大放电功率 40042 (1KW 0-150) + int powerCharge {}; // 储能最大充电功率 40043 (1KW 0-150) + int status {}; // 运行状态:40044 (只读不写,0:无 1:高峰放电 2:低谷充电) + int vtRatio ;// 台区电表变比 40045 + int backflow {}; // 防逆流回差 40058(1KW 10-300) + int overload {}; // 防过载回差 40059(1KW 10-300) } gatewayParam; /////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/protocol/HttpEntity.cpp b/src/protocol/HttpEntity.cpp index aa6b352..def9b46 100644 --- a/src/protocol/HttpEntity.cpp +++ b/src/protocol/HttpEntity.cpp @@ -218,6 +218,8 @@ static std::map g_mapHttpHandlerPost {"/insertServiceApi", HandlerOptions(&HttpEntity::insertServiceApi, {})}, {"/updateServiceApi", HandlerOptions(&HttpEntity::updateServiceApi, {"api_id"})}, + + {"/updateGatewayParams", HandlerOptions(&HttpEntity::updateGatewayParams, {DMStation::STATION_ID})}, }; bool CheckHttpToken(const httplib::Request& req) @@ -935,6 +937,14 @@ Errcode HttpEntity::queryDevicByCategory(const httplib::Request& req, njson& jso jsongateway["workmode"] = station->getGatewayMode(); jsongateway["emu"] = station->emuStatus == 1 ? "在线" : (station->emuStatus == 0 ? "离线" : "--"); jsongateway["cdz"] = station->cdzStatus == 1 ? "在线" : (station->cdzStatus == 0 ? "离线" : "--"); + jsongateway["soc_min"] = station->gatewayParam.socMin; + jsongateway["soc_max"] = station->gatewayParam.socMax; + jsongateway["capacity"] = station->gatewayParam.capacity; + jsongateway["power_safe"] = station->gatewayParam.powerSafe; + jsongateway["power_discharge"] = station->gatewayParam.powerDischarge; + jsongateway["power_charge"] = station->gatewayParam.powerCharge; + jsongateway["backflow"] = station->gatewayParam.backflow; + jsongateway["overload"] = station->gatewayParam.overload; } json["gateway"] = jsongateway; return Errcode::OK; @@ -981,7 +991,7 @@ Errcode HttpEntity::queryDeviceBCUDetail(const httplib::Request& req, njson& jso auto& row = device->vecBCUUnit[i]; std::string soc = Utils::toStr(row[0], 1); std::string soh = Utils::toStr(row[1], 1); - std::string u = Utils::toStr(row[2], 0); + std::string u = Utils::toStr(row[2], 3); std::string t = Utils::toStr(row[3], 2); std::string r_i = Utils::toStr(row[4], 0); jsondata.push_back({{"SOC", soc}, {"SOH", soh}, {"V", u}, {"T", t}, {"R_i", r_i}}); @@ -1011,8 +1021,18 @@ Errcode HttpEntity::insertPolicy(const httplib::Request& req, njson& json, std:: Errcode HttpEntity::updatePolicy(const httplib::Request& req, njson& json, std::string& errmsg) { Fields params; - GetRequestParams(req, {"policy_id", "type", "describe", "value", "is_open"}, params); - return DAO::updatePolicyById(params); + GetRequestParams(req, {"policy_id", "type", "name", "describe", "value", "is_open"}, params); + auto err = DAO::updatePolicyById(params); + if (err == Errcode::OK) + { + int policyId = params.get("policy_id"); + auto policy = Application::data().getPolicyById(policyId); + if (policy) + { + policy->setFields(params); + } + } + return err; }; Errcode HttpEntity::deletePolicy(const httplib::Request& req, njson& json, std::string& errmsg) { @@ -1625,4 +1645,40 @@ Errcode HttpEntity::deleteServiceApi(const httplib::Request& req, njson& json, s Fields params; GetRequestParams(req, {"api_id"}, params); return DAO::remove(NULL, "serviceapi", "api_id", params.value("api_id")); +} + +Errcode HttpEntity::updateGatewayParams(const httplib::Request& req, njson& json, std::string& errmsg) +{ + //上下限SOC,安全输入功率,储能最大充放电功率,防逆流防过载回差。 + Fields params; + GetRequestParams(req, {"station_id", "work_mode", "soc_min", "soc_max", "capacity", "power_safe", "power_discharge", "power_charge", "backflow", "overload"}, params); + + int stationId = params.get("station_id"); + auto station = Application::data().getStation(stationId); + + if (params.contains("work_mode")) + { + int workMode = params.get("work_mode"); + Fields fields; + fields.set("station_id", params.value("station_id")); + fields.set("work_mode", workMode); + Errcode err = DAO::updateStationById(params); + } + + if (station) + { + params.get("work_mode", station->workMode); + params.get("soc_min", station->gatewayParam.socMin); // 储能放电下限值 SOC 40038 (%, 0-99) + params.get("soc_max", station->gatewayParam.socMax); // 储能充电上限值 SOC 40039 (%:1-100) + params.get("capacity", station->gatewayParam.capacity); // 台区变压器容量 40040 (KVA 160-1600) + params.get("power_safe", station->gatewayParam.powerSafe); // 安全输入功率 40041 (KW 0-400) + params.get("power_discharge", station->gatewayParam.powerDischarge); // 储能最大放电功率 40042 (1KW 0-150) + params.get("power_charge", station->gatewayParam.powerCharge); // 储能最大充电功率 40043 (1KW 0-150) + params.get("backflow", station->gatewayParam.backflow); // 防逆流回差 40058(1KW 10-300) + params.get("overload", station->gatewayParam.overload); // 防过载回差 40059(1KW 10-300) + + station->setGarewayWorkMode(); + return Errcode::OK; + } + return Errcode::ERR_PARAM; } \ No newline at end of file diff --git a/src/protocol/HttpEntity.h b/src/protocol/HttpEntity.h index 2c60208..c09fb1f 100644 --- a/src/protocol/HttpEntity.h +++ b/src/protocol/HttpEntity.h @@ -99,7 +99,7 @@ public: // 场站按类某一天的历史曲线数据 Errcode queryStatCharts(const httplib::Request& req, njson& json, std::string& errmsg); - Errcode exportStatReport(const httplib::Request& req, njson& json, std::string& errmsg); + Errcode exportStatReport(const httplib::Request& req, njson& json, std::string& errmsg); Errcode queryEnvironment(const httplib::Request& req, njson& json, std::string& errmsg); @@ -107,4 +107,6 @@ public: Errcode insertServiceApi(const httplib::Request& req, njson& json, std::string& errmsg); Errcode updateServiceApi(const httplib::Request& req, njson& json, std::string& errmsg); Errcode deleteServiceApi(const httplib::Request& req, njson& json, std::string& errmsg); + + Errcode updateGatewayParams(const httplib::Request& req, njson& json, std::string& errmsg); }; \ No newline at end of file diff --git a/src/qt/MainApp.cpp b/src/qt/MainApp.cpp index b74d608..8f64e1d 100644 --- a/src/qt/MainApp.cpp +++ b/src/qt/MainApp.cpp @@ -11,7 +11,6 @@ #include "protocol/MqttEntity.h" - MainApp::MainApp() { QPalette palette(this->palette()); @@ -32,58 +31,75 @@ MainApp::MainApp() //ui.weburl->setTitle("页面地址:"); //ui.weburl->setValue("http://www.baidu.com"); + this->initMenu(); this->setMyLayout(); + this->onActiveMenu("系统总览"); timer = std::make_shared(this); connect(timer.get(), &QTimer::timeout, this, &MainApp::onTimer); timer->start(1000); // 每隔1000毫秒更新一次 } - - -class MyMenu : public QWidget +void MainApp::initMenu() { -public: - MyMenu(QWidget* parent) : QWidget(parent), layout(this) + ui.widgetMenu = std::make_shared(this); + ui.widgetMenu->setObjectName("menu"); + ui.widgetMenu->setStyleSheet("#menu { background-color:rgba(120,120,120,80); border-radius:5px; }"); + ui.widgetMenu->show(); + ui.vecMenuItems.reserve(20); + + ui.layoutMenu = std::make_shared(ui.widgetMenu.get()); + ui.layoutMenu->setSpacing(2); + ui.layoutMenu->setContentsMargins(2, 2, 2, 2); + + ui.labelDT = std::make_shared< QLabel>(); + ui.labelDT->setAlignment(Qt::AlignCenter); + ui.labelDT->setText(Utils::timeStr().c_str()); + ui.layoutMenu->addWidget(ui.labelDT.get(), 0, 0, 1, 1); + // 设置列宽和行高 + ui.layoutMenu->setRowMinimumHeight(0, 40); // 设置第0列的最小宽度为100像素 + // 设置列和行的伸缩因子 + ui.layoutMenu->setRowStretch(0, 0); // 设置第0列的伸缩因子为0,不伸缩 + + std::vector menuItems = {"系统总览", "运行监控"}; + for (auto& name: menuItems) { - this->setObjectName("menu"); - this->setStyleSheet("#menu { background-color:rgba(120,120,120,80); }"); - this->show(); - vecMenuItems.reserve(20); - layout.setSpacing(2); - layout.setContentsMargins(2, 2, 2, 2); + int row = ui.vecMenuItems.size() + 1; + auto itemBtn = std::make_shared(ui.widgetMenu.get()); + ui.vecMenuItems.push_back(itemBtn); + itemBtn->setText(name.c_str()); + itemBtn->setStyleSheet(QSS_BTN_MENU.c_str()); + if (!ui.curActiveMenuBtn) + { + ui.curActiveMenuBtn = itemBtn; + ui.curActiveMenuBtn->setStyleSheet(QSS_BTN_MENU_ACTIVE.c_str()); + } - this->addMenuItem("系统总览"); - //this->addMenuItem("运行监控"); - } - - void addMenuItem(std::string name) - { - int row = vecMenuItems.size(); - auto item = std::make_shared(this); - vecMenuItems.push_back(item); - item->setText(name.c_str()); - item->setStyleSheet(QSS_BTN_MENU.c_str()); + connect(itemBtn.get(), &QPushButton::clicked, this, [=]() + { + if (ui.curActiveMenuBtn == itemBtn) { return; } + if (ui.curActiveMenuBtn) { ui.curActiveMenuBtn->setStyleSheet(QSS_BTN_MENU.c_str()); } + ui.curActiveMenuBtn = itemBtn; + if (ui.curActiveMenuBtn) + { + ui.curActiveMenuBtn->setStyleSheet(QSS_BTN_MENU_ACTIVE.c_str()); + this->onActiveMenu(name); + } + }); QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - item->setSizePolicy(sizePolicy); - layout.addWidget(item.get(), row, 0, 1, 1); + itemBtn->setSizePolicy(sizePolicy); + ui.layoutMenu->addWidget(itemBtn.get(), row, 0, 1, 1); // 设置列宽和行高 - layout.setRowMinimumHeight(row, 50); // 设置第0列的最小宽度为100像素 + ui.layoutMenu->setRowMinimumHeight(row, 50); // 设置第0列的最小宽度为100像素 // 设置列和行的伸缩因子 - layout.setRowStretch(row, 0); // 设置第0列的伸缩因子为0,不伸缩 - layout.setRowStretch(row+1, 2); // 设置第1列的伸缩因子为2,使其更宽 + ui.layoutMenu->setRowStretch(row, 0); // 设置第0列的伸缩因子为0,不伸缩 + ui.layoutMenu->setRowStretch(row+1, 2); // 设置第1列的伸缩因子为2,使其更宽 } - - std::vector> vecMenuItems; - - QGridLayout layout; -}; - - - + ui.widgetMenu->show(); +} void MainApp::setMyLayout() { @@ -99,15 +115,9 @@ void MainApp::setMyLayout() //layout->setVerticalSpacing(10); // 设置行间距为10像素 //layout->setContentsMargins(10, 10, 10, 10); // 设置内容边距为10像素 - QSizePolicy sizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - MyMenu* menu = new MyMenu(this); - menu->setSizePolicy(sizePolicy); - layout.main->addWidget(menu, 0, 0, 1, 1); - - ui.wigetHome = std::make_shared(this); - ui.wigetHome->setSizePolicy(sizePolicy); - layout.main->addWidget(ui.wigetHome.get(), 0, 1, 1, 1); + ui.widgetMenu->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)); + layout.main->addWidget(ui.widgetMenu.get(), 0, 0, 1, 1); // 设置列宽和行高 layout.main->setColumnMinimumWidth(0, 200); // 设置第0列的最小宽度为100像素 @@ -117,12 +127,39 @@ void MainApp::setMyLayout() layout.main->setColumnStretch(0, 0); // 设置第0列的伸缩因子为0,不伸缩 layout.main->setColumnStretch(1, 2); // 设置第1列的伸缩因子为2,使其更宽 //gridLayout->setRowStretch(0, 1); // 设置第0行的伸缩因子为1 - } +void MainApp::onActiveMenu(std::string name) +{ + //ui.wigetHome->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)); + //layout.main->addWidget(ui.wigetHome.get(), 0, 1, 1, 1); + std::shared_ptr widget {}; + if (name == "系统总览") { widget = (ui.wigetHome ? ui.wigetHome : (ui.wigetHome = make_shared(this))); } + else if (name == "运行监控") { widget = (ui.wigetMonitor ? ui.wigetMonitor : (ui.wigetMonitor = make_shared(this))); } + else { } + if (widget == ui.curActiveWidget) { return; } + if (ui.curActiveWidget) + { + ui.curActiveWidget->hide(); + } + + if (widget) + { + widget->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred)); + widget->show(); + layout.main->addWidget(widget.get(), 0, 1, 1, 1); + //layout.main->replaceWidget(ui.curActiveWidget.get(), widget.get()); + } + + ui.curActiveWidget = widget; +} void MainApp::onTimer() { - ui.wigetHome->onTimer(); + ui.labelDT->setText(Utils::timeStr().c_str()); + if (ui.curActiveWidget && ui.curActiveWidget->isVisible()) + { + ui.curActiveWidget->onTimer(); + } } \ No newline at end of file diff --git a/src/qt/MainApp.h b/src/qt/MainApp.h index a8ce9ba..e843f84 100644 --- a/src/qt/MainApp.h +++ b/src/qt/MainApp.h @@ -14,16 +14,17 @@ using namespace std; #include #include "widgets/QWHome.h" - +#include "widgets/QWMonitor.h" class MainApp : public QWidget { Q_OBJECT public: MainApp(); - + void initMenu(); void setMyLayout(); + void onActiveMenu(std::string name); private slots: void onTimer(); @@ -31,7 +32,18 @@ private slots: public: struct { std::shared_ptr weburl {}; + + + std::shared_ptr labelDT {}; + std::shared_ptr widgetMenu; + std::vector> vecMenuItems; + std::shared_ptr layoutMenu; + std::shared_ptr curActiveMenuBtn; + + std::shared_ptr curActiveWidget = nullptr; std::shared_ptr wigetHome; + std::shared_ptr wigetMonitor; + } ui; struct { diff --git a/src/qt/MyQUI.cpp b/src/qt/MyQUI.cpp index db5eade..62a61fe 100644 --- a/src/qt/MyQUI.cpp +++ b/src/qt/MyQUI.cpp @@ -1,19 +1,66 @@ -#include "MyQUI.h" +#include "MyQUI.h" static const std::string QSS_GROUP = "QGroupBox { border: 1px solid gray; margin-top: 8px; border-radius: 5px;}" "QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; left:10px; margin-left: 0px; padding:0 1px; }"; +static const std::string QSS_BTN = +"QPushButton {background:rgba(80, 80, 80,80);border-radius:5px;border:1px solid gray;color:white;font:bold 13px;}"; + +static const std::string QSS_BTN_ACTIVE = +"QPushButton {background:rgba(80, 80, 80,80);border-radius:5px;border:1px solid green;color:green;font:bold 15px;}"; static const std::string QSS_BTN_MENU = -"QPushButton {background:rgba(50,128,218,200);color:white;border-radius:5px;border:2px solid rgb(10,120,215);font:bold 18px;}" +"QPushButton {background:rgba(19, 35, 71,200);color:white;border-radius:5px;border:2px solid rgb(10,120,215);font:bold 18px;}" "QPushButton:hover {background-color:rgb(32,164,128);}" -"QPushButton:pressed {border-width:3px 0 0 3px;background-color:rgb(1,32,54);border-style:inset;}" +"QPushButton:pressed {border-width:3px 0 0 3px;border-style:inset;}" +"QPushButton:disabled {color:rgb(150,150,150);}"; + +static const std::string QSS_BTN_MENU_ACTIVE = +"QPushButton {background:rgba(32,164,128, 200);color:white;border-radius:5px;border:2px solid rgb(10,120,215);font:bold 18px;}" +"QPushButton:hover {background-color:rgb(32,164,128);}" +"QPushButton:pressed {border-width:3px 0 0 3px;border-style:inset;}" "QPushButton:disabled {color:rgb(150,150,150);}"; static const std::string QSS_LINE = "QLineEdit { background-color: rgb(14, 49, 66); color: #ffffff; border: 1px solid gray; border-radius: 5px; font: bold 13px; }"; +static const std::string QSS_TABLE = // 表格整体样式 +"QTableWidget {" +" background-color: transparent;" // 背景色 +" gridline-color: #C0C0C0;" // 网格线颜色 +" border: 1px solid gray;" // 边框 +" color: white;" // 文字颜色 +"}" +// 表头样式 +"QHeaderView { background-color: rgba(150,150,150,50); }" +"QHeaderView::section {" +" background-color: rgba(120,120,120,0);" // 表头背景 +" padding: 4px;" // 内边距 +" border: 1px solid #505050;" // 边框 +" min-height: 25px;" // 最小高度 +"}" +// 单元格样式 +"QTableWidget::item {" +" padding-left: 5px;" +" border-bottom: 1px solid gray;" // 底部边框 +"}" +// 选中状态 +"QTableWidget::item:selected {" +" background-color: rgba(184, 214, 255, 50);" // 选中背景色 +" color: rgb(220,220,220);" // 选中文字颜色 +"}"; + +MyWidget::MyWidget(QWidget* parent) : QWidget(parent) +{ + // 可以在这里设置样式表,也可以在其他地方设置 + setObjectName("MyWidget"); + setStyleSheet("#MyWidget {background-color:rgba(120,120,120,80); border-radius:5px;}"); + // 确保自动填充背景 + setAutoFillBackground(true); +} + + std::shared_ptr MyQUI::GroupBox(QWidget* parent, int x, int y, int w, int h, std::string title) { auto groupBox = std::make_shared(title.c_str(), parent); @@ -22,14 +69,33 @@ std::shared_ptr MyQUI::GroupBox(QWidget* parent, int x, int y, int w, return groupBox; } -void MyQUI::PairLine(QWidget* parent, int x, int y, string k, string v) +MyPairLabelLine MyQUI::PairLine(QWidget* parent, int x, int y, string k, string v, bool readonly/* = true*/) { - auto key = new QLabel(parent); + shared_ptr key = make_shared(parent); key->setText(k.c_str()); key->setGeometry(x, y, 80, 26); - auto value = new QLineEdit(parent); + shared_ptr value = make_shared(parent); value->setText(v.c_str()); value->setGeometry(x+80, y, 260, 26); value->setStyleSheet(QSS_LINE.c_str()); - value->setReadOnly(true); + value->setReadOnly(readonly); + return {key, value}; +} + +void MyQUI::setTableCell(std::shared_ptr table, int row, int col, std::string text, std::string style /*= ""*/) +{ + if (row >= table->rowCount()) + { + table->insertRow(row); + } + auto item = table->item(row, col); + if (!item) + { + item = new QTableWidgetItem(); + table->setItem(row, col, item); + } + item->setText(text.c_str()); + if (style == "OK") { item->setForeground(QBrush(Qt::green)); } + else if (style == "ERR") { item->setForeground(QBrush(Qt::red)); } + else if (style == "WARN") { item->setForeground(QBrush(Qt::cyan)); } } \ No newline at end of file diff --git a/src/qt/MyQUI.h b/src/qt/MyQUI.h index 70ad6d0..feb498f 100644 --- a/src/qt/MyQUI.h +++ b/src/qt/MyQUI.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include #include @@ -22,13 +22,22 @@ #include +#include #include +#include +#include using namespace std; extern const std::string QSS_GROUP; + +extern const std::string QSS_BTN; +extern const std::string QSS_BTN_ACTIVE; extern const std::string QSS_BTN_MENU; +extern const std::string QSS_BTN_MENU_ACTIVE; extern const std::string QSS_LINE; +extern const std::string QSS_TABLE; + class LabelPair { public: @@ -60,17 +69,20 @@ class MyWidget : public QWidget { Q_OBJECT public: - MyWidget(QWidget* parent) : QWidget(parent) {} - + MyWidget(QWidget* parent); virtual void onTimer() {}; }; +using MyPairLabelLine = pair, shared_ptr>; class MyQUI { public: - static std::shared_ptr GroupBox(QWidget* parent, int x, int y, int w, int h, std::string title); + static shared_ptr GroupBox(QWidget* parent, int x, int y, int w, int h, std::string title); - static void PairLine(QWidget* parent, int x, int y, string k, string v); + static MyPairLabelLine PairLine(QWidget* parent, int x, int y, string k, string v, bool readonly=true); + + static void setTableCell(std::shared_ptr table, int row, int col, std::string text, std::string style = ""); + }; \ No newline at end of file diff --git a/src/qt/widgets/QWHome.cpp b/src/qt/widgets/QWHome.cpp index 37d7e81..7966484 100644 --- a/src/qt/widgets/QWHome.cpp +++ b/src/qt/widgets/QWHome.cpp @@ -7,12 +7,16 @@ #include "app/Station.h" #include "protocol/MqttEntity.h" + + + + QWHome::QWHome(QWidget* parent) : MyWidget(parent) { - this->setObjectName("workspace"); - this->setStyleSheet("#workspace { background-color:rgba(100,100,100,50); }"); + this->setObjectName("home"); + this->setStyleSheet("#home { background-color:rgba(100,100,100,50); }"); - int x = 10, y = 10; + int x = 10, y = 0; { this->groupSys = MyQUI::GroupBox(this, x, y, 1190, 120, "系统"); auto pw = groupSys.get(); @@ -21,54 +25,29 @@ QWHome::QWHome(QWidget* parent) : MyWidget(parent) x = 10, y += 130; this->groupHttp = MyQUI::GroupBox(this, x, y, 390, 120, "HTTP"); auto pw = groupHttp.get(); - MyQUI::PairLine(pw, 20, 20, "服务类型: ", "服务端"); - MyQUI::PairLine(pw, 20, 50, "服务端口: ", Utils::toStr(Config::option.http.port)); - MyQUI::PairLine(pw, 20, 80, "服务状态: ", "运行"); + this->addPair("http-t", pw, 20, 20, "服务类型: ", "服务端"); + this->addPair("http-p", pw, 20, 50, "服务端口: ", Utils::toStr(Config::option.http.port)); + this->addPair("http-s", pw, 20, 80, "服务状态: ", "运行"); } { x += 400; this->groupMqtt = MyQUI::GroupBox(this, x, y, 390, 120, "MQTT"); auto pw = groupMqtt.get(); - MyQUI::PairLine(pw, 20, 20, "服务类型: ", "客户端"); - MyQUI::PairLine(pw, 20, 50, "服务地址: ", Config::option.mqtt.host); - MyQUI::PairLine(pw, 20, 80, "服务状态: ", "---"); + this->addPair("mqtt-t", pw, 20, 20, "服务类型: ", "客户端"); + this->addPair("mqtt-h", pw, 20, 50, "服务地址: ", Config::option.mqtt.host); + this->addPair("mqtt-s", pw, 20, 80, "服务状态: ", "---"); } { x += 400; this->groupDB = MyQUI::GroupBox(this, x, y, 390, 120, "数据库"); auto pw = groupDB.get(); - MyQUI::PairLine(pw, 20, 20, "数据库名: ", Config::option.database.dbname); - MyQUI::PairLine(pw, 20, 50, "主机地址: ", Config::option.database.host); - MyQUI::PairLine(pw, 20, 80, "用 户 名: ", Config::option.database.user); + this->addPair("db-n", pw, 20, 20, "数据库名: ", Config::option.database.dbname); + this->addPair("db-h", pw, 20, 50, "主机地址: ", Config::option.database.host); + this->addPair("db-u", pw, 20, 80, "用 户 名: ", Config::option.database.user); - const std::string QSS_TABLE = // 表格整体样式 - "QTableWidget {" - " background-color: transparent;" // 背景色 - " gridline-color: #C0C0C0;" // 网格线颜色 - " border: 1px solid gray;" // 边框 - " color: white;" // 文字颜色 - "}" - // 表头样式 - "QHeaderView::section {" - " background-color: #404040;" // 表头背景 - " padding: 4px;" // 内边距 - " border: 1px solid #505050;" // 边框 - " min-height: 25px;" // 最小高度 - "}" - // 单元格样式 - "QTableWidget::item {" - " padding-left: 5px;" - " border-bottom: 1px solid gray;" // 底部边框 - "}" - // 选中状态 - "QTableWidget::item:selected {" - " background-color: #B8D6FF;" // 选中背景色 - " color: black;" // 选中文字颜色 - "}"; - table = std::make_shared(this); - table->setGeometry(10, y += 130, 1190, 300); + table->setGeometry(10, y += 130, 1190, 265); table->setStyleSheet(QSS_TABLE.c_str()); table->horizontalHeader()->setStretchLastSection(true); // 最后一列占满 table->verticalHeader()->setVisible(false); // 不显示垂直表头 @@ -92,36 +71,55 @@ QWHome::QWHome(QWidget* parent) : MyWidget(parent) table->setColumnWidth(1, 120); table->setColumnWidth(2, 50); table->setColumnWidth(4, 80); - } - textLog = std::make_shared(this); - textLog->setGeometry(10, y += 310, 1190, 280); - textLog->setStyleSheet("background-color: transparent; border: 1px solid gray; font-weight: 400;"); - textLog->setReadOnly(true); + logFilter = MyQUI::PairLine(this, 10, y += 270, "日志过滤: ", "", false); + btnLogClean = std::make_shared("清除", this); + btnLogClean->setGeometry(400, y, 80, 26); + connect(btnLogClean.get(), &QPushButton::clicked, this, [=]() { texteditLog->clear(); }); + + texteditLog = std::make_shared(this); + texteditLog->setGeometry(10, y += 30, 1190, 280); + texteditLog->setStyleSheet("background-color: transparent; border: 1px solid gray; font-weight: 400;"); + texteditLog->setReadOnly(true); { + //////////////////////////////////////////////////////////////////////////////////////// + // QT显示spdlog: 方法一 // 第二个参数是方法函数名称,即调用 QTextEdit的appeng函数; - auto qtSink = std::make_shared(textLog.get(), "append"); - spdlog::default_logger()->sinks().push_back(qtSink); + //auto qtSink = std::make_shared(textLog.get(), "append"); + //spdlog::default_logger()->sinks().push_back(qtSink); + + //////////////////////////////////////////////////////////////////////////////////////// + // QT显示spdlog: 方法二, 自定义实现 QtLogSink + myqtSink = std::make_shared(this); + spdlog::default_logger()->sinks().push_back(myqtSink); + //auto logger = std::make_shared("custom_logger", myqtSink); + //spdlog::register_logger(logger); + + // 连接信号和槽,使用Qt::QueuedConnection确保线程安全 + connect(myqtSink.get(), &QtLogSink::logMessageReceived, this, &QWHome::onLogMessageReceived, Qt::QueuedConnection); } } -void QWHome::setTableCell(int row, int col, std::string text, std::string style /*= ""*/) +QWHome::~QWHome() { - auto item = table->item(row, col); - if (!item) - { - item = new QTableWidgetItem(); - table->setItem(row, col, item); - } - item->setText(text.c_str()); - if (style == "OK") { item->setForeground(QBrush(Qt::green)); } - else if (style == "ERR") { item->setForeground(QBrush(Qt::red)); } + table->clear(); + mapPairs.clear(); } +void QWHome::addPair(string name, QWidget* parent, int x, int y, string k, string v, bool readonly /*= true*/) +{ + if (name.empty()) name = k; + mapPairs[name] = MyQUI::PairLine(parent, x, y, k, v); +} + + + void QWHome::onTimer() { + if (!this->isVisible()) { return; } + auto& appdata = Application().data(); int rowNo = 0; int tsNow = Utils::time(); @@ -135,27 +133,46 @@ void QWHome::onTimer() bool isOpen = station->status > 0; bool isConnected = station->mqttCli->isConnected; - setTableCell(rowNo, 0, std::to_string(station->stationId)); - setTableCell(rowNo, 1, station->name); - setTableCell(rowNo, 2, station->code); - setTableCell(rowNo, 3, isOpen ? "启用" : "未启用", isOpen ? "OK" : "ERR"); - setTableCell(rowNo, 4, isConnected ? "连接成功" : "未连接", isConnected ? "OK" : "ERR"); + MyQUI::setTableCell(table, rowNo, 0, std::to_string(station->stationId)); + MyQUI::setTableCell(table, rowNo, 1, station->name); + MyQUI::setTableCell(table, rowNo, 2, station->code); + MyQUI::setTableCell(table, rowNo, 3, isOpen ? "启用" : "未启用", isOpen ? "OK" : "ERR"); + MyQUI::setTableCell(table, rowNo, 4, isConnected ? "连接成功" : "未连接", isConnected ? "OK" : "ERR"); int tsPolling = station->getPollingTS(); - setTableCell(rowNo, 5, tsPolling > 0 ? std::to_string(tsNow - tsPolling) + "/" + std::to_string(Config::option.mqtt.interval) : "--"); + MyQUI::setTableCell(table, rowNo, 5, tsPolling > 0 ? std::to_string(tsNow - tsPolling) + "/" + std::to_string(Config::option.mqtt.interval) : "--"); - setTableCell(rowNo, 6, Utils::toStr(station->statData.dayElectIn, 0)); - setTableCell(rowNo, 7, Utils::toStr(station->statData.dayElectOut, 0)); - setTableCell(rowNo, 8, Utils::toStr(station->statData.totalElectIn, 0)); - setTableCell(rowNo, 9, Utils::toStr(station->statData.totalElectOut, 0)); - setTableCell(rowNo, 10, Utils::toStr(station->statData.dayFeeIn, 0)); - setTableCell(rowNo, 11, Utils::toStr(station->statData.dayFeeOut, 0)); - setTableCell(rowNo, 12, Utils::toStr(station->statData.totalFeeIn, 0)); - setTableCell(rowNo, 13, Utils::toStr(station->statData.totalFeeOut, 0)); - setTableCell(rowNo, 14, Utils::toStr(station->statData.dayIncome, 0)); - setTableCell(rowNo, 15, Utils::toStr(station->statData.totalIncome, 0)); - setTableCell(rowNo, 16, station->statData.ts > 0 ? Utils::timeStr(station->statData.ts) : "--"); + MyQUI::setTableCell(table, rowNo, 6, Utils::toStr(station->statData.dayElectIn, 0)); + MyQUI::setTableCell(table, rowNo, 7, Utils::toStr(station->statData.dayElectOut, 0)); + MyQUI::setTableCell(table, rowNo, 8, Utils::toStr(station->statData.totalElectIn, 0)); + MyQUI::setTableCell(table, rowNo, 9, Utils::toStr(station->statData.totalElectOut, 0)); + MyQUI::setTableCell(table, rowNo, 10, Utils::toStr(station->statData.dayFeeIn, 0)); + MyQUI::setTableCell(table, rowNo, 11, Utils::toStr(station->statData.dayFeeOut, 0)); + MyQUI::setTableCell(table, rowNo, 12, Utils::toStr(station->statData.totalFeeIn, 0)); + MyQUI::setTableCell(table, rowNo, 13, Utils::toStr(station->statData.totalFeeOut, 0)); + MyQUI::setTableCell(table, rowNo, 14, Utils::toStr(station->statData.dayIncome, 0)); + MyQUI::setTableCell(table, rowNo, 15, Utils::toStr(station->statData.totalIncome, 0)); + MyQUI::setTableCell(table, rowNo, 16, station->statData.ts > 0 ? Utils::timeStr(station->statData.ts) : "--"); rowNo++; } +} + +void QWHome::onLogMessageReceived(const QString& message) +{ + if (!this->isVisible()) { return; } + + bool show = true; + if (logFilter.second) + { + auto filter = logFilter.second->text(); + if (!filter.isEmpty() && !message.contains(filter)) + { + show = false; + } + } + if (show) + { + texteditLog->append(message.trimmed()); + } } \ No newline at end of file diff --git a/src/qt/widgets/QWHome.h b/src/qt/widgets/QWHome.h index 7781b2e..896bba5 100644 --- a/src/qt/widgets/QWHome.h +++ b/src/qt/widgets/QWHome.h @@ -6,23 +6,54 @@ #include +#include +#include + +class QtLogSink : public QObject, public spdlog::sinks::base_sink +{ + Q_OBJECT +public: + QtLogSink(QObject* parent = nullptr) : QObject(parent) {} + +protected: + void sink_it_(const spdlog::details::log_msg& msg) override { + spdlog::memory_buf_t formatted; + spdlog::sinks::base_sink::formatter_->format(msg, formatted); + QString logMessage = QString::fromStdString(fmt::to_string(formatted)); + // 发射信号,传递日志消息 + emit logMessageReceived(logMessage); + } + + void flush_() override {} + +signals: + void logMessageReceived(const QString& message); +}; + + class QWHome : public MyWidget { Q_OBJECT public: QWHome(QWidget* parent); + ~QWHome(); + + void addPair(string name, QWidget* parent, int x, int y, string k, string v, bool readonly = true); // 创建自定义sink //std::shared_ptr qtSink; - + std::map mapPairs; std::shared_ptr groupSys; std::shared_ptr groupHttp; std::shared_ptr groupMqtt; std::shared_ptr groupDB; std::shared_ptr table {}; - std::shared_ptr textLog; + std::shared_ptr texteditLog; + MyPairLabelLine logFilter {}; + std::shared_ptr btnLogClean; + std::shared_ptr myqtSink; void onTimer() override; - void setTableCell(int row, int col, std::string text, std::string style = ""); + void onLogMessageReceived(const QString& message); }; \ No newline at end of file diff --git a/src/qt/widgets/QWMonitor.cpp b/src/qt/widgets/QWMonitor.cpp index e69de29..adf587a 100644 --- a/src/qt/widgets/QWMonitor.cpp +++ b/src/qt/widgets/QWMonitor.cpp @@ -0,0 +1,218 @@ +#include "QWMonitor.h" + +#include "app/Application.h" +#include "app/AppData.h" +#include "app/Station.h" +#include "app/Device.h" +#include "common/Utils.h" +#include "app/DataStruct.h" + +QWMonitor::QWMonitor(QWidget* parent) : MyWidget(parent) +{ + //this->setStyleSheet("background-color: red;"); + int x = 10, y = 10; + for (auto& iter: Application::data().mapStation) + { + auto station = iter.second; + auto btn = make_shared(station->name.c_str(), this); + btn->setGeometry(x, y, 120, 36); + btn->setStyleSheet(QSS_BTN.c_str()); + x += 130; + + if (!curActiveBtn) + { + curActiveBtn = btn; + curActiveBtn->setStyleSheet(QSS_BTN_ACTIVE.c_str()); + } + mapBtnStation[btn] = station; + + connect(btn.get(), &QPushButton::clicked, this, [=]() + { + if (btn != curActiveBtn) + { + if (curActiveBtn) { curActiveBtn->setStyleSheet(QSS_BTN.c_str()); } + if (btn) { btn->setStyleSheet(QSS_BTN_ACTIVE.c_str()); } + curActiveBtn = btn; + this->initStation(station); + } + }); + } + + table = std::make_shared(this); + table->setGeometry(10, y += 50, 700, 800); + table->setStyleSheet(QSS_TABLE.c_str()); + table->horizontalHeader()->setStretchLastSection(true); // 最后一列占满 + table->verticalHeader()->setVisible(false); // 不显示垂直表头 + table->setEditTriggers(QAbstractItemView::NoEditTriggers); // 单元格不可编辑 + table->setSelectionMode(QAbstractItemView::SingleSelection); // 设置为单选模式 + table->setSelectionBehavior(QAbstractItemView::SelectRows); // 设置为整行选中 + table->horizontalHeader()->setFixedHeight(50); + table->horizontalHeader()->setDefaultSectionSize(60); + + QTableWidgetItem* headerItem; + QStringList headerText_Row, headerText_Col; + headerText_Row << "ID" << "类型ID" << "类型名称" << "设备名称" << "编号" << "状态" << "通讯\n状态" << "工作\n状态" << "故障\n状态"; + + // 设置为水平表头 + table->setColumnCount(headerText_Row.size()); + table->setHorizontalHeaderLabels(headerText_Row); + table->setColumnWidth(0, 50); + table->setColumnWidth(1, 60); + table->setColumnWidth(2, 120); + table->setColumnWidth(3, 160); + + connect(table.get(), &QTableWidget::currentCellChanged, this, &QWMonitor::onCurrentCellChanged); + + if (curActiveBtn) + { + this->initStation(mapBtnStation[curActiveBtn]); + } + + this->groupStation = MyQUI::GroupBox(this, 730, y, 480, 800, "设备信息"); + + labDeviceInfo = std::make_shared(groupStation.get()); + labDeviceInfo->setGeometry(10, 20, 400, 26); + + // 将内容widget设置为滚动区域的widget + uiReg.scroll = new QScrollArea(groupStation.get()); + uiReg.scroll->setFixedHeight(600); // 设置滚动区域固定高度600px + uiReg.scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); // 垂直滚动条在需要时出现 + //scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); // 水平滚动条在需要时出现 + uiReg.scroll->setGeometry(10, 90, 460, 700); + uiReg.scroll->setObjectName("MyScroll"); + uiReg.scroll->setStyleSheet("#MyScroll {background-color: transparent; border: 1px solid gray;}"); + uiReg.scroll->setWidgetResizable(true); + + std::string QSS_LISTVIEW = + "QListView { background-color: transparent; color: white; }" + "QListView::item { background-color: transparent; border-bottom: 0px solid gray; padding: 0px; height: 20px; }"; + + uiReg.listReg = new QListWidget(groupStation.get()); + uiReg.listReg->setStyleSheet(QSS_LISTVIEW.c_str()); + uiReg.scroll->setWidget(uiReg.listReg); +}; + +QWMonitor::~QWMonitor() +{ + curDevice = nullptr; + curStation = nullptr; + curActiveBtn = nullptr; + mapBtnStation.clear(); + table->clear(); +} + +void QWMonitor::initStation(shared_ptr station) +{ + table->clearSelection(); + this->curDevice = NULL; + if (uiReg.listReg) + { + uiReg.listReg->clearSelection(); + uiReg.listReg->clear(); + } + this->updateStation(station); +} + +void QWMonitor::updateStation(shared_ptr station) +{ + auto& appdata = Application::data(); + //table->clearContents(); + int row = 0; + for (auto& iter : station->mapDevice) + { + auto& device = iter.second; + MyQUI::setTableCell(table, row, 0, Utils::toStr(device->deviceId)); + MyQUI::setTableCell(table, row, 1, Utils::toStr(device->type)); + MyQUI::setTableCell(table, row, 2, appdata.getDeviceNameById(device->type)); + MyQUI::setTableCell(table, row, 3, device->name); + MyQUI::setTableCell(table, row, 4, device->code); + MyQUI::setTableCell(table, row, 5, device->isOpen ? "启用" : "未启用", device->isOpen ? "OK" : "ERR"); + MyQUI::setTableCell(table, row, 6, device->online ? "在线" : "离线", device->online ? "OK" : "ERR"); + MyQUI::setTableCell(table, row, 7, device->running ? "工作" : "空闲", device->running ? "OK" : "WARN"); + MyQUI::setTableCell(table, row, 8, device->err ? "故障" : "正常", device->err ? "ERR" : "OK"); + ++row; + } + + int rowCount = table->rowCount(); + for (int i = station->mapDevice.size(); iremoveRow(i); + } +} + + +shared_ptr QWMonitor::getCurrentStation() +{ + return curActiveBtn ? mapBtnStation[curActiveBtn] : nullptr; +} + +void QWMonitor::onCurrentCellChanged(int row, int col, int oldRow, int oldCol) +{ + auto station = getCurrentStation(); + if (!station) + { + labDeviceInfo->setText("--"); + return; + } + if (row != oldRow) + { + auto item = table->item(row, 0); + if (item) + { + auto deviceId = item->text().toInt(); + curDevice = station->getDevice(deviceId); + if (curDevice) + { + string info = curDevice->name; + labDeviceInfo->setText(info.c_str()); + return; + } + } + } +} + +void QWMonitor::onTimer() +{ + auto station = getCurrentStation(); + if (!station) return; + + this->updateStation(station); + + if (curDevice) + { + auto mapRegPtr = REGAddr::getRegMapByDeviceType(curDevice->type); + auto& mapDeviceParams = curDevice->mapParams; + + stringstream ss; + int ind = 0; + for (auto& iter : mapDeviceParams) + { + ss.str(""); + + auto& addr = iter.first; + ss << std::setw(3) << std::setfill('0') << ind << ": " << addr << ": " << iter.second; + if (mapRegPtr) { + auto iter = mapRegPtr->find(addr); + if (iter != mapRegPtr->end()) + { + ss << " (" << iter->second.name << ")"; + } + } + ss << "\n"; + + if (ind < uiReg.listReg->count()) + { + uiReg.listReg->item(ind)->setText(ss.str().c_str()); + } + else + { + uiReg.listReg->addItem(ss.str().c_str()); + } + ++ind; + } + for (int i = uiReg.listReg->count()-1; i>=ind; --i) + { + uiReg.listReg->takeItem(i); + } + } +} \ No newline at end of file diff --git a/src/qt/widgets/QWMonitor.h b/src/qt/widgets/QWMonitor.h index e69de29..a24d43b 100644 --- a/src/qt/widgets/QWMonitor.h +++ b/src/qt/widgets/QWMonitor.h @@ -0,0 +1,51 @@ +#pragma once + +#include "qt/MyQUI.h" + +#include +#include + +class Station; +class Device; + +class QWMonitor : public MyWidget +{ + Q_OBJECT +public: + QWMonitor(QWidget* parent); + ~QWMonitor(); + + void initStation(shared_ptr station); + shared_ptr getCurrentStation(); + void updateStation(shared_ptr station); + + void onTimer() override; + +public slots: + void onCurrentCellChanged(int row, int col, int oldRow, int oldCol); + + +public: + std::shared_ptr curActiveBtn; + std::map, std::shared_ptr> mapBtnStation; + std::shared_ptr curStation; + std::shared_ptr curDevice; + + shared_ptr table; + + std::shared_ptr groupStation; + + std::shared_ptr labDeviceInfo; + + std::shared_ptr texteditDevice; + + //std::vector> vecLabelRegData; + + struct { + //QWidget* widget; + //QVBoxLayout* layout; + QScrollArea* scroll {}; + QListWidget* listReg {}; + } uiReg; + +}; \ No newline at end of file