最近一直在写CMDB相关的项目,但是涉及到了人员值班的问题, 因为之前没接触到,导致自身的效率很低, 一度感觉跌入低谷,下面给大家说一下思路以及demo演示
1. 以django框架为例
2. 涉及三个表
3. 人员值班之间互换, 每天会生成当前值班人,每天之后的都是future
- 第一个表为每一次抽签的表,里面包括抽签时间,生效时间,及抽签表的人员id顺序
class DrawOrder(models.Model):
draw_time = models.DateTimeField(null=True)
take_effect_time = models.DateTimeField(null=True)
draw_order = models.CharField(max_length=50, null=True)
- 第二个表为人员表, 里面包含人员姓名和对应的autocrement的id
class PersonnelSummary(models.Model):
name = models.CharField(max_length=30, null=True)
en_name = models.EmailField(null=True)
- 第三个表为动态表,他会存储每一天值班人员的信息,注意是每一天,不是本月所有
class ActiveDudty(models.Model):
duty_time = models.DateTimeField(null=True)
duty_name = models.ForeignKey(PersonnelSummary, on_delete=models.CASCADE, null=True)
大致思路如下:
每一天我们会从历史抽签表
DrawOrder
取他的最后一条数据,你可以这么理解,当天时间大于历史表的最后一条数据,这条数据对应的第一个id就是这个人值班,反过来,生效时间就是他值班!
In [127]: DrawOrder.objects.all().last().draw_order
Out[127]: '9,10,1,2,3,4,5,6,7,8' #值班顺序的人员ID
In [129]: str(DrawOrder.objects.all().last().take_effect_time)
Out[129]: '2018-12-27 16:00:00+00:00' #开始值班的时间
看了上面的代码,相信大家明白这个表的用意了,目的就是我从这个表的时间开始往后推,这样就能算出来今天值班的是谁,那这时候就有人会问了, 那万一我中间新增人员修改人员呢? 问得好,你每修改一次, 你就在这个记录里面新增一条数据不就得了么? 把对应的人员ID改一下
目前我们是支持按月查询, future未来的数据,也就是今天以后的数据都不会写入数据库,因为他是未知的,没有人知道哪一天哪一位同事离职了?或者被裁了
值班时间 | 人员 | 人员ID |
---|---|---|
2018-12-25 | 于洋 | 7 |
上面为每天值班人员表的数据
ActiveDudty
, 一天生成一次, 通过历史表的生效时间和第一个人员id进行推算得出, 注意,人员ID就是历史数据的oder字段中的id
抽签时间 | 生效时间 | 抽签顺序(人员id) |
---|---|---|
2018-11-11 | 2018-12-12 | 1,2,3,4,5,6,7 |
DrawOrder
表中的数据,第一个为抽签时间,代表我抽签的日期,第二个为生效时间,代表我从哪天开始,一目了然这条数据,代表2018-12-12
人员ID为1
的小伙伴值班, 那么我们就可以推一下,12-25
号的应该是哪位朋友值班
#伪代码
data = [1,2,3,4,5,6,7]
local_day = '2018-12-25'
draw_time = '2018-12-12'
count = 1
index = 0
for i in range(local_day - draw_time):
try:
id = data[index
except Exception as e:
index = 0
index += 1
if draw_time +1 == local_day:
break
上面的伪代码可以计算出最后一次抽签日期的生效时间到当前的值班人员以及时间,都可以一一对应,那么我们可能会想到以后如果?️换班的人那么怎么办? 那我们就把换班的日期给他写进去,这样只针对于换班的n*2为人员就会写进去, 其他的还是future
def get_local_month_data(self, month=None):
#获取今天的时间
today = self.get_today()
#看看今天是否生成数据了
# today_time = self.today_is_active()
#找到最后一次抽签的次数!
#last_draw = self.get_last_draw_result()
# 我们需要找到今天之前的生效日期的最后一个
last_draw = DrawOrder.objects.filter(
take_effect_time__lt=parse(today)
).last()
# 遍历future
future_instance = DrawOrder.objects.filter(
take_effect_time__gt=parse(today)
)
# 分割以下目前值班的运维人员的id号码~
data = list(map(lambda x: int(x), last_draw.draw_order.split(',')))
# 找到今天的id
#local_index = today_time.first().duty_name.id + 1
#定义未来顺序日期的列表('顺序', '日期')
future_list = []
#是否是新的日期
single = False
for i in future_instance:
future_take_effect_time = parse(
self.reverse(i.take_effect_time.strftime("%Y-%m-%d 16:00:00")).strftime("%Y-%m-%d 00:00:00"))
if parse(today) == future_take_effect_time:
# 从最新的往后推
data = list(map(lambda x: int(x), i.draw_order.split(',')))
single = True
else:
future_list.append(
{
"order": i.draw_order,
"timer": future_take_effect_time
}
)
# 看看今天是否生成数据了, 没有的话就把今天的写进去, 并且会返回一个今天的索引,用于往后推
local_index = self.today_is_active(data=data, single=single)
#获取本月的总天数, 过了多少天, 还有多少天, 今年
today_detail = self.get_local_month()
#如果当前已经经过了半个月或者n天,从数据库找到这个月的前n天数据
queryset = self.search_today_active(duty_time__year=today_detail[-1],
duty_time__month=today_detail[-2])
#找到已经过去的时间
use_time = self.get_active_instance(queryset=queryset)
if len(use_time) <= 0:
#那肯定的,就是第一天了
pass
#给实例暂时赋值,以后肯定游有用
setattr(self, 'local_day_number', today_detail[0])
setattr(self, 'use_day', today_detail[1])
setattr(self, 'year', today_detail[-1])
setattr(self, 'month', today_detail[-2])
#我们需要找到后面15天或者n天~
print(today_detail)
#定义天数, 这边默认给0,代表当天
auto_day = 1
for _ in range(today_detail[1], today_detail[0]):
#每一天+1
timers = self.get_other_timer(auto_day, parse(today))
timers = str(timers).split(' ')[0]
for i in future_list:
if str(i['timer']).split(' ')[0] == timers:
data = [int(x) for x in i['order'].split(',')]
local_index = data[0]
break
# 防止continue没有+1, 先+1,前提是先做了时间转换
auto_day += 1
# 我们要判断如果今天的日期也找到了,就是说从今天开始做的循环,那么就不写进去了,因为前面queryset已经有数据了!
#if timers == parse(today):
# continue
#一样的逻辑, 进行ID查找
try:
#我在尝试找到id为今天的那个值班人员,然后进行自增,如果自增失败,那么为0
get_index = data.index(local_index)
other_persion_id = data[get_index]
local_index += 1
except (IndexError, KeyError, ValueError) as e:
local_index = 1
get_index = data.index(local_index)
other_persion_id = data[get_index]
local_index += 1
ops_persion = self.get_ops_persion_instance(id=other_persion_id)
d = {
"duty_name": ops_persion.name
}
s = ActiveDudty.objects.filter(duty_time=timers).first()
if s:
continue
#today_time = s.duty_time.strftime("%Y-%m-%d 16:00:00")
#today_time = parse(self.reverse(today_time).strftime("%Y-%m-%d 00:00:00"))
#timers = str(today_time).split(' ')[0]
d['duty_time'] = timers
if d not in use_time:
use_time.append(d)
return sorted(use_time, key=lambda x: x['duty_time'])
个人博客: https://igolang.cn