- 55.99 KB
- 2022-05-17 13:47:54 发布
- 1、本文档共5页,可阅读全部内容。
- 2、本文档内容版权归属内容提供方,所产生的收益全部归内容提供方所有。如果您对本文有版权争议,可选择认领,认领后既往收益都归您。
- 3、本文档由用户上传,本站不保证质量和数量令人满意,可能有诸多瑕疵,付费之前,请仔细先通过免费阅读内容等途径辨别内容交易风险。如存在严重挂羊头卖狗肉之情形,可联系本站下载客服投诉处理。
- 文档侵权举报电话:19940600175。
数据库课程设计报告题目:考勤管理系统班级:计科学号:姓名:2021年12月摘要这次课程设计只是达到训练、牢固知识的目的,熟悉数据库的前台和后台编程、VC++的控件、如何访问数据库等方面的知识。本系统采用了可视化的集成开发环境VisualC++6.0编辑用户操作界面、以SQLSever为后台数据库的考勤系统,考勤制度是每个企事业单位所必需的,计算机的出现使员工出勤情况的记录和统计工作变得十分简单。关键字:SQL数据库、SQL语言、VC++、考勤管理
1.系统设计1.1系统功能分析考勤管理系统的主要功能如下:l上班时间的设定。上下班时间相对固定,可保存在客户端的设置文件中。l员工出入单位的情况记录。出入情况主要由考勤机来记录,但是需要设置人工添加的功能,以备特殊情况的处理。l请假、加班和出差情况的记录。1.2系统功能模块的设计考勤管理系统上下班时间设置工作情况记录考勤统计请假记录出差记录手工补计出勤加班记录图1-1系统功能模块图1.3与其他系统的关系考勤管理系统记录了员工上下班的情况,为工资管理系统直接提供每个月工作时间的统计结果,用以计算工资。同时考勤系统也需要其他系统提供的员工、部门等信息。1.4数据流程图系统流程图如图1-2所示,出勤的原始记录主要来源于考勤机,并且以固定格式保存在数据库中。考勤管理系统的任务是如何处理这些数据。
员工记录出勤时间员工出勤记录请假、值班、出差记录上下班时间安排各种统计信息管理人员考勤员经理审批月度员工考勤统计表图1-2考勤管理系统数据流程图2.数据库设计2.1数据需求分析根据数据流程,可以列出以下管理系统所需的数据项和数据结构。l出勤记录:记录号、员工、出入情况和出入时间,如图3-1所示。l月度考勤统计:记录号、员工、年月、累计正常工作时间、累计请假时间、累计加班时间、累计出差时间、迟到次数、早退次数和旷工次数如图3-2所示。l请假记录:记录号、员工、假期起始时间/结束时间和请假缘由,如图3-3所示。l加班记录:记录号、员工、加班时间长度和日期,如图3-4所示。l出差记录:记录号、员工、出差起始时间/结束时间和具体描述,如图3-5所示。所需的外部支持:l人员信息:员工号、密码、权限、姓名、部门和当前状态等。l部门设置:部门编号、名称等。图1-3ATTENDANCE出勤记录表图1-4ATTENDANCE_STAT月度考勤统计表图1-5LEAVE请假记录表图1-6OVERTIME加班记录表图1-7ERRAND出差记录表2.2数据库概念结构设计考勤管理系统的E-R图如下:
员工月度考勤统计记录编号年月累计工作时间累计请假时间累计加班时间累计出差时间迟到次数早退次数旷工次数请假记录记录编号起始时间结束时间缘由加班记录记录编号加班时间日期出勤记录记录编号出入状态出入时间员工号员工密码职权姓名所在部门…….记录编号起始时间结束时间具体描述3.系统实现3.1系统开发环境软件:SQLSever2000,VC++6.0操作系统:Window73.2各个功能模块的创建3.2.1生成程序框架用AppWizard生成程序框架,加入数据库支持。在MFCAppWizard-Step1中选择Dialogbased选项,其余均采用缺省配置。登陆认证对话框登陆窗口的封装类为CLoginDlg控件类型ID成员变量说明ComboBoxIDC_CMB_DSNm_strDSNODBC数据源EditBoxIDC_EDT_USERm_strUser用户名EditBoxIDC_EDT_PASSWDm_strPasswd密码ButtonIDOK无“登陆”按钮
ButtonIDCANCEL无“取消”按钮为了改变标题“登陆人事管理系统”的字体大小,需要改变其ID为IDC_STATIC_LOGINTEXT(缺省为IDC_STATIC),为CAboutDlg类加入一个CFont类的成员函数m_font,然后在OnInitialDialog()函数中加入以下代码://改变"登录人事管理系统"字体大小LOGFONTLogFont;GetFont()->GetLogFont(&LogFont);LogFont.lfHeight+=LogFont.lfHeight/2;LogFont.lfWidth+=LogFont.lfWidth/2;m_font.CreateFontIndirect(&LogFont);GetDlgItem(IDC_STATIC_LOGINTEXT)->SetFont(&m_font);//如数据库为打开状态,则关闭if(db.IsOpen())db.Close();用户认证过程在“登陆”按钮的处理程序中:voidCLoginDlg::OnOK(){BOOLbLogin=FALSE;CStringstrPasswd,strCount;UpdateData();//更新数据变量if(!db.Open(m_strDSN))return;//连接数据库strPasswd=CCrypt::Encrypt(m_strPasswd,123);//加密密码CRecordsetrs(&db);//构造记录集rs.Open(CRecordset::forwardOnly,"selectCOUNT(ID)asCOUNTfromPERSONwhereID=""+m_strUser+""andPASSWD=""+strPasswd+""andAUTHORITY="4"");//执行查询rs.GetFieldValue("COUNT",strCount);rs.Close();//关闭数据集if(strCount=="1")//判断认证是否通过{EndDialog(IDOK);//结束对话框,返回IDOK}else{MessageBox("请确认用户名和密码,注意大小写!","认证失败");db.Close();//关闭数据库}}3.2.3主对话框窗口的设计主对话框控件列表控件类型ID成员变量说明StaticTextIDC_STATIC_HEAD无“考勤管理系统”静态文本ButtonIDC_BTN_CONFIG无“设置”按钮ButtonIDC_BTN_RECORD无“出勤记录”按钮ButtonIDC_BTN_STATISTICS无“统计”按钮
ButtonIDC_BTN_RELOGIN无“重新登录”按钮ButtonIDC_BTN_EXIT无“退出”按钮在CAttendanceDlg中定义以下成员变量:public:CBrushm_brush;CStatDlg*m_pStatDlg;CAttDlg*m_pAttDlg;CFontm_font;}对话框初始化时需要改变标题字体大小,改变背景颜色等,因此在OnInitDialog()中加入以下代码://改变标题字体大小LOGFONTLogFont;GetFont()->GetLogFont(&LogFont);LogFont.lfHeight+=LogFont.lfHeight/2;LogFont.lfWidth+=LogFont.lfWidth/2;m_font.CreateFontIndirect(&LogFont);GetDlgItem(IDC_STATIC_HEAD)->SetFont(&m_font);//初始化对话框指针为空m_pAttDlg=NULL;m_pStatDlg=NULL;//创建背景画刷m_brush.CreateSolidBrush(RGB(0,255,255));对话框中5个按钮的功能主要就是显示相应的功能对话框。各按钮的BN_CLICKED事件的处理和退出代码如下:voidCAttendanceDlg::OnBtnExit(){EndDialog(IDCANCEL);//退出主对话框,关闭程序}voidCAttendanceDlg::OnBtnRelogin(){//隐藏主对话框ShowWindow(SW_HIDE);//显示登录对话框CLoginDlgdlg;if(dlg.DoModal()==IDOK){ShowWindow(SW_SHOW);//显示对话框}elseEndDialog(IDCANCEL);//退出程序}voidCAttendanceDlg::OnBtnConfig(){//显示工作时间设置对话框CWorkplanDlgdlg;
dlg.DoModal();}voidCAttendanceDlg::OnBtnRecord(){//非模态显示出勤记录对话框if(!m_pAttDlg)//指针为空,创建对话框{m_pAttDlg=newCAttDlg();m_pAttDlg->Create(IDD_DLG_ATTENDANCE,this);m_pAttDlg->ShowWindow(SW_SHOW);}else//对话框已创建m_pAttDlg->ShowWindow(SW_SHOW);//显示窗口}voidCAttendanceDlg::OnBtnStatistics(){//非模态显示考勤统计对话框if(!m_pStatDlg)//指针为空,创建对话框{m_pStatDlg=newCStatDlg();m_pStatDlg->Create(IDD_DLG_STAT,this);m_pStatDlg->ShowWindow(SW_SHOW);}else//对话框已创建m_pStatDlg->ShowWindow(SW_SHOW);//显示窗口}上班时间设置对话框的创建设置对话框控件列表控件类型ID成员变量说明DateTimePickerIDC_WORKSTAT_DAETIMEPICKER1m_Time1上午上班时间DateTimePickerIDC_WORKSTAT_DAETIMEPICKER2m_Time2中午下班时间DateTimePickerIDC_WORKSTAT_DAETIMEPICKER3m_Time3下午上班时间DateTimePickerIDC_WORKSTAT_DAETIMEPICKER4m_Time4下午下班时间ButtonIDC_WORKPLAN_MODIFY无“修改”按钮ButtonIDC_WORKPLAN_RESET无“恢复默认设置”按钮“恢复默认设置”按钮的BN_CLICKED事件处理程序用于恢复原来的设置。这个函数也同时被OnInitDialog()函数引用,以实现初始化操作。voidCWorkplanDlg::OnWorkplanReset(){CStringcstr[4];charstr[4][9];inti;intnHour,nMinute,nSecond;//时,分,秒CStringstrFileName=".\workplan.ini";//INI文件名
//读取INI文件GetPrivateProfileString("WorkPlan","Time1","08:00:00",str[0],9,strFileName);GetPrivateProfileString("WorkPlan","Time2","12:00:00",str[1],9,strFileName);GetPrivateProfileString("WorkPlan","Time3","14:00:00",str[2],9,strFileName);GetPrivateProfileString("WorkPlan","Time4","18:00:00",str[3],9,strFileName);for(i=0;i<4;i++)cstr[i]=str[i];//定义四个时间变量并初始化为INI文件中的值sscanf(cstr[0].Left(2),"%d",&nHour);//得到时sscanf(cstr[0].Mid(3,2),"%d",&nMinute);//得到分sscanf(cstr[0].Mid(6,2),"%d",&nSecond);//得到秒CTimet1(2002,1,1,nHour,nMinute,nSecond);//初始化t1sscanf(cstr[1].Left(2),"%d",&nHour);//得到时sscanf(cstr[1].Mid(3,2),"%d",&nMinute);//得到分sscanf(cstr[1].Mid(6,2),"%d",&nSecond);//得到秒CTimet2(2002,1,1,nHour,nMinute,nSecond);//初始化t2sscanf(cstr[2].Left(2),"%d",&nHour);//得到时sscanf(cstr[2].Mid(3,2),"%d",&nMinute);//得到分sscanf(cstr[2].Mid(6,2),"%d",&nSecond);//得到秒CTimet3(2002,1,1,nHour,nMinute,nSecond);//初始化t3sscanf(cstr[3].Left(2),"%d",&nHour);//得到时sscanf(cstr[3].Mid(3,2),"%d",&nMinute);//得到分sscanf(cstr[3].Mid(6,2),"%d",&nSecond);//得到秒CTimet4(2002,1,1,nHour,nMinute,nSecond);//初始化t4//设置成员变量m_Time1=t1;m_Time2=t2;m_Time3=t3;m_Time4=t4;UpdateData(FALSE);//更新界面数据}3.2.5考勤修改对话框的创建考勤修改对话框控件列表控件类型ID成员变量说明CheckBoxIDC_CHK_SEEKBYTIMEm_bSeekbytime时间范围选项CheckBoxIDC_CHK_SEEKBYPERSONm_bSeekbyperson员工选项DateTimePickerIDC_DATETIMEPICKER1m_starTime起始时间DateTimePickerIDC_DATETIMEPICKER2m_EndTime结束时间EditBoxIDC_EDT_SEEKPERSONIDm_strPersonID员工号EditBoxIDC_EDT_SEEKPERSONNAMEm_nstrName姓名当输入员工号时,需要及时检索员工姓名,以确定设置的条件有效。通过Class
Wizard加入处理IDC_EDT_SEEKPERSONID的EN_CHANGE消息的函数如下:voidCAttDlg::OnChangeEdtSeekpersonid(){UpdateData();//更新数据CPersonRSrs(&db);//构造记录集rs.m_strFilter="ID=""+m_strPersonID+""";//设置过滤条件rs.Open();//打开记录集if(rs.GetRecordCount()==1)//判断员工记录是否存在{m_strName=rs.m_NAME;//得到员工姓名}elsem_strName.Empty();//清除员工姓名的显示rs.Close();//关闭记录集UpdateData(FALSE);//更新界面数据}3.2.6修改出勤记录属性页的创建修改出勤记录属性页控件列表控件类型ID成员变量说明EditBoxIDC_EDT_IOTIMEm_strIOTime出入时间EditBoxIDC_EDT_DEPATIDm_strDepartID部门编号EditBoxIDC_EDT_DEPARTNAMEm_strDepartNAME部门名称EditBoxIDC_EDT_PERSONIDm_strPersonID员工号EditBoxIDC_EDT_PERSONNAMEm_strPersonNAME员工姓名RadioButtonIDC_RADIO_OUT无出入选项的“出”RadioButtonIDC_RADIO_IN无出入选项的“入”ButtonIDC_BTN_ADDALL无“全体员工”按钮ButtonIDC_BTN_ADDDEPART无“部门员工”按钮ButtonIDC_BTN_ADDPERSON无“单个员工”按钮ButtonIDC_BTN_DELETEATTEND无“删除所选记录”按钮ButtonIDC_BTN_SEEKIO无“按条件检索”按钮ListControlIDC_LIST1m_cList出勤记录列表界面初始化操作如下:BOOLCPage1::OnInitDialog(){CPropertyPage::OnInitDialog();//出入情况缺省为出((CButton*)GetDlgItem(IDC_RADIO_OUT))->SetCheck(TRUE);//为List添加网格m_cList.SetExtendedStyle(LVS_EX_GRIDLINES);//设置List的列intnWidth=110;m_cList.InsertColumn(0,"记录编号",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(1,"员工号",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(2,"出入情况",LVCFMT_LEFT,nWidth);
m_cList.InsertColumn(3,"时间",LVCFMT_LEFT,nWidth);CAttendanceRSrs(&db);//构造出勤记录表UpdateList(rs);//更新ListreturnTRUE;//returnTRUEunlessyousetthefocustoacontrol//EXCEPTION:OCXPropertyPagesshouldreturnFALSE}为了方便的更新列表框内容,调用函数可使列表框显示给定的数据表格。voidCPage1::UpdateList(CAttendanceRS&rs)//更新列表框内容{inti=0;CStringstrID,strTime;rs.Open();//打开出勤记录表m_cList.DeleteAllItems();//清除列表框内容while(!rs.IsEOF())//对数据表中所有记录进行处理{m_cList.InsertItem(i,"");//添加新ItemstrID.Format("%d",rs.m_ID);//转换为字符串m_cList.SetItemText(i,0,strID);m_cList.SetItemText(i,1,rs.m_PERSON);m_cList.SetItemText(i,2,rs.m_IN_OUT);m_cList.SetItemText(i,3,rs.m_IO_TIME.Format("%Y-%m-%d%H:%M"));rs.MoveNext();//跳到下一条记录i++;}rs.Close();//关闭出勤记录表}当输入部门编号时,自动检索部门名称。voidCPage1::OnChangeEdtDepartid(){UpdateData();//更新数据CDepartRSrs(&db);//构造记录集rs.m_strFilter="ID=""+m_strDepartID+""";//设置过滤条件rs.Open();//打开记录集if(rs.GetRecordCount()==1)//判断部门代码输入是否正确{m_strDepartName=rs.m_NAME;//提取部门名称}elsem_strDepartName.Empty();//清除部门名称rs.Close();//关闭记录集UpdateData(FALSE);//更新界面数据}添加部门和全体员工出勤记录的过程最终可以分解为添加单个员工记录的过程。为了避免程序的重复,设置了下面的子程序:voidCPage1::IO_Add(CStringstrPersonID)
{intcounter;//用于计数CStringstrIO;//保存出入情况CCounterRSrs_counter(&db);//构造计数器记录表//记录编号rs_counter.m_strFilter="ID="A"";//设置过滤器,提取计数值rs_counter.Open();//打开计数器记录表counter=rs_counter.m_COUNTER_VALUE;//提取计数值counter++;//计数值加1rs_counter.Edit();//编辑计数器rs_counter.m_COUNTER_VALUE=counter;//保存当前计数rs_counter.Update();//提交修改rs_counter.Close();//关闭计数器记录表//添加记录//判断确定出入情况if(((CButton*)GetDlgItem(IDC_RADIO_OUT))->GetCheck())strIO="O";elsestrIO="I";//转换出入时间类型intnYear,nMonth,nDay,nHour,nMinute;//年,月,日,时,分sscanf(m_strIOTime.Left(4),"%d",&nYear);//得到年sscanf(m_strIOTime.Mid(5,2),"%d",&nMonth);//得到月sscanf(m_strIOTime.Mid(8,2),"%d",&nDay);//得到日sscanf(m_strIOTime.Mid(11,2),"%d",&nHour);//得到时sscanf(m_strIOTime.Mid(14,2),"%d",&nMinute);//得到分//得到出入时间CTimeIO_time(nYear,nMonth,nDay,nHour,nMinute,0);CAttendanceRSrs_attendance(&db);//构造考勤记录表rs_attendance.Open();//打开考勤记录表rs_attendance.AddNew();//追加考勤记录rs_attendance.m_ID=counter;rs_attendance.m_PERSON=strPersonID;rs_attendance.m_IN_OUT=strIO;rs_attendance.m_IO_TIME=IO_time;rs_attendance.Update();rs_attendance.Close();//关闭考勤记录表UpdateList(rs_attendance);//更新列表框}添加记录的3个按钮处理程序分别调用以上的函数。voidCPage1::OnBtnAddperson()//追加单个员工考勤记录{if(!m_strPersonName.IsEmpty())//判断员工是否存在{IO_Add(m_strPersonID);//追加单个员工记录
}}voidCPage1::OnBtnAdddepart()//追加部门员工考勤记录{inti,n;//用于保存记录条数CPersonRSrs_person(&db);//构造员工信息表if(m_strDepartName.IsEmpty())return;//判断部门代号是否正确//设置过滤条件rs_person.m_strFilter="DEPARTMENT=""+m_strDepartID+""andSTATE="T"";rs_person.Open();//打开员工信息表n=rs_person.GetRecordCount();//获取员工人数i=0;//初始化已添加记录条数//初始化进度条m_cProgress.SetRange(0,n);m_cProgress.SetPos(0);while(!rs_person.IsEOF())//对数据表中所有记录进行处理{IO_Add(rs_person.m_ID);//添加当前员工出勤记录rs_person.MoveNext();//跳到下一个员工记录m_cProgress.SetPos(++i);//显示进度}rs_person.Close();//关闭员工信息表}voidCPage1::OnBtnAddall()//添加所有员工出勤记录{inti,n;//用于保存记录条数CPersonRSrs_person(&db);//构造员工信息表//设置过滤条件,提取员工列表rs_person.m_strFilter="STATE="T"";rs_person.Open();//打开员工信息表n=rs_person.GetRecordCount();//获取员工人数i=0;//初始化已添加记录条数//初始化进度条m_cProgress.SetRange(0,n);m_cProgress.SetPos(0);while(!rs_person.IsEOF())//对数据表中所有记录进行处理{IO_Add(rs_person.m_ID);//添加当前员工出勤记录rs_person.MoveNext();//跳到下一个员工记录m_cProgress.SetPos(++i);//显示进度}rs_person.Close();//关闭员工信息表}“删除所选记录”
voidCPage1::OnBtnDeleteattend()//删除出勤记录列表中所选记录{CStringstrSQL;intnItem;//得到第一个被选择Item的位置POSITIONpos=m_cList.GetFirstSelectedItemPosition();if(pos==NULL){AfxMessageBox("没有选择记录!");return;}while(pos)//遍历所有被选Item{nItem=m_cList.GetNextSelectedItem(pos);//得到ItemIndex//构造SQL语句strSQL="deletefromATTENDANCEwhereID="+m_cList.GetItemText(nItem,0);db.ExecuteSQL(strSQL);//执行}CAttendanceRSrs(&db);//构造出勤记录表UpdateList(rs);//更新列表框}3.2.7加班记录属性页的创建加班记录属性页控件列表控件类型ID成员变量说明DateTimePickerIDC_OVERTIME_DATETIMEPICKERm_Date日期EditBoxIDC_EDT_OVERTIME_HOURm_nHour加班时间EditBoxIDC_EDT_OVERTIME_PERSONIDm_strPersonID员工号EditBoxIDC_EDT_OVERTIME_PERSONNAMEm_strPersonName员工姓名ButtonIDC_BTN_OVERTIME_ADD无“添加”按钮ButtonIDC_BTN_OVERTIME_DELETEATTEND无“删除所选记录”按钮ButtonIDC_BTN_OVERTIME_SEEKIO无“按条件检索”按钮ListContrlIDC_LIST2m_cList加班记录列表初始代码如下:BOOLCPage2::OnInitDialog(){CPropertyPage::OnInitDialog();//为List添加网格m_cList.SetExtendedStyle(LVS_EX_GRIDLINES);//设置List的列intnWidth=110;m_cList.InsertColumn(0,"记录编号",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(1,"员工号",LVCFMT_LEFT,nWidth);
m_cList.InsertColumn(2,"加班时间",LVCFMT_LEFT,nWidth);m_cList.InsertColumn(3,"加班日期",LVCFMT_LEFT,nWidth);COvertimeRSrs(&db);//构造加班记录表UpdateList(rs);//更新ListreturnTRUE;//returnTRUEunlessyousetthefocustoacontrol//EXCEPTION:OCXPropertyPagesshouldreturnFALSE}当输入员工号时,需要检索员工姓名,以确认输入是否正确。voidCPage2::OnChangeEdtOvertimePersonid(){UpdateData();//更新数据CPersonRSrs(&db);//构造PERSON记录表rs.m_strFilter="ID=""+m_strPersonID+""";//设置过滤条件rs.Open();//打开记录表if(rs.GetRecordCount()==1)//判断员工号是否正确{m_strPersonName=rs.m_NAME;//提取员工姓名}elsem_strPersonName.Empty();//清除员工姓名显示rs.Close();//关闭记录表UpdateData(FALSE);//更新界面数据}“添加”按钮。voidCPage2::OnBtnOvertimeAdd(){intcounter;//用于保存计数CCounterRSrs_counter(&db);//构造计数器记录表UpdateData();//更新数据if(m_strPersonName.IsEmpty())return;//判断员工号是否正确//记录编号rs_counter.m_strFilter="ID="O"";//设置过滤器,提取计数值rs_counter.Open();//打开计数器记录表counter=rs_counter.m_COUNTER_VALUE;//提取计数值counter++;//计数值加1rs_counter.Edit();//编辑计数器rs_counter.m_COUNTER_VALUE=counter;//保存当前计数rs_counter.Update();//提交修改rs_counter.Close();//关闭计数器记录表//添加记录COvertimeRSrs_overtime(&db);//构造加班记录表rs_overtime.Open();//打开表rs_overtime.AddNew();//新增一项记录//设置字段值rs_overtime.m_ID=counter;
rs_overtime.m_PERSON=m_strPersonID;rs_overtime.m_WORK_HOURS=m_nHour;rs_overtime.m_WORK_DATE=m_Date;rs_overtime.Update();//更新数据库rs_overtime.Close();//关闭加班记录表UpdateList(rs_overtime);//更新列表框}3.2.8请假记录和出差记录属性页的创建控件类型ID成员变量说明EditBoxIDC_EDT_LEAVE_STARTTIMEm_strSTime起始时间EditBoxIDC_EDT_LEAVE_ENDTIMEm_strETime结束时间EditBoxIDC_EDT_LEAVE_PERSONIDm_strPersonID员工号EditBoxIDC_EDT_LEAVE_PERSONNAMEm_strPersonName员工姓名EditBoxIDC_EDT_LEAVE_PEASONm_strReason请假原因ButtonIDC_BTN_LEAVE_ADD无“添加”按钮ButtonIDC_BTN_LEAVE_DELETEATTEND无“删除所选记录”按钮ButtonIDC_BTN_LEAVE_SEEKIO无“按条件检索”按钮ListControlIDC_LIST3m_cList加班记录列表请假记录属性页控件列表添加记录代码如下:voidCPage3::OnBtnLeaveAdd(){intcounter;//用于计数CCounterRSrs_counter(&db);//构造计数器记录表UpdateData();//更新数据//记录编号rs_counter.m_strFilter="ID="L"";//设置过滤器,提取计数值rs_counter.Open();//打开计数器记录表counter=rs_counter.m_COUNTER_VALUE;//提取计数值counter++;//计数值加1rs_counter.Edit();//编辑计数器rs_counter.m_COUNTER_VALUE=counter;//保存当前计数rs_counter.Update();//提交修改rs_counter.Close();//关闭计数器记录表//添加记录intnYear,nMonth,nDay,nHour,nMinute;//年,月,日,时,分//转换起始时间类型sscanf(m_strSTime.Left(4),"%d",&nYear);//得到年sscanf(m_strSTime.Mid(5,2),"%d",&nMonth);//得到月sscanf(m_strSTime.Mid(8,2),"%d",&nDay);//得到日sscanf(m_strSTime.Mid(11,2),"%d",&nHour);//得到时sscanf(m_strSTime.Mid(14,2),"%d",&nMinute);//得到分//得到起始时间
CTimeS_time(nYear,nMonth,nDay,nHour,nMinute,0);//转换结束时间类型sscanf(m_strETime.Left(4),"%d",&nYear);//得到年sscanf(m_strETime.Mid(5,2),"%d",&nMonth);//得到月sscanf(m_strETime.Mid(8,2),"%d",&nDay);//得到日sscanf(m_strETime.Mid(11,2),"%d",&nHour);//得到时sscanf(m_strETime.Mid(14,2),"%d",&nMinute);//得到分//得到结束时间CTimeE_time(nYear,nMonth,nDay,nHour,nMinute,0);CLeaveRSrs_leave(&db);//构造请假记录表rs_leave.Open();//打开请假记录表rs_leave.AddNew();//追加请假记录rs_leave.m_ID=counter;rs_leave.m_PERSON=m_strPersonID;rs_leave.m_START_TIME=S_time;rs_leave.m_END_TIME=E_time;rs_leave.m_REASON=m_strReason;rs_leave.Update();rs_leave.Close();//关闭请假记录表UpdateList(rs_leave);//更新列表框}3.2.9考勤统计对话框的创建初始化时设置缺省时间,修改构造函数如下:CStatDlg::CStatDlg(CWnd*pParent/*=NULL*/):CDialog(CStatDlg::IDD,pParent){CTimeEnd_t=CTime::GetCurrentTime();//当前时间CTimeSpantp(30,0,0,0);//时间间隔为30天//{{AFX_DATA_INIT(CStatDlg)m_strTime=End_t.Format("%Y-%m");m_STime=End_t-tp;m_ETime=End_t;m_bSeekbytime=FALSE;m_bSeekbyperson=FALSE;m_strSeektime=_T("");m_strPersonID=_T("");m_strPersonName=_T("");//}}AFX_DATA_INIT}“检索”按钮:voidCStatDlg::OnStatBtnSeek(){CStringstrFilter;//保存过滤字符串CStatRSrs(&db);//构造统计数据表
UpdateData();//更新数据//判断根据员工号过滤if(m_bSeekbyperson)strFilter="PERSON=""+m_strPersonID+""";//判断根据年月过滤if(m_bSeekbytime){if(!strFilter.IsEmpty())//如果已有过滤条件strFilter+="and";//需添加and连接符//设置时间过滤条件strFilter+="YEAR_MONTH=#"+m_strSeektime+"#";}if(!strFilter.IsEmpty())//判断是否有过滤字符串{rs.m_strFilter=strFilter;//设置过滤条件}UpdateList(rs);//更新列表框}统计过程主要是记录判断过程,代码如下:voidCStatDlg::OnStatBtnStat(){CRecordsetrs_Q_attend(&db);//构造Q_attend记录集CRecordsetrs_Q_leave(&db);//构造Q_leave记录集CRecordsetrs_Q_errand(&db);//构造Q_errand记录集CTimeSpantp_1(1,0,0,0);//构造一个1天的CTimeSpanCTimeSpantp_02(0,2,0,0);//构造一个2小时的CTimeSpanCTimeSpanTimeSpan[4];//保存上下班时间intnHours[2];//保存上下午工作时间CStringstrSTime,strETime;//保存始末时间CTimeTimeStamp,LateTime,EarlyTime,WorkStart,WorkEnd;//保存中间判断时间intnWorkHour,nOverHour,nLeaveHDay,nErrandHDay;//保存时间间隔长度BOOLbLate,bEarly,bAbsent,bLeave,bErrand;//保存判断结果intnLateTimes,nEarlyTimes,nAbsentTimes;//保存次数CStringcstr[4];//暂存起始时间charstr[4][9];//暂存起始时间inti,j,n,counter;//用于循环和计数CStringstrTmp,strTmp1,strTmp2;//临时变量//临时变量,年,月,日,时,分,秒intnHour,nMinute,nSecond;CStringstrFileName=".\workplan.ini";//INI文件名UpdateData();//更新数据//读取INI文件GetPrivateProfileString("WorkPlan","Time1","08:00:00",str[0],9,strFileName);GetPrivateProfileString("WorkPlan","Time2","12:00:00",str[1],9,
strFileName);GetPrivateProfileString("WorkPlan","Time3","14:00:00",str[2],9,strFileName);GetPrivateProfileString("WorkPlan","Time4","18:00:00",str[3],9,strFileName);for(i=0;i<4;i++)cstr[i]=str[i];//定义四个时间间隔变量并初始化为INI文件中的值CTimeSpan*pTS;for(i=0;i<4;i++){sscanf(cstr[i].Left(2),"%d",&nHour);//得到时sscanf(cstr[i].Mid(3,2),"%d",&nMinute);//得到分sscanf(cstr[i].Mid(6,2),"%d",&nSecond);//得到秒//构造一个时间间隔变量pTS=newCTimeSpan(0,nHour,nMinute,nSecond);TimeSpan[i]=*pTS;//赋值deletepTS;}nHours[0]=(TimeSpan[1]-TimeSpan[0]).GetTotalHours();//计算上午工作时间if((TimeSpan[1]-TimeSpan[0]).GetMinutes()>30)nHours[0]++;//四舍五入nHours[1]=(TimeSpan[3]-TimeSpan[2]).GetTotalHours();//计算下午工作时间if((TimeSpan[3]-TimeSpan[2]).GetMinutes()>30)nHours[1]++;//四舍五入//转换统计开始时间strSTime="#"+m_STime.Format("%Y-%m-%d")+"#";//转换统计结束时间,且天数加1strETime="#"+(m_ETime+tp_1).Format("%Y-%m-%d")+"#";//提取员工列表CPersonRSrs_person(&db);//构造员工表rs_person.m_strFilter="STATE="T"";//设置过滤器,提取员工列表rs_person.Open();//打开员工表n=rs_person.GetRecordCount();//记录员工人数i=0;//初始化已处理员工人数m_cProgress.SetRange(0,n);//设置进度条m_cProgress.SetPos(0);//初始化进度条while(!rs_person.IsEOF())//依次对每个员工进行统计{//获取出勤记录//执行查询rs_Q_attend.Open(CRecordset::forwardOnly,"selectIN_OUT,IO_TIMEfromATTENDANCEwherePERSON=""+rs_person.m_ID+""andIO_TIME>"+strSTime+"andIO_TIME<"+strETime+"orderbyIO_TIME");
strTmp1.Empty();//清空strTmp1//初始化nWorkHour=nOverHour=0;nLeaveHDay=nErrandHDay=0;nLateTimes=nEarlyTimes=nAbsentTimes=0;TimeStamp=m_STime;//初始化时间戳为统计开始时间while(TimeStamp#"+EarlyTime.Format("%Y-%m-%d%H:%M:%S")+"#");bLeave=(rs_Q_leave.GetRecordCount()>0);//判断是否有请假记录rs_Q_leave.Close();//关闭记录集//判断是否出差rs_Q_errand.Open(CRecordset::forwardOnly,"selectIDfromERRANDwherePERSON=""+rs_person.m_ID+""andSTART_TIME<#"+LateTime.Format("%Y-%m-%d%H:%M:%S")+"#andEND_TIME>#"+EarlyTime.Format("%Y-%m-%d%H:%M:%S")+"#");bErrand=(rs_Q_errand.GetRecordCount()>0);//判断是否有出差记录rs_Q_errand.Close();//关闭记录集if(bLeave)//如果有请假记录nLeaveHDay++;//请假记录加1elseif(bErrand)//如果有出差记录{nErrandHDay++;//出差计数加1nWorkHour+=nHours[j];//按正常班累加工作时间}
else//正常上班{WorkStart=LateTime;//设置工作开始时间WorkEnd=EarlyTime;//设置工作结束时间bLate=TRUE;//初始化迟到判断bAbsent=FALSE;//初始化旷工判断//判断是否迟到if(!rs_Q_attend.IsEOF()&&//记录集不空strTmp1.IsEmpty())//空,第一次GetFieldValuers_Q_attend.GetFieldValue("IO_TIME",strTmp1);//得到IO_TIMEwhile(!rs_Q_attend.IsEOF()&&StrToTime(strTmp1)<=LateTime){//根据时间顺序判断是否迟到//得到IN_OUTrs_Q_attend.GetFieldValue("IN_OUT",strTmp2);bLate=(strTmp2=="O");//判断上班时间前是否报到rs_Q_attend.MoveNext();//跳到下一条出勤记录//得到IO_TIMEif(!rs_Q_attend.IsEOF())rs_Q_attend.GetFieldValue("IO_TIME",strTmp1);}//判断是否旷工if(bLate)//判断是否迟到{if(!rs_Q_attend.IsEOF()&&StrToTime(strTmp1)30)nWorkHour++;//四舍五入}}}//Endof遍历班次}//Endof是否工作日TimeStamp+=tp_1;//推进一天}//EndofTimeStamp#"+m_STime.Format("%Y-%m-%d%H:%M:%S")+"#andWORK_DATE<#"+m_ETime.Format("%Y-%m-%d%H:%M:%S")+"#");if(rs_Q_overtime.GetRecordCount()>0)//有记录{//提取加班时间rs_Q_overtime.GetFieldValue("SUM",strTmp);sscanf(strTmp,"%d",&nOverHour);}elsenOverHour=0;//无记录rs_Q_overtime.Close();//判断是否已有该月考勤记录CStatRSrs_stat(&db);//构造统计数据表//设置过滤串
rs_stat.m_strFilter="PERSON=""+rs_person.m_ID+""andYEAR_MONTH=""+m_strTime+""";rs_stat.Open();//打开数据表if(rs_stat.GetRecordCount()==0)//判断是否有该月份考勤记录{//获取计数CCounterRSrs_counter(&db);//构造计数器表rs_counter.m_strFilter="ID="S"";//设置过滤器,提取计数值rs_counter.Open();//打开计数器记录表counter=rs_counter.m_COUNTER_VALUE;//提取计数值counter++;//计数值加1rs_counter.Edit();//编辑计数器rs_counter.m_COUNTER_VALUE=counter;//保存当前计数rs_counter.Update();//提交修改rs_counter.Close();//关闭计数器记录表//追加统计记录rs_stat.AddNew();rs_stat.m_ID=counter;rs_stat.m_YEAR_MONTH=m_strTime;rs_stat.m_PERSON=rs_person.m_ID;rs_stat.m_WORK_HOUR=nWorkHour;rs_stat.m_OVER_HOUR=nOverHour;rs_stat.m_LEAVE_HDAY=nLeaveHDay;rs_stat.m_ERRAND_HDAY=nErrandHDay;rs_stat.m_LATE_TIMES=nLateTimes;rs_stat.m_EARLY_TIMES=nEarlyTimes;rs_stat.m_ABSENT_TIMES=nAbsentTimes;rs_stat.Update();//提交修改}else{//记录已存在修改数据rs_stat.Edit();rs_stat.m_WORK_HOUR=nWorkHour;rs_stat.m_OVER_HOUR=nOverHour;rs_stat.m_LEAVE_HDAY=nLeaveHDay;rs_stat.m_ERRAND_HDAY=nErrandHDay;rs_stat.m_LATE_TIMES=nLateTimes;rs_stat.m_EARLY_TIMES=nEarlyTimes;rs_stat.m_ABSENT_TIMES=nAbsentTimes;rs_stat.Update();//提交修改}rs_stat.Close();//关闭数据表i++;//已统计员工数加1
m_cProgress.SetPos(i);//显示统计进度rs_person.MoveNext();//跳到下一个员工记录}rs_person.Close();//关闭员工表CStatRSrs_stat(&db);//构造统计数据表UpdateList(rs_stat);//更新列表框}全局变量StrToTime函数代码如下://全局函数,将时间串转换为CTime型变量CTimeStrToTime(CStringstr){//时间串格式"%Y-%m-%d%H:%M:%S",如"1999-01-0111:11:11"intnYear,nMonth,nDay,nHour,nMinute,nSecond;sscanf(str.Left(4),"%d",&nYear);//得到年sscanf(str.Mid(5,2),"%d",&nMonth);//得到月sscanf(str.Mid(8,2),"%d",&nDay);//得到日sscanf(str.Mid(11,2),"%d",&nHour);//得到时sscanf(str.Mid(14,2),"%d",&nMinute);//得到分sscanf(str.Mid(17,2),"%d",&nSecond);//得到分//构造CTime变量CTimeresult(nYear,nMonth,nDay,nHour,nMinute,nSecond);returnresult;}6.总结通过此次几个周的数据库与程序设计方法学联合课程设计的训练,初步了解了数据库的设计方法和VC如何访问数据库并进行数据库的后台编程。通过参照网上书上各种例子,了解了很多VC方面的知识,比如如何访问打开数据库记录,如何运用ListControl控件等,这些知识都是第一次接触,经过多次运用之后,对它们都有所深入的了解,掌握如何运用它们。此次的考勤管理管理系统实现的都是些基本的功能,因为这次课程设计时间有限,所以完成的功能也就很有限,但感觉收获很大,很有成就感。参考文献1.王珊萨师煊.数据库系统概论.高等教育出版社,2021(4):198~2332.李闽溟吴继刚周学明.Visualc++6.0数据库系统开发实例导航.人民邮电出版社3.CSDN下载站