Implement AccountWindow and TransactionWindow for account management
Added AccountWindow to display account tables linked to devices and TransactionWindow for viewing account details. Enhanced DeviceDAO and AccountDAO to support additional filtering and data retrieval functionalities.
This commit is contained in:
parent
c1b8d0c23c
commit
c1b34ce7d7
@ -74,3 +74,35 @@ QList<AccountInfo> AccountDAO::getAccounts(const QString &deviceId, const QStrin
|
|||||||
|
|
||||||
return accounts;
|
return accounts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AccountInfo AccountDAO::getAccountById(const int accountId) {
|
||||||
|
AccountInfo acc;
|
||||||
|
QSqlQuery query(DatabaseManager::instance().database());
|
||||||
|
|
||||||
|
query.prepare(R"(
|
||||||
|
SELECT id, device_id, app_name, card_name, amount, update_time, status, description
|
||||||
|
FROM accounts
|
||||||
|
WHERE id = :id
|
||||||
|
LIMIT 1
|
||||||
|
)");
|
||||||
|
|
||||||
|
query.bindValue(":id", accountId);
|
||||||
|
|
||||||
|
if (!query.exec()) {
|
||||||
|
qWarning() << "Ошибка при получении account по ID:" << query.lastError().text();
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.next()) {
|
||||||
|
acc.id = query.value("id").toInt();
|
||||||
|
acc.deviceId = query.value("device_id").toString();
|
||||||
|
acc.appName = query.value("app_name").toString();
|
||||||
|
acc.cardName = query.value("card_name").toString();
|
||||||
|
acc.amount = query.value("amount").toDouble();
|
||||||
|
acc.updateTime = QDateTime::fromString(query.value("update_time").toString(), Qt::ISODate);
|
||||||
|
acc.status = query.value("status").toString();
|
||||||
|
acc.description = query.value("description").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|||||||
@ -8,4 +8,6 @@ public:
|
|||||||
[[nodiscard]] static bool deleteAccount(int id);
|
[[nodiscard]] static bool deleteAccount(int id);
|
||||||
|
|
||||||
[[nodiscard]] static QList<AccountInfo> getAccounts(const QString &deviceId, const QString &appName);
|
[[nodiscard]] static QList<AccountInfo> getAccounts(const QString &deviceId, const QString &appName);
|
||||||
|
|
||||||
|
[[nodiscard]] static AccountInfo getAccountById(int accountId);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,12 +4,19 @@
|
|||||||
#include "DatabaseManager.h"
|
#include "DatabaseManager.h"
|
||||||
#include "db/DeviceInfo.h"
|
#include "db/DeviceInfo.h"
|
||||||
|
|
||||||
QList<DeviceInfo> DeviceDAO::getAllDevices() {
|
QList<DeviceInfo> DeviceDAO::getAllDevices(const bool online) {
|
||||||
QList<DeviceInfo> devices;
|
QList<DeviceInfo> devices;
|
||||||
|
|
||||||
QSqlQuery query(DatabaseManager::instance().database());
|
QSqlQuery query(DatabaseManager::instance().database());
|
||||||
query.prepare(
|
QString sql = R"(
|
||||||
"SELECT id, status, name, android, screen_width, screen_height, battery, update_time, image FROM devices WHERE image IS NOT NULL AND status = 'device'");
|
SELECT id, status, name, android, screen_width, screen_height, battery, update_time, image
|
||||||
|
FROM devices
|
||||||
|
WHERE image IS NOT NULL
|
||||||
|
)";
|
||||||
|
if (online) {
|
||||||
|
sql += " AND status = 'device'";
|
||||||
|
}
|
||||||
|
query.prepare(sql);
|
||||||
|
|
||||||
if (!query.exec()) {
|
if (!query.exec()) {
|
||||||
qWarning() << "Ошибка при получении списка устройств:" << query.lastError().text();
|
qWarning() << "Ошибка при получении списка устройств:" << query.lastError().text();
|
||||||
|
|||||||
@ -10,5 +10,5 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]] static bool updateImage(const QString &deviceId, const QByteArray &imageData);
|
[[nodiscard]] static bool updateImage(const QString &deviceId, const QByteArray &imageData);
|
||||||
|
|
||||||
[[nodiscard]] static QList<DeviceInfo> getAllDevices();
|
[[nodiscard]] static QList<DeviceInfo> getAllDevices(bool online);
|
||||||
};
|
};
|
||||||
|
|||||||
100
views/AccountWindow.cpp
Normal file
100
views/AccountWindow.cpp
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#include "AccountWindow.h"
|
||||||
|
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QTableWidget>
|
||||||
|
#include <QHeaderView>
|
||||||
|
#include <QScrollArea>
|
||||||
|
|
||||||
|
#include "TransactionWindow.h"
|
||||||
|
#include "dao/AccountDAO.h"
|
||||||
|
#include "dao/DeviceDAO.h"
|
||||||
|
|
||||||
|
AccountWindow::AccountWindow(QWidget *parent): QWidget(parent) {
|
||||||
|
auto *mainLayout = new QVBoxLayout(this);
|
||||||
|
|
||||||
|
// Скролл-область
|
||||||
|
auto *scrollArea = new QScrollArea(this);
|
||||||
|
scrollArea->setWidgetResizable(true);
|
||||||
|
|
||||||
|
// Виджет-контейнер, в котором будет layout с таблицами и лейблами
|
||||||
|
auto *contentWidget = new QWidget;
|
||||||
|
auto *layout = new QVBoxLayout(contentWidget);
|
||||||
|
|
||||||
|
// Убираем отступы и рамку
|
||||||
|
contentWidget->setContentsMargins(0, 0, 0, 0); // Убираем отступы
|
||||||
|
layout->setContentsMargins(0, 0, 0, 0); // Убираем отступы у layout
|
||||||
|
scrollArea->setStyleSheet("border: none;"); // Убираем рамку
|
||||||
|
layout->setAlignment(Qt::AlignTop);
|
||||||
|
|
||||||
|
QList<DeviceInfo> devices = DeviceDAO::getAllDevices(false);
|
||||||
|
for (int i = 0; i < devices.size(); ++i) {
|
||||||
|
DeviceInfo device = devices[i];
|
||||||
|
QList<AccountInfo> accounts = AccountDAO::getAccounts(device.id, "bank");
|
||||||
|
// Текст перед первой таблицей
|
||||||
|
QString title = QString("%1 [%2] | %3").arg(device.name, device.id, device.status);
|
||||||
|
QLabel *label = new QLabel(title, this);
|
||||||
|
layout->addWidget(label);
|
||||||
|
|
||||||
|
if (accounts.length() > 0) {
|
||||||
|
QTableWidget *tableWidget = new QTableWidget(this);
|
||||||
|
tableWidget->setStyleSheet("QTableWidget {"
|
||||||
|
"border: 1px solid grey;"
|
||||||
|
"}");
|
||||||
|
|
||||||
|
tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
|
connect(tableWidget, &QTableWidget::itemDoubleClicked, this, &AccountWindow::onItemDoubleClicked);
|
||||||
|
|
||||||
|
tableWidget->setRowCount(accounts.length()); // Устанавливаем количество строк
|
||||||
|
tableWidget->setColumnCount(5); // Устанавливаем количество столбцов
|
||||||
|
tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
|
||||||
|
tableWidget->setHorizontalHeaderLabels({"Карта", "Сумма", "Время обновления", "Описание", "Статус"});
|
||||||
|
tableWidget->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||||
|
int totalHeight = tableWidget->horizontalHeader()->height();
|
||||||
|
|
||||||
|
|
||||||
|
for (int k = 0; k < accounts.size(); ++k) {
|
||||||
|
AccountInfo account = accounts[k];
|
||||||
|
QTableWidgetItem *item = new QTableWidgetItem("*" + account.cardName);
|
||||||
|
item->setData(Qt::UserRole, account.id);
|
||||||
|
tableWidget->setItem(k, 0, item);
|
||||||
|
tableWidget->setItem(k, 1, new QTableWidgetItem(QString::number(account.amount)));
|
||||||
|
tableWidget->setItem(k, 2, new QTableWidgetItem(account.updateTime.toString("dd.MM.yyyy HH:mm:ss")));
|
||||||
|
tableWidget->setItem(k, 3, new QTableWidgetItem(account.description));
|
||||||
|
tableWidget->setItem(k, 4, new QTableWidgetItem(account.status));
|
||||||
|
totalHeight += tableWidget->rowHeight(k);
|
||||||
|
}
|
||||||
|
tableWidget->setFixedHeight(totalHeight + 2);
|
||||||
|
layout->addWidget(tableWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < devices.size() - 1) {
|
||||||
|
QFrame *separator = new QFrame(this);
|
||||||
|
separator->setFrameShape(QFrame::VLine);
|
||||||
|
separator->setStyleSheet("background-color: black;"); // Цвет разделителя
|
||||||
|
separator->setFixedHeight(1);
|
||||||
|
separator->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
layout->addWidget(separator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавим вертикальный Spacer в конец, чтобы прокручиваемая область не растягивала контент
|
||||||
|
QSpacerItem *spacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||||
|
layout->addItem(spacer);
|
||||||
|
|
||||||
|
contentWidget->setLayout(layout);
|
||||||
|
scrollArea->setWidget(contentWidget);
|
||||||
|
mainLayout->addWidget(scrollArea);
|
||||||
|
setLayout(mainLayout);
|
||||||
|
setWindowTitle("Таблица устройств");
|
||||||
|
}
|
||||||
|
|
||||||
|
void AccountWindow::onItemDoubleClicked(QTableWidgetItem *item) {
|
||||||
|
int column = item->column();
|
||||||
|
if (column == 0) {
|
||||||
|
int accountId = item->data(Qt::UserRole).toInt();
|
||||||
|
qDebug() << accountId;
|
||||||
|
TransactionWindow *detailWindow = new TransactionWindow(accountId, this);
|
||||||
|
detailWindow->exec(); // Ожидаем закрытия окна
|
||||||
|
}
|
||||||
|
}
|
||||||
14
views/AccountWindow.h
Normal file
14
views/AccountWindow.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qtablewidget.h>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class AccountWindow final : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit AccountWindow(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onItemDoubleClicked(QTableWidgetItem *item);
|
||||||
|
};
|
||||||
@ -1,8 +1,10 @@
|
|||||||
#include "MainWindow.h"
|
#include "MainWindow.h"
|
||||||
|
#include "AccountWindow.h"
|
||||||
|
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QMenuBar>
|
#include <QMenuBar>
|
||||||
|
#include <QStackedWidget>
|
||||||
|
|
||||||
#include "db/DeviceInfo.h"
|
#include "db/DeviceInfo.h"
|
||||||
#include "DeviceWidget.h"
|
#include "DeviceWidget.h"
|
||||||
@ -10,64 +12,102 @@
|
|||||||
#include "widget/FlowLayout.h"
|
#include "widget/FlowLayout.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
|
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) {
|
||||||
// QPushButton* btn = new QPushButton("Hello Qt6!", this);
|
// Инициализируем таймер обновления
|
||||||
// setCentralWidget(btn);
|
timer = new QTimer(this);
|
||||||
|
connect(timer, &QTimer::timeout, this, &MainWindow::loadDevices);
|
||||||
|
|
||||||
auto* scrollArea = new QScrollArea(this);
|
stackedWidget = new QStackedWidget(this);
|
||||||
auto* contentWidget = new QWidget;
|
setCentralWidget(stackedWidget);
|
||||||
flowLayout = new FlowLayout(contentWidget);
|
|
||||||
|
|
||||||
|
createDevicePage();
|
||||||
|
stackedWidget->addWidget(devicePage);
|
||||||
|
// stackedWidget->setCurrentWidget(devicePage); FIXME
|
||||||
|
|
||||||
|
// FIXME переделать на ленивое создание
|
||||||
contentWidget->setContentsMargins(0, 0, 0, 0); // Убираем отступы у контейнера
|
accountPage = new AccountWindow(this);
|
||||||
flowLayout->setContentsMargins(0, 0, 0, 0); // Убираем отступы у layout
|
stackedWidget->addWidget(accountPage);
|
||||||
flowLayout->setSpacing(0);
|
stackedWidget->setCurrentWidget(accountPage);
|
||||||
|
|
||||||
|
|
||||||
QVector<DeviceInfo> devices = DeviceDAO::getAllDevices();
|
|
||||||
for (const auto& device : devices) {
|
|
||||||
auto* deviceWidget = new DeviceWidget(device); // Создаем виджет, используя первый элемент из списка devices
|
|
||||||
deviceWidget->setFixedWidth(220);
|
|
||||||
deviceWidget->setFixedHeight(400);
|
|
||||||
|
|
||||||
deviceWidget->setContentsMargins(0, 0, 0, 0);
|
|
||||||
flowLayout->addWidget(deviceWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
resize(800, 600);
|
resize(800, 600);
|
||||||
|
|
||||||
|
// Работа с меню
|
||||||
|
QMenu *menu = menuBar()->addMenu("Меню");
|
||||||
|
auto *devicesPageAction = new QAction("Активные устройства", this);
|
||||||
|
auto *accountPageAction = new QAction("Аккаунты", this);
|
||||||
|
menu->addAction(devicesPageAction);
|
||||||
|
menu->addAction(accountPageAction);
|
||||||
|
|
||||||
|
connect(devicesPageAction, &QAction::triggered, this, [=]() {
|
||||||
|
if (!devicePage) {
|
||||||
|
createDevicePage();
|
||||||
|
}
|
||||||
|
stackedWidget->setCurrentWidget(devicePage);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(accountPageAction, &QAction::triggered, this, [=]() {
|
||||||
|
stackedWidget->setCurrentWidget(accountPage);
|
||||||
|
deleteDevicePage(); // освобождаем ресурсы
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MainWindow::createDevicePage() {
|
||||||
|
if (devicePage) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *scrollArea = new QScrollArea(this);
|
||||||
|
auto *contentWidget = new QWidget;
|
||||||
|
flowLayout = new FlowLayout(contentWidget);
|
||||||
|
flowLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
flowLayout->setSpacing(0);
|
||||||
|
|
||||||
|
QVector<DeviceInfo> devices = DeviceDAO::getAllDevices(true);
|
||||||
|
for (const auto &device: devices) {
|
||||||
|
auto *deviceWidget = new DeviceWidget(device);
|
||||||
|
deviceWidget->setFixedSize(220, 400);
|
||||||
|
flowLayout->addWidget(deviceWidget);
|
||||||
|
}
|
||||||
|
|
||||||
contentWidget->setLayout(flowLayout);
|
contentWidget->setLayout(flowLayout);
|
||||||
scrollArea->setWidget(contentWidget);
|
scrollArea->setWidget(contentWidget);
|
||||||
scrollArea->setWidgetResizable(true);
|
scrollArea->setWidgetResizable(true);
|
||||||
setCentralWidget(scrollArea);
|
|
||||||
|
|
||||||
// Меню
|
devicePage = scrollArea;
|
||||||
QMenu* menu = menuBar()->addMenu("Навигация");
|
stackedWidget->addWidget(devicePage);
|
||||||
|
|
||||||
QAction* actionPage1 = new QAction("Окно 1", this);
|
timer->start(1000);
|
||||||
QAction* actionPage2 = new QAction("Окно 2", this);
|
|
||||||
|
|
||||||
menu->addAction(actionPage1);
|
|
||||||
menu->addAction(actionPage2);
|
|
||||||
|
|
||||||
timer = new QTimer(this);
|
|
||||||
connect(timer, &QTimer::timeout, this, &MainWindow::loadDevices);
|
|
||||||
timer->start(1000); // каждые 1 сек
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::deleteDevicePage() {
|
||||||
void MainWindow::loadDevices() const {
|
if (!devicePage) {
|
||||||
const auto devices = DeviceDAO::getAllDevices();
|
return;
|
||||||
|
|
||||||
// Очистить старые виджеты
|
|
||||||
QLayoutItem* item;
|
|
||||||
while ((item = flowLayout->takeAt(0)) != nullptr) {
|
|
||||||
delete item->widget(); // Удаляем виджет
|
|
||||||
delete item; // Удаляем сам элемент из layout
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timer->stop();
|
||||||
|
|
||||||
|
stackedWidget->removeWidget(devicePage);
|
||||||
|
devicePage->deleteLater();
|
||||||
|
devicePage = nullptr;
|
||||||
|
flowLayout = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Однако, в нем вы вызываете delete для элементов, что изменяет память.
|
||||||
|
* Для того, чтобы не нарушать константность, этот метод должен быть неконстантным (без const в сигнатуре).
|
||||||
|
*/
|
||||||
|
void MainWindow::loadDevices() {
|
||||||
|
const auto devices = DeviceDAO::getAllDevices(true);
|
||||||
|
// Очистить старые виджеты
|
||||||
|
QLayoutItem *item;
|
||||||
|
while ((item = flowLayout->takeAt(0)) != nullptr) {
|
||||||
|
if (item->widget()) {
|
||||||
|
delete item->widget(); // Удаляем виджет
|
||||||
|
}
|
||||||
|
delete item; // Удаляем сам элемент из layout
|
||||||
|
}
|
||||||
// Добавляем новые виджеты для каждого устройства
|
// Добавляем новые виджеты для каждого устройства
|
||||||
for (const auto& device : devices) {
|
for (const auto &device: devices) {
|
||||||
flowLayout->addWidget(new DeviceWidget(device));
|
flowLayout->addWidget(new DeviceWidget(device));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <QMainWindow>
|
#include <QMainWindow>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
#include <QStackedWidget>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include "db/DeviceInfo.h"
|
#include "db/DeviceInfo.h"
|
||||||
#include "widget/FlowLayout.h"
|
#include "widget/FlowLayout.h"
|
||||||
@ -9,10 +10,17 @@ class MainWindow final : public QMainWindow {
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit MainWindow(QWidget *parent = nullptr);
|
explicit MainWindow(QWidget *parent = nullptr);
|
||||||
void loadDevices() const;
|
void loadDevices();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QWidget* central;
|
QWidget* central;
|
||||||
FlowLayout* flowLayout;
|
FlowLayout* flowLayout;
|
||||||
QTimer* timer;
|
QTimer* timer;
|
||||||
|
QStackedWidget* stackedWidget;
|
||||||
|
|
||||||
|
QWidget* devicePage = nullptr;
|
||||||
|
QWidget* accountPage = nullptr;
|
||||||
|
|
||||||
|
void createDevicePage();
|
||||||
|
void deleteDevicePage();
|
||||||
};
|
};
|
||||||
|
|||||||
21
views/TransactionWindow.cpp
Normal file
21
views/TransactionWindow.cpp
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include "TransactionWindow.h"
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
#include "dao/AccountDAO.h"
|
||||||
|
|
||||||
|
TransactionWindow::TransactionWindow(const int accountId, QWidget *parent): QDialog(parent) {
|
||||||
|
setWindowTitle("Транзакции");
|
||||||
|
setMinimumSize(300, 200); // минимальный размер
|
||||||
|
setMaximumSize(800, 400); // максимальный размер
|
||||||
|
|
||||||
|
auto *layout = new QVBoxLayout(this);
|
||||||
|
layout->setAlignment(Qt::AlignCenter);
|
||||||
|
|
||||||
|
AccountInfo account = AccountDAO::getAccountById(accountId);
|
||||||
|
|
||||||
|
QLabel *label = new QLabel(QString("*%1 | %2").arg(account.cardName, account.description), this);
|
||||||
|
layout->addWidget(label);
|
||||||
|
|
||||||
|
setModal(true);
|
||||||
|
}
|
||||||
10
views/TransactionWindow.h
Normal file
10
views/TransactionWindow.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
class TransactionWindow final : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TransactionWindow(int accountId, QWidget *parent = nullptr);
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user