#include "blastopepage.h" #include #include #include #include "countdownwidget.h" #include "global.h" #include "loadingwidget.h" #include "logger.h" #include "loginwindow.h" #include "registryManager/registrymanager.h" #include "ui_blastopepage.h" const int ColIndexBlastStatus = 7; const int ColIndexProgressBar = 8; const int ColIndexOpBtn = 9; const int ColIndexUuid = 10; BlastOpePage::BlastOpePage(QWidget *parent) : QWidget(parent), ui(new Ui::BlastOpePage), dao(DatabaseManager::getInstance().getDatabase()) { QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); if (isFaceVerificationEnabled) { InitFace(); } else { ui->setupUi(this); initPagination(); } } void BlastOpePage::showCountDownWidget(QString uuid, const QString &topic, const QString &message) { CountdownWidget *countdownWidget = new CountdownWidget(this); countdownWidget->resize(200, 200); int x = (this->width() - countdownWidget->width()) / 2; int y = (this->height() - countdownWidget->height()) / 2; countdownWidget->move(x, y); countdownWidget->show(); firingWidget *widget = firingWidgetByUuid.value(uuid); if (widget) { connect( countdownWidget, &CountdownWidget::countdownFinished, widget, [widget, topic, message, countdownWidget]() { widget->onCountdownFinished(topic, message); }, Qt::SingleShotConnection); } } void BlastOpePage::InitFace() { Logger::getInstance().info("start init face verification"); LoadingWidget::showLoading(this, "请求创建人脸识别..."); layout = new QVBoxLayout(this); // TODO: relase the qwebengineview when not successfully verified view = new QWebEngineView(this); view->setAttribute(Qt::WA_OpaquePaintEvent); QWebEnginePage *page = view->page(); QJsonObject metaInfo = getMetaInfo(); if (metaInfo["certName"] == "" || metaInfo["certNo"] == "") { QMessageBox::information(nullptr, "获取用户信息错误", "未获得用户的身份证信息,请联系管理员"); return; } QObject::connect(page, &QWebEnginePage::featurePermissionRequested, [this, page](const QUrl &securityOrigin, QWebEnginePage::Feature feature) { handleFeaturePermission(page, securityOrigin, feature); }); Logger::getInstance().info("FaceVerification: connect"); QUrl postUrl(apiBackendUrl.resolved(QUrl("h-face-verify/pc"))); QJsonObject response = sendPostRequest(postUrl, metaInfo); QString certifyUrl; if (response["code"] != 200) { Logger::getInstance().error( QString("创建人脸识别请求服务器返回错误: userName: %1. response: %2") .arg(metaInfo["certName"].toString(), QString::fromUtf8(QJsonDocument(response).toJson()))); QMessageBox::critical(nullptr, "错误", "无法创建人脸识别,请确认后台录入的身份信息正确"); return; } if (response.contains("data") && response["data"].isObject()) { LoadingWidget::showLoading(this, "人脸识别请求已创建..."); QJsonObject dataObject = response["data"].toObject(); if (dataObject.contains("ResultObject") && dataObject["ResultObject"].isObject()) { QJsonObject resultObject = dataObject["ResultObject"].toObject(); if (resultObject.contains("CertifyId") && resultObject["CertifyId"].isString()) { certifyId = resultObject["CertifyId"].toString(); } if (resultObject.contains("CertifyUrl") && resultObject["CertifyUrl"].isString()) { certifyUrl = resultObject["CertifyUrl"].toString(); } } } if (!certifyUrl.isEmpty()) { view->load(QUrl(certifyUrl)); layout->addWidget(view); layout->setStretchFactor(view, 1); QObject::connect(page, &QWebEnginePage::urlChanged, this, &BlastOpePage::onUrlChanged); } else { QMessageBox::information(nullptr, "提示", "人脸识别请求失败"); Logger::getInstance().error("FaceVerificationInit: Failed to get certifyUrl"); LoadingWidget::hideLoading(); } } void BlastOpePage::closeWebViewAndRestoreUI() { if (view) { layout->removeWidget(view); delete view; view = nullptr; } if (layout) { delete layout; layout = nullptr; } } // 槽函数:处理 URL 改变事件 void BlastOpePage::onUrlChanged(const QUrl &newUrl) { LoadingWidget::showLoading(this, "查询验证结果..."); if (newUrl.host() == "www.integrateblaster.com") { closeWebViewAndRestoreUI(); QNetworkAccessManager manager; QUrl requestUrl(apiBackendUrl.resolved(QUrl(QString("h-face-verify/certifyId/%1").arg(certifyId)))); QNetworkRequest request(requestUrl); QNetworkReply *reply = manager.get(request); QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); if (reply->error() == QNetworkReply::NoError) { QByteArray responseData = reply->readAll(); QJsonDocument jsonDoc = QJsonDocument::fromJson(responseData); if (!jsonDoc.isNull() && jsonDoc.isObject()) { QJsonObject rootObj = jsonDoc.object(); QJsonObject dataObj = rootObj["data"].toObject(); QString message = dataObj["Message"].toString(); QJsonObject resultObj = dataObj["ResultObject"].toObject(); if (resultObj.isEmpty()) { Logger::getInstance().error(QString("获取认证初始化数据失败. message: %1.").arg(message)); int ret = QMessageBox::information(nullptr, "认证失败", message + " ,请重新认证!"); if (ret == QMessageBox::Ok) { InitFace(); } } else { QString passed = resultObj["Passed"].toString(); if (passed == "T") { ui->setupUi(this); initPagination(); Logger::getInstance().info(QString("进入认证界面")); LoadingWidget::hideLoading(); } else if (passed == "F") { int ret = QMessageBox::critical(nullptr, "提示", "操作失败,请重新认证!"); if (ret == QMessageBox::Ok) { InitFace(); } } } } } else { qDebug() << "Request failed:" << reply->errorString(); Logger::getInstance().error( QString("InitFaseVerification request failed. error message: %1").arg(reply->errorString())); } reply->deleteLater(); LoadingWidget::hideLoading(); } LoadingWidget::hideLoading(); } BlastOpePage::~BlastOpePage() { delete ui; if (view) { delete view; } if (layout) { delete layout; } } QJsonObject BlastOpePage::sendPostRequest(const QUrl &url, const QJsonObject &data) { QNetworkAccessManager manager; QNetworkRequest request(url); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); QJsonDocument doc(data); QByteArray postData = doc.toJson(); QNetworkReply *reply = manager.post(request, postData); QEventLoop loop; QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit); loop.exec(); QJsonObject responseJson; if (reply->error() == QNetworkReply::NoError) { QByteArray responseData = reply->readAll(); QJsonDocument responseDoc = QJsonDocument::fromJson(responseData); if (!responseDoc.isNull() && responseDoc.isObject()) { responseJson = responseDoc.object(); } } else { qDebug() << "Error fetching content: " << reply->errorString(); } reply->deleteLater(); return responseJson; } void BlastOpePage::handleFeaturePermission(QWebEnginePage *page, const QUrl &securityOrigin, QWebEnginePage::Feature feature) { if (feature == QWebEnginePage::MediaAudioCapture || feature == QWebEnginePage::MediaAudioVideoCapture || feature == QWebEnginePage::MediaVideoCapture) { page->setFeaturePermission(securityOrigin, feature, QWebEnginePage::PermissionGrantedByUser); } else { page->setFeaturePermission(securityOrigin, feature, QWebEnginePage::PermissionDeniedByUser); } } QJsonObject BlastOpePage::getMetaInfo() { QJsonObject metaInfo; QString certName; QString certNo; QMap userInfo = RegistryManager::instance()->getCurentLoginUser(); certName = userInfo.value("certName", ""); certNo = userInfo.value("identity", ""); metaInfo["certName"] = certName; metaInfo["certNo"] = certNo; return metaInfo; } void BlastOpePage::initPagination() { pageWidget = new PageWidget; connect(pageWidget, &PageWidget::currentPageChanged, this, &BlastOpePage::PageChanged); connect(pageWidget->getComboBox(), QOverload::of(&QComboBox::currentIndexChanged), this, &BlastOpePage::onComboBoxIndexChanged); ui->verticalLayout_4->addWidget(pageWidget); m_pageSize = 10; m_currentPage = 1; RefreshData(); } void BlastOpePage::RefreshData() { loadDataAndDrawTable(m_currentPage, m_pageSize); } void BlastOpePage::loadDataAndDrawTable(int currentPage, int pageSize) { PaginatedHProjectResult result = dao.getAllHProjectsByOpera(currentPage, pageSize); QList> projectList = result.projects; totalCount = result.totalCount; pageWidget->setMaxPage(ceil(static_cast(totalCount) / pageSize)); model = new QStandardItemModel(this); headers = { {"选择", ""}, {"工程名称", "name"}, {"操作员", "operatorName"}, {"爆破员", "blasterName"}, {"井下地址", "addressPath"}, {"雷管数量", "detSum"}, {"起爆器数量", "blastCount"}, {"起爆状态", "blastStatus"}, {"进度", ""}, {"操作", ""}, }; int headerCount = headers.size(); QStringList headerLabels; QMap propMap; for (int i = 0; i < headers.size(); ++i) { headerLabels << headers[i].label; propMap[i] = headers[i].prop; } model->setHorizontalHeaderLabels(headerLabels); for (int row = 0; row < projectList.size(); ++row) { HProject &HProject = *projectList.at(row).data(); QStandardItem *uuidItem = new QStandardItem(); uuidItem->setData(HProject.getUuid(), Qt::UserRole); model->setItem(row, headerCount, uuidItem); for (int col = 0; col < headerCount; ++col) { QString prop = propMap[col]; QStandardItem *item = nullptr; if (col == 0) { item = new QStandardItem(); item->setCheckable(true); item->setCheckState(Qt::Unchecked); item->setText(""); } if (!prop.isEmpty()) { QMetaProperty metaProp = HProject.metaObject()->property(HProject.metaObject()->indexOfProperty(prop.toUtf8())); QVariant value = metaProp.read(&HProject); if (prop == "blastStatus") { QString statusText; if (value.toString() == BlastStatus::SafeChecked) { statusText = "待起爆"; item = new QStandardItem(statusText); item->setForeground(QColor("#f3a3k'k1")); } else if (value.toString() == BlastStatus::Blasted) { statusText = "起 爆 完 成"; item = new QStandardItem(statusText); item->setForeground(QColor("#90d543")); } else { item = new QStandardItem(value.toString()); } } else { item = new QStandardItem(value.toString()); } } if (item) { item->setTextAlignment(Qt::AlignCenter); // 设置文本居中对齐 model->setItem(row, col, item); } } } ui->tableView->setModel(model); connectionItem = QObject::connect(model, &QStandardItemModel::itemChanged, this, &BlastOpePage::onItemCheckboxChanged); ui->tableView->setColumnWidth(0, 30); ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers); // 禁止编辑 for (int i = 1; i < headerCount; ++i) { if (i == 8) { // Column: 进度 ui->tableView->horizontalHeader()->setSectionResizeMode(i, QHeaderView::Custom); ui->tableView->setColumnWidth(i, 180); } else { ui->tableView->horizontalHeader()->setSectionResizeMode(i, QHeaderView::Stretch); } } ui->tableView->setColumnHidden(headerCount, true); ui->tableView->setAlternatingRowColors(true); 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 progressBar1->setValue(0); progressBar1->setAlignment(Qt::AlignCenter); progressBar1->setStyleSheet( "QProgressBar { border: 1px solid grey; border-radius: 5px; background-color: #EEEEEE; " "height: 10px; }" "QProgressBar::chunk { background-color: #05B8CC; width: 2px; margin: 0.5px; border - " "radius: 10px; }"); progressBar1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QProgressBar *progressBar2 = new QProgressBar(ui->tableView); progressBar2->setRange(0, 100); // 设置范围为0到100 progressBar2->setValue(0); progressBar2->setAlignment(Qt::AlignCenter); progressBar2->setStyleSheet( "QProgressBar { border: 1px solid grey; border-radius: 5px; background-color: #EEEEEE; " "height: 10px; }" "QProgressBar::chunk { background-color: #05B8CC; width: 2px; margin: 0.5px; border - " "radius: 10px; }"); progressBar2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QProgressBar *progressBar3 = new QProgressBar(ui->tableView); progressBar3->setRange(0, 100); // 设置范围为0到100 progressBar3->setValue(0); progressBar3->setAlignment(Qt::AlignCenter); progressBar3->setStyleSheet( "QProgressBar { border: 1px solid grey; border-radius: 5px; background-color: #EEEEEE; " "height: 10px; }" "QProgressBar::chunk { background-color: #05B8CC; width: 2px; margin: 0.5px; border - " "radius: 10px; }"); progressBar3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); progressBars.append(ProgressBarTriple(progressBar1, progressBar2, progressBar3)); QHBoxLayout *progressBarLayout = new QHBoxLayout; progressBarLayout->addWidget(progressBar1); progressBarLayout->addWidget(progressBar2); progressBarLayout->addWidget(progressBar3); progressBarLayout->setAlignment(Qt::AlignCenter); progressBarLayout->setContentsMargins(0, 0, 0, 0); progressBarLayout->setSpacing(0); // 设置进度条之间的间距为0 QWidget *progressBarContainer = new QWidget(ui->tableView); progressBarContainer->setLayout(progressBarLayout); QModelIndex progressIndex = model->index(row, progressCol); if (progressIndex.isValid()) { 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, ColIndexBlastStatus); if (statusIndex.isValid()) { QString blastStatus = model->data(statusIndex).toString(); if (blastStatus == "待起爆") { button->setText(startBlastButtonTxt); button->setEnabled(true); } } QHBoxLayout *layout = new QHBoxLayout(widget); layout->addWidget(button); layout->setAlignment(Qt::AlignCenter); layout->setContentsMargins(0, 0, 0, 0); widget->setLayout(layout); QModelIndex index = model->index(row, col); if (index.isValid()) { ui->tableView->setIndexWidget(index, widget); connect(button, &QPushButton::clicked, [this, row, button]() { handleSingleBlastButtonClicked(row, button); }); } } } // 切换页数 void BlastOpePage::PageChanged(int page) { m_currentPage = page; loadDataAndDrawTable(m_currentPage, m_pageSize); } void BlastOpePage::onComboBoxIndexChanged(int index) { QVariant variant = pageWidget->getComboBox()->itemData(index); int value = variant.toInt(); m_pageSize = value; m_currentPage = 1; loadDataAndDrawTable(m_currentPage, m_pageSize); } void BlastOpePage::updateProgressBar(int firingStage, int row) { if (!progressBars.isEmpty()) { QProgressBar *progressBar1 = progressBars[row].bar1; QProgressBar *progressBar2 = progressBars[row].bar2; QProgressBar *progressBar3 = progressBars[row].bar3; switch (firingStage) { case FiringStages::Starting: progressBar1->setValue(0); progressBar2->setValue(0); progressBar3->setValue(0); break; 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; case FiringStages::NetCharging: // 充电开始 progressBar2->setRange(0, 0); // 设置范围为0到100 progressBar2->setValue(0); break; case FiringStages::NetChargingFinished: // 充电完成 progressBar2->setRange(0, 100); // 设置范围为0到100 progressBar2->setValue(100); break; case FiringStages::Blasting: // 起爆中 progressBar3->setRange(0, 0); // 设置范围为0到100 progressBar3->setValue(0); break; case FiringStages::BlastFinished: // 充电完成 progressBar3->setRange(0, 100); // 设置范围为0到100 progressBar3->setValue(100); break; case FiringStages::CancelConfirmed: progressBar1->setRange(0, 100); // 设置范围为0到100 progressBar1->setValue(0); progressBar2->setRange(0, 100); // 设置范围为0到100 progressBar2->setValue(0); progressBar3->setRange(0, 100); // 设置范围为0到100 progressBar3->setValue(0); break; default: break; } } } // update tableView's fields about firing stage void BlastOpePage::onFiringStageUpdated(int stage, int row) { // update blast status item QModelIndex firingStatusItem = model->index(row, ColIndexBlastStatus); if (firingStatusItem.isValid()) { QColor customColor; QFont boldFont; boldFont.setBold(true); qDebug() << "opage::onFiringStageUpdated: stage = " << stage << ", row = " << row; switch (stage) { 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, "起爆检测中..."); customColor = QColor("#44035b"); model->setData(firingStatusItem, customColor, Qt::ForegroundRole); model->setData(firingStatusItem, boldFont, Qt::FontRole); break; case FiringStages::QuickTestFinished: model->setData(firingStatusItem, "检测完成"); customColor = QColor("#404185"); model->setData(firingStatusItem, customColor, Qt::ForegroundRole); break; case FiringStages::NetCharging: model->setData(firingStatusItem, "充电中 ..."); customColor = QColor("#31688e"); model->setData(firingStatusItem, customColor, Qt::ForegroundRole); break; case FiringStages::NetChargingFinished: model->setData(firingStatusItem, "充电完成"); customColor = QColor("#1f918d"); model->setData(firingStatusItem, customColor, Qt::ForegroundRole); break; case FiringStages::Blasting: model->setData(firingStatusItem, "起爆中..."); customColor = QColor("#38b775"); model->setData(firingStatusItem, customColor, Qt::ForegroundRole); break; case FiringStages::BlastFinished: model->setData(firingStatusItem, "起爆完成"); customColor = QColor("#90d543"); model->setData(firingStatusItem, customColor, Qt::ForegroundRole); break; case FiringStages::PendingTriggerButtonClick: model->setData(firingStatusItem, "按下双键起爆..."); customColor = QColor("#8e620"); model->setData(firingStatusItem, customColor, Qt::ForegroundRole); break; case FiringStages::CancelConfirmed: model->setData(firingStatusItem, "已取消"); customColor = QColor("#893c3c"); model->setData(firingStatusItem, customColor, Qt::ForegroundRole); break; case FiringStages::ForceCanceled: model->setData(firingStatusItem, "已强制取消"); customColor = QColor("#893c3c"); model->setData(firingStatusItem, customColor, Qt::ForegroundRole); break; default: break; } } updateProgressBar(stage, row); handleUpdateOpButton(stage, row); } void BlastOpePage::handleSingleBlastButtonClicked(int row, QPushButton *button) { QStandardItem *uuidItem = model->item(row, ColIndexUuid); QString uuid; if (uuidItem) { QVariant uuidVariant = uuidItem->data(Qt::UserRole); if (uuidVariant.isValid()) { uuid = uuidVariant.toString(); } } if (button->text() == startBlastButtonTxt) { button->setDisabled(true); QTimer::singleShot(5000, [button]() { if (button->isEnabled()) { return; } button->setEnabled(true); }); button->setMinimumWidth(80); button->setText(stopBlastButtonTxt); firingWidget *widget = new firingWidget(row, false, uuid); connect(widget, &firingWidget::updatefiringStage, this, &BlastOpePage::onFiringStageUpdated); connect(widget, &firingWidget::countdown, this, &BlastOpePage::showCountDownWidget); connect(widget, &firingWidget::updateProjectStatus, this, &BlastOpePage::handlerUpdateProjectStatus); connect(widget, &firingWidget::closeFiring, this, &BlastOpePage::destroyFiringWidget); if (isShowTriggeringWidget) { widget->show(); } widget->setAttribute(Qt::WA_DeleteOnClose); firingWidgetByUuid.insert(uuid, widget); widget->startBlasting(); } else if (button->text() == stopBlastButtonTxt) { // TODO: wrap into class 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) { return; } firingWidget *widget = firingWidgetByUuid.value(uuid); if (widget) { widget->sendCancelFiringMsg(); } } else { Logger::getInstance().error( QString("handleSingleBlastButtonClicked: unknown button text %1").arg(button->text())); return; } } void BlastOpePage::handleUpdateOpButton(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)); return; } QWidget *widget = ui->tableView->indexWidget(index); QPushButton *button = widget->findChild(); if (!button) { Logger::getInstance().error(QString("can not find button in row %1").arg(row)); return; } switch (stage) { case FiringStages::CancelConfirmed: button->setDisabled(true); button->setText(reStartButtonTxt); break; case FiringStages::Starting: button->setDisabled(true); break; case FiringStages::QuickTesting: button->setEnabled(true); button->setText(stopBlastButtonTxt); break; case FiringStages::QuickTestFinished: button->setEnabled(true); button->setText(stopBlastButtonTxt); break; case FiringStages::NetCharging: button->setEnabled(true); button->setText(stopBlastButtonTxt); break; case FiringStages::NetChargingFinished: button->setEnabled(true); button->setText(stopBlastButtonTxt); break; case FiringStages::PendingTriggerButtonClick: button->setEnabled(true); button->setText(stopBlastButtonTxt); 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; case FiringStages::ForceCanceled: button->setDisabled(true); button->setText(reStartButtonTxt); break; default: button->setEnabled(true); break; } } void BlastOpePage::handlerUpdateProjectStatus(QString uuid, const QString &newStatus) { dao.updateBlastStatusByUuid(uuid, newStatus); firingWidget *widget = firingWidgetByUuid.value(uuid); } void BlastOpePage::destroyFiringWidget(const QString &uuid, int row) { firingWidget *widget = firingWidgetByUuid.value(uuid); if (widget) { widget->close(); // 关闭窗口 widget->deleteLater(); // 释放内存 widget->disconnect(); // 断开信号连接 firingWidgetByUuid.remove(uuid); // 从映射中移除 } } // 槽函数,当 item 状态改变时触发 void BlastOpePage::onItemCheckboxChanged(QStandardItem *item) { if (item->column() == 0) { // 仅处理第一列的勾选状态改变 if (item->checkState() == Qt::Checked) { QStandardItem *uuidItem = model->item(item->row(), 10); if (uuidItem) { QVariant uuidVariant = uuidItem->data(Qt::UserRole); if (uuidVariant.isValid()) { QString uuid = uuidVariant.toString(); uuidMap[item->row()] = uuid; } } } else if (item->checkState() == Qt::Unchecked) { QStandardItem *uuidItem = model->item(item->row(), 10); if (uuidItem) { // 从 item 中获取 uuid 数据 QVariant uuidVariant = uuidItem->data(Qt::UserRole); if (uuidVariant.isValid()) { QString uuid = uuidVariant.toString(); // 从数组中移除该 uuid uuidMap.remove(item->row()); } } } } } void BlastOpePage::on_btnSelect_clicked() { // 禁用表格第一列的选项 for (int row = 0; row < model->rowCount(); ++row) { QStandardItem *item = model->item(row, 0); if (item) { Qt::ItemFlags flags = item->flags(); flags &= ~Qt::ItemIsEnabled; item->setFlags(flags); } } for (auto it = uuidMap.begin(); it != uuidMap.end(); ++it) { int row = it.key(); QString uuid = it.value(); firingWidget *widgetSelect = new firingWidget(row, true, uuid); QModelIndex index = model->index(row, ColIndexUuid); if (index.isValid()) { QWidget *widgetButton = ui->tableView->indexWidget(index); if (widgetButton) { QPushButton *button = widgetButton->findChild(); button->setText(stopBlastButtonTxt); button->setDisabled(true); } } // 信号连接 connect(widgetSelect, &firingWidget::updatefiringStage, this, &BlastOpePage::onFiringStageUpdated); connect(widgetSelect, &firingWidget::batchFiringSignal, this, &BlastOpePage::setBatchBlastTrigger); connect(widgetSelect, &firingWidget::updateProjectStatus, this, &BlastOpePage::handlerUpdateProjectStatus); connect(widgetSelect, &firingWidget::closeFiring, this, &BlastOpePage::destroyBatchFiringWidget); widgetSelect->setAttribute(Qt::WA_DeleteOnClose); uuidWidgetSMap.insert(uuid, widgetSelect); widgetSelect->startBlasting(); if (isShowTriggeringWidget) { widgetSelect->show(); } } } // 完成充电 void BlastOpePage::setBatchBlastTrigger(QString uuid) { selectedUuids.insert(uuid); bool isSame = checkUuidsSame(); if (isSame) { bool successSelect; serialTool = SerialTool::getInstance(nullptr, &successSelect); connect(serialTool, &SerialTool::buttonPressedReceived, this, &BlastOpePage::showCountDownForBatchBlast, Qt::SingleShotConnection); if (serialTool) { QByteArray data = "\r\nENABLE_BUTTON\r\n"; bool success = serialTool->sendData(data); if (success) { Logger::getInstance().info("blast triggered."); } else { Logger::getInstance().warn("blast trigger failed."); } connect( serialTool, &SerialTool::enableButtonReceived, this, [this]() { for (const auto &row : uuidMap.keys()) { onFiringStageUpdated(10, row); } }, Qt::SingleShotConnection); } else { qDebug() << "serialTool Not fond."; QMessageBox::critical(nullptr, "错误", "trigger button devices not found"); } } else { Logger::getInstance().error( QString("The uuids in selectedUuids and uuidMap are different. uuid: %1").arg(uuid)); } } // 检查 selectedUuids 和 uuidMap 中的 uuid 是否相同 bool BlastOpePage::checkUuidsSame() { QSet mapUuids; for (const auto &value : uuidMap) { mapUuids.insert(value); } return selectedUuids == mapUuids; } void BlastOpePage::showCountDownForBatchBlast() { QByteArray data = "\r\nDISABLE_BUTTON\r\n"; bool success = serialTool->sendData(data); if (success) { qDebug() << "Data sent successfully"; } else { qDebug() << "Failed to send data"; } serialTool->releaseInstance(); CountdownWidget *countdownWidgetSelect = new CountdownWidget(this); countdownWidgetSelect->resize(200, 200); int x = (this->width() - countdownWidgetSelect->width()) / 2; int y = (this->height() - countdownWidgetSelect->height()) / 2; countdownWidgetSelect->move(x, y); countdownWidgetSelect->show(); connect(countdownWidgetSelect, &CountdownWidget::countdownFinished, this, &BlastOpePage::triggerBatchFiringBlast, Qt::SingleShotConnection); } void BlastOpePage::triggerBatchFiringBlast() { for (auto it = uuidWidgetSMap.begin(); it != uuidWidgetSMap.end(); ++it) { QString uuid = it.key(); firingWidget *widget = it.value(); QString topic = "hxgc/" + uuid + "/P"; QString message = "起爆"; widget->onCountdownFinished(topic, message); } } void BlastOpePage::destroyBatchFiringWidget(const QString &uuid, int row) { firingWidget *widget = uuidWidgetSMap.value(uuid); if (widget) { widget->close(); widget->deleteLater(); uuidWidgetSMap.remove(uuid); } // reset the table's row by row index 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; item->setFlags(flags); } } }