www.gusucode.com > VC++版的小型考勤管理系统-源码程序 > VC++版的小型考勤管理系统-源码程序\code\StatDlg.cpp

    // StatDlg.cpp : implementation file
// Download by http://www.NewXing.com

#include "stdafx.h"
#include "Attendance.h"
#include "StatDlg.h"
#include "PersonRS.h"
#include "CounterRS.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

extern CDatabase db;
extern CTime StrToTime(CString str);
/////////////////////////////////////////////////////////////////////////////
// CStatDlg dialog


CStatDlg::CStatDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CStatDlg::IDD, pParent)
{
	CTime End_t=CTime::GetCurrentTime(); // 当前时间
	CTimeSpan tp(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
}


void CStatDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CStatDlg)
	DDX_Control(pDX, IDC_STAT_PROGRESS, m_cProgress);
	DDX_Control(pDX, IDC_STAT_LIST, m_cList);
	DDX_Text(pDX, IDC_STAT_EDT_TIME, m_strTime);
	DDX_DateTimeCtrl(pDX, IDC_STAT_DATETIMEPICKER_STARTTIME, m_STime);
	DDX_DateTimeCtrl(pDX, IDC_STAT_DATETIMEPICKER_ENDTIME, m_ETime);
	DDX_Check(pDX, IDC_STAT_CHK_SEEKBYTIME, m_bSeekbytime);
	DDX_Check(pDX, IDC_STAT_CHK_SEEKBYPERSON, m_bSeekbyperson);
	DDX_Text(pDX, IDC_STAT_EDT_SEEKTIME, m_strSeektime);
	DDX_Text(pDX, IDC_STAT_EDT_SEEKPERSONID, m_strPersonID);
	DDX_Text(pDX, IDC_STAT_EDT_SEEKPERSONNAME, m_strPersonName);
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CStatDlg, CDialog)
	//{{AFX_MSG_MAP(CStatDlg)
	ON_EN_CHANGE(IDC_STAT_EDT_SEEKPERSONID, OnChangeStatEdtSeekpersonid)
	ON_BN_CLICKED(IDC_STAT_BTN_SEEK, OnStatBtnSeek)
	ON_BN_CLICKED(IDC_STAT_BTN_STAT, OnStatBtnStat)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CStatDlg message handlers

void CStatDlg::OnChangeStatEdtSeekpersonid() 
{
	UpdateData(); // 更新数据

	CPersonRS rs(&db); // 构造记录集
	rs.m_strFilter = "ID='" + m_strPersonID + "'"; // 设置过滤条件
	rs.Open(); // 打开记录集
	if(rs.GetRecordCount()==1) // 判断员工记录是否存在
	{
		m_strPersonName=rs.m_NAME; // 得到员工姓名
	}
	else m_strPersonName.Empty(); // 清除员工姓名的显示
	rs.Close(); // 关闭记录集
	UpdateData(FALSE); // 更新界面数据
}

void CStatDlg::OnStatBtnSeek() 
{
	CString strFilter; // 保存过滤字符串
	CStatRS rs(&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); // 更新列表框
}

BOOL CStatDlg::OnInitDialog() 
{
	CDialog::OnInitDialog();
	
	// 为List添加网格
	m_cList.SetExtendedStyle(LVS_EX_GRIDLINES);
	// 设置List的列
	int nWidth=100;
	m_cList.InsertColumn(0, "记录编号", LVCFMT_LEFT, 80);
	m_cList.InsertColumn(1, "员工号", LVCFMT_LEFT, 50);
	m_cList.InsertColumn(2, "年月", LVCFMT_LEFT, nWidth);
	m_cList.InsertColumn(3, "正常工作时间(小时)", LVCFMT_LEFT, nWidth+40);
	m_cList.InsertColumn(4, "加班时间(小时)", LVCFMT_LEFT, nWidth);
	m_cList.InsertColumn(5, "请假时间(半天)", LVCFMT_LEFT, nWidth);
	m_cList.InsertColumn(6, "出差时间(半天)", LVCFMT_LEFT, nWidth);
	m_cList.InsertColumn(7, "迟到次数", LVCFMT_LEFT, nWidth-30);
	m_cList.InsertColumn(8, "早退次数", LVCFMT_LEFT, nWidth-30);
	m_cList.InsertColumn(9, "旷工次数", LVCFMT_LEFT, nWidth-30);
	CStatRS rs(&db); // 构造出勤记录表
	UpdateList(rs); // 更新List
	return TRUE;  // return TRUE unless you set the focus to a control
	              // EXCEPTION: OCX Property Pages should return FALSE
}

