add communication ui/structure

This commit is contained in:
baiYue 2025-12-12 17:46:37 +08:00
parent a4e3b529bd
commit 314d53ab98
29 changed files with 2462 additions and 41 deletions

View File

@ -11,7 +11,7 @@ set(CMAKE_AUTORCC ON)
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui Widgets Sql Xml REQUIRED Charts)
find_package(Qt6 REQUIRED COMPONENTS SvgWidgets)
find_package(Qt6 COMPONENTS Network REQUIRED)
find_package(Qt6 COMPONENTS Network WebSockets REQUIRED)
find_package(PostgreSQL REQUIRED)
@ -158,8 +158,9 @@ set_target_properties(DiagramDesigner PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${dd_PlatformDir}/bin"
)
target_link_libraries(DiagramDesigner PRIVATE diagramCavas diagramUtils)
target_link_libraries(DiagramDesigner PRIVATE diagramCavas diagramUtils diagramCommunication)
add_subdirectory(diagramCavas)
add_subdirectory(diagramUtils)
add_subdirectory(diagramCommunication)
file(COPY setting.xml DESTINATION "${CMAKE_BINARY_DIR}/${dd_PlatformDir}/bin")

View File

@ -40,6 +40,7 @@ set(DIAGRAMCAVAS_HEADER_FILES
include/projectIconSetting.h
include/projectIconSelectionDlg.h
include/projectDiagramNameInput.h
include/diagramConnectSetting.h
include/diagramEditor/editPanel.h
include/diagramEditor/editView.h
include/diagramEditor/editScene.h
@ -112,6 +113,7 @@ set(DIAGRAMCAVAS_HEADER_FILES
include/util/scalingSelector.h
include/util/selectorManager.h
include/util/subMovingSelector.h
include/instance/dataAccessor.h
../common/include/httpInterface.h
../common/include/tools.h
../common/include/global.h
@ -160,6 +162,7 @@ set(DIAGRAMCAVAS_SOURCE_FILES
source/projectIconSetting.cpp
source/projectIconSelectionDlg.cpp
source/projectDiagramNameInput.cpp
source/diagramConnectSetting.cpp
source/diagramEditor/editPanel.cpp
source/diagramEditor/editView.cpp
source/diagramEditor/editScene.cpp
@ -232,6 +235,7 @@ set(DIAGRAMCAVAS_SOURCE_FILES
source/util/scalingSelector.cpp
source/util/selectorManager.cpp
source/util/subMovingSelector.cpp
source/instance/dataAccessor.cpp
../common/source/httpInterface.cpp
../common/source/baseProperty.cpp
../common/source/tools.cpp
@ -263,6 +267,7 @@ set(UI_FILES
ui/monitorDetailAttributeDlg.ui
ui/monitorDisplaySettingDlg.ui
ui/loadMonitorPageDlg.ui
ui/diagramConnectSetting.ui
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
@ -288,6 +293,7 @@ target_link_libraries(diagramCavas PUBLIC Qt${QT_VERSION_MAJOR}::Core
target_link_libraries(diagramCavas PRIVATE Qt6::SvgWidgets)
target_link_libraries(diagramCavas PRIVATE Qt6::Xml)
target_link_libraries(diagramCavas PRIVATE Qt6::Network)
target_link_libraries(diagramCavas PRIVATE Qt6::WebSockets)
target_link_libraries(diagramCavas PRIVATE Qt6::Charts)
target_link_libraries(diagramCavas PRIVATE Qt6::Sql ${PostgreSQL_LIBRARIES})
@ -298,6 +304,7 @@ option(BUILD_SHARED_LIBS "Build as shared library" ON)
target_include_directories(diagramCavas PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(diagramCavas PRIVATE diagramUtils)
target_link_libraries(diagramCavas PRIVATE diagramCommunication)
target_compile_definitions(diagramCavas
PUBLIC

View File

@ -18,6 +18,7 @@ class EditBaseItem;
class MonitorPanel;
class CornerMonitorLauncher;
class LoadMonitorPageDlg;
class DiagramConnectSetting;
class DIAGRAM_DESIGNER_PUBLIC DiagramCavas : public QMdiArea
{
@ -64,6 +65,8 @@ public slots:
void onSignal_deleteDiagram(DiagramInfo);
void onSignal_selectDiagram(DiagramInfo);
void onSignal_openNetSetting(); //打开网络设置
void onCreateTestBaseModelDiagram(); //生成测试基模图
/******************************生成组态***********************************/
void onSignal_createEditPanel(QString,QUuid);
@ -104,6 +107,7 @@ private:
QString _curPage;
CornerMonitorLauncher* _cornerButton; //简略菜单呼出按钮
LoadMonitorPageDlg* _loadMonitorPageDlg;
DiagramConnectSetting* _connectSetting;
};
#endif

View File

@ -0,0 +1,35 @@
#ifndef DIAGRAMCONNECTSETTING_H
#define DIAGRAMCONNECTSETTING_H
#include <QDialog>
#include "global.h"
/*******************************************************
********************************************************/
QT_BEGIN_NAMESPACE
namespace Ui { class diagramConnectSetting; }
QT_END_NAMESPACE
struct ChannelConfig;
class DiagramConnectSetting : public QDialog
{
Q_OBJECT
public:
DiagramConnectSetting(QWidget *parent = nullptr);
~DiagramConnectSetting();
void showDlg();
public slots:
void onTestHttpClicked();
void onTestWebsocketClicked();
void onOkClicked();
void onCancelClicked();
private:
void initial();
void updateByConfig(ChannelConfig,int nType = 0); //0http 1websocket
private:
Ui::diagramConnectSetting *ui;
};
#endif

View File

@ -0,0 +1,18 @@
#ifndef DATAACCESSOR_H
#define DATAACCESSOR_H
/*********中转、处理网络数据*********/
#include <QObject>
#include <QMap>
class DataAccessor : public QObject
{
Q_OBJECT
public:
DataAccessor(QObject *parent = nullptr);
~DataAccessor();
private:
QMap<QString,QMap<quint64,double>> _realTimeData;
};
#endif

View File

@ -18,11 +18,15 @@
#include "basePropertyManager.h"
#include "cornerMonitorLauncher.h"
#include "loadMonitorPageDlg.h"
#include "diagramConnectSetting.h"
#include "diagramCommunication/include/communicationManager.h"
#include "diagramCommunication/include/configManager.h"
DiagramCavas::DiagramCavas(QWidget *parent)
: QMdiArea(parent)
,_cornerButton(nullptr)
,_loadMonitorPageDlg(nullptr)
,_connectSetting(nullptr)
{
_pageIndex = 0;
}
@ -77,6 +81,19 @@ void DiagramCavas::initial()
}
});
connect(_loadMonitorPageDlg,&LoadMonitorPageDlg::monitorSelected,this,&DiagramCavas::onSignal_monitorSelected);
_connectSetting = new DiagramConnectSetting(this);
// 初始化通信管理器
CommunicationManager* comm = CommunicationManager::instance();
comm->initialize();
// 加载配置
ConfigManager* config = ConfigManager::instance();
config->loadConfig("config.json");
// 应用配置
comm->updateHttpConfig(config->getHttpConfig());
comm->updateWebSocketConfig(config->getWebSocketConfig());
}
void DiagramCavas::onSignal_addDrawingPanel(PowerEntity* pItem,DiagramMode mode,QString parent)
@ -432,6 +449,13 @@ void DiagramCavas::onSignal_selectDiagram(DiagramInfo info)
}
}
void DiagramCavas::onSignal_openNetSetting()
{
if(_connectSetting){
_connectSetting->showDlg();
}
}
void DiagramCavas::removePanel(PowerEntity* pEntity)
{
QMap<QString,QPair<DrawingPanel*,QMdiSubWindow*>>::Iterator iter;

View File

@ -0,0 +1,70 @@
#include "diagramConnectSetting.h"
#include "ui_diagramConnectSetting.h"
#include "diagramCommunication/include/configManager.h"
DiagramConnectSetting::DiagramConnectSetting(QWidget *parent)
: QDialog(parent)
, ui(new Ui::diagramConnectSetting)
{
ui->setupUi(this);
this->setWindowFlags(Qt::FramelessWindowHint | windowFlags());
initial();
}
DiagramConnectSetting::~DiagramConnectSetting()
{
delete ui;
}
void DiagramConnectSetting::initial()
{
connect(ui->btn_testHttp,&QPushButton::clicked,this,&DiagramConnectSetting::onTestHttpClicked);
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);
}
void DiagramConnectSetting::updateByConfig(ChannelConfig info,int nType)
{
if(nType == 0){
ui->le_httpName->setText(info.name);
ui->le_httpIp->setText(info.endpoint);
ui->le_httpOver->setText(QString::number(info.timeout));
}
else if(nType == 1){
ui->le_websocName->setText(info.name);
ui->le_websocIp->setText(info.endpoint);
ui->le_websocOver->setText(QString::number(info.timeout));
ui->le_websocHeart->setText(QString::number(info.heartbeatInterval));
}
}
void DiagramConnectSetting::showDlg()
{
show();
ConfigManager* config = ConfigManager::instance();
auto httpInfo = config->getHttpConfig();
updateByConfig(httpInfo,0);
auto socketInfo = config->getWebSocketConfig();
updateByConfig(socketInfo,1);
}
void DiagramConnectSetting::onTestHttpClicked()
{
}
void DiagramConnectSetting::onTestWebsocketClicked()
{
}
void DiagramConnectSetting::onOkClicked()
{
hide();
}
void DiagramConnectSetting::onCancelClicked()
{
hide();
}

View File

@ -0,0 +1,12 @@
#include "instance/dataAccessor.h"
DataAccessor::DataAccessor(QObject* parent)
: QObject(parent)
{
}
DataAccessor::~DataAccessor()
{
}

View File

@ -112,29 +112,6 @@ void MonitorDisplaySettingDlg::onCheckboxToggled(bool val)
void MonitorDisplaySettingDlg::onIconSelectClicked()
{
// if(!_curMeta.isEmpty() && !_curModel.isEmpty()){
// auto mapAllSvg = ProjectModelManager::instance().getData()[_curMeta][_curModel].modelSetting.mapSvg;
// ProjectIconSelectionDlg dialog(mapAllSvg, this);
// if (dialog.exec() == QDialog::Accepted) {
// QByteArray selectedSVG = dialog.selectedSVG();
// if (!selectedSVG.isEmpty()) {
// QSvgRenderer renderer(selectedSVG);
// QPixmap pixmap(32, 32);
// pixmap.fill(Qt::transparent);
// QPainter painter(&pixmap);
// renderer.render(&painter);
// ui->btn_selectIcon->setIcon(QIcon(pixmap));
// if (validateSvgData(selectedSVG)) {
// updateIconDisplay(selectedSVG);
// if(_curType.isValid() && _curState.isValid()){
// _tempSetting[_curType][_curState].bytPicture = selectedSVG;
// }
// }
// }
// }
// }
if(_curMeta.isEmpty() || _curModel.isEmpty()){
return;
}
@ -217,22 +194,6 @@ void MonitorDisplaySettingDlg::onDeviceComboBoxChanged(const QString& str)
void MonitorDisplaySettingDlg::onStateComboBoxChanged(const QString& str)
{
/*if(_tempSetting.contains(_curType)){
monitorItemStateStruct keyState;
keyState.sState = str;
keyState.eState = monitorItemState(ui->cb_state->currentData().toInt());
if(_tempSetting[_curType].contains(keyState)){
saveSetting(_curType,_curState);
auto info = _tempSetting[_curType][keyState];
ui->checkBox_custom->setChecked(info.bEnable);
if(_curModel != info.sModel){
_curModel = info.sModel;
}
_curState = keyState;
loadSetting(_curType,_curState);
}
}*/
if (str.isEmpty() || str == _curState.sState) {
return;
}

View File

@ -0,0 +1,469 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>diagramConnectSetting</class>
<widget class="QDialog" name="diagramConnectSetting">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>393</width>
<height>502</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>12</pointsize>
</font>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QWidget" name="widget" native="true">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>21</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(196, 196, 196);</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="topMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="styleSheet">
<string notr="true">color: rgb(0, 0, 0);
font: 12pt &quot;Microsoft YaHei UI&quot;;</string>
</property>
<property name="text">
<string>网络通信设置</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>302</width>
<height>18</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>HTTP设置</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<property name="spacing">
<number>8</number>
</property>
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>HTTP服务器配置</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="horizontalSpacing">
<number>4</number>
</property>
<property name="verticalSpacing">
<number>8</number>
</property>
<item row="2" column="2">
<widget class="QLabel" name="label_6">
<property name="text">
<string>ms</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>超时时间:</string>
</property>
</widget>
</item>
<item row="1" column="1" colspan="3">
<widget class="QLineEdit" name="le_httpIp"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>连接名称:</string>
</property>
</widget>
</item>
<item row="2" column="3">
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>217</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1" colspan="3">
<widget class="QLineEdit" name="le_httpName"/>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="le_httpOver">
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>服务器地址</string>
</property>
</widget>
</item>
<item row="3" column="3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>连接测试</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="btn_testHttp">
<property name="text">
<string>测试连接</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>状态:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_httpState">
<property name="text">
<string>未连接</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_5">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>WebSoket设置</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>WebSocket服务器配置</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="verticalSpacing">
<number>8</number>
</property>
<item row="3" column="3" colspan="2">
<spacer name="horizontalSpacer_7">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>214</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>服务器地址</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>连接名称:</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QLabel" name="label_11">
<property name="text">
<string>ms</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="le_websocOver">
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>超时时间:</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_12">
<property name="text">
<string>心跳间隔:</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="4">
<widget class="QLineEdit" name="le_websocName"/>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="le_websocHeart">
<property name="maximumSize">
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
<item row="1" column="1" colspan="4">
<widget class="QLineEdit" name="le_websocIp"/>
</item>
<item row="4" column="3">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="2">
<widget class="QLabel" name="label_7">
<property name="text">
<string>ms</string>
</property>
</widget>
</item>
<item row="2" column="3" colspan="2">
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>217</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox_5">
<property name="title">
<string>连接测试</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="btn_testWebsoc">
<property name="text">
<string>测试连接</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_13">
<property name="text">
<string>状态:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_websocState">
<property name="text">
<string>未连接</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_9">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>操作日志</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QListWidget" name="lst_log"/>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<spacer name="horizontalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btn_ok">
<property name="text">
<string>保存</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_cancel">
<property name="text">
<string>取消</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,58 @@
project(diagramCommunication)
set(DIAGRACOMMUNICATION_HEADER_FILES
include/channelConfig.h
include/baseChannel.h
include/communicationManager.h
include/httpChannel.h
include/webSocketChannel.h
include/configManager.h
include/uiCommunicationBus.h
include/dataProcessor.h
../common/include/compiler.hpp
../common/include/export.hpp
../common/include/operatingSystem.hpp
)
set(DIAGRACOMMUNICATION_SOURCE_FILES
source/communicationManager.cpp
source/baseChannel.cpp
source/webSocketChannel.cpp
source/httpChannel.cpp
source/configManager.cpp
source/uiCommunicationBus.cpp
source/dataProcessor.cpp
)
if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_library(diagramCommunication SHARED
MANUAL_FINALIZATION
${DIAGRACOMMUNICATION_HEADER_FILES}
${DIAGRACOMMUNICATION_SOURCE_FILES}
)
else()
add_library(diagramCommunication SHARED
${DIAGRACOMMUNICATION_HEADER_FILES}
${DIAGRACOMMUNICATION_SOURCE_FILES}
)
endif()
target_link_libraries(diagramCommunication PUBLIC Qt${QT_VERSION_MAJOR}::Core)
target_link_libraries(diagramCommunication PRIVATE Qt6::Xml)
target_link_libraries(diagramCommunication PRIVATE Qt6::Network)
target_link_libraries(diagramCommunication PRIVATE Qt6::WebSockets)
target_link_libraries(diagramCommunication PRIVATE Qt6::Sql ${PostgreSQL_LIBRARIES})
option(BUILD_SHARED_LIBS "Build as shared library" ON)
target_include_directories(diagramCommunication PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_definitions(diagramCommunication
PUBLIC
DIAGRAM_DESIGNER_SHARED
PRIVATE
DIAGRAM_DESIGNER_EXPORTS
#QT_NO_KEYWORDS
)

View File

@ -0,0 +1,49 @@
// ConfigManager.h
#pragma once
#include "channelConfig.h"
#include <QObject>
#include <QString>
#include <QFile>
#include <QJsonDocument>
#include "export.hpp"
class DIAGRAM_DESIGNER_PUBLIC ConfigManager : public QObject
{
Q_OBJECT
public:
static ConfigManager* instance();
// 加载配置
bool loadConfig(const QString& configFile = "");
// 保存配置
bool saveConfig();
// 获取配置
ChannelConfig getHttpConfig() const;
ChannelConfig getWebSocketConfig() const;
// 更新配置
void setHttpConfig(const ChannelConfig& config);
void setWebSocketConfig(const ChannelConfig& config);
// 获取配置路径
QString configFilePath() const;
signals:
void configLoaded();
void configSaved();
void httpConfigChanged(const ChannelConfig& config);
void websocketConfigChanged(const ChannelConfig& config);
private:
ConfigManager(QObject* parent = nullptr);
bool createDefaultConfig();
ChannelConfig getDefaultHttpConfig() const;
ChannelConfig getDefaultWebSocketConfig() const;
ChannelConfig m_httpConfig;
ChannelConfig m_websocketConfig;
QString m_configFile;
};

View File

@ -0,0 +1,71 @@
#pragma once
#include <QObject>
#include <QUrl>
#include <QTimer>
#include <QMutex>
#include <QMap>
#include "export.hpp"
class DIAGRAM_DESIGNER_PUBLIC BaseChannel : public QObject
{
Q_OBJECT
public:
struct ChannelConfig {
QString channelId;
QUrl endpoint;
int timeout = 30000; // 超时时间(ms)
int reconnectInterval = 5000; // 重连间隔(ms)
int maxRetries = 3; // 最大重试次数
QVariantMap params; // 自定义参数
};
explicit BaseChannel(const ChannelConfig& config, QObject* parent = nullptr);
virtual ~BaseChannel();
// 连接管理
virtual bool connect() = 0;
virtual bool disconnect() = 0;
virtual bool isConnected() const = 0;
// 数据发送
virtual bool send(const QByteArray& data) = 0;
// 信息获取
QString channelId() const { return m_config.channelId; }
ChannelConfig config() const { return m_config; }
QUrl endpoint() const { return m_config.endpoint; }
// 控制
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);
protected:
// 公共方法
void startReconnectTimer();
void stopReconnectTimer();
void reconnect();
// 工具方法
QByteArray generateMessageId() const;
qint64 currentTimestamp() const;
// 成员变量
ChannelConfig m_config;
bool m_autoReconnect = true;
private slots:
void onReconnectTimeout();
private:
QTimer* m_reconnectTimer = nullptr;
int m_reconnectCount = 0;
QMutex m_mutex;
};

View File

@ -0,0 +1,74 @@
// ChannelConfig.h
#pragma once
#include <QObject>
#include <QString>
#include <QUrl>
#include <QVariantMap>
#include <QDateTime>
#include "export.hpp"
// 简化配置结构
struct DIAGRAM_DESIGNER_PUBLIC ChannelConfig {
// 通用配置
QString id; // 通道ID: "http_channel" 或 "websocket_channel"
QString name; // 通道名称
QString endpoint; // 连接地址
int timeout = 30000; // 超时时间(ms)
bool enabled = true; // 是否启用
bool autoConnect = false; // 是否自动连接
// 认证
QString username;
QString password;
// 状态
bool connected = false;
QDateTime lastConnectTime;
int errorCount = 0;
// HTTP特有
QVariantMap headers; // HTTP头
// WebSocket特有
int heartbeatInterval = 30000; // 心跳间隔
// 转换为Map
QVariantMap toMap() const {
return {
{"id", id},
{"name", name},
{"endpoint", endpoint},
{"timeout", timeout},
{"enabled", enabled},
{"autoConnect", autoConnect},
{"username", username},
{"password", password},
{"connected", connected},
{"lastConnectTime", lastConnectTime.toString(Qt::ISODate)},
{"errorCount", errorCount},
{"headers", headers},
{"heartbeatInterval", heartbeatInterval}
};
}
// 从Map创建
static ChannelConfig fromMap(const QVariantMap& map) {
ChannelConfig config;
config.id = map.value("id").toString();
config.name = map.value("name").toString();
config.endpoint = map.value("endpoint").toString();
config.timeout = map.value("timeout", 30000).toInt();
config.enabled = map.value("enabled", true).toBool();
config.autoConnect = map.value("autoConnect", false).toBool();
config.username = map.value("username").toString();
config.password = map.value("password").toString();
config.connected = map.value("connected", false).toBool();
config.lastConnectTime = QDateTime::fromString(
map.value("lastConnectTime").toString(), Qt::ISODate);
config.errorCount = map.value("errorCount", 0).toInt();
config.headers = map.value("headers").toMap();
config.heartbeatInterval = map.value("heartbeatInterval", 30000).toInt();
return config;
}
};

View File

@ -0,0 +1,73 @@
// CommunicationManager.h
#pragma once
#include "channelConfig.h"
#include "httpChannel.h"
#include "webSocketChannel.h"
#include <QObject>
#include <QSharedPointer>
#include "export.hpp"
class DIAGRAM_DESIGNER_PUBLIC CommunicationManager : public QObject
{
Q_OBJECT
public:
static CommunicationManager* instance();
// 初始化
bool initialize();
// HTTP通道操作
bool connectHttp();
bool disconnectHttp();
bool sendHttpRequest(const QString& path,
const QByteArray& data = QByteArray(),
const QString& method = "GET");
// WebSocket通道操作
bool connectWebSocket();
bool disconnectWebSocket();
bool sendWebSocketMessage(const QByteArray& data);
bool sendWebSocketText(const QString& text);
// 状态查询
bool isHttpConnected() const;
bool isWebSocketConnected() const;
ChannelConfig getHttpConfig() const;
ChannelConfig getWebSocketConfig() const;
// 配置更新
void updateHttpConfig(const ChannelConfig& config);
void updateWebSocketConfig(const ChannelConfig& config);
signals:
// HTTP通道信号
void httpConnected();
void httpDisconnected();
void httpDataReceived(const QByteArray& data);
void httpError(const QString& error);
// WebSocket通道信号
void websocketConnected();
void websocketDisconnected();
void websocketDataReceived(const QByteArray& data);
void websocketTextReceived(const QString& text);
void websocketError(const QString& error);
private:
CommunicationManager(QObject* parent = nullptr);
~CommunicationManager();
// 内部初始化
void initHttpChannel();
void initWebSocketChannel();
// 配置
ChannelConfig m_httpConfig;
ChannelConfig m_websocketConfig;
// 通道实例
QSharedPointer<HttpChannel> m_httpChannel;
QSharedPointer<WebSocketChannel> m_websocketChannel;
};

View File

@ -0,0 +1,39 @@
// DataProcessor.h
#pragma once
#include <QObject>
#include <QVariant>
#include <QMap>
#include <QMutex>
#include "export.hpp"
// 网络数据处理中心
class DIAGRAM_DESIGNER_PUBLIC DataProcessor : public QObject
{
Q_OBJECT
public:
static DataProcessor* instance();
// 处理数据
void processData(const QVariant& data,int conType = 0);
// 获取处理后的数据
QVariant getProcessedData(const QString& key) const;
// 清除所有数据
void clearAllData();
signals:
// 数据处理完成信号
void httpProcessed(const QString& sType,const QVariant& data);
void websocketProcessed(const QVariant& data);
private:
DataProcessor(QObject* parent = nullptr);
// 通用处理函数
void processJson(const QVariant& data,int conType = 0); //0http 1websocket
// 数据缓存
QMap<QString, QVariant> m_dataCache;
mutable QMutex m_mutex;
};

View File

@ -0,0 +1,32 @@
// HttpChannel.h
#pragma once
#include "baseChannel.h"
class DIAGRAM_DESIGNER_PUBLIC HttpChannel : public BaseChannel
{
Q_OBJECT
public:
HttpChannel(const ChannelConfig& config, QObject* parent = nullptr);
bool connect() override;
bool disconnect() override;
bool isConnected() const override;
bool send(const QByteArray& data) override;
// HTTP方法
bool get(const QString& path = "");
bool post(const QByteArray& data, const QString& path = "");
bool put(const QByteArray& data, const QString& path = "");
bool deleteResource(const QString& path = "");
// 配置
void setBasicAuth(const QString& username, const QString& password);
void setHeader(const QString& name, const QString& value);
private:
QString m_username;
QString m_password;
QMap<QString, QString> m_headers;
};

View File

@ -0,0 +1,48 @@
// uiCommunicationBus.h
#pragma once
#include "export.hpp"
#include <QObject>
#include <QMap>
#include <QVariant>
#include <QMutex>
// UI通信总线
class DIAGRAM_DESIGNER_PUBLIC UiCommunicationBus : public QObject
{
Q_OBJECT
public:
static UiCommunicationBus* instance();
// 发送HTTP请求
void sendHttpRequest(const QString& endpoint, const QVariant& data = QVariant());
// 发送HTTP请求无回复
void sendHttpRequestNoReply(const QString& endpoint, const QVariant& data = QVariant());
// 向UI发送数据
void sendToUi(const QString& uiId, const QString& action, const QVariant& data);
// 广播到所有UI
void broadcastToUis(const QString& action, const QVariant& data);
// 注册/注销UI
void registerUi(const QString& uiId, QObject* uiObject);
void unregisterUi(const QString& uiId);
signals:
void httpDataProcessed(const QString& type,const QVariant& data); //发送分拣过的数据给外部
void websocketDataProcessed(const QVariant& data);
private:
UiCommunicationBus(QObject* parent = nullptr);
// 处理HTTP响应
void onHttpDataReceived(const QByteArray& data);
// 处理WebSocket数据
void onWebSocketDataReceived(const QByteArray& data);
// UI注册表
QMap<QString, QObject*> m_uiObjects;
mutable QMutex m_mutex;
};

View File

@ -0,0 +1,38 @@
// WebSocketChannel.h
#pragma once
#include "baseChannel.h"
#include <QWebSocket>
class DIAGRAM_DESIGNER_PUBLIC WebSocketChannel : public BaseChannel
{
Q_OBJECT
public:
struct WebSocketConfig {
int heartbeatInterval = 30000;
};
WebSocketChannel(const ChannelConfig& config, QObject* parent = nullptr);
bool connect() override;
bool disconnect() override;
bool isConnected() const override;
bool send(const QByteArray& data) override;
bool sendText(const QString& text);
void setWebSocketConfig(const WebSocketConfig& config);
signals:
void textMessageReceived(const QString& message);
private slots:
void onConnected();
void onDisconnected();
void onTextMessageReceived(const QString& message);
void onBinaryMessageReceived(const QByteArray& message);
private:
QWebSocket* m_webSocket = nullptr;
WebSocketConfig m_wsConfig;
};

View File

@ -0,0 +1,76 @@
#include "baseChannel.h"
#include <QDateTime>
#include <QCryptographicHash>
#include <QDebug>
BaseChannel::BaseChannel(const ChannelConfig& config, QObject* parent)
: QObject(parent)
, m_config(config)
, m_reconnectTimer(new QTimer(this))
{
m_reconnectTimer->setSingleShot(true);
QObject::connect(m_reconnectTimer,&QTimer::timeout, this, &BaseChannel::onReconnectTimeout);
qDebug() << "BaseChannel created:" << m_config.channelId;
}
BaseChannel::~BaseChannel()
{
stopReconnectTimer();
qDebug() << "BaseChannel destroyed:" << m_config.channelId;
}
void BaseChannel::setAutoReconnect(bool enable)
{
m_autoReconnect = enable;
if (!enable) {
stopReconnectTimer();
}
}
void BaseChannel::startReconnectTimer()
{
if (m_autoReconnect && m_reconnectCount < m_config.maxRetries) {
int delay = m_config.reconnectInterval * (1 << m_reconnectCount); // 指数退避
m_reconnectTimer->start(qMin(delay, 30000)); // 最大30秒
m_reconnectCount++;
}
}
void BaseChannel::stopReconnectTimer()
{
m_reconnectTimer->stop();
m_reconnectCount = 0;
}
void BaseChannel::reconnect()
{
if (m_autoReconnect) {
disconnect();
QTimer::singleShot(100, this, [this]() {
connect();
});
}
}
void BaseChannel::onReconnectTimeout()
{
if (m_autoReconnect) {
qDebug() << "Reconnecting channel" << m_config.channelId
<< "attempt" << m_reconnectCount << "/" << m_config.maxRetries;
connect();
}
}
QByteArray BaseChannel::generateMessageId() const
{
QString id = QString("%1_%2")
.arg(m_config.channelId)
.arg(QDateTime::currentMSecsSinceEpoch());
return QCryptographicHash::hash(id.toUtf8(), QCryptographicHash::Md5).toHex();
}
qint64 BaseChannel::currentTimestamp() const
{
return QDateTime::currentMSecsSinceEpoch();
}

View File

@ -0,0 +1,266 @@
// CommunicationManager.cpp
#include "communicationManager.h"
#include <QDebug>
CommunicationManager* CommunicationManager::instance()
{
static CommunicationManager* instance = nullptr;
static QMutex mutex;
if (!instance) {
QMutexLocker locker(&mutex);
if (!instance) {
instance = new CommunicationManager;
}
}
return instance;
}
CommunicationManager::CommunicationManager(QObject* parent)
: QObject(parent)
{
// 设置默认配置
m_httpConfig.id = "http_channel";
m_httpConfig.name = "HTTP通道";
m_httpConfig.endpoint = "http://localhost:8080";
m_websocketConfig.id = "websocket_channel";
m_websocketConfig.name = "WebSocket通道";
m_websocketConfig.endpoint = "ws://localhost:8888/ws";
}
CommunicationManager::~CommunicationManager()
{
disconnectHttp();
disconnectWebSocket();
}
bool CommunicationManager::initialize()
{
// 初始化HTTP通道
initHttpChannel();
// 初始化WebSocket通道
initWebSocketChannel();
qInfo() << "CommunicationManager initialized";
return true;
}
void CommunicationManager::initHttpChannel()
{
if (m_httpChannel) {
m_httpChannel->disconnect();
}
// 创建HTTP通道
HttpChannel::ChannelConfig httpConfig;
httpConfig.endpoint = QUrl(m_httpConfig.endpoint);
httpConfig.timeout = m_httpConfig.timeout;
m_httpChannel.reset(new HttpChannel(httpConfig));
// 设置认证
if (!m_httpConfig.username.isEmpty() && !m_httpConfig.password.isEmpty()) {
m_httpChannel->setBasicAuth(m_httpConfig.username, m_httpConfig.password);
}
// 设置HTTP头
for (auto it = m_httpConfig.headers.begin(); it != m_httpConfig.headers.end(); ++it) {
m_httpChannel->setHeader(it.key(), it.value().toString());
}
// 连接信号
connect(m_httpChannel.data(), &HttpChannel::connected,
this, &CommunicationManager::httpConnected);
connect(m_httpChannel.data(), &HttpChannel::disconnected,
this, &CommunicationManager::httpDisconnected);
connect(m_httpChannel.data(), &HttpChannel::dataReceived,
this, &CommunicationManager::httpDataReceived);
connect(m_httpChannel.data(), &HttpChannel::errorOccurred,
this, &CommunicationManager::httpError);
}
void CommunicationManager::initWebSocketChannel()
{
if (m_websocketChannel) {
m_websocketChannel->disconnect();
}
// 创建WebSocket通道
WebSocketChannel::ChannelConfig wsConfig;
wsConfig.endpoint = QUrl(m_websocketConfig.endpoint);
wsConfig.timeout = m_websocketConfig.timeout;
WebSocketChannel::WebSocketConfig websocketConfig;
websocketConfig.heartbeatInterval = m_websocketConfig.heartbeatInterval;
m_websocketChannel.reset(new WebSocketChannel(wsConfig));
m_websocketChannel->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);
}
bool CommunicationManager::connectHttp()
{
if (!m_httpChannel) {
qWarning() << "HTTP channel not initialized";
return false;
}
if (m_httpChannel->isConnected()) {
return true;
}
return m_httpChannel->connect();
}
bool CommunicationManager::disconnectHttp()
{
if (!m_httpChannel) {
return false;
}
if (!m_httpChannel->isConnected()) {
return true;
}
return m_httpChannel->disconnect();
}
bool CommunicationManager::sendHttpRequest(const QString& path,
const QByteArray& data,
const QString& method)
{
if (!m_httpChannel || !m_httpChannel->isConnected()) {
qWarning() << "HTTP channel not connected";
return false;
}
if (method == "GET") {
return m_httpChannel->get(path);
} else if (method == "POST") {
return m_httpChannel->post(data, path);
} else if (method == "PUT") {
return m_httpChannel->put(data, path);
} else if (method == "DELETE") {
return m_httpChannel->deleteResource(path);
}
qWarning() << "Unsupported HTTP method:" << method;
return false;
}
bool CommunicationManager::connectWebSocket()
{
if (!m_websocketChannel) {
qWarning() << "WebSocket channel not initialized";
return false;
}
if (m_websocketChannel->isConnected()) {
return true;
}
return m_websocketChannel->connect();
}
bool CommunicationManager::disconnectWebSocket()
{
if (!m_websocketChannel) {
return false;
}
if (!m_websocketChannel->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 m_websocketChannel->send(data);
}
bool CommunicationManager::sendWebSocketText(const QString& text)
{
if (!m_websocketChannel || !m_websocketChannel->isConnected()) {
qWarning() << "WebSocket channel not connected";
return false;
}
return m_websocketChannel->sendText(text);
}
bool CommunicationManager::isHttpConnected() const
{
return m_httpChannel && m_httpChannel->isConnected();
}
bool CommunicationManager::isWebSocketConnected() const
{
return m_websocketChannel && m_websocketChannel->isConnected();
}
ChannelConfig CommunicationManager::getHttpConfig() const
{
return m_httpConfig;
}
ChannelConfig CommunicationManager::getWebSocketConfig() const
{
return m_websocketConfig;
}
void CommunicationManager::updateHttpConfig(const ChannelConfig& config)
{
bool reconnect = false;
if (m_httpConfig.endpoint != config.endpoint) {
// 端点变化,需要重新初始化
reconnect = true;
}
m_httpConfig = config;
initHttpChannel();
if (reconnect && config.autoConnect) {
connectHttp();
}
qInfo() << "HTTP config updated";
}
void CommunicationManager::updateWebSocketConfig(const ChannelConfig& config)
{
bool reconnect = false;
if (m_websocketConfig.endpoint != config.endpoint) {
reconnect = true;
}
m_websocketConfig = config;
initWebSocketChannel();
if (reconnect && config.autoConnect) {
connectWebSocket();
}
qInfo() << "WebSocket config updated";
}

View File

@ -0,0 +1,217 @@
// ConfigManager.cpp
#include "configManager.h"
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDebug>
#include <QMutex>
ConfigManager* ConfigManager::instance()
{
static ConfigManager* instance = nullptr;
static QMutex mutex;
if (!instance) {
QMutexLocker locker(&mutex);
if (!instance) {
instance = new ConfigManager;
}
}
return instance;
}
ConfigManager::ConfigManager(QObject* parent)
: QObject(parent)
{
// 设置默认配置路径
QString appDir = QCoreApplication::applicationDirPath();
m_configFile = appDir + "/config.json";
qDebug() << "ConfigManager initialized, config file:" << m_configFile;
}
bool ConfigManager::loadConfig(const QString& configFile)
{
if (!configFile.isEmpty()) {
m_configFile = configFile;
}
QFile file(m_configFile);
// 如果文件不存在,创建默认配置
if (!file.exists()) {
qWarning() << "Config file not found, creating default config:" << m_configFile;
return createDefaultConfig();
}
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "Failed to open config file:" << m_configFile;
return false;
}
QByteArray jsonData = file.readAll();
file.close();
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(jsonData, &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "JSON parse error:" << error.errorString();
return false;
}
if (!doc.isObject()) {
qWarning() << "Config is not a JSON object";
return false;
}
QVariantMap root = doc.object().toVariantMap();
// 加载HTTP配置
if (root.contains("http")) {
m_httpConfig = ChannelConfig::fromMap(root["http"].toMap());
} else {
qWarning() << "Config missing 'http' section, creating default";
m_httpConfig = getDefaultHttpConfig();
}
// 加载WebSocket配置
if (root.contains("websocket")) {
m_websocketConfig = ChannelConfig::fromMap(root["websocket"].toMap());
} else {
qWarning() << "Config missing 'websocket' section, creating default";
m_websocketConfig = getDefaultWebSocketConfig();
}
qInfo() << "Config loaded from:" << m_configFile;
qInfo() << "HTTP endpoint:" << m_httpConfig.endpoint;
qInfo() << "WebSocket endpoint:" << m_websocketConfig.endpoint;
emit configLoaded();
return true;
}
bool ConfigManager::saveConfig()
{
// 确保目录存在
QFileInfo fileInfo(m_configFile);
QDir dir = fileInfo.dir();
if (!dir.exists()) {
if (!dir.mkpath(".")) {
qCritical() << "Failed to create config directory:" << dir.path();
return false;
}
}
QVariantMap root = {
{"http", m_httpConfig.toMap()},
{"websocket", m_websocketConfig.toMap()},
{"lastSaved", QDateTime::currentDateTime().toString(Qt::ISODate)}
};
QFile file(m_configFile);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
qCritical() << "Failed to open config file for writing:" << m_configFile;
return false;
}
QJsonDocument doc = QJsonDocument::fromVariant(root);
file.write(doc.toJson(QJsonDocument::Indented));
file.close();
qInfo() << "Config saved to:" << m_configFile;
emit configSaved();
return true;
}
bool ConfigManager::createDefaultConfig()
{
// 设置默认配置
m_httpConfig = getDefaultHttpConfig();
m_websocketConfig = getDefaultWebSocketConfig();
// 保存默认配置
bool success = saveConfig();
if (success) {
qInfo() << "Default config created at:" << m_configFile;
} else {
qCritical() << "Failed to create default config";
}
return success;
}
ChannelConfig ConfigManager::getDefaultHttpConfig() const
{
ChannelConfig config;
config.id = "http_channel";
config.name = "SCADA数据接口";
config.endpoint = "http://192.168.1.100:8080/api";
config.timeout = 30000;
config.enabled = true;
config.autoConnect = true;
config.username = "";
config.password = "";
config.connected = false;
config.lastConnectTime = QDateTime();
config.errorCount = 0;
// 默认HTTP头
config.headers = QVariantMap{
{"Content-Type", "application/json"},
};
return config;
}
ChannelConfig ConfigManager::getDefaultWebSocketConfig() const
{
ChannelConfig config;
config.id = "websocket_channel";
config.name = "实时数据推送";
config.endpoint = "ws://192.168.1.101:8888/ws";
config.timeout = 30000;
config.enabled = true;
config.autoConnect = false;
config.connected = false;
config.lastConnectTime = QDateTime();
config.errorCount = 0;
config.heartbeatInterval = 30000;
return config;
}
ChannelConfig ConfigManager::getHttpConfig() const
{
return m_httpConfig;
}
ChannelConfig ConfigManager::getWebSocketConfig() const
{
return m_websocketConfig;
}
void ConfigManager::setHttpConfig(const ChannelConfig& config)
{
m_httpConfig = config;
emit httpConfigChanged(config);
}
void ConfigManager::setWebSocketConfig(const ChannelConfig& config)
{
m_websocketConfig = config;
emit websocketConfigChanged(config);
}
QString ConfigManager::configFilePath() const
{
return m_configFile;
}

View File

@ -0,0 +1,85 @@
// DataProcessor.cpp
#include "dataProcessor.h"
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
DataProcessor* DataProcessor::instance()
{
static DataProcessor* instance = nullptr;
static QMutex mutex;
if (!instance) {
QMutexLocker locker(&mutex);
if (!instance) {
instance = new DataProcessor;
}
}
return instance;
}
DataProcessor::DataProcessor(QObject* parent)
: QObject(parent)
{
qDebug() << "DataProcessor initialized";
}
void DataProcessor::processData(const QVariant& data,int conType)
{
qDebug() << "处理数据_size:" << data.toString().size();
// 根据数据类型处理
processJson(data.toJsonObject(),conType);
}
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);
}
}
else if(conType == 1){
if(dataObj.contains("targets")){ //实时数据相关
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")){
/*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();
}*/
}
//QMutexLocker locker(&m_mutex);
//m_dataCache[dataType] = data;
}
QVariant DataProcessor::getProcessedData(const QString& key) const
{
QMutexLocker locker(&m_mutex);
return m_dataCache.value(key);
}
void DataProcessor::clearAllData()
{
QMutexLocker locker(&m_mutex);
m_dataCache.clear();
qDebug() << "已清除所有处理数据";
}

