
课程设计
题 目: 考勤管理系统
专 业: 计算机科学与技术
年 级: 大二
班 级:
学 号:
姓 名:
指导老师 :
完成时间 : 2017年6月8号
一、实验目的
数据库系统课程设计是为了配合数据库原理及应用开发而设置的,是计算机科学与技术、网络工程、信息安全、物联网工程、软件工程等专业集中实践的教学环节,是将关系数据库理论知识转化为解决实际问题能力的重要环节。数据库系统课程设计目的在于加深对关系数据库理论知识的理解,通过使用具体的 DBMS,掌握一种实际的数据库管理系统并掌握其操作技术,熟练掌握使用数据库前端开发工具(如 VB、 C++、 Java、 Delphi、 PowerBuilder等),进一步提高同学们运用数据库技术解决实际问题的能力。
二、实验平台
●PowerDesigner
●Axure
●Sql sever 2005
●QT 5.6
三、实验内容
目前市面上流行的后台数据库管理系统有:适合大型企业的Oracle,适合中小型企业的SQL SERVER,以及开源的 MySQL。考虑到数据库管理系统的易操作性以及实验室的实际情况,本次课程设计推荐使用 SQL SERVER 作为课程设计的后台数据库管理系统,也可以使用MySQL或 Oracle 等。前台数据库应用开发工具有 VB、PB、Delphi、VC、Java,以及广泛流行于互联网上的.NET、J2EE 技术等。.NET、J2EE 技术采用的是典型的 B/S 计算模式,是大学后续课程涉及到的开发技术,目前不适合本次课程设计实践教学开发环境。经典的桌面数据库应用开发是典型的 C/S计算模式,即应用数据库前端开发工具编写客户端程序,通过客户端程序来连接和访问后台数据库。考虑到同学们都学习过C/C++,因此,本次选用VC++作为前台数据库开发工具(也可以选用VB、Delphi、Java 等)。
两周的课程设计要求同学们开发一个小型数据库管理信息系统。所设计的小型管理信息系统应包含查询、插入、删除、修改、统计、用户权限管理等基本功能,界面采用菜单或对话框的形式。根据同学们所选的设计课题,给出系统需求分析,设计出系统的概念模型、逻辑模型,用SQL语言实现数据库的建立、应用和维护,最后写出详细的设计说明书。
四、实验要求
考勤制度是每个企事业单位所必需的,计算机的出现使员工出勤情况的记录和统计变得十分简单。
考勤管理系统的主要功能如下:
●上下班时间的设定。上下班时间相对固定,可保存在客户端的设置文件中。
●员工出入单位的情况记录。出入情况主要由考勤机来记录,但是需要设置人工添加的功能,以针对特殊情况的处理。
●请假、加班和出差情况的记录。
●每个月底进行整个月的出勤情况统计。
考勤系统记录了员工上下班的情况,为工资管理直接提供每个月工作时间的统计结果,用以计算工资。同时考勤系统也需要其它系统提供的员工、部门等信息。
五、实验步骤
1.系统需求分析
1.1系统功能分析
考勤管理系统的主要功能如下:
●上下班时间的设定。上下班时间相对固定,可保存在客户端的设置文件中。
●员工出入单位的情况记录。出入情况主要由考勤机来记录,但是需要设置人工添加的功能,以针对特殊情况的处理。
●请假、加班和出差情况的记录。
●每个月底进行整个月的出勤情况统计。
1.2系统功能模块设计(划分)
本系统功能模块如图 1所示。
1.3与其它系统的关系
考勤系统记录了员工上下班的情况,为工资管理直接提供每个月工作时间的统计结果,用以计算工资。同时考勤系统也需要其它系统提供的员工、部门等信息。
1.4数据流程图
系统的数据流程如图 2所示。出勤的原始时间记录主要来源于考勤机,并且以固定格式保存的数据库中。考勤管理系统的任务是如何处理这些数据。
2.数据库设计
2.1数据库需求分析
根据数据流程,可以列出以下管理系统所需的数据项和数据结构
●出勤记录:记录号、员工、出入情况、出入时间。
●请假记录:记录号、员工、假期起始时间、假期结束时间、请假缘由。
●加班记录:记录号、员工、加班时间长度、日期。
●出差记录:记录号、员工、出差起始时间、出差结束时间、具体描述。
●月度考勤统计:记录号、员工、年月、累计正常工作时间、累计请假时间、累计加班时间、累计出差时间、迟到次数、早退次数、旷工次数
所需的外部数据支持:
●人员信息:员工号、密码、权限、姓名、部门、当前状态等
●部门设置:部门编号、名称等
2.2数据库概念结构设计
图 3是本系统所需数据的E-R 模型图。
2.3数据库逻辑结构设计
根据系统的 E-R 图,总共需要 8 个数据表的数据支持。其中人员信息和部门设置可以使用人事管理系统中已有的数据表,而出勤记录、月度考勤统计、请假、加班、出差表和上下班时间表需要设计。这8个数据表的结构如表 1到表 8所示。
表1 ATTENDANCE出勤记录表
| 名称 | 代码 | 数据类型 |
| 记录编号 | ID | Number (20) |
| 出入状态 | IN_OUT | Characters (2) |
| 出入时间 | IO_TIME | Date & Time |
| 名称 | 代码 | 数据类型 |
| 记录编号 | ID | Number (20) |
| 统计年月 | YEAR_MONTH | Date & Time |
| 累计工作时间 | WORK_HOUR | Integer |
| 累计请假时间 | LEAVE_HDAY | Integer |
| 累计加班时间 | OVER_HOUR | Integer |
| 累计出差时间 | ERRAND_HDAY | Integer |
| 迟到次数 | LATE_TIMES | Integer |
| 早退次数 | EARLY_TIMES | Integer |
| 旷工次数 | ABSENT_TIMES | Integer |
| 名称 | 代码 | 数据类型 |
| 记录编号 | ID | Number (20) |
| 起始时间 | START_TIME | Date & Time |
| 结束时间 | END_TIME | Date & Time |
| 缘由 | REASON | Text |
| 名称 | 代码 | 数据类型 |
| 记录编号 | ID | Number (20) |
| 加班时间 | WORK_HOURS | Integer |
| 日期 | WORK_DATE | Date & Time |
| 名称 | 代码 | 数据类型 |
| 记录编号 | ID | Number (20) |
| 起始时间 | START_TIME | Date & Time |
| 结束时间 | END_TIME | Date & Time |
| 具体描述 | DESCRIPSION | Text |
| 名称 | 代码 | 数据类型 |
| 员工号 | PERSON_ID | Number (20) |
| 密码 | PERSON | Variable characters (20) |
| 权限 | AUTHORITY | Text |
| 姓名 | NAME | Variable characters (20) |
| 性别 | SEX | Characters (2) |
| 生日 | BIRTHDAY | Date & Time |
| 所在部门 | DEPARTMENT | Variable characters (20) |
| 职务 | JOB | Variable characters (20) |
| 受教育程度 | EDU_LEVEL | Variable characters (20) |
| 专业技能 | SPECIATY | Text |
| 家庭住址 | ADDRESS | Text |
| 联系电话 | TEL | Number (20) |
| 电子信箱 | Text | |
| 当前状态 | STATE | Characters (2) |
| 备注 | REMARK | Text |
| 名称 | 代码 | 数据类型 |
| 部门编号 | ID | Number (20) |
| 部门名称 | NAME | Text |
| 部门经理 | MANAGER | Variable characters (20) |
| 简介 | INTRO | Text |
| 名称 | 代码 | 数据类型 |
| 季节 | Season | Variable characters (20) |
| 上班 | Go_to_work | Date & Time |
| 下班 | Go_off_work | Date & Time |
Power Designer 是Sybase公司的CASE工具集,使用它可以方便地对管理信息系统进行分析设计,他几乎包括了数据库模型设计的全过程。利用Power Designer可以制作数据流程图、概念数据模型、物理数据模型,还可以为数据仓库制作结构模型,也能对团队设计模型进行控制。
SQL Server 是Microsoft 公司推出的关系型数据库管理系统。数据库引擎为关系型数据和结构化数据提供了更安全可靠的存储功能,使您可以构建和管理用于业务的高可用和高性能的数据应用程序。
具体过程如下:
●打开PowerDesigner16,新建一个概念模型项目,将上面进行需求分析和数据库设计所得的表在软件中表示出来,同时将各个表之间的联系给关联好。
●概念模型设计好之后,选择 Tools -> Generate Physical Date Model ,在 DBMS 选项中选择想要生成脚本的对应的数据库,我这里选择的是对应的 Microsoft SQL Server 2005 ,点击确定即可生成对应数据库的物理模型。
●生成物理模型之后,再检查下实体之间是不是有一些和预计的不同的地方,有的话则是概念模型的设计不正确,需要重复第一步,没有的话就可以继续下一步。
●检查完物理模型之后,就可以将建立的模型以SQL脚本的形式导出来,具体操作是 Datebase -> Generate Datebase ,再点确定就可以将脚本导出来。
●打开SQL Server Management Studio ,在自己的数据库位置单击右键,选择 新建查询 ,然后导入上一步生成的SQL脚本,选择 执行 即可将在PowerDesigner16中设计好的物理模型生成在SQL Server Managemenat Studio中,至此,数据库的设计与建立工作完成。
2.5使用Axure RP 8 进行界面的设计
Axure RP是美国Axure Software Solution公司旗舰产品,是一个专业的快速原型设计工具,让负责定义需求和规格、设计功能和界面的专家能够快速创建应用软件或Web网站的线框图、流程图、原型和规格说明文档。
具体过程如下:(以登陆界面为例)
●首先明确登录界面需要多少的输入框和标签以及按钮,需要多少就拖多少到中间的空白处去。
●为了能够更好地理解各个控件是干什么用的,最好把对象名给改成自己能够理解的。
●按照自己喜欢的风格摆放各个控件的位置,调整属性。
●具体教程可以参考百度。
3.各功能模块的设计与实现
3.1功能说明
a)上下班时间设置
系统默认采用每个季节八点上班,晚上十点下班,在上下班时间设置模块中能够更改选中季节的上下班时间。
b)添加修改出勤记录
通过系统选用上班(I)或者下班(O)进行出勤记录的添加,如果上班记录添加的时间晚于当个季节的上班时间,则会在迟到记录中加一,下班也是同样的道理。
c)加班记录
通过系统可以选择添加加班小时数,同时添加加班记录的时刻会被记录在记录表中。
d)请假记录
通过系统可以添加请假记录,选择请假的起始时间和结束时间后,系统会自动将请假的时间记录到记录表中。
e)出差记录
通过系统可以添加出差记录,选择出差的起始时间和结束时间后,系统会自动将出差的时间记录到记录表中。
f)考勤统计
系统可以自动汇总出勤表、加班表、请假表、出差表的数据,计算出每个员工的考勤情况如加班小时数和迟到次数等等。
3.2用户界面设计
完成数据库创建和功能说明以后,我们可以进行下一步工作,即设计用户界面。
a)登录认证窗口
登录认证采用两种身份验证方式,管理员方式和员工方式。
b)主窗体
主窗体用来选择所要执行的功能。
c)上下班时间设置窗体
上下班时间窗体用来设置选中季节的对应上下班时间。
d)考勤修改窗体
考勤修改窗体用来记录每次的上下班时间。
e)添加修改出勤记录界面
出勤修改界面用来修改出勤记录,如迟到次数和早退次数等等。
f)加班记录界面
加班记录界面用来记录加班信息。
g)请假记录界面
请假记录界面用来记录请假信息。
h)出差记录界面
出差记录界面用来记录出差信息。
i)考勤统计窗口
考勤统计窗口用来显示或者全部删除或者指定删除统计信息。
j)注册窗口
注册窗口用来注册新员工信息。
k)忘记密码窗口
忘记密码窗口用来重置密码。
l)提交成功窗口
提交成功窗口用来显示提交是否成功。
3.3各功能模块的实现
a)数据模块的创建
数据模块的创建通过导入PowerDesignr16生成的脚本文件生成,导入的是数据的结构,也可以和脚本一起导入数据,但是我选择的是手动输入数据。
b)上下班时间设置
上下班时间的设置在与数据库连通之后,首先通过select语句查找出当前选择的季节的上下班时间,然后通过update进行上下班时间的更新。
c)添加修改出勤记录
出勤记录的修改首先通过select查询到对应员工号,如果没有对应员工号则询问是否要添加到员工表中,如果添加的话,顺便也会给统计表中插入一条新员工的记录。查询成功后即可选择迟到次数和早退次数等等,输入相应的值再按下提交(update)后即可将出勤信息修改。
d)加班记录
加班记录的增加首先通过select查询到对应员工号,如果没有对应员工号则询问是否要添加到员工表中,如果添加的话,顺便也会给统计表中插入一条新员工的记录。查询成功后即可增加加班信息,加班信息包括加班时长和加班日期,按下提交(insert)后即可将加班记录增加到加班记录表中。
e)请假记录
请假记录的增加首先通过select查询到对应员工号,如果没有对应员工号则询问是否要添加到员工表中,如果添加的话,顺便也会给统计表中插入一条新员工的记录。查询成功后即可增加请假信息,请假信息包括请假的起始时间和结束时间以及请假的缘由,按下提交(insert)后即可将请假记录增加到请假记录中。
f)出差记录
出差记录的增加首先通过select查询到对应员工号,如果没有对应员工号则询问是否要添加到员工表中,如果添加的话,顺便也会给统计表中插入一条新员工的记录。查询成功后即可增加出差信息,出差信息包括出差的起始时间和结束时间以及出差的缘由,按下提交(insert)后即可将出差记录增加到出差记录中。
g)考勤统计
考勤统计通过将各个分表如出勤表、请假表等表进行汇总,汇总出的数据存入考勤统计表中。
4.系统实现
4.1系统总体设计
系统总体采用面向对象设计方法进行设计开发。对象指的是类的实例。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。加上QT所采用的就是C++的编程方法,选用面向对象编程方式成为了一种必然。
从以上对数据库和功能的分析总结出本系统需要一个登录模块,一个注册模块,一个找回密码模块,一个功能选择模块,一个上下班时间设置模块,一个出勤登记模块,一个考勤修改模块,一个请假登记模块,一个出差登记模块,一共是九个模块。
ODBC数据库访问技术只适用于windows系统,因为需要在ODBC驱动程序管理器中进行数据源注册,而只有windows才集成了ODBC驱动程序管理器(“控制面板/管理工具/数据源”)。ADO(ActiveX Data Object)具有跨系统平台特性,它直接对DBMS数据库进行操作,即系统中必须有DBMS,但不需要驱动程序,不需要注册数据源,所以具有很好的可移植性。由于开发环境选在Windows XP,使用的数据库为Microsoft SQL Server 2005,因此采用ODBC的连接方式而不是ADO方式。
得益于采用面向对象的方式开发,软件在开发过程中的测试可以采用单元测试方法,测试每个模块即可,最后再组装到一起进行集成测试,这样可以尽可能地节省时间。
4.2ODBC连接方式的实现
开放数据库连接(Open Database Connectivity,ODBC)是微软公司开放服务结构(WOSA,Windows Open Services Architecture)中有关数据库的一个组成部分,它建立了一组规范,并提供了一组对数据库访问的标准API(应用程序编程接口)。这些API利用SQL来完成其大部分任务。ODBC本身也提供了对SQL语言的支持,用户可以直接将SQL语句送给ODBC。这里我们只需要知道基本的ODBC连接方式和配制方法即可。
Windows已经包含了应用程序、驱动管理器、驱动程序以及数据源,我们所要做的就是配置好数据源,具体配置方法如下:
●打开 控制面板 -> 管理工具 -> 数据源(ODBC)。
●单击 添加 按钮,准备添加一个新的数据源,这个数据源是与自己所写的程序相关的。填写好名称,这个名称和后面程序进行ODBC连接有至关重要的联系,服务器选择数据库所在的服务器,完毕之后选择下一步。
●如图所示选择连接方式,输入正确的账号密码,单击下一步。
●默认的数据库更改为要操作的数据库,点击下一步。
●一直按下一步直到完成,然后单击 测试数据源 ,如果测试成功则ODBC配置成功,可以进行接下来的工作。
接下来就是在QT中实现使用ODBC方式连接数据库:
●在QT中使用数据库操作需要添加对应的头文件,以及在工程文件中添加对SQL的支持。
●添加完成后即可通过代码进行数据库的连接
●其中,QSqlDatebase::addDatebase(“QODBC”) 为添加ODBC的驱动到QT程序中,没有驱动的话也就无法正确连接数据库。setHostName("416-12") 为设置想要连接的主机的名字,如果是远程服务器的话也可以直接输入IP地址。setDatabaseName("sqlserver") 为设置数据库的连接名,这里就用到了之前设置数据源时的名称,这个连接名需要和数据源里面的名称一样才能连接。setUserName("sa") 和 setPassword("sa520") 分别为设置登陆账号和密码,如果采用的是Windows账户登陆的话就不需要设置这两项,不是的话就需要设置。最后的那个open() 是用来判断是不是已经打开对应的数据库,成功的话会返回true ,否则就是false ,表示不成功,需要重新设置。
此外,在Microsoft SQL Server Management Studio中可以直接导出对应表的增、删、查、改脚本,具体方法如下:
●到这里也就结束了ODBC连接方式的实现,接下来可以根据对应的功能写代码了。
4.3登陆界面的实现
登录界面所需要的东西主要是用户和管理员单选框、账号和密码输入框、登录按钮、注册账号按钮和找回密码按钮,这里列出我的一些主要的控件:
| 控件类型 | 控件名 | 用途说明 |
| QLabel | TitleLabel | 标题 |
| QPushButton | RegisterButton | 注册 |
| ForgetPushButton | 忘记密码 | |
| LandButton | 登陆 | |
| pushButton | 重置输入框 | |
| QRadioButton | user_radioButton | 用户按钮 |
| admin_radioButton | 管理员按钮 | |
| QLineEdit | AccountEdit | 账户输入 |
| PasswordEdit | 密码输入 |
需要注意的是:
●四周的弹簧是用来固定比例的,这样可以在改变窗口大小的时候动态改变各个控件的大小。
●背景的改变放在该类的构造函数中,使用自动填充全部。
●密码输入时显示为加密模式,使用ui->PasswordEdit->setEchoMode(QLineEdit::Password);
●回车的焦点设置为登陆按钮
●按下登陆或注册或忘记密码时会将当前窗口隐藏,同时打开对应的窗口。
4.4注册界面的实现
用户注册界面主要用到的是两个按钮,一个提交,一个返回,其他的均为输入框,主要控件如下:
| 控件类型 | 控件名 | 用途说明 |
| QPushButton | SubmitButton | 提交 |
| ReturnButton | 返回 | |
| QLineEdit | PersonNumberLineEdit | 输入用户名 |
| PasswordLineEdit | 输入密码 | |
| NameLineEdit | 输入姓名 | |
| TELLineEdit | 输入手机号码 | |
| QDate | BirthdayDateEdit | 选择生日 |
需要注意的是:
●必须输入的为员工号,其他可以填也可以不填,不填的话就找不回密码。
4.5找回密码的实现
找回密码界面主要使用三个按钮,四个输入框,部分主要控件如下:
| 控件类型 | 控件名 | 用途说明 |
| QPushButton | PasswordPushButton | 确认用户名 |
| SubmitPushButton | 提交 | |
| ReturnPushButton | 返回 | |
| QLineEdit | PersonNumberLineEdit | 输入用户名 |
| NameLineEdit | 输入密码 | |
| TELLineEdit | 输入手机号 | |
| NewPasswordLineEdit | 输入新密码 |
需要注意的是:
●如果注册时没有输入姓名和手机号,在这里是找不回密码的,只有联系管理员在数据库中修改。
4.6主界面的实现
主界面主要使用七个按钮,部分主要控件如下:
| 控件类型 | 控件名 | 用途说明 |
| QPushButton | WorkSetButton | 上下班时间 |
| WorkAttendanceButton | 考勤修改 | |
| AttendanceButton | 出勤管理 | |
| OverTimeButton | 加班管理 | |
| LeaveButton | 请假管理 | |
| ErrandButton | 出差管理 | |
| WorkAttendanceStatisticsButton | 考勤统计 |
需要注意的是:
●四周的弹簧和之前的一样,都是为了维持固定比例不变形。
●每个按钮是交叉分布的,所以有图的部分是点不了的。
4.7上下班时间设置的实现
上下班时间设置界面主要使用两个显示标签,四个按钮,两个下拉框和两个时间设置框,部分主要控件如下:
| 控件类型 | 控件名 | 用途说明 |
| QLabel | CurrentUpTimeShowLable | 显示当前上班时间 |
| CurrentDownTimeShowLable | 显示当前下班时间 | |
| QPushButton | UpSubmitButton | 提交上班时间更改 |
| DownSubmitButton | 提交下班时间更改 | |
| InitializationButton | 初始化上下班时间 | |
| BackButton | 返回 | |
| QComboBox | up_season_comboBox | 上班季节下拉框 |
| down_season_comboBox | 下班季节下拉框 | |
| QTimeEdit | Down_timeEdit | 下班时间设置框 |
| Up_timeEdit | 上班时间设置框 |
需要注意的是:
●重置为初值只能重置当前页面的,而不是重置全部。
●系统默认上班时间上午八点,下班时间晚上十点。
●上下班时间表是存在数据库中的,而不是存在程序之中。
4.8考勤修改的实现
考勤修改界面主要使用九个按钮,八个输入框和七个显示标签,部分主要控件如下:
| 控件类型 | 控件名 | 用途说明 |
| QPushButton | PersonSubmitButton | 提交员工号 |
| returnButton | 返回 | |
| ChangeWorkSubmitButton | 工作时间修改提交 | |
| ChangeOvertimeSubmitButton | 加班时间修改提交 | |
| ChangeLeaveSubmitButton | 请假时间修改提交 | |
| ChangeErrandSubmitButton | 出差时间修改提交 | |
| ChangeLateSubmitButton | 迟到次数修改提交 | |
| ChangeLeaveearlySubmitButton | 早退次数修改提交 | |
| ChangeAbsenteeismSubmitButton | 旷工次数修改提交 | |
| QLineEdit | PersonlineEdit | 员工号输入 |
| WorkTimeChange_lineEdit | 改变的工作时间 | |
| OverTimeChange_lineEdit | 改变的加班时间 | |
| LeaveTimeChange_lineEdit | 改变的请假时间 | |
| ErrandTimeChange_lineEdit | 改变的出差时间 | |
| LateTimesChange_lineEdit | 改变的迟到次数 | |
| LeaveEarlyTimesChange_lineEdit | 改变的早退次数 | |
| AbsenteeismTimesChange_lineEdit | 改变的旷工次数 | |
| QLabel | CurrentWorkTimeNumberLabel | 显示当前工作时间 |
| CurrentOvertimeTimeNumberLabel | 显示当前加班时间 |
| CurrentLeaveTimeNumberLabel | 显示当前请假时间 | |
| CurrentErrandTimeNumberLabel | 显示当前出差时间 | |
| CurrentLateTimesNumberLabel | 显示当前迟到次数 | |
| CurrentLeaveearlyTimesNumberLabel | 显示当前早退次数 | |
| CurrentAbsenteeismTimesNumberLabel | 显示当前旷工次数 |
需要注意的是:
●只有输入了员工表中已有的员工号才能进行更改。
●如果输入的员工号不存在,可以选择新建一个员工信息,
4.9出勤记录的实现
出勤记录界面主要使用三个按钮,一个输入框,两个单选框和一个时间设置框,部分主要控件如下:
| 控件类型 | 控件名 | 用途说明 |
| QPushButton | PersonNumberSubmitButton | 提交员工号 |
| SubmitButton | 提交出勤信息 | |
| ReturnButton | 返回 | |
| QLineEdit | PersonNumberEditLine | 输入员工号 |
| QRadioButton | IN_radioButton | 选择上班 |
| OUT_radioButton_2 | 选择下班 | |
| QDateTimeEdit | IN_OUT_dateTimeEdit | 上下班时间记录 |
需要注意的是:
●只有输入了员工表中已有的员工号才能进行信息记录。
●必须选择上班或者是下班,否则会提示错误无法提交信息。
4.10加班记录的实现
加班记录界面主要使用三个按钮,一个输入框,一个双精度自旋框和一个时间设置框,部分主要控件如下:
| 控件类型 | 控件名 | 用途说明 |
| QPushButton | PersonNumberSubmitButton | 提交员工号 |
| SubmitButton | 提交信息 | |
| ReturnButton | 返回 | |
| QLineEdit | PersonNumberlineEdit | 输入员工号 |
| QDoubleSpinBox | OvertimeLengthdoubleSpinBox | 输入加班时长 |
| QDateTimeEdit | OvertimeDatedateEdit | 加班记录日期 |
需要注意的是:
●只有输入了员工表中已有的员工号才能进行信息记录。
●这里的加班日期是指加班的那天而不是进行记录的那天。
4.11请假记录的实现
请假记录界面主要使用三个按钮,两个输入框和两个时间选择框,部分主要控件如下:
| 控件类型 | 控件名 | 用途说明 |
| QPushButton | PersonSubmitButton | 提交用户名 |
| SubmitButton | 提交信息 | |
| ReturnButton | 返回 | |
| QLineEdit | PersonEditLine | 输入员工号 |
| QTextEdit | ReasontextEdit | 输入请假备注 |
| QDateTimeEdit | LeaveBegin_dateTimeEdit | 请假起始时间 |
| LeaveEnd_dateTimeEdit | 请假结束时间 |
需要注意的是:
●只有输入了员工表中已有的员工号才能进行信息记录。
●请假缘由字数没有。
4.12 出差记录的实现
出差记录界面主要使用三个按钮,两个输入框和两个时间设置框,部分主要控件如下:
| 控件类型 | 控件名 | 用途说明 |
| QPushButton | PersonSubmitButton | 提交员工号 |
| SubmitButton | 提交信息 | |
| ReturnButton | 返回 | |
| QLineEdit | PersonEditLine | 输入员工号 |
| QTextEdit | Description_textEdit | 输入出差备注 |
| QDateTimeEdit | ErrandBegin_dateTimeEdit | 出差起始时间 |
| ErrandEnd_dateTimeEdit | 出差结束时间 |
需要注意的是:
●只有输入了员工表中已有的员工号才能进行信息记录。
●具体描述部分没有字数。
4.13 考勤统计和记录删除的实现
考勤统计和记录删除界面主要使用四个按钮和一个表格显示视图,部分主要控件如下:
| 控件类型 | 控件名 | 用途说明 |
| QPushButton | ChooseDeleteButton | 选中行删除 |
| AllClearButton | 全部删除 | |
| ShowStatisticButton | 显示统计信息 | |
| ReturnButton | 返回 | |
| QTableView | showTableView | 显示表格 |
需要注意的是:
●这里说的删除不是删除当前行,而是删除与当前表格相关的员工的信息,如加班表、出勤表中的相关信息全部删除。
●选中删除必须选中一行,否则会直接删除第一行的员工相关信息。
六、 实验心得
本实验如果采用的是实验指导书中的方法去做的话,过程会稍显复杂,于是我选择了我比较熟悉的QT来做,能够节约时间,实验期间主要心得与收获如下:
1.实验本身并不是很难,因为大多的实现方法就是增、删、查、改四项,真正有问题的是实现部分,因为要考虑到各个组件和界面的交互操作。
2.代码本身不难写,难的是数据库的设计和界面的美工,这两个方面是这么久一直没有涉及过的,尤其是界面的美工,对于我这种审美有点不对劲的人来说,别人觉得好看的我不一定觉得好看,我觉得好看的别人觉得很难看。数据库的设计也是,要详细分析好各个数据项的数据类型,否则编写代码的时候会出现很严重的类型匹配错误。
3.好的开发工具很重要。像VC++ 6.0这个软件年代太久远了,但是机房的电脑又装不了我另一个比较熟悉的VS2015,所以只能锁定在QT。而且QT的版本选择也是很重要,之前花了一天的时间下了又删,从QT5.9开始一直试到了QT5.6才能在XP系统上用,但是磨刀不误砍柴工,这点时间上的花费是值得的。
4.完成题目所要求的功能大概只花了两天时间,但是剩下的时间也不能玩,我刚好可以把最近学的 《重构 改善既有代码的设计》这本书上的东西运用到实际上来,对我的代码进行重构,这个过程很痛苦,因为有些地方改了之后就会报错,花费很多时间来换条路进行重构。但是结局是开心的,因为最后完成了我的目标,使得代码的整洁度、可读性和鲁棒度都得到了不小的提升。
七、部分代码展示
//attendance_change.cpp
void Attendance_Change::on_PersonNumberSubmitButton_clicked() //确定按钮
{
exist = false; //判断员工号是否存在
personNumber = ui->PersonNumberEditLine->text();
QSqlQuery sqlquery;
sqlquery.exec("SELECT [PERSON]"
"FROM [TYX_DB_Attendance].[dbo].[PERSON]");
while(sqlquery.next()){
QString tempPersonID = sqlquery.value(0).toString();
if(tempPersonID.compare(personNumber) == 0){ // 如果存在和输入的相同的员工号,则可以直接使用
exist = true;
}
}
if(exist){
QMessageBox::warning(this,"Query was successful
ui->groupBox_2->show();
ui->groupBox_3->show();
ui->SubmitButton->show();
}
else{ //不存在输入的员工号,选择新建或者不新建返回
int ret = QMessageBox::question(this,"Query failed
if(ret == QMessageBox::Yes){
sqlquery.prepare("INSERT INTO [TYX_DB_Attendance].[dbo].[PERSON]([PERSON],[PASSWORD])"
"VALUES"
"(:PERSON,:PASSWORD)");
sqlquery.bindValue(":PERSON",personNumber);
sqlquery.bindValue(":PASSWORD",personNumber);
sqlquery.exec();
//插入新员工到考勤表
stat_insert();
ui->groupBox_2->show();
ui->groupBox_3->show();
ui->SubmitButton->show();
}
}
//获取记录条数
QSqlQuery sqlqueryID;
sqlqueryID.exec("SELECT [ID]"
"FROM [TYX_DB_Attendance].[dbo].[ATTENDANCE]");
if(sqlqueryID.last()){
IDNumber = sqlqueryID.value(0).toInt() + 1 ;
}
}
void Attendance_Change::on_SubmitButton_clicked() //提交按钮
{
QString IO_radio;
bool io_ok = false;
if(ui->IN_radioButton->isChecked()){
IO_radio = "I";
io_ok = true;
}
else if(ui->OUT_radioButton_2->isChecked()){
IO_radio = "O";
io_ok = true;
}
else{
QMessageBox::warning(this,"No choice
}
if(io_ok){
QSqlQuery sqlquery;
sqlquery.prepare("INSERT INTO [TYX_DB_Attendance].[dbo].[ATTENDANCE]([ID],[PERSON],[IN_OUT],[IO_TIME])"
"VALUES"
"(:ID"
",:PERSON"
",:IN_OUT"
",:IO_TIME)");
sqlquery.bindValue(":ID",IDNumber);
sqlquery.bindValue(":PERSON",personNumber);
sqlquery.bindValue(":IN_OUT",IO_radio);
sqlquery.bindValue(":IO_TIME",ui->IN_OUT_dateTimeEdit->dateTime());
if(sqlquery.exec()){
QMessageBox::information(this,"Submit successfully!
}
else{
QMessageBox::warning(this,"Submit failure",db.lastError().text());
}
IDNumber ++;
}
stat_addWorkTime();
}
void Attendance_Change::stat_addWorkTime(){
QTime time = QTime::currentTime();
//获得当前季节上下班时间
QTime up_time = QTime::currentTime();
QTime down_time = QTime::currentTime();
QSqlQuery sqlquery;
sqlquery.prepare("SELECT [Season],[Go_to_work],[Go_off_work]"
"FROM [TYX_DB_Attendance].[dbo].[Commuting schedule]"
"WHERE [Season] = ? ");
sqlquery.addBindValue(season);
sqlquery.exec();
sqlquery.next();
up_time = sqlquery.value(1).toTime();
down_time = sqlquery.value(2).toTime();
if(ui->IN_radioButton->isChecked()){
//如果迟到
if(time > up_time){
sqlquery.prepare("UPDATE [TYX_DB_Attendance].[dbo].[ATTENDANCE_STAT]"
"SET [YEAR_MONTH] = ? "
",[LATE_TIMES] = [LATE_TIMES] + 1 "
"WHERE [PERSON] = ? ");
sqlquery.addBindValue(QDateTime::currentDateTime());
sqlquery.addBindValue(personNumber);
sqlquery.exec();
}
}
else if(ui->OUT_radioButton_2->isChecked()){
//如果早退
if(time < down_time){
sqlquery.prepare("UPDATE [TYX_DB_Attendance].[dbo].[ATTENDANCE_STAT]"
"SET [YEAR_MONTH] = ? "
",[EARLY_TIMES] = [EARLY_TIMES] + 1 "
"WHERE [PERSON] = ? ");
sqlquery.addBindValue(QDateTime::currentDateTime());
sqlquery.addBindValue(personNumber);
sqlquery.exec();
}
}
//工作时间计算
int worktime = 0;
sqlquery.prepare("SELECT t1.[PERSON], t1.[IO_TIME], t2.[IO_TIME] "
"FROM [TYX_DB_Attendance].[dbo].[ATTENDANCE] AS t1 , [TYX_DB_Attendance].[dbo].[ATTENDANCE] AS t2 "
"WHERE t1.[PERSON] = ? AND t1.[IN_OUT] = 'I' AND t1.[IN_OUT] <> t2.[IN_OUT] AND t1.[PERSON] = t2.[PERSON]");
sqlquery.addBindValue(personNumber);
sqlquery.exec();
while(sqlquery.next()){
if(sqlquery.value(1).toDate() == sqlquery.value(2).toDate()){
worktime += sqlquery.value(2).toTime().hour() - sqlquery.value(1).toTime().hour();
// qDebug() << sqlquery.value(2).toDateTime() << sqlquery.value(1).toDateTime() << worktime ;
}
}
//工作时间插入统计表
sqlquery.prepare("UPDATE [TYX_DB_Attendance].[dbo].[ATTENDANCE_STAT]"
"SET [YEAR_MONTH] = ? "
",[WORK_HOUR] = ? "
"WHERE [PERSON] = ? ");
sqlquery.addBindValue(QDateTime::currentDateTime());
sqlquery.addBindValue(worktime);
sqlquery.addBindValue(personNumber);
sqlquery.exec();
}
//attendance_statistics.cpp
void Attendance_Statistics::on_ChooseDeleteButton_clicked()
{
int ret = QMessageBox::question(this,"Clear This
if(ret == QMessageBox::Yes){
int row = ui->showTableView->currentIndex().row();
// qDebug() << row;
QSqlQuery sqlquery;
sqlquery.prepare("SELECT [PERSON]"
"FROM [TYX_DB_Attendance].[dbo].[ATTENDANCE_STAT]");
sqlquery.exec();
if(sqlquery.seek(row)){
personName = sqlquery.value(0).toString();
//删除考勤
sqlquery.prepare("DELETE FROM [TYX_DB_Attendance].[dbo].[ATTENDANCE]"
"WHERE [PERSON] = ? ");
sqlquery.addBindValue(personName);
sqlquery.exec();
//删除加班
sqlquery.prepare("DELETE FROM [TYX_DB_Attendance].[dbo].[OVERTIME]"
"WHERE [PERSON] = ? ");
sqlquery.addBindValue(personName);
sqlquery.exec();
//删除请假
sqlquery.prepare("DELETE FROM [TYX_DB_Attendance].[dbo].[LEAVE]"
"WHERE [PERSON] = ? ");
sqlquery.addBindValue(personName);
sqlquery.exec();
//删除出差
sqlquery.prepare("DELETE FROM [TYX_DB_Attendance].[dbo].[ERRAND]"
"WHERE [PERSON] = ? ");
sqlquery.addBindValue(personName);
sqlquery.exec();
//重置统计表
sqlquery.prepare("UPDATE [TYX_DB_Attendance].[dbo].[ATTENDANCE_STAT]"
"SET [YEAR_MONTH] = ? "
",[WORK_HOUR] = 0 "
",[LEAVE_HDAY] = 0 "
",[OVER_HOUR] = 0 "
",[ERRAND_HDAY] = 0 "
",[LATE_TIMES] = 0 "
",[EARLY_TIMES] = 0 "
",[ABSENT_TIMES] = 0 ");
sqlquery.addBindValue(QDateTime::currentDateTime());
sqlquery.exec();
//显示更改后的表
on_ShowStatisticButton_clicked();
}
}
}
