diff --git a/bin/Release/assets/config/monitoraddr.json b/bin/Release/assets/config/monitoraddr.json new file mode 100644 index 0000000..ba9da6b --- /dev/null +++ b/bin/Release/assets/config/monitoraddr.json @@ -0,0 +1,109 @@ +{ + "EMS":{ + "deviceType":101, + "addr_YC":[ + ["A相电压", "0x107E", "0.0", " V", "0.1"], + ["A相电流", "0x1084", "0.0", " A"], + ["B相电压", "0x1080", "0.0", " V", "0.1"], + ["B相电流", "0x1086", "0.0", " A"], + ["C相电压", "0x1082", "0.0", " V", "0.1"], + ["C相电流", "0x1088", "0.0", " A"] + ], + "addr_YX": [ ] + }, + "PCS":{ + "deviceType":102, + "addr_YC":[ + ["A相电压", "0x0010", "0.0", " V", "0.1"], + ["A相电流", "0x0019", "0.0", " A"], + ["B相电压", "0x0011", "0.0", " V", "0.1"], + ["B相电流", "0x001A", "0.0", " A"], + ["C相电压", "0x0011", "0.0", " V", "0.1"], + ["C相电流", "0x001B", "0.0", " A"] + ], + "addr_YX": [ ] + }, + "PCU":{ + "deviceType":103, + "addr_YC":[ + ["A相电压", "0x0013", "0.0", " V", "0.1"], + ["A相电流", "0x001C", "0.0", " A"], + ["B相电压", "0x0014", "0.0", " V", "0.1"], + ["B相电流", "0x001D", "0.0", " A"], + ["C相电压", "0x0015", "0.0", " V", "0.1"], + ["C相电流", "0x001E", "0.0", " A"] + ], + "addr_YX": [ ] + }, + "BMS":{ + "deviceType":104, + "addr_YC":[ + ["SOC", "0x0001", "0", " %"], + ["SOH", "0x0002", "0", " %"], + ["电压", "0x0003", "0.0", " V", "0.1"], + ["电流", "0x0005", "0.0", " A"], + ["单体最大电压", "0x0021", "0.0", " V", "0.1"], + ["单体最小电压", "0x0024", "0.0", " V", "0.1"], + ["单体最大温度", "0x0029", "0.0", " ℃"], + ["单体最小温度", "0x002C", "0.0", " ℃"] + ], + "addr_YX": [ ] + }, + "BCU":{ + "deviceType":105, + "addr_YC":[ + ["簇电压", "0x0003", "0.0", " V"], + ["簇电流", "0x0005", "0", " A"], + ["簇温度", "0x0007", "0.0", " ℃"], + ["簇电阻", "0x0009", "0.0", " Ω"], + ["簇SOC", "0x000B", "0", " %"], + ["簇SOH", "0x000C", "0", " %"] + ], + "addr_YX": [ ] + }, + "MEM":{ + "deviceType":3, + "addr_YC":[ + ["A相电压", "0x000B", "0.0", " V"], + ["A相电流", "0x000D", "0.0", " A"], + ["B相电压", "0x000F", "0.0", " V"], + ["B相电流", "0x0011", "0.0", " A"], + ["C相电压", "0x0013", "0.0", " V"], + ["C相电流", "0x0015", "0.0", " A"] + ], + "addr_YX": [ ] + }, + "TH": { + "deviceType":10, + "addr_YC":[ + ["温度", "0x0003", "0.0", " ℃", "0.1"], + ["湿度", "0x0004", "0.0", " %", "0.1"] + ], + "addr_YX": [ ] + }, + "Cooling": { + "deviceType":14, + "addr_YC":[ + ["开关", "0x1003", "0", "", "1"], + ["采样模式", "0x1004", "0", "", "1"], + ["制冷状态", "0x1005", "0", "", "1"], + ["制热状态", "0x1006", "0", "", "1"], + ["高温告警", "0x1007", "0", "", "1"], + ["低温告警", "0x1008", "0", "", "1"], + ["高压告警", "0x1009", "0", "", "1"], + ["低压告警", "0x100A", "0", "", "1"] + ] + }, + "Charger": { + "deviceType":106, + "addr_YC":[ + ["需求电压", "31071", "0.0", " V"], + ["需求电流", "31073", "0.0", " A"], + ["需求功率", "31075", "0.0", " kW"], + ["功率限值", "31077", "0.0", " kW"], + ["输出电压", "31079", "0.0", " V"], + ["输出电流", "31081", "0.0", " A"], + ["输出功率", "31083", "0.0", " kW"], + ] + } +} \ No newline at end of file diff --git a/bin/Release/assets/config/registeraddr.json b/bin/Release/assets/config/registeraddr.json index 9bea55a..49c89d5 100644 --- a/bin/Release/assets/config/registeraddr.json +++ b/bin/Release/assets/config/registeraddr.json @@ -66,6 +66,103 @@ {"key": "0x207A", "datatype": "uint16", "remark": "判断总表的三相总有功 < -5.0fkW 充电 >5.0fkW放电 否则停机0:充电 1:放电 2:停机"} ] }, + "EMS_YC":{ + "addr":[ + {"key": "0x1001", "datatype": "uint16", "remark": "BMS(电池堆)个数1"}, + {"key": "0x1002", "datatype": "uint16", "remark": "BCU通道个数1~2"}, + {"key": "0x1003", "datatype": "uint16", "remark": "BCU(电池簇)个数1~40"}, + {"key": "0x1004", "datatype": "uint16", "remark": "PCU(主控)个数1~4"}, + {"key": "0x1005", "datatype": "uint16", "remark": "PCU通道个数1~4"}, + {"key": "0x1006", "datatype": "uint16", "remark": "PCS(模块)个数1~40"}, + {"key": "0x1007", "datatype": "uint16", "remark": "电表通道个数1"}, + {"key": "0x1008", "datatype": "uint16", "remark": "电表个数1~10"}, + {"key": "0x1009", "datatype": "uint16", "remark": "消防通道个数1~10"}, + {"key": "0x100A", "datatype": "uint16", "remark": "消防个数1~10"}, + {"key": "0x100B", "datatype": "uint16", "remark": "UPS通道个数1~10"}, + {"key": "0x100C", "datatype": "uint16", "remark": "UPS个数1~10"}, + {"key": "0x100D", "datatype": "uint16", "remark": "温湿度通道个数1"}, + {"key": "0x100E", "datatype": "uint16", "remark": "温湿度个数1~10"}, + {"key": "0x100F", "datatype": "uint16", "remark": "空调通道个数1"}, + {"key": "0x1010", "datatype": "uint16", "remark": "空调个数1~10"}, + {"key": "0x1011", "datatype": "uint16", "remark": "控制干接点(配电系统)个数16"}, + {"key": "0x1012", "datatype": "uint16", "remark": "状态干接点(配电系统)个数16"}, + {"key": "0x1072", "datatype": "uint32", "remark": "系统最大可充电功率(1KW)"}, + {"key": "0x1074", "datatype": "uint32", "remark": "系统最大可放电功率(1KW)"}, + {"key": "0x1076", "datatype": "uint32", "remark": "储能母线电压(0.1V)"}, + {"key": "0x1078", "datatype": "int32", "remark": "储能母线电流(0.1A)"}, + {"key": "0x107A", "datatype": "uint16", "remark": "储能系统SOC(0.1)"}, + {"key": "0x107B", "datatype": "uint16", "remark": "储能系统SOH(0.1)"}, + {"key": "0x107C", "datatype": "uint16", "remark": "电流变比"}, + {"key": "0x107D", "datatype": "uint16", "remark": "电压变比"}, + {"key": "0x107E", "datatype": "uint32", "remark": "A相电压(1V)"}, + {"key": "0x1080", "datatype": "uint32", "remark": "B相电压(1V)"}, + {"key": "0x1082", "datatype": "uint32", "remark": "C相电压(1V)"}, + {"key": "0x1084", "datatype": "int32", "remark": "A相电流(1A)"}, + {"key": "0x1086", "datatype": "int32", "remark": "B相电流(1A)"}, + {"key": "0x1088", "datatype": "int32", "remark": "C相电流(1A)"}, + {"key": "0x108A", "datatype": "uint32", "remark": "AB相电压(1V)"}, + {"key": "0x108C", "datatype": "uint32", "remark": "BC相电压(1V)"}, + {"key": "0x108E", "datatype": "uint32", "remark": "CA相电压(1V)"}, + {"key": "0x1090", "datatype": "int32", "remark": "A相有功功率(1kW)"}, + {"key": "0x1092", "datatype": "int32", "remark": "B相有功功率(1kW)"}, + {"key": "0x1094", "datatype": "int32", "remark": "C相有功功率(1kW)"}, + {"key": "0x1096", "datatype": "int32", "remark": "三相总有功功率(1kW)"}, + {"key": "0x1098", "datatype": "int32", "remark": "当前控制功率(0.1kW)"}, + {"key": "0x109A", "datatype": "uint32", "remark": "负荷率(0.01)"}, + {"key": "0x109C", "datatype": "uint32", "remark": "三相不平衡度(0.01)"}, + {"key": "0x109E", "datatype": "uint32", "remark": "功率因素比率(0.01)"}, + {"key": "0x10A0", "datatype": "int32", "remark": "进线开关柜功率(1kW)"}, + {"key": "0x10A2", "datatype": "int32", "remark": "用户关口表功率(1kW)"}, + {"key": "0x1104", "datatype": "int32", "remark": "正向总有功总需量(1kW)"}, + {"key": "0x1106", "datatype": "uint32", "remark": "尖段电价(1RMB)"}, + {"key": "0x1108", "datatype": "uint32", "remark": "峰段电价(1RMB)"}, + {"key": "0x110A", "datatype": "uint32", "remark": "平段电价(1RMB)"}, + {"key": "0x110C", "datatype": "uint32", "remark": "谷段电价(1RMB)"}, + {"key": "0x110E", "datatype": "uint32", "remark": "日充电电量(1kWh)"}, + {"key": "0x1110", "datatype": "uint32", "remark": "日放电电量(1kWh)"}, + {"key": "0x1112", "datatype": "uint32", "remark": "日充电费用(1RMB)"}, + {"key": "0x1114", "datatype": "uint32", "remark": "日放电费用(1RMB)"}, + {"key": "0x1116", "datatype": "int32", "remark": "日收益(1RMB)"}, + {"key": "0x1118", "datatype": "uint32", "remark": "日正向尖有功电能(1kWh)"}, + {"key": "0x111A", "datatype": "uint32", "remark": "日正向峰有功电能(1kWh)"}, + {"key": "0x111C", "datatype": "uint32", "remark": "日正向平有功电能(1kWh)"}, + {"key": "0x111E", "datatype": "uint32", "remark": "日正向谷有功电能(1kWh)"}, + {"key": "0x1120", "datatype": "uint32", "remark": "日正向总有功电能(1kWh)"}, + {"key": "0x1122", "datatype": "uint32", "remark": "日反向尖有功电能(1kWh)"}, + {"key": "0x1124", "datatype": "uint32", "remark": "日反向峰有功电能(1kWh)"}, + {"key": "0x1126", "datatype": "uint32", "remark": "日反向平有功电能(1kWh)"}, + {"key": "0x1128", "datatype": "uint32", "remark": "日反向谷有功电能(1kWh)"}, + {"key": "0x112A", "datatype": "uint32", "remark": "日反向总有功电能(1kWh)"}, + {"key": "0x112C", "datatype": "uint32", "remark": "总充电电量(1kWh)"}, + {"key": "0x112E", "datatype": "uint32", "remark": "总放电电量(1kWh)"}, + {"key": "0x1130", "datatype": "uint32", "remark": "总充电费用(1RMB)"}, + {"key": "0x1132", "datatype": "uint32", "remark": "总放电费用(1RMB)"}, + {"key": "0x1134", "datatype": "int32", "remark": "总收益(1RMB)"}, + {"key": "0x1136", "datatype": "uint32", "remark": "总正向尖有功电能(1kWh)"}, + {"key": "0x1138", "datatype": "uint32", "remark": "总正向峰有功电能(1kWh)"}, + {"key": "0x113A", "datatype": "uint32", "remark": "总正向平有功电能(1kWh)"}, + {"key": "0x113C", "datatype": "uint32", "remark": "总正向谷有功电能(1kWh)"}, + {"key": "0x113E", "datatype": "uint32", "remark": "总正向总有功电能(1kWh)"}, + {"key": "0x1140", "datatype": "uint32", "remark": "总反向尖有功电能(1kWh)"}, + {"key": "0x1142", "datatype": "uint32", "remark": "总反向峰有功电能(1kWh)"}, + {"key": "0x1144", "datatype": "uint32", "remark": "总反向平有功电能(1kWh)"}, + {"key": "0x1146", "datatype": "uint32", "remark": "总反向谷有功电能(1kWh)"}, + {"key": "0x1148", "datatype": "uint32", "remark": "总反向总有功电能(1kWh)"}, + {"key": "0x11AE", "datatype": "int16", "remark": "交流A相电压(1V)"}, + {"key": "0x11AF", "datatype": "int16", "remark": "交流B相电压(1V)"}, + {"key": "0x11B0", "datatype": "int16", "remark": "交流C相电压(1V)"}, + {"key": "0x11B1", "datatype": "int16", "remark": "交流A相频率(1Hz)"}, + {"key": "0x11B2", "datatype": "int16", "remark": "交流B相频率(1Hz)"}, + {"key": "0x11B3", "datatype": "int16", "remark": "交流C相频率(1Hz)"}, + {"key": "0x11B4", "datatype": "int32", "remark": "总直流功率(1kW)"}, + {"key": "0x11B6", "datatype": "uint32", "remark": "总直流电压(0.1V)"}, + {"key": "0x11B8", "datatype": "int32", "remark": "总直流电流(0.1A)"}, + {"key": "0x121B", "datatype": "int16", "remark": "储能系统温度(0.1℃)"}, + {"key": "0x121C", "datatype": "uint16", "remark": "储能充放电时段hh(时)"}, + {"key": "0x121D", "datatype": "uint16", "remark": "储能充放电时段mm(分)"}, + {"key": "0x121E", "datatype": "uint16", "remark": "储能充放电时段ss(秒)"} + ] + }, "PCU_YC":{ "addr":[ {"key": "0x0001", "datatype": "uint16", "remark": "所属通道号1~4"}, diff --git a/bin/Release/assets/config/registeraddrs.py b/bin/Release/assets/config/registeraddrs.py index 668562e..d6f7043 100644 --- a/bin/Release/assets/config/registeraddrs.py +++ b/bin/Release/assets/config/registeraddrs.py @@ -38,6 +38,7 @@ wb = load_workbook('EMU对外通信点表最终修改1版_v9.xlsx', data_only=Tr text = "" text = read_sheet(wb, "EMS_YT", "EMS遥调") text += ',\n' + read_sheet(wb, "EMS_YX", "EMS遥信") +text += ',\n' + read_sheet(wb, "EMS_YC", "EMS遥测") text += ',\n' + read_sheet(wb, "PCU_YC", "PCU遥测") text += ',\n' + read_sheet(wb, "PCU_YX", "PCU遥信") text += ',\n' + read_sheet(wb, "PCS_YC", "PCS遥测") diff --git a/bin/Release/assets/ui/iconFullscreen.png b/bin/Release/assets/ui/iconFullscreen.png new file mode 100644 index 0000000..10bf560 Binary files /dev/null and b/bin/Release/assets/ui/iconFullscreen.png differ diff --git a/bin/Release/assets/ui/iconFullscreenExit.png b/bin/Release/assets/ui/iconFullscreenExit.png new file mode 100644 index 0000000..d418dbc Binary files /dev/null and b/bin/Release/assets/ui/iconFullscreenExit.png differ diff --git a/src/app/AppData.cpp b/src/app/AppData.cpp index 159b9d9..5e775b1 100644 --- a/src/app/AppData.cpp +++ b/src/app/AppData.cpp @@ -33,13 +33,13 @@ std::string ElectPeriod::dump() } -void AppData::initFromDB() +bool AppData::initFromDB() { auto dao = DaoEntity::create(""); if (!dao->isConnected()) { spdlog::error("Init app data failed, database connected error."); - return; + return false; } std::string str; @@ -235,26 +235,17 @@ void AppData::initFromDB() } } } + return true; } -void AppData::init() +bool AppData::init() { - this->initFromDB(); + bool ret = this->initFromDB(); + if (!ret) { return false; } + - auto& optionMqtt = Config::option.mqtt; - if (!optionMqtt.host.empty()) - { - for (auto& item : mapStation) - { - auto& station = item.second; - if (station->status == 1) - { - // "tcp://localhost:1883" - station->mqttCli->init(optionMqtt.host, station->code, optionMqtt.username, optionMqtt.password); - } - } - } this->launchDate = Config::option.lunchDate; + return true; } std::shared_ptr AppData::getStation(int stationId) diff --git a/src/app/AppData.h b/src/app/AppData.h index 6a61ef8..79d26eb 100644 --- a/src/app/AppData.h +++ b/src/app/AppData.h @@ -57,8 +57,8 @@ public: class AppData { public: - void init(); - void initFromDB(); + bool init(); + bool initFromDB(); // 读取统计数据: 今日统计数据,累计统计数据 void loadStatData(); diff --git a/src/app/Application.cpp b/src/app/Application.cpp index 21610f7..43bbcd7 100644 --- a/src/app/Application.cpp +++ b/src/app/Application.cpp @@ -18,6 +18,8 @@ void Application::init() // MQTT 数据结构 MqttClient::loadDataStruct("assets/config/registeraddr.json"); + // 设备读取寄存器的地址定义 + Device::loadParamAddr("assets/config/monitoraddr.json"); // 设置数据库配置 DaoEntity::setOption(Config::option.database.host, @@ -34,7 +36,7 @@ void Application::init() // 连接数据库,读取基础信息 // 初始化系统基础数据 - appdata.init(); + this->isInit = appdata.init(); // 创建设备处理线程 std::thread([=]() { runThreadDevice(); }).detach(); @@ -47,11 +49,11 @@ void Application::init() } }).detach(); - // 创建主业务循环线程 - std::thread([=]() { runThreadMain(); }).detach(); - // 统计分析 std::thread([=]() { runThreadStat(); }).detach(); + + // 创建主业务循环线程 + std::thread([=]() { runThreadMain(); }).detach(); } @@ -71,47 +73,37 @@ void Application::runThreadMain() while (!isQuit) { - //// 连接场站 - //static TimeTick ttStation; - //if (ttStation.elapse(10000)) - //{ - // if (!mqttCli->isConnected) - // { - // } - // else - // { - // for (auto& item: appdata.mapStation) - // { - // auto station = item.second; - // if (station && !station->isConnected) - // { - // std::string stationCode = station->code; - // std::vector vecTopics = { - // "up/json" + stationCode + "/EMS_YX", - // "up/json" + stationCode + "/EMS_YC", - // "up/json" + stationCode + "/PCU_YX", - // "up/json" + stationCode + "/PCU_YC", - // }; - // mqttCli->subscribe(vecTopics, [=](int id) - // { - // station->isConnected = (id == 0); - // }); - // } - // break; - // } - // } - //} + if (!this->isInit) // 初始化失败 + { + std::this_thread::sleep_for(std::chrono::milliseconds(10000)); + this->isInit = appdata.init(); + if (!this->isInit) { continue; } + } + + static TimeTick ttMqtt; + // 检查 场站的 MQTT 连接 + if (ttMqtt.elapse(10)) + { + auto& optionMqtt = Config::option.mqtt; + if (!optionMqtt.host.empty()) + { + for (auto& item : appdata.mapStation) + { + if (item.second) + { + item.second->initMqtt(); + //item.second->polling(); + } + } + } + } /////////////////////////////////////////////////////////////////////////////////////////// /// 召测 static TimeTick tt1; if (tt1.elapse(10)) { - for (auto& item: appdata.mapStation) - { - auto& station = item.second; - station->polling(); - } + } std::this_thread::sleep_for(std::chrono::milliseconds(10)); } diff --git a/src/app/Application.h b/src/app/Application.h index 3832257..fd1177a 100644 --- a/src/app/Application.h +++ b/src/app/Application.h @@ -33,6 +33,7 @@ public: public: bool isQuit = false; + bool isInit = false; // 登录的管理员信息 Operator op; diff --git a/src/app/Device.cpp b/src/app/Device.cpp index 84816f3..8c95cb2 100644 --- a/src/app/Device.cpp +++ b/src/app/Device.cpp @@ -7,6 +7,19 @@ #include +std::map> Device::s_mapDeviceParamAddr; + +static std::vector& GetDeviceParamAddrs(int deviceType) +{ + static std::vector vecAddrs = {}; + auto iter = Device::s_mapDeviceParamAddr.find(deviceType); + if (iter != Device::s_mapDeviceParamAddr.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) { @@ -20,6 +33,41 @@ std::shared_ptr Device::create(Fields& fields) return device; } + +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(); + spdlog::info(jsonnodeItem.dump()); + + int type = jsonnodeItem["deviceType"]; + auto& vec = s_mapDeviceParamAddr[type]; + for (auto& v : jsonnodeItem["addr_YC"]) + { + 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)); + } + } + } + catch (nlohmann::json::parse_error& e) + { + spdlog::error("[device] parse [{}] error: ", filename, e.what()); + } +} + void Device::setFields(Fields& fields) { fields.get("device_id", this->deviceId); @@ -53,6 +101,12 @@ void Device::setFields(Fields& fields) } } } + + auto& vecAddrs = GetDeviceParamAddrs(this->type); + for (auto& item: vecAddrs) + { + this->mapMyParams[item.addr] = &item; + } } int Device::startComm() @@ -174,42 +228,47 @@ void Device::storeDB(int npos) { } - - - - -void Device::setParam(std::string k, std::string v) +void Device::setParam(std::string k, int v) { - mapParams[k] = v; + float ratio = 1.0; + auto iter = mapMyParams.find(k); + if (iter != mapMyParams.end()) + { + ratio = iter->second->ratio; + spdlog::info("[device] set param: {} {}={}, ratio={}", iter->second->name, k, v, ratio); + } + + int precision = (ratio != 1.0f) ? 2 : 0; + mapParams[k] = Utils::toStr(v*ratio, precision); if (type == 3 ) // 电表 { - if (k == "") this->err = Utils::toInt(v); + if (k == "") this->err = v; } else if (type == 101) // EMS { } else if (type == 102) // PCS { - if (k == "0x1003") err = Utils::toInt(v); // 故障状态 R uint16 1故障,0正常 0 0x1003 - if (k == "0x1005") online = Utils::toInt(v); // 设备在线 R uint16 1在线,0无效 1 0x1005 - if (k == "0x1009") running = (v=="1" || v=="2"); //充放状态 R uint16 0:待机, 1:充电, 2:放电, 3:搁置 0 0x1009 + if (k == "0x1003") err = v; // 故障状态 R uint16 1故障,0正常 0 0x1003 + if (k == "0x1005") online = v; // 设备在线 R uint16 1在线,0无效 1 0x1005 + if (k == "0x1009") running = (v==1 || v==2); //充放状态 R uint16 0:待机, 1:充电, 2:放电, 3:搁置 0 0x1009 } else if (type == 103) // PCU { - if (k == "0x1002") err = Utils::toInt(v); //故障状态 R uint16 1故障,0正常 0 0x1002 - if (k == "0x1004") online = Utils::toInt(v); //设备在线 R uint16 1在线,0无效 1 0x1004 - if (k == "0x1006") running = Utils::toInt(v); //启停状态 R uint16 1开机,0关机 1 0x1006 + if (k == "0x1002") err = v; //故障状态 R uint16 1故障,0正常 0 0x1002 + if (k == "0x1004") online = v; //设备在线 R uint16 1在线,0无效 1 0x1004 + if (k == "0x1006") running = v; //启停状态 R uint16 1开机,0关机 1 0x1006 } else if (type == 104) // BMS { - if (k == "0x004A") { err = (v=="1"); online = 1; } //运行状态 R uint16 0 运行状态 0-正常 1-告警 2-保护 0x004A - if (k == "0x004B") running = (v=="1" || v=="2"); //充放电状态 R uint16 0 0-待机 1-充电 2-放电 0x004B + if (k == "0x004A") { err = (v==1); online = 1; } //运行状态 R uint16 0 运行状态 0-正常 1-告警 2-保护 0x004A + if (k == "0x004B") running = (v==1 || v==2); //充放电状态 R uint16 0 0-待机 1-充电 2-放电 0x004B } else if (type == 105) // BCU { - if (k == "0xA003") running = (v=="51" || v=="68"); //蓄电池充放电状态 R uint16 "0x11开路,0x22待机,0x33充电,0x44放电" 34 0xA003 - if (k == "0xA004") err = (v=="85"); online=1; //电池组运行状态 R uint16 "0x11跳机,0x22待机,0x33放空,0x44充满,0x55预警,0x66正常" 102 0xA004 + if (k == "0xA003") running = (v==0x33 || v==0x44); //蓄电池充放电状态 R uint16 "0x11开路,0x22待机,0x33充电,0x44放电" 34 0xA003 + if (k == "0xA004") err = (v==0x55); online=1; //电池组运行状态 R uint16 "0x11跳机,0x22待机,0x33放空,0x44充满,0x55预警,0x66正常" 102 0xA004 } else if (type == 106) // 充电桩 { @@ -229,7 +288,6 @@ std::string Device::getParam(std::string k, std::string defaultVal) return defaultVal; } - void Device::getRuntimeParams(std::vector>& params) { // 3 电表 @@ -240,71 +298,23 @@ void Device::getRuntimeParams(std::vector>& // 105 BCU // 106 充电桩 // 109 光伏板 - - - if (this->type == 3) + auto& vecAddr = s_mapDeviceParamAddr[this->type]; + for (auto& itemAddr: vecAddr) { - params.push_back({"A相电压", getParam("0x000B", "0.0") + " V"}); - params.push_back({"A相电流", getParam("0x000D", "0.0") + " A"}); - params.push_back({"B相电压", getParam("0x000F", "0.0") + " V"}); - params.push_back({"B相电流", getParam("0x0011", "0.0") + " A"}); - params.push_back({"C相电压", getParam("0x0013", "0.0") + " V"}); - params.push_back({"C相电流", getParam("0x0015", "0.0") + " A"}); - } - else if (this->type == 101) // EMS - { - params.push_back({"A相电压", getParam("0x107E", "0.0") + " V"}); - params.push_back({"A相电流", getParam("0x1084", "0.0") + " A"}); - params.push_back({"B相电压", getParam("0x1080", "0.0") + " V"}); - params.push_back({"B相电流", getParam("0x1086", "0.0") + " A"}); - params.push_back({"C相电压", getParam("0x1082", "0.0") + " V"}); - params.push_back({"C相电流", getParam("0x1088", "0.0") + " A"}); - } - else if (this->type == 102) // PCS - { - params.push_back({"A相电压", getParam("0x0010", "0.0") + " V"}); - params.push_back({"A相电流", getParam("0x0019", "0.0") + " A"}); - params.push_back({"B相电压", getParam("0x0011", "0.0") + " V"}); - params.push_back({"B相电流", getParam("0x001A", "0.0") + " A"}); - params.push_back({"C相电压", getParam("0x0011", "0.0") + " V"}); - params.push_back({"C相电流", getParam("0x001B", "0.0") + " A"}); - } - else if (this->type == 103) // PCU - { - params.push_back({"A相电压", getParam("0x0013", "0.0") + " V"}); - params.push_back({"A相电流", getParam("0x001C", "0.0") + " A"}); - params.push_back({"B相电压", getParam("0x0014", "0.0") + " V"}); - params.push_back({"B相电流", getParam("0x001D", "0.0") + " A"}); - params.push_back({"C相电压", getParam("0x0015", "0.0") + " V"}); - params.push_back({"C相电流", getParam("0x001E", "0.0") + " A"}); - } - else if (this->type == 104) // BMS - { - params.push_back({"SOC", getParam("0x0001", "0") + " %"}); - params.push_back({"SOH", getParam("0x0002", "0") + " %"}); - params.push_back({"电压", getParam("0x0003", "0.0") + " V"}); - params.push_back({"电流", getParam("0x0005", "0.0") + " A"}); - params.push_back({"单体最大电压", getParam("0x0021", "0.0") + " V"}); - params.push_back({"单体最小电压", getParam("0x0024", "0.0") + " V"}); - params.push_back({"单体最大温度", getParam("0x0029", "0.0") + " ℃"}); - params.push_back({"单体最小温度", getParam("0x002C", "0.0") + " ℃"}); - } - else if (this->type == 105) // BCU - { - params.push_back({"簇电压", getParam("0x0003", "0.0") + " V"}); - params.push_back({"簇电流", getParam("0x0005", "0") + " A"}); - params.push_back({"簇温度", getParam("0x0007", "0.0") + " ℃"}); - params.push_back({"簇电阻", getParam("0x0009", "0.0") + " Ω"}); - params.push_back({"簇SOC", getParam("0x000B", "0") + " %"}); - params.push_back({"簇SOH", getParam("0x000C", "0") + " %"}); - } - else - { - params.push_back({"额定电压", getParam("0x0001", "0.0") + " V"}); - params.push_back({"实时电压", getParam("0x0001", "0.0") + " V"}); - params.push_back({"额定电流", getParam("0x0001", "0.0") + " A"}); - params.push_back({"实时电流", getParam("0x0001", "0.0") + " A"}); - params.push_back({"额定功率", getParam("0x0001", "0.0") + " W"}); - params.push_back({"实时功率", getParam("0x0001", "0.0") + " W"}); + params.push_back({itemAddr.name, getParam(itemAddr.addr, itemAddr.defaultVal) + itemAddr.unit}); + } +} + +void Device::getRuntimeParams1(std::vector>& params) +{ + if (type == 106) + { + params.push_back({"需求电压", getParam("31072", "0.0") + " V"}); + params.push_back({"需求电流", getParam("31074", "0.0") + " A"}); + params.push_back({"需求功率", getParam("31076", "0.0") + " kW"}); + params.push_back({"功率限值", getParam("31078", "0.0") + " kW"}); + params.push_back({"输出电压", getParam("31080", "0.0") + " V"}); + params.push_back({"输出电流", getParam("31082", "0.0") + " A"}); + params.push_back({"输出功率", getParam("31084", "0.0") + " kW"}); } } diff --git a/src/app/Device.h b/src/app/Device.h index 9899680..187cd6b 100644 --- a/src/app/Device.h +++ b/src/app/Device.h @@ -1,20 +1,39 @@ #pragma once -#include +#include #include #include #include +#include #include #include "common/Fields.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); void setFields(Fields& fields); @@ -30,13 +49,15 @@ public: bool cache(int npos); void storeDB(int npos); - void setParam(std::string k, std::string v); + void setParam(std::string k, int v); std::string getParam(std::string k, std::string defaultVal = ""); void getRuntimeParams(std::vector>& params); - + void getRuntimeParams1(std::vector>& params); public: + static std::map> s_mapDeviceParamAddr; + int deviceId = -1; int type = -1; std::string name; @@ -60,4 +81,8 @@ public: std::map mapCacheCurrent; std::map mapCachePower; std::map mapParams; + + std::map mapMyParams; + + }; diff --git a/src/app/Station.cpp b/src/app/Station.cpp index b6c38c7..b046e6c 100644 --- a/src/app/Station.cpp +++ b/src/app/Station.cpp @@ -7,6 +7,7 @@ #include "common/Utils.h" #include "protocol/MqttEntity.h" #include "common/JsonN.h" +#include "app/Config.h" Station::Station() : stationId(0) { @@ -181,6 +182,14 @@ void Station::writeRuntimeData(std::string dt, int npos) } } +void Station::initMqtt() +{ + if (status!=0 && mqttCli) + { + auto& optionMqtt = Config::option.mqtt; + mqttCli->init(optionMqtt.host, code, optionMqtt.username, optionMqtt.password); + } +} void Station::polling() { @@ -188,4 +197,20 @@ void Station::polling() { mqttCli->polling(); } +} + +void Station::setGarewayWorkMode() +{ + if (!mqttCli) + { + return; + } + + njson json; + json["ts"] = Utils::time(); + json["no"] = 1; // 设备编号 + json["40001"] = this->workModeId; + + std::string text = json.dump(); + mqttCli->publish("Gateway_YT", text); } \ No newline at end of file diff --git a/src/app/Station.h b/src/app/Station.h index 1764cb6..f618026 100644 --- a/src/app/Station.h +++ b/src/app/Station.h @@ -109,12 +109,15 @@ public: void writeRuntimeData(std::string dt, int npos); + void initMqtt(); void polling(); + void setGarewayWorkMode(); public: int stationId {}; std::string name; std::string code; + bool isOpen {false}; int status {0}; bool isConnected {false}; diff --git a/src/main.cpp b/src/main.cpp index aa10176..3a2398a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -118,6 +118,9 @@ void memberJsonTest() } + + + int main(int argc, char** argv) { // 设置控制台输出为 UTF-8 编码 @@ -125,6 +128,53 @@ int main(int argc, char** argv) // 设置控制台输入为 UTF-8 编码(如果需要输入中文) SetConsoleCP(CP_UTF8); + float ratio = 1.1f; + int precision = 0; + if (ratio != 1.0f) + { + precision = 2; + }; + + //qputenv("QTWEBENGINE_REMOTE_DEBUGGING", "9222"); // 即使内置视图,有时也需要开启调试端口 + //QApplication app(argc, argv); + + //QMainWindow mainWindow; + + //// 主窗口和布局 + //QWidget myRoot; + + //QHBoxLayout* layout = new QHBoxLayout(&myRoot); + + //// 创建主 Web 视图 + //QWebEngineView* mainWebView = new QWebEngineView; + //mainWebView->load(QUrl("https://www.example.com")); + + //// 创建用于显示开发者工具的 Web 视图 + //QWebEngineView* devToolsView = new QWebEngineView; + + //// 将主 Web 页面的开发者工具页面设置为 devToolsView 的页面 + //mainWebView->page()->setDevToolsPage(devToolsView->page()); + //// 如果你需要先导航主页面,然后在某个事件(如按钮点击)后显示开发者工具,可以将这行代码放在事件处理函数中。 + + //// 将两个视图添加到布局中 + //layout->addWidget(mainWebView); + //layout->addWidget(devToolsView); + //// 可以适当设置两个视图的大小比例,例如: + //// layout->setStretchFactor(0, 2); // 主视图占2份 + //// layout->setStretchFactor(1, 1); // 开发者工具视图占1份 + //myRoot.show(); + + //mainWindow.resize(1600, 900); + //mainWindow.setCentralWidget(&myRoot); + //mainWindow.show(); + + //// 如果你想在启动时自动打开开发者工具,可以触发一个“打开”事件(但setDevToolsPage本身调用后通常需要一些条件才弹出,有时需要手动在浏览器中inspected后再内置查看) + //// 更常见的做法是连接一个信号,例如页面加载完成后,或者通过一个按钮触发 devToolsView->show()。 + + //return app.exec(); + + + Spdlogger::init(spdlog::level::debug, ""); spdlog::info("[main] start ... ======================================================================"); diff --git a/src/protocol/HttpEntity.cpp b/src/protocol/HttpEntity.cpp index 30e8f37..76df57d 100644 --- a/src/protocol/HttpEntity.cpp +++ b/src/protocol/HttpEntity.cpp @@ -798,37 +798,50 @@ Errcode HttpEntity::queryDevicByCategory(const httplib::Request& req, njson& jso njson jsondata = njson::array(); auto station = Application::data().getStation(stationId); - if (station) + if (station && station->status == 1) { std::vector> vecDevice; station->getDeviceByGroup(category, vecDevice); for(auto& device: vecDevice) { - njson jsonnode; - jsonnode["stationId"] = stationId; - jsonnode["category"] = category; - jsonnode["device_id"] = device->deviceId; - jsonnode["name"] = device->name; - jsonnode["code"] = device->code; - jsonnode["type"] = device->type; - jsonnode["typename"] = Application::data().getDeviceNameById(device->type); - jsonnode["view"] = 1; - - jsonnode["is_online"] = device->online;// ? "在线" : "离线"; - jsonnode["is_error"] = device->err;// ? "故障" : "正常"; - jsonnode["is_running"] = device->running;// ? "工作" : "空闲"; - - njson jsonarrayParams = njson::array(); - VecPairSS vec; - device->getRuntimeParams(vec); - for (auto& item: vec) + if (device->isOpen) { - jsonarrayParams.push_back({{"k", item.first}, {"v", item.second}}); + njson jsonnode; + jsonnode["stationId"] = stationId; + jsonnode["category"] = category; + jsonnode["device_id"] = device->deviceId; + jsonnode["name"] = device->name; + jsonnode["code"] = device->code; + jsonnode["type"] = device->type; + jsonnode["typename"] = Application::data().getDeviceNameById(device->type); + jsonnode["view"] = 1; + jsonnode["is_online"] = device->online;// ? "在线" : "离线"; + jsonnode["is_error"] = device->err;// ? "故障" : "正常"; + jsonnode["is_running"] = device->running;// ? "工作" : "空闲"; + { + VecPairSS vec; + device->getRuntimeParams(vec); + njson jsonarrayParams = njson::array(); + for (auto& item: vec) + { + jsonarrayParams.push_back({{"k", item.first}, {"v", item.second}}); + } + jsonnode["params"] = jsonarrayParams; + } + if (device->type == 106) + { + VecPairSS vec; + device->getRuntimeParams1(vec); + njson jsonarrayParams = njson::array(); + for (auto& item: vec) + { + jsonarrayParams.push_back({{"k", item.first}, {"v", item.second}}); + } + jsonnode["params1"] = jsonarrayParams; + } + jsondata.push_back(jsonnode); } - - jsonnode["params"] = jsonarrayParams; - jsondata.push_back(jsonnode); } } json["data"] = jsondata; diff --git a/src/protocol/MqttEntity.cpp b/src/protocol/MqttEntity.cpp index 82f616e..6b25fa7 100644 --- a/src/protocol/MqttEntity.cpp +++ b/src/protocol/MqttEntity.cpp @@ -28,7 +28,7 @@ void MqttClient::loadDataStruct(std::string filename) for (auto& jsonitem : json.items()) { std::string name = jsonitem.key(); - auto jsonnodeItem = jsonitem.value(); + auto& jsonnodeItem = jsonitem.value(); //int count = jsonnodeItem["count"]; auto jsonaddrs = jsonnodeItem["addr"]; @@ -56,25 +56,34 @@ void MqttClient::loadDataStruct(std::string filename) int MqttClient::init(string addr, string clientId, string username, string password) { + if (isConnected) + { + return MQTTASYNC_SUCCESS; + } + if (addr.empty()) + { + return MQTTASYNC_FAILURE; + } + this->addr = addr; this->clientId = clientId; - //this->mapTopicInfo["EMS_YX"] = TopicInfo("EMS_YX", 101); - //this->mapTopicInfo["EMS_YC"] = TopicInfo("EMS_YC", 101); - //this->mapTopicInfo["EMS_YT"] = TopicInfo("EMS_YT", 101); - //this->mapTopicInfo["PCS_YX"] = TopicInfo("PCS_YX", 102, 1); + this->mapTopicInfo["EMS_YX"] = TopicInfo("EMS_YX", 101); + this->mapTopicInfo["EMS_YC"] = TopicInfo("EMS_YC", 101); + this->mapTopicInfo["EMS_YT"] = TopicInfo("EMS_YT", 101); + this->mapTopicInfo["PCS_YX"] = TopicInfo("PCS_YX", 102, 1); this->mapTopicInfo["PCS_YC"] = TopicInfo("PCS_YC", 102, 1); - //this->mapTopicInfo["PCU_YX"] = TopicInfo("PCU_YX", 103); - //this->mapTopicInfo["PCU_YC"] = TopicInfo("PCU_YC", 103); - //this->mapTopicInfo["BMS_YX"] = TopicInfo("BMS_YX", 104); - //this->mapTopicInfo["BMS_YC"] = TopicInfo("BMS_YC", 104); - //this->mapTopicInfo["BCU_YX"] = TopicInfo("BCU_YX", 105, 1); - //this->mapTopicInfo["BCU_YC"] = TopicInfo("BCU_YC", 105, 1); - //this->mapTopicInfo["MEM_YC"] = TopicInfo("MEM_YC", 3); - //this->mapTopicInfo["Cooling_YC"] = TopicInfo("Cooling_YC", 110); - //this->mapTopicInfo["TH_YC"] = TopicInfo("TH_YC", 111); - //this->mapTopicInfo["Gateway_YX"] = TopicInfo("Gateway_YX", 112); - //this->mapTopicInfo["Charger_YC"] = TopicInfo("Charger_YC", 113); + this->mapTopicInfo["PCU_YX"] = TopicInfo("PCU_YX", 103); + this->mapTopicInfo["PCU_YC"] = TopicInfo("PCU_YC", 103); + this->mapTopicInfo["BMS_YX"] = TopicInfo("BMS_YX", 104); + this->mapTopicInfo["BMS_YC"] = TopicInfo("BMS_YC", 104); + this->mapTopicInfo["BCU_YX"] = TopicInfo("BCU_YX", 105, 1); + this->mapTopicInfo["BCU_YC"] = TopicInfo("BCU_YC", 105, 1); + this->mapTopicInfo["MEM_YC"] = TopicInfo("MEM_YC", 3); + this->mapTopicInfo["Cooling_YC"] = TopicInfo("Cooling_YC", 110); + this->mapTopicInfo["TH_YC"] = TopicInfo("TH_YC", 111); + this->mapTopicInfo["Gateway_YX"] = TopicInfo("Gateway_YX", 112); + this->mapTopicInfo["Charger_YC"] = TopicInfo("Charger_YC", 113); MQTTAsync_connectOptions option = MQTTAsync_connectOptions_initializer; MQTTAsync_message pubmsg = MQTTAsync_message_initializer; @@ -176,6 +185,10 @@ void MqttClient::subscribe() { spdlog::error("[mqtt] subscribe [{},{}] failed, err={}", topic, qos, rc); } + else + { + spdlog::info("[mqtt] subscribe [{},{}] ", topic, qos); + } } } @@ -332,8 +345,8 @@ int MqttClient::onMessageArrived(char* topic, int topicLen, MQTTAsync_message* m if (iter != mapRegInfo.end()) { auto addr = iter->first; - std::string val = JSON::toStr(data[i]); - spdlog::info("[mqtt] read register addr: [{}]={}, {}", addr, val, iter->second.remark); + auto& val = data[i]; + //spdlog::info("[mqtt] read register addr: [{}]={}, {}", addr, val, iter->second.remark); device->setParam(addr, val); ++iter; } @@ -341,11 +354,11 @@ int MqttClient::onMessageArrived(char* topic, int topicLen, MQTTAsync_message* m } else if (data.is_number()) { - device->setParam(key, Utils::toStr(data.get())); + device->setParam(key, data.get()); } else if (data.is_string()) { - device->setParam(key, Utils::toStr(data.get())); + device->setParam(key, Utils::toInt(data.get())); } } } diff --git a/src/qt/MainWeb.cpp b/src/qt/MainWeb.cpp index 1f49cf4..32a70ba 100644 --- a/src/qt/MainWeb.cpp +++ b/src/qt/MainWeb.cpp @@ -8,6 +8,10 @@ #include #include #include +#include +#include + +#include "common/Spdlogger.h" void MySplash(MainWeb* mainWin) { @@ -44,6 +48,41 @@ MainWeb::MainWeb() this->setWindowTitle("光储充站监控与运营管理平台"); this->setGeometry(0, 0, 1920, 1080); this->hide(); + //this->setMouseTracking(true); + this->setAttribute(Qt::WA_Hover, true); + + this->initWebview(); + this->mySplash(); + + btnFullscreen.setParent(this); + btnFullscreen.raise(); + btnFullscreen.setGeometry(0, 0, 34, 34); + btnFullscreen.setStyleSheet("background: transparent; background-image: url(./assets/ui/iconFullscreen.png);"); + + QObject::connect(&btnFullscreen, &QPushButton::clicked, [=](bool checked) + { + isFullscreen ? this->showNormal() : this->showFullScreen(); + isFullscreen = !isFullscreen; + if (isFullscreen) + { + btnFullscreen.setStyleSheet("background: transparent; background-image: url(./assets/ui/iconFullscreenExit.png);"); + } + else + { + btnFullscreen.setStyleSheet("background: transparent; background-image: url(./assets/ui/iconFullscreen.png);"); + } + }); + + this->show(); +} + + +void MainWeb::initWebview() +{ + qputenv("QTWEBENGINE_REMOTE_DEBUGGING", "9222"); // 即使内置视图,有时也需要开启调试端口 + //this->setCentralWidget(&webView); + webView.setParent(this); + webView.setGeometry(0, 0, 1920, 1080); // 在加载页面之前清除缓存 //QWebEngineProfile::defaultProfile()->clearHttpCache(); @@ -52,19 +91,31 @@ MainWeb::MainWeb() //settings->setAttribute(QWebEngineSettings::LocalStorageEnabled, true); //settings->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, true); // 解决http资源加载问题 //settings->setAttribute(QWebEngineSettings::PluginsEnabled, true); - - webView.setGeometry(0, 0, 1920, 1080); // 默认设置透明, 解决加载时的白屏闪烁 //webView.page()->setBackgroundColor(Qt::transparent); //webView.setContextMenuPolicy(Qt::NoContextMenu); webView.load(QUrl(Config::option.webSrvUrl.c_str())); - this->setCentralWidget(&webView); - + webView.hide(); + // 将主 Web 页面的开发者工具页面设置为 devToolsView 的页面 + webView.page()->setDevToolsPage(devTools.page()); + QObject::connect(&webView, &QWebEngineView::loadFinished, [=](bool ok) + { + if (ok) + { + webView.show(); + } + else + { + spdlog::error("[web] webview load failed, url={}", Config::option.webSrvUrl); + webView.hide(); + } + }); +} +void MainWeb::mySplash() +{ //===动态程序启动画面=== - splash = std::make_shared(QPixmap("./assets/ui/splash.png")); - QCoreApplication::processEvents(); label1.setParent(splash.get()); label1.setStyleSheet("background-color: gray"); @@ -73,33 +124,70 @@ MainWeb::MainWeb() labelProgress.setParent(splash.get()); labelProgress.setStyleSheet("background-color: rgb(29, 54, 102)"); labelProgress.setGeometry(10, 10, 0, 20); - + splash->show(); label1.show(); labelProgress.show(); + int i = 0; + while ((++i)<100) + { + splash->showMessage(QString("Loading... %1 ms").arg(i), Qt::AlignBottom | Qt::AlignRight, Qt::black); + labelProgress.setGeometry(100, 480, i*10*0.8, 20); + QCoreApplication::processEvents(); + QThread::msleep(20); + } + splash->finish(this);//程序启动画面结束 +} - QObject::connect(&webView, &QWebEngineView::loadFinished, [=](bool ok) - { - if (ok) - { - int i = 0; - while ((++i)<100) - { - splash->showMessage(QString("Loading... %1 ms").arg(i), Qt::AlignBottom | Qt::AlignRight, Qt::black); - labelProgress.setGeometry(100, 480, i*10*0.8, 20); - QCoreApplication::processEvents(); - QThread::msleep(20); - } - splash->finish(this);//程序启动画面结束 - this->show(); - } - else - { - qDebug() << "页面加载失败!"; - // 这里可以执行加载失败后的处理 - } - }); +void MainWeb::showDevTools() +{ + if (layout) + { + //webView.setParent(this); + //QLayoutItem* item; + //while ((item = layout->takeAt(0)) != nullptr) { // 不断取出第一个项 + // //if (item->widget()) { + // // delete item->widget(); // 删除控件 + // //} + // //else if (item->layout()) { // 如果是子QLayout + // // delete item->layout(); // 删除子布局 + // //} + // delete item; // 最后删除QLayoutItem本身 + //} + //delete layout; + //layout = NULL; + } + else + { + // 如果你需要先导航主页面,然后在某个事件(如按钮点击)后显示开发者工具,可以将这行代码放在事件处理函数中。 + layout = new QHBoxLayout(this); + // 将两个视图添加到布局中 + layout->addWidget(&webView); + layout->addWidget(&devTools); + layout->setStretch(0, 2); // 主视图占2份 + layout->setStretch(1, 1); // 开发者工具视图占1份 + } +} - //this->show(); +bool MainWeb::event(QEvent* e) +{ + if (QEvent::HoverMove == e->type())//鼠标移动 + { + QHoverEvent* hoverEvent = static_cast(e); + int x = hoverEvent->pos().x(); + int y = hoverEvent->pos().y(); + + if (x > 40 || y > 40) { btnFullscreen.hide(); } + else { btnFullscreen.show(); } + } + return QWidget::event(e); +} + +void MainWeb::keyPressEvent(QKeyEvent* e) +{ + if (e->key() == Qt::Key_F12) + { + this->showDevTools(); + } } \ No newline at end of file diff --git a/src/qt/MainWeb.h b/src/qt/MainWeb.h index 96305fb..ba21914 100644 --- a/src/qt/MainWeb.h +++ b/src/qt/MainWeb.h @@ -2,15 +2,32 @@ #include #include #include +#include +#include -class MainWeb : public QMainWindow +class MainWeb : public QWidget { Q_OBJECT public: MainWeb(); + void initWebview(); + void mySplash(); + void showDevTools(); + bool event(QEvent* e); + void keyPressEvent(QKeyEvent* event); + +public: QWebEngineView webView; - std::shared_ptr splash {}; + QWebEngineView devTools; + + std::shared_ptr splash; QLabel label1; QLabel labelProgress; + + QLabel labelFullscreen; + QPushButton btnFullscreen; + bool isFullscreen = false; + + QHBoxLayout* layout = NULL; }; \ No newline at end of file