277 lines
9.0 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-30
*/
void MainWindow::on_ConsumptionAction_triggered()
{
ui->stackedWidget->setCurrentWidget(ui->consumePage);
}
/**
* @brief 读卡器扫描卡片
* 点击消费页面的“查询”触发。
* 如果读卡器未连接,显示警告信息并跳转到设置页面。
* 显示Inventory的查询结果最多显示10张卡。
* @param void
* @return void
* @author 柯劲帆
* @date 2024-07-30
*/
void MainWindow::on_consumeInventoryButton_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->consumeCardIdBox->clear();
if (cardIdList.empty())
{
QMessageBox::warning(this, "提示", "未发现卡片,请将卡片放置于读卡器上方。");
}
else
{
ui->consumeCardIdBox->addItems(cardIdList);
}
}
/**
* @brief 消费
* 该函数在用户点击“消费”按钮时触发,用于对指定卡片进行消费操作。
* @param void
* @return void
* @details
* 函数首先检查软件是否已准备好并且数据库已连接。如果数据库未连接,函数将显示警告信息并返回。
* 接着,函数检查是否选择了卡片。如果未选择卡片,函数将显示警告信息并返回。
* 然后,函数检查并获取绑定的用户信息。如果卡片不存在或已挂失或未启用,函数将显示相应的警告信息并返回。
* 如果消费金额大于50元函数会要求进行密码验证。如果验证失败函数将显示警告信息并返回。
* 在所有检查通过后,函数调用 `deductCard` 函数进行消费操作,并在操作成功后显示消费结果。
* @author 柯劲帆
* @date 2024-07-30
*/
void MainWindow::on_consumeButton_clicked()
{
if (!softwareReady())
{
QMessageBox::warning(this, QString("提示"), QString("数据库未连接,请设置。"));
if (ui->stackedWidget->currentWidget() != ui->settingPage)
{
ui->stackedWidget->setCurrentWidget(ui->settingPage);
}
return;
}
if (ui->consumeCardIdBox->currentIndex() == -1)
{
QMessageBox::warning(this, "提示", "请放置卡片并点击查询按钮。");
return;
}
QString cardId = ui->consumeCardIdBox->currentText();
int userId;
int cardStatus;
double originalBalance;
// 检查和获取绑定用户
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("数据库异常。消费失败。"));
return;
}
if (query.next()) // 卡已被注册获取用户ID
{
cardStatus = query.value("status").toInt();
if (cardStatus == -1)
{
QMessageBox::warning(this, QString("提示"), QString("此卡已被挂失。消费失败。"));
return;
}
if (cardStatus == 0)
{
QMessageBox::warning(this, QString("提示"), QString("此卡未被启用。消费失败。"));
return;
}
userId = query.value("userId").toInt();
originalBalance = query.value("balance").toDouble();
}
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("数据库异常。消费失败。"));
return;
}
QMessageBox::warning(this, QString("提示"), QString("此卡未被启用。消费失败。"));
return;
}
double deductValue = ui->consumeValueBox->value();
if (!(deductValue > 0.00))
{
QMessageBox::warning(this, "提示", "请输入大于0.00的消费金额。");
return;
}
if (originalBalance - deductValue < 0.00)
{
QMessageBox::warning(this, "提示", "余额不足。");
return;
}
if (deductValue > 300.00)
{
QMessageBox::warning(this, "提示", "消费金额不得超过300.00元。");
return;
}
if (deductValue > 50.00)
{
QString prompt = "消费超过50.00元,需要密码验证。";
QString info;
success = verifyUser(userId, prompt, info);
if (!success)
{
QMessageBox::warning(this, "提示", info + QString("\n用户验证不通过。消费失败。"));
return;
}
}
QString info;
double finalBalance;
QString recordId;
success = deductCard(cardId, deductValue, originalBalance, finalBalance, recordId, info);
if (!success)
{
QMessageBox::warning(this, "提示", info + QString("\n消费失败。"));
return;
}
success = reader.insertRecord(recordId, cardId);
if (!success)
{
QMessageBox::warning(this, "提示", "消费完成。写卡失败。本交易不记录在卡上。");
}
QString consumeResultMessage = QString("消费成功:") + QString::number(deductValue) + QString("\n");
consumeResultMessage += QString("原余额:") + QString::number(originalBalance) + QString("\n");
consumeResultMessage += QString("消费后余额:") + QString::number(finalBalance) + QString("\n");
consumeResultMessage += QString("消费设备:") + device.getName() + QString("\n");
consumeResultMessage += QString("交易记录号:") + recordId + QString("\n");
QMessageBox::information(this, "消费成功", consumeResultMessage);
ui->consumeValueBox->setValue(0.00);
return;
}
/**
* @brief 卡消费
* 该函数用于对指定卡片进行消费操作。消费前会进行一系列检查,包括卡片状态、余额是否足够以及单次消费额是否超过上限等。
* 如果所有检查通过,将调用存储过程 `sp_consumeCard` 进行消费操作,并返回消费后的余额。
* @param cardId 要消费的卡号
* @param deductValue 消费金额
* @param originalBalance 消费前的余额,通过引用返回
* @param finalBalance 消费后的余额,通过引用返回
* @param recordId 交易记录号,通过引用返回
* @param info 如果出现异常,填入异常信息,通过引用返回
* @return bool 是否消费成功
* - true 成功
* - false 失败
* @author 柯劲帆
* @date 2024-07-30
*/
bool MainWindow::deductCard(QString cardId, double deductValue, double &originalBalance, double &finalBalance, QString &recordId, QString &info)
{
QSqlQuery query(db->getDatabase());
bool success;
query.prepare(QString("select userId, `status`, balance from card "
"where id = :cardId;"));
query.bindValue(":cardId", cardId);
success = query.exec();
if (!success)
{
info = "数据库异常。";
return false;
}
if (!query.next())
{
info = "卡号不存在。";
return false;
}
int cardStatus = query.value("status").toInt();
if (cardStatus == -1)
{
info = "此卡已被挂失。";
return false;
}
if (cardStatus == 0)
{
info = "此卡未被启用。";
return false;
}
originalBalance = query.value("balance").toDouble();
int userId = query.value("userId").toInt();
if (originalBalance - deductValue < 0.00)
{
info = "余额不足。";
return false;
}
if (deductValue > 300.00)
{
info = "单次消费额上限为300.00元。";
return false;
}
QDateTime currentTime = QDateTime::currentDateTime();
recordId = getRecordId(currentTime, userId, 0);
query.finish();
query.prepare(QString("call sp_consumeCard (:cardId, :value, :recordId, :device, :time, :type, @newBalance);"));
query.bindValue(":cardId", cardId);
query.bindValue(":value", deductValue);
query.bindValue(":recordId", recordId);
query.bindValue(":device", device.getId());
query.bindValue(":time", currentTime.toString("yyyy-MM-dd hh:mm:ss"));
query.bindValue(":type", 0);
success = query.exec();
if (!success)
{
info = "数据库异常。";
return false;
}
query.exec("select @newBalance;");
query.next();
finalBalance = query.value("@newBalance").toDouble();
return true;
}