diff --git a/eUi (2).zip b/eUi (2).zip deleted file mode 100644 index 4344973..0000000 Binary files a/eUi (2).zip and /dev/null differ diff --git a/eUi (3).zip b/eUi (3).zip deleted file mode 100644 index f627253..0000000 Binary files a/eUi (3).zip and /dev/null differ diff --git a/eUi (4).zip b/eUi (4).zip deleted file mode 100644 index 9517854..0000000 Binary files a/eUi (4).zip and /dev/null differ diff --git a/eUi.7z b/eui_581.zip similarity index 71% rename from eUi.7z rename to eui_581.zip index 274ba7b..8f33274 100644 Binary files a/eUi.7z and b/eui_581.zip differ diff --git a/include/global.h b/include/global.h index 2cf9c8d..f9de8fd 100644 --- a/include/global.h +++ b/include/global.h @@ -9,7 +9,8 @@ #include #pragma execution_character_set("utf-8") const std::string softwareVersion = "2.0.2"; -const std::string euiJsonVersion = "1.0.5"; +const std::string euiJsonVersion = "1.0.6"; +#define saveImgEnable 1 #define switchToTongYongUi 1 //是否切换到通用UI界面 #define skipLogin 1 //是否跳过登录界面 #define sColor_Blue "51, 56, 69" diff --git a/include/interface.h b/include/interface.h index 97e757b..3a41d80 100644 --- a/include/interface.h +++ b/include/interface.h @@ -8,6 +8,7 @@ public: virtual void init(qtFuncBridge*,nlohmann::ordered_json& json) = 0; virtual void cleanup() = 0; virtual SQLiteDB* getDatabase() = 0; + virtual bool excuteCliCommandPreset(const QString& uuid) = 0; }; extern "C" { diff --git a/include/qtBridge.h b/include/qtBridge.h index e7393d9..933d106 100644 --- a/include/qtBridge.h +++ b/include/qtBridge.h @@ -44,7 +44,10 @@ signals: void pieWidgetAddNG(); void pieWidgetAddOK(); void histogramWidgetAddData(std::vector); - + void setPlcConnectionError(); + void setPlcConnectionOk(); + void setCamConnectionError(); + void setCamConnectionOk(); /////////////////////////////////////////////// // 切换界面 @@ -68,5 +71,9 @@ signals: void loadingWindow_clearWarningLog(); ////////////////////////////////////////////////////////////// void reInitConfig(); + + //排障 + void runCommand_addBtn(const QString& btnName, const QString& tip, const QString& uuid); + }; #pragma once \ No newline at end of file diff --git a/include/sql/qSqlBase.h b/include/sql/qSqlBase.h index 27dbac7..8eb6cfd 100644 --- a/include/sql/qSqlBase.h +++ b/include/sql/qSqlBase.h @@ -97,7 +97,20 @@ public: bool res = query.exec(sql); return res; } - + std::vector getTables() { + std::vector tables; + // 查询所有表名,排除sqlite系统表 + QString sql = "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%';"; + QSqlQuery query(m_db); + if (!query.exec(sql)) { + qDebug() << "getTables failed:" << query.lastError().text(); + return tables; + } + while (query.next()) { + tables.push_back(query.value(0).toString()); + } + return tables; + } bool dropTable(const QString& tableName) { QString sql = QString("DROP TABLE IF EXISTS %1").arg(tableName); return execute(sql); @@ -317,7 +330,7 @@ public: // 记录开始时间 auto start = high_resolution_clock::now(); // 查询表中的所有数据 - QString csvFileName = filePath + "/" + tableName + ".csv"; + QString csvFileName = filePath; QString sql = QString("SELECT * FROM \"%1\"").arg(tableName); QSqlQuery query(m_db); @@ -444,42 +457,94 @@ public: //stopAutoExport(); } std::mapcsvAndChartLink; - void addtData(const QString& snCode, const std::map& data) { - std::lock_guard locker(_mutex); - QString currentProcessCsvName = getCurrentProcessCsvName(); - if (currentProcessCsvName != currentProcessCsvNameCache) - if (_db->createTable(currentProcessCsvName, db_InitColumns)) - currentProcessCsvNameCache = currentProcessCsvName; - auto res = _db->_search(currentProcessCsvName, {}, { {"条码",snCode} }); - if (res.empty() == true)//当前数据为空时查询过去的数据是否为空 - { - auto lastRes = _db->_search(getLastProcessCsvName(), {}, { {"条码",snCode} }); - if (lastRes.empty() == true)//过去的数据也为空 则视作现在要插入的数据为全新的数据 - { - std::map insertData = data; - insertData["条码"] = snCode; - insertData["创建时间"] = QDateTime::currentDateTime().toString("hh:mm:ss"); - insertData["修改时间"] = QDateTime::currentDateTime().toString("hh:mm:ss"); - _db->_insert(currentProcessCsvName, insertData); + bool addtData(const QString& snCode, const std::map& data) { + try { + if (snCode.isEmpty()) { + qWarning() << "addtData: snCode is empty."; + return false; } - else//过去的数据不为空 更新到过去的数据上 - { - std::map updateData = data; - updateData["修改时间"] = QDateTime::currentDateTime().toString("hh:mm:ss"); - _db->_update(getLastProcessCsvName(), updateData, { {"条码",snCode} }); + if (data.empty()) { + qWarning() << "addtData: data is empty."; + return false; + } + std::lock_guard locker(_mutex); + QString currentProcessCsvName = getCurrentProcessCsvName(); + if (currentProcessCsvName != currentProcessCsvNameCache) { + if (!_db->createTable(currentProcessCsvName, db_InitColumns)) { + qWarning() << "addtData: Failed to create table:" << currentProcessCsvName; + return false; + } + currentProcessCsvNameCache = currentProcessCsvName; } - } - else//当前数据不为空 更新到当前数据上 - { - std::map updateData = data; - updateData["修改时间"] = QDateTime::currentDateTime().toString("hh:mm:ss"); - _db->_update(getCurrentProcessCsvName(), updateData, { {"条码",snCode} }); - } - if (timer.elapsed() > m_intervalMs) - { - exportCsv(); - timer.start(); + // 获取当前表的所有列名 + QSqlQuery colQuery; + QString colSql = QString("PRAGMA table_info(\"%1\")").arg(currentProcessCsvName); + QList tableColumns; + if (colQuery.exec(colSql)) { + while (colQuery.next()) { + tableColumns.append(colQuery.value(1).toString()); + } + } + + // 检查 data 中的 key 是否在表结构中,不在则新增列 + for (const auto& kv : data) { + if (!tableColumns.contains(kv.first)) { + // 默认新增为 TEXT 类型 + if (!_db->addColumn(currentProcessCsvName, kv.first, "TEXT")) { + qWarning() << "addtData: Failed to add column:" << kv.first << "to table:" << currentProcessCsvName; + // 可选择 return false 或继续 + } + } + } + + auto res = _db->_search(currentProcessCsvName, {}, { {"条码",snCode} }); + + QString nowTime = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz"); // 精度提升到毫秒 + bool opResult = false; + + if (res.empty()) { + auto lastRes = _db->_search(getLastProcessCsvName(), {}, { {"条码",snCode} }); + if (lastRes.empty()) { + // 插入新数据 + std::map insertData = data; + insertData["条码"] = snCode; + insertData["创建时间"] = nowTime; + insertData["修改时间"] = nowTime; + opResult = _db->_insert(currentProcessCsvName, insertData); + if (!opResult) { + qWarning() << "addtData: Insert failed for table:" << currentProcessCsvName << "snCode:" << snCode; + } + } else { + // 更新过去的数据 + std::map updateData = data; + updateData["修改时间"] = nowTime; + opResult = _db->_update(getLastProcessCsvName(), updateData, { {"条码",snCode} }); + if (!opResult) { + qWarning() << "addtData: Update failed for table:" << getLastProcessCsvName() << "snCode:" << snCode; + } + } + } else { + // 更新当前数据 + std::map updateData = data; + updateData["修改时间"] = nowTime; + opResult = _db->_update(getCurrentProcessCsvName(), updateData, { {"条码",snCode} }); + if (!opResult) { + qWarning() << "addtData: Update failed for table:" << getCurrentProcessCsvName() << "snCode:" << snCode; + } + } + + if (timer.elapsed() > m_intervalMs) { + exportCsv(); + timer.start(); + } + return opResult; + } catch (const std::exception& ex) { + qCritical() << "addtData: Exception caught:" << ex.what(); + return false; + } catch (...) { + qCritical() << "addtData: Unknown exception caught."; + return false; } } bool isNewData(const QString& snCode) { @@ -528,8 +593,7 @@ private: // } // delete _db; //} - void init(SQLiteDB* database_ptr = nullptr) - { + void init(SQLiteDB* database_ptr = nullptr){ std::lock_guard locker(_mutex); if (database_ptr == nullptr) _db = new SQLiteDB("./sqlDatabse/", "database"); @@ -609,20 +673,12 @@ private: return (dateStr + "白班"); // 上一班是白班 } } - //void startAutoExport(int intervalMs = 10000) { - // m_intervalMs = intervalMs; - // m_running = true; - // this->start(); - //} - //void stopAutoExport() { - // m_running = false; - // this->wait(); - //} - void exportCsv() - { + void exportCsv(){ //std::lock_guard locker(_mutex); - _db->exportTableToCSV(getLastProcessCsvName(), "./csv/", _mutex); - _db->exportTableToCSV(getCurrentProcessCsvName(), "./csv/", _mutex); + QString name = getLastProcessCsvName(); + _db->exportTableToCSV(name, "./csv/"+ name +".csv", _mutex); + name = getCurrentProcessCsvName(); + _db->exportTableToCSV(name, "./csv/" + name + ".csv", _mutex); QString currentProcessCsvName = getCurrentProcessCsvName(); if (currentProcessCsvName != currentProcessCsvNameCache) if (!_db->createTable(currentProcessCsvName, db_InitColumns)) { diff --git a/resources/icon/cam_connection_error.png b/resources/icon/cam_connection_error.png new file mode 100644 index 0000000..dedc64f Binary files /dev/null and b/resources/icon/cam_connection_error.png differ diff --git a/resources/icon/cam_connection_ok.png b/resources/icon/cam_connection_ok.png new file mode 100644 index 0000000..903b20c Binary files /dev/null and b/resources/icon/cam_connection_ok.png differ diff --git a/resources/icon/lan_connection_error.png b/resources/icon/lan_connection_error.png new file mode 100644 index 0000000..f00b195 Binary files /dev/null and b/resources/icon/lan_connection_error.png differ diff --git a/resources/icon/lan_connection_ok.png b/resources/icon/lan_connection_ok.png new file mode 100644 index 0000000..c269354 Binary files /dev/null and b/resources/icon/lan_connection_ok.png differ diff --git a/resources/resources.qrc b/resources/resources.qrc index fca8a25..b562f8e 100644 --- a/resources/resources.qrc +++ b/resources/resources.qrc @@ -37,6 +37,10 @@ icon/rollback.png icon/plugin.png icon/summary_data.png + icon/lan_connection_error.png + icon/lan_connection_ok.png + icon/cam_connection_error.png + icon/cam_connection_ok.png TongYongUiIcon/0.cameraModule.png diff --git a/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp b/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp index 7876a18..a5f8c50 100644 --- a/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp +++ b/rpcModule/rpc_finsTcp/rpc_finsTcp.cpp @@ -61,8 +61,8 @@ bool rpc_finsTcp::readData(std::vector& vec_mat, QByteArray& data) ptr = new JsonRpcClient("127.0.0.1", 9000); read_JsonRpcClient[data] = ptr; } - auto result = read_JsonRpcClient[data]->call("excuteCli", QJsonArray{QString(data)}, "finstcp"); - data = variantListToByteArray(result); + // auto result = read_JsonRpcClient[data]->call("excuteCli", QJsonArray{QString(data)}, "finstcp"); + data = ptr->finsReadCall("excuteCli", QString(data), "finstcp"); return true; } bool ifRetryCMD = false; @@ -219,52 +219,122 @@ bool JsonRpcClient::reconnect() { return false; } } +QVariant jsonToVariant(const nlohmann::json& j) +{ + if (j.is_null()) return QVariant(); + if (j.is_boolean()) return j.get(); + if (j.is_number_integer()) return j.get(); + if (j.is_number_unsigned()) return static_cast(j.get()); + if (j.is_number_float()) return j.get(); + if (j.is_string()) return QString::fromStdString(j.get()); -QVariant JsonRpcClient::call(const QString& method, const QJsonArray& params, const QString& module) { - QMutexLocker locker(&mutex_); // 确保线程安全 + if (j.is_array()) { + QVariantList list; + for (const auto& el : j) list.append(jsonToVariant(el)); + return list; + } + + if (j.is_object()) { + QVariantMap map; + for (auto it = j.begin(); it != j.end(); ++it) + map[QString::fromStdString(it.key())] = jsonToVariant(it.value()); + return map; + } + + return QVariant(); // fallback +} +QVariant JsonRpcClient::call(const QString& method, const QJsonArray& params, const QString& module) +{ + QMutexLocker locker(&mutex_); if (socket_.state() != QAbstractSocket::ConnectedState) { - qWarning() << "[JsonRpcClient] Socket not connected, trying to reconnect..."; + qWarning() << "[JsonRpcClient] Socket not connected."; if (!reconnect()) return QVariant(); } - QJsonObject request{ - {"jsonrpc", "2.0"}, - {"method", method}, - {"params", params}, - {"id", idCounter_++} - }; + QString reqStr = QString(R"({"jsonrpc":"2.0","method":"%1","params":%2,"id":%3)") + .arg(method) + .arg(QString::fromUtf8(QJsonDocument(params).toJson(QJsonDocument::Compact))) + .arg(idCounter_++); if (!module.isEmpty()) { - request["module"] = module; + reqStr += QString(R"(,"module":"%1")").arg(module); } + reqStr += "}"; - QJsonDocument doc(request); - QByteArray data = doc.toJson(QJsonDocument::Compact); - - if (socket_.write(data) == -1 || !socket_.waitForBytesWritten(1000)) { - qWarning() << "[JsonRpcClient] Write failed:" << socket_.errorString(); + if (socket_.write(reqStr.toUtf8()) == -1 || !socket_.waitForBytesWritten(1000)) { + qWarning() << "[JsonRpcClient] Write failed."; return QVariant(); } - if (!socket_.waitForReadyRead(3000)) { - qWarning() << "[JsonRpcClient] No response received:" << socket_.errorString(); + if (!socket_.waitForReadyRead(10000)) { + qWarning() << "[JsonRpcClient] Read timeout."; return QVariant(); } QByteArray responseData = socket_.readAll(); - QJsonParseError parseError; - QJsonDocument respDoc = QJsonDocument::fromJson(responseData, &parseError); - if (parseError.error != QJsonParseError::NoError) { - qWarning() << "[JsonRpcClient] JSON parse error:" << parseError.errorString(); + // 使用 nlohmann json 替代 Qt 解析 + try { + auto respJson = nlohmann::json::parse(responseData.constData(), responseData.constData() + responseData.size()); + + if (respJson.contains("error")) { + qWarning() << "[JsonRpcClient] Error:" << QString::fromStdString(respJson["error"].dump()); + return QVariant(); + } + + return jsonToVariant(respJson["result"]); + } + catch (const nlohmann::json::parse_error& e) { + qWarning() << "[JsonRpcClient] Parse error:" << e.what(); return QVariant(); } +} +QByteArray JsonRpcClient::finsReadCall(const QString& method, const QString& params, const QString& module) { + QMutexLocker locker(&mutex_); + if (socket_.state() != QAbstractSocket::ConnectedState) { + qWarning() << "[JsonRpcClient] Socket not connected."; + if (!reconnect()) return QByteArray(); + } - QJsonObject resp = respDoc.object(); - if (resp.contains("error")) { - qWarning() << "[JsonRpcClient] JSON-RPC error:" << resp["error"]; - return QVariant(); + QString reqStr = QString(R"({"jsonrpc":"2.0","method":"%1","params":["%2"],"id":%3)") + .arg(method) + .arg(params) + .arg(idCounter_++); + if (!module.isEmpty()) { + reqStr += QString(R"(,"module":"%1")").arg(module); + } + reqStr += "}"; + + if (socket_.write(reqStr.toUtf8()) == -1 || !socket_.waitForBytesWritten(1000)) { + qWarning() << "[JsonRpcClient] Write failed."; + return QByteArray(); + } + + if (!socket_.waitForReadyRead(10000)) { + qWarning() << "[JsonRpcClient] Read timeout."; + return QByteArray(); + } + + QByteArray responseData = socket_.readAll(); + + // 使用 nlohmann json 替代 Qt 解析 + try { + if (responseData.contains("error")) { + //qWarning() << "[JsonRpcClient] Error:" << QString::fromStdString(respJson["error"].dump()); + return QByteArray(); + } + int startPos = responseData.indexOf(": [") + 3; + int length = responseData.indexOf("],") - startPos; + auto splitResult = responseData.mid(startPos, length); + QByteArray result; + for (int i = 0; i < splitResult.size(); i+=3) { + result.append(splitResult[i] -48); + } + return result; + } + catch (const nlohmann::json::parse_error& e) { + qWarning() << "[JsonRpcClient] Parse error:" << e.what(); + return QByteArray(); } - return resp["result"].toVariant(); } void JsonRpcClient::writeCall(const QString& method, const QJsonArray& params, const QString& module) { if (socket_.state() != QAbstractSocket::ConnectedState) { diff --git a/rpcModule/rpc_finsTcp/rpc_finsTcp.h b/rpcModule/rpc_finsTcp/rpc_finsTcp.h index d9d9166..90cf3d4 100644 --- a/rpcModule/rpc_finsTcp/rpc_finsTcp.h +++ b/rpcModule/rpc_finsTcp/rpc_finsTcp.h @@ -20,6 +20,7 @@ #include #include #include +#include enum connectionStatus { None, Disconnected, @@ -32,6 +33,7 @@ public: JsonRpcClient(const QString& host = "127.0.0.1", quint16 port = 9000); void writeCall(const QString& method, const QJsonArray& params = {}, const QString& module = QString()); QVariant call(const QString& method, const QJsonArray& params = {}, const QString& module = QString()); + QByteArray finsReadCall(const QString& method, const QString& params = "", const QString& module = QString()); bool reconnect(); // 主动重连,或 call() 失败时调用 private: diff --git a/src/Core/back/backStruct.h b/src/Core/back/backStruct.h index 3016070..e52be03 100644 --- a/src/Core/back/backStruct.h +++ b/src/Core/back/backStruct.h @@ -5,22 +5,6 @@ typedef dsModuleBase* (*CreateFunction)(); typedef void (*ReleaseFunction)(dsModuleBase* animal); -struct correctionStruct -{ - std::vector in_X_X0Y; - std::vector in_Y_X0Y; - std::vector in_Z_X0Y; - std::vector in_Z_X0Y_Value; - std::vector in_X_X0Z; - std::vector in_Y_X0Z;; - std::vector in_Z_X0Z; - std::vector in_Y_X0Z_Value; - std::vector in_X_Y0Z; - std::vector in_Y_Y0Z; - std::vector in_Z_Y0Z; - std::vector in_X_Y0Z_Value; -}; - typedef struct { QString m_stationKy; QString key; // 相机名称 diff --git a/src/Core/back/detData.h b/src/Core/back/detData.h index 7185d35..eb18711 100644 --- a/src/Core/back/detData.h +++ b/src/Core/back/detData.h @@ -8,7 +8,10 @@ #include #include #include - +enum saveMode { + basic, + oneFile +}; //所有检测需要的数据均放在这里 class camera; class detData; @@ -16,8 +19,7 @@ class detDataManager; class triggerManager; using resultHandleCallback = std::function)>; using algoEvaluateCallback = std::function,handleAiModelManager*)>; -class detData -{ +class detData{ public: @@ -48,6 +50,8 @@ public: triggerManager* triggerPtr = nullptr;//触发器指针 一般为plc模块指针 #pragma endregion #pragma region 存图相关 + saveMode _saveMode = saveMode::basic; + QString saveObjectName = "";//存图项目名 用于与其他检测项目区分开 QMutex resultMutex;//结果图锁 std::vector resultImgs;//结果图容器 std::vector segOriginImgs;//seg检测原图容器 @@ -57,12 +61,14 @@ public: std::vector oriImgs;//原图容器 std::vector oriFormat;//原图格式 如果数量不一致直接全存bmp std::vector imgSaveNameParameter;//命名规则 str1_str2... 第一个参数已默认为相机名,在构造函数 + void customSaveParam(QString saveObjectNameIN, saveMode _saveModeIN, std::vector imgSaveNameParameterIN) { + saveObjectName = saveObjectNameIN; + _saveMode = _saveModeIN; + imgSaveNameParameter.insert(imgSaveNameParameter.end(),imgSaveNameParameterIN.begin(), imgSaveNameParameterIN.end()); + } #pragma endregion QMap additional; - detData(std::string IN_cameraKeyName) { - cameraKeyName = IN_cameraKeyName; - imgSaveNameParameter.push_back(cameraKeyName); - } + detData() {} ~detData() { for (auto& img : oriImgs) img.release(); @@ -74,8 +80,7 @@ public: img.second.release(); } }; -class detDataManager -{ +class detDataManager{ public: detDataManager(triggerManager* in_triggerManager) :_triggerManager(in_triggerManager){ @@ -84,18 +89,14 @@ public: std::unordered_map>map; QMutex dataMutex; - std::shared_ptr createDetData( - QString IN_cameraKeyName, - std::string IN_SN,int imgAmountMin, - std::vector oriFormat){ - + std::shared_ptr createDetData(QString IN_cameraKeyName,std::string IN_SN, int imgAmountMin,std::vector oriFormat) { QMutexLocker locker(&dataMutex); - std::shared_ptr dataPtr(new detData(IN_cameraKeyName.toStdString())); + std::shared_ptr dataPtr(new detData()); + dataPtr->cameraKeyName = IN_cameraKeyName.toStdString(); + dataPtr->imgSaveNameParameter.push_back(IN_cameraKeyName.toStdString()); dataPtr->oriFormat = oriFormat; dataPtr->triggerPtr = _triggerManager; dataPtr->SNcode = IN_SN; - //dataPtr->registerResultHandleCallback(resultSolver); - //dataPtr->registerAlgoEvaluateCallback(_algoEvaluateCallback); dataPtr->imgAmountMin = imgAmountMin; dataPtr->dManager = this; @@ -105,22 +106,26 @@ public: qDebug() << "创建新容器失败"; return dataPtr; } - std::shared_ptr getDetData(QString uuid) - { + std::shared_ptr createDetData() { + QMutexLocker locker(&dataMutex); + std::shared_ptr dataPtr(new detData()); + map.insert({ dataPtr->uuid,dataPtr }); + if (dataPtr == nullptr) + qDebug() << "创建新容器失败"; + return dataPtr; + } + std::shared_ptr getDetData(QString uuid){ QMutexLocker locker(&dataMutex); auto it = map.find(uuid); - if (it != map.end()) - { + if (it != map.end()) { return it->second; } return nullptr; } - bool deleteDetData(QString uuid) - { + bool deleteDetData(QString uuid) { QMutexLocker locker(&dataMutex); auto it = map.find(uuid); - if (it != map.end()) - { + if (it != map.end()) { map.erase(it); return true; } diff --git a/src/Core/back/imgSaveThreadManager.h b/src/Core/back/imgSaveThreadManager.h index 8ade4f7..c24e65f 100644 --- a/src/Core/back/imgSaveThreadManager.h +++ b/src/Core/back/imgSaveThreadManager.h @@ -4,7 +4,7 @@ #include #include #include -#define saveImgEnable 1 + enum imgSaveThreadType { oriImg, @@ -107,55 +107,48 @@ public: path = pathIn; } imgSaveThread saveThread; - QString genDirName(std::shared_ptr data, imgSaveThreadType type) { - //sqlTableDatas sqlRes = sql->selectSingleData("saveHour", data->SNcode);//查找之前的数据 - //获取关键数据 - QString imgSaveDirStr = path;//所有图片的路径 sample "D://CCD" - QString imgTypeDirStr;//二级目录,图片类型决定 sample "Result" - QString dateDirStr;//三级目录,日期决定 sample"2024-6-8" - QString hourDirStr;//四级目录,小时段决定 sample "14H" - QString okNgStr;//五级目录,OK/NG决定 sample "OK" - QString detailNameStr;//六级目录 主要是SN,如没有sn则可能是相机名称 -#pragma region 赋值 - //imgTypeDirStr - switch (type) - { - case oriImg: - imgTypeDirStr = "原图"; - break; - case resImg: - imgTypeDirStr = "结果图"; - break; - default: - imgTypeDirStr = "error"; - } + QString genDirName(std::shared_ptr data, imgSaveThreadType type, saveMode mode){ + // 一级目录(根路径) + const QString basePath = path; + + // 二级目录(图片类型) + static const QMap typeMap{ + { oriImg, "原图" }, + { resImg, "结果图" } + }; + QString imgTypeDir = typeMap.value(type, "error"); + + // 日期与小时 + QDateTime now = QDateTime::currentDateTime(); + QString dateDir = now.toString("yyyy-MM-dd"); + QString hourDir = QString("%1H").arg(now.time().hour()); + + // 检测结果 + QString resultDir; + if (!data->aiDetOK && !data->halconOK) resultDir = "NG"; + else if (!data->aiDetOK) resultDir = "aiNG"; + else if (!data->halconOK) resultDir = "halconNG"; + else resultDir = "OK"; + + if (mode == oneFile) { + - { - QDateTime currentDateTime = QDateTime::currentDateTime(); - dateDirStr = currentDateTime.toString("yyyy-MM-dd"); - hourDirStr = QString::number(currentDateTime.time().hour()) + "H//"; } - if(data->aiDetOK == false && data->halconOK == false) - okNgStr = "NG"; - else if (data->aiDetOK == false) - okNgStr = "aiNG"; - else if (data->halconOK == false) - okNgStr = "halconNG"; - else - okNgStr = "OK"; - //detailNameStr - if (data->SNcode.length() != 0 && data->SNcode.length() < 50) - detailNameStr = QString::fromStdString(data->SNcode); - else - detailNameStr = QString::fromStdString(data->cameraKeyName); -#pragma endregion - return QString(imgSaveDirStr + "/" + - imgTypeDirStr + "/" + - dateDirStr + "/" + - hourDirStr + "/" + - okNgStr + "/" + - detailNameStr + "/"); + // SN 或相机名 + QString detailName = (data->SNcode.size() > 0 && data->SNcode.size() < 50) + ? QString::fromStdString(data->SNcode) + : QString::fromStdString(data->cameraKeyName); + + // 拼接路径 + QDir dir(basePath); + dir = QDir(dir.filePath(imgTypeDir)); + dir = QDir(dir.filePath(dateDir)); + dir = QDir(dir.filePath(hourDir)); + dir = QDir(dir.filePath(resultDir)); + dir = QDir(dir.filePath(detailName)); + return dir.path() + "/"; } + std::vector genFileNames(std::shared_ptr data, imgSaveThreadType type, std::string format = "") { std::vector resultFileNames; @@ -193,9 +186,8 @@ public: return resultFileNames; } - void saveOri(std::shared_ptr data) - { - QString fileSavePath = genDirName(data, oriImg);//获取文件夹名 + void saveOri(std::shared_ptr data) { + QString fileSavePath = genDirName(data, oriImg, data->_saveMode);//获取文件夹名 createDirectoryIfNotExists(fileSavePath);//不存在此文件夹则创建 std::vectorfileNames = genFileNames(data, oriImg); @@ -205,9 +197,8 @@ public: if (queueSize > 10) qDebug() << "queueSize " << queueSize; } - void saveRes(std::shared_ptr data) - { - QString fileSavePath = genDirName(data, resImg);//获取文件夹名 + void saveRes(std::shared_ptr data){ + QString fileSavePath = genDirName(data, resImg,data->_saveMode);//获取文件夹名 createDirectoryIfNotExists(fileSavePath);//不存在此文件夹则创建 //结果图保存 std::vectorresFileNames = genFileNames(data, resImg); diff --git a/src/Core/back/triggerManager.cpp b/src/Core/back/triggerManager.cpp index 74d2c92..48547b7 100644 --- a/src/Core/back/triggerManager.cpp +++ b/src/Core/back/triggerManager.cpp @@ -25,6 +25,8 @@ triggerManager::triggerManager(detProcess* _detProcessIn, qtFuncBridge* bridgeIn triggerFileName = QString::fromStdString(triggerJson["moduleName"]); IpAndPort = QString::fromStdString(triggerJson["initStr"]); + heartBeatIntervalMS = triggerJson["heartBeatIntervalMS"]; + sleepIntervalMS = triggerJson["sleepIntervalMS"]; std::vector heartbeats = triggerJson["heartBeatCmd"]; for (auto& cmd : heartbeats) { heartBeatCmds.push_back(QString::fromStdString(cmd)); @@ -34,18 +36,16 @@ void triggerManager::run(){ if(connectHost() == false) return; QThread::msleep(1000); - int cnt = 0; + QElapsedTimer heartTimer; while (runFlag){ reciveCommond(); - QThread::msleep(10); + QThread::msleep(sleepIntervalMS); //心跳 - cnt++; - if (cnt > 100) { + if (heartTimer.elapsed()> heartBeatIntervalMS) { sendFinsMsg(heartBeatCmds[heartBeatCmdCnt++]); if(heartBeatCmdCnt >= heartBeatCmds.size()) heartBeatCmdCnt = 0; - cnt = 0; - // qDebug() << "heartbeat"; + heartTimer.start(); } } @@ -133,8 +133,23 @@ void triggerManager::decodeCameraCMD(readAllStruct& _struct, QByteArray byte) { if (byte.isEmpty()) { - qCritical() << "ERROR:cant read data from Fins,无法从fins读取数据"; + if (isConnected == true) { + lostConnectionCountTimer.start(); + std::cout<< "与PLC的连接已断开,正在尝试重连" << std::endl; + } + if (lostConnectionRePrintTimer.elapsed() > 1000) { + qCritical() << "ERROR:cant read data from Fins,无法从fins读取数据"; + emit bridge->setPlcConnectionError(); + isConnected = false; + lostConnectionRePrintTimer.start(); + } return; } + else if (isConnected == false) { + emit bridge->setPlcConnectionOk(); + isConnected = true; + qDebug() << "掉线时间:" << lostConnectionCountTimer.elapsed() / 1000.0 << "秒"; + std::cout << "重连成功,经过时间:" << lostConnectionCountTimer.elapsed() / 1000.0 << "秒" << std::endl; + } checkCallbackAndTrigger(_struct,byte); } \ No newline at end of file diff --git a/src/Core/back/triggerManager.h b/src/Core/back/triggerManager.h index 4235cb8..ab8f446 100644 --- a/src/Core/back/triggerManager.h +++ b/src/Core/back/triggerManager.h @@ -7,6 +7,7 @@ #include #include #include +#include #define switchToRpc 1 #define debugTesting 0 @@ -19,33 +20,32 @@ class detProcess; //防止重复触发 class triggerLockerT { public: - triggerLockerT() {} - ~triggerLockerT() { - lockerList.clear(); + // 不存在则返回true + bool checkLocker(int pos) const { + return lockerVec.find(pos) == lockerVec.end(); } - bool checkLocker(int pos) { - for (auto& it : lockerList) { - if (it == pos) { - return false; - } - } - return true; - } - void reFreshLocker(QByteArray& input) { - if (input.size() == 0)return; - for (auto& it : lockerList) { - if (input.at(it) == 0) { - lockerList.erase(std::remove(lockerList.begin(), lockerList.end(), it), lockerList.end()); - } - } - } - void adddLocker(int pos) { - lockerList.push_back(pos); - } - std::vectorlockerList; -private: + // 如果和加锁的值不同则删除 + void reFreshLocker(const QByteArray& input) { + for (auto it = lockerVec.begin(); it != lockerVec.end(); ) { + if (it->first >= input.size() || input.at(it->first) != it->second) { + it = lockerVec.erase(it); // erase 返回下一个迭代器 + } + else { + ++it; + } + } + } + + // 添加锁 + void addLocker(int pos, int val) { + lockerVec[pos] = val; + } + +private: + std::unordered_map lockerVec; }; + //触发器类 fins触发 tcp触发等 替代myiothread class triggerManager : public serviceModule { @@ -61,8 +61,7 @@ public: QString triggerFileName; QString IpAndPort; QString triggerInitStr; - ~triggerManager() - { + ~triggerManager(){ runFlag = false; this->stop(); this->terminate(); @@ -71,8 +70,7 @@ public: triggerManager(detProcess*, qtFuncBridge* bridgeIn, nlohmann::ordered_json& triggerJson); bool connectHost(); void run(); - void stop() - { + void stop(){ runFlag = false; this->terminate(); } @@ -206,15 +204,13 @@ public: #pragma endregion //CALL BACK - struct triggerCallbackStruct - { + struct triggerCallbackStruct{ int triggerAddress; int triggerValue; triggerCallback func; std::string funcName; }; - bool registerCallback(int triggerAddress, int triggerValue, triggerCallback func, std::string funcName ="") - { + bool registerCallback(int triggerAddress, int triggerValue, triggerCallback func, std::string funcName =""){ triggerCallbackStruct _triggerCallbackStruct; _triggerCallbackStruct.triggerAddress = triggerAddress; _triggerCallbackStruct.triggerValue = triggerValue; @@ -230,8 +226,7 @@ public: return false; } std::map> triggerCallbackFuncs; - void checkCallbackAndTrigger(readAllStruct& _struct,QByteArray & byteArray)//检查是否符合回调函数的触发条件 - { + void checkCallbackAndTrigger(readAllStruct& _struct,QByteArray & byteArray){//检查是否符合回调函数的触发条件 for (auto callback : triggerCallbackFuncs[_struct.readAllCmd]) { if (checkTrigger(callback.triggerAddress, callback.triggerValue, _struct, byteArray) == true) @@ -249,8 +244,7 @@ public: } } std::string readSnFromQByteArray(QByteArray plcByte, int dmPos, - bool highLowConversion, bool clearAfterRead, int Size) - { + bool highLowConversion, bool clearAfterRead, int Size){ int startPos = 0; for (auto& _struct : readAllCmds) { if (dmPos > _struct.startPos && @@ -262,8 +256,7 @@ public: return "ERROR_OUT_OF_RANGE"; } int triggerPos = (dmPos - startPos) * 2; - if (triggerPos < 0) - { + if (triggerPos < 0){ std::cout << "Read SN error,trigger is DM:" << dmPos << ",but read start at DM:" << startPos << endl; return "snErrorsnError" + getCurrentDateTime(); } @@ -271,20 +264,16 @@ public: if (plcByte.at(triggerPos + 1) == 0 && plcByte.at(triggerPos) == 0) return "snErrorsnError" + getCurrentDateTime(); int snCount = 0; - if (highLowConversion == true) - { - while (plcByte.at(snCount + triggerPos) != 0 || plcByte.at(snCount + triggerPos + 1) != 0) - { + if (highLowConversion == true){ + while (plcByte.at(snCount + triggerPos) != 0 || plcByte.at(snCount + triggerPos + 1) != 0){ if (plcByte.at(snCount + triggerPos) != 0) str += QChar(plcByte.at(snCount + triggerPos)); snCount++; } } - else - { - while (plcByte.at(snCount + triggerPos) != 0 || plcByte.at(snCount + triggerPos + 1) != 0) - { + else{ + while (plcByte.at(snCount + triggerPos) != 0 || plcByte.at(snCount + triggerPos + 1) != 0){ if (plcByte.at(snCount + triggerPos + 1) != 0) str += QChar(plcByte.at(snCount + triggerPos + 1)); @@ -303,6 +292,7 @@ public: } private: + QElapsedTimer lostConnectionCountTimer,lostConnectionRePrintTimer; qtFuncBridge* bridge; bool libLoadedflag = false; QLibrary* m_lib = nullptr; @@ -319,25 +309,34 @@ private: /// 值 /// QByteArray /// - bool checkTrigger(int dmPos, int value, readAllStruct& _struct, QByteArray& byte, bool lockerDisable = false) - { + bool checkTrigger(int dmPos, int value, readAllStruct& _struct, QByteArray& byte, bool lockerDisable = false){ int triggerPos = (dmPos - _struct.startPos) * 2 + 1; if (byte.size() < triggerPos) return false; - if (byte.at(triggerPos) == value) - { + if (byte.at(triggerPos) == value){ if (tLocker[_struct.readAllCmd].checkLocker(triggerPos) == false) return false; if (lockerDisable == false) - tLocker[_struct.readAllCmd].adddLocker(triggerPos); + tLocker[_struct.readAllCmd].addLocker(triggerPos, value); + return true; + } + else + return false; + } + bool checkTrigger_Unsafe(int dmPos, int value, readAllStruct& _struct, QByteArray& byte, bool lockerDisable = false) { + int triggerPos = (dmPos - _struct.startPos) * 2 + 1; + if (byte.at(triggerPos) == value) { + if (tLocker[_struct.readAllCmd].checkLocker(triggerPos) == false) + return false; + if (lockerDisable == false) + tLocker[_struct.readAllCmd].addLocker(triggerPos, value); return true; } else return false; } //接受数据 - bool reciveFinsMsg(QByteArray& readByte) - { + bool reciveFinsMsg(QByteArray& readByte){ if (!trigger->readData(vec_mat, readByte)) { qCritical() << "[TCP] " << " finstcp_ptr readData error!"; @@ -349,7 +348,8 @@ private: //解析并触发 void decodeCameraCMD(readAllStruct&,QByteArray byte); //触发器的配置 - int interval = 50;//间隔 + int sleepIntervalMS = 50;//间隔 + int heartBeatIntervalMS = 800; int heartBeatCmdCnt = 0; std::vector heartBeatCmds; #if switchToRpc==0 @@ -359,6 +359,7 @@ private: ReleaseRpcModuleBaseFunction destory_finstcp; //释放 rpcModuleBase* trigger = nullptr; #endif + bool isConnected = true; bool runFlag = true; bool init = false; std::vector vec_mat;//没啥用,一直保持为空就好 diff --git a/src/Core/backendInterface.cpp b/src/Core/backendInterface.cpp index 2d81932..de15859 100644 --- a/src/Core/backendInterface.cpp +++ b/src/Core/backendInterface.cpp @@ -28,6 +28,9 @@ public: SQLiteDB* getDatabase() { return _detProcess->dataBase; } + bool excuteCliCommandPreset(const QString& uuid) { + return _detProcess->_cliManager->excutePreset(uuid); + } private: bool initOnce = false; detProcess* _detProcess; diff --git a/src/Core/detProcess.hpp b/src/Core/detProcess.hpp index 8ca3d5a..adc1c05 100644 --- a/src/Core/detProcess.hpp +++ b/src/Core/detProcess.hpp @@ -11,9 +11,10 @@ public: CsvWriter* _csvWriter = nullptr; missonResultHandle* _missonResultHandle = nullptr; ServiceManager _serviceManager; + CLIManager* _cliManager; // 命令行接口管理器 bool initOnce = false; - detProcess():_cliManager(&_serviceManager){ - dataBase = new SQLiteDB("./DataBase/", "eui_db"); + detProcess(){ + dataBase = new SQLiteDB("./sqlDatabse/", "eui_db"); _csvWriter = new CsvWriter(dataBase); } @@ -33,6 +34,7 @@ public: _serviceManager._csvWriter = _csvWriter; _serviceManager._handleAiModelManager = new handleAiModelManager(jsonIn, bridgeIn); connect(bridgeIn, &qtFuncBridge::reInitConfig, this, [=]() {reinitConfig(); }); + _cliManager = new CLIManager(&_serviceManager, bridgeIn); } } @@ -88,6 +90,7 @@ public: json["missionSettings"], dataBase, bridge ); + _cliManager->initBasicPreset(); //_threadManager->registerResultHandleCallback( // [this](std::shared_ptr data) { // detectionResultHandle(data); @@ -110,7 +113,7 @@ private: nlohmann::ordered_json json; qtFuncBridge* bridge; MissionLoader _missionLoader; // 任务加载器,用于加载任务配置 - CLIManager _cliManager; // 命令行接口管理器 + }; #pragma once diff --git a/src/core/back/CLIManager.h b/src/core/back/CLIManager.h index 095f253..91f87f8 100644 --- a/src/core/back/CLIManager.h +++ b/src/core/back/CLIManager.h @@ -23,79 +23,131 @@ private: class CLIManager { public: - CLIManager(ServiceManager* _serviceManagerIn):_serviceManager(_serviceManagerIn){} + CLIManager(ServiceManager* _serviceManagerIn,qtFuncBridge* bridgeIn) + :_serviceManager(_serviceManagerIn), bridge(bridgeIn) {} ~CLIManager() {} - void cliCommands(const std::string& command,std::vectorargs) { - auto it = commandMap.find(command); - if (it != commandMap.end()) { - switch (it->second) { - case Trigger: - trigger(args); - break; - case Evaluate: - evaluate(args); - break; - default: - break; +#pragma region trash +// void cliCommands(const std::string& command,std::vectorargs) { +// auto it = commandMap.find(command); +// if (it != commandMap.end()) { +// switch (it->second) { +// case Trigger: +// trigger(args); +// break; +// case Evaluate: +// evaluate(args); +// break; +// default: +// break; +// } +// } else { +// std::cerr << "Unknown command: " << command << std::endl; +// } +// } +// void trigger(std::vector&args) { +// try { +//#pragma region 错误检查 +// if (_serviceManager->_triggerManager == nullptr) { +// std::cerr << "Trigger manager is not initialized." << std::endl; +// return; +// } +// if (args.size() < 1) { +// std::cerr << "Insufficient arguments for trigger command." << std::endl; +// return; +// } +// if (args[0].type() != QVariant::String) { +// std::cerr << "Invalid argument type for trigger command." << std::endl; +// return; +// } +// +//#pragma endregion +// if (args[0].toString() == "write" && args.size() >= 3) { +// bool result = _serviceManager->_triggerManager->sendFinsMsg( +// QString("write_" + args[1].toString() + "_" +// + args[2].toString() +// )); +// if (!result) +// std::cerr << "Failed to send write command." << std::endl; +// else +// std::cout << "Write command sent successfully." << std::endl; +// return; +// } +// else if (args[0].toString() == "read" && args.size() >= 2) { +// QVariant result = _serviceManager->_triggerManager->read(args[1].toInt()); +// if (result.isValid()) { +// std::cout << "Read command result: " << result.toString().toStdString() << std::endl; +// } +// else { +// std::cerr << "Failed to read data." << std::endl; +// } +// } +// } +// catch(const std::exception& e) { +// std::cerr << "Error in trigger command: " << e.what() << std::endl; +// } +// catch (...) { +// std::cerr << "Unknown error occurred in trigger command." << std::endl; +// } +// } +// void evaluate(std::vector&args) { +//#pragma region 处理错误 +// //if() +//#pragma endregion +// +// } +#pragma endregion + bool cliCommand(const QString& command) { + auto strList = command.split("#"); + if (strList[0] == "fins") { + _serviceManager->_triggerManager->sendFinsMsg(strList[1]); + return true; + } + else if (strList[0] == "reconfig") { + return true; + } + else if (strList[0] == "waitMs") { + QThread::msleep(strList[1].toInt()); + return true; + } + std::cout << "命令未定义!" << command.toStdString() << std::endl; + return false; + } + bool excutePreset(const QString& uuid) { + auto commands = presets[uuid]; + std::thread([this,commands] {for (auto& command : commands)cliCommand(command); }).detach(); + return true; + } + void addPreset(const QString& btnName, QStringList commands) { + presets[btnName] = commands; + + } + void initBasicPreset() { + for (auto& data : _serviceManager->_triggerManager->triggerCallbackFuncs) { + for (auto& callbacks : data.second) { + QString uuid = QUuid::createUuid().toString();; + auto commands = basicTriggerPresetGenerate(callbacks.triggerAddress); + QString tips; + for(auto& cmd : commands) { + tips += cmd + "\n"; + } + emit bridge->runCommand_addBtn( + QString::fromStdString(callbacks.funcName),tips,uuid); + presets[uuid] = commands; } - } else { - std::cerr << "Unknown command: " << command << std::endl; } } - - void trigger(std::vector&args) { - try { -#pragma region 错误检查 - if (_serviceManager->_triggerManager == nullptr) { - std::cerr << "Trigger manager is not initialized." << std::endl; - return; - } - if (args.size() < 1) { - std::cerr << "Insufficient arguments for trigger command." << std::endl; - return; - } - if (args[0].type() != QVariant::String) { - std::cerr << "Invalid argument type for trigger command." << std::endl; - return; - } - -#pragma endregion - if (args[0].toString() == "write" && args.size() >= 3) { - bool result = _serviceManager->_triggerManager->sendFinsMsg( - QString("write_" + args[1].toString() + "_" - + args[2].toString() - )); - if (!result) - std::cerr << "Failed to send write command." << std::endl; - else - std::cout << "Write command sent successfully." << std::endl; - return; - } - else if (args[0].toString() == "read" && args.size() >= 2) { - QVariant result = _serviceManager->_triggerManager->read(args[1].toInt()); - if (result.isValid()) { - std::cout << "Read command result: " << result.toString().toStdString() << std::endl; - } - else { - std::cerr << "Failed to read data." << std::endl; - } - } - } - catch(const std::exception& e) { - std::cerr << "Error in trigger command: " << e.what() << std::endl; - } - catch (...) { - std::cerr << "Unknown error occurred in trigger command." << std::endl; - } - } - void evaluate(std::vector&args) { -#pragma region 处理错误 - //if() -#pragma endregion - + QStringList basicTriggerPresetGenerate(int& triggerAddress) { + QString triggerAddressStr = QString::number(triggerAddress); + return { + "fins#write_short_"+ triggerAddressStr +"_1", + "waitMs#500", + "fins#write_short_" + triggerAddressStr + "_0", + }; } private: + qtFuncBridge* bridge; + QMap presets; ServiceManager* _serviceManager; enum CommandType { Trigger, diff --git a/eUi.zip b/src/core/fuck-u-code-windows-amd64.exe similarity index 54% rename from eUi.zip rename to src/core/fuck-u-code-windows-amd64.exe index 5ae1054..c9da3c8 100644 Binary files a/eUi.zip and b/src/core/fuck-u-code-windows-amd64.exe differ diff --git a/src/launcher/GUI/front/pages/displayPageWidget.h b/src/launcher/GUI/front/pages/displayPageWidget.h index 5945e21..4485f73 100644 --- a/src/launcher/GUI/front/pages/displayPageWidget.h +++ b/src/launcher/GUI/front/pages/displayPageWidget.h @@ -14,6 +14,7 @@ #include #include #include +#include class displayWidget :public QWidget { Q_OBJECT @@ -29,7 +30,8 @@ public: dayNightShiftHistogramWidget* _dayNightShiftHistogramWidget; userSwitch* _userSwitch; softwareDataDisplay* _softwareDataDisplay; - //uiModuleLocationMap* _uiModuleLocationMap = new uiModuleLocationMap(); + ConnectionWidget* _ConnectionWidget = new ConnectionWidget(this); + runCommandWidget* _runCommandWidget; LogWindow* log = new LogWindow(); displayWidget(appConfig* config) :m_config(config) { @@ -172,12 +174,13 @@ public: lineWidgetJustForShow->setFixedWidth(5); titleLayout->addWidget(lineWidgetJustForShow); QFont font3("微软雅黑", 10, QFont::Bold); +#pragma region 日志分析按钮 { QVBoxLayout* btnLayout = new QVBoxLayout(); QPushButton* btn = new QPushButton(this); btn->setIcon(QIcon(":/TongYongUiIcon/TongYongUiIcon/4.LogAnalyze.png")); btn->setFixedSize(QSize(50, 50)); - btn->setIconSize(QSize(25, 25)); // 设置图标大小,保持等比例(根据你图标原始比例设置合适尺寸) + btn->setIconSize(QSize(25, 25)); btn->setStyleSheet(R"( QPushButton { background-color: transparent; @@ -198,12 +201,14 @@ public: emit changeStackWidget(2); }); } +#pragma endregion +#pragma region 打开配置文件按钮 { QVBoxLayout* btnLayout = new QVBoxLayout(); QPushButton* btn = new QPushButton(this); btn->setIcon(QIcon(":/TongYongUiIcon/TongYongUiIcon/9.paramSetting.png")); btn->setFixedSize(QSize(50, 50)); - btn->setIconSize(QSize(25, 25)); // 设置图标大小,保持等比例(根据你图标原始比例设置合适尺寸) + btn->setIconSize(QSize(25, 25)); btn->setStyleSheet(R"( QPushButton { background-color: transparent; @@ -224,11 +229,13 @@ public: QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(config->settingJsonPath))); }); } +#pragma endregion +#pragma region 结果图查看按钮 { QVBoxLayout* btnLayout = new QVBoxLayout(); QPushButton* btn = new QPushButton(this); btn->setIcon(QIcon(":/TongYongUiIcon/TongYongUiIcon/23.1.imageView.png")); - btn->setIconSize(QSize(50, 50)); // 设置图标大小,保持等比例(根据你图标原始比例设置合适尺寸) + btn->setIconSize(QSize(50, 50)); btn->setStyleSheet(R"( QPushButton { background-color: transparent; @@ -249,23 +256,74 @@ public: QDesktopServices::openUrl(QUrl::fromLocalFile(QString::fromStdString(config->imgSavePath))); }); } - +#pragma endregion +#pragma region 修改检测参数按钮 + { + QVBoxLayout* btnLayout = new QVBoxLayout(); + QPushButton* btn = new QPushButton(this); + btn->setIcon(QIcon(":/TongYongUiIcon/TongYongUiIcon/search_1.png")); + btn->setFixedSize(QSize(75, 50)); + btn->setIconSize(QSize(25, 25)); + btn->setStyleSheet(R"( + QPushButton { + background-color: transparent; + border: none; + } + QPushButton:hover { + background-color: black; + border-radius: 5px; + } + )"); + QLabel* text = new QLabel("修改检测参数"); + text->setFont(font3); + text->setPalette(palette); + btnLayout->addWidget(btn); + btnLayout->addWidget(text); + titleLayout->addLayout(btnLayout); + connect(btn, &QPushButton::clicked, [=]() { + JsonParamTableEditor* dlg = new JsonParamTableEditor(this); + dlg->setJsonObject(m_config->settingJson["backend"]["missionSettings"]), + dlg->setAttribute(Qt::WA_DeleteOnClose); + connect(dlg, &JsonParamTableEditor::jsonAccepted, [this](const nlohmann::json& result) { + m_config->settingJson["backend"]["missionSettings"] = result; + }); + dlg->show(); }); + } +#pragma endregion +#pragma region 故障排查按钮 + { + QVBoxLayout* btnLayout = new QVBoxLayout(); + QPushButton* btn = new QPushButton(this); + btn->setIcon(QIcon(":/TongYongUiIcon/TongYongUiIcon/18.help.png")); + btn->setFixedSize(QSize(50, 50)); + btn->setIconSize(QSize(25, 25)); + btn->setStyleSheet(R"( + QPushButton { + background-color: transparent; + border: none; + } + QPushButton:hover { + background-color: black; + border-radius: 5px; + } + )"); + QLabel* text = new QLabel("故障排查"); + text->setFont(font3); + text->setPalette(palette); + btnLayout->addWidget(btn); + btnLayout->addWidget(text); + titleLayout->addLayout(btnLayout); + _runCommandWidget = new runCommandWidget(); + connect(btn, &QPushButton::clicked, [=]() { + _runCommandWidget->show(); }); + } +#pragma endregion QWidget* spacerWidget = new QWidget; spacerWidget->setMaximumWidth(1920); titleLayout->addWidget(spacerWidget, 1); #endif - fancyButtonText* btn = new fancyButtonText(200, 50, u8"修改检测参数", ""); - connect(btn, &QPushButton::clicked, [=]() { - JsonParamTableEditor* dlg = new JsonParamTableEditor(this); - dlg->setJsonObject(m_config->settingJson["backend"]["missionSettings"]), - dlg->setAttribute(Qt::WA_DeleteOnClose); - connect(dlg, &JsonParamTableEditor::jsonAccepted, [this](const nlohmann::json& result) { - m_config->settingJson["backend"]["missionSettings"] = result; - }); - dlg->show(); }); - - - titleLayout->addWidget(btn); + + titleLayout->addWidget(_ConnectionWidget); vLayout->addWidget(titleWidget); vLayout->addWidget(&_ImageWidgetManager); diff --git a/src/launcher/GUI/front/pages/sqlControlWidget.cpp b/src/launcher/GUI/front/pages/sqlControlWidget.cpp deleted file mode 100644 index de61c95..0000000 --- a/src/launcher/GUI/front/pages/sqlControlWidget.cpp +++ /dev/null @@ -1,243 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -sqliteReader::sqliteReader() -{ - readIniFile(".//config//sqliteReader.ini"); - //_sqlManager = &_core._appConfig._sqlManager; - //std::vector res=_sqlManager->getTableList(); - //widgetInit(res); -} - -sqliteReader::~sqliteReader() -{ - //_sqlManager.uninitlize(); -} -void sqliteReader::widgetInit(std::vectortables) -{ - //1 - layout1 = new QVBoxLayout(); - this->setLayout(layout1); - - //1-1 - QWidget* vLayout2Widget = new QWidget(); - QHBoxLayout * vLayoutt2 = new QHBoxLayout(); - vLayout2Widget->setLayout(vLayoutt2); - layout1->addWidget(vLayout2Widget); - - //1-1-1 - QLabel* vLayout2Label = new QLabel(u8"请选择日期"); - vLayoutt2->addWidget(vLayout2Label); - - QComboBox * Layou2MBox = new QComboBox(); - for (auto &data : tables) - { - Layou2MBox->addItem(QString::fromStdString(data)); - } - vLayoutt2->addWidget(Layou2MBox); - connect(Layou2MBox, QOverload::of(&QComboBox::currentIndexChanged), this, [=]() {switchWidget(Layou2MBox->currentText().toStdString()); }); - - QLabel* vLayout2Label2 = new QLabel(u8"根据SN查询"); - vLayoutt2->addWidget(vLayout2Label2); - - QLineEdit *Layout2LEdit = new QLineEdit(); - vLayoutt2->addWidget(Layout2LEdit); - - QPushButton* layout2QPBtn = new QPushButton(u8"查询"); - vLayoutt2->addWidget(layout2QPBtn); - - QPushButton* dumpCsvBtn = new QPushButton(u8"导出为csv"); - vLayoutt2->addWidget(dumpCsvBtn); - - connect(layout2QPBtn,& QPushButton::clicked, this, [=]() {searchSN(Layou2MBox->currentText().toStdString(), Layout2LEdit->text().toStdString()); }); - connect(dumpCsvBtn, &QPushButton::clicked, this, [=]() {_dumpToExcel.mainWidget->show(); }); - //1-2 - tableWidget = new QTableWidget(); - - - layout1->addWidget(tableWidget); - switchWidget(Layou2MBox->currentText().toStdString()); - -} -void sqliteReader::switchWidget(std::string tableName) -{ -#if 0 - sqlTableDatas res = _sqlManager->selectAllData(tableName); - tableWidget->clear(); - delete tableWidget; - tableWidget = new QTableWidget(); - tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); - layout1->addWidget(tableWidget); - if (res.rowDatas.size() > 0) - { - int colsNum = res.rowDatas[0].size() + 1 - avoidMap.size(); - tableWidget->setColumnCount(colsNum); - //tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("SN")); - //for (int i = 0; i < res.at(0).dataVec.size(); i++) - //创建列名 - { - int index = 0; - std::unordered_map::iterator it; - std::unordered_map::iterator it2; - - for (auto&data : res.rowDatas[0]) - { - it = avoidMap.find(QString::fromStdString(data.key)); - if (it == avoidMap.end()) - { - QString Name = QString::fromStdString(data.key); - it2 = cuttomName.find(Name); - if (it2 != cuttomName.end()) - Name = it2->second; - tableWidget->setHorizontalHeaderItem(index, new QTableWidgetItem(Name)); - index++; - } - } - } - //tableWidget->setColumnCount(res.size()); - for (int i = 0; i < res.rowDatas.size(); i++) - { - //for (auto& data : res.rowDatas[0]) - { - int row = tableWidget->rowCount(); - tableWidget->insertRow(row); - //tableWidget->setItem(row, 0, new QTableWidgetItem(QString::fromStdString(data.key))); - { - int index = 0; - std::unordered_map::iterator it; - for (auto& data : res.rowDatas[i]) - { - it = avoidMap.find(QString::fromStdString(data.key)); - if (it == avoidMap.end()) - { - tableWidget->setItem(row, index, new QTableWidgetItem(QString::fromStdString(data.value))); - index++; - } - } - } - } - } - } -#endif - //tableWidget->horizontalHeader -} -void sqliteReader::searchSN(std::string tableName, std::string SN) -{ -#if 0 - sqlTableDatas res = _sqlManager->selectRowData(SN); - tableWidget->clear(); - delete tableWidget; - tableWidget = new QTableWidget(); - layout1->addWidget(tableWidget); - if (res.rowDatas.size()>0)//非空 - { - tableWidget->setColumnCount(res.rowDatas[0].size() - avoidMap.size()); - //tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("SN")); - { - int index = 0; - std::unordered_map::iterator it; - std::unordered_map::iterator it2; - for (auto&data : res.rowDatas[0]) - { - it = avoidMap.find(QString::fromStdString(data.key)); - if (it == avoidMap.end()) - { - QString Name = QString::fromStdString(data.key); - it2 = cuttomName.find(Name); - if (it2 != cuttomName.end()) - Name = it2->second; - tableWidget->setHorizontalHeaderItem(index, new QTableWidgetItem(Name)); - index++; - } - } - } - - //tableWidget->setColumnCount(res.dataVec.size()); - - int row = tableWidget->rowCount(); - tableWidget->insertRow(row); - { - int index = 0; - std::unordered_map::iterator it; - for (auto&data : res.rowDatas[0]) - { - it = avoidMap.find(QString::fromStdString(data.key)); - if (it == avoidMap.end()) - { - tableWidget->setItem(row, index, new QTableWidgetItem(QString::fromStdString(data.value))); - index++; - } - } - } - } - else - { - if(res.rowDatas.size()!=0) - { - tableWidget->setColumnCount(res.rowDatas[0].size() + 1); - tableWidget->setHorizontalHeaderItem(0, new QTableWidgetItem("SN")); - tableWidget->setColumnCount(1); - } - - int row = tableWidget->rowCount(); - tableWidget->insertRow(row); - tableWidget->setItem(row, 0, new QTableWidgetItem(u8"找不到该数据!")); - } - -#endif - //tableWidget->horizontalHeader -} - -bool sqliteReader::readIniFile(const QString &filePath) { - //std::unordered_map avoiData; - //std::unordered_map cutomName; - QFile file(filePath); - - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - QTextStream in(&file); - QString currentSection; - - while (!in.atEnd()) { - QString line = in.readLine().trimmed(); - if (line.startsWith('[') && line.endsWith(']')) { - // This line is a section header - currentSection = line.mid(1, line.length() - 2); - } - else if (!line.isEmpty() && !line.startsWith(';') && !currentSection.isEmpty()) { - // This line is a key-value pair within a section - int separatorIndex = line.indexOf('='); - if (separatorIndex != -1) { - if (!currentSection.compare("avoid")) - { - QString key = line.left(separatorIndex).trimmed(); - QString value = line.mid(separatorIndex + 1).trimmed(); - if (!value.compare("true")) - avoidMap.insert({ key, value }); - } - else if (!currentSection.compare("customName")) - { - QString key = line.left(separatorIndex).trimmed(); - QString value = line.mid(separatorIndex + 1).trimmed().toUtf8(); - cuttomName.insert({ key, value }); - } - } - } - } - - file.close(); - } - else - { - file.close(); - return false; - } - - return true; -} \ No newline at end of file diff --git a/src/launcher/GUI/front/pages/sqlControlWidget.h b/src/launcher/GUI/front/pages/sqlControlWidget.h index ac107a1..9dafbc8 100644 --- a/src/launcher/GUI/front/pages/sqlControlWidget.h +++ b/src/launcher/GUI/front/pages/sqlControlWidget.h @@ -1,28 +1,140 @@ #include #include #include - +#include +#include #include #include #include #include +#include +#include class sqliteReader : public QWidget { Q_OBJECT public: - sqliteReader(); - ~sqliteReader(); - QVBoxLayout* layout1; - QTableWidget* tableWidget; - //sqlManager* _sqlManager; - dumpToExcel _dumpToExcel; - std::unordered_mapavoidMap;//不显示该数据 - std::unordered_mapcuttomName;//自定义列名 - void widgetInit(std::vectortables); - void switchWidget(std::string tableNam); - void searchSN(std::string tableNam, std::string SN); - bool readIniFile(const QString& filePath); + sqliteReader() { + QFont font("微软雅黑", 12, QFont::Bold); + QPalette palette; + palette.setColor(QPalette::WindowText, Qt::white); + + //1-1 + QHBoxLayout* vLayout = new QHBoxLayout(); + layout->addLayout(vLayout); + + //1-1-1 + QLabel* showLabel = new QLabel(u8"班次"); + showLabel->setFont(font); + showLabel->setPalette(palette); + vLayout->addWidget(showLabel); + + tableSelectComboBox->setFixedWidth(150); + vLayout->addWidget(tableSelectComboBox); + connect(tableSelectComboBox, QOverload::of(&QComboBox::currentIndexChanged), + this, [=]() {switchWidget(tableSelectComboBox->currentText()); }); + + refreshBtn->setFont(font); + refreshBtn->setPalette(palette); + vLayout->addWidget(refreshBtn); + connect(refreshBtn, &QPushButton::clicked, + this, [=]() {refreshTable(); }); + + QLabel* showLabel2 = new QLabel(u8"SN查询"); + showLabel2->setFont(font); + showLabel2->setPalette(palette); + vLayout->addWidget(showLabel2); + + QLineEdit* snInputLineEdit = new QLineEdit(); + vLayout->addWidget(snInputLineEdit); + + vLayout->addWidget(searchSnBtn); + connect(searchSnBtn, &QPushButton::clicked, this, [=]() {searchSN(tableSelectComboBox->currentText(), snInputLineEdit->text()); }); + + vLayout->addWidget(dumpToCsvBtn); + connect(dumpToCsvBtn, &QPushButton::clicked, this, [=]() {dumpToCsv(tableSelectComboBox->currentText()); }); + //1-2 + layout->addWidget(tableWidget); + } + appConfig* _config; + //QTableView* view = new QTableView; + + void refreshTable() { + tableSelectComboBox->clear(); + auto tables = _config->g_db->getTables(); + for (int i = tables.size() - 1; i > 0 ; i--){ + if (!tables[i].contains("set")) + tableSelectComboBox->addItem(tables[i]); + } + } + void switchWidget(QString tableName) { + QSqlQueryModel* model = new QSqlQueryModel; + model->setQuery("SELECT * from \"" + tableName + "\""); + + if (model->lastError().isValid()) { + qDebug() << "查询失败:" << model->lastError().text(); + return; + } + tableWidget->setModel(model); + } + void searchSN(QString tableName, QString SN) { + // Construct SQL query to search for SN in the specified table + QString queryStr = QString("SELECT * FROM \"%1\" WHERE 条码 = '%2'") + .arg(tableName) + .arg(SN); + + QSqlQueryModel* model = new QSqlQueryModel; + model->setQuery(queryStr); + + if (model->lastError().isValid()) { + qDebug() << "SN查询失败:" << model->lastError().text(); + // Optionally clear the table or show an error + tableWidget->setModel(nullptr); + return; + } + + tableWidget->setModel(model); + } + void dumpToCsv(QString tableName) { + // 打开文件管理器,默认文件名为表名.csv + QString filePath = QFileDialog::getSaveFileName( + this, + u8"导出为CSV", + QDir::homePath() + "/" + tableName + ".csv", + u8"CSV文件 (*.csv)" + ); + + if (filePath.isEmpty()) { + return; // 用户取消 + } + + // 导出数据 + bool success = false; + if (_config && _config->g_db) { + std::mutex mutex; + success = _config->g_db->exportTableToCSV(tableName, filePath, mutex); + } + + // 提示导出结果 + if (success) { + QMessageBox::information(this, u8"导出成功", u8"数据已成功导出到:\n" + filePath); + } else { + QMessageBox::warning(this, u8"导出失败", u8"导出CSV文件失败,请检查路径或数据库状态。"); + } + } + +private: + QComboBox* tableSelectComboBox = new QComboBox(); + QVBoxLayout* layout = new QVBoxLayout(this); + QTableView* tableWidget = new QTableView(); + fancyButtonText* refreshBtn = new fancyButtonText(80, 25, u8"刷新", ""); + fancyButtonText* searchSnBtn = new fancyButtonText(80, 25, u8"查询", ""); + fancyButtonText* dumpToCsvBtn = new fancyButtonText(80, 25, u8"导出", ""); +protected: + void showEvent(QShowEvent* event) override { + QWidget::showEvent(event); + refreshTable(); + } }; class sqlControlWidget :public QWidget { @@ -36,8 +148,15 @@ public: QTableWidget* sqlWidget = new QTableWidget(); QLabel* disconnnectedLabel = new QLabel("服务已离线"); - sqlControlWidget() - { + sqlControlWidget(appConfig* _configIN){ + _sqliteReader._config = _configIN; + this->setObjectName("sqlControlWidget"); + this->setStyleSheet(R"( + QWidget#sqlControlWidget { + background: rgb(50, 55, 60); + border-radius: 10px; /* 圆角半径 */ + } + )"); QPalette palette; palette.setColor(QPalette::WindowText, Qt::white); QFont font("微软雅黑", 24, QFont::Bold); @@ -70,8 +189,8 @@ public: //btnLayout->addWidget(sqlWidget); Layout->addLayout(btnLayout); - Layout->addWidget(&_sqliteReader); + } }; #pragma once \ No newline at end of file diff --git a/src/launcher/GUI/front/pages/summary_data_page.h b/src/launcher/GUI/front/pages/summary_data_page.h index f45f3eb..34d1d62 100644 --- a/src/launcher/GUI/front/pages/summary_data_page.h +++ b/src/launcher/GUI/front/pages/summary_data_page.h @@ -398,10 +398,8 @@ protected: QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); - int radius = 10; // 圆角半径 + int radius = 10; QRect r = rect(); - - // 填充圆角背景 painter.setBrush(QColor(50, 55, 60)); painter.setPen(Qt::NoPen); painter.drawRoundedRect(r, radius, radius); diff --git a/src/launcher/GUI/mainwindow.cpp b/src/launcher/GUI/mainwindow.cpp index 501f2a8..ec62954 100644 --- a/src/launcher/GUI/mainwindow.cpp +++ b/src/launcher/GUI/mainwindow.cpp @@ -245,7 +245,7 @@ void MainWindow::leftBarInit(){ registerPageBar(":/icon/icon/config.png", u8"日志", _logWidget); //手动检测 - _manualDetWidget = new manualDetWidget(); + //_manualDetWidget = new manualDetWidget(m_config); //registerPageBar(":/icon/icon/cycleButton.png", u8"手动检测", _manualDetWidget); //历史图片 @@ -253,7 +253,7 @@ void MainWindow::leftBarInit(){ //registerPageBar(":/icon/icon/history.png", u8"历史图片", _historyWidget); //SQL - _sqlControlWidget = new sqlControlWidget(); + _sqlControlWidget = new sqlControlWidget(config); registerPageBar(":/icon/icon/sql.png", u8"数据库", _sqlControlWidget); //PLUGIN diff --git a/src/launcher/GUI/mainwindow.h b/src/launcher/GUI/mainwindow.h index ee9b7b0..bd4b71c 100644 --- a/src/launcher/GUI/mainwindow.h +++ b/src/launcher/GUI/mainwindow.h @@ -290,7 +290,7 @@ signals: protected: void mouseDoubleClickEvent(QMouseEvent* event) override { - if (event->pos().y() > 35) + if (event->pos().y() < 35) return toggleMaximize(reverse); QMainWindow::mouseDoubleClickEvent(event); diff --git a/src/launcher/GUI/uiModule/uiModule_952BiaoDingSwitch.h b/src/launcher/GUI/uiModule/uiModule_952BiaoDingSwitch.h index d64e221..50ecfa3 100644 --- a/src/launcher/GUI/uiModule/uiModule_952BiaoDingSwitch.h +++ b/src/launcher/GUI/uiModule/uiModule_952BiaoDingSwitch.h @@ -119,7 +119,6 @@ public: // 设置按钮显示√ SaveBtn.setText("√"); SaveBtn.toGreen(); - // 创建一个定时器 QTimer::singleShot(1000, [=]() mutable { // 一秒后还原文本 SaveBtn.toDefault(); diff --git a/src/launcher/GUI/uiModule/uiModule_dsStatsWidget.h b/src/launcher/GUI/uiModule/uiModule_dsStatsWidget.h index c35fd6f..120e7b0 100644 --- a/src/launcher/GUI/uiModule/uiModule_dsStatsWidget.h +++ b/src/launcher/GUI/uiModule/uiModule_dsStatsWidget.h @@ -104,5 +104,70 @@ private: QMutex mutex; int okCnt = 0, ngCnt = 0; }; - +class stateLabel :public QLabel { +public: + QPixmap okImg, errorImg; + QTimer* timer = nullptr; + QPixmap transparent; + bool blink = false; + stateLabel(QString okImgPath,QString errorImgPath, QWidget* parent = nullptr) { + okImg = QPixmap(okImgPath).scaled(25, 25, Qt::KeepAspectRatio, Qt::SmoothTransformation); + errorImg = QPixmap(errorImgPath).scaled(25, 25, Qt::KeepAspectRatio, Qt::SmoothTransformation); + transparent = QPixmap(okImg); + transparent.fill(Qt::transparent); // 透明图片 + this->setPixmap(okImg); + this->setAlignment(Qt::AlignCenter); + } + void setOK() { + blink = false; + this->setPixmap(okImg); + if (timer != nullptr) { + delete timer; + timer = nullptr; + } + } + void setError() { + if (!timer) { + //this->setPixmap(errorImg); + timer = new QTimer(this); + connect(timer, &QTimer::timeout, this, [this]() mutable { + blink = !blink; + if (blink == false) { + this->setPixmap(transparent); + } + else { + this->setPixmap(errorImg); + } + }); + } + if (!timer->isActive()) + timer->start(600); + } +}; +class ConnectionWidget : public QWidget { +public: + QVBoxLayout* layout = new QVBoxLayout(this); + stateLabel* lanConnectonLabel = new stateLabel(":/icon/icon/lan_connection_ok.png", ":/icon/icon/lan_connection_error.png",this); + stateLabel* camConnectonLabel = new stateLabel(":/icon/icon/cam_connection_ok.png", ":/icon/icon/cam_connection_error.png", this); + QPixmap lanConnectionOk, lanConnectionError, camConnectionOK, camConnectionError; + QTimer* timer1 = nullptr,*timer2 = nullptr; + QPixmap transparent1, transparent2; + ConnectionWidget(QWidget* parent = nullptr) : + QWidget(parent){ + layout->addWidget(lanConnectonLabel); + layout->addWidget(camConnectonLabel); + } + void setPlcConnected() { + lanConnectonLabel->setOK(); + } + void setPlcDisconnected() { + lanConnectonLabel->setError(); + } + void setCamConnected() { + camConnectonLabel->setOK(); + } + void setCamDisconnected() { + camConnectonLabel->setError(); + } +}; #pragma once \ No newline at end of file diff --git a/src/launcher/GUI/uiModule/uiModule_imageView.h b/src/launcher/GUI/uiModule/uiModule_imageView.h index 83f6232..980995d 100644 --- a/src/launcher/GUI/uiModule/uiModule_imageView.h +++ b/src/launcher/GUI/uiModule/uiModule_imageView.h @@ -250,7 +250,7 @@ class ImageWidget : public QWidget { Q_OBJECT public: QComboBox switchBox; - QMutex switchBoxMutex; + QMutex switchViewerMutex; ImageWidget(QWidget* parent = nullptr) : QWidget(parent) { QVBoxLayout* layout = new QVBoxLayout(this); setObjectName("ImageWidget"); @@ -267,23 +267,22 @@ public: QFont font("微软雅黑", 8 , QFont::Bold); QWidget* hWidget = new QWidget(this); QHBoxLayout* hLayout = new QHBoxLayout(hWidget); - hWidget->setFixedHeight(15); -#if switchToTongYongUi == 0 + hWidget->setFixedHeight(16); + auto spaceItem = new QSpacerItem(100, 1); hLayout->addSpacerItem(spaceItem); -#endif + label = new QLabel(u8"相机标签"); label->setAlignment(Qt::AlignLeft); label->setFont(font); label->setPalette(palette); - label->setFixedHeight(10 * 2); + label->setFixedHeight(21); + switchBox.setFont(font); switchBox.setPalette(palette); + switchBox.setFixedHeight(21); switchBox.setFixedWidth(100); - -#if switchToTongYongUi == 1 - switchBox.hide(); -#endif + connect(&switchBox, &QComboBox::currentTextChanged, [=](QString type) { switchViewType(type); @@ -333,7 +332,7 @@ public slots: //combobox切换槽 void switchViewType(QString name) { - QMutexLocker locker(&switchBoxMutex); + QMutexLocker locker(&switchViewerMutex); auto& it = map.find(name); if (it == map.end()) { @@ -363,7 +362,7 @@ public slots: return; } it.value() = std::make_shared(resImgInput); - QMutexLocker locker(&switchBoxMutex); + QMutexLocker locker(&switchViewerMutex); if (type == switchBox.currentText()) showImgOnGraphicsView(resImgInput); } diff --git a/src/launcher/GUI/uiModule/uiModule_runCommand.h b/src/launcher/GUI/uiModule/uiModule_runCommand.h new file mode 100644 index 0000000..030b158 --- /dev/null +++ b/src/launcher/GUI/uiModule/uiModule_runCommand.h @@ -0,0 +1,52 @@ +#include +#include +#include +#include + +class runCommandWidget : public QDialog { + Q_OBJECT +public: + explicit runCommandWidget(QWidget* parent = nullptr) + : QDialog(parent) { + this->setWindowTitle("执行命令"); + this->resize(400, 800); + //setWindowFlags(this->windowFlags() | Qt::FramelessWindowHint); // 去掉边框 //现在、、 + //setAttribute(Qt::WA_TranslucentBackground); // 背景透明 + this->setObjectName("JsonParamTableEditor"); + this->setStyleSheet(QString("QDialog#JsonParamTableEditor {background-color: rgb(%1);border: 2px solid #000000;border-radius: 6px;}").arg(sColor_Blue)); + + btnWidgets = new QListWidget(this); + btnWidgets->setStyleSheet("background: transparent;"); + QVBoxLayout* layout = new QVBoxLayout(this); + layout->addWidget(btnWidgets); + this->setFixedSize(sizeX, sizeY); + } + +signals: + void excuteCommandPreset(QString uuid); + +public slots: + void addBtn(const QString& btnName, const QString& tip, const QString& uuid) { + QListWidgetItem* item = new QListWidgetItem(btnWidgets); + item->setSizeHint(QSize(sizeX - 30, 30)); + btnWidgets->addItem(item); + fancyButtonText* funcBtn = new fancyButtonText(sizeX - 30, 30, btnName, tip); + btnWidgets->setItemWidget(item, funcBtn); + connect(funcBtn, &fancyButtonText::clicked, this, [this, uuid]() { + QMessageBox::StandardButton reply; + reply = QMessageBox::question( + this, // 父窗口 + "提示", // 标题 + "确定要执行此操作吗?", // 内容 + QMessageBox::Yes | QMessageBox::No // 按钮 + ); + if (reply == QMessageBox::Yes) { + emit excuteCommandPreset(uuid); + } + }); + } +private: + int sizeX = 300, sizeY = 500; + QListWidget* btnWidgets; +}; +#pragma once \ No newline at end of file diff --git a/src/launcher/appConfig/appConfig.h b/src/launcher/appConfig/appConfig.h index fe78de7..9b9bf93 100644 --- a/src/launcher/appConfig/appConfig.h +++ b/src/launcher/appConfig/appConfig.h @@ -2,6 +2,7 @@ #include #include #include +#include class appConfig { public: @@ -19,7 +20,7 @@ public: nlohmann::ordered_json settingJson; std::string softwareTile;//软件标题 std::string imgSavePath;//原图存储路径 - + SQLiteDB* g_db = nullptr; //triggerStruct _triggerStruct; //std::vector< cameraStruct> _cameraStructs; //sqlConfigStruct _sqlConfigStruct; diff --git a/src/launcher/appCore.hpp b/src/launcher/appCore.hpp index cfbc0d1..72a35b9 100644 --- a/src/launcher/appCore.hpp +++ b/src/launcher/appCore.hpp @@ -5,7 +5,6 @@ #include //QT #include -#include // #include "interface.h" #include @@ -57,7 +56,7 @@ public: logService _logService; appConfig _appConfig; backEnd backend; - SQLiteDB* g_db = nullptr; + appCore(){ }; @@ -67,7 +66,7 @@ public slots: } void recvInitFinished() { - g_db = backend.backend->getDatabase(); + _appConfig.g_db = backend.backend->getDatabase(); } }; diff --git a/src/launcher/logger/logService.cpp b/src/launcher/logger/logService.cpp index b46673c..6b25770 100644 --- a/src/launcher/logger/logService.cpp +++ b/src/launcher/logger/logService.cpp @@ -20,6 +20,8 @@ logService::logService() _logToQtWidget->sendStdLogSignal(outPutMsg);//Qt日志界面 _logToQtWidget->sendMainWindowStdLogSignal(outPutMsg);//Qt主界面 _logService->qtLogger->LogDebug("[STD]" + output);//spdLog + }); + _stdConsoleRedirector->registerCallback([&](const std::string& output) { _stdConsoleRedirector->writeToConsole(output); }); // QT日志到 spdLog Qt日志界面 @@ -27,7 +29,9 @@ logService::logService() _logService->qtLogger->LogDebug("[QT]" + output.toStdString()); _logToQtWidget->sendQtLogSignal(output);//Qt日志界面 }); - + _qtRediretor->registerCallback([&](const QString& output) { + _stdConsoleRedirector->writeToConsole(output.toStdString()); // 逐个字符写入缓冲区 + }); } logService::~logService() diff --git a/src/launcher/logger/logService.h b/src/launcher/logger/logService.h index b3a83c4..0387a50 100644 --- a/src/launcher/logger/logService.h +++ b/src/launcher/logger/logService.h @@ -38,6 +38,10 @@ public: logToQtWidget* _logToQtWidget; //SpdLogger stdLogger; SpdLogger* qtLogger; + void disableConsole() { + _stdConsoleRedirector->eraseSecondCallback(); + _qtRediretor->eraseSecondCallback(); + } logService(); ~logService(); }; diff --git a/src/launcher/logger/qtLogRediretor.h b/src/launcher/logger/qtLogRediretor.h index c65474e..affabba 100644 --- a/src/launcher/logger/qtLogRediretor.h +++ b/src/launcher/logger/qtLogRediretor.h @@ -1,6 +1,6 @@ #include #include - +#include class qtRediretor { public: @@ -11,10 +11,16 @@ public: } void sendMsg(QString& msg) { + std::lock_guard lock(consoleLock); for (auto& callback : callbacks) callback(msg); } + void eraseSecondCallback() { + std::lock_guard lock(consoleLock); + callbacks.erase(callbacks.begin() + 1, callbacks.end()); + } private: + std::mutex consoleLock; std::vector callbacks; }; diff --git a/src/launcher/logger/stdLogRediretor.hpp b/src/launcher/logger/stdLogRediretor.hpp index 41d3543..c8ef888 100644 --- a/src/launcher/logger/stdLogRediretor.hpp +++ b/src/launcher/logger/stdLogRediretor.hpp @@ -33,6 +33,10 @@ public: void registerCallback(CallbackType callback) { callbacks.push_back(callback); } + void eraseSecondCallback() { + std::lock_guard lock(consoleLock); + callbacks.erase(callbacks.begin() + 1, callbacks.end()); + } void writeToConsole(const std::string& str) { std::lock_guard lock(consoleLock); originalBuffer->sputn(str.c_str(), str.size()); diff --git a/src/launcher/main.cpp b/src/launcher/main.cpp index dced034..36225f1 100644 --- a/src/launcher/main.cpp +++ b/src/launcher/main.cpp @@ -128,6 +128,14 @@ void connectSignalAndSlot(appCore* _core, MainWindow* _MainWindow, qtFuncBridge* QObject::connect(bridge, &qtFuncBridge::histogramWidgetAddData, _MainWindow, [=](std::vectordefects) {_MainWindow->_displayWidget->_dayNightShiftHistogramWidget->addDefect(defects); }); + QObject::connect(bridge, &qtFuncBridge::setPlcConnectionError, + _MainWindow, [=]() {_MainWindow->_displayWidget->_ConnectionWidget->setPlcDisconnected(); }); + QObject::connect(bridge, &qtFuncBridge::setPlcConnectionOk, + _MainWindow, [=]() {_MainWindow->_displayWidget->_ConnectionWidget->setPlcConnected(); }); + QObject::connect(bridge, &qtFuncBridge::setCamConnectionError, + _MainWindow, [=]() {_MainWindow->_displayWidget->_ConnectionWidget->setCamDisconnected(); }); + QObject::connect(bridge, &qtFuncBridge::setCamConnectionOk, + _MainWindow, [=]() {_MainWindow->_displayWidget->_ConnectionWidget->setCamConnected(); }); //登录界面 QObject::connect(bridge, &qtFuncBridge::initResult, _MainWindow, &MainWindow::recvInitFinished); @@ -140,6 +148,13 @@ void connectSignalAndSlot(appCore* _core, MainWindow* _MainWindow, qtFuncBridge* //波形图 QObject::connect(bridge, &qtFuncBridge::summaryData_addData, _MainWindow, &MainWindow::slot_summaryData_addData); + + //排障 + QObject::connect(bridge, &qtFuncBridge::runCommand_addBtn, + _MainWindow->_displayWidget->_runCommandWidget, &runCommandWidget::addBtn); + QObject::connect(_MainWindow->_displayWidget->_runCommandWidget, + &runCommandWidget::excuteCommandPreset, + [=](QString uuid) {_core->backend.backend->excuteCliCommandPreset(uuid); }); } int main(int argc, char* argv[]) @@ -194,6 +209,7 @@ int main(int argc, char* argv[]) #if HIDE_CONSOLE if (hWnd) { ShowWindow(hWnd, SW_HIDE); + _core._logService.disableConsole(); }// 隐藏控制台窗口 #endif return a.exec(); diff --git a/src/mission/581-Ruke/CMakeLists.txt b/src/mission/581-Ruke/CMakeLists.txt index 76bbff3..bba2e81 100644 --- a/src/mission/581-Ruke/CMakeLists.txt +++ b/src/mission/581-Ruke/CMakeLists.txt @@ -40,8 +40,8 @@ FILE(GLOB UI_FILES "./*.ui") #find_package(Qt5 COMPONENTS Core REQUIRED) -find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Network REQUIRED) -find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Network REQUIRED) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Gui Network Sql REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Gui Network Sql REQUIRED) add_library(${CURRENT_FOLDER} SHARED ${HEAD_FILES} @@ -64,6 +64,7 @@ target_link_libraries(${CURRENT_FOLDER} PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Network + Qt${QT_VERSION_MAJOR}::Sql ) diff --git a/updateLog.txt b/updateLog.txt index 60d8e19..732079b 100644 --- a/updateLog.txt +++ b/updateLog.txt @@ -2,4 +2,8 @@ json1.0.4 心跳改为数组,循环发送 去除Triggers{readNum,sleepTime,writeType} json1.0.5 -批量读取改为数组 readAllCmd \ No newline at end of file +批量读取改为数组 readAllCmd +json1.0.6 +加入心跳间隔heartBeatIntervalMS +加入图像压缩阈值uiShowImgCompressThreshold +加入睡眠时间sleepIntervalMS \ No newline at end of file