From 37776d1258ec5edfb0ac83cf755cc01fa4fc7034 Mon Sep 17 00:00:00 2001 From: baiYue Date: Fri, 19 Dec 2025 18:28:13 +0800 Subject: [PATCH] add node recommendation --- common/include/global.h | 8 + diagramCavas/include/bayInfoDlg.h | 2 + diagramCavas/include/diagramCavas.h | 3 + diagramCavas/include/diagramConnectSetting.h | 5 +- .../graphicsDataModel/fixedPortsModel.h | 9 + diagramCavas/include/instance/dataAccessor.h | 9 +- diagramCavas/include/itemPropertyDlg.h | 4 + diagramCavas/include/measureSettingDlg.h | 3 + diagramCavas/include/monitorConfigDlg.h | 11 + diagramCavas/include/monitorPanel.h | 2 + diagramCavas/source/bayInfoDlg.cpp | 9 + diagramCavas/source/diagramCavas.cpp | 44 ++++ diagramCavas/source/diagramConnectSetting.cpp | 43 +++- .../graphicsDataModel/fixedPortsModel.cpp | 76 +++++- diagramCavas/source/instance/dataAccessor.cpp | 160 +++++++++++-- diagramCavas/source/itemPropertyDlg.cpp | 18 +- diagramCavas/source/measureSettingDlg.cpp | 5 + diagramCavas/source/monitorConfigDlg.cpp | 66 +++++- diagramCavas/ui/diagramConnectSetting.ui | 132 ++++++----- diagramCavas/ui/monitorConfigDlg.ui | 74 ++++-- diagramCommunication/include/baseChannel.h | 10 +- .../include/communicationManager.h | 21 +- diagramCommunication/include/dataProcessor.h | 1 + diagramCommunication/include/httpChannel.h | 2 +- .../include/uiCommunicationBus.h | 77 ++++++- .../include/webSocketChannel.h | 5 +- .../source/communicationManager.cpp | 216 +++++++++++++----- diagramCommunication/source/configManager.cpp | 6 +- diagramCommunication/source/dataProcessor.cpp | 30 +-- diagramCommunication/source/httpChannel.cpp | 37 ++- .../source/uiCommunicationBus.cpp | 13 +- .../source/webSocketChannel.cpp | 32 ++- source/monitorPagesDlg.cpp | 2 +- 33 files changed, 917 insertions(+), 218 deletions(-) diff --git a/common/include/global.h b/common/include/global.h index 4e25397..ec013f9 100644 --- a/common/include/global.h +++ b/common/include/global.h @@ -1373,6 +1373,14 @@ struct ModelTypeInfo{ //类型临时信息 QString sMeta; //该类型元模名 QString sModel; //该类型工程模名 }; + +/*******************传递的数据************************/ +struct HttpRecommandInfo{ //推荐数据服务 + QString sInput; //输入的前缀 + int nOffset = 0; //正确位置计数 + QStringList lstRecommand; //推荐列表 +}; + /** * Constants used for fetching QVariant data from GraphModel. */ diff --git a/diagramCavas/include/bayInfoDlg.h b/diagramCavas/include/bayInfoDlg.h index e5feb65..6647554 100644 --- a/diagramCavas/include/bayInfoDlg.h +++ b/diagramCavas/include/bayInfoDlg.h @@ -33,6 +33,8 @@ public slots: void onDeleteClicked(); void onModifyClicked(); void onIndexRbtnClicked(const QPoint &pos); //索引列表右键菜单 + + void onHttpDataUpdated(HttpRecommandInfo); private: void initial(); private: diff --git a/diagramCavas/include/diagramCavas.h b/diagramCavas/include/diagramCavas.h index 0e425a4..c9659e2 100644 --- a/diagramCavas/include/diagramCavas.h +++ b/diagramCavas/include/diagramCavas.h @@ -20,6 +20,7 @@ class CornerMonitorLauncher; class LoadMonitorPageDlg; class DiagramConnectSetting; class DataAccessor; +struct HttpRecommandInfo; class DIAGRAM_DESIGNER_PUBLIC DiagramCavas : public QMdiArea { @@ -34,6 +35,8 @@ public: MonitorPanel* getMonitorPanel(QString); void updateSubPos(); + void passRecommmandHttpData(HttpRecommandInfo); //传递推荐列表数据 + DiagramConnectSetting* getConnectSettingDlg() {return _connectSetting;} public: void initial(); signals: diff --git a/diagramCavas/include/diagramConnectSetting.h b/diagramCavas/include/diagramConnectSetting.h index 4217e0e..cfca25e 100644 --- a/diagramCavas/include/diagramConnectSetting.h +++ b/diagramCavas/include/diagramConnectSetting.h @@ -20,8 +20,11 @@ public: ~DiagramConnectSetting(); void showDlg(); + void updateHttpLog(QString sType,QString data); + void updateWebsocketLog(QString); public slots: - void onTestHttpClicked(); + void onTestHttpRecommandClicked(); + void onTestHttpDataClicked(); void onTestWebsocketClicked(); void onOkClicked(); void onCancelClicked(); diff --git a/diagramCavas/include/graphicsDataModel/fixedPortsModel.h b/diagramCavas/include/graphicsDataModel/fixedPortsModel.h index 7947b06..0aee13d 100644 --- a/diagramCavas/include/graphicsDataModel/fixedPortsModel.h +++ b/diagramCavas/include/graphicsDataModel/fixedPortsModel.h @@ -32,6 +32,7 @@ class ModelProperty; struct itemPageInfo; class EditBaseItem; class MonitorPanel; +class ItemPropertyDlg; class FixedPortsModel : public BaseModel, public Serializable { @@ -112,9 +113,15 @@ public: void monitorItemSet(QUuid); //运行时item设置完成 void updateMonitorDisplay(); //更新监控图元显示 + void startAcceptData(); //开始接收实时数据 + void stopAcceptData(QString); //停止接收实时数据 QMap>>& getMonitorStateMap(){return m_monitorStateMap;} void setMonitorDisplaySetting(QMap> map){m_monitorDisplaySetting = map;} QMap>& getMonitorDisplaySetting(){return m_monitorDisplaySetting;} + + /************************数据显示*************************/ + void setCurItemPropertyDlg(ItemPropertyDlg* p) {m_curPropertyDlg = p;} + ItemPropertyDlg* getCurItemPropertyDlg() {return m_curPropertyDlg;} Q_SIGNALS: void activatePage(const QString&); //激活当前model所在page void updateCurrentItems(QList,bool); //更新当前组态元件列表 <名称,uid> @@ -169,6 +176,8 @@ private: QMap>> m_monitorStateMap; //元件状态对照表 > QMap> m_monitorDisplaySetting; //元件设置 QList m_lstMonitorRelation; //监控item层级关系 + + ItemPropertyDlg* m_curPropertyDlg; public: static bool _dataInitialised; }; diff --git a/diagramCavas/include/instance/dataAccessor.h b/diagramCavas/include/instance/dataAccessor.h index 7c4ab36..32d01a3 100644 --- a/diagramCavas/include/instance/dataAccessor.h +++ b/diagramCavas/include/instance/dataAccessor.h @@ -6,18 +6,25 @@ #include #include +class DiagramCavas; + class DataAccessor : public QObject { Q_OBJECT public: DataAccessor(QObject *parent = nullptr); ~DataAccessor(); + + void setParent(DiagramCavas* p) {_parentCavas = p;} public slots: void onReceiveHttpData(const QString& sType,const QVariant& data); void onReceiveWebsocketData(const QVariant& data); private: - QMap> _realTimeData; + QString removeAfterStreamBySplit(const QString& url); //手动处理websocket的config +private: + QMap> _realTimeData; //实时数据缓存 todo:自动清理 mutable QMutex m_mutex; + DiagramCavas* _parentCavas; }; #endif diff --git a/diagramCavas/include/itemPropertyDlg.h b/diagramCavas/include/itemPropertyDlg.h index 9d754af..368f467 100644 --- a/diagramCavas/include/itemPropertyDlg.h +++ b/diagramCavas/include/itemPropertyDlg.h @@ -29,10 +29,13 @@ public: void setModelController(FixedPortsModel* p) {_curModelController = p;} auto getModelController() {return _curModelController;} auto getCurItem() {return _curItem;} + public slots: void onOkClicked(); void onCancelClicked(); void onGroupSelected(const QString&); + + void onHttpDataUpdated(HttpRecommandInfo); //更新推荐列表 private: Ui::itemPropertyDlg *ui; @@ -47,6 +50,7 @@ private: QString _curModel; //当前模型名 GraphicsProjectModelItem* _curItem; FixedPortsModel* _curModelController; + QString _curGroup; //当前属性组 }; #endif diff --git a/diagramCavas/include/measureSettingDlg.h b/diagramCavas/include/measureSettingDlg.h index 2a559e9..0d7403e 100644 --- a/diagramCavas/include/measureSettingDlg.h +++ b/diagramCavas/include/measureSettingDlg.h @@ -12,6 +12,7 @@ QT_END_NAMESPACE class BayInfoDlg; struct MeasurementInfo; +struct HttpRecommandInfo; class MeasureSettingDlg : public QDialog { @@ -36,6 +37,8 @@ public slots: void onAddParaClicked(); void onDelParaClicked(); void onEventStrategyChange(int); //事件策略改变 + + void onHttpDataUpdated(HttpRecommandInfo); //更新推荐对象列表(若有) private: void clearData(); private: diff --git a/diagramCavas/include/monitorConfigDlg.h b/diagramCavas/include/monitorConfigDlg.h index f7625e5..a7f7645 100644 --- a/diagramCavas/include/monitorConfigDlg.h +++ b/diagramCavas/include/monitorConfigDlg.h @@ -14,6 +14,8 @@ class QItemSelection; class QStandardItemModel; class QStandardItem; struct monitorItemAttributeInfo; +class QCompleter; +class QStringListModel; class MonitorConfigDlg : public QDialog { @@ -24,6 +26,7 @@ public: void initial(); void updateSelectedItems(); + void updateRecommandLst(QStringList); //更新当前推荐列表 public slots: void onOkClicked(); void onCancelClicked(); @@ -32,6 +35,10 @@ public slots: void onItemSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); //选中设备事件 void onPropertyCheckChanged(QStandardItem *item); //属性勾选改变信号 void onPropertySelectionChanged(const QModelIndex ¤t, const QModelIndex &previous); //属性选中事件 + + void onConnectParamChanged(const QString&); //连接参数变化事件(发送推荐查询) +protected: + bool eventFilter(QObject *obj, QEvent *event) override; private: void savePropertyData(const QModelIndex ¤t,QUuid uid); //保存属性到uid的属性 void loadPropertyData(const QModelIndex ¤t,QUuid uid); @@ -42,6 +49,10 @@ private: QMap> _tempConfig; QStandardItemModel* _curItemModel; QUuid _curUuid; + QStringList _curRecommandLst; //当前推荐列表 + QCompleter* _recommandCompleter; //自动填充器 + QStringListModel* _strLstModel; //自动填充模型 + }; #endif diff --git a/diagramCavas/include/monitorPanel.h b/diagramCavas/include/monitorPanel.h index 1f291e2..9b22130 100644 --- a/diagramCavas/include/monitorPanel.h +++ b/diagramCavas/include/monitorPanel.h @@ -35,6 +35,8 @@ public: void initDisplayState(); //初始化显示状态参照表 void initDisplaySetting(); //初始化显示状态设置 + + MonitorConfigDlg* getMonitorConfigDlg() {return _pConfigDlg;} public: //对层级关系的序列化与反序列化 QJsonArray serializeRelationToJsonArray(const QList& data) const; diff --git a/diagramCavas/source/bayInfoDlg.cpp b/diagramCavas/source/bayInfoDlg.cpp index 2cf7bb1..1367c34 100644 --- a/diagramCavas/source/bayInfoDlg.cpp +++ b/diagramCavas/source/bayInfoDlg.cpp @@ -443,3 +443,12 @@ void BayInfoDlg::onIndexRbtnClicked(const QPoint &pos) // 在点击位置显示菜单 menu.exec(ui->tableWidget_local->mapToGlobal(pos)); } + +void BayInfoDlg::onHttpDataUpdated(HttpRecommandInfo info) +{ + if(_measureDlg){ + if(_measureDlg->isVisible()){ + + } + } +} diff --git a/diagramCavas/source/diagramCavas.cpp b/diagramCavas/source/diagramCavas.cpp index bb3ffd0..b4fe609 100644 --- a/diagramCavas/source/diagramCavas.cpp +++ b/diagramCavas/source/diagramCavas.cpp @@ -23,6 +23,8 @@ #include "diagramCommunication/include/configManager.h" #include "instance/dataAccessor.h" #include "uiCommunicationBus.h" +#include "itemPropertyDlg.h" +#include "monitorConfigDlg.h" DiagramCavas::DiagramCavas(QWidget *parent) : QMdiArea(parent) @@ -66,6 +68,47 @@ void DiagramCavas::updateSubPos() _cornerButton->positionAtCorner(); } +void DiagramCavas::passRecommmandHttpData(HttpRecommandInfo info) +{ + QMdiSubWindow* pSub = currentSubWindow(); + if(!pSub) + return; + QWidget* pWindow= pSub->widget(); + BaseDrawingPanel* pPanel = dynamic_cast(pWindow); + if(pPanel) + { + if(pPanel->getMode() == DM_run) + { + auto pMonitor = dynamic_cast(pPanel); + if(pMonitor){ + auto pDlg = pMonitor->getMonitorConfigDlg(); + if(pDlg){ + + QStringList lst; + for(auto &str:info.lstRecommand){ + QString sCompleteName = info.sInput+str; + if(!lst.contains(sCompleteName)) + lst.append(sCompleteName); + } + pDlg->updateRecommandLst(lst); + } + //FixedPortsModel* pModel = pMonitor->getModelController(); + } + } + else if(pPanel->getMode() == DM_edit) + { + auto pDraw = dynamic_cast(pPanel); + if(pDraw){ + FixedPortsModel* pModel = pDraw->getModelController(); + ItemPropertyDlg* pDlg = pModel->getCurItemPropertyDlg(); + if(pDlg){ + pDlg->onHttpDataUpdated(info); + } + } + } + } +} + void DiagramCavas::initial() { //todo:读取数据并初始化 @@ -99,6 +142,7 @@ void DiagramCavas::initial() comm->updateWebSocketConfig(config->getWebSocketConfig()); _dataAccessor = new DataAccessor(this); + _dataAccessor->setParent(this); connect(UiCommunicationBus::instance(), SIGNAL(httpDataProcessed(QString,QVariant)), _dataAccessor, diff --git a/diagramCavas/source/diagramConnectSetting.cpp b/diagramCavas/source/diagramConnectSetting.cpp index 96c2c08..7dc2f01 100644 --- a/diagramCavas/source/diagramConnectSetting.cpp +++ b/diagramCavas/source/diagramConnectSetting.cpp @@ -1,6 +1,8 @@ #include "diagramConnectSetting.h" #include "ui_diagramConnectSetting.h" #include "diagramCommunication/include/configManager.h" +#include "uiCommunicationBus.h" +#include "communicationManager.h" DiagramConnectSetting::DiagramConnectSetting(QWidget *parent) : QDialog(parent) @@ -18,7 +20,8 @@ DiagramConnectSetting::~DiagramConnectSetting() void DiagramConnectSetting::initial() { - connect(ui->btn_testHttp,&QPushButton::clicked,this,&DiagramConnectSetting::onTestHttpClicked); + connect(ui->btn_testRecommand,&QPushButton::clicked,this,&DiagramConnectSetting::onTestHttpRecommandClicked); + connect(ui->btn_testData,&QPushButton::clicked,this,&DiagramConnectSetting::onTestWebsocketClicked); connect(ui->btn_testWebsoc,&QPushButton::clicked,this,&DiagramConnectSetting::onTestWebsocketClicked); connect(ui->btn_ok,&QPushButton::clicked,this,&DiagramConnectSetting::onOkClicked); connect(ui->btn_cancel,&QPushButton::clicked,this,&DiagramConnectSetting::onCancelClicked); @@ -49,7 +52,29 @@ void DiagramConnectSetting::showDlg() updateByConfig(socketInfo,1); } -void DiagramConnectSetting::onTestHttpClicked() +void DiagramConnectSetting::updateHttpLog(QString sType,QString data) +{ + ui->lst_log->addItem("接收http:"+data); + if(sType == "recommend"){ + ui->label_httpRecommand->setText("联通"); + } + else if(sType == "subscriptions"){ + ui->label_httpData->setText("联通"); + } +} + +void DiagramConnectSetting::updateWebsocketLog(QString str) +{ + ui->lst_log->addItem("接收websocket:"+str); +} + +void DiagramConnectSetting::onTestHttpRecommandClicked() +{ + QString strUrl = ui->le_httpIp->text()+"/measurement/recommend?input="; + UiCommunicationBus::instance()->sendHttpRequest(strUrl); +} + +void DiagramConnectSetting::onTestHttpDataClicked() { } @@ -61,6 +86,20 @@ void DiagramConnectSetting::onTestWebsocketClicked() void DiagramConnectSetting::onOkClicked() { + CommunicationManager* comm = CommunicationManager::instance(); + ConfigManager* config = ConfigManager::instance(); + + // 应用配置 + auto httpConfig = config->getHttpConfig(); + auto websocketConfig = config->getWebSocketConfig(); + httpConfig.endpoint = ui->le_httpIp->text(); + httpConfig.timeout = ui->le_httpOver->text().toInt(); + + websocketConfig.endpoint = ui->le_websocIp->text(); + websocketConfig.timeout = ui->le_websocOver->text().toInt(); + websocketConfig.heartbeatInterval = ui->le_websocHeart->text().toInt(); + comm->updateHttpConfig(httpConfig); + comm->updateWebSocketConfig(config->getWebSocketConfig()); hide(); } diff --git a/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp b/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp index 9078cd7..44955d7 100644 --- a/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp +++ b/diagramCavas/source/graphicsDataModel/fixedPortsModel.cpp @@ -47,6 +47,7 @@ #include "projectIconSetting.h" #include "monitorPanel.h" #include "designerView.h" +#include "uiCommunicationBus.h" #include "global.h" bool FixedPortsModel::_dataInitialised = false; @@ -59,6 +60,7 @@ FixedPortsModel::FixedPortsModel(PowerEntity* pEntity) ,m_proModelSettingDlg(nullptr) ,m_projectIconSettingDlg(nullptr) ,m_pBayManager(nullptr) + ,m_curPropertyDlg(nullptr) { _cavas = nullptr; loadNodeDataFromDataBase(); @@ -1299,7 +1301,7 @@ QPointF FixedPortsModel::getTerminalPos(const QString& sTerminalId) ElectricConnectLineItem* FixedPortsModel::getLineItemById(const QString& terminalId) { - for(auto iter:_nodeItem) //获取id所在的lineitem + for(auto &iter:_nodeItem) //获取id所在的lineitem { auto item = dynamic_cast(iter); if(item) @@ -1326,6 +1328,7 @@ void FixedPortsModel::showModelDlg(const QString& sName,QUuid uuid,GraphicsProje if(pDlg) { pDlg->showDlg(mapData[sName],uuid,pItem); + m_curPropertyDlg = pDlg; } else qDebug()<<"showModelDlg err"; @@ -2797,3 +2800,74 @@ void FixedPortsModel::updateMonitorDisplay() } } } + +void FixedPortsModel::startAcceptData() +{ + QStringList lstTarget; //待订阅的对象 + for(auto& lst:m_monitorPara){ + for(auto& para:lst){ + if(para.bSelected && !para.sConnectPara.isEmpty()){ + if(!lstTarget.contains(para.sConnectPara)) + lstTarget.append(para.sConnectPara); + } + } + } + + QJsonObject obj; //构建开始请求 + obj["action"] = "start"; + QJsonArray arrMeasure; + + QJsonObject objMeasure; + objMeasure["interval"] = "2s"; + QJsonArray arrTargets; + for(auto& strTarget:lstTarget){ + arrTargets.append(strTarget); + } + objMeasure["targets"] = arrTargets; + + arrMeasure.append(objMeasure); + obj["measurements"] = arrMeasure; + + QString sPath = "/monitors/data/subscriptions"; + + QJsonDocument doc(obj); + QVariant variant = doc.toVariant(); + UiCommunicationBus::instance()->sendHttpRequest(sPath,variant,"POST"); + + QList> requestLst; //等待请求的队列 + for(auto& str:lstTarget){ + requestLst.append(qMakePair(str,"request")); + } + + UiCommunicationBus::instance()->insertTempRequest(_pageName,requestLst); +} + +void FixedPortsModel::stopAcceptData(QString page) +{ + if(UiCommunicationBus::instance()->getSesstionMap().contains(page)){ + auto& curSession = UiCommunicationBus::instance()->getSesstionMap()[page]; + + QJsonObject obj; //构建开始请求 + obj["action"] = "stop"; + obj["client_id"] = curSession.first; + QJsonArray arrMeasure; + + QJsonObject objMeasure; + objMeasure["interval"] = "2s"; + QJsonArray arrTargets; + for(auto& pairTarget:curSession.second){ + arrTargets.append(pairTarget.first); + pairTarget.second = "closing"; + } + objMeasure["targets"] = arrTargets; + + arrMeasure.append(objMeasure); + obj["measurements"] = arrMeasure; + + QString sPath = "/monitors/data/subscriptions"; + + QJsonDocument doc(obj); + QVariant variant = doc.toVariant(); + UiCommunicationBus::instance()->sendHttpRequest(sPath,variant,"POST"); + } +} diff --git a/diagramCavas/source/instance/dataAccessor.cpp b/diagramCavas/source/instance/dataAccessor.cpp index 4e0b411..6f665f5 100644 --- a/diagramCavas/source/instance/dataAccessor.cpp +++ b/diagramCavas/source/instance/dataAccessor.cpp @@ -1,10 +1,17 @@ #include "instance/dataAccessor.h" +#include "communicationManager.h" +#include "uiCommunicationBus.h" +#include "configManager.h" +#include "diagramCavas.h" +#include "diagramConnectSetting.h" #include #include #include +#include "global.h" DataAccessor::DataAccessor(QObject* parent) : QObject(parent) + ,_parentCavas(nullptr) { } @@ -17,28 +24,120 @@ DataAccessor::~DataAccessor() void DataAccessor::onReceiveHttpData(const QString& sType,const QVariant& data) { if(sType == "subscriptions"){ + QMap>>& tempRequest = UiCommunicationBus::instance()->getTempRequestMap(); QJsonObject dataObj = data.toJsonObject(); QString sClientId = dataObj.value("client_id").toString(); - QMap lstRequest; + QMap lstTarget; QJsonArray measureArr = dataObj.value("measurements").toArray(); for(const QJsonValue& value : measureArr){ QJsonObject obj = value.toObject(); QString sId = obj["id"].toString(); QString sCode = obj["code"].toString(); - if(sId == "1001"){ - if(!lstRequest.contains(sId)){ - lstRequest.insert(sId,sCode); + if(!lstTarget.contains(sId)){ + lstTarget.insert(sId,sCode); + } + } + + QString sAction; + auto mapSesstion = UiCommunicationBus::instance()->getSesstionMap(); + bool bClientExist = false; + for(auto& session:mapSesstion){ + if(session.first == sClientId){ //在会话列表中已存在,是stop(暂只使用stop和start) + bClientExist = true; + sAction = "stop"; + break; + } + } + + if(sAction.isEmpty()){ //不是stop的情况 + QStringList lstKeys = lstTarget.keys(); + for(auto it = tempRequest.begin(); it != tempRequest.end(); ++it){ + const QString& page = it.key(); + QList>& tempList = it.value(); + + // 从 tempList 提取所有 first 元素 + QStringList firstElements; + firstElements.reserve(tempList.size()); + for (const auto& pair : tempList) + { + firstElements.append(pair.first); + } + + // 对两个列表进行排序(因为 moveMatchingRequests 内部会排序比较) + QStringList sortedFirstElements = firstElements; + QStringList sortedLstKeys = lstKeys; + + std::sort(sortedFirstElements.begin(), sortedFirstElements.end()); + std::sort(sortedLstKeys.begin(), sortedLstKeys.end()); + + // 比较两个列表是否相同 + if (sortedFirstElements == sortedLstKeys) + { + // 这里需要一个 id 参数,你可以从 lstRequest 中获取或使用其他方式 + QString id; // 你需要确定 id 从哪里来 + + // 调用 moveMatchingRequests + for(auto& pair:tempList){ + pair.second = "connecting"; + } + UiCommunicationBus::instance()->insertSesstionMap(id, lstTarget); + sAction = "start"; + break; } } } - /*QString input = dataObj.value("input").toString(); - int offSet = dataObj.value("offset").toInt(); - QJsonArray recommendedList = dataObj.value("recommended_list").toArray(); - for(const QJsonValue& value : recommendedList){ - QString content = value.toString(); - }*/ + + if(!lstTarget.isEmpty()){ + if(sAction == "start"){ + auto config = ConfigManager::instance()->getWebSocketConfig(); + QString sPre = removeAfterStreamBySplit(config.endpoint); //手动移除 + config.endpoint = sPre + "/" + sClientId; + CommunicationManager::instance()->updateWebSocketConfig(config,sClientId); + CommunicationManager::instance()->connectWebSocket(sClientId); + } + else if(sAction == "stop"){ //已经停止完毕,从session中移除会话 + auto &map = UiCommunicationBus::instance()->getSesstionMap(); + for(auto iter = map.begin();iter != map.end();++iter){ + if(iter->first == sClientId){ + iter = map.erase(iter); + break; + } + } + CommunicationManager::instance()->disconnectWebSocket(sClientId); + CommunicationManager::instance()->removeChannel(sClientId); + } + } + } + else if(sType == "recommend"){ + QJsonArray dataArr = data.toJsonArray(); + for(const QJsonValue& value:dataArr){ + QJsonObject dataObj = value.toObject(); + QString input = dataObj.value("input").toString(); + int offSet = dataObj.value("offset").toInt(); + QJsonArray recommendedList = dataObj.value("recommended_list").toArray(); + + HttpRecommandInfo info; + for(const QJsonValue& value : recommendedList){ + QString content = value.toString(); + info.lstRecommand.append(content); + } + info.sInput = input.left(offSet); + info.nOffset = offSet; + if(_parentCavas){ + _parentCavas->passRecommmandHttpData(info); + } + } + } + if(_parentCavas){ + auto pDlg = _parentCavas->getConnectSettingDlg(); + if(pDlg){ + QJsonObject jsonObj = data.value(); + QJsonDocument doc(jsonObj); + QString compactJson = doc.toJson(QJsonDocument::Compact); + pDlg->updateHttpLog(sType,compactJson); + } } } @@ -51,17 +150,52 @@ void DataAccessor::onReceiveWebsocketData(const QVariant& data) QJsonObject targetObj = value.toObject(); QString targetId = targetObj["id"].toString(); QJsonArray arrData = targetObj["datas"].toArray(); + + QMap newInnerMap; for (const QJsonValue& data : arrData){ QJsonObject dataObj = data.toObject(); QString sTime = dataObj["time"].toString(); + double dVal = dataObj["value"].toDouble(); bool ok = false; quint64 value = sTime.toULongLong(&ok); if (ok) { - // 使用 value + newInnerMap.insert(value,dVal); } - double dVal = dataObj["value"].toDouble(); + } + + QMutexLocker locker(&m_mutex); + if (_realTimeData.contains(targetId)) { + _realTimeData[targetId].insert(newInnerMap); + + } else { + _realTimeData.insert(targetId, newInnerMap); } } } - QMutexLocker locker(&m_mutex); + if(_parentCavas){ + auto pDlg = _parentCavas->getConnectSettingDlg(); + if(pDlg){ + QJsonObject jsonObj = data.value(); + QJsonDocument doc(jsonObj); + QString compactJson = doc.toJson(QJsonDocument::Compact); + pDlg->updateWebsocketLog(compactJson); + } + } +} + +QString DataAccessor::removeAfterStreamBySplit(const QString& url) +{ + QStringList parts = url.split('/'); + QStringList resultParts; + + for (int i = 0; i < parts.size(); i++) { + if (parts[i] == "stream") { + // 找到 "stream" 后,停止添加后续部分 + resultParts.append("stream"); + break; + } + resultParts.append(parts[i]); + } + + return resultParts.join('/'); } diff --git a/diagramCavas/source/itemPropertyDlg.cpp b/diagramCavas/source/itemPropertyDlg.cpp index 6f4cdad..b2ffbb4 100644 --- a/diagramCavas/source/itemPropertyDlg.cpp +++ b/diagramCavas/source/itemPropertyDlg.cpp @@ -7,7 +7,7 @@ #include "ui_itemPropertyDlg.h" #include "baseContentDlg.h" #include "baseInfoDlg.h" -//#include "topologyManager.h" +#include "graphicsDataModel/fixedPortsModel.h" #include "basePropertyManager.h" #include "baseProperty.h" #include "ptExtraInfoDlg.h" @@ -131,12 +131,16 @@ void ItemPropertyDlg::onOkClicked() } } } + _curGroup = ""; _curItem = nullptr; + _curModelController->setCurItemPropertyDlg(nullptr); hide(); } void ItemPropertyDlg::onCancelClicked() { + _curGroup = ""; + _curModelController->setCurItemPropertyDlg(nullptr); hide(); } @@ -165,6 +169,7 @@ void ItemPropertyDlg::onGroupSelected(const QString& str) } ui->stackedWidget->setCurrentWidget(groupViews_[str]); + _curGroup = str; } @@ -203,6 +208,17 @@ void ItemPropertyDlg::createGroupView(const QString& str) ui->stackedWidget->addWidget(contentDlg); } +void ItemPropertyDlg::onHttpDataUpdated(HttpRecommandInfo info) +{ + if(_curGroup == "bay"){ + auto pWidget = groupViews_[_curGroup]; + auto pBay = dynamic_cast(pWidget); + if(pBay){ + pBay->onHttpDataUpdated(info); + } + } +} + void ItemPropertyDlg::showDlg(modelDataInfo dataInfo,QUuid uuid,GraphicsProjectModelItem* pItem) { groupValue_ = dataInfo.groupInfo; diff --git a/diagramCavas/source/measureSettingDlg.cpp b/diagramCavas/source/measureSettingDlg.cpp index e3b980b..318ecfd 100644 --- a/diagramCavas/source/measureSettingDlg.cpp +++ b/diagramCavas/source/measureSettingDlg.cpp @@ -361,3 +361,8 @@ void MeasureSettingDlg::onEventStrategyChange(int n) ui->sw_event->setCurrentIndex(1); } } + +void MeasureSettingDlg::onHttpDataUpdated(HttpRecommandInfo info) +{ + // +} diff --git a/diagramCavas/source/monitorConfigDlg.cpp b/diagramCavas/source/monitorConfigDlg.cpp index 022bb00..a408487 100644 --- a/diagramCavas/source/monitorConfigDlg.cpp +++ b/diagramCavas/source/monitorConfigDlg.cpp @@ -1,6 +1,10 @@ #include "monitorConfigDlg.h" #include "ui_monitorConfigDlg.h" +#include +#include +#include #include "monitorPanel.h" +#include "uiCommunicationBus.h" #include "global.h" MonitorConfigDlg::MonitorConfigDlg(QWidget *parent) @@ -8,6 +12,8 @@ MonitorConfigDlg::MonitorConfigDlg(QWidget *parent) , ui(new Ui::monitorConfigDlg) ,_parent(nullptr) ,_curItemModel(nullptr) + ,_recommandCompleter(nullptr) + ,_strLstModel(nullptr) { ui->setupUi(this); this->setWindowFlags(Qt::FramelessWindowHint | windowFlags()); @@ -36,13 +42,44 @@ void MonitorConfigDlg::initial() connect(_curItemModel,&QStandardItemModel::itemChanged, this,&MonitorConfigDlg::onPropertyCheckChanged); connect(ui->treeView_para->selectionModel(), &QItemSelectionModel::currentChanged, this, &MonitorConfigDlg::onPropertySelectionChanged); + _recommandCompleter = new QCompleter(this); + _recommandCompleter->setCaseSensitivity(Qt::CaseInsensitive); + _recommandCompleter->setFilterMode(Qt::MatchContains); + _recommandCompleter->setCompletionMode(QCompleter::PopupCompletion); + _strLstModel = new QStringListModel(this); + + _recommandCompleter->setModel(_strLstModel); + ui->le_query->setCompleter(_recommandCompleter); + ui->le_query->installEventFilter(this); + ui->le_query->setPlaceholderText("输入空格获取初始值"); + connect(ui->le_query, &QLineEdit::textChanged, this, [=](const QString &text) { + if (text.endsWith(".")) { + onConnectParamChanged(text); + } + }); + //connect(ui->le_query,&QLineEdit::textChanged, this,&MonitorConfigDlg::onConnectParamChanged); } void MonitorConfigDlg::updateSelectedItems() { ui->treeView_item->expandAll(); _tempConfig = _parent->getModelController()->getMonitorPara(); - int a = 1; +} + +void MonitorConfigDlg::updateRecommandLst(QStringList lst) +{ + for(auto& newName:lst){ + if(!newName.isEmpty()){ + if(!_curRecommandLst.contains(newName)){ + _curRecommandLst.append(newName); + } + } + } + _strLstModel->setStringList(_curRecommandLst); + if (_recommandCompleter->popup()->isVisible()) { + _recommandCompleter->popup()->hide(); + } + _recommandCompleter->complete(); // 重新显示补全列表 } void MonitorConfigDlg::onOkClicked() @@ -147,6 +184,33 @@ void MonitorConfigDlg::onPropertySelectionChanged(const QModelIndex ¤t, co } } +void MonitorConfigDlg::onConnectParamChanged(const QString& str) +{ + QVariantMap map; + map.insert("input",str); + UiCommunicationBus::instance()->sendHttpRequest("/measurement/recommend",QVariant(),"GET",map); +} + +bool MonitorConfigDlg::eventFilter(QObject *obj, QEvent *event) +{ + if (obj == ui->le_query && event->type() == QEvent::KeyPress) { + QKeyEvent *keyEvent = static_cast(event); + + if (keyEvent->key() == Qt::Key_Space) { + qDebug() << "eventFilter:space"; + onConnectParamChanged(ui->le_query->text()); + _recommandCompleter->complete(); + return true; + } + + if (keyEvent->text() == ".") { + qDebug() << "eventFilter:dot"; + // 返回false让事件继续传播 + } + } + return QDialog::eventFilter(obj, event); +} + void MonitorConfigDlg::savePropertyData(const QModelIndex &previous,QUuid uid) { if(_tempConfig.contains(uid)){ diff --git a/diagramCavas/ui/diagramConnectSetting.ui b/diagramCavas/ui/diagramConnectSetting.ui index 28d1912..438372e 100644 --- a/diagramCavas/ui/diagramConnectSetting.ui +++ b/diagramCavas/ui/diagramConnectSetting.ui @@ -6,8 +6,8 @@ 0 0 - 393 - 502 + 414 + 588 @@ -98,12 +98,19 @@ font: 12pt "Microsoft YaHei UI"; HTTP服务器配置 - - 4 - 8 + + + + 连接名称: + + + + + + @@ -118,49 +125,6 @@ font: 12pt "Microsoft YaHei UI"; - - - - - - - 连接名称: - - - - - - - Qt::Orientation::Horizontal - - - - 217 - 20 - - - - - - - - - - - - 50 - 16777215 - - - - - - - - 服务器地址 - - - @@ -174,6 +138,39 @@ font: 12pt "Microsoft YaHei UI"; + + + + + + + 服务器地址: + + + + + + + Qt::Orientation::Horizontal + + + + 217 + 20 + + + + + + + + + 50 + 16777215 + + + + @@ -182,15 +179,15 @@ font: 12pt "Microsoft YaHei UI"; 连接测试 - - - + + + - 测试连接 + 测试节点推荐 - + Qt::Orientation::Horizontal @@ -203,21 +200,21 @@ font: 12pt "Microsoft YaHei UI"; - + 状态: - - + + 未连接 - + Qt::Orientation::Horizontal @@ -230,6 +227,27 @@ font: 12pt "Microsoft YaHei UI"; + + + + 测试数据服务 + + + + + + + 状态: + + + + + + + 未连接 + + + diff --git a/diagramCavas/ui/monitorConfigDlg.ui b/diagramCavas/ui/monitorConfigDlg.ui index 119190e..1f2dc25 100644 --- a/diagramCavas/ui/monitorConfigDlg.ui +++ b/diagramCavas/ui/monitorConfigDlg.ui @@ -6,8 +6,8 @@ 0 0 - 641 - 504 + 673 + 506 @@ -103,7 +103,7 @@ font: 12pt "Microsoft YaHei UI"; 监控参数配置 - + @@ -131,18 +131,12 @@ font: 12pt "Microsoft YaHei UI"; - + 配置详情 - - 6 - - - 10 - @@ -150,7 +144,7 @@ font: 12pt "Microsoft YaHei UI"; - + @@ -160,8 +154,14 @@ font: 12pt "Microsoft YaHei UI"; - - + + + + + 9 + + + @@ -172,6 +172,12 @@ font: 12pt "Microsoft YaHei UI"; + + + 60 + 0 + + 字符 @@ -184,7 +190,20 @@ font: 12pt "Microsoft YaHei UI"; - + + + + Qt::Orientation::Horizontal + + + + 526 + 20 + + + + + 0 @@ -206,13 +225,6 @@ font: 12pt "Microsoft YaHei UI"; 10 - - - - 接线图中展示: - - - @@ -240,6 +252,26 @@ font: 12pt "Microsoft YaHei UI"; + + + + 接线图中展示: + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + diff --git a/diagramCommunication/include/baseChannel.h b/diagramCommunication/include/baseChannel.h index eae7411..44dc23a 100644 --- a/diagramCommunication/include/baseChannel.h +++ b/diagramCommunication/include/baseChannel.h @@ -36,16 +36,17 @@ public: QString channelId() const { return m_config.channelId; } ChannelConfig config() const { return m_config; } QUrl endpoint() const { return m_config.endpoint; } + QString sessionId() const {return m_sessionId;} // 控制 void setAutoReconnect(bool enable); bool isAutoReconnect() const { return m_autoReconnect; } signals: - void connected(); - void disconnected(); - void dataReceived(const QByteArray& data); - void errorOccurred(const QString& error); + void connected(const QString& = ""); + void disconnected(const QString& = ""); + void dataReceived(const QByteArray& data,const QString& = ""); + void errorOccurred(const QString& error,const QString& = ""); protected: // 公共方法 @@ -60,6 +61,7 @@ protected: // 成员变量 ChannelConfig m_config; bool m_autoReconnect = true; + QString m_sessionId; //会话id(http无) private slots: void onReconnectTimeout(); diff --git a/diagramCommunication/include/communicationManager.h b/diagramCommunication/include/communicationManager.h index 308f301..ef825ca 100644 --- a/diagramCommunication/include/communicationManager.h +++ b/diagramCommunication/include/communicationManager.h @@ -23,23 +23,26 @@ public: bool disconnectHttp(); bool sendHttpRequest(const QString& path, const QByteArray& data = QByteArray(), - const QString& method = "GET"); + const QString& method = "GET", + const QVariantMap& query = QVariantMap()); // WebSocket通道操作 - bool connectWebSocket(); - bool disconnectWebSocket(); - bool sendWebSocketMessage(const QByteArray& data); - bool sendWebSocketText(const QString& text); + bool connectWebSocket(const QString& sessionId = ""); + bool disconnectWebSocket(const QString& sessionId = ""); + bool removeChannel(const QString& sessionId); + + bool sendWebSocketMessage(const QByteArray& data,const QString& sessionId); + bool sendWebSocketText(const QString& text,const QString& sessionId); // 状态查询 bool isHttpConnected() const; - bool isWebSocketConnected() const; + bool isWebSocketConnected(const QString& sessionId) const; ChannelConfig getHttpConfig() const; ChannelConfig getWebSocketConfig() const; // 配置更新 void updateHttpConfig(const ChannelConfig& config); - void updateWebSocketConfig(const ChannelConfig& config); + void updateWebSocketConfig(const ChannelConfig& config,const QString& sessionId = ""); signals: // HTTP通道信号 @@ -61,7 +64,7 @@ private: // 内部初始化 void initHttpChannel(); - void initWebSocketChannel(); + void initWebSocketChannel(QString sessionId = ""); //服务器回传的会话id // 配置 ChannelConfig m_httpConfig; @@ -69,5 +72,5 @@ private: // 通道实例 QSharedPointer m_httpChannel; - QSharedPointer m_websocketChannel; + QMap> m_websocketChannelMap; // }; diff --git a/diagramCommunication/include/dataProcessor.h b/diagramCommunication/include/dataProcessor.h index 1840c55..c8e9ae9 100644 --- a/diagramCommunication/include/dataProcessor.h +++ b/diagramCommunication/include/dataProcessor.h @@ -32,6 +32,7 @@ private: DataProcessor(QObject* parent = nullptr); // 通用处理函数 void processJson(const QVariant& data,int conType = 0); //0http 1websocket + void processJsonArray(const QVariant& data); // 数据缓存 QMap m_dataCache; diff --git a/diagramCommunication/include/httpChannel.h b/diagramCommunication/include/httpChannel.h index 8c7e546..3bca4a6 100644 --- a/diagramCommunication/include/httpChannel.h +++ b/diagramCommunication/include/httpChannel.h @@ -16,7 +16,7 @@ public: bool send(const QByteArray& data) override; // HTTP方法 - bool get(const QString& path = ""); + bool get(const QString& path = "",const QVariantMap& queryMap = QVariantMap()); bool post(const QByteArray& data, const QString& path = ""); bool put(const QByteArray& data, const QString& path = ""); bool deleteResource(const QString& path = ""); diff --git a/diagramCommunication/include/uiCommunicationBus.h b/diagramCommunication/include/uiCommunicationBus.h index d1afc05..4b24451 100644 --- a/diagramCommunication/include/uiCommunicationBus.h +++ b/diagramCommunication/include/uiCommunicationBus.h @@ -16,7 +16,7 @@ public: static UiCommunicationBus* instance(); // 发送HTTP请求 - void sendHttpRequest(const QString& endpoint, const QVariant& data = QVariant()); + void sendHttpRequest(const QString& endpoint, const QVariant& data = QVariant(),const QString& method = "GET",const QVariantMap& = QVariantMap()); // 发送HTTP请求(无回复) void sendHttpRequestNoReply(const QString& endpoint, const QVariant& data = QVariant()); @@ -30,6 +30,79 @@ public: // 注册/注销UI void registerUi(const QString& uiId, QObject* uiObject); void unregisterUi(const QString& uiId); + + QMap>>& getTempRequestMap() {return _tempRequest;} + void insertTempRequest(QString page,QList> lst){ + if(!_tempRequest.contains(page)){ + _tempRequest.insert(page,lst); + } + } + + QMap>>>& getSesstionMap() {return _session;} + void insertSesstionMap(QString id,QMap targetMap){ //从临时列表移除,插入到会话列表 + + QStringList sortedTargetList; //排序后的target列表 + for(auto it = targetMap.begin();it != targetMap.end();++it){ + sortedTargetList.append(it.key()); + } + sortedTargetList.sort(); + + auto it = _tempRequest.begin(); + while (it != _tempRequest.end()) + { + const QString& page = it.key(); + QList>& tempList = it.value(); + + // 提取当前 tempList 中所有 first 元素组成的列表 + QStringList firstElements; + firstElements.reserve(tempList.size()); + for (const auto& pair : tempList) + { + firstElements.append(pair.first); + } + + // 先进行简单检查:如果元素数量不同,肯定不匹配 + if (firstElements.size() != sortedTargetList.size()) + { + ++it; + continue; + } + + // 排序 firstElements + QStringList sortedFirstElements = firstElements; + sortedFirstElements.sort(); + + // 比较排序后的列表 + if (sortedFirstElements == sortedTargetList) + { + // 匹配成功 + // 检查 _session 中是否已有此 page + if (!_session.contains(page)) + { + QList> newList; + for (const auto& item : tempList) { //如果订阅不成功,从候选列表中移除 todo:记录错误target + auto it = targetMap.find(item.first); + if (it != targetMap.end()) { + if (it.value() == "1001") { + continue; // 跳过 + } + } + newList.append(item); + } + + tempList = newList; + // _session 中没有此 page,可以插入 + _session[page] = qMakePair(id, tempList); + } + // 无论 _session 中是否有此 page,都从 _tempRequest 删除 *********同一个page中只存在一个会话****** + it = _tempRequest.erase(it); + } + else + { + ++it; + } + } + } signals: void httpDataProcessed(const QString& type,const QVariant& data); //发送分拣过的数据给外部 void websocketDataProcessed(const QVariant& data); @@ -45,4 +118,6 @@ private: // UI注册表 QMap m_uiObjects; mutable QMutex m_mutex; + QMap>> _tempRequest; //临时请求队列,一个QList为一次会话 <图名<节点名,状态>> + QMap>>> _session; //会话队列 <图名<会话id<节点名,状态>>> }; diff --git a/diagramCommunication/include/webSocketChannel.h b/diagramCommunication/include/webSocketChannel.h index 4cca44a..a2f78cf 100644 --- a/diagramCommunication/include/webSocketChannel.h +++ b/diagramCommunication/include/webSocketChannel.h @@ -13,7 +13,7 @@ public: int heartbeatInterval = 30000; }; - WebSocketChannel(const ChannelConfig& config, QObject* parent = nullptr); + WebSocketChannel(const ChannelConfig& config, QString sessionId,QObject* parent = nullptr); bool connect() override; bool disconnect() override; @@ -24,14 +24,13 @@ public: void setWebSocketConfig(const WebSocketConfig& config); signals: - void textMessageReceived(const QString& message); + void textMessageReceived(const QString& message,const QString& = ""); private slots: void onConnected(); void onDisconnected(); void onTextMessageReceived(const QString& message); void onBinaryMessageReceived(const QByteArray& message); - private: QWebSocket* m_webSocket = nullptr; WebSocketConfig m_wsConfig; diff --git a/diagramCommunication/source/communicationManager.cpp b/diagramCommunication/source/communicationManager.cpp index f579ca2..0889d32 100644 --- a/diagramCommunication/source/communicationManager.cpp +++ b/diagramCommunication/source/communicationManager.cpp @@ -41,7 +41,7 @@ bool CommunicationManager::initialize() initHttpChannel(); // 初始化WebSocket通道 - initWebSocketChannel(); + //initWebSocketChannel(); qInfo() << "CommunicationManager initialized"; return true; @@ -81,13 +81,8 @@ void CommunicationManager::initHttpChannel() this, &CommunicationManager::httpError); } -void CommunicationManager::initWebSocketChannel() +void CommunicationManager::initWebSocketChannel(QString sessionId) { - if (m_websocketChannel) { - m_websocketChannel->disconnect(); - } - - // 创建WebSocket通道 WebSocketChannel::ChannelConfig wsConfig; wsConfig.endpoint = QUrl(m_websocketConfig.endpoint); wsConfig.timeout = m_websocketConfig.timeout; @@ -95,20 +90,63 @@ void CommunicationManager::initWebSocketChannel() WebSocketChannel::WebSocketConfig websocketConfig; websocketConfig.heartbeatInterval = m_websocketConfig.heartbeatInterval; - m_websocketChannel.reset(new WebSocketChannel(wsConfig)); - m_websocketChannel->setWebSocketConfig(websocketConfig); + if(sessionId.isEmpty()){ //没有指定会话,初始化已有channel + for(auto& pChannel:m_websocketChannelMap){ + pChannel->disconnect(); + pChannel.reset(new WebSocketChannel(wsConfig,pChannel->sessionId())); + pChannel->setWebSocketConfig(websocketConfig); - // 连接信号 - connect(m_websocketChannel.data(), &WebSocketChannel::connected, - this, &CommunicationManager::websocketConnected); - connect(m_websocketChannel.data(), &WebSocketChannel::disconnected, - this, &CommunicationManager::websocketDisconnected); - connect(m_websocketChannel.data(), &WebSocketChannel::dataReceived, - this, &CommunicationManager::websocketDataReceived); - connect(m_websocketChannel.data(), &WebSocketChannel::errorOccurred, - this, &CommunicationManager::websocketError); - connect(m_websocketChannel.data(), &WebSocketChannel::textMessageReceived, - this, &CommunicationManager::websocketTextReceived); + // 连接信号 + connect(pChannel.data(), &WebSocketChannel::connected, + this, &CommunicationManager::websocketConnected); + connect(pChannel.data(), &WebSocketChannel::disconnected, + this, &CommunicationManager::websocketDisconnected); + connect(pChannel.data(), &WebSocketChannel::dataReceived, + this, &CommunicationManager::websocketDataReceived); + connect(pChannel.data(), &WebSocketChannel::errorOccurred, + this, &CommunicationManager::websocketError); + connect(pChannel.data(), &WebSocketChannel::textMessageReceived, + this, &CommunicationManager::websocketTextReceived); + } + } + else{ + for(auto& pChannel:m_websocketChannelMap){ + if(pChannel->sessionId() == sessionId){ //已存在 + pChannel->disconnect(); + pChannel.reset(new WebSocketChannel(wsConfig,pChannel->sessionId())); + pChannel->setWebSocketConfig(websocketConfig); + + // 连接信号 + connect(pChannel.data(), &WebSocketChannel::connected, + this, &CommunicationManager::websocketConnected); + connect(pChannel.data(), &WebSocketChannel::disconnected, + this, &CommunicationManager::websocketDisconnected); + connect(pChannel.data(), &WebSocketChannel::dataReceived, + this, &CommunicationManager::websocketDataReceived); + connect(pChannel.data(), &WebSocketChannel::errorOccurred, + this, &CommunicationManager::websocketError); + connect(pChannel.data(), &WebSocketChannel::textMessageReceived, + this, &CommunicationManager::websocketTextReceived); + return; + } + } + + QSharedPointer newChannel(new WebSocketChannel(wsConfig,sessionId)); + newChannel->setWebSocketConfig(websocketConfig); + + // 连接信号 + connect(newChannel.data(), &WebSocketChannel::connected, + this, &CommunicationManager::websocketConnected); + connect(newChannel.data(), &WebSocketChannel::disconnected, + this, &CommunicationManager::websocketDisconnected); + connect(newChannel.data(), &WebSocketChannel::dataReceived, + this, &CommunicationManager::websocketDataReceived); + connect(newChannel.data(), &WebSocketChannel::errorOccurred, + this, &CommunicationManager::websocketError); + connect(newChannel.data(), &WebSocketChannel::textMessageReceived, + this, &CommunicationManager::websocketTextReceived); + m_websocketChannelMap.insert(sessionId,newChannel); + } } bool CommunicationManager::connectHttp() @@ -140,7 +178,8 @@ bool CommunicationManager::disconnectHttp() bool CommunicationManager::sendHttpRequest(const QString& path, const QByteArray& data, - const QString& method) + const QString& method, + const QVariantMap& query) { if (!m_httpChannel || !m_httpChannel->isConnected()) { qWarning() << "HTTP channel not connected"; @@ -148,7 +187,7 @@ bool CommunicationManager::sendHttpRequest(const QString& path, } if (method == "GET") { - return m_httpChannel->get(path); + return m_httpChannel->get(path,query); } else if (method == "POST") { return m_httpChannel->post(data, path); } else if (method == "PUT") { @@ -161,51 +200,108 @@ bool CommunicationManager::sendHttpRequest(const QString& path, return false; } -bool CommunicationManager::connectWebSocket() +bool CommunicationManager::connectWebSocket(const QString& sessionId) { - if (!m_websocketChannel) { - qWarning() << "WebSocket channel not initialized"; - return false; - } - - if (m_websocketChannel->isConnected()) { + if(sessionId.isEmpty()){ + for(auto& pChannel:m_websocketChannelMap){ + if (!pChannel->isConnected()) { + pChannel->connect(); + } + } return true; } + else + { + for(auto& pChannel:m_websocketChannelMap){ + if(pChannel->sessionId() == sessionId){ + if (pChannel->isConnected()) { + return true; + } - return m_websocketChannel->connect(); -} - -bool CommunicationManager::disconnectWebSocket() -{ - if (!m_websocketChannel) { - return false; + return pChannel->connect(); + } + } } - if (!m_websocketChannel->isConnected()) { + qWarning() << "WebSocket channel not initialized"; + return false; + +} + +bool CommunicationManager::disconnectWebSocket(const QString& sessionId) +{ + + if(sessionId.isEmpty()){ //不指定则断开所有通道 + for(auto& pChannel:m_websocketChannelMap){ + if(pChannel->sessionId() == sessionId){ + if (pChannel->isConnected()) { + pChannel->disconnect(); + } + } + } return true; } + else{ + for(auto& pChannel:m_websocketChannelMap){ + if(pChannel->sessionId() == sessionId){ + if (!pChannel->isConnected()) { + return true; + } - return m_websocketChannel->disconnect(); -} - -bool CommunicationManager::sendWebSocketMessage(const QByteArray& data) -{ - if (!m_websocketChannel || !m_websocketChannel->isConnected()) { - qWarning() << "WebSocket channel not connected"; - return false; + return pChannel->disconnect(); + } + } } - return m_websocketChannel->send(data); + return false; } -bool CommunicationManager::sendWebSocketText(const QString& text) +bool CommunicationManager::removeChannel(const QString& sessionId) { - if (!m_websocketChannel || !m_websocketChannel->isConnected()) { - qWarning() << "WebSocket channel not connected"; - return false; + for(auto& pChannel:m_websocketChannelMap){ + if(pChannel->sessionId() == sessionId){ + if (pChannel->isConnected()) { + pChannel->disconnect(); + } + m_websocketChannelMap.remove(sessionId); + return true; + } + } + return false; +} + +bool CommunicationManager::sendWebSocketMessage(const QByteArray& data,const QString& sessionId) +{ + for(auto& pChannel:m_websocketChannelMap){ + if(pChannel->sessionId() == sessionId){ + if(!pChannel->isConnected()){ + qWarning() << "WebSocket channel not connected"; + return false; + } + + return pChannel->send(data); + } } - return m_websocketChannel->sendText(text); + qWarning() << "WebSocket channel not connected"; + return false; +} + +bool CommunicationManager::sendWebSocketText(const QString& text,const QString& sessionId) +{ + for(auto& pChannel:m_websocketChannelMap){ + if(pChannel->sessionId() == sessionId){ + if(!pChannel->isConnected()){ + qWarning() << "WebSocket channel not connected"; + return false; + } + + return pChannel->sendText(text); + } + } + + qWarning() << "WebSocket channel not connected"; + return false; } bool CommunicationManager::isHttpConnected() const @@ -213,9 +309,17 @@ bool CommunicationManager::isHttpConnected() const return m_httpChannel && m_httpChannel->isConnected(); } -bool CommunicationManager::isWebSocketConnected() const +bool CommunicationManager::isWebSocketConnected(const QString& sessionId) const { - return m_websocketChannel && m_websocketChannel->isConnected(); + for(auto& pChannel:m_websocketChannelMap){ + if(pChannel->sessionId() == sessionId){ + if(pChannel->isConnected()){ + return true; + } + } + } + + return false; } ChannelConfig CommunicationManager::getHttpConfig() const @@ -247,7 +351,7 @@ void CommunicationManager::updateHttpConfig(const ChannelConfig& config) qInfo() << "HTTP config updated"; } -void CommunicationManager::updateWebSocketConfig(const ChannelConfig& config) +void CommunicationManager::updateWebSocketConfig(const ChannelConfig& config,const QString& sessionId) { bool reconnect = false; @@ -256,10 +360,10 @@ void CommunicationManager::updateWebSocketConfig(const ChannelConfig& config) } m_websocketConfig = config; - initWebSocketChannel(); + initWebSocketChannel(sessionId); if (reconnect && config.autoConnect) { - connectWebSocket(); + connectWebSocket(sessionId); } qInfo() << "WebSocket config updated"; diff --git a/diagramCommunication/source/configManager.cpp b/diagramCommunication/source/configManager.cpp index 61ec1b0..3abb19c 100644 --- a/diagramCommunication/source/configManager.cpp +++ b/diagramCommunication/source/configManager.cpp @@ -153,8 +153,8 @@ ChannelConfig ConfigManager::getDefaultHttpConfig() const config.id = "http_channel"; config.name = "SCADA数据接口"; - config.endpoint = "http://192.168.1.100:8080/api"; - config.timeout = 30000; + config.endpoint = "http://192.168.46.100:10080"; + config.timeout = 10000; config.enabled = true; config.autoConnect = true; config.username = ""; @@ -178,7 +178,7 @@ ChannelConfig ConfigManager::getDefaultWebSocketConfig() const config.id = "websocket_channel"; config.name = "实时数据推送"; config.endpoint = "ws://192.168.1.101:8888/ws"; - config.timeout = 30000; + config.timeout = 10000; config.enabled = true; config.autoConnect = false; config.connected = false; diff --git a/diagramCommunication/source/dataProcessor.cpp b/diagramCommunication/source/dataProcessor.cpp index 9153f99..c3b86d6 100644 --- a/diagramCommunication/source/dataProcessor.cpp +++ b/diagramCommunication/source/dataProcessor.cpp @@ -27,10 +27,15 @@ DataProcessor::DataProcessor(QObject* parent) void DataProcessor::processData(const QVariant& data,int conType) { - qDebug() << "处理数据_size:" << data.toString().size(); + qDebug() << "data_size:" << data.toJsonObject().size(); // 根据数据类型处理 - processJson(data.toJsonObject(),conType); + if (data.canConvert()) { + processJson(data.toJsonObject(),conType); + } + else if(data.canConvert()){ + processJsonArray(data); + } } void DataProcessor::processJson( const QVariant& data,int conType) @@ -38,9 +43,6 @@ void DataProcessor::processJson( const QVariant& data,int conType) QJsonObject dataObj = data.toJsonObject(); if(conType == 0){ if(dataObj.contains("client_id")){ //实时数据相关 - emit httpProcessed("recommend",data); - } - else if(dataObj.contains("input")){ emit httpProcessed("subscriptions",data); } } @@ -49,21 +51,11 @@ void DataProcessor::processJson( const QVariant& data,int conType) emit websocketProcessed(data); } } +} - if(dataObj.contains("client_id")){ //实时数据相关 - /*QString clientId = dataObj.value("client_id").toString(); - QJsonArray arrTarget = dataObj.value("targets").toArray(); - for (const QJsonValue& value : arrTarget) { - QJsonObject obj = value.toObject(); - QString targetId = obj["id"].toString(); - QString sCode = obj["code"].toString(); - }*/ - } - else if(dataObj.contains("input")){ - - } - //QMutexLocker locker(&m_mutex); - //m_dataCache[dataType] = data; +void DataProcessor::processJsonArray(const QVariant& data) +{ + emit httpProcessed("recommend",data); } QVariant DataProcessor::getProcessedData(const QString& key) const diff --git a/diagramCommunication/source/httpChannel.cpp b/diagramCommunication/source/httpChannel.cpp index 75979a4..53c6311 100644 --- a/diagramCommunication/source/httpChannel.cpp +++ b/diagramCommunication/source/httpChannel.cpp @@ -5,6 +5,7 @@ #include #include #include +#include HttpChannel::HttpChannel(const ChannelConfig& config, QObject* parent) : BaseChannel(config, parent) @@ -35,16 +36,30 @@ bool HttpChannel::send(const QByteArray& data) return post(data); } -bool HttpChannel::get(const QString& path) +bool HttpChannel::get(const QString& path,const QVariantMap& queryMap) { if (!m_config.endpoint.isValid()) { emit errorOccurred("Invalid endpoint"); return false; } - QUrl url = m_config.endpoint; - if (!path.isEmpty()) { - url.setPath(url.path() + "/" + path); + QUrl url; + if(path.contains("http")){ //url全部输入 + url = QUrl(path); + } + else{ //url部分输入 + url = m_config.endpoint; + if (!path.isEmpty()) { + url.setPath(url.path() + path); + } + + if(!queryMap.isEmpty()){ + QUrlQuery query; + for(auto iter = queryMap.begin();iter != queryMap.end();++iter){ + query.addQueryItem(iter.key(),iter.value().toString()); + }; + url.setQuery(query); + } } QNetworkAccessManager* manager = new QNetworkAccessManager(this); @@ -57,21 +72,25 @@ bool HttpChannel::get(const QString& path) } }); + if(url.isEmpty()) + qDebug()<<"http url empty!"; + QNetworkRequest request(url); // 设置头 - for (auto it = m_headers.begin(); it != m_headers.end(); ++it) { - request.setRawHeader(it.key().toUtf8(), it.value().toUtf8()); - } + // for (auto it = m_headers.begin(); it != m_headers.end(); ++it) { + // request.setRawHeader(it.key().toUtf8(), it.value().toUtf8()); + // } QNetworkReply* reply = manager->get(request); - QObject::connect(reply, &QNetworkReply::finished, [this, reply, manager]() { + QObject::connect(reply, &QNetworkReply::finished, this,[this, reply, manager]() { if (reply->error() == QNetworkReply::NoError) { QByteArray data = reply->readAll(); emit dataReceived(data); } else { emit errorOccurred(reply->errorString()); + qDebug()<errorString(); } reply->deleteLater(); @@ -90,7 +109,7 @@ bool HttpChannel::post(const QByteArray& data, const QString& path) QUrl url = m_config.endpoint; if (!path.isEmpty()) { - url.setPath(url.path() + "/" + path); + url.setPath(url.path() + path); } QNetworkAccessManager* manager = new QNetworkAccessManager(this); diff --git a/diagramCommunication/source/uiCommunicationBus.cpp b/diagramCommunication/source/uiCommunicationBus.cpp index e1e0dcf..81693b6 100644 --- a/diagramCommunication/source/uiCommunicationBus.cpp +++ b/diagramCommunication/source/uiCommunicationBus.cpp @@ -39,10 +39,9 @@ UiCommunicationBus::UiCommunicationBus(QObject* parent) DataProcessor* processor = DataProcessor::instance(); connect(processor, &DataProcessor::httpProcessed, this, [this](const QString& dataType, const QVariant& data) { - if(dataType == "recommend"){ - // 推荐列表请求将数据分发回订阅ui - broadcastToUis(dataType, data); - } + // if(dataType == "recommend"){ + // broadcastToUis(dataType, data); + // } emit httpDataProcessed(dataType,data); }); @@ -54,12 +53,12 @@ UiCommunicationBus::UiCommunicationBus(QObject* parent) qDebug() << "UiCommunicationBus initialized"; } -void UiCommunicationBus::sendHttpRequest(const QString& endpoint, const QVariant& data) +void UiCommunicationBus::sendHttpRequest(const QString& endpoint, const QVariant& data,const QString& method,const QVariantMap& query) { CommunicationManager* comm = CommunicationManager::instance(); QJsonDocument doc = QJsonDocument::fromVariant(data); - bool success = comm->sendHttpRequest(endpoint, doc.toJson()); + bool success = comm->sendHttpRequest(endpoint, doc.toJson(),method,query); if (success) { qDebug() << "HTTP请求已发送:" << endpoint; @@ -102,7 +101,7 @@ void UiCommunicationBus::onHttpDataReceived(const QByteArray& data) } } - qDebug() << "HTTP响应已处理"; + qDebug() << "HTTP "; } void UiCommunicationBus::onWebSocketDataReceived(const QByteArray& data) diff --git a/diagramCommunication/source/webSocketChannel.cpp b/diagramCommunication/source/webSocketChannel.cpp index d23036f..6f45bed 100644 --- a/diagramCommunication/source/webSocketChannel.cpp +++ b/diagramCommunication/source/webSocketChannel.cpp @@ -2,7 +2,7 @@ #include "webSocketChannel.h" #include -WebSocketChannel::WebSocketChannel(const ChannelConfig& config, QObject* parent) +WebSocketChannel::WebSocketChannel(const ChannelConfig& config, QString sessionId, QObject* parent) : BaseChannel(config, parent) , m_webSocket(new QWebSocket) { @@ -14,6 +14,7 @@ WebSocketChannel::WebSocketChannel(const ChannelConfig& config, QObject* parent) this, &WebSocketChannel::onTextMessageReceived); QObject::connect(m_webSocket, &QWebSocket::binaryMessageReceived, this, &WebSocketChannel::onBinaryMessageReceived); + m_sessionId = sessionId; } bool WebSocketChannel::connect() @@ -27,7 +28,24 @@ bool WebSocketChannel::connect() return false; } - m_webSocket->open(m_config.endpoint); + // 1. 从 WebSocket URL 提取 host 和 port + QUrl url(m_config.endpoint); + QString host = url.host(); + int port = url.port(80); // 默认端口 80 + + // 2. 构建 Origin URL + QString origin = QString("http://%1:%2").arg(host).arg(port); + + // 3. 创建 QNetworkRequest 并设置 Origin + QNetworkRequest request(url); + request.setRawHeader("Origin", origin.toUtf8()); + + // 4. 使用 QWebSocket 连接 + QWebSocket *socket = new QWebSocket(); + socket->open(request); + + qDebug() << "WebSocket URL:" << m_config.endpoint; + qDebug() << "Origin:" << origin; return true; } @@ -73,21 +91,21 @@ void WebSocketChannel::setWebSocketConfig(const WebSocketConfig& config) void WebSocketChannel::onConnected() { - emit connected(); + emit connected(m_sessionId); } void WebSocketChannel::onDisconnected() { - emit disconnected(); + emit disconnected(m_sessionId); } void WebSocketChannel::onTextMessageReceived(const QString& message) { - emit textMessageReceived(message); - emit dataReceived(message.toUtf8()); + emit textMessageReceived(message,m_sessionId); + emit dataReceived(message.toUtf8(),m_sessionId); } void WebSocketChannel::onBinaryMessageReceived(const QByteArray& message) { - emit dataReceived(message); + emit dataReceived(message,m_sessionId); } diff --git a/source/monitorPagesDlg.cpp b/source/monitorPagesDlg.cpp index 29c8e7d..7dd87e6 100644 --- a/source/monitorPagesDlg.cpp +++ b/source/monitorPagesDlg.cpp @@ -51,7 +51,7 @@ void MonitorPagesDlg::onItemClicked(const QModelIndex &index) { QStandardItem* item = _pModel->itemFromIndex(index); int nLevel = getLevel(item); - if(nLevel == 0) //顶层不响应 + if(nLevel == 0 || nLevel == -1) //顶层不响应 return; QStandardItem* parent = item->parent(); if(item)