Java班组排班,五个班组排班轮询,实现三班倒和做三休二

需求

工作人员分为五个班组:甲、乙、丙、丁、戊,现在需要给这五个班组安排每日值班计划,要求就是需要实现:三班倒、做三休二

其中每日值班分为三个班次:白班、中班、夜班

三班倒的意思就是:某个班组连续三天需要在不同的班次工作。比如甲班,第一天是在白班,那么第二天就是在中班,第三天就是在夜班

做三休二顾名思义就是工作三天,休息两天。比如甲班,第一、二、三天都工作了,那么第四、五天就休息,第六天再开始工作,如此循环

需要实现的效果如下图:

在这里插入图片描述

安排值班计划时,需要先选择从哪一天开始到哪一天结束,比如我选择要安排的值班日期是:2024-05-01 到 2024-05-31,就是一整个月的值班计划。除了选择要安排的日期,也可以选择从哪个班次(白班、中班、夜班三选一)开始排班,比如班次选择的是中班,那就是从2024-05-01的中班开始排班一直轮询到结束时间,那2024-05-01这一天的白班就没有排就是空的

然后不管是从哪个班次开始排班,都是要甲组作为第一个排班的班组。

实现

先设置一个班组列表:

List<String> teamList = Arrays.asList("甲组","乙组","丙组","丁组","戊组"); // 轮班的班组列表

再设置一个班次列表:

//List<String> shiftList = Arrays.asList("白班","中班","夜班"); // 轮班的班次列表
// 因为是做三休二,所以除了白、中、夜班,在班次列表中,我们加上两个休班,这样方便我们进行轮班
List<String> shiftList = Arrays.asList("白班","中班","夜班","休班","休班"); // 轮班的班次列表

根据开始时间、结束时间,获取这个区间的所有日期:

/**
 * 根据开始、结束时间获取之间的所有日期
 */
public static List<String> rangeDay(DateTime start,DateTime end,String format){
    List<String> dates = new LinkedList<>();
    DateTime currentDate = start;
    while (!currentDate.isAfter(end)) {
        dates.add(DateUtil.format(currentDate,format));
        currentDate = currentDate.offset(DateField.DAY_OF_MONTH,1);
    }
    return dates;
}

将排班信息保存到 TeamRotation 实体对象的list中:

@Getter
@Setter
public class TeamRotation {

    /**
     * 排班日期
     */
    private String pbrq;

    /**
     * 白班班组
     */
    private String bbbz;

    /**
     * 中班班组
     */
    private String zbbz;

    /**
     * 夜班班组
     */
    private String ybbz;

    /**
     * 休班班组1
     */
    private String xbbz1;

    /**
     * 休班班组2
     */
    private String xbbz2;

    public TeamRotation() {}

    public TeamRotation(String pbrq) {
        this.pbrq = pbrq;
    }
}

开始排班

下面是实现排班的方法:

/**
 * 轮询班次
 * @param dateList 日期列表
 * @param jzbc 甲组班次(默认从白班开始)
 */
