简单的排班系统

Posted cetclyb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单的排班系统相关的知识,希望对你有一定的参考价值。

最近项目中有需要实现排班功能,就是有3个班组,实现三班倒的排班功能,目的在于后续统计每个班次生产量。
1:功能设计
结合实际情况,这样设计系统:首先设计一张班组表,用于班组的增删改查。班组成员的信息在这个张表中不做体现。
再设计一张上班时段管理表,用于配置上班时段。
再设计一种排班表,用于配置那个班在那天上那个时段。
再设计一种班时表,班时表真实的记录各个班车上班详情。班时表每月可以生动或者自动生成下月的。
2:设计实现
2.1:班组表

班组表主要时班组名称和生效状态,再后生成班时表时,值选择生效的班组。
2.2:上班时段表

记录时段上班时段。
例如三班倒的班时,A、B、C,他们分别都上8个小时的时长,但各自的开始和结束时间不一样;
再如两班倒的A12、B12,他们分别上12个小时的时长,也是开始的结束时间不一样。
具体怎么定义,可以根据车间实际的工作时段自行定义,只要确保班时名称和班时编号不重叠就可以了。
2.3:排班表

这个就是根据各个班组和班组对应上班时段和上班日期确定对应的记录。
例如:班组2-1,上两班倒,上2休1,白班一天、夜班一天。
配置方法如下:

首先新增一条记录:选择班组2-1,上班序号设置1,这个标识第一天,上班时段选择A12,即白班从8:00倒20:00。
再新增一条记录:选择班组2-1,上班序号设置2,这个标识第二天,上班时段选择B12,即晚班班从20:00倒8:00。
再新增一条记录:选择班组2-1,上班序号设置3,这个标识第三天,上班时段不选择,即标识无上班时段,即休息。
设置完毕后,排班记录如下:

2.4:班时表
当基础数据设置完毕后,就可以生成班时表。班时表可以手动生成也可以自动生成,每次生成从当前时间开始未生成的时间启倒下月结束时间段的数据。如果下月数据已经生成,就不再生成。
生成逻辑时:首先查找所有生效的班组,然后查找所有生效的排班记录,然后查找各个班组最晚一条班时记录。然后根据各个班组最晚一条排班记录中的上班序号,再生效的排班记录中匹配的对应的记录,软后开始以排班记录中该班组的最大上班序列未周期,以最晚排班记录中的上班序列再加1作为启动点,以下月月末未结束时间,开始循环生成本班组的班时表。

还是以班组2-1为例,灰色底色的是标识该班时已经过了当前时间,该班时不要修改,只能查看。绿色底色标识,该天为休息时间。
如果仔细看,会发现再12月31日和1月1日交接时间点上,该班的排班不连续,正常如果31号为白班,那么1号应该为夜班。但班时表上却为休息,并且后续排班都按这个时间点开始重新轮回。这是什么原因?其实再1月1日的排班是手动修改的。过程是这样,在生成1月份的班时前,先手动增加料一条1月1号的记录,这条记录,没有和12月31日的记录接续,直接重新排序了一条,后续在生成班时时,就从最晚的记录开始接续执行。这样,1月份的班时就按1月1日的开始接续了。
如果没有手动修改,那就会按12月31日的开始接续。例如我们看看班组2-2:

