您现在的位置是: 网站首页 >Django >Django轮班排班管理系统 Django
【Schedule轮班排班】06.生成值班数据,获取上次值班人员
admin2018年11月28日 15:05
【Django | Html | JavaScript | Python
】
1959人已围观
Django轮班排班管理系统简介 基于内部业务需求,某些岗位需要进行工作日值班以及周六值班, 如果每次手动去制作Excel排班表,确实比较费时间,就考虑自动化生成的方式去做。 没有什么技术含量,可以了解下循环生成数据方法。我也没找到相关的代码参考,个人写的很烂,仅供参考。 环境要求:Django2.x.x
http://127.0.0.1:8000/duty/generate/duty/
分析:
- 获取选择的日期
- 然后会根据这个日期进行选择提示
- 如果值班表没有历史数据的,则获取值班成员最后一个显示,也就是值班从第一名重新开始
- 如果值班表有数据的,得到上次值班人员名字,和值班成员表进行匹配,知道匹配到在成员表的人(这儿考虑到离职的人)
- 然后指定生成的开始日期和结束日期
- 指定值班类型
- 进入
generate_duty_data
函数生成 - 得到值班的原始顺序,然后根据上次值班的人分析出顺序差值,得到一个新的值班顺序
- 根据这个新的值班顺序,遍历值班表的日期,填充值班人员到值班表中
- 完成
生成值班模板
创建eate-duty.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 %}
生成值班数据视图
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获取上次值班人员
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
from .views import GenerateDutyInfo
urlpatterns = [
path('generate/duty/', permission_required('usercenter.permission_user_manage', raise_exception=True)(GenerateDutyInfo.as_view()), name='create_duty'), # 生成值班日期
]
点击生成,这样选择就从第一名成员开始排序
生成好后再访问 http://127.0.0.1:8000/duty/generate/duty/ 选择30号,下方就显示上次排班的人员信息
核对一下都是正确的
很赞哦! (2)
相关文章
文章交流
- emoji
0人参与,0条评论