public static List<TeamRotation> pollingShifts(List<String> dateList,String jzbc){
	List<TeamRotation> result = new LinkedList<>(); // 存储最后的结果
	List<String> teamList = Arrays.asList("甲组","乙组","丙组","丁组","戊组"); // 轮班的班组列表
	List<String> shiftList = Arrays.asList("白班","中班","夜班","休班","休班"); // 轮班的班次列表
	int shiftSize = shiftList.size();
	
	int count = 0; // 标记第一天
	boolean flag = false; // 标记从哪个班次开始轮询
	boolean isBye = false; // 标记是否有轮空的班次(没有被安排班组)
	for (String date : dateList) {
		TeamRotation rotation = new TeamRotation(date);
		for (int i = 0; i < shiftSize; i++) {
			if (jzbc.equals(shiftList.get(i))) flag = true;
			// 还没到开始轮询的班次,则跳过,并且标记有轮空的班次
			if (!flag){
				isBye = true;
				continue;
			}
			// 获取当前班次值班的班组(第一天默认是第一个班组)
			String bz = count == 0 ? teamList.get(0) : teamList.get(i);
			switch (i){
				case 0: rotation.setBbbz(bz);break;
				case 1: rotation.setZbbz(bz);break;
				case 2: rotation.setYbbz(bz);break;
				case 3: rotation.setXbbz1(bz);break;
				case 4: rotation.setXbbz2(bz);break;
			}
			if (count == 0) Collections.rotate(teamList, 1); // 将班组列表向右移动1位(只有第一天排班才需要移动)
		}
		if (count == 0){
			if (isBye){
				// 在开始轮询的班次之前有班次没有安排班组(比如开始轮询的班次是“夜班”,那么第一天的白班和中班就没有安排班组)
				// 选择开始安排的班次是白、中、夜三个班次选一,所以夜班、休班、休班是一定有安排到班组的,白、中两个班次就不一定会有班组。
				// 创建一个temp list,它的元素分别是第一天五个班次对应的班组,但因为白、中两个班次不一定会有班组,所以第一、第二个元素先设置成空字符串
				List<String> temp = new LinkedList<>(Arrays.asList("", "", rotation.getYbbz(),rotation.getXbbz1(),rotation.getXbbz2()));
				// 然后在 teamList 中,要找到除夜、休、休这三个班次的班组以外的其它两个班组
				List<String> reduce = teamList.stream().filter(item -> !temp.contains(item)).collect(Collectors.toList());
				// 再将这两个班组设置到temp中第一、第二个位置
				temp.set(0,reduce.get(0));
				temp.set(1,reduce.get(1));
				// 最后再将temp赋值给teamList,这样后续排班时才能实现三班倒和轮休
				teamList = temp;
			}else {
				// 第一天排班时假如是从白班开始,每遍历一个班次,teamList就会移动一次,当遍历完五次时,teamList会重新变成 甲乙丙丁戊 的排序
				// 这个时候我们就需要将 teamList 的顺序变成第一天五个班次对应的班组的顺序,这样后续排班时才能实现三班倒和轮休
				teamList = Arrays.asList(rotation.getBbbz(),rotation.getZbbz(),rotation.getYbbz(),rotation.getXbbz1(),rotation.getXbbz2());
			}
		}
		Collections.rotate(teamList, 1); // 每安排好一天的排班,teamList需要向右移动1位
		result.add(rotation);
		count++;
	}
	return result;
}
public static void main(String[] args) {
    DateTime start = DateUtil.parseDate("2024-05-01");
    DateTime end = DateUtil.parseDate("2024-05-10");
    List<String> dateList = rangeDay(start, end, "yyyy-MM-dd");
    List<TeamRotation> result = pollingShifts(dateList,"白班");
    for (TeamRotation one : result) {
        System.out.println(one.getPbrq() + "\t白班:" + one.getBbbz() + "\t中班:" + one.getZbbz() + "\t夜班:" + one.getYbbz() + "\t休班:" + one.getXbbz1() + "\t休班:" + one.getXbbz2());
    }
}

实现效果

在这里插入图片描述

看这张图很明显就是五天过后,第六天值班的班组和第一天的一样,第七天和第二天的一样,以此类推。就是五天为一个周期,不同周期之间,每天各个班次值班的班组都是一样的。


第二张图就是假设是从中班开始安排,那么第一天的白班就是null,中班才是甲组,然后丙组在休班2,所以第二天的白班是丙组,甲组则安排在夜班,而中班却是乙组。去对照六号、七号这两天的排班,我们不难发现,其实第一天的白班null应该是对应乙组。

在这里插入图片描述


从夜班开始安排也是一样的道理:

在这里插入图片描述

其实不管是从哪个班次开始安排,只要我们确定好第一天的排班班组顺序,那么后续的安排就很好安排了,就是轮着去嘛。然后确定第一天的班组顺序,可以好好去理解、调试下 pollingShifts() 方法里,最下面那个 if (count == 0){} 这个判断里面的代码。

最后

以上就是本篇文章的全部内容了,看完记得点赞~ 也可以关注我~

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

符华-

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值