3:程序实现
本系统是基于net6实现的,各个页面模型相对比较加单,技术核心其实在班时的生成。
生成时,首先查询有效班组
其中查询最晚班时
在查询排班记录
让后根据班组、排班记录和最晚班时生成新的班时。
写的过程中发现一个排班bug,大家可以看看问题再哪。


            //查找班组
            var queryCT = DC.Set<Classteam>()
                .Where(x => x.status == PolicyStatus.canuse)
                .Select(x => new Classteam_View
                
                    ID = x.ID,
                    Name = x.Name,
                    Code = x.Code,
                    status = x.status,
                    B_datetime = x.B_datetime,
                    E_datetime = x.E_datetime,
                )
                .OrderBy(x => x.Name)
                .ToList();
            //查找最晚班时
            var queryCW = DC.Set<Classwork>()
                .Select(x => new Classwork_View
                
                    ID = x.ID,
                    Name_view = x.classteam.Name,
                    seq = x.seq,
                    Name_view2 = x.workpolicy.Name,
                    Last_datetime = x.Last_datetime,
                )
                .OrderBy(x => x.ID)
                .GroupBy(x => new  x.Name_view , x => x.Last_datetime)
                .Select(x => new 
                    Name_view = x.Key.Name_view,
                    Last_datetime =x.Max()
                )
                .ToList();
            var queryCWLast = new List<Classwork_View>();
            for(int i = 0; i < queryCW.Count; i ++)
                var queryCWtmp = DC.Set<Classwork>()
                                .CheckContain(queryCW[i].Name_view, x => x.classteam.Name)
                                .CheckEqual(queryCW[i].Last_datetime, x => x.Last_datetime)
                                .Select(x => new Classwork_View
                                
                                    ID = x.ID,
                                    classteamId = x.classteamId,
                                    Name_view = x.classteam.Name,
                                    seq = x.seq,
                                    workpolicyId = x.workpolicyId,
                                    Name_view2 = x.workpolicy.Name,
                                    Last_datetime = x.Last_datetime,
                                )
                                .ToList();
                //queryCWLast.Concat(queryCWtmp);
                queryCWLast.AddRange(queryCWtmp);
            
            
            //查找排班
            var queryCP = DC.Set<ClassPolicy>()
               .Where(x => x.status == PolicyStatus.canuse)
               .Select(x => new ClassPolicy_View
               
                   ID = x.ID,
                   classteamId = x.classteam.ID,
                   Name_view = x.classteam.Name,
                   seq = x.seq,
                   workpolicyId = x.workpolicy.ID,
                   Name_view2 = x.workpolicy.Name,
                   status = x.status,
                   B_datetime = x.B_datetime,
                   E_datetime = x.E_datetime,
               )
               .OrderBy(x => x.Name_view)
               .ToList();

            DateTime begindatetime = DateTime.Now.AddDays(1 - DateTime.Now.Day);
            DateTime lastday = begindatetime.AddMonths(1).AddDays(-1).Date;
            DateTime nextlastday = begindatetime.AddMonths(2).AddDays(-1).Date;
            string strlastday = lastday.ToString("yyyyMMdd");
            string strnextlastday = nextlastday.ToString("yyyyMMdd");

            //
            DateTime startdatetime = DateTime.Now.Date;

            int maxCP = 0;
            int startCP = 1;

            int classworknoinfoflag = 1;
            int classworkcreateflag = 0;

            for (int i = 0; i < queryCT.Count; i++)//班组
            
                startdatetime = DateTime.Now.Date;

                maxCP = 0;
                startCP = 1;
                classworknoinfoflag = 1;
                classworkcreateflag = 0;

                Dictionary<int, ClassPolicy_View> dictCP = new Dictionary<int, ClassPolicy_View>();
                for(int j = 0; j <queryCP.Count; j++)//排班计划
                
                    if (queryCP[j].Name_view == queryCT[i].Name)
                    
                        dictCP.Add(queryCP[j].seq, queryCP[j]);
                        if (maxCP < queryCP[j].seq)
                            maxCP = queryCP[j].seq;
                    
                
                if (dictCP.Count == 0)//无排班计划
                    continue;
                Dictionary<int, ClassPolicy_View> dictCPsort = dictCP.OrderBy(p => p.Key).ToDictionary(p => p.Key, o => o.Value);


                for (int k = 0; k < queryCWLast.Count; k++)//班组工作
                                    
                    if (queryCWLast[k].Name_view == queryCT[i].Name)
                    
                        classworknoinfoflag = 0;
                        if ((queryCWLast[k].Last_datetime?.ToString("yyyyMMDD").CompareTo(strnextlastday)) != 0)
                        
                            startdatetime = (DateTime)queryCWLast[k].Last_datetime;
                            startCP = queryCWLast[k].seq;
                        
                        else
                        
                            如果下一月班组工作已经有了,就不要在生成了
                            classworkcreateflag = 1;
                        
                    
                

                if (classworkcreateflag == 1)
                    continue;
                if(classworknoinfoflag == 1)
                
                    //之前无班时
                    Console.WriteLine("no info");
                

                TimeSpan midTime = nextlastday - startdatetime;
                for (int x = 0; x < midTime.Days; x ++)
                
                    startdatetime = startdatetime.AddDays(1);
                    startCP++;
                    if (startCP > maxCP)
                        startCP = 1;
                    ClassPolicy_View CP_view;
                    bool result = dictCPsort.TryGetValue(startCP, out CP_view);
                    if (!result)
                        continue;

                    Classwork classwk = new Classwork
                    
                        classteamId = CP_view.classteamId,
                        classteam = CP_view.classteam,
                        seq = startCP,
                        workpolicyId = (CP_view.workpolicyId == null)?null: CP_view.workpolicyId,
                        workpolicy = CP_view.workpolicy,
                        Last_datetime = startdatetime
                    ;
                    DC.AddEntity(classwk);
                
                DC.SaveChanges();
            
        

