#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 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 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 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 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); // 设置内容 } } }