您现在的位置是: 网站首页 >Django >Django轮班排班管理系统 Django
【Schedule轮班排班】06.生成值班数据,获取上次值班人员
admin2018年11月28日 15:05 【Django | Html | JavaScript | Python 】 1826人已围观
Django轮班排班管理系统简介 基于内部业务需求,某些岗位需要进行工作日值班以及周六值班, 如果每次手动去制作Excel排班表,确实比较费时间,就考虑自动化生成的方式去做。 没有什么技术含量,可以了解下循环生成数据方法。我也没找到相关的代码参考,个人写的很烂,仅供参考。 环境要求:Django2.x.x
http://127.0.0.1:8000/duty/generate/duty/ ![BLOG_20181128_150628_11](/media/blog/images/2018/11/BLOG_20181128_150628_11.png "博客图集BLOG_20181128_150628_11.png") 分析: - 获取选择的日期 - 然后会根据这个日期进行选择提示 - 如果值班表没有历史数据的,则获取值班成员最后一个显示,也就是值班从第一名重新开始 - 如果值班表有数据的,得到上次值班人员名字,和值班成员表进行匹配,知道匹配到在成员表的人(这儿考虑到离职的人) - 然后指定生成的开始日期和结束日期 - 指定值班类型 - 进入`generate_duty_data`函数生成 - **得到值班的原始顺序,然后根据上次值班的人分析出顺序差值,得到一个新的值班顺序** - 根据这个新的值班顺序,遍历值班表的日期,填充值班人员到值班表中 - 完成 ## 生成值班模板 创建eate-duty.html模板 ```html {% extends 'base-duty.html' %} {% load static %} {% load duty_template_tags %} {% block css %} <link href="{% static 'hAdmin/css/plugins/datapicker/datepicker3.css' %}" rel="stylesheet"> {% endblock %} {% block title %}{{ block.super }} - 生成值班{% endblock %} {% block breadcrumb %} <li> <a href="/">主页</a> </li> <li> <strong>生成值班</strong> </li> {% endblock %} {% block content %} <div class="ibox float-e-margins"> <div class="ibox-title"> <h5>根据已存在的日期数据,生成值班表</h5> </div> <div class="ibox-content"> <p>若修改日期数据,需要重新生成值班表;从选择日期往后生成,下方显示的值班人员参考为该日期之前的值班人员</p> <p> 上次值班已生成到:{% if last_schedule %}{{ last_schedule.last.date }}{% else %}未生成数据{% endif %} ,日期选择不得超过已生成的日期:{{ end_date }} </p> <form method="post" autocomplete="off"> <div class="row"> <div class="col-sm-12"> <form role="form"> <div class="form-group" id="choose_date"> <label>可选日期</label> <div class="input-group date"> <input type="text" class="form-control" name="choose_date" value="{{ today|date:"Y-m-d" }}" id="id_choose_date"> <span class="input-group-addon"><i class="fa fa-calendar"></i></span> </div> </div> <div class="form-group"> <label>上次晚班</label> <select class="form-control m-b" name="last_night_duty"> <option value="">------</option> {% for employee in all_employee %} <option value="{{ employee.id }}">{{ employee.name }}</option> {% endfor %} </select> <div style="color:#ADADAD" title="所选日期上一个值班人员">以上参考选择:<span id="id_last_night_duty">{{ last_night_duty.staff }}</span></div> </div> <div class="form-group"> <label>上次周末</label> <select class="form-control m-b" name="last_weekend_duty"> <option value="">------</option> {% for employee in all_employee %} <option value="{{ employee.id }}">{{ employee.name }}</option> {% endfor %} </select> <div style="color:#ADADAD" title="所选日期上一个值班人员">以上参考选择:<span id="id_last_weekend_duty">{{ last_weekend_duty.staff }}</span></div> </div> {% csrf_token %} <div> <button class="btn btn-primary" type="submit">开始生成</button> </div> </form> </div> </div> </form> </div> </div> {% endblock %} {% block js %} <script src="{% static 'hAdmin/js/plugins/datapicker/bootstrap-datepicker.js' %}"></script> <script> $('#choose_date .input-group.date').datepicker({ language: "zh-CN", todayBtn: "linked", keyboardNavigation: false, forceParse: false, calendarWeeks: true, autoclose: true, todayHighlight: true, endDate: "{{ end_date }}", format: "yyyy-mm-dd", }); $('#id_choose_date').change(function () { let choose_date = $('#id_choose_date').val(); $.ajax({ url: '{% url "duty:get_last_duty" %}?this_date=' + choose_date, type: 'GET', dataType: 'json', timeout: 3000, cache: false, success: succFunction, //成功执行方法 }); function succFunction(last_duty) { let json2cval = eval(last_duty); $('#id_last_night_duty').html(json2cval.last_night_duty_name); $('#id_last_weekend_duty').html(json2cval.last_weekend_duty_name); } }); </script> {% endblock %} ``` ## 生成值班数据视图 ```python def generate_duty_data(last_duty_name, duty_type, start_date, end_date): print('正在生成类型为{}值班信息'.format(duty_type)) all_employee = Employee.objects.filter(available=True) # 生成默认的顺序{name:{'default_order': num}, ...} employee_order = dict() for employee in all_employee: employee_order[employee.name] = {} employee_order[employee.name]['default_order'] = employee.num # print(employee_order) # 将选择的last_duty_name的新顺序变为值班成员的数量,也就是排班排到最后一位,得到新顺序和默认顺序的差值 employee_order[last_duty_name]['new_order'] = all_employee.count() diff_num = all_employee.count() - employee_order[last_duty_name]['default_order'] print('顺序差值:', diff_num) # 在默认的顺序字典中增加新的顺序 new_employee_order = {} for name, item in employee_order.items(): employee_order[name]['new_order'] = employee_order[name]['default_order'] + diff_num if employee_order[name]['new_order'] > all_employee.count(): employee_order[name]['new_order'] -= all_employee.count() # 根据这个新字典顺便生成新顺序:名字的对应关系 new_employee_order[employee_order[name]['new_order']] = name print(employee_order) print(new_employee_order) # {new_order: name, ...} # 待排序的值班进行排序 next_duty = Schedule.objects.filter(duty_type=duty_type, date__gte=start_date, date__lte=end_date).order_by('date') # 更新从选定日期到生成的最后日期的值班表 i = 0 for duty in next_duty: # print(duty, i % all_employee.count() + 1) duty.staff = new_employee_order[i % all_employee.count() + 1] duty.real_staff = '' duty.save() i += 1 class GenerateDutyInfo(View): """ 生成值班表,填充值班人员 """ def get(self, request): # 获取上次值班安排到的日期,也就是安排了值班人员的最后一个日期 last_schedule = Schedule.objects.exclude(Q(staff__isnull=True) | Q(staff='')).order_by('date') all_employee = Employee.objects.filter(available=True) today = datetime.date.today() # 可选日期开始 if Schedule.objects.all(): # 如果存在值班表 end_date = Schedule.objects.order_by('-date').first().date # 可选日期结束 else: end_date = today last_night_duty = last_schedule.filter(duty_type=1).last() # 获取上次晚班的数据 last_weekend_duty = last_schedule.filter(duty_type=2).last() # 获取上次周末值班数据 return render(request, 'create-duty.html', locals()) def post(self, request): choose_date = request.POST.get('choose_date') end_date = Schedule.objects.order_by('-date').first().date # 排班结束日期 this_date = datetime.date.today() # 默认为今天的日期 if choose_date: yy, mm, dd = choose_date.split('-') this_date = datetime.date(int(yy), int(mm), int(dd)) # 获取选择的日期 # 获取选择的上次值班人员id last_night_duty_id = request.POST.get('last_night_duty') last_weekend_duty_id = request.POST.get('last_weekend_duty') # 获取值班表中该日期数据信息,以日期从小到大排序 previous_night_duty = Schedule.objects.filter(duty_type=1, date__lt=this_date).order_by('date') previous_weekend_duty = Schedule.objects.filter(duty_type=2, date__lt=this_date).order_by('date') # 值班成员中的第一个 all_employee = Employee.objects.filter(available=True) # 如果选择了上次晚班值班人员 if last_night_duty_id: last_night_duty_name, last_night_duty_num = Employee.objects.filter(id=last_night_duty_id).values_list('name', 'num').first() else: # 默认情况下为值班成员第一个 last_night_duty_name = all_employee.first().name # 如果值班表中已安排过晚班,从中获取上次值班人员,exclude表示得到staff中有值得数据 all_previous_night_duty = previous_night_duty.exclude(Q(staff__isnull=True) & Q(staff='')) if all_previous_night_duty: # 得到上次值班人员,要考虑到值班成员列表中消失的名字 for previous_night_duty in all_previous_night_duty.reverse(): # 倒序,日期最新的在前 # print(previous_night_duty) if all_employee.filter(name=previous_night_duty.staff): last_night_duty_name = previous_night_duty.staff # 获取值班表名字在成员中的一个,获取到后停止 break print('上次晚上值班人员:', last_night_duty_name) generate_duty_data(last_duty_name=last_night_duty_name, duty_type=1, start_date=this_date, end_date=end_date) # --------------------------------------------------------- # 如果选择了上次周末值班人员 if last_weekend_duty_id: last_weekend_duty_name, last_weekend_duty_num = Employee.objects.filter(id=last_weekend_duty_id).values_list('name', 'num').first() else: # 默认情况下为值班成员第一个 last_weekend_duty_name = all_employee.first().name # 如果值班表中已安排过周末值班,从中获取上次值班人员,exclude表示得到staff中有值得数据 all_previous_weekend_duty = previous_weekend_duty.exclude(Q(staff__isnull=True) & Q(staff='')) if all_previous_weekend_duty: # 得到上次值班人员,要考虑到值班成员列表中消失的名字 for previous_weekend_duty in all_previous_weekend_duty.reverse(): # 倒序,日期最新的在前 # print(previous_weekend_duty) if all_employee.filter(name=previous_weekend_duty.staff): last_weekend_duty_name = previous_weekend_duty.staff # 获取值班表名字在成员中的一个,获取到后停止 break print('上次周末值班人员:', last_weekend_duty_name) generate_duty_data(last_duty_name=last_weekend_duty_name, duty_type=2, start_date=this_date, end_date=end_date) return redirect(reverse('duty:create_duty')) ``` ## 模板中js获取上次值班人员 ```python def get_last_duty(request): """ 根据给定的一个日期,从值班表中得到这个日期之前的值班人员信息 :param reqeust: :return: """ yy, mm, dd = request.GET.get('this_date').split('-') this_date = datetime.date(int(yy), int(mm), int(dd)) # 获取值班表中日期数据信息,以日期从大到小排序 previous_night_duty = Schedule.objects.filter(duty_type=1, date__lt=this_date).order_by('-date') previous_weekend_duty = Schedule.objects.filter(duty_type=2, date__lt=this_date).order_by('-date') all_employee = Employee.objects.filter(available=True) last_night_duty_name = last_weekend_duty_name = all_employee.last().name # 未安排过值班的,默认显示值班成员最后一个,然后从第一人开始排 for night_duty in previous_night_duty: if all_employee.filter(name=night_duty.staff): last_night_duty_name = night_duty.staff # 获取值班表名字在成员中的一个,获取到后停止 break for weekend_duty in previous_weekend_duty: if all_employee.filter(name=weekend_duty.staff): last_weekend_duty_name = weekend_duty.staff # 获取值班表名字在成员中的一个,获取到后停止 break last_duty = dict() last_duty['last_night_duty_name'] = last_night_duty_name last_duty['last_weekend_duty_name'] = last_weekend_duty_name return HttpResponse(json.dumps(last_duty)) ``` ## 生成值班url ```python from .views import GenerateDutyInfo urlpatterns = [ path('generate/duty/', permission_required('usercenter.permission_user_manage', raise_exception=True)(GenerateDutyInfo.as_view()), name='create_duty'), # 生成值班日期 ] ``` ![BLOG_20181128_151955_12](/media/blog/images/2018/11/BLOG_20181128_151955_12.png "博客图集BLOG_20181128_151955_12.png") 点击生成,这样选择就从第一名成员开始排序 ![BLOG_20181128_152027_16](/media/blog/images/2018/11/BLOG_20181128_152027_16.png "博客图集BLOG_20181128_152027_16.png") 生成好后再访问 http://127.0.0.1:8000/duty/generate/duty/ 选择30号,下方就显示上次排班的人员信息 ![BLOG_20181128_152152_21](/media/blog/images/2018/11/BLOG_20181128_152152_21.png "博客图集BLOG_20181128_152152_21.png") 核对一下都是正确的
很赞哦! (2)
相关文章
文章交流
- emoji