excel排班表模板

六人,一人中班,其余为早晚班,周六周日不休,周一到周五每人休一天,晚班必须三人

    先依照下图,填上每月的一号和星期一,部门员工名字

    填充日期(1-31号)

    选中日期1,可以看到单元格右下角有个实心小点。鼠标放在这个小点上,指针会变成实心加号的形状。

    然后拖住鼠标左键往右侧拖拉,点击下拉菜单,选【填充序列】,效果如图

    填充星期

    填充方式和填充日期的一致,下拉菜单中【填充序列】和【以天数填充】效果一样,就是1234567,如选择【以工作日填充】,效果就是周一到周五循环。

    调整excel表格的宽度

    可以复制或在依照上面的方法,为员工批量添加白班和休息日期。

    这时候表格样式看着不顺眼,每个单元格太宽,要批量调整的话,全选需要调整的列,然后鼠标放在任意两列中间,指针会变成双箭头的样式(我截不了图,手工画一个意思一下)。然后双击,就可以把这些列的宽度调整成一样了。

    修正表头为居中对齐

    选中表头“排班表”所在行,点击【合并后居中】即可。

    调整表格高度

    参照“调整excel表格的宽度”的方法调整宽度,最终得出排班表。

参考技术A 在A1输第一天的日期
A2=INT(ROW(A1)/COUNTA($G$1:$G$10))+$A$1
往下拉.

B1=INDEX($G$1:$G$10,MOD(ROW()-1,COUNTA($G$1:$G$10))+1)
往下拉.

C1=CHOOSE(MOD(INT((ROW()-1)/COUNTA($G$1:$G$10))+INDEX($H$1:$H$10,MOD(ROW()-1,COUNTA($G$1:$G$10))+1)-1,5)+1,"A","B","C","D","E")
往下拉.

班次要改的话,直接在G到H列改就可以了,只要班次不超过10班公式都应该不会有问题.
参考技术B 先做一个班次表,如在G1到H4:

早上8点到12点;下午2点到5点 1
中午12点到2点;下午5点到晚上9点 2
中午12点到2点 3
9点到第二天早上8点 4

在A1输第一天的日期
A2=INT(ROW(A1)/COUNTA($G$1:$G$10))+$A$1
往下拉.

B1=INDEX($G$1:$G$10,MOD(ROW()-1,COUNTA($G$1:$G$10))+1)
往下拉.

C1=CHOOSE(MOD(INT((ROW()-1)/COUNTA($G$1:$G$10))+INDEX($H$1:$H$10,MOD(ROW()-1,COUNTA($G$1:$G$10))+1)-1,5)+1,"A","B","C","D","E")
往下拉.

班次要改的话,直接在G到H列改就可以了,只要班次不超过10班公式都应该不会有问题.

比如说,如果你想把不同时间单列的话,在G1:H6直接输:
早上8点到12点 1
中午12点到2点 2
中午12点到2点 3
下午2点到5点 1
下午5点到晚上9点 2
9点到第二天早上8点 4

要改倒班人数的话,就要改C1的公式:
C1=CHOOSE(MOD(INT((ROW()-1)/COUNTA($G$1:$G$10))+INDEX($H$1:$H$10,MOD(ROW()-1,COUNTA($G$1:$G$10))+1)-1,倒班人数)+1,倒班人名顺序清单)

比如说是6个人倒班:
C1=CHOOSE(MOD(INT((ROW()-1)/COUNTA($G$1:$G$10))+INDEX($H$1:$H$10,MOD(ROW()-1,COUNTA($G$1:$G$10))+1)-1,6)+1,"A","B","C","D","E","F")
参考技术C 人太少,而且3个必须晚班,周末必须全在,有点费时。我做个了排班表,给你参考下,地址在百度云http://yun.baidu.com/share/link?shareid=2649293021&uk=2770994055&third=0,你看是差不多 参考技术D 这个很难吗?

以上是关于简单的排班系统的主要内容,如果未能解决你的问题,请参考以下文章

基于java+ssm医院门诊预约挂号排班系统-计算机毕业设计

布局优化基于遗传算法求解公交排班问题matlab源码

布局优化基于遗传算法求解公交排班问题matlab源码

布局优化基于遗传算法求解公交排班问题matlab源码

matlab基于遗传算法的公交排班系统分析matlab优化算法五

简单的排班系统