考勤系统
1、需求概述
1.1 背景
考勤已经成为人们上下班的一个必须过程,但是当今还是有许多是以纸质签到作为考勤。这样的考勤效率低,为了更好地解决这一问题,所以需要建立一个完善的考勤系统。
1.2 系统目标
建立考勤系统管理,提高考勤工作的效率和准确性,避免因为考勤问题影响正常工作,主要是实现员工上下班打卡考勤进行记录,对自己考勤信息的查询,另一个是管理人员对员工考勤记录的修改,激活或者注销员工信息。
1.3 功能需求
1.4 非功能需求
1.4.1 安全性
(1)该考勤系统对于安全性的考虑就是数据不被串改与丢失即可
(2)可以做到一人一号,降低出错概率
1.4.2 可靠性
(3)当系统出现故障和用户出现错误的操作后支持恢复
(4)当用户在使用过程中遇到错误的时候可以立即定位问题
(5)当网络不稳定或使用中异常中断的情况下系统有相应的容错措施
1.4.3 易使用性
(1)用户能够快速地找到所需功能并使用
(2)软件在熟练使用后应该可以更快的进行各项操作
1.4.4 可维护性
(1)管理员可以在后台查到公司员工各时间段的打卡记录
(2)管理员能在后台进行系统维护及个时间段一次的考勤记录统计,如有差错可修改考勤记录
1.4.5 性能需求
(3)估计公司员工为39人,每天登录员工数为25左右,网络的带宽为100M带宽。
(4)在非高峰时间根据工号或名字特定条件进行搜索,可以在3秒内得到搜索结果。
(5)当通过互联网接入系统的时候,期望在编号和名称搜索时最长查##询时间<10秒。
1.5 软件与硬件或其他外部系统接口
1.6 设计和实现的限制
(1)系统建设成本是否符合公司利益
(2)在连通互联网后,网络速率能否符合查询需求
(3)在系统出错时能否有及时的技术补救措施与完整的相对策略
(4)管理员的修改权限能否在技术上实现
2、系统数据库设计
2.1 第一步:标识实体
打卡机
员工
2.2 第二步:绘制ER图
2.3 第三步:制作数据表
2.4 第四步:生成数据库表
根据数据表建立数据库表,在员工数据库表中将编号设置为主键,打卡机表中将编号设置为外键,打卡表中把打卡号设置为主键,员工编号和打卡机编号设置为外键,在将他们联系起来。
(1) 根据数据表在数据库中新建punch(打卡机)表,并添加数据
USE [Attendance]
GO
/****** Object: Table [dbo].[punch] Script Date: 07/12/2019 16:49:35 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[punch](
[id] [varchar](50) NOT NULL,
[positon] [varchar](50) NULL,
CONSTRAINT [PK_punch] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
(2) 根据数据表在数据库中新建record(记录)表,并添加数据
USE [Attendance]
GO
/****** Object: Table [dbo].[record] Script Date: 07/12/2019 16:54:55 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[record](
[serial] [int] IDENTITY(1,1) NOT NULL,
[s_id] [varchar](50) NULL,
[date] [date] NULL,
[time] [time](0) NULL,
[p_id] [varchar](50) NULL,
CONSTRAINT [PK_record] PRIMARY KEY CLUSTERED
(
[serial] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[record] WITH CHECK ADD CONSTRAINT [FK_record_punch] FOREIGN KEY([p_id])
REFERENCES [dbo].[punch] ([id])
GO
ALTER TABLE [dbo].[record] CHECK CONSTRAINT [FK_record_punch]
GO
ALTER TABLE [dbo].[record] WITH CHECK ADD CONSTRAINT [FK_record_staff] FOREIGN KEY([s_id])
REFERENCES [dbo].[staff] ([id])
GO
ALTER TABLE [dbo].[record] CHECK CONSTRAINT [FK_record_staff]
GO
(3) 根据数据表在数据库中新建staff(职员)表,并添加数据
USE [Attendance]
GO
/****** Object: Table [dbo].[staff] Script Date: 07/12/2019 16:56:15 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[staff](
[id] [varchar](50) NOT NULL,
[name] [varchar](50) NULL,
[sex] [varchar](10) NULL,
[par] [varchar](50) NULL,
[role] [varchar](50) NULL,
[pwd] [varchar](50) NULL,
CONSTRAINT [PK_staff] PRIMARY KEY CLUSTERED
(
[id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_PADDING OFF
GO
3、考勤系统界面设计
3.1 登录界面设计
3.2 管理员主界面设计
3.2.1 新用户注册界面设计
3.3 职员主界面设计
4、考勤系统功能实现——登录、注册
4.1.1 登录界面及登录功能实现代码:
员工或者管理员输入账号和密码后即可实现登录
4.1.2登录功能实现代码如下:
(1)连接数据库
private void bt_Login_Click(object sender, EventArgs e)
{
String connStr = ConfigurationManager.ConnectionStrings["Attendance"].ConnectionString;
SqlConnection sqlConn = new SqlConnection(connStr);
try
{
// 连接数据库
sqlConn.Open();
// 构造命令发送给数据库
String sqlStr = "select * from staff where ID=@id and pwd=@pwd";
SqlCommand cmd = new SqlCommand(sqlStr, sqlConn);
// 注意是用用户ID登录,而不是用户名,用户名可能会重复
cmd.Parameters.Add(new SqlParameter("@id", this.tb_User.Text.Trim()));
cmd.Parameters.Add(new SqlParameter("@pwd", this.tb_Password.Text.Trim()));
SqlDataReader dr = cmd.ExecuteReader();
(2)连接数据库后,查询数据库记录,能否登录
// 如果从数据库中查询到记录,则表示可以登录
if (dr.HasRows)
{
dr.Read();
UserInfo.userId = int.Parse(dr["id"].ToString());
UserInfo.userName = dr["name"].ToString();
UserInfo.userPwd = dr["pwd"].ToString();
UserInfo.userRole = dr["role"].ToString();
MessageBox.Show(UserInfo.userRole + "登录成功");
(3)输入账号和密码后,判断登录人员的角色并跳转到相应的界面,并隐藏当前界面
if (UserInfo.userRole == "管理员")
{
// 显示收银员主界面
MainFormAdmin formAdmin = new MainFormAdmin();
formAdmin.Show();
// 隐藏登录界面
this.Hide();
}
if (UserInfo.userRole == "职员")
{
// 显示库管员主界面
MainFormUser formUser = new MainFormUser();
formUser.Show();
// 隐藏登录界面
this.Hide();
}
}
else
{
MessageBox.Show("用户名或密码错误", "提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
catch (Exception exp)
{
MessageBox.Show("访问数据库错误:" + exp.Message);
}
finally
{
sqlConn.Close();
}
}
4.2.1 注册界面
在新用户注册窗口启动时,自动从数据库中获取最大的员工编号,
并加1作为新员工编号.
//在新用户注册窗口启动时,自动从数据库中获取最大的员工编号,
并加1作为新员工编号。
String sqlStr = "select MAX(id+1) as id from employee";
4.2.2 实现注册职员信息功能代码:
在管理员界面实现注册员工信息,并能够将信息存储到后台数据库上
(1)连接数据库;构造查询命令
private void RecordForm2_Load(object sender, EventArgs e)
{
String connStr = ConfigurationManager.ConnectionStrings["Attendance"].ConnectionString;
SqlConnection sqlConn = new SqlConnection(connStr);
try
{
// 连接数据库
sqlConn.Open();
// 构造查询命令
String sqlStr = "select MAX(id+1) as id from staff";
SqlCommand cmd = new SqlCommand(sqlStr, sqlConn);
SqlDataReader dr = cmd.ExecuteReader();
if(dr.HasRows)
{
dr.Read();
this.tb_Id.Text = dr["id"].ToString();
}
}
catch (Exception exp)
{
MessageBox.Show("访问数据库错误:" + exp.Message);
}
finally
{
sqlConn.Close();
}
}
(2)点击“确认”按钮,录入职员信息
// 点击“确认”按钮,录入职员信息
private void bt_Ok_Click(object sender, EventArgs e)
{
String id = this.tb_Id.Text.Trim();
String name = this.tb_Name.Text.Trim();
String pwd = this.tb_Pwd.Text.Trim();
String sex = this.tb_sex.Text.Trim();
String par = this.tb_par.Text.Trim();
String role = this.tb_role.Text.Trim();
(3)更新数据库,并构造查询命令
// 更新数据库
String connStr = ConfigurationManager.ConnectionStrings["Attendence"].ConnectionString;
SqlConnection sqlConn = new SqlConnection(connStr);
try
{
// 连接数据库
sqlConn.Open();
// 构造命令
String sqlStr = "insert into staff(ID, NAME, PWD, SEX, PAR, ROLE) values(@id, @name, @pwd, @sex, @par, @role)";
SqlCommand cmd = new SqlCommand(sqlStr, sqlConn);
// SQL字符串参数赋值
cmd.Parameters.Add(new SqlParameter("@id", id));
cmd.Parameters.Add(new SqlParameter("@name", name));
cmd.Parameters.Add(new SqlParameter("@pwd", pwd));
cmd.Parameters.Add(new SqlParameter("@sex",sex));
cmd.Parameters.Add(new SqlParameter("@par", par));
cmd.Parameters.Add(new SqlParameter("@role", role));
(4)命令发送给数据库; 根据返回值判断是否插入成功
// 将命令发送给数据库
int res = cmd.ExecuteNonQuery();
// 根据返回值判断是否插入成功
if (res != 0)
{
MessageBox.Show("员工信息录入成功");
}
else
{
MessageBox.Show("员工信息信息录入失败");
}
}
catch (Exception exp)
{
MessageBox.Show("访问数据库错误:" + exp.Message);
}
finally
{
sqlConn.Close();
}
}
5、串口及串口编程
5.1 串口编程界面
(1)主要包括串口设置和注册新卡的功能界面 ,实现串口选择、读取卡片和写入卡片信息的功能:(2)功能效果实现
5.2 使用串口调试工具实现数据传输
(1)在下拉列表中列出本机所有串口
// TODO: 在下拉列表中列出本机所有串口
string[] ports = SerialPort.GetPortNames();//获取计算机可用串口
if (ports.Length > 0)//有可用串口
{
comboBoxCOMList.Items.AddRange(ports);//添加到下拉列表
comboBoxCOMList.SelectedIndex = 0;//默认选择第一项
}
(2)初始化串口参数
// TODO: 初始化串口参数
serialPort1.BaudRate = 115200;//波特率115200
serialPort1.DataBits = 8;
serialPort1.Parity = Parity.None;
serialPort1.StopBits = StopBits.One;
(3)将待发送数据发送出去
// TODO: 将`待发送数据`发送出去
string sendContent = this.tbWrite.Text.ToString();
this.serialPort1.Write(sendContent);
MessageBox.Show("已发送数据!");
(4)接收数据,并在接收数据区域显示出来
// TODO: 接收数据,并在接收数据区域显示出来
Control.CheckForIllegalCrossThreadCalls = false;
string str = serialPort1.ReadExisting().ToString();
tbRead.Text = str;
(5)清空接收区域
// TODO: 清空接收区域
tbRead.Text = "";
6、考勤系统功能实现——打卡
6.1 主要代码
private void Form1_Load(object sender, EventArgs e)
{
string[] ports = SerialPort.GetPortNames();//获取计算机可用串口
if(ports.Length > 0)//有可用串口
{
comboBoxCOMList.Items.AddRange(ports);//添加到下拉列表
comboBoxCOMList.SelectedIndex = 0;//默认选择第一项
}
comboBoxHandle.SelectedIndex = 0;
}
private void InitSerialPort()//初始化串口
{
serialPort1.BaudRate = 115200;//波特率115200
serialPort1.DataBits = 8;
serialPort1.Parity = Parity.None;
serialPort1.StopBits = StopBits.One;
serialPort1.ReceivedBytesThreshold = 1;
}
7、考勤系统功能实现——查询
7.1 界面展示
7.1.1 员工登陆查询后的界面
7.2 主要代码
连接数据库;构造命令发送给数据库
// 连接数据库
sqlConn.Open();
// 构造命令发送给数据库
String sqlStr = "select * from record where date>=@start and date<=@end and s_id = @id";
SqlCommand cmd = new SqlCommand(sqlStr, sqlConn);
cmd.Parameters.Add(new SqlParameter("@start", this.start.Value.ToShortDateString()));
cmd.Parameters.Add(new SqlParameter("@end", this.end.Value.ToShortDateString()));
cmd.Parameters.Add(new SqlParameter("@id", UserInfo.userId));
SqlDataAdapter adp = new SqlDataAdapter();
adp.SelectCommand = cmd;
将DataSet和DataAdapter绑定
// 将DataSet和DataAdapter绑定
DataSet ds = new DataSet();
自定义一个表(MyGoods)来标识数据库的GOODS表
// 自定义一个表(MyGoods)来标识数据库的GOODS表
adp.Fill(ds, "MyGoods");
指定DataGridView的数据源为DataSet的MyGoods表
// 指定DataGridView的数据源为DataSet的MyGoods表
this.dgv_Goods.DataSource = ds.Tables["MyGoods"];
8、考勤系统功能实现——统计
8.1 界面展示
8.1.1 管理员界面
8.1.2 考勤统计
8.1.3 部门迟到早退名单统计结果界面
8.2 主要代码
(1)构造命令,统计一个部门中有哪些员工工作时间不满540分钟
//构造命令,统计一个部门中有哪些员工工作时间不满540分钟
string sqlStr = @"select t4.par, COUNT(*) as count from
(
select t3. *,t.name,t.par from
(
select t1.s_id,t1.date,datediff(n,t1.time,t2.time) as diff from record t1
inner join record t2
on t1.date=t2.date
and t1.s_id=t2.s_id
and t1.p_id=1
and t2.p_id=2
and t1.date>=@start
and t1.date<=@end
)t3,staff t where t3.s_id=t.id
)t4 where t4.diff<540 group by t4.par";
(2)添加查询条件
// 添加查询条件
SqlCommand cmd = new SqlCommand(sqlStr, sqlConn);
cmd.Parameters.Add(new SqlParameter("@start", this.dtp_Start.Value.ToShortDateString()));
cmd.Parameters.Add(new SqlParameter("@end", this.dtp_End.Value.ToShortDateString()));
(3)将该查询过程绑定到DataAdapte
// 将该查询过程绑定到DataAdapter
SqlDataAdapter adp = new SqlDataAdapter();
adp.SelectCommand = cmd;
(4)将DataSet和DataAdapter绑定
// 将DataSet和DataAdapter绑定
DataSet ds = new DataSet();
(5)自定义一个表(MyAttendance)来标识数据库的MyAttendance表
// 自定义一个表(MyGoods)来标识数据库的MyAttendance表
adp.Fill(ds, "MyAttendance");
(6)指定DataGridView的数据源为DataSet的MyGoods表
// 指定DataGridView的数据源为DataSet的MyGoods表
this.dataGridView1.DataSource = ds.Tables["MyAttendance"];
}
catch (Exception exp)
{
MessageBox.Show("访问数据库错误:" + exp.Message);
}
finally
{
sqlConn.Close();
}
9、考勤系统发布安装
9.1 考勤系统发布安装前的准备
(1)为考勤系统添加图标
(注:主窗体图标需要右键(SuperAttendance),点击属性,找到应用程序中的图标选项。其他的窗体需要变图标则需要在属性中找Icon选项,换上图标)
(2)为管理员主界面添加关于窗体