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.
155 lines
6.4 KiB
C++
155 lines
6.4 KiB
C++
#include "LogWindow.h"
|
||
|
||
#include <QHBoxLayout>
|
||
#include <QHeaderView>
|
||
#include <QPixmap>
|
||
#include <QResizeEvent>
|
||
#include <QScrollArea>
|
||
#include <QSplitter>
|
||
#include <QVBoxLayout>
|
||
|
||
#include "dao/AppLogDAO.h"
|
||
|
||
static constexpr int COL_ID = 0;
|
||
static constexpr int COL_TIME = 1;
|
||
static constexpr int COL_SOURCE = 2;
|
||
static constexpr int COL_DEVICE = 3;
|
||
static constexpr int COL_MESSAGE = 4;
|
||
|
||
LogWindow::LogWindow(QWidget *parent) : QDialog(parent) {
|
||
setWindowTitle("Логи ошибок");
|
||
resize(1100, 650);
|
||
|
||
// ── Таблица ───────────────────────────────────────────────────────────────
|
||
m_table = new QTableWidget(this);
|
||
m_table->setColumnCount(5);
|
||
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_SOURCE, 170);
|
||
m_table->setColumnWidth(COL_DEVICE, 120);
|
||
|
||
// ── Панель скриншота ──────────────────────────────────────────────────────
|
||
m_screenshotLabel = new QLabel("Выберите строку для просмотра скриншота");
|
||
m_screenshotLabel->setAlignment(Qt::AlignCenter);
|
||
m_screenshotLabel->setMinimumWidth(320);
|
||
m_screenshotLabel->setWordWrap(true);
|
||
m_screenshotLabel->setStyleSheet("background: #1a1a1a; color: #888; border-radius: 4px;");
|
||
|
||
auto *scrollArea = new QScrollArea(this);
|
||
scrollArea->setWidget(m_screenshotLabel);
|
||
scrollArea->setWidgetResizable(true);
|
||
scrollArea->setMinimumWidth(320);
|
||
|
||
// ── Сплиттер ─────────────────────────────────────────────────────────────
|
||
auto *splitter = new QSplitter(Qt::Horizontal, this);
|
||
splitter->addWidget(m_table);
|
||
splitter->addWidget(scrollArea);
|
||
splitter->setStretchFactor(0, 7);
|
||
splitter->setStretchFactor(1, 3);
|
||
|
||
// ── Пагинация ─────────────────────────────────────────────────────────────
|
||
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(splitter, 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::currentCellChanged, this,
|
||
[this](int row, int, int, int) {
|
||
if (row < 0) return;
|
||
const int logId = m_table->item(row, COL_ID)->text().toInt();
|
||
showScreenshot(logId);
|
||
});
|
||
|
||
loadPage();
|
||
}
|
||
|
||
void LogWindow::loadPage() {
|
||
const int total = AppLogDAO::getTotalCount();
|
||
m_totalPages = qMax(1, (total + m_pageSize - 1) / m_pageSize);
|
||
m_page = qBound(0, m_page, m_totalPages - 1);
|
||
|
||
const QList<AppLogEntry> entries = AppLogDAO::getLogs(m_page, m_pageSize);
|
||
|
||
m_table->setRowCount(static_cast<int>(entries.size()));
|
||
for (int i = 0; i < entries.size(); ++i) {
|
||
const auto &e = entries[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_SOURCE, new QTableWidgetItem(e.source));
|
||
m_table->setItem(i, COL_DEVICE, new QTableWidgetItem(e.deviceId));
|
||
m_table->setItem(i, COL_MESSAGE, new QTableWidgetItem(e.message));
|
||
}
|
||
|
||
// Сбрасываем скриншот при смене страницы
|
||
m_screenshotLabel->setPixmap({});
|
||
m_screenshotLabel->setText("Выберите строку для просмотра скриншота");
|
||
|
||
updatePagination();
|
||
}
|
||
|
||
void LogWindow::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);
|
||
}
|
||
|
||
void LogWindow::showScreenshot(int logId) {
|
||
const QByteArray bytes = AppLogDAO::getScreenshot(logId);
|
||
if (bytes.isEmpty()) {
|
||
m_originalPixmap = {};
|
||
m_screenshotLabel->setPixmap({});
|
||
m_screenshotLabel->setText("Скриншот отсутствует");
|
||
return;
|
||
}
|
||
if (!m_originalPixmap.loadFromData(bytes)) {
|
||
m_originalPixmap = {};
|
||
m_screenshotLabel->setText("Не удалось загрузить скриншот");
|
||
return;
|
||
}
|
||
rescaleScreenshot();
|
||
}
|
||
|
||
void LogWindow::rescaleScreenshot() {
|
||
if (m_originalPixmap.isNull()) return;
|
||
m_screenshotLabel->setPixmap(
|
||
m_originalPixmap.scaled(m_screenshotLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)
|
||
);
|
||
}
|
||
|
||
void LogWindow::resizeEvent(QResizeEvent *event) {
|
||
QDialog::resizeEvent(event);
|
||
rescaleScreenshot();
|
||
}
|