View File

@ -0,0 +1,260 @@
// HttpAdapter.cpp
#include "httpChannel.h"
#include <QNetworkRequest>
#include <QNetworkProxy>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QTimer>
#include <QDebug>
HttpAdapter::HttpAdapter(const ChannelConfig& config, QObject* parent)
: CommunicationChannel(config, parent)
, m_networkManager(new QNetworkAccessManager(this))
{
// 配置SSL
if (m_config.sslConfig.isNull()) {
QSslConfiguration sslConfig = QSslConfiguration::defaultConfiguration();
sslConfig.setPeerVerifyMode(QSslSocket::VerifyNone);
m_config.sslConfig = sslConfig;
}
// 连接信号
connect(m_networkManager, &QNetworkAccessManager::authenticationRequired,
this, &HttpAdapter::onAuthenticationRequired);
qDebug() << "HttpAdapter created for" << m_config.channelId;
}
HttpAdapter::~HttpAdapter()
{
// 取消所有未完成的请求
for (auto reply : m_pendingRequests.keys()) {
reply->abort();
reply->deleteLater();
}
m_pendingRequests.clear();
}
bool HttpAdapter::connectToHost()
{
// HTTP协议无需建立持久连接只需验证端点是否可达
if (m_config.endpoint.isEmpty() || !m_config.endpoint.isValid()) {
emit errorOccurred("Invalid endpoint URL: " + m_config.endpoint.toString());
return false;
}
// 发送一个测试请求验证连接
HttpRequest testRequest;
testRequest.method = GET;
QNetworkRequest request(m_config.endpoint);
request.setSslConfiguration(m_config.sslConfig);
request.setRawHeader("User-Agent", "PowerSCADA/1.0");
QNetworkReply* reply = m_networkManager->get(request);
connect(reply, &QNetworkReply::finished,
this, [this, reply]() {
onReplyFinished(reply);
});
m_pendingRequests.insert(reply, testRequest);
// 设置超时
QTimer::singleShot(m_config.timeout, this, [this, reply]() {
if (reply && reply->isRunning()) {
reply->abort();
emit errorOccurred("Connection timeout");
}
});
emit connected();
return true;
}
bool HttpAdapter::disconnectFromHost()
{
// 取消所有未完成的请求
for (auto reply : m_pendingRequests.keys()) {
reply->abort();
reply->deleteLater();
}
m_pendingRequests.clear();
emit disconnected();
return true;
}
bool HttpAdapter::sendData(const QByteArray& data)
{
HttpRequest request;
request.method = POST;
request.data = data;
request.contentType = "application/octet-stream";
return sendRequest(request);
}
bool HttpAdapter::isConnected() const
{
// HTTP是无状态协议总是返回true表示可以发送请求
return m_config.endpoint.isValid();
}
bool HttpAdapter::sendRequest(const HttpRequest& request)
{
if (!m_config.endpoint.isValid()) {
emit errorOccurred("Invalid endpoint URL");
return false;
}
QNetworkRequest networkRequest(m_config.endpoint);
networkRequest.setSslConfiguration(m_config.sslConfig);
networkRequest.setRawHeader("User-Agent", "PowerSCADA/1.0");
networkRequest.setRawHeader("Content-Type", request.contentType.toUtf8());
// 添加自定义头
for (auto it = request.headers.begin(); it != request.headers.end(); ++it) {
networkRequest.setRawHeader(it.key().toUtf8(), it.value().toUtf8());
}
QNetworkReply* reply = nullptr;
switch (request.method) {
case GET:
reply = m_networkManager->get(networkRequest);
break;
case POST:
reply = m_networkManager->post(networkRequest, request.data);
break;
case PUT:
reply = m_networkManager->put(networkRequest, request.data);
break;
case DELETE:
reply = m_networkManager->deleteResource(networkRequest);
break;
default:
emit errorOccurred("Unsupported HTTP method");
return false;
}
if (!reply) {
emit errorOccurred("Failed to create network request");
return false;
}
// 设置请求超时
QTimer* timeoutTimer = new QTimer(this);
timeoutTimer->setSingleShot(true);
connect(timeoutTimer, &QTimer::timeout, this, [this, reply]() {
if (reply && reply->isRunning()) {
reply->abort();
emit errorOccurred("Request timeout");
}
});
timeoutTimer->start(m_config.timeout);
connect(reply, &QNetworkReply::finished, this, [this, reply, timeoutTimer]() {
timeoutTimer->stop();
timeoutTimer->deleteLater();
onReplyFinished(reply);
});
m_pendingRequests.insert(reply, request);
return true;
}
void HttpAdapter::setAuthentication(const QString& username, const QString& password)
{
m_username = username;
m_password = password;
}
void HttpAdapter::setProxy(const QNetworkProxy& proxy)
{
m_networkManager->setProxy(proxy);
}
bool HttpAdapter::readDataPoints(const QStringList& pointIds)
{
QJsonObject requestObj;
requestObj["command"] = "read";
requestObj["points"] = QJsonArray::fromStringList(pointIds);
requestObj["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);
HttpRequest request;
request.method = POST;
request.data = QJsonDocument(requestObj).toJson();
request.contentType = "application/json";
return sendRequest(request);
}
bool HttpAdapter::writeDataPoint(const QString& pointId, const QVariant& value)
{
QJsonObject requestObj;
requestObj["command"] = "write";
requestObj["point"] = pointId;
requestObj["value"] = QJsonValue::fromVariant(value);
requestObj["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);
HttpRequest request;
request.method = POST;
request.data = QJsonDocument(requestObj).toJson();
request.contentType = "application/json";
return sendRequest(request);
}
bool HttpAdapter::sendControlCommand(const QString& deviceId, int command, const QVariant& param)
{
QJsonObject requestObj;
requestObj["command"] = "control";
requestObj["device"] = deviceId;
requestObj["cmd"] = command;
requestObj["param"] = QJsonValue::fromVariant(param);
requestObj["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);
HttpRequest request;
request.method = POST;
request.data = QJsonDocument(requestObj).toJson();
request.contentType = "application/json";
return sendRequest(request);
}
void HttpAdapter::onReplyFinished(QNetworkReply* reply)
{
if (!reply || !m_pendingRequests.contains(reply)) {
return;
}
auto request = m_pendingRequests.take(reply);
if (reply->error() != QNetworkReply::NoError) {
QString errorMsg = QString("HTTP error: %1 - %2")
.arg(reply->error())
.arg(reply->errorString());
emit errorOccurred(errorMsg);
} else {
QByteArray responseData = reply->readAll();
emit dataReceived(responseData);
// 记录日志
qDebug() << "HTTP response received:" << reply->url().toString()
<< "Status:" << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt()
<< "Size:" << responseData.size() << "bytes";
}
reply->deleteLater();
}
void HttpAdapter::onAuthenticationRequired(QNetworkReply* reply, QAuthenticator* authenticator)
{
if (!m_username.isEmpty() && !m_password.isEmpty()) {
authenticator->setUser(m_username);
authenticator->setPassword(m_password);
} else {
qWarning() << "Authentication required but no credentials provided";
}
}

View File

@ -0,0 +1,143 @@
// HttpChannel.cpp
#include "httpChannel.h"
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QAuthenticator>
#include <QDebug>
HttpChannel::HttpChannel(const ChannelConfig& config, QObject* parent)
: BaseChannel(config, parent)
{
}
bool HttpChannel::connect()
{
// HTTP无需建立持久连接
emit connected();
return true;
}
bool HttpChannel::disconnect()
{
// HTTP无需断开持久连接
emit disconnected();
return true;
}
bool HttpChannel::isConnected() const
{
return m_config.endpoint.isValid(); // 只要端点有效就认为"可连接"
}
bool HttpChannel::send(const QByteArray& data)
{
return post(data);
}
bool HttpChannel::get(const QString& path)
{
if (!m_config.endpoint.isValid()) {
emit errorOccurred("Invalid endpoint");
return false;
}
QUrl url = m_config.endpoint;
if (!path.isEmpty()) {
url.setPath(url.path() + "/" + path);
}
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
QObject::connect(manager, &QNetworkAccessManager::authenticationRequired,
[this](QNetworkReply* reply, QAuthenticator* authenticator) {
if (!m_username.isEmpty() && !m_password.isEmpty()) {
authenticator->setUser(m_username);
authenticator->setPassword(m_password);
}
});
QNetworkRequest request(url);
// 设置头
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]() {
if (reply->error() == QNetworkReply::NoError) {
QByteArray data = reply->readAll();
emit dataReceived(data);
} else {
emit errorOccurred(reply->errorString());
}
reply->deleteLater();
manager->deleteLater();
});
return true;
}
bool HttpChannel::post(const QByteArray& data, const QString& path)
{
if (!m_config.endpoint.isValid()) {
emit errorOccurred("Invalid endpoint");
return false;
}
QUrl url = m_config.endpoint;
if (!path.isEmpty()) {
url.setPath(url.path() + "/" + path);
}
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
for (auto it = m_headers.begin(); it != m_headers.end(); ++it) {
request.setRawHeader(it.key().toUtf8(), it.value().toUtf8());
}
QNetworkReply* reply = manager->post(request, data);
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());
}
reply->deleteLater();
manager->deleteLater();
});
return true;
}
bool HttpChannel::put(const QByteArray& data, const QString& path)
{
// 类似post的实现
return post(data, path); // 简化处理
}
bool HttpChannel::deleteResource(const QString& path)
{
// 类似get的实现
return get(path); // 简化处理
}
void HttpChannel::setBasicAuth(const QString& username, const QString& password)
{
m_username = username;
m_password = password;
}
void HttpChannel::setHeader(const QString& name, const QString& value)
{
m_headers[name] = value;
}

