diff --git a/PayloadAPP.pro b/PayloadAPP.pro index ffcd779..f6b1c55 100644 --- a/PayloadAPP.pro +++ b/PayloadAPP.pro @@ -4,6 +4,7 @@ QT += quickwidgets qml greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++17 +# CONFIG += console QMAKE_PROJECT_DEPTH = 0 # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. @@ -73,6 +74,7 @@ RESOURCES += \ map/places_map.qrc DISTFILES += \ + config.ini \ res/Qss/qss.qss \ style.qss diff --git a/homepagedlg.ui b/homepagedlg.ui index 7f9ada4..d46b754 100644 --- a/homepagedlg.ui +++ b/homepagedlg.ui @@ -22,10 +22,10 @@ <item> <spacer name="horizontalSpacer"> <property name="orientation"> - <enum>Qt::Horizontal</enum> + <enum>Qt::Orientation::Horizontal</enum> </property> <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> + <enum>QSizePolicy::Policy::Fixed</enum> </property> <property name="sizeHint" stdset="0"> <size> @@ -36,12 +36,12 @@ </spacer> </item> <item> - <widget class="QWidget" name="widget" native="true"> + <widget class="QWidget" name="image" native="true"> <property name="toolTip"> - <string><html><head/><body><p><img src=":/res/981csNew.png"/><img src=":/res/981csP.png"/></p></body></html></string> + <string/> </property> <property name="whatsThis"> - <string><html><head/><body><p><img src=":/res/981csNew.png"/></p></body></html></string> + <string/> </property> <property name="styleSheet"> <string notr="true">image: url(:/res/981csNew.png);</string> @@ -51,10 +51,10 @@ <item> <spacer name="horizontalSpacer_2"> <property name="orientation"> - <enum>Qt::Horizontal</enum> + <enum>Qt::Orientation::Horizontal</enum> </property> <property name="sizeType"> - <enum>QSizePolicy::Fixed</enum> + <enum>QSizePolicy::Policy::Fixed</enum> </property> <property name="sizeHint" stdset="0"> <size> diff --git a/mainwindow.cpp b/mainwindow.cpp index 966f939..c7707dc 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -74,6 +74,7 @@ void MainWindow::initWindow() mWeb = new CWebEngineView(); mWeb->setPage(new CustomWebEnginePage()); + mWeb->load(QUrl("http://192.168.150.1")); // mWeb = new QWebEngineView(this); // 设置栈窗口,多页面共享同一窗口 @@ -98,7 +99,7 @@ void MainWindow::initButton() ui->toolButton_5->setIcon(QIcon(":/res/PDT.png")); ui->toolButton_6->setIcon(QIcon(":/res/Ku.png")); ui->toolButton_7->setIcon(QIcon(":/res/research.png")); - ui->toolButton_8->setIcon(QIcon("3D.png")); + ui->toolButton_8->setIcon(QIcon(":/res/3D.png")); ui->toolButton->setIconSize(QSize(sizeX,sizeY)); ui->toolButton_2->setIconSize(QSize(sizeX,sizeY)); ui->toolButton_3->setIconSize(QSize(sizeX,sizeY)); @@ -250,6 +251,7 @@ void MainWindow::toolButton_2_clicked() void MainWindow::toolButton_3_clicked() { changeBtnColor(3); + // mWeb->load(QUrl("http://192.168.1.10")); ui->stackedWidget->setCurrentWidget(mWeb); } @@ -257,8 +259,8 @@ void MainWindow::toolButton_3_clicked() void MainWindow::toolButton_4_clicked() { changeBtnColor(4); - mWeb->load(QUrl("http://192.168.1.10")); - mWeb->show(); + // mWeb->load(QUrl("http://192.168.1.10")); + // mWeb->show(); ui->stackedWidget->setCurrentWidget(mWeb); //process->kill(); } @@ -267,8 +269,8 @@ void MainWindow::toolButton_4_clicked() void MainWindow::toolButton_5_clicked() { changeBtnColor(5); - mWeb->load(QUrl("http://192.168.150.1")); - mWeb->show(); + // mWeb->load(QUrl("http://192.168.150.1")); + // mWeb->show(); ui->stackedWidget->setCurrentWidget(mWeb); } @@ -276,8 +278,8 @@ void MainWindow::toolButton_5_clicked() void MainWindow::toolButton_6_clicked() { changeBtnColor(6); - mWeb->load(QUrl("http://192.168.0.2")); - mWeb->show(); + // mWeb->load(QUrl("http://192.168.0.2")); + // mWeb->show(); ui->stackedWidget->setCurrentWidget(mWeb); } diff --git a/mainwindow.ui b/mainwindow.ui index d825e2f..047ee6b 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -161,7 +161,11 @@ <item row="2" column="2"> <layout class="QHBoxLayout" name="horizontalLayout_2"> <item> - <layout class="QVBoxLayout" name="SubPage"/> + <widget class="QStackedWidget" name="stackedWidget"> + <widget class="QWidget" name="Page1"> + <layout class="QVBoxLayout" name="SubPage"/> + </widget> + </widget> </item> </layout> </item> @@ -178,322 +182,6 @@ </property> </spacer> </item> -<<<<<<< HEAD -======= - <item row="2" column="0"> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="pushButton"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - </font> - </property> - <property name="contextMenuPolicy"> - <enum>Qt::DefaultContextMenu</enum> - </property> - <property name="styleSheet"> - <string notr="true">checked { background-color: rgb(125, 205, 255); }</string> - </property> - <property name="text"> - <string> 主页 </string> - </property> - <property name="icon"> - <iconset resource="mainwindow.qrc"> - <normaloff>:/res/home.png</normaloff>:/res/home.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>30</width> - <height>30</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="pushButton_2"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - </font> - </property> - <property name="contextMenuPolicy"> - <enum>Qt::DefaultContextMenu</enum> - </property> - <property name="styleSheet"> - <string notr="true"/> - </property> - <property name="text"> - <string> 光电吊舱</string> - </property> - <property name="icon"> - <iconset resource="mainwindow.qrc"> - <normaloff>:/res/GDDC.png</normaloff>:/res/GDDC.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>30</width> - <height>30</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="pushButton_3"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - </font> - </property> - <property name="contextMenuPolicy"> - <enum>Qt::DefaultContextMenu</enum> - </property> - <property name="styleSheet"> - <string notr="true">background-color: rgb(125, 205, 255);</string> - </property> - <property name="text"> - <string> L链 </string> - </property> - <property name="icon"> - <iconset resource="mainwindow.qrc"> - <normaloff>:/res/WIFI.png</normaloff>:/res/WIFI.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>30</width> - <height>30</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="pushButton_4"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - </font> - </property> - <property name="contextMenuPolicy"> - <enum>Qt::DefaultContextMenu</enum> - </property> - <property name="styleSheet"> - <string notr="true"/> - </property> - <property name="text"> - <string> 自组网 </string> - </property> - <property name="icon"> - <iconset resource="mainwindow.qrc"> - <normaloff>:/res/wifi4G.png</normaloff>:/res/wifi4G.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>32</width> - <height>32</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="pushButton_5"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - </font> - </property> - <property name="contextMenuPolicy"> - <enum>Qt::DefaultContextMenu</enum> - </property> - <property name="styleSheet"> - <string notr="true"/> - </property> - <property name="text"> - <string> PDT集群 </string> - </property> - <property name="icon"> - <iconset resource="mainwindow.qrc"> - <normaloff>:/res/ptz.png</normaloff>:/res/ptz.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>30</width> - <height>30</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="pushButton_6"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - </font> - </property> - <property name="contextMenuPolicy"> - <enum>Qt::DefaultContextMenu</enum> - </property> - <property name="styleSheet"> - <string notr="true"/> - </property> - <property name="text"> - <string> Ku卫通 </string> - </property> - <property name="icon"> - <iconset resource="mainwindow.qrc"> - <normaloff>:/res/w.png</normaloff>:/res/w.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>30</width> - <height>30</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="pushButton_7"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - </font> - </property> - <property name="contextMenuPolicy"> - <enum>Qt::DefaultContextMenu</enum> - </property> - <property name="styleSheet"> - <string notr="true"/> - </property> - <property name="text"> - <string> 搜救载荷 </string> - </property> - <property name="icon"> - <iconset resource="mainwindow.qrc"> - <normaloff>:/res/research.png</normaloff>:/res/research.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>30</width> - <height>30</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="pushButton_8"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="font"> - <font> - <pointsize>12</pointsize> - </font> - </property> - <property name="contextMenuPolicy"> - <enum>Qt::DefaultContextMenu</enum> - </property> - <property name="styleSheet"> - <string notr="true"/> - </property> - <property name="text"> - <string> 三维建模 </string> - </property> - <property name="icon"> - <iconset resource="mainwindow.qrc"> - <normaloff>:/res/photo.png</normaloff>:/res/photo.png</iconset> - </property> - <property name="iconSize"> - <size> - <width>30</width> - <height>30</height> - </size> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </item> - <item row="2" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout_2"> - <item> - <widget class="QStackedWidget" name=""> - <widget class="QWidget" name="Page1" native="true"> - <layout class="QVBoxLayout" name="SubPage"/> - </widget> - </widget> - </item> - </layout> - </item> ->>>>>>> 5801c7a (feat: 增加搜救载荷页面:搜救载荷通信、搜救信息imsi列表和详细信息显示、搜救信息地图显示;) </layout> </widget> <action name="toolbar2_action1"> diff --git a/map/places_map.qml b/map/places_map.qml index 171a3a1..fd73c3f 100644 --- a/map/places_map.qml +++ b/map/places_map.qml @@ -37,8 +37,10 @@ MapView { // } // Component.onCompleted: {console.log(map.supportedMapTypes)} + // 搜救信息位置显示,与页面列表信息同步 - signal locationClicked(string imsi) + // signal locationClicked(string imsi) + signal indexClicked(int row) MapItemView { id: itemview @@ -54,11 +56,10 @@ MapView { property double longitude: model.longitude coordinate: QtPositioning.coordinate(latitude, longitude) //图像底部中心对齐坐标点 - anchorPoint.x: item.width * 0.5 - anchorPoint.y: item.height + anchorPoint.x: image.width * 0.5 + anchorPoint.y: image.height sourceItem: Item { - id: item width: image.width height: image.height Image { @@ -70,7 +71,7 @@ MapView { height: itemMouse.containsMouse ? imageHeight*1.25: imageHeight Text { anchors.centerIn: parent - text: model.row + text: (model.row + 1) font.pixelSize: image.width*0.5 color: "black" horizontalAlignment: Text.AlignRight // 设置水平对齐方式为右对齐 @@ -85,14 +86,87 @@ MapView { propagateComposedEvents: true cursorShape: Qt.PointingHandCursor onClicked: { - locationClicked(imsi) - // console.log(model.row, isSelected, imsiSelectionModel.isItemSelected(model.row)) + indexClicked(model.row) } } } } } + + //点击外部列表时,地图上显示被选中的图标 + ListModel { + id: listSelectModel + } + + MapItemView { + parent: mapview.map + // model: testModel + model: listSelectModel + z:3 + delegate: MapQuickItem { // 当前选中的标记 + z: itemview.z + 1 + // property string imsi: model.imsi + property double latitude: model.latitude + property double longitude: model.longitude + property string imagesource: "selectlocation.png" + property bool selected: true + coordinate: QtPositioning.coordinate(latitude, longitude) + //图像底部中心对齐坐标点 + anchorPoint.x: selectimgae.width * 0.5 + anchorPoint.y: selectimgae.height + sourceItem: Item { + Image { + id: selectimgae + source: imagesource + property double imageWidth: 30 + property double imageHeight: 30 + width: imageWidth + height: imageHeight + } + } + } + } + // // 外部信号发射时创建图标 + Connections { + target: imsiSelectModel + function onSelectionChanged (selected, deselected) { + var indexs = imsiSelectModel.selectedIndexes + // if (indexs.length === 0) { + listSelectModel.clear() + // } + for (var i=0; i<indexs.length; i++){ + if (indexs[i].column === 0) { + listSelectModel.append({ + "latitude": imsiDataModel.data(indexs[i], imsiDataModel.getRole("latitude")), // 258 + "longitude": imsiDataModel.data(indexs[i], imsiDataModel.getRole("longitude")) //257 + });// 258); + } + } + } + } + + // Connections { + // target: imsiDataModel + // function onDetailUpdated (imsi, longitude, latitude){ + // listSelectModel.clear() + // listSelectModel.append({"imsi":imsi, "latitude": latitude, "longitude": longitude}); + // console.log(listSelectModel.length) + // } + // } + + // MouseArea { + // anchors.fill: parent + // hoverEnabled: false + // propagateComposedEvents: true + // onClicked: { + // listSelectModel.clear() + // mouse.accepted() + // } + // } + + + // 右下角经纬度显示 HoverHandler { // 最外层的鼠标事件不要用MouseArea,不然hover事件和内层冲突 diff --git a/map/places_map.qrc b/map/places_map.qrc index c6e03b4..7c2bf38 100644 --- a/map/places_map.qrc +++ b/map/places_map.qrc @@ -2,6 +2,7 @@ <qresource prefix="/"> <file>marker.png</file> <file>places_map.qml</file> + <file>selectlocation.png</file> </qresource> <qresource prefix="/map"/> </RCC> diff --git a/map/selectlocation.png b/map/selectlocation.png new file mode 100644 index 0000000..61bfedd Binary files /dev/null and b/map/selectlocation.png differ diff --git a/res/981csNew.png b/res/981csNew.png new file mode 100644 index 0000000..5f4d9e6 Binary files /dev/null and b/res/981csNew.png differ diff --git a/res/Qss/qss.qss b/res/Qss/qss.qss index 77d7933..32fd959 100644 --- a/res/Qss/qss.qss +++ b/res/Qss/qss.qss @@ -214,7 +214,7 @@ QTableWidget::item { /*设置单元格背景颜色*/ QTableWidget::item:selected { - /*background-color:#CCFFE5;*/ + background-color:#CCFFE5; } /*设置表头背景颜色、角落颜色*/ QHeaderView::section,QTableCornerButton:section diff --git a/rescueload.cpp b/rescueload.cpp index 33e31ee..be57de2 100644 --- a/rescueload.cpp +++ b/rescueload.cpp @@ -1,9 +1,12 @@ #include "rescueload.h" #include <QDateTime> +#include <QDir> +#include <QFile> #include <QJsonArray> #include <QJsonDocument> #include <QJsonObject> +#include <QMessageBox> // ==================== ImsiData数据类 start ======================= QHash<QString, QString> ImsiData::operatorMap = { @@ -69,6 +72,20 @@ ImsiTableModel::ImsiTableModel(QObject *parent) m_roleNames[operatorRole] = "operator"; m_horizontalHeader = {"IMSI", "运营商"}; + + m_defaultDir = QString("./搜救信息"); // 默认目录 + // 检查并创建默认目录 + QDir dir(m_defaultDir); + if (!dir.exists()) { + dir.mkpath("."); + } +} + +ImsiTableModel::~ImsiTableModel() +{ + QString timeStr = QDateTime::currentDateTime().toString("yyyy-MM-ddThh-mm-ss"); + QString defaultPath = QString("%1/搜救信息%2.csv").arg(getSaveDir(), timeStr); + saveDataListToCsv(defaultPath); } QVariant ImsiTableModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -87,7 +104,7 @@ int ImsiTableModel::rowCount(const QModelIndex &parent) const // For list models only the root node (an invalid parent) should return the list's size. For all // other (valid) parents, rowCount() should return 0 so that it does not become a tree model. Q_UNUSED(parent) - return dataMap.count(); + return m_dataMap.count(); } int ImsiTableModel::columnCount(const QModelIndex &parent) const @@ -104,8 +121,8 @@ QVariant ImsiTableModel::data(const QModelIndex &index, int role) const int column = index.column(); int row = index.row(); - QString imsi = imsiList.at(row); - ImsiData data = dataMap.value(imsi); + QString imsi = m_imsiList.at(row); + ImsiData data = m_dataMap.value(imsi); switch (role) { case Qt::DisplayRole: if (column == 1) { @@ -139,27 +156,95 @@ QVariant ImsiTableModel::data(const QModelIndex &index, int role) const return QVariant(); } +QModelIndex ImsiTableModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid() || row < 0 || column < 0 || row >= rowCount() || column >= columnCount()) + return QModelIndex(); + + // Create and return a QModelIndex for the given row and column + return createIndex(row, column); +} + +void ImsiTableModel::setDataMap(const QHash<QString, ImsiData> &dataMap) +{ + beginResetModel(); + this->m_dataMap = dataMap; + this->m_imsiList = dataMap.keys(); + for (int i = 0; i < m_imsiList.size(); ++i) { + m_imsiIndex.insert(m_imsiList[i], i); + } + endResetModel(); +} + +void ImsiTableModel::updateData(const ImsiData &data) +{ + QString imsi = data.imsi; + if (m_dataMap.contains(imsi)) { + // 更新现有数据 + m_dataMap[imsi] = data; + int row = m_imsiIndex.value(imsi); + emit dataChanged(index(row, 0), index(row, columnCount() - 1)); + } else { + // 插入新数据 + beginInsertRows(QModelIndex(), m_imsiList.size(), m_imsiList.size()); + m_imsiList.append(imsi); + m_dataMap.insert(imsi, data); + endInsertRows(); + } +} + +int ImsiTableModel::getRole(QString rolename) +{ + if (rolename == "latitude") + return latitudeRole; + else if (rolename == "longitude") + return longitudeRole; + else + return -1; +} + QHash<int, QByteArray> ImsiTableModel::roleNames() const { return m_roleNames; } + +void ImsiTableModel::saveDataListToCsv(const QString& filePath, const QString& delimiter) { + QFile file(filePath); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + qWarning("Could not open file for writing."); + return; + } + QTextStream out(&file); + QStringList row; + row << "IMSI" << "运营商" << "经度" << "纬度" << "海拔高度" << "频点" << "强度" << "记录时间"; // CSV header + out << row.join(delimiter) << "\n"; + for (const QString& imsi : m_imsiList) { + row.clear(); + ImsiData data = m_dataMap.value(imsi); + row << data.imsi + << data.operatorName + << data.longitude + << data.latitude + << QString::number(data.altitude) + << data.fcn + << QString::number(data.rssi) + << data.createDate; + out << row.join(delimiter) << "\n"; + } + file.close(); +} // ======================= ImsiTableModel end===================== // ======================= RescuLoad start=========================== RescueLoad::RescueLoad(QObject *parent) - :QObject(parent), remoteIp("10.10.10.51"), remotePort(8056) + :QObject(parent), remoteIp("10.10.10.50"), remotePort(8056) { - remoteIp = "127.0.0.1"; + // remoteIp = "127.0.0.1"; } RescueLoad::~RescueLoad() {} -const QMap<QString, ImsiData> RescueLoad::getDataMap() const -{ - return dataMap; -} - void RescueLoad::startCommunication() { @@ -205,28 +290,29 @@ void RescueLoad::handleMessage(const QByteArray &datagram) { QJsonValue vType = baseObj.value("type"); QJsonValue vMsg = baseObj.value("msg"); - if (!vType.isDouble() || !vMsg.isString()) return; + // if (!vType.isDouble() || !vMsg.isString()) return; int type = vType.toInt(); QString msg = vMsg.toString(); - if ("success" != msg) return; + // if ("success" != msg) return; switch (type) { case 1: // 4G心跳包 // todo + sendMessage(QString("{\"cmd\": \"heartbeat\"}")); // 定时回心跳,或者单独开定时器 break; case 2: // 5G心跳包 + sendMessage(QString("{\"cmd\": \"heartbeat\"}")); break; case 3:{ // IMSI数据 QJsonArray array = baseObj.value("data").toArray(); - dataMap.clear(); + for (int i = 0; i < array.size(); i++){ QJsonObject json = array.at(i).toObject(); ImsiData data(json); // ImsiData data; - dataMap.insert(data.imsi, data); + emit dataUpdate(data); } - emit dataUpdate(); break; } default: diff --git a/rescueload.h b/rescueload.h index 17f5d8d..97471b5 100644 --- a/rescueload.h +++ b/rescueload.h @@ -17,7 +17,6 @@ */ //搜救载荷移动身份识别码数据 -// typedef struct class ImsiData { public: @@ -29,14 +28,14 @@ public: ImsiData(const ImsiData& from); ~ImsiData(){}; public: - QString latitude; + QString imsi; + QString operatorName; QString longitude; + QString latitude; int altitude; // 海拔高度 - QString createDate; - int rssi; // 强度 QString fcn; // 频点/BAND - QString imsi; - QString operatorName; + int rssi; // 强度 + QString createDate; } /*ImsiData*/; @@ -57,34 +56,33 @@ public: }; public: explicit ImsiTableModel(QObject *parent = nullptr); - - + virtual ~ImsiTableModel(); QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + Q_INVOKABLE QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override; - - void setDataMap(const QMap<QString, ImsiData>& dataMap ) { - beginResetModel(); - this->dataMap = dataMap; - this->imsiList = dataMap.keys(); - endResetModel(); + void setDataMap(const QHash<QString, ImsiData>& dataMap ); + void updateData(const ImsiData &data); + QHash<QString, ImsiData>& getDataMap(){ + return m_dataMap; } - - QMap<QString, ImsiData> getDataMap(){ - return dataMap; - } - - + QString getSaveDir() {return m_defaultDir;} + Q_INVOKABLE int getRole(QString); + void saveDataListToCsv(const QString &filePath, const QString &delimiter = ","); +signals: + void detailUpdated(QString, double, double); protected: // return the roles mapping to be used by QML virtual QHash<int, QByteArray> roleNames() const override; private: - QMap<QString, ImsiData> dataMap; - QList<QString> imsiList; + QHash<QString, ImsiData> m_dataMap; // 用于存储数据,不需要排序时用QHash即可 + QList<QString> m_imsiList; // 用于同步TableView的行索引 + QHash<QString, int> m_imsiIndex; // 用于更新数据时获取行索引 QHash<int, QByteArray> m_roleNames; QStringList m_horizontalHeader; + QString m_defaultDir; }; @@ -96,8 +94,6 @@ public: RescueLoad(QObject *parent); ~RescueLoad(); -private: - QMap<QString, ImsiData> dataMap; // udp通信 public: @@ -106,16 +102,18 @@ public: void sendMessage(const QByteArray &datagram); void syncTime(); void sendNameList(const QString action, const QString type, const QList<QString> &wnamelist, const QList<QString> &bnamelist); - const QMap<QString, ImsiData> getDataMap() const; + signals: - void dataUpdate(); + void dataUpdate(ImsiData data); private slots: void readData(); -private: - QUdpSocket* udpSocket; +public : QString remoteIp; int remotePort; + +private: + QUdpSocket* udpSocket; void handleMessage(const QByteArray &datagram); diff --git a/rescueloadwidget.cpp b/rescueloadwidget.cpp index b033246..3563cf3 100644 --- a/rescueloadwidget.cpp +++ b/rescueloadwidget.cpp @@ -1,6 +1,5 @@ #include "rescueloadwidget.h" #include <QQuickWidget> -#include "qdatetime.h" #include "qjsonarray.h" #include "ui_rescueloadwidget.h" #include <QJsonDocument> @@ -13,7 +12,8 @@ #include <QQmlContext> #include <QQmlApplicationEngine> #include <QQmlComponent> - +#include <QFileDialog> +#include <QMessageBox> RescueLoadWidget::RescueLoadWidget(QWidget *parent) : QWidget(parent) @@ -26,10 +26,10 @@ RescueLoadWidget::RescueLoadWidget(QWidget *parent) // 数据交互和视图设置 rescueLoad = new RescueLoad(this); rescueLoad->startCommunication(); // todo: 转移到子线程中运行 - rescueLoad->sendMessage(QString("Hello")); + // rescueLoad->sendMessage(QString("Hello")); - connect(rescueLoad, &RescueLoad::dataUpdate, rescueLoad, [=](){ - imsiDataModel->setDataMap(rescueLoad->getDataMap()); + connect(rescueLoad, &RescueLoad::dataUpdate, rescueLoad, [=](ImsiData data){ + imsiDataModel->updateData(data); }); // 地图组件, 必须在RescueLoad和ImsiDataModel初始化后加载 @@ -48,6 +48,7 @@ RescueLoadWidget::~RescueLoadWidget() void RescueLoadWidget::openQLocationMap() { QQuickView *qmlView = new QQuickView(); qmlView->rootContext()->setContextProperty("imsiDataModel", imsiDataModel); // 注意,先绑定属性,再设置qml + qmlView->rootContext()->setContextProperty("imsiSelectModel", ui->deviceview->selectionModel()); // 注意,先绑定属性,再设置qml qmlView->setSource(QUrl("qrc:/places_map.qml")); QWidget *container = QWidget::createWindowContainer(qmlView, this); ui->mapGroup->setLayout(new QVBoxLayout); @@ -55,8 +56,14 @@ void RescueLoadWidget::openQLocationMap() { qDebug()<<"搜救地图开启"<<imsiDataModel->getDataMap().keys().size(); // 接收QML的信号 QObject* object = (QObject* )qmlView->rootObject(); - connect(object, SIGNAL(locationClicked(QString)), this, SLOT(updateDetailTable(QString))); - } + // connect(object, SIGNAL(locationClicked(QString)), this, SLOT(updateDetailTable(QString))); + QObject::connect(object, SIGNAL(indexClicked(int)), this, SLOT(tableIndexClicked(int))); +} + +void RescueLoadWidget::tableIndexClicked(int row){ + // qDebug()<<row; + emit ui->deviceview->clicked(imsiDataModel->index(row)); +} void RescueLoadWidget::initialUi() { @@ -120,7 +127,10 @@ void RescueLoadWidget::setTable(QTableView* tableView) { } selectModel->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows); preRow = curRow; - updateDetailTable(imsi); + + if (tableView == ui->deviceview){ + updateDetailTable(imsi); + } }); // 选中行更新名单编辑区 @@ -187,10 +197,11 @@ void RescueLoadWidget::setDeviceDetail(QTableWidget* deviceDetail) { // 更新指定imsi的详细信息 void RescueLoadWidget::updateDetailTable(const QString imsi) { - const QMap<QString, ImsiData>& dataMap = rescueLoad->getDataMap(); + const QHash<QString, ImsiData>& dataMap = imsiDataModel->getDataMap(); if (!dataMap.contains(imsi)) return; - ImsiData data = rescueLoad->getDataMap().value(imsi); - qDebug()<<"更新详细信息start: " << imsi; + ImsiData data = imsiDataModel->getDataMap().value(imsi); + // qDebug()<<"更新详细信息start: " << imsi; + emit imsiDataModel->detailUpdated(imsi, data.longitude.toDouble(), data.latitude.toDouble()); ui->deviceDetail->item(0, 0)->setText(data.imsi); ui->deviceDetail->item(1, 0)->setText(data.operatorName); ui->deviceDetail->item(2, 0)->setText(data.longitude); @@ -200,16 +211,18 @@ void RescueLoadWidget::updateDetailTable(const QString imsi) ui->deviceDetail->item(6, 0)->setText(QString::number(data.rssi)); ui->deviceDetail->item(7, 0)->setText(data.createDate); ui->deviceDetail->show(); - qDebug()<<"更新详细信息end: " << imsi; + + // qDebug()<<"更新详细信息end: " << imsi; } slots void RescueLoadWidget::on_start4G_clicked() { // 开启4g功放 rescueLoad->sendMessage(QString("{\"cmd\": \"startCell\"}")); - + rescueLoad->sendMessage(QString("{\"cmd\": \"heartbeat\"}")); // 时间同步 rescueLoad->syncTime(); + } @@ -223,7 +236,7 @@ slots void RescueLoadWidget::on_start5G_clicked() { // 开启5g功放 rescueLoad->sendMessage(QString("{\"cmd\": \"startCell_5g\"}")); - + rescueLoad->sendMessage(QString("{\"cmd\": \"heartbeat\"}")); // 时间同步 rescueLoad->syncTime(); } @@ -327,3 +340,24 @@ void RescueLoadWidget::updateWBnamelist(QString listType, QString sendType, QLis } + +void RescueLoadWidget::on_ipportBtn_clicked() +{ + QString newIp = ui->ipEdit->text().trimmed(); + int newPort = ui->portEdit->text().trimmed().toInt(); + rescueLoad->remoteIp = newIp; + rescueLoad->remotePort = newPort; +} + + +void RescueLoadWidget::on_saveFileButton_clicked() +{ + QString timeStr = QDateTime::currentDateTime().toString("yyyy-MM-ddThh-mm-ss"); + QString defaultPath = QString("%1/搜救信息%2.csv").arg(imsiDataModel->getSaveDir(), timeStr); + QString filePath = QFileDialog::getSaveFileName(this, tr("保存文件"), defaultPath, tr("CSV 文件 (*.csv)")); + qDebug()<< filePath; + if (!filePath.isEmpty()) { + imsiDataModel->saveDataListToCsv(filePath); + } +} + diff --git a/rescueloadwidget.h b/rescueloadwidget.h index 520e43c..b49a7f4 100644 --- a/rescueloadwidget.h +++ b/rescueloadwidget.h @@ -49,6 +49,10 @@ private slots: void on_addblistBtn_clicked(); void updateDetailTable(const QString imsi); + void tableIndexClicked(int row); + void on_ipportBtn_clicked(); + void on_saveFileButton_clicked(); + private: void setDeviceTable(QTableWidget* tableWidget); void addNewData(); diff --git a/rescueloadwidget.ui b/rescueloadwidget.ui index 5ebe54c..ad46a28 100644 --- a/rescueloadwidget.ui +++ b/rescueloadwidget.ui @@ -6,7 +6,7 @@ <rect> <x>0</x> <y>0</y> - <width>1100</width> + <width>1106</width> <height>684</height> </rect> </property> @@ -33,178 +33,6 @@ </property> </widget> </item> - <item row="1" column="0"> - <widget class="QGroupBox" name="groupBox"> - <property name="minimumSize"> - <size> - <width>220</width> - <height>180</height> - </size> - </property> - <property name="maximumSize"> - <size> - <width>400</width> - <height>16777215</height> - </size> - </property> - <property name="title"> - <string>功能控制</string> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="4"> - <spacer name="horizontalSpacer_3"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>28</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="1"> - <widget class="QPushButton" name="stop4G"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>90</width> - <height>30</height> - </size> - </property> - <property name="text"> - <string>停止4G功放</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QPushButton" name="start4G"> - <property name="enabled"> - <bool>true</bool> - </property> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>90</width> - <height>30</height> - </size> - </property> - <property name="text"> - <string>开启4G功放</string> - </property> - <property name="autoDefault"> - <bool>false</bool> - </property> - <property name="default"> - <bool>false</bool> - </property> - </widget> - </item> - <item row="1" column="3"> - <widget class="QPushButton" name="stop5G"> - <property name="minimumSize"> - <size> - <width>90</width> - <height>30</height> - </size> - </property> - <property name="text"> - <string>停止5G功放</string> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QPushButton" name="start5G"> - <property name="minimumSize"> - <size> - <width>90</width> - <height>30</height> - </size> - </property> - <property name="text"> - <string>开启5G功放</string> - </property> - </widget> - </item> - <item row="1" column="2"> - <spacer name="horizontalSpacer_7"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>5</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="4"> - <spacer name="horizontalSpacer_6"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>28</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="0"> - <spacer name="horizontalSpacer_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>28</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="1" column="0"> - <spacer name="horizontalSpacer_4"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>28</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - <item row="0" column="2"> - <spacer name="horizontalSpacer_5"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>5</width> - <height>20</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </item> <item row="0" column="2" rowspan="2"> <widget class="QWidget" name="widget" native="true"> <property name="sizePolicy"> @@ -221,7 +49,7 @@ </property> <layout class="QVBoxLayout" name="verticalLayout"> <property name="bottomMargin"> - <number>9</number> + <number>0</number> </property> <item> <widget class="QTabWidget" name="tabWidget"> @@ -234,7 +62,7 @@ <property name="minimumSize"> <size> <width>320</width> - <height>280</height> + <height>300</height> </size> </property> <property name="currentIndex"> @@ -244,7 +72,20 @@ <attribute name="title"> <string>设备检索列表</string> </attribute> - <layout class="QHBoxLayout" name="horizontalLayout_2"> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QPushButton" name="saveFileButton"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>保存当前检索的设备列表到文件</string> + </property> + </widget> + </item> <item> <widget class="QTableView" name="deviceview"> <property name="toolTip"> @@ -315,7 +156,7 @@ background-color:transparent; <property name="minimumSize"> <size> <width>320</width> - <height>280</height> + <height>275</height> </size> </property> <property name="maximumSize"> @@ -345,7 +186,7 @@ background-color:transparent; <property name="minimumSize"> <size> <width>0</width> - <height>242</height> + <height>240</height> </size> </property> <property name="font"> @@ -435,6 +276,283 @@ background-color:transparent; </layout> </widget> </item> + <item row="1" column="0"> + <widget class="QGroupBox" name="groupBox"> + <property name="minimumSize"> + <size> + <width>310</width> + <height>180</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>400</width> + <height>16777215</height> + </size> + </property> + <property name="title"> + <string>功能控制</string> + </property> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="0"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>13</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string>载荷IP:</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="ipEdit"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>10.10.10.50</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>端口:</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + <property name="wordWrap"> + <bool>false</bool> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="portEdit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>60</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>8056</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="ipportBtn"> + <property name="maximumSize"> + <size> + <width>50</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>修改</string> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_8"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>13</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item row="1" column="0"> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>13</width> + <height>17</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="1"> + <widget class="QPushButton" name="start4G"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>90</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string>开启4G功放</string> + </property> + <property name="autoDefault"> + <bool>false</bool> + </property> + <property name="default"> + <bool>false</bool> + </property> + </widget> + </item> + <item row="0" column="2"> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>18</width> + <height>17</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="3"> + <widget class="QPushButton" name="start5G"> + <property name="minimumSize"> + <size> + <width>90</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string>开启5G功放</string> + </property> + </widget> + </item> + <item row="0" column="4"> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>25</width> + <height>17</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0"> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>13</width> + <height>17</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1"> + <widget class="QPushButton" name="stop4G"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>90</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string>停止4G功放</string> + </property> + </widget> + </item> + <item row="1" column="2"> + <spacer name="horizontalSpacer_7"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>18</width> + <height>17</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="3"> + <widget class="QPushButton" name="stop5G"> + <property name="minimumSize"> + <size> + <width>90</width> + <height>30</height> + </size> + </property> + <property name="text"> + <string>停止5G功放</string> + </property> + </widget> + </item> + <item row="1" column="4"> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>25</width> + <height>17</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </widget> + </item> <item row="1" column="1"> <widget class="QGroupBox" name="groupBox_3"> <property name="enabled"> @@ -442,7 +560,7 @@ background-color:transparent; </property> <property name="minimumSize"> <size> - <width>0</width> + <width>370</width> <height>210</height> </size> </property>