1. 功能介绍
当前设计的考勤系统主要给高校的教师使用,上课时,学生进入教室拿出学生卡自己进行打开考勤,可以在系统里申请请假以及查看在校期间所有的上课出勤信息。
考虑到整个学校学生众多,个人隐私问题,为此每个新学生需要由管理员或自己的班主任教师登录进入学生信息管理页面进行增加学生的信息操作,进行添加学生的相关信息;再由学生自己到登录界面进行学生注册操作,完善自己的其他信息,当注册成功提示后,在进入到登陆界面填入注册时的账号和密码就可以登录成功,最后才可以使用学生操作页面的功能模块等操作。教师则需要通过指定的教师账号和密码登录到教师管理后台,才能使用教师的操作页面的功能模块等。系统管理员则需要通过指定的管理员账号、密码登录到管理员后台,才能使用管理员操作页面的功能模块等。三者的操作页面相互独立,都有权限限制。
目前设计的这个基于RFID的学生考勤管理系统,采用C++作为编程语言,Qt作为整体UI软件框架,数据库采用SQLite,在设计这个考勤系统前,在互联网上进行了广泛搜索,找到了很多案例,发现很多考勤管理系统,操作流程和管理行也存在一些问题,本系统在结合其他软件的优点后,去除了一些不需要的模块,设计出一款全新的考勤管理系统。
包含的功能模块如下:
1) 登录模块:用户名和密码登录,本设计有三类用户名,包括系统管理员,教师和学生;
2) 学生信息管理模块:学生基本信息的增加,删除,修改,查询;
3) 考勤管理模块:进行学生签到和签退;
4) 射频卡管理模块:利用射频卡对学生的考勤情况进行记录;
5) 查询模块:管理员,教师,学生都可以对自己权限范围内考勤结果进行查询;
6) 请假查询模块:通过ID查询学生请假情况;
7) 数据备份模块:系统数据定期进行保存,但系统服务器出现故障时提供帮助。
该系统有3个用户权限,学生操作页面、管理员操作页面、教师操作页面。学生操作页面,可以查看自己的考勤记录;教师操作页面可以查看自己班级学生的考勤记录,添加考勤的学生;管理员可以查看所有人的考勤记录,支持所有功能。
USB接口的IC卡读写器,采用明华公司推出的一 款射频读写器RF-EYE 。它采 用 了 USB 接口通讯和取电, 支持ISO14443-3协议的卡片,例如 Mifare One、 UltraLight、 Mifare 4K、 MifarePro 等。 提供的接口函数库可满足用户二次开发的需要; 其完善、 可靠的接口函数, 支持访问射频卡的全部功能。
完整项目源码与资料下载: https://download.csdn.net/download/xiaolong1126626497/75319096
2. 设计实现
2.1 系统功能模块
整体的设计框图如下:
2.2 登录流程图
管理员与教师填写登录信息的模块,需要输入注册时的登录账号和登录密码,用户身份选择教师或者管理员其中的一个即可,管理员账号和教师的账号相互独立。
2.3 添加学生
数据都是存放在本地SQLite里的。
2.4 请假管理
3. 项目源码
3.1 配置信息读取与保存
//读配置
void LoginWindow::read_config()
{
//读取配置文件
QString text;
text=QCoreApplication::applicationDirPath()+"/"+CONFIG;
QString pass;
QString user;
//判断文件是否存在
if(QFile::exists(text))
{
QFile filenew(text);
filenew.open(QIODevice::ReadOnly);
QDataStream in(&filenew); // 从文件读取序列化数据
in >> user >> pass; //提取写入的数据
filenew.close();
//设置界面值
ui->lineEdit_user_name->setText(user);
ui->lineEdit_password->setText(pass);
ui->checkBox_save_password->setChecked(true);
}
}
//写配置
void LoginWindow::write_config()
{
QString pass;
QString user;
//从UI界面获取用户的个性化配置参数
pass=ui->lineEdit_password->text();
user=ui->lineEdit_user_name->text();
/*保存数据到文件,方便下次加载*/
QString text;
text=QCoreApplication::applicationDirPath()+"/"+CONFIG;
QFile filesrc(text);
filesrc.open(QIODevice::WriteOnly);
QDataStream out(&filesrc);
out << user; //序列化用户名
out << pass; //序列化密码
filesrc.flush();
filesrc.close();
}
3.2 登录信息保存与查找
//创建账号密码表
void LoginWindow::CreateUserPassTAB()
{
//数据库:建表,如果存在就不创建,不存在就创建
QSqlQuery sql_query(database);
//下面语句查询指定的表是否存在.
sql_query.exec(QString("select count(*) from sqlite_master where type='table' and name='%1'").arg("password"));
if(sql_query.next())
{
if(sql_query.value(0).toInt()==0)
{
qDebug("数据库表是不存在的.准备创建.\n");
//创建表格 创建表格语句:create table <table_name> (f1 type1, f2 type2,…);
/* CREATE TABLE 是告诉数据库系统创建一个新表的关键字。
* CREATE TABLE 语句后跟着表的唯一的名称
* 或标识*/
/*下面的语句: 创建一个名称为password的表,字段分别是存放 账号、密码、身份(0管理员、1教师、2学生)*/
QString create_sql = "create table password(id int primary key, user varchar(100),password varchar(100),int type)";
sql_query.prepare(create_sql);
if(!sql_query.exec())
{
Log_Text_Display("数据库表创建失败.\n");
}
else
{
Log_Text_Display("数据库表创建成功.\n");
//初始化的管理员密码
addPasswords(ROOT_USER,ROOT_PASSWORD,0);
}
}
else
{
Log_Text_Display("数据库表是存在的.不需要创建.\n");
}
}
}
//显示日志
void LoginWindow::Log_Text_Display(QString text)
{
qDebug()<<text;
}
//插入数据到数据库文件
bool LoginWindow::addPasswords(QString user,QString pass,int type)
{
//指定操作的数据库
QSqlQuery sql_query(database);
//查询最大ID
QString select_max_sql = "select max(id) from password";
int max_id = 0;
sql_query.prepare(select_max_sql);
if(!sql_query.exec())
{
Log_Text_Display("数据库最大ID查找失败.\n");
}
else
{
while(sql_query.next())
{
max_id = sql_query.value(0).toInt();
}
Log_Text_Display(QString("data base max id:%1\n").arg(max_id));
//添加数据
//插入数据 插入语句:insert into <table_name> values (value1, value2,…);
QString insert_sql = tr("insert into password values(?,?,?,?)");
sql_query.prepare(insert_sql);
//if(max_id!=0)max_id+=1; //判断是否是第一次数据
sql_query.addBindValue(max_id+1); //id
sql_query.addBindValue(user); //账号
sql_query.addBindValue(pass); //密码
sql_query.addBindValue(type); //类型
if(!sql_query.exec())
{
Log_Text_Display("数据插入失败.\n");
}
else
{
return true;
}
}
return false;
}
//比较密码 true成功 false失败
bool LoginWindow::ComparePasswords(QString user,QString pass,int type)
{
//指定操作的数据库
QSqlQuery sql_query(database);
//查询全部数据
sql_query.prepare("select * from password");
if(!sql_query.exec())
{
Log_Text_Display("数据库查询错误.\n");
}
else
{
while(sql_query.next())
{
int id = sql_query.value(0).toInt(); //ID--主键
QString sql_user = sql_query.value(1).toString(); //账号
QString sql_pass = sql_query.value(2).toString(); //密码
int sql_type = sql_query.value(3).toInt(); //身份类型
//比较密码
if(user==sql_user && sql_pass==pass && sql_type ==type)
{
return true;
}
}
}
return false;
}
3.3 主界面的初始化
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("学生考勤管理系统");
//设置并打开数据库
if (QSqlDatabase::contains(LOG_IN_DATABASE_CONNECT_NAME))
{
database = QSqlDatabase::database(LOG_IN_DATABASE_CONNECT_NAME);
}
else
{
//数据库类型
database = QSqlDatabase::addDatabase("QSQLITE",LOG_IN_DATABASE_CONNECT_NAME);
database.setDatabaseName(LOG_IN_DATABASE_NAME); //数据库名称
database.setUserName("xl"); //用户名
database.setPassword("123456"); //密码
}
//打开数据库,如果数据库存在就打开,不存在就自动创建
if(database.open()==false)
{
qDebug("数据库打开失败.请检查程序运行路径和权限.\n");
}
else
{
qDebug("连接数据库成功.\n");
}
//创建账号密码表
CreateUserPassTAB();
//配置账号密码的管理表格样式属性
//奇数偶数行颜色交替
//ui->tableWidget_user_pass->setAlternatingRowColors(true);
//选中时一行整体选中
ui->tableWidget_user_pass->setSelectionBehavior(QAbstractItemView::SelectRows);
//最后一行拉伸填充
//ui->tableWidget_user_pass->horizontalHeader()->setStretchLastSection(true);
//选中一行表头是否加粗
ui->tableWidget_user_pass->horizontalHeader()->setHighlightSections(false);
//表头不可单击
ui->tableWidget_user_pass->horizontalHeader()->setSectionsClickable(false);
//表列随着表格变化而自适应变化
ui->tableWidget_user_pass->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
//配置学生管理表格样式属性
//奇数偶数行颜色交替
//ui->tableWidget_student->setAlternatingRowColors(true);
//选中时一行整体选中
ui->tableWidget_student->setSelectionBehavior(QAbstractItemView::SelectRows);
//最后一行拉伸填充
//ui->tableWidget_student->horizontalHeader()->setStretchLastSection(true);
//选中一行表头是否加粗
ui->tableWidget_student->horizontalHeader()->setHighlightSections(false);
//表头不可单击
ui->tableWidget_student->horizontalHeader()->setSectionsClickable(false);
//表列随着表格变化而自适应变化
ui->tableWidget_student->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
//配置学生考勤列表的样式属性
//奇数偶数行颜色交替
//ui->tableWidget_SignIn->setAlternatingRowColors(true);
//选中时一行整体选中
ui->tableWidget_SignIn->setSelectionBehavior(QAbstractItemView::SelectRows);
//最后一行拉伸填充
//ui->tableWidget_SignIn->horizontalHeader()->setStretchLastSection(true);
//选中一行表头是否加粗
ui->tableWidget_SignIn->horizontalHeader()->setHighlightSections(false);
//表头不可单击
ui->tableWidget_SignIn->horizontalHeader()->setSectionsClickable(false);
//表列随着表格变化而自适应变化
ui->tableWidget_SignIn->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
//配置请假列表的样式属性
//奇数偶数行颜色交替
//ui->tableWidget_SignIn->setAlternatingRowColors(true);
//选中时一行整体选中
ui->tableWidget_leave->setSelectionBehavior(QAbstractItemView::SelectRows);
//最后一行拉伸填充
ui->tableWidget_leave->horizontalHeader()->setStretchLastSection(true);
//选中一行表头是否加粗
ui->tableWidget_leave->horizontalHeader()->setHighlightSections(false);
//表头不可单击
ui->tableWidget_leave->horizontalHeader()->setSectionsClickable(false);
//表列随着表格变化而自适应变化
//ui->tableWidget_leave->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
//更新数据
on_pushButton_update_data_clicked();
on_pushButton_update_student_clicked();
on_pushButton_SignIn_update_data_clicked();
on_pushButton_leave_update_clicked();
//定时器--实时时间显示
timer=new QTimer;
connect(timer, SIGNAL(timeout()), this, SLOT(timer_update()));
timer->start(1000);
}
3.4 请假信息存储
//请假
void Widget::on_pushButton_leave_clicked()
{
//在数据库创建请假模块学生信息表
CreateLeaveSurface();
//填写请假信息
QString number=ui->lineEdit_leave_number_in->text();
if(number.isEmpty())
{
QMessageBox::information(this,"提示","请认真填写学号.",
QMessageBox::Ok,QMessageBox::Ok);
return;
}
//请假事由
QString text=ui->lineEdit_text->text();
if(text.isEmpty())
{
QMessageBox::information(this,"提示","请填写事由.",
QMessageBox::Ok,QMessageBox::Ok);
return;
}
Log_Text_Display(QString("请假查询的学号:%1.\n").arg(number));
//查询到学号选中表格
//指定操作的数据库
QSqlQuery sql_query(database);
//查询全部数据
sql_query.prepare("select * from student");
if(!sql_query.exec())
{
Log_Text_Display("学生数据库查询错误.\n");
}
else
{
bool flag=1;
while(sql_query.next())
{
// ID、学号、姓名、电话、状态
int find_id = sql_query.value(0).toInt(); //ID
QString find_number = sql_query.value(1).toString(); //学号
QString find_name = sql_query.value(2).toString(); //姓名
QString find_phone = sql_query.value(3).toString(); //电话
QString find_state = sql_query.value(4).toString(); //状态
//
//查找学号
if(find_number == number)
{
flag=0;
//返回行数。
int RowCount=ui->tableWidget_leave->rowCount(); //获取当前总行数
ui->tableWidget_leave->setRowCount(RowCount+1); //设置行数
int i;
//通过总列数创建单元格
for(i=0;i<ui->tableWidget_leave->columnCount();i++)
{
ui->tableWidget_leave->setItem(RowCount,i,new QTableWidgetItem(""));
//设置文本对齐方式
ui->tableWidget_leave->item(RowCount,i)->setTextAlignment(Qt::AlignHCenter|Qt::AlignVCenter);
}
//设置签到状态
QDateTime current_date_time =QDateTime::currentDateTime();
QString current_date =current_date_time.toString("yyyy.MM.dd");
find_state=QString("时间: %1 事由: %2").arg(current_date).arg(text);
//设置表格显示的数据
ui->tableWidget_leave->item(RowCount,0)->setText(find_number);
ui->tableWidget_leave->item(RowCount,1)->setText(find_name);
ui->tableWidget_leave->item(RowCount,2)->setText(find_phone);
ui->tableWidget_leave->item(RowCount,3)->setText(find_state);
//存放到数据库
//准备插入数据
//查询最大ID
QString select_max_sql = "select max(id) from leave";
int max_id = 0;
sql_query.prepare(select_max_sql);
if(!sql_query.exec())
{
Log_Text_Display("请假表最大ID查找失败.\n");
}
else
{
while(sql_query.next())
{
max_id = sql_query.value(0).toInt();
}
Log_Text_Display(QString("data base max id:%1\n").arg(max_id));
//添加数据
//插入数据 插入语句:insert into <table_name> values (value1, value2,…);
QString insert_sql = tr("insert into leave values(?,?,?,?,?)");
sql_query.prepare(insert_sql);
//ID、学号、姓名、电话、事由
sql_query.addBindValue(max_id+1); //id
sql_query.addBindValue(find_number);
sql_query.addBindValue(find_name);
sql_query.addBindValue(find_phone);
sql_query.addBindValue(find_state);
if(!sql_query.exec())
{
Log_Text_Display("请假表数据插入失败.\n");
return;
}
else //插入成功
{
//插入成功就清除页面
ui->lineEdit_leave_number_in->clear();
ui->lineEdit_text->clear();
}
}
break;
}
}
if(flag)
{
QMessageBox::information(this,"提示","未查找到此学号.",
QMessageBox::Ok,QMessageBox::Ok);
return;
}
}
}