1
0
forked from BRT/arc
arc/views/event/EventWindow.cpp
trnsmkot 04025aa32b Add database migration, DAO enhancements, and OCR-based transaction handling updates
Implemented database migration for adding new fields (`json`, `sent_to_server`) in `events` table. Updated DAO methods to support the new fields and introduced `markSentToServer`. Enhanced Ozon transaction workflows with OCR-based extraction, event error handling improvements, and result reporting. Refactored `EventHandler` for streamlined task processing and stale event cleanup.
2026-03-08 14:20:12 +07:00

212 lines
9.1 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 <QDialog>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QJsonDocument>
#include <QJsonObject>
#include <QPlainTextEdit>
#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_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<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));
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);
}