View File

@ -0,0 +1,189 @@
// UiCommunicationBus.cpp
#include "uiCommunicationBus.h"
#include "communicationManager.h"
#include "dataProcessor.h"
#include <QJsonDocument>
#include <QDebug>
#include <QJsonObject>
#include <QJsonArray>
UiCommunicationBus* UiCommunicationBus::instance()
{
static UiCommunicationBus* instance = nullptr;
static QMutex mutex;
if (!instance) {
QMutexLocker locker(&mutex);
if (!instance) {
instance = new UiCommunicationBus;
}
}
return instance;
}
UiCommunicationBus::UiCommunicationBus(QObject* parent)
: QObject(parent)
{
// 连接到CommunicationManager
CommunicationManager* comm = CommunicationManager::instance();
// 连接HTTP信号
connect(comm, &CommunicationManager::httpDataReceived,
this, &UiCommunicationBus::onHttpDataReceived);
// 连接WebSocket信号
connect(comm, &CommunicationManager::websocketDataReceived,
this, &UiCommunicationBus::onWebSocketDataReceived);
// 连接DataProcessor信号
DataProcessor* processor = DataProcessor::instance();
connect(processor, &DataProcessor::httpProcessed,
this, [this](const QString& dataType, const QVariant& data) {
if(dataType == "recommend"){
// 推荐列表请求将数据分发回订阅ui
broadcastToUis(dataType, data);
}
emit httpDataProcessed(dataType,data);
});
connect(processor, &DataProcessor::websocketProcessed,
this, [this](const QVariant& data) {
emit websocketDataProcessed(data);
});
qDebug() << "UiCommunicationBus initialized";
}
void UiCommunicationBus::sendHttpRequest(const QString& endpoint, const QVariant& data)
{
CommunicationManager* comm = CommunicationManager::instance();
QJsonDocument doc = QJsonDocument::fromVariant(data);
bool success = comm->sendHttpRequest(endpoint, doc.toJson());
if (success) {
qDebug() << "HTTP请求已发送:" << endpoint;
} else {
qWarning() << "HTTP请求发送失败:" << endpoint;
}
}
void UiCommunicationBus::sendHttpRequestNoReply(const QString& endpoint, const QVariant& data)
{
CommunicationManager* comm = CommunicationManager::instance();
QJsonDocument doc = QJsonDocument::fromVariant(data);
comm->sendHttpRequest(endpoint, doc.toJson());
qDebug() << "无回复HTTP请求已发送:" << endpoint;
}
void UiCommunicationBus::onHttpDataReceived(const QByteArray& data)
{
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "HTTP响应解析失败:" << error.errorString();
return;
}
QVariant response = doc.toVariant();
if (response.typeId() == QMetaType::QVariantMap) {
QVariantMap responseMap = response.toMap();
DataProcessor* processor = DataProcessor::instance();
QString state = responseMap.value("msg").toString();
if(state == "success"){
if(responseMap.contains("payload")){
processor->processData(responseMap.value("payload"));
}
}
}
qDebug() << "HTTP响应已处理";
}
void UiCommunicationBus::onWebSocketDataReceived(const QByteArray& data)
{
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(data, &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "WebSocket数据解析失败:" << error.errorString();
return;
}
QVariant response = doc.toVariant();
if (response.typeId() == QMetaType::QVariantMap) {
QVariantMap responseMap = response.toMap();
DataProcessor* processor = DataProcessor::instance();
QString state = responseMap.value("msg").toString();
if(state == "success"){
if(responseMap.contains("payload")){
processor->processData(responseMap.value("payload"),1);
}
}
}
qDebug() << "WebSocket数据已处理";
}
void UiCommunicationBus::sendToUi(const QString& uiId, const QString& action, const QVariant& data)
{
QMutexLocker locker(&m_mutex);
if (!m_uiObjects.contains(uiId)) {
qWarning() << "UI未注册:" << uiId;
return;
}
QObject* uiObject = m_uiObjects[uiId];
// 尝试调用通用的消息处理槽
bool success = QMetaObject::invokeMethod(uiObject, "onMessage",
Qt::QueuedConnection,
Q_ARG(QString, action),
Q_ARG(QVariant, data));
if (!success) {
qWarning() << "调用UI消息处理失败:" << uiId << "action:" << action;
}
}
void UiCommunicationBus::broadcastToUis(const QString& action, const QVariant& data)
{
QMutexLocker locker(&m_mutex);
for (auto it = m_uiObjects.begin(); it != m_uiObjects.end(); ++it) {
QObject* uiObject = it.value();
QMetaObject::invokeMethod(uiObject, "onMessage",
Q_ARG(QString, action),
Q_ARG(QVariant, data));
}
qDebug() << "消息广播:" << action << "接收者:" << m_uiObjects.size();
}
void UiCommunicationBus::registerUi(const QString& uiId, QObject* uiObject)
{
if (uiId.isEmpty() || !uiObject) {
qWarning() << "注册UI失败: 参数无效";
return;
}
QMutexLocker locker(&m_mutex);
m_uiObjects[uiId] = uiObject;
qDebug() << "UI已注册:" << uiId;
}
void UiCommunicationBus::unregisterUi(const QString& uiId)
{
QMutexLocker locker(&m_mutex);
m_uiObjects.remove(uiId);
qDebug() << "UI已注销:" << uiId;
}

