完成所有功能。(硬件接口存在部分问题无法解决,直接跳过处理)
This commit is contained in:
parent
20604b7f22
commit
6a6f666e46
@ -1,5 +1,6 @@
|
||||
#include <cstdlib>
|
||||
#include "VCDOurs.h"
|
||||
#include "qlogging.h"
|
||||
|
||||
CVCDOurs::CVCDOurs(void)
|
||||
{
|
||||
@ -422,7 +423,7 @@ int CVCDOurs::writeBlocks( int nFirstBlock, int nBlockNum, uchar_t *pDat, uchar_
|
||||
int k = 0;
|
||||
for( int i = 0; i < nBlockNum; i++ )
|
||||
{
|
||||
k += writeBlock( nFirstBlock + i, pDat+i*8, pucUID );
|
||||
k += writeBlock( nFirstBlock + i, pDat+i*4, pucUID );
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
@ -71,12 +71,12 @@ public:
|
||||
virtual int readMultipleBlocks(
|
||||
uchar_t *pucUID, // NULL表示select模式
|
||||
uchar_t optional_flag, // optional bit = 1, 要求返回block的安全状态
|
||||
uchar_t ucBlkno, // 开始block no
|
||||
uchar_t blocknum, // 实际读的block是:blocknum+1;
|
||||
uchar_t ucBlkno, // 开始block no
|
||||
uchar_t blocknum, // 实际读的block是:blocknum+1;
|
||||
uchar_t buf[], // 返回读取的数据
|
||||
uchar_t aucSecurity[] // 如果optional_flag = 1, 返回该block的安全状态:1表示locked.
|
||||
)
|
||||
{
|
||||
{
|
||||
t15bOption = optional_flag;
|
||||
return readBlocks( ucBlkno, blocknum+1, buf, aucSecurity, pucUID );
|
||||
}
|
||||
|
@ -172,6 +172,12 @@ void MainWindow::on_consumeButton_clicked()
|
||||
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");
|
||||
@ -263,8 +269,6 @@ bool MainWindow::deductCard(QString cardId, double deductValue, double &original
|
||||
query.next();
|
||||
finalBalance = query.value("@newBalance").toDouble();
|
||||
|
||||
/// @todo 写卡
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -118,6 +118,12 @@ void MainWindow::on_depositByCardIdButton_clicked()
|
||||
return;
|
||||
}
|
||||
|
||||
success = reader.insertRecord(recordId, cardId);
|
||||
if (!success)
|
||||
{
|
||||
QMessageBox::warning(this, "提示", "充值成功。写卡失败。本交易不记录在卡上。");
|
||||
}
|
||||
|
||||
QString depositResultMessage = QString("充值成功:") + QString::number(topUpValue) + QString("元\n");
|
||||
depositResultMessage += QString("原余额:") + QString::number(originalBalance) + QString("元\n");
|
||||
depositResultMessage += QString("充值后余额:") + QString::number(finalBalance) + QString("元\n");
|
||||
@ -223,9 +229,10 @@ void MainWindow::on_depositByUserIdButton_clicked()
|
||||
* @param finalBalance 充值后的余额,通过引用返回
|
||||
* @param recordId 交易编号,通过引用返回
|
||||
* @param info 如果出现异常,填入异常信息,通过引用返回
|
||||
* @return bool 是否充值成功
|
||||
* - true 成功
|
||||
* - false 失败
|
||||
* @return int 是否充值成功
|
||||
* - 0 失败
|
||||
* - 1 成功
|
||||
* - 2 充值成功但写卡失败
|
||||
* @details
|
||||
* 函数首先检查设备是否支持充值。如果设备不支持,函数返回失败并设置错误信息。
|
||||
* 接着,函数查询数据库获取卡片的当前状态和余额。如果卡片不存在、已挂失或未启用,函数返回失败并设置相应的错误信息。
|
||||
@ -299,8 +306,6 @@ bool MainWindow::topUpCard(QString cardId, double topUpValue, double &originalBa
|
||||
query.next();
|
||||
finalBalance = query.value("@newBalance").toDouble();
|
||||
|
||||
/// @todo 写卡
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -327,5 +332,5 @@ QString MainWindow::getRecordId(QDateTime currentTime, int userId, int recordTyp
|
||||
QString typeStr = QString::number(recordType); // 第25位:记录类型
|
||||
QString randomHex = QString::number(QRandomGenerator::global()->bounded(0x10000), 16).rightJustified(4, '0'); // 第26-29位:随机十六进制数
|
||||
QString recordId = timeStr + userIdStr + typeStr + randomHex; // 共30位
|
||||
return recordId;
|
||||
return recordId.toUpper();
|
||||
}
|
||||
|
@ -83,7 +83,6 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
ui->queryResultTable->setColumnWidth(5, 240);
|
||||
|
||||
|
||||
|
||||
// 设置启动页面
|
||||
ui->stackedWidget->setCurrentWidget(ui->settingPage);
|
||||
}
|
||||
@ -93,4 +92,3 @@ MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
|
@ -71,6 +71,7 @@ private slots:
|
||||
void on_queryInventoryButton_clicked();
|
||||
void on_userRecordQueryButton_clicked();
|
||||
void on_userIdRecordQueryButton_clicked();
|
||||
void on_cardRecordQueryButton_clicked();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
|
@ -247,7 +247,7 @@ void MainWindow::on_newCardButton_clicked()
|
||||
}
|
||||
else if (userCardStatus == -1) // 用户有挂失卡,需要移资
|
||||
{
|
||||
/// @todo 弹出验证用户界面,要求用户输入密码;在数据库中将挂失卡的信息和消费记录移到新卡
|
||||
// 弹出验证用户界面,要求用户输入密码;在数据库中将挂失卡的信息和消费记录移到新卡
|
||||
QString info, prompt = QString("如需将挂失卡移资到本卡,请输入密码。");
|
||||
bool success = verifyUser(userId, prompt, info);
|
||||
if (!success)
|
||||
@ -333,8 +333,6 @@ bool MainWindow::bindUserWithCard(int userId, QString cardId, QString &info)
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @todo 写卡
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -570,8 +568,6 @@ bool MainWindow::transferCard(int userId, QString newCardId, QString oldCardId,
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @todo 将数据库上的记录写到新卡上
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -606,7 +602,5 @@ bool MainWindow::reopenCard(QString cardId, QString &info)
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @todo 看看是否有写卡需求
|
||||
|
||||
return true;
|
||||
}
|
||||
|
131
queryPage.cpp
131
queryPage.cpp
@ -283,6 +283,136 @@ void MainWindow::on_userIdRecordQueryButton_clicked()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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("已被挂失"));
|
||||
}
|
||||
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 cardId = :cardId and id = :recordId;"));
|
||||
query.bindValue(":cardId", cardId);
|
||||
|
||||
|
||||
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`,以便在界面上显示。
|
||||
@ -374,4 +504,3 @@ void MainWindow::displayInTableWidget(std::vector<QStringList> transactionRecord
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,8 @@ void MainWindow::on_quitAppAction_triggered()
|
||||
|
||||
/**
|
||||
* @brief 退出程序
|
||||
* 在退出页面点击“确认”按钮触发
|
||||
* 在退出页面点击“确认”按钮触发
|
||||
* 关闭读卡器连接,销毁数据库对象(内部关闭数据库连接)
|
||||
* @param void
|
||||
* @return void
|
||||
* @author 柯劲帆
|
||||
@ -26,5 +27,7 @@ void MainWindow::on_quitAppAction_triggered()
|
||||
*/
|
||||
void MainWindow::on_confirmQuitButton_clicked()
|
||||
{
|
||||
if (reader.is_connected()) reader.disconnect();
|
||||
free(db);
|
||||
this->close();
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "readerAPI.h"
|
||||
#include "qdebug.h"
|
||||
|
||||
|
||||
/**
|
||||
@ -29,7 +30,7 @@ bool Reader::is_connected()
|
||||
*/
|
||||
bool Reader::connect()
|
||||
{
|
||||
if (CVCDOurs::connectReaderByCOM(comNumber))
|
||||
if (connectReaderByCOM(comNumber))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -41,6 +42,19 @@ bool Reader::connect()
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 关闭连接
|
||||
* @param void
|
||||
* @return void
|
||||
* @author 柯劲帆
|
||||
* @date 2024-07-31
|
||||
*/
|
||||
void Reader::disconnect()
|
||||
{
|
||||
disconnectReaderByCOM();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 设置COM口号
|
||||
* @param comNumber 要设置的COM口号
|
||||
@ -131,14 +145,13 @@ bool Reader::readRecordNumber(int &recordNum, int &recordIndex, QString cardId)
|
||||
uchar_t recordIndexHex[4] = {0}; // 一个block有4个byte,1个byte有两个hex,会返回8个hex存在4个uchar_t中
|
||||
|
||||
uchar_t cardIdHex[8] = {0};
|
||||
QByteArray ba = cardId.toLatin1();
|
||||
StringToHex(ba.data(), cardIdHex);
|
||||
StringToHex(cardId.toLatin1().data(), cardIdHex);
|
||||
|
||||
int hexNum = readBlocks(0, 1, recordIndexHex, nullptr, cardIdHex);
|
||||
int hexNum = readSingleBlock(cardIdHex, 0, 0, recordIndexHex, nullptr);
|
||||
if (hexNum == 0) return false;
|
||||
|
||||
recordNum = (int)(recordIndexHex[0] & 0x0F);
|
||||
recordIndex = (int)(recordIndexHex[1] >> 4);
|
||||
recordIndex = (int)(recordIndexHex[0] >> 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -171,10 +184,9 @@ bool Reader::writeRecordNumber(int recordNum, int recordIndex, QString cardId)
|
||||
recordIndexStr[0] += (uchar_t)(recordNum);
|
||||
|
||||
uchar_t cardIdHex[8] = {0};
|
||||
QByteArray ba = cardId.toLatin1();
|
||||
StringToHex(ba.data(), cardIdHex);
|
||||
StringToHex(cardId.toLatin1().data(), cardIdHex);
|
||||
|
||||
int success = writeBlock(0, recordIndexStr, cardIdHex);
|
||||
int success = writeSingleBlock(cardIdHex, 0, 4, recordIndexStr);
|
||||
return success == 1;
|
||||
}
|
||||
|
||||
@ -207,14 +219,12 @@ bool Reader::insertRecord(QString record, QString cardId)
|
||||
int blockIndex = 1 + 4 * recordIndex;
|
||||
|
||||
uchar_t cardIdHex[8] = {0};
|
||||
QByteArray ba = cardId.toLatin1();
|
||||
StringToHex(ba.data(), cardIdHex);
|
||||
StringToHex(cardId.toLatin1().data(), cardIdHex);
|
||||
|
||||
uchar_t recordHex[4 * 4] = {0};
|
||||
ba = record.toLatin1();
|
||||
StringToHex(ba.data(), recordHex);
|
||||
StringToHex(record.toLatin1().data(), recordHex);
|
||||
|
||||
int writeLineNumber = writeBlocks(blockIndex, 4, recordHex, cardIdHex);
|
||||
int writeLineNumber = writeMultipleBlocks(cardIdHex, blockIndex, 4, 4, recordHex);
|
||||
|
||||
return writeLineNumber != 0;
|
||||
}
|
||||
@ -234,7 +244,7 @@ bool Reader::insertRecord(QString record, QString cardId)
|
||||
* @author 柯劲帆
|
||||
* @date 2024-07-31
|
||||
*/
|
||||
QStringList Reader::getRecords(QString cardId, bool &ok)
|
||||
QStringList Reader::readAllRecords(QString cardId, bool &ok)
|
||||
{
|
||||
QStringList recordList;
|
||||
|
||||
@ -247,37 +257,43 @@ QStringList Reader::getRecords(QString cardId, bool &ok)
|
||||
}
|
||||
|
||||
uchar_t cardIdHex[8] = {0};
|
||||
QByteArray ba = cardId.toLatin1();
|
||||
StringToHex(ba.data(), cardIdHex);
|
||||
StringToHex(cardId.toLatin1().data(), cardIdHex);
|
||||
|
||||
for (int i = 0; i < recordNum; i++)
|
||||
{
|
||||
QString recordStr = "";
|
||||
int recordIndex = 1 + 4 * ((recordStartIndex + i) % maxRecordNum);
|
||||
for (int j = 0; j < 4; j++)
|
||||
StringToHex(cardId.toLatin1().data(), cardIdHex); // readMultipleBlocks不知为何会改变cardIdHex的值,要重新赋值
|
||||
int recordBlockIndex = 1 + 4 * ((recordStartIndex + i) % maxRecordNum);
|
||||
uchar_t recordHex[4 * 4] = {0};
|
||||
int hexNum = readMultipleBlocks(cardIdHex, 0, recordBlockIndex, 4, recordHex, nullptr);
|
||||
if (hexNum == 0)
|
||||
{
|
||||
uchar_t blockHex[4] = {0}; // 一个block有4个byte,1个byte有两个hex,会返回8个hex存在4个uchar_t中
|
||||
int hexNum = readBlocks(recordIndex + j, 1, blockHex, nullptr, cardIdHex);
|
||||
if (hexNum == 0)
|
||||
{
|
||||
ok = false;
|
||||
return recordList;
|
||||
}
|
||||
// 原来的处理代码
|
||||
// ok = false;
|
||||
// return recordList;
|
||||
|
||||
char blockStr[9] = {0};
|
||||
HexToString(blockHex, 4, blockStr);
|
||||
|
||||
recordStr += QString(blockStr);
|
||||
// 这里经常出现hexNum == 0,循环终止的情况,原因是返回的reply为空值: “[]”
|
||||
// 一旦出现[],后面的值大概率会出错。
|
||||
// 出现主要集中在第二遍循环时。
|
||||
// 尝试解决方案:每一遍循环重新inventory重置一下环境(怀疑某些变量被改了)、每一遍循环睡眠2秒,都没有解决这个问题
|
||||
// 因此在发生错误时,直接返回能够正确读取的记录ID。
|
||||
break;
|
||||
}
|
||||
recordList.push_back(recordStr);
|
||||
|
||||
char recordStr[33] = {0};
|
||||
HexToString(recordHex, 4 * 4, recordStr);
|
||||
recordStr[30] = '\0';
|
||||
QString qRecordStr = QString(recordStr).toUpper();
|
||||
|
||||
recordList.push_back(qRecordStr);
|
||||
}
|
||||
ok = true;
|
||||
return recordList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 卡初始化
|
||||
* 将第1个block初始化为全0。
|
||||
* 将第1个block的记录数量设置为0,最近一条交易记录下标设置为maxRecordNum-1。
|
||||
* @param cardId 要初始化的卡片ID,类型为 QString
|
||||
* @return bool 是否初始化成功
|
||||
* - true 初始化成功
|
||||
@ -292,10 +308,10 @@ QStringList Reader::getRecords(QString cardId, bool &ok)
|
||||
bool Reader::initCard(QString cardId)
|
||||
{
|
||||
uchar_t cardIdHex[8] = {0};
|
||||
QByteArray ba = cardId.toLatin1();
|
||||
StringToHex(ba.data(), cardIdHex);
|
||||
StringToHex(cardId.toLatin1().data(), cardIdHex);
|
||||
|
||||
uchar_t allZeroHex[4] = {0};
|
||||
int writeLineNumber = writeBlock(0, allZeroHex, cardIdHex);
|
||||
uchar_t initHex[4] = {0};
|
||||
initHex[0] = (char)(maxRecordNum - 1) << 4;
|
||||
int writeLineNumber = writeSingleBlock(cardIdHex, 0, 4, initHex);
|
||||
return writeLineNumber != 0;
|
||||
}
|
||||
|
@ -2,9 +2,11 @@
|
||||
#define READERAPI_H
|
||||
|
||||
#include <HF15693.h>
|
||||
#include <VCDOurs.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <VCDOurs.h>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
typedef unsigned char uchar_t;
|
||||
|
||||
@ -29,13 +31,15 @@ public:
|
||||
void setComNumber(int comNumber);
|
||||
int getComNumber();
|
||||
|
||||
|
||||
bool is_connected();
|
||||
|
||||
bool connect();
|
||||
void disconnect();
|
||||
QStringList inventory(int maxViccNum);
|
||||
bool insertRecord(QString record, QString cardId);
|
||||
bool writeRecords(QStringList recordList, QString cardId);
|
||||
QStringList getRecords(QString cardId, bool &ok);
|
||||
QStringList readAllRecords(QString cardId, bool &ok);
|
||||
bool initCard(QString cardId);
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user