#include "EventWindow.h" #include #include #include #include #include #include #include #include #include "dao/EventDAO.h" #include "net/NetworkService.h" static constexpr int COL_ID = 0; static constexpr int COL_TIME = 1; static constexpr int COL_TYPE = 2; static constexpr int COL_BANK = 3; static constexpr int COL_DEVICE = 4; static constexpr int COL_STATUS = 5; static constexpr int COL_AMOUNT = 6; static constexpr int COL_COMMENT = 7; static constexpr int COL_JSON = 8; static constexpr int COL_SENT = 9; static constexpr int COL_ACTION = 10; static void sendErrorToServer(const QString &type, const QString &materialId, const QString &bankName) { QJsonObject errData; errData["status"] = "error"; errData["description"] = "Closed manually"; QJsonObject obj; obj["type"] = type; obj["material_id"] = materialId; obj["bank_name"] = bankName; obj["data"] = errData; auto *thread = new QThread; auto *networkService = new NetworkService; networkService->moveToThread(thread); networkService->setPayload(QJsonDocument(obj).toJson()); QObject::connect(thread, &QThread::started, networkService, &NetworkService::postTaskResult); QObject::connect(networkService, &NetworkService::finished, thread, &QThread::quit); QObject::connect(networkService, &NetworkService::finished, networkService, &QObject::deleteLater); QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater); thread->start(); } static QString statusDisplayName(EventStatus s) { switch (s) { case EventStatus::Wait: return "Ожидание"; case EventStatus::InProgress: return "В работе"; case EventStatus::Complete: return "Завершено"; case EventStatus::Error: return "Ошибка"; default: return "—"; } } static QString typeDisplayName(EventType t) { switch (t) { case EventType::FetchProfile: return "Профиль"; case EventType::FetchTransactions: return "Транзакции"; case EventType::CreateTransaction: return "Платёж"; default: return "—"; } } EventWindow::EventWindow(QWidget *parent) : QDialog(parent) { setWindowTitle("События"); resize(1400, 600); // ── Таблица ─────────────────────────────────────────────────────────────── m_table = new QTableWidget(this); m_table->setColumnCount(11); m_table->setHorizontalHeaderLabels({ "#", "Время", "Тип", "Банк", "Устройство", "Статус", "Сумма", "Комментарий", "JSON", "Отпр.", "" }); m_table->setEditTriggers(QAbstractItemView::NoEditTriggers); m_table->setSelectionBehavior(QAbstractItemView::SelectRows); m_table->setSelectionMode(QAbstractItemView::SingleSelection); m_table->verticalHeader()->hide(); m_table->horizontalHeader()->setStretchLastSection(true); m_table->setColumnWidth(COL_ID, 45); m_table->setColumnWidth(COL_TIME, 145); m_table->setColumnWidth(COL_TYPE, 100); m_table->setColumnWidth(COL_BANK, 90); m_table->setColumnWidth(COL_DEVICE, 120); m_table->setColumnWidth(COL_STATUS, 100); m_table->setColumnWidth(COL_AMOUNT, 80); m_table->setColumnWidth(COL_JSON, 200); m_table->setColumnWidth(COL_SENT, 45); m_table->setColumnWidth(COL_ACTION, 80); // ── Пагинация ───────────────────────────────────────────────────────────── m_prevBtn = new QPushButton("←", this); m_nextBtn = new QPushButton("→", this); m_pageLabel = new QLabel(this); m_pageLabel->setAlignment(Qt::AlignCenter); m_pageLabel->setMinimumWidth(140); auto *refreshBtn = new QPushButton("Обновить", this); auto *paginationLayout = new QHBoxLayout; paginationLayout->addWidget(m_prevBtn); paginationLayout->addWidget(m_pageLabel); paginationLayout->addWidget(m_nextBtn); paginationLayout->addStretch(); paginationLayout->addWidget(refreshBtn); auto *mainLayout = new QVBoxLayout(this); mainLayout->addWidget(m_table, 1); mainLayout->addLayout(paginationLayout); // ── Сигналы ─────────────────────────────────────────────────────────────── connect(m_prevBtn, &QPushButton::clicked, this, [this]() { if (m_page > 0) { --m_page; loadPage(); } }); connect(m_nextBtn, &QPushButton::clicked, this, [this]() { if (m_page < m_totalPages - 1) { ++m_page; loadPage(); } }); connect(refreshBtn, &QPushButton::clicked, this, [this]() { m_page = 0; loadPage(); }); connect(m_table, &QTableWidget::cellDoubleClicked, this, [this](int row, int col) { if (col != COL_JSON) return; auto *item = m_table->item(row, col); if (!item) return; const QString json = item->toolTip(); if (json.isEmpty()) return; auto *dlg = new QDialog(this); dlg->setWindowTitle("JSON"); dlg->resize(600, 400); auto *edit = new QPlainTextEdit(dlg); edit->setReadOnly(true); edit->setPlainText(QJsonDocument::fromJson(json.toUtf8()).toJson(QJsonDocument::Indented)); auto *layout = new QVBoxLayout(dlg); layout->addWidget(edit); dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->show(); }); loadPage(); } void EventWindow::loadPage() { const int total = EventDAO::getTotalCount(); m_totalPages = qMax(1, (total + m_pageSize - 1) / m_pageSize); m_page = qBound(0, m_page, m_totalPages - 1); const QList events = EventDAO::getEvents(m_page, m_pageSize); m_table->setRowCount(static_cast(events.size())); for (int i = 0; i < events.size(); ++i) { const auto &e = events[i]; m_table->setItem(i, COL_ID, new QTableWidgetItem(QString::number(e.id))); m_table->setItem(i, COL_TIME, new QTableWidgetItem( e.timestamp.toLocalTime().toString("dd.MM.yy HH:mm:ss"))); m_table->setItem(i, COL_TYPE, new QTableWidgetItem(typeDisplayName(e.type))); m_table->setItem(i, COL_BANK, new QTableWidgetItem(e.bankName)); m_table->setItem(i, COL_DEVICE, new QTableWidgetItem(e.deviceId)); m_table->setItem(i, COL_STATUS, new QTableWidgetItem(statusDisplayName(e.status))); m_table->setItem(i, COL_AMOUNT, new QTableWidgetItem( e.amount > 0 ? QString::number(e.amount, 'f', 2) : "—")); m_table->setItem(i, COL_COMMENT, new QTableWidgetItem(e.comment)); auto *jsonItem = new QTableWidgetItem(e.json.left(80)); jsonItem->setToolTip(e.json); m_table->setItem(i, COL_JSON, jsonItem); m_table->setItem(i, COL_SENT, new QTableWidgetItem(e.sentToServer ? "+" : "")); // Подсветка строки по статусу QColor bg; switch (e.status) { case EventStatus::Error: bg = QColor(255, 230, 230); break; case EventStatus::Complete: bg = QColor(230, 255, 230); break; case EventStatus::InProgress: bg = QColor(230, 240, 255); break; default: bg = QColor(255, 255, 230); break; } for (int col = 0; col < m_table->columnCount(); ++col) { if (auto *item = m_table->item(i, col)) item->setBackground(bg); } // Кнопка "Закрыть" только для активных задач if (e.status == EventStatus::Wait || e.status == EventStatus::InProgress) { auto *closeBtn = new QPushButton("Закрыть"); closeBtn->setStyleSheet("background: #e74c3c; color: white; border: none; padding: 3px 8px; border-radius: 3px;"); const int eventId = e.id; const QString externalId = e.externalId; const QString bankName = e.bankName; const QString typeStr = eventTypeToString(e.type); connect(closeBtn, &QPushButton::clicked, this, [this, eventId, externalId, bankName, typeStr]() { EventDAO::updateEvent(eventId, EventStatus::Error, "Closed manually"); sendErrorToServer(typeStr, externalId, bankName); loadPage(); }); m_table->setCellWidget(i, COL_ACTION, closeBtn); } } updatePagination(); } void EventWindow::updatePagination() { m_pageLabel->setText(QString("Страница %1 из %2").arg(m_page + 1).arg(m_totalPages)); m_prevBtn->setEnabled(m_page > 0); m_nextBtn->setEnabled(m_page < m_totalPages - 1); }