1
0
forked from BRT/arc
arc/views/event/EventWindow.cpp
slava 832fb03aac Add EventWindow, database migrations, and enhanced DAO methods
Implemented `EventWindow` for viewing events with pagination and table-based UI. Added database migration to remove `UNIQUE` constraint on `external_id` in `events`. Enhanced DAO methods for event retrieval, pagination, and transaction updates. Integrated OCR recognition in transaction scripts and streamlined event handling in services.
2026-03-04 22:56:47 +07:00

182 lines
7.9 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "EventWindow.h"
#include <QHBoxLayout>
#include <QHeaderView>
#include <QJsonDocument>
#include <QJsonObject>
#include <QThread>
#include <QVBoxLayout>
#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_ACTION = 8;
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(1100, 600);
// ── Таблица ───────────────────────────────────────────────────────────────
m_table = new QTableWidget(this);
m_table->setColumnCount(9);
m_table->setHorizontalHeaderLabels({
"#", "Время", "Тип", "Банк", "Устройство", "Статус", "Сумма", "Комментарий", ""
});
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_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();
});
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<EventInfo> events = EventDAO::getEvents(m_page, m_pageSize);
m_table->setRowCount(static_cast<int>(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));
// Подсветка строки по статусу
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);
}