2024-08-03 00:49:42 +08:00

514 lines
18 KiB
C++
Raw Permalink 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 "mainwindow.h"
#include "ui_mainwindow.h"
/**
* @brief 切换到查询页面
* 点击工具栏的“查询”触发
* @param void
* @return void
* @author 柯劲帆
* @date 2024-07-31
*/
void MainWindow::on_QueryAction_triggered()
{
queryPageInitContent();
ui->stackedWidget->setCurrentWidget(ui->queryPage);
}
/**
* @brief 读卡器扫描卡片
* 点击查询页面的“查询”触发。
* 如果读卡器未连接,显示警告信息并跳转到设置页面。
* 显示Inventory的查询结果最多显示10张卡。
* @param void
* @return void
* @author 柯劲帆
* @date 2024-07-31
*/
void MainWindow::on_queryInventoryButton_clicked()
{
if (!reader.is_connected())
{
QMessageBox::warning(this, QString("提示"), QString("读卡器未连接,请设置。"));
if (ui->stackedWidget->currentWidget() != ui->settingPage)
{
ui->stackedWidget->setCurrentWidget(ui->settingPage);
}
return;
}
QStringList cardIdList = reader.inventory(10); // 最多显示10张卡
ui->queryCardIdBox->clear();
if (cardIdList.empty())
{
QMessageBox::warning(this, "提示", "未发现卡片,请将卡片放置于读卡器上方。");
}
else
{
ui->queryCardIdBox->addItems(cardIdList);
}
}
/**
* @brief 用户选择卡片查询记录
* 该函数在用户点击“查询”按钮时触发用于根据选择的卡片ID查询该卡片的所有交易记录。
* @param void
* @return void
* @details
* 函数首先检查数据库是否已连接。如果数据库未连接,函数将显示警告信息并返回。
* 接着,函数检查是否选择了卡片。如果未选择卡片,函数将显示警告信息并返回。
* 然后函数会查询卡片的绑定用户信息包括用户ID、卡片状态和余额。如果卡片未被启用或已挂失函数将显示相应的警告信息并返回。
* 在查询卡片信息成功后,函数会要求进行用户身份验证。如果验证失败,函数将显示警告信息并返回,并重置查询页面。
* 如果验证成功,函数会查询该卡片的所有交易记录,并将这些记录转换为 `QStringList` 后显示在界面的表格中。
* @author 柯劲帆
* @date 2024-07-31
*/
void MainWindow::on_userRecordQueryButton_clicked()
{
if (!databaseReady())
{
QMessageBox::warning(this, QString("提示"), QString("数据库未连接,请设置。"));
if (ui->stackedWidget->currentWidget() != ui->settingPage)
{
ui->stackedWidget->setCurrentWidget(ui->settingPage);
}
return;
}
if (ui->queryCardIdBox->currentIndex() == -1)
{
QMessageBox::warning(this, "提示", "请放置卡片并点击查询按钮。");
return;
}
QString cardId = ui->queryCardIdBox->currentText();
int userId;
int cardStatus;
double balance;
// 检查和获取绑定用户
QSqlQuery query(db->getDatabase());
query.prepare(QString("select userId, `status`, balance from card "
"where id = :cardId;"));
query.bindValue(":cardId", cardId);
bool success = false;
success = query.exec();
if (!success)
{
QMessageBox::warning(this, QString("提示"), QString("数据库异常。查询失败。"));
queryPageInitContent();
return;
}
if (query.next()) // 卡已被注册获取用户ID
{
cardStatus = query.value("status").toInt();
if (cardStatus == 0)
{
QMessageBox::warning(this, QString("提示"), QString("此卡未被启用。"));
queryPageInitContent();
return;
}
if (cardStatus == -1)
{
ui->queryCardStatusLabel->setText(QString("已被挂失"));
}
if (cardStatus == 1)
{
ui->queryCardStatusLabel->setText(QString("启用中"));
}
userId = query.value("userId").toInt();
balance = query.value("balance").toDouble();
ui->queryBalanceShowEdit->setText(QString::number(balance, 'f', 2));
}
else // 卡没有注册
{
query.finish();
query.prepare(QString("insert into card "
"values (:cardId, 0, 0.0, null);"));
query.bindValue(":cardId", cardId);
success = query.exec();
if (!success)
{
QMessageBox::warning(this, QString("提示"), QString("数据库异常。查询失败。"));
queryPageInitContent();
return;
}
QMessageBox::warning(this, QString("提示"), QString("此卡未被启用。"));
queryPageInitContent();
return;
}
QString prompt = "查询用户所有交易记录需要验证用户身份。";
QString info;
success = verifyUser(userId, prompt, info);
if (!success)
{
QMessageBox::warning(this, "提示", info + QString("\n用户验证不通过。查询失败。"));
queryPageInitContent();
return;
}
query.finish();
query.prepare(QString("select time, type, value, balance, device, id from record_view "
"where cardId = :cardId;"));
query.bindValue(":cardId", cardId);
success = query.exec();
if (!success)
{
QMessageBox::warning(this, QString("提示"), QString("数据库异常。查询失败。"));
queryPageInitContent();
return;
}
std::vector<QStringList> transactionRecordList;
while (query.next())
{
QStringList transactionRecord = transactionRecord2QStringList
(
query.value("time").toDateTime(),
query.value("type").toInt(),
query.value("value").toDouble(),
query.value("balance").toDouble(),
query.value("device").toString(),
query.value("id").toString()
);
transactionRecordList.push_back(transactionRecord);
}
displayInTableWidget(transactionRecordList);
}
/**
* @brief 用户输入学/工号查询记录
* 该函数在用户点击“查询”按钮时触发,用于根据输入的学/工号查询该用户的所有交易记录。
* @param void
* @return void
* @details
* 函数首先检查软件是否已准备好并且数据库已连接。如果数据库未连接,函数将显示警告信息并返回。
* 接着,函数检查是否输入了学/工号。如果未输入学/工号,函数将显示警告信息并返回。
* 然后,函数会验证用户身份,如果验证失败,函数将显示警告信息并返回,并重置查询页面。
* 如果验证成功,函数会查询该学/工号绑定的卡片信息包括卡片ID、状态和余额并将余额和状态显示在界面上。
* 接着,函数会查询该卡片的所有交易记录,并将这些记录转换为 `QStringList` 后显示在界面的表格中。
* @author 柯劲帆
* @date 2024-07-31
*/
void MainWindow::on_userIdRecordQueryButton_clicked()
{
if (!softwareReady())
{
QMessageBox::warning(this, QString("提示"), QString("数据库未连接,请设置。"));
if (ui->stackedWidget->currentWidget() != ui->settingPage)
{
ui->stackedWidget->setCurrentWidget(ui->settingPage);
}
return;
}
if (!queryUserIdFilled)
{
QMessageBox::warning(this, "提示", "请填写学/工号。");
return;
}
int userId = ui->queryUserIdBox->value();
bool success = false;
QString prompt = "查询用户所有交易记录需要验证用户身份。";
QString info;
success = verifyUser(userId, prompt, info); // 内部会检查用户是否存在
if (!success)
{
QMessageBox::warning(this, "提示", info + QString("\n查询失败。"));
queryPageInitContent();
return;
}
QSqlQuery query(db->getDatabase());
query.prepare(QString("select id, `status`, balance from card "
"where userId = :userId;"));
query.bindValue(":userId", userId);
success = query.exec();
if (!success)
{
QMessageBox::warning(this, "提示", "数据库异常。查询失败。");
queryPageInitContent();
return;
}
if (!query.next())
{
QMessageBox::warning(this, "提示", "学/工号未绑定卡。查询失败。");
queryPageInitContent();
return;
}
QString cardId = query.value("id").toString();
int cardStatus = query.value("status").toInt();
double balance = query.value("balance").toDouble();
ui->queryBalanceShowEdit->setText(QString::number(balance, 'f', 2));
if (cardStatus == -1)
{
ui->queryCardStatusLabel->setText(QString("已被挂失"));
}
else if (cardStatus == 1)
{
ui->queryCardStatusLabel->setText(QString("启用中"));
}
query.finish();
query.prepare(QString("select time, type, value, balance, device, id from record_view "
"where cardId = :cardId;"));
query.bindValue(":cardId", cardId);
success = query.exec();
if (!success)
{
QMessageBox::warning(this, QString("提示"), QString("数据库异常。查询失败。"));
queryPageInitContent();
return;
}
std::vector<QStringList> transactionRecordList;
while (query.next())
{
QStringList transactionRecord = transactionRecord2QStringList
(
query.value("time").toDateTime(),
query.value("type").toInt(),
query.value("value").toDouble(),
query.value("balance").toDouble(),
query.value("device").toString(),
query.value("id").toString()
);
transactionRecordList.push_back(transactionRecord);
}
displayInTableWidget(transactionRecordList);
}
/**
* @brief 查询卡内记录
* @param void
* @return void
* @author 柯劲帆
* @date 2024-07-31
*/
void MainWindow::on_cardRecordQueryButton_clicked()
{
if (!databaseReady())
{
QMessageBox::warning(this, QString("提示"), QString("数据库未连接,请设置。"));
if (ui->stackedWidget->currentWidget() != ui->settingPage)
{
ui->stackedWidget->setCurrentWidget(ui->settingPage);
}
return;
}
if (ui->queryCardIdBox->currentIndex() == -1)
{
QMessageBox::warning(this, "提示", "请放置卡片并点击查询按钮。");
return;
}
QString cardId = ui->queryCardIdBox->currentText();
int cardStatus;
double balance;
// 检查和获取绑定用户
QSqlQuery query(db->getDatabase());
query.prepare(QString("select userId, `status`, balance from card "
"where id = :cardId;"));
query.bindValue(":cardId", cardId);
bool success = false;
success = query.exec();
if (!success)
{
QMessageBox::warning(this, QString("提示"), QString("数据库异常。查询失败。"));
queryPageInitContent();
return;
}
if (query.next()) // 卡已被注册获取用户ID
{
cardStatus = query.value("status").toInt();
if (cardStatus == 0)
{
QMessageBox::warning(this, QString("提示"), QString("此卡未被启用。"));
queryPageInitContent();
return;
}
if (cardStatus == -1)
{
ui->queryCardStatusLabel->setText(QString("已被挂失"));
}
if (cardStatus == 1)
{
ui->queryCardStatusLabel->setText(QString("启用中"));
}
balance = query.value("balance").toDouble();
ui->queryBalanceShowEdit->setText(QString::number(balance, 'f', 2));
}
else // 卡没有注册
{
query.finish();
query.prepare(QString("insert into card "
"values (:cardId, 0, 0.0, null);"));
query.bindValue(":cardId", cardId);
success = query.exec();
if (!success)
{
QMessageBox::warning(this, QString("提示"), QString("数据库异常。查询失败。"));
queryPageInitContent();
return;
}
QMessageBox::warning(this, QString("提示"), QString("此卡未被启用。"));
queryPageInitContent();
return;
}
QStringList cardRecordIdList = reader.readAllRecords(cardId, success);
if (!success)
{
QMessageBox::warning(this, QString("提示"), QString("读卡器异常。查询失败。"));
queryPageInitContent();
return;
}
query.finish();
query.prepare(QString("select time, type, value, balance, device, id from record_view "
"where id = :recordId;"));
std::vector<QStringList> transactionRecordList;
for (int i = 0; i < cardRecordIdList.size(); i++)
{
QString recordId = cardRecordIdList[i];
query.bindValue(":recordId", recordId);
success = query.exec();
if (!success)
{
QMessageBox::warning(this, QString("提示"), QString("数据库异常。查询失败。"));
queryPageInitContent();
return;
}
if (!query.next()) {
// 原来的代码
// QMessageBox::warning(this, QString("提示"), QString("数据库异常。查询失败。"));
// queryPageInitContent();
// return;
// 这里本来应该报错退出但是读卡器经常发疯见Reader::readAllRecords(QString cardId, bool &ok)
// 所以发现有不在数据库中的记录号,直接跳过
continue;
}
QStringList transactionRecord = transactionRecord2QStringList
(
query.value("time").toDateTime(),
query.value("type").toInt(),
query.value("value").toDouble(),
query.value("balance").toDouble(),
query.value("device").toString(),
query.value("id").toString()
);
transactionRecordList.push_back(transactionRecord);
}
displayInTableWidget(transactionRecordList);
}
/**
* @brief 将数据库查询返回的数据转化为QStringList
* 该函数用于将数据库查询返回的交易记录数据转换为一个 `QStringList`,以便在界面上显示。
* @param time 交易时间,类型为 QDateTime
* @param type 交易类型,非零表示充值,零表示消费
* @param value 交易金额,类型为 double
* @param balance 交易后的余额,类型为 double
* @param device 交易设备名称,类型为 QString
* @param id 交易记录号,类型为 QString
* @return QStringList 转换后的交易记录列表
* @details
* 函数将输入的交易时间、交易类型、交易金额、余额、设备名称和记录号转换为一个QStringList。
* 交易类型用QString表示充值为“充值”消费为“消费”。交易金额根据交易类型显示为正值或负值保留两位小数。
* @author 柯劲帆
* @date 2024-07-31
*/
QStringList MainWindow::transactionRecord2QStringList(QDateTime time, int type, double value, double balance, QString device, QString id)
{
QStringList stringList = {
time.toString("yyyy-MM-dd hh:mm:ss"),
type != 0 ? QString("充值") : QString("消费"),
QString::number((type != 0 ? value : -value), 'f', 2),
QString::number(balance, 'f', 2),
device,
id
};
return stringList;
}
/**
* @brief 初始化查询页面的各个组件内容
* 该函数用于初始化查询页面上的各个组件包括清空用户ID输入框、清空查询结果表、清空余额显示框和重置卡片状态标签。
* @param void
* @return void
* @details
* 函数首先将 queryUserIdFilled 标志设置为false表示尚未填入用户ID。
* 然后函数依次清空用户ID输入框、查询结果表和余额显示框并将卡片状态标签设置为"-"。
* @author 柯劲帆
* @date 2024-07-31
*/
void MainWindow::queryPageInitContent()
{
queryUserIdFilled = false;
ui->queryUserIdBox->clear();
ui->queryResultTable->clearContents();
ui->queryBalanceShowEdit->clear();
ui->queryCardStatusLabel->setText(QString("-"));
}
/**
* @brief 在列表组件中显示内容
* 该函数用于在 `QTableWidget` 中显示交易记录列表。交易记录包括充值和消费信息,并且根据交易类型进行颜色标注。
* @param transactionRecordList 包含交易记录的 `QStringList` 向量,每个 `QStringList` 表示一条记录
* @return void
* @details
* 函数首先清除 `QTableWidget` 中的所有内容,然后设置行数为 `transactionRecordList` 的大小。
* 接着,函数遍历每条交易记录,并将其内容逐行逐列插入 `QTableWidget` 中。对于充值记录,文本颜色设置为绿色;
* 对于消费记录,文本颜色设置为红色。所有单元格内容都右对齐。
* @author 柯劲帆
* @date 2024-07-31
*/
void MainWindow::displayInTableWidget(std::vector<QStringList> transactionRecordList)
{
ui->queryResultTable->clearContents();
int numRows = transactionRecordList.size();
ui->queryResultTable->setRowCount(numRows);
for (int i = 0; i < numRows; i++)
{
QStringList transactionRecord = transactionRecordList[i];
bool is_deposit = transactionRecord[1] == QString("充值");
for (int j = 0; j < 6; j++)
{
QTableWidgetItem *item = new QTableWidgetItem(transactionRecord[j]);
item->setTextAlignment(Qt::AlignRight | Qt::AlignVCenter); // 设置右对齐
// 渲染:充值为绿色,消费为红色(不知为何不工作)
if (is_deposit)
item->setForeground(QBrush(QColor(Qt::green)));
else
item->setForeground(QBrush(QColor(Qt::red)));
ui->queryResultTable->setItem(i, j, item); // 设置内容
}
}
}