void CStatDlg::UpdateList(CStatRS& rs)
{
	int i=0;
	CString str;
	rs.Open(); // 打开统计数据表
	m_cList.DeleteAllItems(); // 清除列表框内容
	while(!rs.IsEOF()) // 对数据表中所有记录进行处理
	{
		m_cList.InsertItem(i, ""); // 添加新Item
		str.Format("%d", rs.m_ID); // 转换为字符串
		m_cList.SetItemText(i, 0, str);
		m_cList.SetItemText(i, 1, rs.m_PERSON);
		m_cList.SetItemText(i, 2, rs.m_YEAR_MONTH);
		str.Format("%d", rs.m_WORK_HOUR);
		m_cList.SetItemText(i, 3, str);
		str.Format("%d", rs.m_OVER_HOUR);
		m_cList.SetItemText(i, 4, str);
		str.Format("%d", rs.m_LEAVE_HDAY);
		m_cList.SetItemText(i, 5, str);
		str.Format("%d", rs.m_ERRAND_HDAY);
		m_cList.SetItemText(i, 6, str);
		str.Format("%d", rs.m_LATE_TIMES);
		m_cList.SetItemText(i, 7, str);
		str.Format("%d", rs.m_EARLY_TIMES);
		m_cList.SetItemText(i, 8, str);
		str.Format("%d", rs.m_ABSENT_TIMES);
		m_cList.SetItemText(i, 9, str);
		rs.MoveNext(); // 跳到下一条记录
		i++;
	}
	rs.Close(); // 关闭统计数据表
}

