Procházet zdrojové kódy

some updates and code optmize

Yao před 1 měsícem
rodič
revize
4c5a44edd0

+ 115 - 72
blastopepage.cpp

@@ -12,6 +12,10 @@
 #include "registryManager/registrymanager.h"
 #include "ui_blastopepage.h"
 
+const int ColIndexBlastStatus = 7;
+const int ColIndexProgressBar = 8;
+const int ColIndexOpBtn = 9;
+
 BlastOpePage::BlastOpePage(QWidget *parent)
     : QWidget(parent), ui(new Ui::BlastOpePage), dao(DatabaseManager::getInstance().getDatabase()) {
     QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
@@ -28,7 +32,7 @@ void BlastOpePage::showCountDownWidget(QString uuid, const QString &topic, const
 
     countdownWidget->move(x, y);
     countdownWidget->show();
-    firingWidget *widget = uuidWidgetMap.value(uuid);
+    firingWidget *widget = firingWidgetByUuid.value(uuid);
 
     if (widget) {
         connect(
@@ -239,9 +243,9 @@ void BlastOpePage::initPagination() {
     RefreshData();
 }
 
-void BlastOpePage::RefreshData() { loadDataFromSource(currentPage, pageSize); }
+void BlastOpePage::RefreshData() { loadDataAndDrawTable(currentPage, pageSize); }
 
-void BlastOpePage::loadDataFromSource(int currentPage, int pageSize) {
+void BlastOpePage::loadDataAndDrawTable(int currentPage, int pageSize) {
     PaginatedHProjectResult result = dao.getAllHProjectsByOpera(currentPage, pageSize);
     QList<QSharedPointer<HProject>> projectList = result.projects;
     totalCount = result.totalCount;
@@ -250,9 +254,15 @@ void BlastOpePage::loadDataFromSource(int currentPage, int pageSize) {
     model = new QStandardItemModel(this);
 
     headers = {
-        {"选择", ""},  // 新增选择列
-        {"工程名称", "name"},   {"操作员", "operatorName"},   {"爆破员", "blasterName"},   {"井下地址", "addressPath"},
-        {"雷管数量", "detSum"}, {"起爆器数量", "blastCount"}, {"起爆状态", "blastStatus"}, {"进度", ""},
+        {"选择", ""},
+        {"工程名称", "name"},
+        {"操作员", "operatorName"},
+        {"爆破员", "blasterName"},
+        {"井下地址", "addressPath"},
+        {"雷管数量", "detSum"},
+        {"起爆器数量", "blastCount"},
+        {"起爆状态", "blastStatus"},
+        {"进度", ""},
         {"操作", ""},
     };
 
@@ -285,15 +295,7 @@ void BlastOpePage::loadDataFromSource(int currentPage, int pageSize) {
 
                 if (prop == "blastStatus") {
                     QString statusText;
-                    if (value.toString() == BlastStatus::Created) {
-                        statusText = "未 注 册";
-                        item = new QStandardItem(statusText);
-                        item->setForeground(QColor("#e7c66b"));
-                    } else if (value.toString() == BlastStatus::Registered) {
-                        statusText = "待安全确认";
-                        item = new QStandardItem(statusText);
-                        item->setForeground(QColor("#f3a361"));
-                    } else if (value.toString() == BlastStatus::SafeChecked) {
+                    if (value.toString() == BlastStatus::SafeChecked) {
                         statusText = "待起爆";
                         item = new QStandardItem(statusText);
                         item->setForeground(QColor("#f3a3k'k1"));
@@ -334,6 +336,7 @@ void BlastOpePage::loadDataFromSource(int currentPage, int pageSize) {
     ui->tableView->verticalHeader()->setDefaultSectionSize(50);
 
     for (int row = 0; row < projectList.size(); ++row) {
+        // 初始化progressBars
         int progressCol = headers.size() - 2;  //
         QProgressBar *progressBar1 = new QProgressBar(ui->tableView);
         progressBar1->setRange(0, 100);  // 设置范围为0到100
@@ -383,12 +386,15 @@ void BlastOpePage::loadDataFromSource(int currentPage, int pageSize) {
             ui->tableView->setIndexWidget(progressIndex, progressBarContainer);
         }
         int col = headers.size() - 1;
-        // 创建一个按钮
+
+        // 创建操作按钮
         QWidget *widget = new QWidget(ui->tableView);
         QPushButton *button = new QPushButton(widget);
         button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+        // 添加button disable时样式为灰色
+        button->setStyleSheet("QPushButton:disabled { background-color: #d3d3d3; color: gray; }");
 
-        QModelIndex statusIndex = model->index(row, propMap.key("blastStatus"));
+        QModelIndex statusIndex = model->index(row, ColIndexBlastStatus);
         if (statusIndex.isValid()) {
             QString blastStatus = model->data(statusIndex).toString();
             if (blastStatus == "待起爆") {
@@ -414,7 +420,7 @@ void BlastOpePage::loadDataFromSource(int currentPage, int pageSize) {
 // 切换页数
 void BlastOpePage::PageChanged(int page) {
     currentPage = page;
-    loadDataFromSource(currentPage, pageSize);
+    loadDataAndDrawTable(currentPage, pageSize);
 }
 
 void BlastOpePage::onComboBoxIndexChanged(int index) {
@@ -422,7 +428,7 @@ void BlastOpePage::onComboBoxIndexChanged(int index) {
     int value = variant.toInt();
     pageSize = value;
     currentPage = 1;
-    loadDataFromSource(currentPage, pageSize);
+    loadDataAndDrawTable(currentPage, pageSize);
 }
 
 void BlastOpePage::updateProgressBar(int firingStage, int row) {
@@ -432,12 +438,12 @@ void BlastOpePage::updateProgressBar(int firingStage, int row) {
         QProgressBar *progressBar3 = progressBars[row].bar3;
         switch (firingStage) {
             case FiringStages::QuickTesting:
-                // 组网状态
+                // 起爆检测状态
                 progressBar1->setRange(0, 0);  // 设置范围为0到100
                 progressBar1->setValue(0);
                 break;
             case FiringStages::QuickTestFinished:
-                // 组网完成
+                // 起爆检测完成
                 progressBar1->setRange(0, 100);  // 设置范围为0到100
                 progressBar1->setValue(100);
                 break;
@@ -461,7 +467,7 @@ void BlastOpePage::updateProgressBar(int firingStage, int row) {
                 progressBar3->setRange(0, 100);  // 设置范围为0到100
                 progressBar3->setValue(100);
                 break;
-            case FiringStages::NotStarted:
+            case FiringStages::Starting:
                 progressBar1->setRange(0, 100);
                 progressBar1->setValue(0);
                 progressBar2->setRange(0, 100);
@@ -475,53 +481,54 @@ void BlastOpePage::updateProgressBar(int firingStage, int row) {
     }
 }
 
+// update tableView's fields about firing stage
 void BlastOpePage::onFiringStageUpdated(int stage, int row) {
+    // update blast status item
     QModelIndex firingStatusItem = model->index(row, 7);
     if (firingStatusItem.isValid()) {
         QColor customColor;
         QFont boldFont;
         boldFont.setBold(true);
         switch (stage) {
-            case FiringStages::NotStarted:
+            case FiringStages::Starting:
                 model->setData(firingStatusItem, "待起爆");
                 customColor = QColor("#44035b");
                 model->setData(firingStatusItem, customColor, Qt::ForegroundRole);
                 model->setData(firingStatusItem, boldFont, Qt::FontRole);
                 break;
             case FiringStages::QuickTesting:
-                model->setData(firingStatusItem, "组 网 中 ...");
+                model->setData(firingStatusItem, "起爆检测中...");
                 customColor = QColor("#44035b");
                 model->setData(firingStatusItem, customColor, Qt::ForegroundRole);
                 model->setData(firingStatusItem, boldFont, Qt::FontRole);
                 break;
             case FiringStages::QuickTestFinished:
-                model->setData(firingStatusItem, "组 网 完 成");
+                model->setData(firingStatusItem, "检测完成");
                 customColor = QColor("#404185");
                 model->setData(firingStatusItem, customColor, Qt::ForegroundRole);
                 break;
             case FiringStages::NetCharging:
-                model->setData(firingStatusItem, "充  中 ...");
+                model->setData(firingStatusItem, "充电中 ...");
                 customColor = QColor("#31688e");
                 model->setData(firingStatusItem, customColor, Qt::ForegroundRole);
                 break;
             case FiringStages::NetChargingFinished:
-                model->setData(firingStatusItem, "充   成");
+                model->setData(firingStatusItem, "充电完成");
                 customColor = QColor("#1f918d");
                 model->setData(firingStatusItem, customColor, Qt::ForegroundRole);
                 break;
             case FiringStages::Blasting:
-                model->setData(firingStatusItem, "起   ...");
+                model->setData(firingStatusItem, "起爆中...");
                 customColor = QColor("#38b775");
                 model->setData(firingStatusItem, customColor, Qt::ForegroundRole);
-                updateOpBtn(6, row);  // 更新按钮
                 break;
             case FiringStages::BlastFinished:
-                model->setData(firingStatusItem, "起   成");
+                model->setData(firingStatusItem, "起爆完成");
                 customColor = QColor("#90d543");
                 model->setData(firingStatusItem, customColor, Qt::ForegroundRole);
                 break;
-            case FiringStages::PendingTrigger:
-                model->setData(firingStatusItem, "按 下 双 建 起 爆 ...");
+            case FiringStages::PendingTriggerButtonClick:
+                model->setData(firingStatusItem, "按下双键起爆...");
                 customColor = QColor("#8e620");
                 model->setData(firingStatusItem, customColor, Qt::ForegroundRole);
                 break;
@@ -529,10 +536,13 @@ void BlastOpePage::onFiringStageUpdated(int stage, int row) {
                 break;
         }
     }
+
+    updateProgressBar(stage, row);
+    updateOpBtnStage(stage, row);
 }
 
 void BlastOpePage::handleSingleBlastButtonClick(int row, QPushButton *button) {
-    QStandardItem *uuidItem = model->item(row, 10);
+    QStandardItem *uuidItem = model->item(row, ColIndexOpBtn);
     QString uuid;
     if (uuidItem) {
         QVariant uuidVariant = uuidItem->data(Qt::UserRole);
@@ -545,9 +555,7 @@ void BlastOpePage::handleSingleBlastButtonClick(int row, QPushButton *button) {
         button->setMinimumWidth(80);
         button->setText(stopBlastButtonTxt);
         firingWidget *widget = new firingWidget(row, false, uuid);
-        connect(widget, &firingWidget::updateBlastStatus, this, &BlastOpePage::updateProgressBar);
         connect(widget, &firingWidget::updateBlastStatus, this, &BlastOpePage::onFiringStageUpdated);
-        connect(widget, &firingWidget::updateButton, this, &BlastOpePage::updateOpBtn);
         connect(widget, &firingWidget::countdown, this, &BlastOpePage::showCountDownWidget);
         connect(widget, &firingWidget::updateProjectStatus, this, &BlastOpePage::handlerUpdateProjectStatus);
         connect(widget, &firingWidget::closeFiring, this, &BlastOpePage::destroyFiringWidget);
@@ -556,39 +564,72 @@ void BlastOpePage::handleSingleBlastButtonClick(int row, QPushButton *button) {
         }
 
         widget->setAttribute(Qt::WA_DeleteOnClose);
-        uuidWidgetMap.insert(uuid, widget);
+        firingWidgetByUuid.insert(uuid, widget);
 
     } else if (button->text() == stopBlastButtonTxt) {
-        firingWidget *widget = uuidWidgetMap.value(uuid);
+        firingWidget *widget = firingWidgetByUuid.value(uuid);
         if (widget) {
-            widget->cancelBlasting();
+            widget->sendCancelFiringMsg();
         }
+        button->setText("...");
     }
 }
 
-void BlastOpePage::updateOpBtn(int status, int row) {
-    qDebug() << "statusButton:" << status;
-    QModelIndex index = model->index(row, 8);
-    if (index.isValid()) {
-        QWidget *widget = ui->tableView->indexWidget(index);
-        if (widget) {
-            QPushButton *button = widget->findChild<QPushButton *>();
-            if (button) {
-                // 使用样式表设置图标居中
-                button->setStyleSheet(
-                    "QPushButton {"
-                    "    padding: 0px;"
-                    "    border: none;"
-                    "    background-color: transparent;"
-                    "}");
-
-                // 添加图标,假设图标文件名为 blast.svg,并且该文件存在于项目资源中
-                QIcon icon(":/icons/icons/svg/blast.svg");
-                button->setText("");
-                button->setIcon(icon);
-                button->setIconSize(QSize(32, 32));
-            }
-        }
+void BlastOpePage::updateOpBtnStage(int stage, int row) {
+    QModelIndex index = model->index(row, ColIndexOpBtn);
+    if (!index.isValid()) {
+        Logger::getInstance().error(QString("can not get updateOpBtnStage index %1").arg(row));
+        RefreshData();
+        return;
+    }
+    QWidget *widget = ui->tableView->indexWidget(index);
+    QPushButton *button = widget->findChild<QPushButton *>();
+    if (!button) {
+        Logger::getInstance().error(QString("can not find button in row %1").arg(row));
+        return;
+    }
+
+    switch (stage) {
+        case FiringStages::Starting:
+            button->setText(stopBlastButtonTxt);
+            button->setDisabled(true);
+            break;
+        case FiringStages::QuickTesting:
+            button->setEnabled(true);
+            break;
+        case FiringStages::QuickTestFinished:
+            button->setEnabled(true);
+            break;
+        case FiringStages::NetCharging:
+            button->setEnabled(true);
+            break;
+        case FiringStages::NetChargingFinished:
+            button->setEnabled(true);
+            break;
+        case FiringStages::PendingTriggerButtonClick:
+            button->setText(stopBlastButtonTxt);
+            button->setEnabled(true);
+            break;
+        case FiringStages::Blasting:
+            button->setDisabled(true);
+            button->setText("...");
+            break;
+        case FiringStages::BlastFinished:
+            button->setDisabled(true);
+            button->setText("");
+            // 使用样式表设置图标居中
+            button->setStyleSheet(
+                "QPushButton {"
+                "    padding: 0px;"
+                "    border: none;"
+                "    background-color: transparent;"
+                "}");
+            button->setIcon(QIcon(":/icons/icons/svg/blast.svg"));
+            button->setIconSize(QSize(32, 32));
+            break;
+        default:
+            button->setEnabled(false);
+            break;
     }
 }
 
@@ -597,12 +638,14 @@ void BlastOpePage::handlerUpdateProjectStatus(QString uuid, const QString &newSt
 }
 
 void BlastOpePage::destroyFiringWidget(const QString &uuid) {
-    firingWidget *widget = uuidWidgetMap.value(uuid);
+    firingWidget *widget = firingWidgetByUuid.value(uuid);
     if (widget) {
-        widget->close();             // 关闭窗口
-        widget->deleteLater();       // 释放内存
-        uuidWidgetMap.remove(uuid);  // 从映射中移除
+        widget->close();                  // 关闭窗口
+        widget->deleteLater();            // 释放内存
+        widget->disconnect();             // 断开信号连接
+        firingWidgetByUuid.remove(uuid);  // 从映射中移除
     }
+    RefreshData();
 }
 
 // 槽函数,当 item 状态改变时触发
@@ -647,23 +690,21 @@ void BlastOpePage::on_btnSelect_clicked() {
         int row = it.key();
         QString uuid = it.value();
         firingWidget *widgetSelect = new firingWidget(row, true, uuid);
-        QModelIndex index = model->index(row, 9);
+        QModelIndex index = model->index(row, ColIndexOpBtn);
         if (index.isValid()) {
             QWidget *widgetButton = ui->tableView->indexWidget(index);
             if (widgetButton) {
                 QPushButton *button = widgetButton->findChild<QPushButton *>();
-                button->setText("取消起爆流程");
+                button->setText(stopBlastButtonTxt);
+                button->setDisabled(true);
             }
         }
 
         // 信号连接
-        connect(widgetSelect, &firingWidget::updateBlastStatus, this, &BlastOpePage::updateProgressBar);
         connect(widgetSelect, &firingWidget::updateBlastStatus, this, &BlastOpePage::onFiringStageUpdated);
-        connect(widgetSelect, &firingWidget::selectSignal, this, &BlastOpePage::setBatchBlastTrigger);
-        connect(widgetSelect, &firingWidget::updateButton, this, &BlastOpePage::updateOpBtn);
+        connect(widgetSelect, &firingWidget::batchFiringSignal, this, &BlastOpePage::setBatchBlastTrigger);
         connect(widgetSelect, &firingWidget::updateProjectStatus, this, &BlastOpePage::handlerUpdateProjectStatus);
         connect(widgetSelect, &firingWidget::closeFiring, this, &BlastOpePage::destroyBatchFiringWidget);
-        widgetSelect->show();
         widgetSelect->setAttribute(Qt::WA_DeleteOnClose);
         uuidWidgetSMap.insert(uuid, widgetSelect);
 
@@ -758,11 +799,13 @@ void BlastOpePage::destroyBatchFiringWidget(const QString &uuid) {
         uuidWidgetSMap.remove(uuid);
     }
     for (int row = 0; row < model->rowCount(); ++row) {
+        // 恢复 checkbox 可选
         QStandardItem *item = model->item(row, 0);
         if (item) {
             Qt::ItemFlags flags = item->flags();
-            flags &= ~Qt::ItemIsEnabled;  // 去除 ItemIsEnabled 标志位
+            flags |= Qt::ItemIsEnabled;
             item->setFlags(flags);
         }
     }
+    RefreshData();
 }

+ 4 - 4
blastopepage.h

@@ -46,7 +46,7 @@ class BlastOpePage : public QWidget {
     void onComboBoxIndexChanged(int index);
     void updateProgressBar(int value, int row);
     void onFiringStageUpdated(int status, int row);
-    void updateOpBtn(int status, int row);
+    void updateOpBtnStage(int status, int row);
     void showCountDownWidget(QString uuid, const QString &topic, const QString &message);
     void handlerUpdateProjectStatus(QString uuid, const QString &status);
     void destroyFiringWidget(const QString &uuid);
@@ -60,7 +60,7 @@ class BlastOpePage : public QWidget {
    private:
     void handleFeaturePermission(QWebEnginePage *page, const QUrl &securityOrigin, QWebEnginePage::Feature feature);
     void RefreshData();
-    void loadDataFromSource(int currentPage, int pageSize);
+    void loadDataAndDrawTable(int currentPage, int pageSize);
     void InitFace();
     void closeWebViewAndRestoreUI();
     void parseJsonString(const QJsonDocument &jsonDoc);
@@ -75,7 +75,7 @@ class BlastOpePage : public QWidget {
     Ui::BlastOpePage *ui;
     QList<HeaderInfo> headers;
     QStandardItemModel *model;
-    QMap<QString, firingWidget *> uuidWidgetMap;
+    QMap<QString, firingWidget *> firingWidgetByUuid;
     QWebEngineView *view;
     QVBoxLayout *layout;
     QString certifyId;
@@ -91,7 +91,7 @@ class BlastOpePage : public QWidget {
     int pageSize;     // 每页显示的记录数量
     int currentPage;  // 当前页面
     int totalCount;
-    QString stopBlastButtonTxt = "中止起爆";
+    QString stopBlastButtonTxt = "取消起爆";
     QString startBlastButtonTxt = "开启起爆";
 };
 

+ 73 - 80
fireWidget/firingwidget.cpp

@@ -48,6 +48,7 @@ firingWidget::firingWidget(const int &row, const bool &select, const QString &uu
     QStringList topics = {m_topic};
     mqttThread->setConnectionInfo("114.55.233.194", 1883, "hxgc", "hxgc123456", "P" + uuid, topics);
     connect(mqttThread, &MqttThread::mqttConnected, this, &firingWidget::onMqttConnected);
+    connect(mqttThread, &MqttThread::mqttDisconnected, this, &firingWidget::onMqttDisconnected);
     mqttThread->start();
     connect(mqttThread, &MqttThread::projectMqttMessageReceived, this, &firingWidget::handleProjectFiringMqttMessage);
     connect(this, &firingWidget::lastStageChanged, this, &firingWidget::handleFiringStageChanged);
@@ -56,7 +57,9 @@ firingWidget::firingWidget(const int &row, const bool &select, const QString &uu
 }
 
 firingWidget::~firingWidget() {
-    BlastingProjManager::removeBlastingProject(m_curProjUuid);
+    mqttThread->stopThread();
+    mqttThread->wait();
+    qDebug() << "firingWidget::~firingWidget()";
     delete ui;
 }
 
@@ -64,67 +67,55 @@ void firingWidget::sendMqttMessage(const QString &topic, const QByteArray &messa
     if (mqttThread && m_isMqttConnected) {
         emit mqttThread->sendMessageRequested(topic, message, quint8(2), false);
     } else {
-        Logger::getInstance().error("MQTT未连接, 无法发送消息");
+        Logger::getInstance().error("MQTT未连接, 无法发送消息" + topic + ", " + message);
     }
 }
 
 void firingWidget::startBlasting() {
-    QTimer::singleShot(1000, this, [this]() {
-        m_lastStage = 0;
-        emit lastStageChanged(0);
+    checkBlasterConnection();
+    // 等待3s mqtt连接后再发送mqtt消息
+    QTimer::singleShot(3000, this, [this]() {
+        m_lastStage = FiringStages::Starting;
+        emit lastStageChanged(FiringStages::Starting);
     });
+}
 
-    // 3s内如果没有收到mqtt响应,则报错
-    QTimer *connectionCheckTimer = new QTimer(this);
-    connectionCheckTimer->setSingleShot(true);
-    bool isReceivedMessage = false;
+// 检查有没有收到爆破器的消
+void firingWidget::checkBlasterConnection() {
+    m_lastMsgTime = QDateTime::currentDateTime();
+    QTimer *timer = new QTimer(this);
     connect(mqttThread, &MqttThread::projectMqttMessageReceived, this,
-            [connectionCheckTimer](const QByteArray &message) {
-                qDebug() << ANSI_COLOR_GREEN << "Received connection confirmation message from MQTT server."
-                         << ANSI_COLOR_RESET;
-                connectionCheckTimer->stop();
-            });
-    connect(connectionCheckTimer, &QTimer::timeout, this, [this]() {
-        if (m_isMqttConnected) {
-            QMessageBox::critical(nullptr, "起爆错误", "未收到爆破器的连接确认消息,请检查爆破器是否在线");
-            Logger::getInstance().error("启动爆破后,未收到爆破器的连接确认消息");
-            cancelBlasting();
-        } else {
-            QMessageBox::critical(this, "连接mqtt错误", "MQTT连接失败,请尝试重新登录");
+            [&]() { m_lastMsgTime = QDateTime::currentDateTime(); });
+
+    connect(timer, &QTimer::timeout, this, [this, timer]() {
+        if (m_lastStage == FiringStages::CancelConfirmed || m_lastStage == FiringStages::BlastFinished) {
+            return;
+        }
+        if (m_lastMsgTime.secsTo(QDateTime::currentDateTime()) > 3) {
+            QMessageBox msgBox;
+            msgBox.setWindowTitle("起爆检测测试错误");
+            msgBox.setText("超时未收到爆破器消息,是否继续等待");
+            QPushButton *yesButton = msgBox.addButton("继续等待", QMessageBox::YesRole);
+            QPushButton *noButton = msgBox.addButton("取消", QMessageBox::NoRole);
+            yesButton->setStyleSheet(
+                "QPushButton { background-color:rgb(5, 58, 156); color: white; padding: 5px 15px; "
+                "border-radius: 4px; }");
+            noButton->setStyleSheet(
+                "QPushButton { background-color: #f44336; color: white; padding: 5px 15px; "
+                "border-radius: 4px; }");
+            msgBox.exec();
+            if (msgBox.clickedButton() == noButton) {
+                timer->stop();
+                timer->deleteLater();
+                sendCancelFiringMsg();
+                emit closeFiring(m_curProjUuid);
+                return;
+            }
         }
     });
-    connectionCheckTimer->start(2000);
-}
 
-// void firingWidget::startHeartbeatMonitor() {
-//     m_isHeartBeating = true;
-//     QThread *heartbeatThread = new QThread();
-//     QTimer *heartbeatTimer = new QTimer(nullptr);
-//     heartbeatTimer->setInterval(3000);  // 3 seconds interval
-//     heartbeatTimer->moveToThread(heartbeatThread);
-//
-//     connect(heartbeatThread, &QThread::started, heartbeatTimer,
-//             static_cast<void (QTimer::*)()>(&QTimer::start));
-//     connect(heartbeatThread, &QThread::finished, heartbeatTimer, &QTimer::stop);
-//     connect(heartbeatThread, &QThread::finished, heartbeatTimer, &QTimer::deleteLater);
-//     connect(heartbeatThread, &QThread::finished, heartbeatThread, &QThread::deleteLater);
-//
-//     connect(heartbeatTimer, &QTimer::timeout, this, [this]() {
-//         if (!m_isHeartBeating) {
-//             Logger::getInstance().error("爆破器心跳检测失败,连接可能已断开");
-//             QMetaObject::invokeMethod(
-//                 this,
-//                 [this]() {
-//                     QMessageBox::critical(this, "连接错误",
-//                     "爆破器心跳检测失败,连接可能已断开"); cancelBlasting();
-//                 },
-//                 Qt::QueuedConnection);
-//         }
-//         m_isHeartBeating = false;  // Reset flag for next interval
-//     });
-//
-//     heartbeatThread->start();
-// }
+    timer->start(5000);  // 每10秒检查一次
+}
 void firingWidget::on_pushButton_2_clicked() { emit countdown(m_curProjUuid, m_topic, "message"); }
 
 // NOTE: aborted, changed to upload in the smartmine server side.
@@ -217,7 +208,7 @@ void firingWidget::handleProjectFiringMqttMessage(const QByteArray &message, con
                                                     .arg(m_curProjUuid, ErrorBlastStatus::getErrorMessage(status)));
                     QMessageBox::critical(nullptr, "爆破器报错",
                                           QString("错误错误信息: %1").arg(ErrorBlastStatus::getErrorMessage(status)));
-                    cancelBlasting();
+                    sendCancelFiringMsg();
                     return;
                 }
 
@@ -225,8 +216,8 @@ void firingWidget::handleProjectFiringMqttMessage(const QByteArray &message, con
                 if (stage != m_lastStage) {
                     m_lastStage = stage;
                     switch (stage) {
-                        case FiringStages::NotStarted:
-                            navProgress->setState(FiringStages::NotStarted);
+                        case FiringStages::Starting:
+                            navProgress->setState(FiringStages::Starting);
                             ui->pushButton_2->setText("立即测试");
                             ui->pushButton_2->setEnabled(false);
                             break;
@@ -237,11 +228,11 @@ void firingWidget::handleProjectFiringMqttMessage(const QByteArray &message, con
                             ui->pushButton_2->setEnabled(false);
                             break;
                         case FiringStages::QuickTestFinished:
-                            // 组网测试检查报错雷管数量,如果有错误,提示用户确认是否继续
+                            // 起爆检测测试检查报错雷管数量,如果有错误,提示用户确认是否继续
                             if (relayInfo["errorCount"].toInt() > 0) {
                                 QMessageBox msgBox;
-                                msgBox.setWindowTitle("组网测试错误");
-                                msgBox.setText(QString("组网测试发现 %1 个报错雷管,是否继续起爆?")
+                                msgBox.setWindowTitle("起爆检测测试错误");
+                                msgBox.setText(QString("起爆检测测试发现 %1 个报错雷管,是否继续起爆?")
                                                    .arg(relayInfo["errorCount"].toInt()));
                                 QPushButton *yesButton = msgBox.addButton("确定继续", QMessageBox::YesRole);
                                 QPushButton *noButton = msgBox.addButton("取消", QMessageBox::NoRole);
@@ -253,7 +244,7 @@ void firingWidget::handleProjectFiringMqttMessage(const QByteArray &message, con
                                     "border-radius: 4px; }");
                                 msgBox.exec();
                                 if (msgBox.clickedButton() == noButton) {
-                                    cancelBlasting();
+                                    sendCancelFiringMsg();
                                     return;
                                 }
                             }
@@ -283,7 +274,6 @@ void firingWidget::handleProjectFiringMqttMessage(const QByteArray &message, con
                             ui->pushButton_2->setEnabled(false);
                             emit progressChanged(FiringStages::Blasting, m_row);
                             emit updateBlastStatus(FiringStages::Blasting, m_row);
-                            emit updateButton(FiringStages::Blasting, m_row);
                             ui->pushButton_2->setText("起爆");
                             navProgress->setState(FiringStages::Blasting);
                             break;
@@ -292,18 +282,20 @@ void firingWidget::handleProjectFiringMqttMessage(const QByteArray &message, con
                             emit progressChanged(FiringStages::BlastFinished, m_row);
                             emit updateBlastStatus(FiringStages::BlastFinished, m_row);
                             emit updateProjectStatus(m_curProjUuid, BlastStatus::Blasted);
-                            emit updateButton(FiringStages::BlastFinished, m_row);
                             ui->pushButton_2->setText("已完成起爆");
                             navProgress->setState(FiringStages::BlastFinished);
                             emit closeFiring(m_curProjUuid);
                             break;
-                        case 7:  // TODO: ?
-                            ui->pushButton_2->setEnabled(false);
-                            ui->pushButton_2->setText("已完成起爆");
-                            emit progressChanged(0, m_row);
-                            emit updateBlastStatus(0, m_row);
+                        case FiringStages::CancelConfirmed:
                             navProgress->setState(FiringStages::BlastFinished);
+                            ui->pushButton_2->setEnabled(false);
+                            ui->pushButton_2->setText("已确认取消");
+
+                            emit progressChanged(FiringStages::Starting, m_row);
+                            emit updateBlastStatus(FiringStages::Starting, m_row);
+                            emit updateProjectStatus(m_curProjUuid, BlastStatus::Created);
                             emit closeFiring(m_curProjUuid);
+
                             break;
                         default:
                             break;
@@ -333,6 +325,11 @@ void firingWidget::onMqttConnected() {
     m_isMqttConnected = true;
 }
 
+void firingWidget::onMqttDisconnected() {
+    Logger::getInstance().info(QString("Project(%1) firing MQTT disconncted.").arg(m_curProjUuid));
+    m_isMqttConnected = false;
+}
+
 void firingWidget::onButtonPressedReceived(const QString &topic, const QString &message) {
     QByteArray data = "\r\nDISABLE_BUTTON\r\n";
     // 调用发送数据的方法
@@ -362,21 +359,22 @@ void firingWidget::handleFiringStageChanged(int newStage) {
     QString message;
     QString buttonText;
     switch (newStage) {
-        case 0:
+        case FiringStages::Starting:
             message = "起爆测试";
             buttonText = "立即测试";
             sendMqttMessage(topic, message.toUtf8());
+            emit updateBlastStatus(FiringStages::Starting, m_row);
             break;
-        case 2:
+        case FiringStages::QuickTestFinished:
             message = "开始充电";
             buttonText = "充电";
             sendMqttMessage(topic, message.toUtf8());
             break;
-        case 4:
+        case FiringStages::NetChargingFinished:
             message = "起爆";
             buttonText = "起爆";
             break;
-        case 5:
+        case FiringStages::Blasting:
             if (!m_select) {
                 if (connection) {
                     disconnect(connection);
@@ -421,22 +419,17 @@ void firingWidget::handleFiringStageChanged(int newStage) {
             }
         } else if (m_lastStage == FiringStages::NetChargingFinished && m_select) {
             qDebug() << "多台起爆:待起爆状态";
-            emit selectSignal(m_curProjUuid);
-        } else {  //????
+            emit batchFiringSignal(m_curProjUuid);
+        } else {
             qDebug() << "Stage 值变为: " << newStage << "发送消息" << message.toUtf8();
         }
     }
 }
 
-void firingWidget::cancelBlasting() {
-    emit progressChanged(0, m_row);
-    emit updateBlastStatus(0, m_row);
-    emit updateProjectStatus(m_curProjUuid, BlastStatus::Created);
-
+void firingWidget::sendCancelFiringMsg() {
     QString message = "取消流程";
-    if (!message.isEmpty()) {
-        sendMqttMessage(m_topic, message.toUtf8());
-    }
+    QString topic = "hxgc/" + m_curProjUuid + "/P";
+    sendMqttMessage(topic, message.toUtf8());
 }
 void firingWidget::on_sendTest_4_clicked() {}
 

+ 6 - 4
fireWidget/firingwidget.h

@@ -25,7 +25,7 @@ public class Reply{
    private int errorCount =0;
    private int busVoltage = 0;
    private int buscurrent =0;
-   private int stage = 1;//组网中,组网完成,充电中,充电完成, 起爆中,起爆完成
+   private int stage = 1;//起爆检测中,起爆检测完成,充电中,充电完成, 起爆中,起爆完成
 }
 */
 namespace Ui {
@@ -39,7 +39,7 @@ class firingWidget : public QWidget {
    public:
     explicit firingWidget(const int &row, const bool &select, const QString &uuid = "", QWidget *parent = nullptr);
     ~firingWidget();
-    void cancelBlasting();
+    void sendCancelFiringMsg();
     void testOnBlastSuccess(const QJsonObject &data);
 
    public slots:
@@ -51,6 +51,7 @@ class firingWidget : public QWidget {
     void handleProjectFiringMqttMessage(const QByteArray &message, const QMqttTopicName &topic);
 
     void onMqttConnected();
+    void onMqttDisconnected();
     // 双键按下
     void onButtonPressedReceived(const QString &topic, const QString &message);
     void handleFiringStageChanged(int newStage);
@@ -61,8 +62,7 @@ class firingWidget : public QWidget {
     void lastStageChanged(int newStage);
     void projSafeCheckSuccess(QString projectUuid);
     void updateBlastStatus(int status, int row);
-    void selectSignal(QString uuid);
-    void updateButton(int status, int row);
+    void batchFiringSignal(QString uuid);
     void updateProjectStatus(QString uuid, QString status);
     void updateData(const QJsonObject &jsonObj);
     void safeChecked(const QJsonObject &jsonObj);
@@ -80,6 +80,7 @@ class firingWidget : public QWidget {
     void sendMqttMessage(const QString &topic, const QByteArray &message);
     void startBlasting();
     void onSafeChecked(const QString projectUuid);
+    void checkBlasterConnection();
 
    private:
     Ui::firingWidget *ui;
@@ -100,6 +101,7 @@ class firingWidget : public QWidget {
     QMetaObject::Connection connectionPress;
     QString m_latitude;
     QString m_longitude;
+    QDateTime m_lastMsgTime;
 };
 
 #endif  // FIRINGWIDGET_H

+ 1 - 1
fireWidget/firingwidget.ui

@@ -191,7 +191,7 @@ QPushButton:disabled {
            </size>
           </property>
           <property name="text">
-           <string>立即组网</string>
+           <string>立即起爆检测</string>
           </property>
          </widget>
         </item>

+ 1 - 1
fireWidget/navprogress.cpp

@@ -9,7 +9,7 @@ NavProgress::NavProgress(QWidget *parent) : QWidget(parent), navStyle(NavStyle_J
     secondCircleBlinking = false;
     thridCircleGreen = false;
     thridCircleBlinking = false;
-    topInfo = {"组网", "充电", "起爆"};
+    topInfo = {"起爆检测", "充电", "起爆"};
     blinkTimer = new QTimer(this);
     connect(blinkTimer, &QTimer::timeout, this, &NavProgress::toggleBlinkColors);
     blinkColor = Qt::red;

+ 9 - 8
global.h

@@ -84,14 +84,15 @@ inline QString getErrorMessage(int code) {
 
 // namespace FiringStages
 namespace FiringStages {
-const static int NotStarted = 0;
-const static int QuickTesting = 1;         // 组网测试中
-const static int QuickTestFinished = 2;    // 组网测试完成
-const static int NetCharging = 3;          // 组网充电中
-const static int NetChargingFinished = 4;  // 组网充电完成
-const static int Blasting = 5;             // 爆破中
-const static int BlastFinished = 6;        // 爆破完成
-const static int PendingTrigger = 10;      // 待触发按钮触发起爆
+const static int Starting = 0;
+const static int QuickTesting = 1;                // 起爆检测测试中
+const static int QuickTestFinished = 2;           // 起爆检测测试完成
+const static int NetCharging = 3;                 // 起爆检测充电中
+const static int NetChargingFinished = 4;         // 起爆检测充电完成
+const static int Blasting = 5;                    // 爆破中
+const static int BlastFinished = 6;               // 爆破完成
+const static int CancelConfirmed = 7;             // 确认取消
+const static int PendingTriggerButtonClick = 10;  // 待触发按钮触发起爆
 }  // namespace FiringStages
 // namespace FiringStages
 

+ 10 - 10
mainwindow.cpp

@@ -22,8 +22,9 @@
 
 MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
     try {
-        this->setWindowFlags(Qt::FramelessWindowHint);
+        this->setWindowFlags(Qt::FramelessWindowHint | Qt::Window);
         this->setWindowState(Qt::WindowMaximized);  // Maximizes the window
+
         // this->setFixedSize(1360, 864);
         ui->setupUi(this);
         LoadingWidget::init(ui->stackedWidget);
@@ -133,7 +134,6 @@ void MainWindow::switchPage(QWidget *button) {
 void MainWindow::initialMqttService() {
     Logger::getInstance().info("Start init Mqtt server.");
     MqttClient *pcMqttInit = MqttClient::getInstance();
-    // "hxgc/topic"
     QStringList topics = {MQTT_TOPIC_COMPANY_PROJECTS};
     pcMqttInit->connectToMqttBroker("114.55.233.194", 1883, "hxgc", "hxgc123456", mqttClientId, topics);
     connect(pcMqttInit, &MqttClient::proMessageReceived, this, &MainWindow::handleMqttProjectsMessage);
@@ -252,17 +252,17 @@ MainWindow::~MainWindow() {
 }
 
 void MainWindow::mousePressEvent(QMouseEvent *event) {
-    if (event->button() == Qt::LeftButton) {
-        m_dragPosition = event->globalPos() - frameGeometry().topLeft();
-        event->accept();
-    }
+    // if (event->button() == Qt::LeftButton) {
+    //     m_dragPosition = event->globalPos() - frameGeometry().topLeft();
+    //     event->accept();
+    // }
 }
 
 void MainWindow::mouseMoveEvent(QMouseEvent *event) {
-    if (event->buttons() & Qt::LeftButton) {
-        move(event->globalPos() - m_dragPosition);
-        event->accept();
-    }
+    // if (event->buttons() & Qt::LeftButton) {
+    //     move(event->globalPos() - m_dragPosition);
+    //     event->accept();
+    // }
 }
 
 QList<QString> MainWindow::findAllChildUuids(const QJsonArray &addressArray, const QString targetUuid) {

+ 20 - 5
mqtt/mqttclient.cpp

@@ -19,8 +19,6 @@ MqttClient::MqttClient(QObject *parent) : QObject(parent), mqClient(new QMqttCli
     connect(mqClient, &QMqttClient::errorChanged, this, [this](QMqttClient::ClientError error) {
         Logger::getInstance().error(QString("MQTT client occured error: %1").arg(error));
     });
-
-    connect(mqClient, &QMqttClient::connected, this, &MqttClient::connected);
 }
 
 // 单例模式
@@ -35,6 +33,7 @@ MqttClient *MqttClient::createNewInstance() { return new MqttClient(); }
 void MqttClient::connectToMqttBroker() {
     mqClient->setHostname("114.55.233.194");
     mqClient->setPort(1883);
+    mqClient->setKeepAlive(20);
 
     // // 设置账号和密码
     mqClient->setUsername("hxgc");
@@ -50,6 +49,7 @@ void MqttClient::connectToMqttBroker(const QString &hostname, quint16 port, cons
                                      const QStringList &topicsToSubscribe) {
     mqClient->setHostname(hostname);
     mqClient->setPort(port);
+    mqClient->setKeepAlive(20);
 
     // 设置账号和密码
     mqClient->setUsername(username);
@@ -63,6 +63,7 @@ void MqttClient::connectToMqttBroker(const QString &hostname, quint16 port, cons
 }
 void MqttClient::onConnected() {
     Logger::getInstance().debug("MQTT conncted");
+    m_connectRetryCount = 0;
     subscribeToTopics(m_subscribeTopics);
 }
 
@@ -72,6 +73,13 @@ void MqttClient::subscribeToTopics(const QStringList &topics) {
     }
 }
 
+void MqttClient::disconnectFromMqttBroker() {
+    Logger::getInstance().info("MQTT client disconnecting from broker" + mqClient->state());
+    if (mqClient->state() == QMqttClient::Connected) {
+        mqClient->disconnectFromHost();
+    }
+}
+
 void MqttClient::subscribeToTopic(const QString &topic) { mqClient->subscribe(topic); }
 
 void MqttClient::sendMessage(const QString &topic, const QByteArray &message, quint8 qos, bool isRetainedMsg) {
@@ -103,17 +111,24 @@ void MqttClient::onMessageReceived(const QByteArray &message, const QMqttTopicNa
 void MqttClient::onStateChanged(QMqttClient::ClientState state) {
     switch (state) {
         case QMqttClient::ClientState::Disconnected:
-            QMessageBox::warning(nullptr, "提示", "mqtt连接已断开,请重新登录");
-            Logger::getInstance().info("Start init Mqtt server.");
+            m_connectRetryCount++;
+            if (m_connectRetryCount < 3) {
+                Logger::getInstance().info(QString("Mqtt reconnecting... (%1)").arg(m_connectRetryCount));
+                connectToMqttBroker();
+            } else {
+                Logger::getInstance().error("Mqtt reconnect failed after 3 attempts");
+                QMessageBox::warning(nullptr, "提示", "mqtt连接已断开,请重新登录");
+            }
             break;
         case QMqttClient::ClientState::Connecting:
             qDebug() << "MQTT 客户端状态: 正在连接";
             break;
         case QMqttClient::ClientState::Connected:
+            m_connectRetryCount = 0;  // 重置连接重试计数
             qDebug() << "MQTT 客户端状态: 已连接";
             break;
         default:
-            qDebug() << "MQTT 客户端状态: 未知状态";
+            Logger::getInstance().info("Mqtt unkown state: " + QString::number(state));
             break;
     }
 }

+ 3 - 0
mqtt/mqttclient.h

@@ -19,9 +19,11 @@ class MqttClient : public QObject {
     void connectToMqttBroker(const QString &hostname, quint16 port, const QString &username, const QString &password,
                              const QString &clientId, const QStringList &topicsToSubscribe);
     void subscribeToTopics(const QStringList &topics);
+    void disconnectFromMqttBroker();
     void connectToMqttBroker();
    signals:
     void connected();
+    void disConnected();
     void messageReceived(const QByteArray &message, const QMqttTopicName &topic);
     void proMessageReceived(const QByteArray &message, const QMqttTopicName &topic);
    private slots:
@@ -36,5 +38,6 @@ class MqttClient : public QObject {
     static MqttClient *instance;  // 静态成员变量,用于保存单例实例
     QMqttClient *mqClient;
     QStringList m_subscribeTopics;
+    int m_connectRetryCount = 0;  // 连接重试次数
 };
 #endif  // MQTTCLIENT_H

+ 5 - 8
mqttthread.cpp

@@ -5,14 +5,7 @@
 
 MqttThread::MqttThread(QObject *parent) : QThread(parent) {}
 
-MqttThread::~MqttThread() {
-    m_stopFlag = true;
-    quit();
-    wait();
-    if (mqttClient) {
-        delete mqttClient;
-    }
-}
+MqttThread::~MqttThread() { stopThread(); }
 
 void MqttThread::setConnectionInfo(const QString &hostname, quint16 port, const QString &username,
                                    const QString &password, const QString &clientId,
@@ -28,8 +21,11 @@ void MqttThread::setConnectionInfo(const QString &hostname, quint16 port, const
 MqttClient *MqttThread::getMqttClient() const { return mqttClient; }
 
 void MqttThread::stopThread() {
+    mqttClient->disconnectFromMqttBroker();
     m_stopFlag = true;
+    Logger::getInstance().info("MqttThread: 停止线程请求已发送");
     quit();
+    wait(3000);
 }
 
 void MqttThread::run() {
@@ -38,6 +34,7 @@ void MqttThread::run() {
     mqttClient->connectToMqttBroker(m_hostname, m_port, m_username, m_password, m_clientId, m_topicsToSubscribe);
 
     connect(mqttClient, &MqttClient::connected, this, &MqttThread::mqttConnected);
+    connect(mqttClient, &MqttClient::disConnected, this, &MqttThread::mqttDisconnected);
     connect(mqttClient, &MqttClient::messageReceived, this, &MqttThread::projectMqttMessageReceived);
     connect(this, &MqttThread::sendMessageRequested, mqttClient, &MqttClient::sendMessage);
     while (!m_stopFlag) {

+ 1 - 0
mqttthread.h

@@ -23,6 +23,7 @@ class MqttThread : public QThread {
 
    signals:
     void mqttConnected();
+    void mqttDisconnected();
     // 转发 MQTT 消息接收信号
     void projectMqttMessageReceived(const QByteArray &message, const QMqttTopicName &topic);
     void sendMessageRequested(const QString &topic, const QByteArray &message, quint8 qos, bool isRetainedMsg);

+ 5 - 0
qss/tableview.qss

@@ -24,6 +24,11 @@ QTableView {
     gridline-color: transparent; /* 网格线颜色透明 */
 }
 
+/* 序号列header */
+QTableCornerButton::section {
+    background-color: #4472C4;
+}
+
 /* 表头样式 */
 QHeaderView::section {
     background-color: #4472C4;