View File

@ -0,0 +1,93 @@
// WebSocketChannel.cpp
#include "webSocketChannel.h"
#include <QDebug>
WebSocketChannel::WebSocketChannel(const ChannelConfig& config, QObject* parent)
: BaseChannel(config, parent)
, m_webSocket(new QWebSocket)
{
QObject::connect(m_webSocket, &QWebSocket::connected,
this, &WebSocketChannel::onConnected);
QObject::connect(m_webSocket, &QWebSocket::disconnected,
this, &WebSocketChannel::onDisconnected);
QObject::connect(m_webSocket, &QWebSocket::textMessageReceived,
this, &WebSocketChannel::onTextMessageReceived);
QObject::connect(m_webSocket, &QWebSocket::binaryMessageReceived,
this, &WebSocketChannel::onBinaryMessageReceived);
}
bool WebSocketChannel::connect()
{
if (m_webSocket->state() == QAbstractSocket::ConnectedState) {
return true;
}
if (!m_config.endpoint.isValid()) {
emit errorOccurred("Invalid endpoint");
return false;
}
m_webSocket->open(m_config.endpoint);
return true;
}
bool WebSocketChannel::disconnect()
{
if (m_webSocket->state() != QAbstractSocket::UnconnectedState) {
m_webSocket->close();
}
return true;
}
bool WebSocketChannel::isConnected() const
{
return m_webSocket->state() == QAbstractSocket::ConnectedState;
}
bool WebSocketChannel::send(const QByteArray& data)
{
if (!isConnected()) {
emit errorOccurred("WebSocket not connected");
return false;
}
qint64 sent = m_webSocket->sendBinaryMessage(data);
return sent == data.size();
}
bool WebSocketChannel::sendText(const QString& text)
{
if (!isConnected()) {
emit errorOccurred("WebSocket not connected");
return false;
}
qint64 sent = m_webSocket->sendTextMessage(text);
return sent == text.size();
}
void WebSocketChannel::setWebSocketConfig(const WebSocketConfig& config)
{
m_wsConfig = config;
}
void WebSocketChannel::onConnected()
{
emit connected();
}
void WebSocketChannel::onDisconnected()
{
emit disconnected();
}
void WebSocketChannel::onTextMessageReceived(const QString& message)
{
emit textMessageReceived(message);
emit dataReceived(message.toUtf8());
}
void WebSocketChannel::onBinaryMessageReceived(const QByteArray& message)
{
emit dataReceived(message);
}

View File

@ -214,6 +214,9 @@ void CMainWindow::initializeAction()
}
});
QAction* settingAct = ui->menuSetting->addAction(QString::fromWCharArray(L"网络设置"));
connect(settingAct,&QAction::triggered,m_pDiagramCavas,&DiagramCavas::onSignal_openNetSetting);
QAction* testAct = ui->menuTest->addAction(QString::fromWCharArray(L"生成测试基模"));
connect(testAct,&QAction::triggered,m_pDiagramCavas,&DiagramCavas::onCreateTestBaseModelDiagram);
}

View File

@ -48,10 +48,16 @@
<string>测试</string>
</property>
</widget>
<widget class="QMenu" name="menuSetting">
<property name="title">
<string>设置</string>
</property>
</widget>
<addaction name="menuFile"/>
<addaction name="menuView"/>
<addaction name="menuMode"/>
<addaction name="menuProject"/>
<addaction name="menuSetting"/>
<addaction name="menuTest"/>
</widget>
<widget class="QToolBar" name="toolBar">