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<GroupInfoDO> groupInfos;
|
// 组策略
|
private GroupStrategyInfoDO groupStrategy;
|
// 上班时间段
|
private List<WorkTimePeriodInfoDO> workTimePeriods;
|
// 休班规则
|
private List<BreakTimeRuleInfoDO> breakTimeRules;
|
// 开始时间
|
private LocalDate firstDayOfStrategyType;
|
// 结束时间
|
private LocalDate lastDayOfStrategyType;
|
// 结果表
|
private ScheduleTimeTableBO scheduleTimeTable;
|
|
private Set<String> breakDates;
|
// 倒班
|
private GroupStrategyMemberCycleMethodEnum method;
|
// 当下时间
|
private LocalDate currentDate;
|
// 周期
|
private GroupStrategyCycleTypeEnum cycle;
|
|
private Map<Long, List<Long>> groupUserPool;
|
|
|
|
public GroupStrategyUtil(GroupStrategyInfoDO groupStrategyInfoDO,
|
LocalDate date,
|
GroupStrategyCycleTypeEnum cycle,
|
List<GroupInfoDO> groupInfos,
|
List<WorkTimePeriodInfoDO> workTimePeriods,
|
List<BreakTimeRuleInfoDO> breakTimeRules,
|
Map<Long,List<Long>> 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<ScheduleGroupDayPeriodBO> dayPeriods = planTemplate.getDayPeriods();
|
int planSize = dayPeriods.size();
|
// 10.外循环 当日时间的最后一个时间段
|
// 10.当日的第一个轮班
|
LocalDateTime shiftDay = startDateTime.plusHours(0).plusMinutes(0);
|
// 11.开始
|
// 班组排班
|
List<GroupStrategyTimeTableInfo> timeTableInfos = new ArrayList<>();
|
// 班组人员排班
|
List<GroupStrategyUserTimeTableInfo> 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<GroupStrategyUserTimeTableInfo> 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<Long> 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<Long> 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<GroupStrategyUserTimeTableInfo> userWorkWork(List<Long> users, GroupStrategyTimeTableInfo timeTableInfo) {
|
List<GroupStrategyUserTimeTableInfo> 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<ScheduleGroupDayPeriodBO> 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<Integer> day = new HashSet<>();
|
Set<Integer> week = new HashSet<>();
|
Set<Integer> 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<String> makeBreakDatesCacheByRules(List<BreakTimeRuleInfoDO> breakTimeRules,LocalDate startDate, LocalDate lastDayOfStrategyType) {
|
|
// 0.按照现在规则 需要把 day 和 (week、month区分开)
|
|
Set<String> result = new HashSet<>();
|
LocalDate stepDate = startDate.plusDays(0);
|
int year = startDate.getYear();
|
Set<Integer> weekRule = new HashSet<>();
|
Set<Integer> 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;
|
}
|
}
|