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
9848b1b371
commit
f8fa93a6d9
@ -74,3 +74,35 @@ QList<AccountInfo> AccountDAO::getAccounts(const QString &deviceId, const QStrin
|
||||
|
||||
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 QList<AccountInfo> getAccounts(const QString &deviceId, const QString &appName);
|
||||
|
||||
[[nodiscard]] static AccountInfo getAccountById(int accountId);
|
||||
};
|
||||
|
||||
@ -4,12 +4,19 @@
|
||||
#include "DatabaseManager.h"
|
||||
#include "db/DeviceInfo.h"
|
||||
|
||||
QList<DeviceInfo> DeviceDAO::getAllDevices() {
|
||||
QList<DeviceInfo> DeviceDAO::getAllDevices(const bool online) {
|
||||
QList<DeviceInfo> devices;
|
||||
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
query.prepare(
|
||||
"SELECT id, status, name, android, screen_width, screen_height, battery, update_time, image FROM devices WHERE image IS NOT NULL AND status = 'device'");
|
||||
QString sql = R"(
|
||||
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()) {
|
||||
qWarning() << "Ошибка при получении списка устройств:" << query.lastError().text();
|
||||
|
||||
@ -10,5 +10,5 @@ public:
|
||||
|
||||
[[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 "AccountWindow.h"
|
||||
|
||||
#include <QLabel>
|
||||
#include <QScrollArea>
|
||||
#include <QMenuBar>
|
||||
#include <QStackedWidget>
|
||||
|
||||
#include "db/DeviceInfo.h"
|
||||
#include "DeviceWidget.h"
|
||||
@ -10,64 +12,102 @@
|
||||
#include "widget/FlowLayout.h"
|
||||
|
||||
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);
|
||||
auto* contentWidget = new QWidget;
|
||||
flowLayout = new FlowLayout(contentWidget);
|
||||
stackedWidget = new QStackedWidget(this);
|
||||
setCentralWidget(stackedWidget);
|
||||
|
||||
createDevicePage();
|
||||
stackedWidget->addWidget(devicePage);
|
||||
// stackedWidget->setCurrentWidget(devicePage); FIXME
|
||||
|
||||
|
||||
contentWidget->setContentsMargins(0, 0, 0, 0); // Убираем отступы у контейнера
|
||||
flowLayout->setContentsMargins(0, 0, 0, 0); // Убираем отступы у layout
|
||||
flowLayout->setSpacing(0);
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
// FIXME переделать на ленивое создание
|
||||
accountPage = new AccountWindow(this);
|
||||
stackedWidget->addWidget(accountPage);
|
||||
stackedWidget->setCurrentWidget(accountPage);
|
||||
|
||||
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);
|
||||
scrollArea->setWidget(contentWidget);
|
||||
scrollArea->setWidgetResizable(true);
|
||||
setCentralWidget(scrollArea);
|
||||
|
||||
// Меню
|
||||
QMenu* menu = menuBar()->addMenu("Навигация");
|
||||
devicePage = scrollArea;
|
||||
stackedWidget->addWidget(devicePage);
|
||||
|
||||
QAction* actionPage1 = new QAction("Окно 1", this);
|
||||
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 сек
|
||||
timer->start(1000);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::loadDevices() const {
|
||||
const auto devices = DeviceDAO::getAllDevices();
|
||||
|
||||
// Очистить старые виджеты
|
||||
QLayoutItem* item;
|
||||
while ((item = flowLayout->takeAt(0)) != nullptr) {
|
||||
delete item->widget(); // Удаляем виджет
|
||||
delete item; // Удаляем сам элемент из layout
|
||||
void MainWindow::deleteDevicePage() {
|
||||
if (!devicePage) {
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <QMainWindow>
|
||||
#include <QVBoxLayout>
|
||||
#include <QStackedWidget>
|
||||
#include <QTimer>
|
||||
#include "db/DeviceInfo.h"
|
||||
#include "widget/FlowLayout.h"
|
||||
@ -9,10 +10,17 @@ class MainWindow final : public QMainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
void loadDevices() const;
|
||||
void loadDevices();
|
||||
|
||||
private:
|
||||
QWidget* central;
|
||||
FlowLayout* flowLayout;
|
||||
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