#include "firingwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "../backendapimanager.h" #include "../global.h" #include "../logger.h" #include "ui_firingwidget.h" #define ANSI_COLOR_GREEN "\x1B[32m" #define ANSI_COLOR_RESET "\x1B[0m" // Static constant definitions const int ErrorBlastStatusList::DEV_ERROR = 0xA0; const int ErrorBlastStatusList::BUS_SHORT = 0xA1; const int ErrorBlastStatusList::BUS_VOLTAGE_ERR = 0xA2; const int ErrorBlastStatusList::DET_OFFLINE_ERR = 0xA3; firingWidget::firingWidget(const int &row, const bool &select, const QString &uuid, QWidget *parent) : QWidget(parent), ui(new Ui::firingWidget), m_uuid(uuid), m_row(row), m_select(select), daoProj(DatabaseManager::getInstance().getDatabase()), daoDet(DatabaseManager::getInstance().getDatabase()), daoReg(DatabaseManager::getInstance().getDatabase()) { ui->setupUi(this); ui->pushButton_2->setText("立即测试"); ui->textEdit->setStyleSheet("border: none;background: transparent;"); ui->frame_2->setStyleSheet("border: none;background: transparent;"); QFrame *frame = ui->frame_2; // 使用你为 QFrame 设置的对象名称 navProgress = new NavProgress(frame); ui->verticalLayout->setContentsMargins(0, 30, 0, 0); ui->scrollArea->setStyleSheet("background: rgba(0, 0, 0, 22); border-radius: 20px;"); ui->verticalLayout->addWidget(navProgress); mqttThread = new MqttThread(this); QStringList topics = {"hxgc/" + uuid + "/B"}; mqttThread->setConnectionInfo("114.55.233.194", 1883, "hxgc", "hxgc123456", "P" + uuid, topics); connect(mqttThread, &MqttThread::mqttConnected, this, &firingWidget::onMqttConnected); mqttThread->start(); connect(mqttThread, &MqttThread::projectMqttMessageReceived, this, &firingWidget::handleProjectFiringMqttMessage); connect(this, &firingWidget::lastStageChanged, this, &firingWidget::handleFiringStageChanged); connect(this, &firingWidget::updateData, this, &firingWidget::onBlastSuccess); startBlasting(); } firingWidget::~firingWidget() { delete ui; } void firingWidget::sendMqttMessage(const QString &topic, const QByteArray &message) { if (mqttThread && m_isMqttConnected) { emit mqttThread->sendMessageRequested(topic, message, quint8(2), false); } else { Logger::getInstance().error("MQTT未连接, 无法发送消息"); } } void firingWidget::startBlasting() { QTimer::singleShot(1000, this, [this]() { lastStage = 0; emit lastStageChanged(0); }); // 3s内如果没有收到mqtt响应,则报错 QTimer *connectionCheckTimer = new QTimer(this); connectionCheckTimer->setSingleShot(true); bool isReceivedMessage = false; 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连接失败,请尝试重新登录"); } }); 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(&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(); // } void firingWidget::on_pushButton_2_clicked() { emit countdown(m_uuid, topic, "message"); } // NOTE: aborted, changed to upload in the smartmine server side. bool firingWidget::uploadToDanLing(const QJsonObject &jsonObj) { QString htid = jsonObj["project_htid"].toString(); QString htm = ""; // QString xmbh = jsonObj["project_xmbh"].toString(); QString sbbh = jsonObj["equipment_sn"].toString(); QString bprysfz = jsonObj["operator_identity"].toString(); QString dwdm = jsonObj["company_code"].toString(); QString xtm = ""; // QString jd = jsonObj["blast_longitude"].toString(); QString bpsj = jsonObj["blast_time"].toString(); QString wd = jsonObj["blast_latitude"].toString(); QStringList uidList; QJsonArray regs = jsonObj["regs"].toArray(); for (const auto ® : regs) { QJsonObject regObj = reg.toObject(); QJsonArray dets = regObj["dets"].toArray(); for (const auto &det : dets) { QJsonObject detObj = det.toObject(); uidList.append(detObj["uid"].toString()); } } QString uid = uidList.join(","); QString plainText = QString( "{\"htid\":\"%1\",\"htm\":\"%2\",\"xmbh\":\"%3\",\"sbbh\":\"%4\"," "\"bprysfz\":\"%5\",\"dwdm\":\"%6\",\"xtm\":\"%7\",\"jd\":\"%8\"," "\"bpsj\":\"%9\",\"wd\":\"%10\",\"uid\":\"%11\"}") .arg(htid) .arg(htm) .arg(xmbh) .arg(sbbh) .arg(bprysfz) .arg(dwdm) .arg(xtm) .arg(jd) .arg(bpsj) .arg(wd) .arg(uid); Des3Encryption des3; QByteArray key = "jadl12345678912345678912"; QByteArray encryptedData = des3.des3Encrypt(plainText.toUtf8(), key); QByteArray base64Encoded = encryptedData.toBase64(); QString encodedJson = QUrl::toPercentEncoding(base64Encoded); QString baseUrl = "http://test.mbdzlg.com/mbdzlgtxzx/servlet/DzlgSysbJsonServlert"; QUrl url(baseUrl); QUrlQuery query; query.addQueryItem("param", encodedJson); url.setQuery(query); QNetworkAccessManager manager; QNetworkRequest request(url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); QByteArray postData; QNetworkReply *reply = manager.post(request, postData); QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); if (reply->error() == QNetworkReply::NoError) { QByteArray responseData = reply->readAll(); qDebug() << "Response:" << QString(responseData); } else { qDebug() << "Error:" << reply->errorString(); } reply->deleteLater(); return true; } void firingWidget::handleProjectFiringMqttMessage(const QByteArray &message, const QMqttTopicName &topic) { QString msgText = QString("Topic: %1, Message: %2").arg(topic.name(), QString(message)); QTextEdit *textEdit = ui->scrollAreaWidgetContents->findChild("textEdit"); if (textEdit) { textEdit->append(msgText); } qDebug() << ANSI_COLOR_GREEN << "Received message on topic:" << topic.name() << ", Message:" << QString(message) << ANSI_COLOR_RESET; int stage = 0; QJsonDocument jsonDoc = QJsonDocument::fromJson(message); if (!jsonDoc.isNull() && jsonDoc.isObject()) { QJsonObject jsonObj = jsonDoc.object(); if (jsonObj.contains("type") && jsonObj["type"].toInt() == 1) { if (jsonObj.contains("data") && jsonObj["data"].isObject()) { QJsonObject dataObject = jsonObj["data"].toObject(); int status = dataObject["status"].toInt(); if (ErrorBlastStatusList::isErrorStatus(status)) { Logger::getInstance().error(QString("爆破器返回异常. 工程uuid: %1; 错误code: %2") .arg(m_uuid, ErrorBlastStatusList::getErrorMessage(status))); QMessageBox::critical( nullptr, "爆破器报错", QString("错误错误信息: %1").arg(ErrorBlastStatusList::getErrorMessage(status))); cancelBlasting(); return; } stage = dataObject["stage"].toInt(); if (stage != lastStage) { lastStage = stage; switch (stage) { case 0: navProgress->setState(0); ui->pushButton_2->setText("立即测试"); ui->pushButton_2->setEnabled(false); break; case 1: navProgress->setState(1); emit progressChanged(1, m_row); emit updateBlastStatus(1, m_row); ui->pushButton_2->setText("立即测试"); ui->pushButton_2->setEnabled(false); break; case 2: ui->pushButton_2->setEnabled(true); emit progressChanged(2, m_row); emit updateBlastStatus(2, m_row); qDebug() << "stage:" << stage; ui->pushButton_2->setText("充电"); navProgress->setState(2); break; case 3: ui->pushButton_2->setEnabled(false); emit progressChanged(3, m_row); emit updateBlastStatus(3, m_row); ui->pushButton_2->setText("充电"); navProgress->setState(3); break; case 4: ui->pushButton_2->setEnabled(true); emit progressChanged(4, m_row); emit updateBlastStatus(4, m_row); ui->pushButton_2->setText("起爆"); navProgress->setState(4); break; case 5: ui->pushButton_2->setEnabled(false); emit progressChanged(5, m_row); emit updateBlastStatus(5, m_row); emit updateButton(5, m_row); ui->pushButton_2->setText("起爆"); navProgress->setState(5); break; case 6: ui->pushButton_2->setEnabled(false); emit progressChanged(6, m_row); emit updateBlastStatus(6, m_row); emit updateProjectStatus(m_uuid, BlastStatus::Blasted); emit updateButton(6, m_row); ui->pushButton_2->setText("已完成起爆"); navProgress->setState(6); break; case 7: ui->pushButton_2->setEnabled(false); emit progressChanged(0, m_row); // 发送进度值 emit updateBlastStatus(0, m_row); // 正在测试 ui->pushButton_2->setText("已完成起爆"); navProgress->setState(6); break; default: break; } emit lastStageChanged(lastStage); } } } if (jsonObj.contains("type") && jsonObj["type"].toInt() == 2) { if (jsonObj.contains("data") && jsonObj["data"].isObject()) { QJsonObject dataObject = jsonObj["data"].toObject(); emit updateData(dataObject); emit closeFiring(m_uuid); } } } } void firingWidget::onCountdownFinished(const QString &topic, const QString &message) { qDebug() << "Countdown finished for topic:" << topic << ", message:" << message; sendMqttMessage(topic, message.toUtf8()); } void firingWidget::onMqttConnected() { Logger::getInstance().info(QString("Project(%1) firing MQTT connected successfully.").arg(m_uuid)); m_isMqttConnected = true; } void firingWidget::onButtonPressedReceived(const QString &topic, const QString &message) { QByteArray data = "\r\nDISABLE_BUTTON\r\n"; // 调用发送数据的方法 bool success = serialTool->sendData(data); if (!success) { Logger::getInstance().error(QString("onButtonPressedReceived: Failed to send data: %1").arg(data)); return; } emit countdown(m_uuid, topic, message); qDebug() << "Data sent successfully"; } void firingWidget::onSafeChecked(const QString projectUuid) { if (projectUuid == m_uuid) { lastStage = 3; // 设置为待安全确认状态 emit projSafeCheckSuccess(m_uuid); emit lastStageChanged(lastStage); qDebug() << ANSI_COLOR_GREEN << "安全确认成功,进入待起爆状态" << ANSI_COLOR_RESET; } else { qDebug() << "Project UUID mismatch, expected: " << m_uuid << ", got: " << projectUuid; } } // 状态改变 void firingWidget::handleFiringStageChanged(int newStage) { QString topic = "hxgc/" + m_uuid + "/P"; QString message; QString buttonText; switch (lastStage) { case 0: message = "起爆测试"; buttonText = "立即测试"; sendMqttMessage(topic, message.toUtf8()); break; case 2: message = "开始充电"; buttonText = "充电"; sendMqttMessage(topic, message.toUtf8()); break; case 4: message = "起爆"; buttonText = "起爆"; break; case 5: if (!m_select) { if (connection) { disconnect(connection); qDebug() << "Connection disconnected."; } if (connectionPress) { disconnect(connectionPress); qDebug() << "connectionPress disconnected."; } serialTool->releaseInstance(); } qDebug() << ANSI_COLOR_GREEN << "释放按键 5" << ANSI_COLOR_RESET; break; default: return; } if (!message.isEmpty()) { if (lastStage == 4 && !m_select) { bool success2; serialTool = SerialTool::getInstance(nullptr, &success2); if (serialTool) { QByteArray data = "\r\nENABLE_BUTTON\r\n"; bool success = serialTool->sendData(data); if (success) { qDebug() << "Data sent successfully"; } else { qDebug() << "Failed to send data"; } connection = connect(serialTool, &SerialTool::enableButtonReceived, [this]() { emit updateBlastStatus(10, m_row); }); connectionPress = connect(serialTool, &SerialTool::buttonPressedReceived, [this, topic, message]() { this->onButtonPressedReceived(topic, message); }); } else { qDebug() << "serialTool Not fond."; // 在准备起爆状态下 但是没有获取串口 lastStage = 10; } } else if (lastStage == 4 && m_select) { qDebug() << "多台起爆:待起爆状态"; emit selectSignal(m_uuid); } else { //???? qDebug() << "Stage 值变为: " << newStage << "发送消息" << message.toUtf8(); } } } void firingWidget::cancelBlasting() { emit progressChanged(0, m_row); // 重置进度 emit updateBlastStatus(0, m_row); emit updateProjectStatus(m_uuid, BlastStatus::Created); // TODO: 重置状态为已注册 // QString message = "取消流程"; // if (!message.isEmpty()) { // sendMqttMessage(topic, message.toUtf8()); // } } void firingWidget::on_sendTest_4_clicked() {} void firingWidget::testOnBlastSuccess(const QJsonObject &jsonObj) { onBlastSuccess(jsonObj); } // 处理爆破成功,安全验证装置通过MQTT传回的数据 void firingWidget::onBlastSuccess(const QJsonObject &jsonObj) { Logger::getInstance("blastRecord.log").info(QJsonDocument(jsonObj).toJson(QJsonDocument::Indented)); blast_uuid = QUuid::createUuid().toString(QUuid::WithoutBraces).remove(QRegularExpression("-")); saveAndUploadRecord(jsonObj); } void firingWidget::saveAndUploadRecord(const QJsonObject &jsonObj) { QSqlDatabase db = DatabaseManager::getInstance().getDatabase(); if (!db.transaction()) { Logger::getInstance().critical(QString("Failed to start DB transaction. Error: %1").arg(db.lastError().text())); return; } qDebug() << "Starting transaction for blast record with uuid:" << jsonObj; HBlastRecord *blastRecord = recordBlastProject(jsonObj); if (blastRecord == nullptr) { Logger::getInstance("error_blast_records.log") .error(QString("Failed to create blast record. projectName: %1, ProjectID: %2; " "rollback transaction: %3") .arg(jsonObj["project_name"].toString(), jsonObj["project_htid"].toString(), db.rollback() ? "success" : "failed")); return; } QList blastEquipmentRecords; for (const auto ®Value : jsonObj["regs"].toArray()) { QJsonObject equipmentJsonObject = regValue.toObject(); HBlastEquipmentRecord *hBlastEquipmentRecord = recordBlastEquipment(blastRecord->getUuid(), equipmentJsonObject); if (hBlastEquipmentRecord != nullptr) { blastEquipmentRecords.append(hBlastEquipmentRecord); } QList hBlastRecordDets = recordBlastProjectDets( blastRecord->getUuid(), hBlastEquipmentRecord->getUuid(), equipmentJsonObject["dets"].toArray()); hBlastEquipmentRecord->setDetRecords(hBlastRecordDets); } blastRecord->setEquipmentRecords(blastEquipmentRecords); if (db.commit()) { Logger::getInstance().info(QString("Transaction committed successfully. blast_uuid: %1").arg(blast_uuid)); } else { Logger::getInstance().error(QString("Failed to commit transaction: %1. try to rollback: %2") .arg(db.lastError().text(), db.rollback() ? "success" : "failed")); return; } qDebug() << "Transaction committed successfully for blast record with uuid:" << blastRecord->getUuid(); uploadBlastRecordToServer(blastRecord); } void firingWidget::uploadBlastRecordToServer(HBlastRecord *blastRecord) { if (blastRecord == nullptr) { return; } if (!backendAPIManager::uploadBlastProjectFull(blastRecord->ToJson())) { Logger::getInstance().error(QString("Failed to upload blast project. data: %1") .arg(QJsonDocument(blastRecord->ToJson()).toJson(QJsonDocument::Indented))); } Logger::getInstance().info( QString("Blast project uploaded to server successfully. blast_uuid: %1").arg(blastRecord->getUuid())); } HBlastRecord *firingWidget::recordBlastProject(const QJsonObject &jsonObj) { HBlastRecord *record = new HBlastRecord(); record->setIsOfflineBlast(jsonObj["is_offline_blast"].toString() == "true"); record->setProjectName(jsonObj["project_name"].toString()); record->setProjectHtid(jsonObj["project_htid"].toString()); record->setProjectXmbh(jsonObj["project_xmbh"].toString()); record->setOperatorName(jsonObj["operator_name"].toString()); record->setPhone(jsonObj["phone"].toString()); record->setOperatorIdentity(jsonObj["operator_identity"].toString()); record->setEquipmentSn(jsonObj["equipment_sn"].toString()); record->setCompanyCode(jsonObj["company_code"].toString()); record->setAppVersion(jsonObj["app_version"].toString()); // TODO: 如何获得坐标 record->setLongitude(jsonObj["blast_longitude"].toString().left(10)); record->setLatitude(jsonObj["blast_latitude"].toString().left(10)); record->setRegDetCount(jsonObj["reg_deto_count"].toString().toInt()); record->setErrorDetCount(jsonObj["error_deto_count"].toString().toInt()); QDateTime blastTime = QDateTime::fromString(jsonObj["blast_time"].toString(), "yyyy-MM-dd hh:mm:ss"); record->setBlastAt(blastTime); record->setCreatedAt(QDateTime::currentDateTime()); record->setUuid(blast_uuid); if (daoProj.addHBlastRecord(*record)) { qDebug() << "Record inserted successfully."; return record; } else { qDebug() << "Failed to insert record."; delete record; return nullptr; } } HBlastEquipmentRecord *firingWidget::recordBlastEquipment(const QString blastProjectUuid, const QJsonObject ®Obj) { HBlastEquipmentRecord *recordReg = new HBlastEquipmentRecord(); reg_uuid = QUuid::createUuid().toString(QUuid::WithoutBraces).remove(QRegularExpression("-")); recordReg->setUuid(reg_uuid); recordReg->setEquipSn(regObj["equipment_sn"].toString()); recordReg->setEquipVersion(regObj["equipment_version"].toString()); recordReg->setRegDetoCount(regObj["reg_deto_count"].toString().toInt()); recordReg->setErrorDetoCount(regObj["error_deto_count"].toString().toInt()); recordReg->setAfterTestBusV(regObj["after_test_bus_v"].toString()); recordReg->setAfterTestBusI(regObj["after_test_bus_i"].toString()); recordReg->setBusLeakageCurrentI(regObj["bus_leakage_current_i"].toString()); recordReg->setNetChargedV(regObj["net_charged_v"].toString()); recordReg->setNetChargedI(regObj["net_charged_i"].toString()); recordReg->setBeforeBlastingV(regObj["before_blasting_v"].toString()); recordReg->setBeforeBlastingI(regObj["before_blasting_i"].toString()); recordReg->setRecordUuid(blastProjectUuid); recordReg->setCreatedAt(QDateTime::currentDateTime()); if (!daoReg.saveHBlastRegRecord(*recordReg)) { Logger::getInstance().error(QString("Failed to save HBlastRegRecord: %1").arg(recordReg->getEquipSn())); delete recordReg; return nullptr; } return recordReg; } QList firingWidget::recordBlastProjectDets(const QString projectUuid, const QString equipmentUuid, const QJsonArray detsArray) { QList recordDets; for (const auto &detValue : detsArray) { QJsonObject detObj = detValue.toObject(); HBlastRecordDet *recordDet = new HBlastRecordDet(); recordDet->setId(0); recordDet->setUuid(QUuid::createUuid().toString(QUuid::WithoutBraces).remove(QRegularExpression("-"))); recordDet->setOutCode(detObj["out_code"].toString()); recordDet->setInnerCode(detObj["in_code"].toString()); recordDet->setUid(detObj["uid"].toString()); recordDet->setStatus(detObj["status"].toString()); recordDet->setFreq(detObj["freq"].toString()); recordDet->setDelayTime(detObj["delay_time"].toString()); recordDet->setTag(detObj["tag"].toString()); recordDet->setBlastRecordUuid(projectUuid); recordDet->setEquipmentRecordUuid(equipmentUuid); recordDet->setCreatedAt(QDateTime::currentDateTime()); if (daoDet.addHBlastRecordDet(*recordDet)) { recordDets.append(recordDet); } else { Logger::getInstance().error(QString("Failed to insert record det. data %1") .arg(QJsonDocument(recordDet->ToJson()).toJson(QJsonDocument::Compact))); delete recordDet; continue; } } return recordDets; }