package com.gkhy.safePlatform.account.utils.schedule; import com.gkhy.safePlatform.account.entity.schedule.*; import com.gkhy.safePlatform.account.enums.CrossSkyEnum; import com.gkhy.safePlatform.account.enums.UnitOfMeaSureEnum; import com.gkhy.safePlatform.account.enums.schedule.GroupStrategyCycleTypeEnum; import com.gkhy.safePlatform.account.enums.schedule.GroupStrategyMemberCycleMethodEnum; import com.gkhy.safePlatform.account.enums.schedule.GroupStrategyStatusTimeTableStatusEnum; import com.gkhy.safePlatform.account.enums.schedule.TimeTypeEnum; import com.gkhy.safePlatform.account.model.bo.ScheduleGroupDayPeriodBO; import com.gkhy.safePlatform.account.model.bo.ScheduleGroupDayPlanBO; import com.gkhy.safePlatform.account.model.bo.ScheduleRuleBO; import com.gkhy.safePlatform.account.model.bo.ScheduleTimeTableBO; import com.gkhy.safePlatform.account.model.constant.ScheduleConstants; import com.gkhy.safePlatform.account.utils.DateUtil; import java.time.DayOfWeek; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.temporal.TemporalAdjusters; import java.util.*; public class GroupStrategyUtil { // 规则的缓存 private ScheduleRuleBO rule; // 首日排班模板 private ScheduleGroupDayPlanBO planTemplate; // 班组 private List groupInfos; // 组策略 private GroupStrategyInfoDO groupStrategy; // 上班时间段 private List workTimePeriods; // 休班规则 private List breakTimeRules; // 开始时间 private LocalDate firstDayOfStrategyType; // 结束时间 private LocalDate lastDayOfStrategyType; // 结果表 private ScheduleTimeTableBO scheduleTimeTable; private Set breakDates; // 倒班 private GroupStrategyMemberCycleMethodEnum method; // 当下时间 private LocalDate currentDate; // 周期 private GroupStrategyCycleTypeEnum cycle; private Map> groupUserPool; public GroupStrategyUtil(GroupStrategyInfoDO groupStrategyInfoDO, LocalDate date, GroupStrategyCycleTypeEnum cycle, List groupInfos, List workTimePeriods, List breakTimeRules, Map> groupUserPool, GroupStrategyMemberCycleMethodEnum method) { this.method = method; this.groupInfos = groupInfos; this.workTimePeriods = workTimePeriods; this.breakTimeRules = breakTimeRules; this.currentDate = date; this.groupUserPool = groupUserPool; this.cycle = cycle; this.groupStrategy = groupStrategyInfoDO; // 1.区分规则 this.distinctRules(); // 2.生成模板 this.initFirstDayWorkSchedule(); // 3.起始日期 this.initPeriod(); } public void run(){ scheduleTimeTable = new ScheduleTimeTableBO(); // 根据 method 来跑班组 switch (method) { case RESERVE: makeTimeInfosByReserve();break; case WEIGHTS:break; } } /** * @Description: 普通倒班 */ private void makeTimeInfosByReserve() { // 规则 reserve 普通倒班 LocalDateTime startDateTime = firstDayOfStrategyType.atStartOfDay(); LocalDateTime lastDayOfStrategyTypeTime = lastDayOfStrategyType.atStartOfDay(); int groupSize = groupInfos.size(); List dayPeriods = planTemplate.getDayPeriods(); int planSize = dayPeriods.size(); // 10.外循环 当日时间的最后一个时间段 // 10.当日的第一个轮班 LocalDateTime shiftDay = startDateTime.plusHours(0).plusMinutes(0); // 11.开始 // 班组排班 List timeTableInfos = new ArrayList<>(); // 班组人员排班 List userTimeTableInfos = new ArrayList<>(); int offset = 0; while (!shiftDay.isAfter(lastDayOfStrategyTypeTime)) { // 11.1 从多个班组中获取时间段个数的班组 GroupStrategyTimeTableInfo groupStrategyTimeTableInfo; // 判断是否是休假 LocalDate specificDay = shiftDay.toLocalDate(); if (matchRules(rule,shiftDay)) { // 休息日 for (int z = 0; z < groupInfos.size(); z++) { groupStrategyTimeTableInfo = new GroupStrategyTimeTableInfo(); groupStrategyTimeTableInfo.setGroupId(groupInfos.get(z).getId()); groupStrategyTimeTableInfo.setGroupStrategyId(groupStrategy.getId()); groupStrategyTimeTableInfo.setSpecificDate(specificDay); groupStrategyTimeTableInfo.setStartTime(specificDay.atTime(0,0,0)); groupStrategyTimeTableInfo.setEndTime(specificDay.atTime(23, 59, 59)); groupStrategyTimeTableInfo.setType(TimeTypeEnum.REST.getCode()); groupStrategyTimeTableInfo.setStatus(GroupStrategyStatusTimeTableStatusEnum.ENABLED.getCode()); timeTableInfos.add(groupStrategyTimeTableInfo); } }else{ // 1.时间组>= 班组大小 if (workTimePeriods.size() >= groupInfos.size()) { // 上班 // todo 暂不考虑 一班一天多个工作段 }else { // 2.班组 > 时间组 int loop = 0; GroupStrategyTimeTableInfo timeTableInfo; List userTimeTableInfo; while (loop < planSize) { for (int i = (offset % groupSize); i < groupSize; i++, loop++) { timeTableInfo = this.workWork(specificDay, shiftDay, groupInfos.get(i), dayPeriods.get(loop)); // 班组 timeTableInfos.add(timeTableInfo); // 班组人员 List users = groupUserPool.get(groupInfos.get(i).getId()); userTimeTableInfo = this.userWorkWork(users, timeTableInfo); userTimeTableInfos.addAll(userTimeTableInfo); } for (int i = 0; i < (offset % groupSize); i++,loop++) { //班组 timeTableInfo = this.workWork(specificDay, shiftDay, groupInfos.get(i), dayPeriods.get(loop)); timeTableInfos.add(timeTableInfo); // 班组人员 List users = groupUserPool.get(groupInfos.get(i).getId()); userTimeTableInfo = this.userWorkWork(users, timeTableInfo); userTimeTableInfos.addAll(userTimeTableInfo); } } } // 班组位移 offset ++; } // 下一天 shiftDay = shiftDay.plusDays(1); } this.scheduleTimeTable.setTimeTableInfo(timeTableInfos); this.scheduleTimeTable.setUserTimeTableInfos(userTimeTableInfos); } private List userWorkWork(List users, GroupStrategyTimeTableInfo timeTableInfo) { List userTimeTableInfos = new ArrayList<>(); if (users != null && users.size() > 0) { GroupStrategyUserTimeTableInfo userTimeTableInfo; for (int j = 0; j < users.size(); j++) { userTimeTableInfo = new GroupStrategyUserTimeTableInfo(); userTimeTableInfo.setUid(users.get(j)); userTimeTableInfo.setGroupId(timeTableInfo.getGroupId()); userTimeTableInfo.setType(timeTableInfo.getType()); userTimeTableInfo.setSpecificDate(timeTableInfo.getSpecificDate()); userTimeTableInfo.setStartTime(timeTableInfo.getStartTime()); userTimeTableInfo.setEndTime(timeTableInfo.getEndTime()); userTimeTableInfo.setGroupStrategyId(groupStrategy.getId()); userTimeTableInfos.add(userTimeTableInfo); } } return userTimeTableInfos; } /** * @Description: specificDate 具体日 shiftDay 0:0:0; */ private GroupStrategyTimeTableInfo workWork(LocalDate specificDate, LocalDateTime shiftDay, GroupInfoDO groupInfoDO, ScheduleGroupDayPeriodBO dayPeriod) { GroupStrategyTimeTableInfo groupStrategyTimeTableInfo = new GroupStrategyTimeTableInfo(); groupStrategyTimeTableInfo.setGroupStrategyId(groupStrategy.getId()); if (dayPeriod.getType() == TimeTypeEnum.WORK) { LocalDateTime startWorkTime = shiftDay .plusHours(dayPeriod.getStartHour()) .plusMinutes(dayPeriod.getStartMin()); LocalDateTime endWorkTime = shiftDay .plusHours(dayPeriod.getEndHour()) .plusMinutes(dayPeriod.getEndMin()); // 工作时间段是否跨天 if (dayPeriod.getEnableAcrossDay() == CrossSkyEnum.ENABLE_CROSS_DAY) { endWorkTime = endWorkTime.plusDays(1); } groupStrategyTimeTableInfo.setGroupId(groupInfoDO.getId()); groupStrategyTimeTableInfo.setStatus(GroupStrategyStatusTimeTableStatusEnum.ENABLED.getCode()); groupStrategyTimeTableInfo.setStartTime(startWorkTime); groupStrategyTimeTableInfo.setEndTime(endWorkTime); groupStrategyTimeTableInfo.setSpecificDate(specificDate); groupStrategyTimeTableInfo.setType(TimeTypeEnum.WORK.getCode()); } if (dayPeriod.getType() == TimeTypeEnum.REST) { groupStrategyTimeTableInfo = new GroupStrategyTimeTableInfo(); groupStrategyTimeTableInfo.setGroupId(groupInfoDO.getId()); groupStrategyTimeTableInfo.setSpecificDate(specificDate); groupStrategyTimeTableInfo.setStartTime(specificDate.atTime(0,0,0)); groupStrategyTimeTableInfo.setEndTime(specificDate.atTime(23, 59, 59)); groupStrategyTimeTableInfo.setType(TimeTypeEnum.REST.getCode()); groupStrategyTimeTableInfo.setStatus(GroupStrategyStatusTimeTableStatusEnum.ENABLED.getCode()); } return groupStrategyTimeTableInfo; } private void initFirstDayWorkSchedule() { ScheduleGroupDayPlanBO scheduleGroupDayPlan = new ScheduleGroupDayPlanBO(); List dayPeriods = new ArrayList<>(); // 上班组 WorkTimePeriodInfoDO workTimePeriodInfoDO; ScheduleGroupDayPeriodBO dayPeriod; if (workTimePeriods.size() <= groupInfos.size()) { for (int i = 0; i < workTimePeriods.size(); i++) { workTimePeriodInfoDO = workTimePeriods.get(i); dayPeriod = new ScheduleGroupDayPeriodBO(); CrossSkyEnum enableAcrossDay = CrossSkyEnum.parse(workTimePeriodInfoDO.getEnableAcrossDay()); dayPeriod.setEnableAcrossDay(enableAcrossDay); dayPeriod.setStartHour(workTimePeriodInfoDO.getStartHour()); dayPeriod.setStartMin(workTimePeriodInfoDO.getStartMin()); dayPeriod.setEndHour(workTimePeriodInfoDO.getEndHour()); dayPeriod.setEndMin(workTimePeriodInfoDO.getEndMin()); dayPeriod.setType(TimeTypeEnum.WORK); dayPeriods.add(dayPeriod); } for (int i = 0; i < groupInfos.size() - workTimePeriods.size(); i++) { dayPeriod = new ScheduleGroupDayPeriodBO(); dayPeriod.setEnableAcrossDay(CrossSkyEnum.UNENABLE_CROSS_DAY); dayPeriod.setStartHour(0); dayPeriod.setStartMin(0); dayPeriod.setEndHour(23); dayPeriod.setEndMin(59); dayPeriod.setType(TimeTypeEnum.REST); dayPeriods.add(dayPeriod); } } scheduleGroupDayPlan.setDayPeriods(dayPeriods); // 休息组 this.planTemplate = scheduleGroupDayPlan; } private void distinctRules() { ScheduleRuleBO rule = new ScheduleRuleBO(); Set day = new HashSet<>(); Set week = new HashSet<>(); Set month = new HashSet<>(); if (breakTimeRules != null && breakTimeRules.size() > 0) { for (int i = 0; i < breakTimeRules.size(); i++) { BreakTimeRuleInfoDO breakTimeRuleInfoDO = breakTimeRules.get(i); String[] split = breakTimeRuleInfoDO.getRuleNumber().split(","); if (breakTimeRuleInfoDO.getRule().equals(UnitOfMeaSureEnum.DAY.getCode())) { for (int j = 0; j < split.length; j++) { day.add(Integer.parseInt(split[j])); } } if (breakTimeRuleInfoDO.getRule().equals(UnitOfMeaSureEnum.WEEK.getCode())) { for (int j = 0; j < split.length; j++) { week.add(Integer.parseInt(split[j])); } } if (breakTimeRuleInfoDO.getRule().equals(UnitOfMeaSureEnum.MONTH.getCode())) { for (int j = 0; j < split.length; j++) { month.add(Integer.parseInt(split[j])); } } } } rule.setDayRule(day); rule.setWeekRule(week); rule.setMonthRule(month); this.rule = rule; } /** * @Description: 根据 breakTimeRules 和 typeDeadline 截止日期 生成 */ public static boolean matchRules(ScheduleRuleBO rule, LocalDateTime judgeDate) { int dayOfWeek = judgeDate.getDayOfWeek().getValue(); int dayOfMonth = judgeDate.getDayOfMonth(); int dayOfYear = judgeDate.getDayOfYear(); return rule.getDayRule().contains(dayOfYear) || rule.getWeekRule().contains(dayOfWeek) || rule.getMonthRule().contains(dayOfMonth); } private void initPeriod(){ firstDayOfStrategyType = groupStrategy.getCycleStartTime(); switch (cycle) { case WEEK: lastDayOfStrategyType = firstDayOfStrategyType.with(DayOfWeek.SATURDAY); break; case MONTH: lastDayOfStrategyType = firstDayOfStrategyType.with(TemporalAdjusters.lastDayOfMonth()); break; case YEAR: lastDayOfStrategyType = firstDayOfStrategyType.with(TemporalAdjusters.lastDayOfYear()); break; } } public static Set makeBreakDatesCacheByRules(List breakTimeRules,LocalDate startDate, LocalDate lastDayOfStrategyType) { // 0.按照现在规则 需要把 day 和 (week、month区分开) Set result = new HashSet<>(); LocalDate stepDate = startDate.plusDays(0); int year = startDate.getYear(); Set weekRule = new HashSet<>(); Set monthRule = new HashSet<>(); if (breakTimeRules != null && breakTimeRules.size() > 0) { for (int i = 0; i < breakTimeRules.size(); i++) { BreakTimeRuleInfoDO breakTimeRuleInfoDO = breakTimeRules.get(i); String[] split = breakTimeRuleInfoDO.getRuleNumber().split(","); if (breakTimeRuleInfoDO.getRule().equals(UnitOfMeaSureEnum.DAY.getCode())) { for (int j = 0; j < split.length; j++) { int index = Integer.parseInt(split[j]); String format = LocalDate.ofYearDay(year, index).format(ScheduleConstants.BREAK_POINT_FMT); result.add(format); } } else if (breakTimeRuleInfoDO.getRule().equals(UnitOfMeaSureEnum.WEEK.getCode())){ for (int j = 0; j < split.length; j++) { weekRule.add(Integer.parseInt(split[j])); } } else if (breakTimeRuleInfoDO.getRule().equals(UnitOfMeaSureEnum.MONTH.getCode())) { for (int j = 0; j < split.length; j++) { monthRule.add(Integer.parseInt(split[j])); } } } while (!stepDate.isAfter(lastDayOfStrategyType)) { int dayOfWeek = stepDate.getDayOfWeek().getValue(); int dayOfMonth = stepDate.getDayOfMonth(); if (weekRule.contains(dayOfWeek) || monthRule.contains(dayOfMonth)) { result.add(stepDate.format(ScheduleConstants.BREAK_POINT_FMT)); } stepDate = stepDate.plusDays(1); } } return result; } public ScheduleRuleBO getRule() { return rule; } public void setRule(ScheduleRuleBO rule) { this.rule = rule; } public ScheduleGroupDayPlanBO getPlanTemplate() { return planTemplate; } public void setPlanTemplate(ScheduleGroupDayPlanBO planTemplate) { this.planTemplate = planTemplate; } public ScheduleTimeTableBO getScheduleTimeTable() { return scheduleTimeTable; } public void setScheduleTimeTable(ScheduleTimeTableBO scheduleTimeTable) { this.scheduleTimeTable = scheduleTimeTable; } public LocalDate getCurrentDate() { return currentDate; } public void setCurrentDate(LocalDate currentDate) { this.currentDate = currentDate; } public LocalDate getFirstDayOfStrategyType() { return firstDayOfStrategyType; } public void setFirstDayOfStrategyType(LocalDate firstDayOfStrategyType) { this.firstDayOfStrategyType = firstDayOfStrategyType; } public LocalDate getLastDayOfStrategyType() { return lastDayOfStrategyType; } public void setLastDayOfStrategyType(LocalDate lastDayOfStrategyType) { this.lastDayOfStrategyType = lastDayOfStrategyType; } }