c#考勤统计
现在项目需求,需要从多张表中获取数据,组装到一个实体对象中,并通过计算统计出每个员工的考勤记录。(全凭自己思考做的,不足的地方希望各位大神指正!毕竟自己能力有限,思考不全)
考勤统计列表:
明细列表:
如下代码:
/// <summary> /// 获取考勤列表 /// </summary> /// <param name="dto"></param> /// <param name="Page"></param> /// <param name="PageSize"></param> /// <returns></returns> public ResultEntity<List<AttendCountDTO>> QueryAttendList(SearchAttendCountDTO dto, int Page, int PageSize) { #region 获取当前年月日 var FirstDate = DateTime.Parse(DateTime.Now.ToString("yyyy-MM") + " -01"); //当前月第一天 var NowDate = DateTime.Now; #endregion var lists = new List<AttendCountDTO>(); DepartRepository departRepository = new DepartRepository(); AttendCountRepository attendCountRepository = new AttendCountRepository(); HolidayRepository holidayRepository = new HolidayRepository(); DPEAssRepository dpeAssRepository = new DPEAssRepository(); PostRepository postRepository = new PostRepository(); AttendEditorRepository attendEditorRepository = new AttendEditorRepository(); AttendancesRepository attendRepository = new AttendancesRepository(); GetWorkDays workDays = new GetWorkDays(); var allEmployees = attendCountRepository.QueryAllEmployee(dto); //所有员工 var allEmployeeIds = allEmployees.Select(f => f.Id).ToList(); //所有员工Id var allAttendEntities = attendRepository.GetAllAttendancesById(allEmployeeIds); //所有员工的所有考勤 var allOffWorkEntities = attendRepository.GetAllOffWork(allEmployeeIds); //所有员工的所有考勤 var allDPEEntities = dpeAssRepository.GetAllDPEAssById(allEmployeeIds); //获得所有员工关联表 var allDPEIds = allDPEEntities.Select(f => f.PostId).ToList(); //获得所有员工关联表的岗位Id var allPostEntities = postRepository.GetAllPostById(allDPEIds); //获得所有员工的岗位信息 var allDepartIds = allPostEntities.Select(f => f.DepartmentId).ToList(); //获得所有员工岗位的部门Id var allDepartEntities = departRepository.QueryAllDepart(allDepartIds); //获得所有员工的部门信息 var allAttendConfigEntities = attendEditorRepository.GetAllAttendancesConfigById(allDepartIds); //获得所有员工的考勤配置信息 if (allEmployees.Count() > 0) { foreach (var Employee in allEmployees) { AttendCountDTO attendCountDTO = new AttendCountDTO(); #region 获得部门名称,和该部门的上班下班时间 string[] WorkDayNums = null; int NoWorkDayNum = 0; var workStartTime = new DateTime(2007, 1, 1, 9, 00, 00); var workEndTime = new DateTime(2007, 1, 1, 18, 00, 00); var dpeass = allDPEEntities.Where(f => f.EmployeeId == Employee.Id).FirstOrDefault(); if (dpeass != null) { var post = allPostEntities.Where(f => f.Id == dpeass.PostId).FirstOrDefault(); if (post != null) { if (string.IsNullOrEmpty(dto.Position) || post.Name == dto.Position) { attendCountDTO.Position = post.Name; var department = allDepartEntities.Where(f => f.Id == post.DepartmentId).FirstOrDefault(); //获取员工所属的部门 if (department != null) { if (string.IsNullOrEmpty(dto.DepartmentName) || department.Name.Contains(dto.DepartmentName)) { attendCountDTO.DepartmentName = department.Name; attendCountDTO.DepartmentId = department.Id; var attendConfig = allAttendConfigEntities.Where(f => f.DepartmentId == department.Id).FirstOrDefault(); if (attendConfig != null) { workStartTime = DateTime.Parse(attendConfig.StartTime); //该部门的上班时间和下班时间 workEndTime = DateTime.Parse(attendConfig.EndTime); #region 工作日 string workDay = attendConfig.WorkDays; string WorkDay = workDay.Substring(0, workDay.Length - 1); WorkDayNums = WorkDay.Split(','); NoWorkDayNum = 7 - WorkDayNums.Count(); //该员工所在部门的一周非工作天数 #endregion } } else { continue; } } } else { continue; } } } #endregion #region 根据当天时刻修正次数 int Modify = 0; var time = DateTime.Parse(NowDate.ToString("HH:mm:ss")); var startTime = DateTime.Parse(workStartTime.ToString("HH:mm:ss")); var endTime = DateTime.Parse(workEndTime.ToString("HH:mm:ss")); if (time <= startTime) //当前时间在第二天中午之前,为为一天,中午12点后计算结果为2天,则需要对考勤次数进行修正。 { Modify = 0; } else if (time >= startTime && time <= DateTime.Parse("12:00:00")) { Modify = -1; } else if (time >= DateTime.Parse("12:00:00") && time < endTime) { Modify = 1; } else if (time >= endTime) { Modify = 0; } #endregion DateTime firstDate = FirstDate; var applyTime = Employee.EntryDate; //员工入职时间 if (applyTime.HasValue && applyTime >= FirstDate) //如果员工是这个月内刚入职的,取入职时间 { firstDate = DateTime.Parse(applyTime.Value.ToString("yyyy-MM-dd")); } var attendEntities = allAttendEntities.Where(f => f.CreaterId == Employee.Id && (f.CreateDate >= firstDate && f.CreateDate <= NowDate)).OrderBy(f =>f.CreateDate).ToList(); var attendCounts = attendEntities.Count(); //当前月实际打卡的次数 #region //实际打卡的天数 List<string> list = new List<string>(); foreach (var attend in attendEntities) { var attendDay = attend.CreateDate.ToLongDateString(); list.Add(attendDay); } attendCountDTO.ActualDays = list.Distinct().Count(); //实际打卡的天数 #endregion #region 应打卡的天数 int days = 0; int AllDay = 0; var nowTime = DateTime.Now; if (applyTime != null) { attendCountDTO.OutHiredate = applyTime == null ? "" : DateTime.Parse(applyTime.ToString()).ToString("yyyy-MM-dd HH:mm:ss"); attendCountDTO.Hiredate = applyTime; if (NoWorkDayNum == 0) { AllDay = workDays.GetNoHolidayWorkDay(firstDate,NowDate); } else { AllDay = workDays.GetDate(firstDate, NowDate, WorkDayNums); //获取到(设置的指定的工作日)所有天数 //AllDay = workDays.GetWorkDay(firstDate, NowDate, NoWorkDayNum); //获取工作天数(已去除设置的非工作日) } var holidayDays = holidayRepository.GetHolidayByTime(firstDate, nowTime); //当月所有的节假日 if (holidayDays.Count() > 0) { holidayDays.ForEach(f => { TimeSpan ts = f.EndTime - f.BeginTime; days += ts.Days; }); } #region 请假的天数 int offWorkDay = 0; DateTime? validEndTime = null; var OffWorkEntitys = allOffWorkEntities.Where(f => f.CreaterId == Employee.Id && f.StartTime >= firstDate && f.StartTime <= nowTime).ToList(); if (OffWorkEntitys.Count() > 0) { foreach (var item in OffWorkEntitys) { if (item.EndTime > nowTime) //如果请假的结束时间大于当前考勤的统计时间,取当前时间, { validEndTime = nowTime; } else { validEndTime = item.EndTime; //如果请假的结束时间小于等于当前考勤的统计时间,取请假的结束时间, } TimeSpan? t1 = validEndTime - item.StartTime; offWorkDay += t1.Value.Days; } } #endregion attendCountDTO.ShouldDays = AllDay - days - offWorkDay; //应打卡的天数(工作日天数-法定节假日天数 - 请假天数) #endregion attendCountDTO.AbsenteeismDays = attendCountDTO.ShouldDays - attendCountDTO.ActualDays; //应打天数-实打天数 attendCountDTO.ShouldAttendCounts = (attendCountDTO.ShouldDays * 2) - Modify; //应打考勤的次数 attendCountDTO.NoAttendCounts = attendCountDTO.ShouldAttendCounts - attendCounts; //未打卡的次数(应打卡的次数-实际打卡的次数) } #region 判断迟到还是早退,以及次数 //var entitys = GetResignInfo(Employee.Id); //所有考勤次数 int lateCount = 0; int earlyLeaveCount = 0; int AllCounts = attendEntities.Count(); for (int i = 0; i < AllCounts; i++) { if (i == 0 && i + 1 == AllCounts) //只打卡了一次 (第一种情况) 只判断是否迟到 { if (attendEntities[i].CreateDate.TimeOfDay.TotalHours >= workStartTime.TimeOfDay.TotalHours) lateCount += 1; } if (i == 0 && i + 1 < AllCounts) //打卡多次,这是第一次 (第二种情况) { if (attendEntities[i].CreateDate.ToLongDateString() == attendEntities[i + 1].CreateDate.ToLongDateString()) { if (attendEntities[i].CreateDate.TimeOfDay.TotalHours >= workStartTime.TimeOfDay.TotalHours) lateCount += 1; } else if (attendEntities[i].CreateDate.ToLongDateString() != attendEntities[i + 1].CreateDate.ToLongDateString()) { if (attendEntities[i].CreateDate.TimeOfDay.TotalHours >= workStartTime.TimeOfDay.TotalHours) lateCount += 1; } } if (i > 0 && i + 1 < AllCounts) //打卡多次,既不是第一次,也不是最后一次 (第三种情况) { if (attendEntities[i].CreateDate.ToLongDateString() == attendEntities[i - 1].CreateDate.ToLongDateString()) { if (attendEntities[i].CreateDate.TimeOfDay.TotalHours <= workEndTime.TimeOfDay.TotalHours) earlyLeaveCount += 1; //打卡了两次,这是下午一次 } if (attendEntities[i].CreateDate.ToLongDateString() == attendEntities[i + 1].CreateDate.ToLongDateString()) { if (attendEntities[i].CreateDate.TimeOfDay.TotalHours > workStartTime.TimeOfDay.TotalHours) lateCount += 1; //打卡了两次,这是上午一次 } if (attendEntities[i].CreateDate.ToLongDateString() != attendEntities[i - 1].CreateDate.ToLongDateString() && attendEntities[i].CreateDate.ToLongDateString() != attendEntities[i + 1].CreateDate.ToLongDateString()) { if (attendEntities[i].CreateDate.TimeOfDay.TotalHours >= workStartTime.TimeOfDay.TotalHours) lateCount += 1; //只打卡一次,大于上午上班时间,即迟到 } } if (i > 0 && i + 1 == AllCounts) //打卡多次,这是是最后一次 (第四种情况) { if (attendEntities[i].CreateDate.ToLongDateString() == attendEntities[i - 1].CreateDate.ToLongDateString()) { if (attendEntities[i].CreateDate.TimeOfDay.TotalHours <= workEndTime.TimeOfDay.TotalHours) earlyLeaveCount += 1; //打卡了两次,这是下午一次 } if (attendEntities[i].CreateDate.ToLongDateString() != attendEntities[i - 1].CreateDate.ToLongDateString()) { if (attendEntities[i].CreateDate.TimeOfDay.TotalHours >= workStartTime.TimeOfDay.TotalHours) lateCount += 1; } } } attendCountDTO.LateCounts = lateCount; attendCountDTO.EarlyLeaveCounts = earlyLeaveCount; attendCountDTO.Id = Employee.Id; attendCountDTO.Name = Employee.Name; attendCountDTO.PhoneNumber = Employee.Phone; lists.Add(attendCountDTO); #endregion } } DateTime? EndTime = null; if (dto.EndTime.HasValue) { EndTime = dto.EndTime.Value.AddDays(1); } var filterEmployees = lists.Where(f => (string.IsNullOrEmpty(dto.DepartmentName) || (!string.IsNullOrEmpty(f.DepartmentName) && f.DepartmentName.Contains(dto.DepartmentName))) && (string.IsNullOrEmpty(dto.Position) || f.Position == dto.Position) && (!dto.StartTime.HasValue || f.Hiredate >= dto.StartTime) && (!EndTime.HasValue || f.Hiredate <= EndTime)).ToList(); var filterEmployee = filterEmployees.OrderBy(f => f.Hiredate).Skip((Page - 1) * PageSize).ToList(); var resultEntity = GetResultEntity(filterEmployee); resultEntity.Count = filterEmployees.Count(); return resultEntity; } /// <summary> /// 获取考勤详情 /// </summary> /// <param name="param"></param> /// <returns></returns> public ResultEntity<List<AttendCountDetailDTO>> QueryAttendDetailList(AttendDetailDTO param) { var lists = new List<AttendCountDetailDTO>(); AttendEditorRepository attendEditorRepository = new AttendEditorRepository(); AttendancesRepository attendRepositry = new AttendancesRepository(); AttendancesConfig attendConfig = new AttendancesConfig(); var attendEditor = attendEditorRepository.GetAttendancesConfigById(param.DepartmentId); //设置的规定考勤 if (attendEditor == null) { attendConfig.StartTime = "09:00:00"; attendConfig.EndTime = "18:00:00"; } else { attendConfig.StartTime = attendEditor.StartTime; attendConfig.EndTime = attendEditor.EndTime; } var attends = attendRepositry.GetAttendancesById(param.Id); //实际员工打卡信息 var DetailCount = attends.Count(); //考勤次数 for (int i = 0; i < attends.Count(); i++) { AttendCountDetailDTO dto = new AttendCountDetailDTO(); dto.AttendDate = attends[i].CreateDate.ToString("yyyy-MM-dd HH:mm:ss"); dto.ActualAttendTime = attends[i].CreateDate.ToLongTimeString().ToString(); if (DetailCount ==1) //只打卡了一次 { if (int.Parse(attends[i].CreateDate.ToString("HH")) >= 1 && int.Parse(attends[i].CreateDate.ToString("HH")) <= 12) { dto.AttendType = "上午考勤"; } else { dto.AttendType = "下午考勤"; } if (attends[i].CreateDate.TimeOfDay.TotalHours <= DateTime.Parse(attendConfig.StartTime).TimeOfDay.TotalHours) { dto.IsLate = false; } else { dto.IsLate = true; } } if (i == 0 && i + 1 < DetailCount) //打卡多次,这是第一次 (第二种情况) { if (attends[i].CreateDate.ToLongDateString() == attends[i + 1].CreateDate.ToLongDateString()) { if (int.Parse(attends[i].CreateDate.ToString("HH")) >= 1 && int.Parse(attends[i].CreateDate.ToString("HH")) <= 12) { dto.AttendType = "上午考勤"; } else { dto.AttendType = "下午考勤"; } if ( attends[i].CreateDate.TimeOfDay.TotalHours <= DateTime.Parse(attendConfig.StartTime).TimeOfDay.TotalHours) { dto.IsLate = false; } else { dto.IsLate = true; } } else if (attends[i].CreateDate.ToLongDateString() != attends[i + 1].CreateDate.ToLongDateString()) { if (int.Parse(attends[i].CreateDate.ToString("HH")) >= 1 && int.Parse(attends[i].CreateDate.ToString("HH")) <= 12) { dto.AttendType = "上午考勤"; } else { dto.AttendType = "下午考勤"; } if ( attends[i].CreateDate.TimeOfDay.TotalHours <= DateTime.Parse(attendConfig.StartTime).TimeOfDay.TotalHours) { dto.IsLate = false; } else { dto.IsLate = true; } } } if (i > 0 && i + 1 < DetailCount) //打卡多次,既不是第一次,也不是最后一次 (第三种情况) { if (attends[i].CreateDate.ToLongDateString() == attends[i - 1].CreateDate.ToLongDateString()) //打卡了两次,这是下午一次 { if (attends[i].CreateDate.TimeOfDay.TotalHours <= DateTime.Parse(attendConfig.EndTime).TimeOfDay.TotalHours) { dto.IsRarlyLeave = true; } else { dto.IsRarlyLeave = false; } if (int.Parse(attends[i].CreateDate.ToString("HH")) >= 1 && int.Parse(attends[i].CreateDate.ToString("HH")) <= 12) { dto.AttendType = "上午考勤"; } else { dto.AttendType = "下午考勤"; } } if (attends[i].CreateDate.ToLongDateString() == attends[i + 1].CreateDate.ToLongDateString()) //打卡了两次,这是上午一次 { if ( attends[i].CreateDate.TimeOfDay.TotalHours <= DateTime.Parse(attendConfig.StartTime).TimeOfDay.TotalHours) { dto.IsLate = false; } else { dto.IsLate = true; } if (int.Parse(attends[i].CreateDate.ToString("HH")) >= 1 && int.Parse(attends[i].CreateDate.ToString("HH")) <= 12) { dto.AttendType = "上午考勤"; } else { dto.AttendType = "下午考勤"; } } if (attends[i].CreateDate.ToLongDateString() != attends[i - 1].CreateDate.ToLongDateString() && attends[i].CreateDate.ToLongDateString() != attends[i + 1].CreateDate.ToLongDateString()) //一天只打卡了一次, { if (int.Parse(attends[i].CreateDate.ToString("HH")) >= 1 && int.Parse(attends[i].CreateDate.ToString("HH")) <= 12) { dto.AttendType = "上午考勤"; } else { dto.AttendType = "下午考勤"; } if (attends[i].CreateDate.TimeOfDay.TotalHours <= DateTime.Parse(attendConfig.StartTime).TimeOfDay.TotalHours) { dto.IsLate = false; } else { dto.IsLate = true; } } } if (i > 0 && i + 1 == DetailCount) //打卡多次,这是是最后一次 (第四种情况) { if (attends[i].CreateDate.ToLongDateString() == attends[i - 1].CreateDate.ToLongDateString()) //打卡了两次,这是下午一次 { if (attends[i].CreateDate.TimeOfDay.TotalHours <= DateTime.Parse(attendConfig.EndTime).TimeOfDay.TotalHours) { dto.IsRarlyLeave = true; } else { dto.IsRarlyLeave = false; } if (int.Parse(attends[i].CreateDate.ToString("HH")) >= 1 && int.Parse(attends[i].CreateDate.ToString("HH")) <= 12) { dto.AttendType = "上午考勤"; } else { dto.AttendType = "下午考勤"; } } if (attends[i].CreateDate.ToLongDateString() != attends[i - 1].CreateDate.ToLongDateString()) //只打卡了一次 { if (int.Parse(attends[i].CreateDate.ToString("HH")) >= 1 && int.Parse(attends[i].CreateDate.ToString("HH")) <= 12) { dto.AttendType = "上午考勤"; } else { dto.AttendType = "下午考勤"; } if ( attends[i].CreateDate.TimeOfDay.TotalHours <= DateTime.Parse(attendConfig.StartTime).TimeOfDay.TotalHours) { dto.IsLate = false; } else { dto.IsLate = true; } } } dto.Address = attends[i].Addr; dto.Picture = attends[i].GPS; dto.AttendRemark = attends[i].Description; lists.Add(dto); } var resultEntity = GetResultEntity(lists); resultEntity.Count = lists.Count(); return resultEntity; }
注意:1、工作日不是周一到周五,而是系统配置,即周一到周日中任意某天都可能是工作日。
2、节假日也是由系统配置。
3、统计的是当月月初到查看的此刻的统计数据,(如果员工是新员工,即入职时间在当月月初之后,已新员工入职时间算起)
4、一天控制写入两次打卡记录,上午一次,下午一次(上午以最早打卡时间为准,下午以最晚打卡时间为准)
5、一天如果只打卡了一次,只判断是否迟到。
6、上下班时间由该员工所在部门的系统配置,配置了就按配置时间,否则按写死的默认值。
计算一个月中工作日天数的代码:(分别是计算传统的周一到周五的工作日,和指定时间的工作日天数(本人项目))
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace HYSMA.AppSrv.AttendManage.AttendCase { /// <summary> /// 取工作日 /// </summary> public class GetWorkDays { /// <summary> /// 根据时间差,获取工作日天数(除去了周六周日) /// </summary> /// <param name="StartTime"></param> /// <param name="EndTime"></param> /// <returns></returns> public int GetWorkDay(DateTime StartTime, DateTime EndTime) { DateTime start = StartTime; DateTime end = EndTime; TimeSpan span = end - start; //int totleDay=span.Days; //DateTime spanNu = DateTime.Now.Subtract(span); int AllDays = Convert.ToInt32(span.TotalDays) + 1;//差距的所有天数 int totleWeek = AllDays / 7;//差别多少周 int yuDay = AllDays % 7; //除了整个星期的天数 int lastDay = 0; if (yuDay == 0) //正好整个周 { lastDay = AllDays - (totleWeek * 2); } else { int weekDay = 0; int endWeekDay = 0; //多余的天数有几天是周六或者周日 switch (start.DayOfWeek) { case DayOfWeek.Monday: weekDay = 1; break; case DayOfWeek.Tuesday: weekDay = 2; break; case DayOfWeek.Wednesday: weekDay = 3; break; case DayOfWeek.Thursday: weekDay = 4; break; case DayOfWeek.Friday: weekDay = 5; break; case DayOfWeek.Saturday: weekDay = 6; break; case DayOfWeek.Sunday: weekDay = 7; break; } if ((weekDay == 6 && yuDay >= 2) || (weekDay == 7 && yuDay >= 1) || (weekDay == 5 && yuDay >= 3) || (weekDay == 4 && yuDay >= 4) || (weekDay == 3 && yuDay >= 5) || (weekDay == 2 && yuDay >= 6) || (weekDay == 1 && yuDay >= 7)) { endWeekDay = 2; } if ((weekDay == 6 && yuDay < 1) || (weekDay == 7 && yuDay < 5) || (weekDay == 5 && yuDay < 2) || (weekDay == 4 && yuDay < 3) || (weekDay == 3 && yuDay < 4) || (weekDay == 2 && yuDay < 5) || (weekDay == 1 && yuDay < 6)) { endWeekDay = 1; } lastDay = AllDays - (totleWeek * 2) - endWeekDay; } return lastDay; } /// <summary> /// 获取工作日天数(无节假日) /// </summary> /// <param name="StartTime"></param> /// <param name="EndTime"></param> /// <returns></returns> public int GetNoHolidayWorkDay(DateTime StartTime, DateTime EndTime) { TimeSpan t = EndTime - StartTime; var tatalDay = Convert.ToInt32(t.TotalDays); return tatalDay; } /// <summary> /// 获取一个时间段中(周一有几天,周二有几天,周三有几天。。。。到周日)(从而获取工作日天数) /// </summary> /// <param name="startDate"></param> /// <param name="endDate"></param> /// <param name="workDay">从数据库中取得的设置的工作日时间(如:周一,周三,周五,周日)</param> /// <returns></returns> public int GetDate(DateTime startDate, DateTime endDate ,string[] workDay) //这里的workDay数组是我从数据库中取得的字符串(原始格式类似:"周一,周三,周六..."),通过split分割而成的。以便进行操作 { int mondayCount = 0, tuesdayCount = 0, wednesdayCount = 0, thursdayCount = 0, fridayCount = 0, satursdayCount = 0, sundayCount = 0;//每个星期日(星期一,星期二...)的总天数 int LastDay = 0; DateTime startDT = startDate; //开始时间 DateTime endDT = endDate; //结束时间 TimeSpan dt = endDT - startDT; int dayCount = Convert.ToInt32(dt.TotalDays); //总天数 (后一个日期在中午12点之前,这天不算,超过12点,加上这一天) for (int i = 0; i < dayCount; i++) { switch (startDT.AddDays(i).DayOfWeek) { case DayOfWeek.Monday: mondayCount += 1; break; case DayOfWeek.Tuesday: tuesdayCount += 1; break; case DayOfWeek.Wednesday: wednesdayCount += 1; break; case DayOfWeek.Thursday: thursdayCount += 1; break; case DayOfWeek.Friday: fridayCount += 1; break; case DayOfWeek.Saturday: satursdayCount += 1; break; case DayOfWeek.Sunday: sundayCount += 1; break; } } foreach (var item in workDay) { switch (item) { case "周一": LastDay += mondayCount; break; case "周二": LastDay += tuesdayCount; break; case "周三": LastDay += wednesdayCount; break; case "周四": LastDay += thursdayCount; break; case "周五": LastDay += fridayCount; break; case "周六": LastDay += satursdayCount; break; case "周日": LastDay += sundayCount; break; } } //int lastDays = mondayCount + tuesdayCount + wednesdayCount + thursdayCount + fridayCount + satursdayCount + sundayCount; return LastDay; } } }