void CStatDlg::OnStatBtnStat() 
{
	CRecordset rs_Q_attend(&db); // 构造Q_attend记录集
	CRecordset rs_Q_leave(&db);  // 构造Q_leave记录集
	CRecordset rs_Q_errand(&db);  // 构造Q_errand记录集
	CTimeSpan tp_1(1,0,0,0); // 构造一个1天的CTimeSpan
	CTimeSpan tp_02(0,2,0,0); // 构造一个2小时的CTimeSpan
	CTimeSpan TimeSpan[4]; // 保存上下班时间
	int nHours[2]; // 保存上下午工作时间
	CString strSTime,strETime; // 保存始末时间
	CTime TimeStamp, LateTime, EarlyTime,WorkStart,WorkEnd; // 保存中间判断时间
	int nWorkHour,nOverHour,nLeaveHDay,nErrandHDay; // 保存时间间隔长度
	BOOL bLate,bEarly,bAbsent,bLeave,bErrand; // 保存判断结果
	int nLateTimes,nEarlyTimes,nAbsentTimes; // 保存次数
	CString cstr[4]; // 暂存起始时间
	char str[4][9]; // 暂存起始时间
	int i,j,n,counter; // 用于循环和计数
	CString strTmp,strTmp1,strTmp2; // 临时变量
	// 临时变量,年,月,日,时,分,秒
	int nHour,nMinute,nSecond;
	CString strFileName=".\\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=new CTimeSpan(0,nHour,nMinute,nSecond);
		TimeSpan[i]=*pTS; // 赋值
		delete pTS;
	}
	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")+"#";
	// 转换统计结束时间,且天数加1
	strETime="#"+(m_ETime+tp_1).Format("%Y-%m-%d")+"#";
	// 提取员工列表
	CPersonRS rs_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,
			"select IN_OUT,IO_TIME from ATTENDANCE\
			where PERSON='" + rs_person.m_ID
			+ "' and IO_TIME>" + strSTime
			+ " and IO_TIME<" +strETime
			+ " order by IO_TIME");
		strTmp1.Empty(); // 清空strTmp1
		// 初始化
		nWorkHour=nOverHour=0;
		nLeaveHDay=nErrandHDay=0;
		nLateTimes=nEarlyTimes=nAbsentTimes=0;
		TimeStamp=m_STime; // 初始化时间戳为统计开始时间
		while(TimeStamp < m_ETime+tp_02) // 判断是否超出统计结束时间
		{
			if(TimeStamp.GetDayOfWeek()!=1 &&
			   TimeStamp.GetDayOfWeek()!=7) // 判断是否工作日
			{
				for(j=0;j<=1;j++) // 遍历班次
				{
					LateTime=TimeStamp+TimeSpan[2*j]; // 设置迟到时间
					EarlyTime=TimeStamp+TimeSpan[2*j+1]; // 设置早退时间
					// 判断是否请假
					rs_Q_leave.Open(CRecordset::forwardOnly,
						"select ID from LEAVE where\
						PERSON='" + rs_person.m_ID
						+ "' and START_TIME<#"
						+ LateTime.Format("%Y-%m-%d %H:%M:%S")
						+ "# and END_TIME>#"
						+ EarlyTime.Format("%Y-%m-%d %H:%M:%S")
						+ "#");
					bLeave=(rs_Q_leave.GetRecordCount()>0);	// 判断是否有请假记录
					rs_Q_leave.Close(); // 关闭记录集
					// 判断是否出差
					rs_Q_errand.Open(CRecordset::forwardOnly,
						"select ID from ERRAND where\
						PERSON='" + rs_person.m_ID
						+ "' and START_TIME<#"
						+ LateTime.Format("%Y-%m-%d %H:%M:%S")
						+ "# and END_TIME>#"
						+ EarlyTime.Format("%Y-%m-%d %H:%M:%S")
						+ "#");
					bErrand=(rs_Q_errand.GetRecordCount()>0); // 判断是否有出差记录
					rs_Q_errand.Close(); // 关闭记录集
					if(bLeave) // 如果有请假记录
						nLeaveHDay++; // 请假记录加1
					else if(bErrand) // 如果有出差记录
					{
						nErrandHDay++; // 出差计数加1
						nWorkHour+=nHours[j]; // 按正常班累加工作时间
					}
					else // 正常上班
					{
						WorkStart=LateTime; // 设置工作开始时间
						WorkEnd=EarlyTime; // 设置工作结束时间
						bLate=TRUE; // 初始化迟到判断
						bAbsent=FALSE; // 初始化旷工判断
						// 判断是否迟到
						if(!rs_Q_attend.IsEOF() && // 记录集不空
							strTmp1.IsEmpty()) // 空,第一次GetFieldValue
							rs_Q_attend.GetFieldValue("IO_TIME",strTmp1); // 得到IO_TIME
						while(!rs_Q_attend.IsEOF()
							&& StrToTime(strTmp1)<=LateTime)
						{// 根据时间顺序判断是否迟到
							// 得到IN_OUT
							rs_Q_attend.GetFieldValue("IN_OUT",strTmp2);
							bLate=(strTmp2=="O"); // 判断上班时间前是否报到
							rs_Q_attend.MoveNext(); // 跳到下一条出勤记录
							// 得到IO_TIME
							if(!rs_Q_attend.IsEOF())
								rs_Q_attend.GetFieldValue("IO_TIME",strTmp1);
						}
						// 判断是否旷工
						if(bLate) // 判断是否迟到
						{
							if(!rs_Q_attend.IsEOF() && StrToTime(strTmp1)<EarlyTime)
								WorkStart=StrToTime(strTmp1); // 记录迟到时间
							else bAbsent=TRUE; // 如果下班前仍未报到记为旷工
						}
						bEarly=FALSE;
						// 判断是否早退
						while(!rs_Q_attend.IsEOF() && StrToTime(strTmp1)<EarlyTime)
						{
							// 得到IN_OUT
							rs_Q_attend.GetFieldValue("IN_OUT",strTmp2);
							bEarly=(strTmp2=="O"); // 判断是否有早退
							if(bEarly)
							{
								// 将早退时间记录为工作结束时间
								WorkEnd=StrToTime(strTmp1);
							}
							else WorkEnd=EarlyTime; // 将下班时间记录为工作结束时间
							rs_Q_attend.MoveNext(); // 跳至下一条出勤记录
							// 得到IO_TIME
							if(!rs_Q_attend.IsEOF())
								rs_Q_attend.GetFieldValue("IO_TIME",strTmp1);
						}
						// 如果旷工,增加旷工次数记录
						if(bAbsent) nAbsentTimes++;
						else
						{
							// 如果迟到,增加迟到次数记录
							if(bLate) nLateTimes++;
							// 如果早退,增加早退次数记录
							if(bEarly) nEarlyTimes++;
							// 计算实际工作时间
							nWorkHour+=(WorkEnd-WorkStart).GetTotalHours();
							if((WorkEnd-WorkStart).GetMinutes()>30)
								nWorkHour++; // 四舍五入
						}
					}
				} // End of 遍历班次
			} // End of 是否工作日
			TimeStamp+=tp_1; // 推进一天
		} // End of TimeStamp < m_ETime+tp_02
		rs_Q_attend.Close(); // 关闭Q_attend记录集
		// 统计加班时间
		CRecordset rs_Q_overtime(&db); // 构造Q_overtime记录集
		rs_Q_overtime.Open(CRecordset::forwardOnly,
			"select sum(WORK_HOURS) as SUM from OVERTIME\
			where PERSON='" + rs_person.m_ID
			+ "' and WORK_DATE>#"
			+ m_STime.Format("%Y-%m-%d %H:%M:%S")
			+ "# and WORK_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);
		}
		else nOverHour=0; // 无记录
		rs_Q_overtime.Close();
		// 判断是否已有该月考勤记录
		CStatRS rs_stat(&db); // 构造统计数据表
		// 设置过滤串
		rs_stat.m_strFilter="PERSON='" + rs_person.m_ID
			+ "' and YEAR_MONTH='" + m_strTime + "'";
		rs_stat.Open(); // 打开数据表
		if(rs_stat.GetRecordCount()==0) // 判断是否有该月份考勤记录
		{
			// 获取计数
			CCounterRS rs_counter(&db); // 构造计数器表
			rs_counter.m_strFilter = "ID='S'"; // 设置过滤器,提取计数值
			rs_counter.Open(); // 打开计数器记录表
			counter=rs_counter.m_COUNTER_VALUE; // 提取计数值
			counter++; // 计数值加1
			rs_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(); // 关闭员工表
	CStatRS rs_stat(&db); // 构造统计数据表
	UpdateList(rs_stat); // 更新列表框
}