/// <summary> /// 是否是长假归来的员工 /// </summary> /// <param name="job_num">工号</param> /// <param name="emp_name">姓名</param> /// <param name="emp_name">本月从一号开始未打卡的天数</param> /// <returns></returns> public static bool LongHolidayReturnBackFromThisMonth(string job_num, string emp_name, DateTime date_time, int count) { bool result = false; using (var context = new Context()) { List <AnalysisOfMonth> analysis_of_month_list = context.AnalysisOfMonth.Where(x => x.job_num == job_num && x.emp_name == emp_name).OrderBy(t => t.date).AsNoTracking().ToList(); //有之前月份的月度分析记录的才有可能是归来人员 if (analysis_of_month_list.Count > 0) { AnalysisOfMonth last_one = analysis_of_month_list.Last(); //如果上个月的月度打卡记录分析直接为空的话(上个月一整个月都没来,但是更早之前来过) if (last_one.date < new DateTime(date_time.Year, date_time.Month - 1, 1)) { return(true); } //上个月最后工作日所在的未打卡日期切片的天数 int last_holiday_count = 0; //只分析上个月的,避免因为重复分析分析了同一个月的 if (last_one.date.Year == date_time.Year && last_one.date.Month == date_time.Month - 1) { //避免为空的情况(下面的代码会报错,且从逻辑上来说没有处理的必要) if (last_one.absence_punch_card_day_list.Length > 0) { List <int> last_holiday = last_one.absence_punch_card_day_list.Split(";").Reverse().Skip(1).First().Split(",").Select(Int32.Parse).ToList(); //获取上个月工作日列表 List <int> workday_list = GetWorkDayListOfMonth(date_time.Year, date_time.Month); if ((last_holiday.Contains(workday_list.Last()))) { last_holiday_count = last_holiday.Count; } } } //假如上个月最后一个未打卡日期列表切片里面包含工作日的最后一天,且切片天数和下个月从一号开始未打卡天数 //加在一起大于LongHolidayJudge里面设置的天数,就判定他属于请了长假,或是出差之类的,将他划归为归来人员 if (LongHolidayJudge(last_holiday_count + count)) { return(true); } } } return(result); }
/// <summary> /// 对所有员工的打卡数据进行分析,返回月度和每日的分析结果 /// </summary> /// <param name="attendance_info_all_list">一个月里所有员工的所有打卡数据</param> /// <param name="skip_employee_list">不需要分析的员工列表</param> /// <param name="work_day_list">某月的工作日列表</param> /// <param name="weekend_day_List">某月的周末日期列表(排除周末加班)</param> /// <returns>所有员工的月度和每日打卡数据分析结果</returns> public AnalysisResult GetAnalysisResult(List <AttendanceInfo> attendance_info_all_list, List <SkipEmployee> skip_employee_list, List <int> work_day_list, List <int> weekend_day_List) { //以员工为目标对数据进行分组 //因为暂时不会写这个对象的类型,没办法通过传参来调用,所以只能放在具体的方法里,希望以后可以重写 var employee_group = attendance_info_all_list.GroupBy(x => new { x.job_num, x.emp_name }).ToList(); //从员工分组列表中剔除那些不需要分析的 foreach (var skip_employee in skip_employee_list) { employee_group.RemoveAll(x => x.Key.job_num == skip_employee.job_num && x.Key.emp_name == skip_employee.emp_name); } //单个员工的月度打卡数据分析结果 AnalysisOfMonth analysis_of_month = new AnalysisOfMonth(); //所有员工的月度打卡数据分析结果 List <AnalysisOfMonth> analysis_of_month_list = new List <AnalysisOfMonth>(); //单个员工本月内每天打卡数据的分析结果 List <AnalysisOfDay> analysis_of_day_one_list = new List <AnalysisOfDay>(); //所有员工本月内每天打卡数据的分析结果 List <AnalysisOfDay> analysis_of_day_all_list = new List <AnalysisOfDay>(); foreach (var employee in employee_group) { analysis_of_day_one_list = analysisOfDay.GetAnalysisOfDayList(employee.ToList(), analysis_of_month); foreach (var v in analysis_of_day_one_list) { analysis_of_day_all_list.Add(v); } analysis_of_month = analysisOfMonth.GetAnalysisOfMonth(employee.ToList(), work_day_list, weekend_day_List, analysis_of_day_one_list); analysis_of_month_list.Add(analysis_of_month); } AnalysisResult result = new AnalysisResult(); result.analysis_of_day = analysis_of_day_all_list; result.analysis_of_month = analysis_of_month_list; return(result); }
/// <summary> /// 分析某个员工对象一天的打卡数据 /// </summary> /// <param name="infos">当天员工所有的打卡记录</param> /// <returns></returns> public static List <AnalysisOfDay> GetAnalysisOfDayList(List <AttendanceInfo> one_emp_month_infos, AnalysisOfMonth analysis_of_month) { List <AnalysisOfDay> one_emp_day_analysis_list = new List <AnalysisOfDay>(); List <List <AttendanceInfo> > one_emp_day_infos_group = analysisUtil.GetSliceOfDayFromMonth(one_emp_month_infos.First().inout_time.Date, one_emp_month_infos); foreach (var one_emp_day_infos in one_emp_day_infos_group) { AnalysisOfDay analysis_result_of_one_day = GetAnalysisResultOfOneDay(one_emp_day_infos); one_emp_day_analysis_list.Add(analysis_result_of_one_day); } return(one_emp_day_analysis_list); }
/// <summary> /// 分析某个员工对象一个月的打卡数据,用以获得一些整体性的无法从单日里面获取的信息 /// </summary> /// <param name="emp_month_infos">目标员工对象一个月的打卡数据</param> /// <param name="workdayList">某月的工作日列表</param> /// <param name="weekend_day_list">某月的周末日期列表(排除周末加班)</param> /// <returns>某员工月度打卡数据分析结果</returns> public static AnalysisOfMonth GetAnalysisOfMonth(List <AttendanceInfo> one_emp_month_infos, List <int> work_day_list, List <int> weekend_day_list, List <AnalysisOfDay> analysis_of_day_list) { //员工月度早晚打卡小时数据 PunchCardHourDistinguish punch_card_hour_distinguish = analysisUtil.GetFirstAndLastPunchCardHour(one_emp_month_infos); List <PunchCardHour> first_and_last_punch_card_hours_all = punch_card_hour_distinguish.all; List <PunchCardHour> first_and_last_punch_card_hours_normal = punch_card_hour_distinguish.normal; List <PunchCardHour> first_and_last_punch_card_hours_only_one = punch_card_hour_distinguish.only_one; AnalysisOfMonth analysis_of_month = new AnalysisOfMonth(); AttendanceInfo first_day_info = one_emp_month_infos.First(); analysis_of_month.date = new DateTime(first_day_info.inout_time.Year, first_day_info.inout_time.Month, 1); //日期(年月) analysis_of_month.card_id = first_day_info.card_id; //卡号 analysis_of_month.job_num = first_day_info.job_num; //工号 analysis_of_month.emp_name = first_day_info.emp_name; //姓名 analysis_of_month.punch_card_day_count = first_and_last_punch_card_hours_all.Count(); foreach (var analysis_of_day in analysis_of_day_list) { //不包括一天只打一次卡的 if (analysis_of_day.punch_card_count_total > 1) { //总打卡数(不包括一天只打一次卡的),之所以这么做,是因为后面日平均打卡数要用到这个数据 analysis_of_month.punch_card_count_valid_month += analysis_of_day.punch_card_count_valid; } } foreach (var day in first_and_last_punch_card_hours_normal) { analysis_of_month.attendance_time_of_month += day.time_of_duration; //所有正常打卡日在公司的总时间 } if (first_and_last_punch_card_hours_normal.Count() > 0) //以防某个员工一个月内没有一天有两次以上打卡的极端情况 { analysis_of_month.punch_card_count_valid_day = analysis_of_month.punch_card_count_valid_month / (double)first_and_last_punch_card_hours_normal.Count(); //打卡日里的平均打卡次数 AttendanceNormalAndShort attendance_normal_and_short = analysisUtil.GetAttendanceNormalAndShort(first_and_last_punch_card_hours_normal); analysis_of_month.attendance_time_of_day_normal = attendance_normal_and_short.attendance_time_of_day_normal; analysis_of_month.attendance_time_of_day_normal_count = attendance_normal_and_short.attendance_time_of_day_normal_count; analysis_of_month.attendance_time_of_day_short = attendance_normal_and_short.attendance_time_of_day_short; analysis_of_month.attendance_time_of_day_short_count = attendance_normal_and_short.attendance_time_of_day_short_count; } List <int> punch_card_day_list_all = first_and_last_punch_card_hours_all.Select(t => t.day).ToList(); List <int> punch_card_day_list_only_one = first_and_last_punch_card_hours_only_one.Select(t => t.day).ToList(); List <int> punch_card_day_hour_list_only_one = first_and_last_punch_card_hours_only_one.Select(t => t.start_hour).ToList(); List <int> less_than_workday_list = work_day_list.Except(punch_card_day_list_all).ToList(); //打卡日期比工作日期少的日期所组成的list List <int> more_than_workday_list = punch_card_day_list_all.Except(work_day_list).ToList(); //打卡日期比工作日期多的日期所组成的list analysis_of_month.absence_punch_card_day_count = less_than_workday_list.Count; //缺勤打卡次数 analysis_of_month.exceed_punch_card_day_count = more_than_workday_list.Count; //超勤打卡次数 if (analysis_of_month.exceed_punch_card_day_count > 0) { analysis_of_month.exceed_punch_card_day_list = string.Join(",", more_than_workday_list.ToList()); } analysis_of_month.has_only_one_punch_card_day = punch_card_day_list_only_one.Count > 0 ? true : false; analysis_of_month.only_one_punch_card_day_list = string.Join(",", punch_card_day_list_only_one); analysis_of_month.only_one_punch_card_day_hour_list = string.Join(",", punch_card_day_hour_list_only_one); //这里都用正常打卡日(至少两次打卡,排除一次打卡),因为单次打卡日要首先要判断此次打卡是初始打卡还是最后打卡, //再者由于其只有一次打卡导致接下来的打卡小时变更次数统计那里由于缺少相应的记录而无所适从,所以干脆独立出来. analysis_of_month.start_hour_unique_list = string.Join(",", first_and_last_punch_card_hours_normal.OrderBy(t => t.start_hour).Select(t => t.start_hour).Distinct().ToList()); analysis_of_month.end_hour_unique_list = string.Join(",", first_and_last_punch_card_hours_normal.OrderBy(t => t.end_hour).Select(t => t.end_hour).Distinct().ToList()); StartAndEenHourChangeTimes start_and_een_hour_change_times = analysisUtil.GetStartAndEenHourChangeTimes(first_and_last_punch_card_hours_normal); analysis_of_month.start_hour_change_times = start_and_een_hour_change_times.start_hour_change_times; analysis_of_month.end_hour_change_times = start_and_een_hour_change_times.end_hour_change_times; //获取是否满勤以及身份推测等相关信息 FullAttendanceAndRoleSpeculate full_attendance_and_role_speculate = analysisUtil.GetFullAttendanceAndRoleSpeculate(less_than_workday_list, weekend_day_list, analysis_of_month.job_num, analysis_of_month.emp_name, analysis_of_month.date); analysis_of_month.full_attendance = full_attendance_and_role_speculate.full_attendance; analysis_of_month.role_speculate = full_attendance_and_role_speculate.role_speculate; analysis_of_month.limited_full_attendance = full_attendance_and_role_speculate.limited_full_attendance; analysis_of_month.absence_sections_count = full_attendance_and_role_speculate.absence_sections.Count(); if (analysis_of_month.absence_punch_card_day_count > 0) { foreach (var one_section in full_attendance_and_role_speculate.absence_sections) { analysis_of_month.absence_punch_card_day_list += string.Join(",", one_section) + ";"; } } analysis_of_month.exist_long_holiday = full_attendance_and_role_speculate.long_holiday; return(analysis_of_month); }
/// <summary> /// 入口方法 /// </summary> public void AnalysisResultsToMySQL() { using (var context = new Context()) { //获取一个月内所有员工的打卡信息 List <AttendanceInfo> attendance_info_all_list = context.AttendanceInfo .OrderBy(x => x.inout_time) .AsNoTracking() .ToList(); if (attendance_info_all_list.Count == 0) { Console.WriteLine("数据表数据为空,停止分析"); return; } //确认数据表里的数据是同年同月的 if (attendance_info_all_list.First().inout_time.Year != attendance_info_all_list.Last().inout_time.Year&& attendance_info_all_list.First().inout_time.Month != attendance_info_all_list.Last().inout_time.Month) { Console.WriteLine("此数据表横跨多个月份,请提供一个月的员工打卡数据"); return; } int year = attendance_info_all_list.First().inout_time.Year; int month = attendance_info_all_list.First().inout_time.Month; //获取工作日列表 List <int> work_day_list = analysisUtil.GetWorkDayListOfMonth(year, month); //获取周末日期列表(排除周末加班) List <int> weekend_day_list = analysisUtil.GetWeekendDayListOfMonth(year, month); //获取所有不需要分析的人员 List <SkipEmployee> skip_employee_list = context.SkipEmployee.AsNoTracking().ToList(); AnalysisResult analysis_result = GetAnalysisResult(attendance_info_all_list, skip_employee_list, work_day_list, weekend_day_list); AnalysisOfMonth first_analysis_of_month = analysis_result.analysis_of_month.First(); int month_exist_count = context.AnalysisOfMonth.Where(x => x.job_num == first_analysis_of_month.job_num && x.emp_name == first_analysis_of_month.emp_name && x.date == first_analysis_of_month.date).Count(); if (month_exist_count == 0) { context.AnalysisOfMonth.AddRange(analysis_result.analysis_of_month); var month_count = context.SaveChanges(); Console.WriteLine("存储员工月度打卡分析记录:" + month_count + "条"); } else { Console.WriteLine("月度分析结果中的第一条在数据库中已存在,放弃录入"); } AnalysisOfDay first_analysis_of_day = analysis_result.analysis_of_day.First(); int day_exist_count = context.AnalysisOfDay.Where(x => x.job_num == first_analysis_of_day.job_num && x.emp_name == first_analysis_of_day.emp_name && x.date == first_analysis_of_day.date).Count(); if (day_exist_count == 0) { TimeSpan zero = new TimeSpan(0, 0, 0); List <AnalysisOfDay> a = analysis_result.analysis_of_day.Where(x => x.half_late_tm < zero || x.late_tm < zero || x.half_leave_early_tm < zero || x.leave_early_tm < zero).ToList(); context.AnalysisOfDay.AddRange(a); context.AnalysisOfDay.AddRange(analysis_result.analysis_of_day); var day_count = context.SaveChanges(); Console.WriteLine("存储员工每天打卡分析记录:" + day_count + "条"); } else { Console.WriteLine("员工每天打卡记录分析结果中的第一条在数据库中已存在,放弃录入"); } } }