前言 :
这个前后做了几个月
目录
- 需求说明
- 代码架构
一 需求说明
1.1 班次类型
医生 | 夜班 | 连留 |
一线医生 | 上 | 上 |
二线医生 | 上 |
医生 | 夜班 | 连留 |
一线医生 | 上 | 上 |
二线医生 | 上 |
医生 | 白班 | 夜班 |
一线医生 | 上 | 上 |
二线医生 | 上 | 上 |
医生 | 会诊 |
一线医生 | 上 |
一线医生 | 上 |
1.2 员工信息表 ( 该表格需要手动填写, 自己申报 )
1.3 排班日期表 ( 第一列需要手动更新 )
排班规则
夜班 :
不能超过最大夜班数量
夜班不能连续上
夜班当天不会诊 , 不连留
调休日不夜班
会诊
不能超过最大会诊数量
当天不夜班
休息日不会诊
连留
休息日不连留
不能超过最大数量
当天不夜班
周末白班
当天不调休
不能跟夜班冲突
不能超过最大夜班数量
二 代码实现 :
# -*- coding: utf-8 -*-
"""
Created on Mon May 25 13:40:20 2020
@author: chengxf2
V2: 2020/06/29
增加规则
1: 当前夜班, 前两天都不能是夜班
2: 会诊人员可能是一线人员 , 不能跟连留 , 夜班 冲突
3: 每次加载表格的时候 , 清空一下表格的内容 , 防止上一次残留
v3: 2020/7/23
1: 休息日白班不能连续排班
2: 在排班结果没有确定下来之前不再写表格,I/O 读取的时间耗时
3: 运用墨菲定律 , 迭代次数为 30000 次 , 总排序有 3 千万
连续迭代 100 次 ,
4: 周五班属于周末班次, 但是要排会诊连留
5 某些人上固定班次
6: 会诊一线二线医生都有
"""
import os
from openpyxl import load_workbook
import numpy as np
from datetime import datetime
from enum import Enum
class DoctorKind(Enum):
LineOne = 0 #一线医生
LineSecond = 1 #二线医生
class Night_Type(Enum):
WorkingDay = 0
Weekend = 1
class CheckType(Enum):
Stay = 0 #连留
Diagnosis =1 #会诊
class Week(Enum):
WorkingDay = 0 #工作日
Weekend =1 #周末
Friday = 2 #周末
class AppointedDay(Enum):
ONE_DAY = 0 #一线白班
ONE_NIGHT = 2 #一线夜班
TWO_DAY = 4 #二线白班
TWO_NIGHT = 6 #二线夜班
class Result(Enum):
Success = 0 # " 排班成功 "
Error = 100
Failure_ONE_Stay = 102 #" 一线连留失败 "
Failure_ONE_Night = 104 #" 一线夜班失败 "
Failure_ONE_Working = 106 #工作日班次失败
Failure_ONE_Weekend = 108 #周末班次失败
Failure_ONE_Friday = 110 #夜班失败
Failure_ONE_WeekendDay = 112 #" 一线周末白班失败 "
Failure_ONE_WeekendNight = 114 #" 一线周末夜班失败 "
Failure_ONE_Fixed_Stay = 116 #" 一线连留失败 "
Failure_ONE_Fixed_Night = 118 #" 一线夜班失败 "
Failure_ONE_Fixed_WeekendDay = 120 #" 一线周末白班失败 "
Failure_ONE_Fixed_WeekendNight = 122 #" 一线周末夜班失败 "
Failure_TWO_Working = 200 #二线工作日
Failure_TWO_WeekEnd = 202 #二线夜班
Failure_TWO_Friday = 204 #二线周五
Failure_TWO_Night = 206 #" 二线夜班失败 "
Failure_TWO_WeekendDay = 208 # " 二线周末白班失败 "
Failure_TWO_WeekendNight = 210 # " 二线夜班失败 "
Failure_Fixed_Dianosisi = 212 #" 会诊失败 "
Failure_TWO_Fixed_Night = 214 #" 二线夜班失败 "
Failure_TWO_Fixed_WeekendDay = 216 # " 二线周末白班失败 "
Failure_TWO_Fixed_WeekendNight = 218 # " 二线夜班失败 "
Failure_Dianosisi = 300 #" 会诊失败 "
"""
excel 开头的代表从表里读; count 代表当前已经排出来的情况
workNight: 工作日夜班总数
restDay: 休息日白班总数
restNight: 休息日夜班总数
stay: 连留总数
diagnosis: 会诊总数
noDiagnosis: 会诊里外日
noWork: 调休 ; 不上班
row: 行号
column: 列号
"""
class Doctor:
def __init__(self,workNight, restDay, restNight, stay, diagnosis, noDiagnosis, noWork,listdayPer,listnightPer):
self.excelWorkNight = workNight; #工作日夜班, 一线二线医生都有
self.countWorkNight = 0 ;# 计数工作日夜班数量
self.excelRest = restDay ; #休息日白班, 从表读出
self.countRest = 0; #计数休息日白班
self.excelRestNight = restNight #休息日夜班 , 从表读出
self.countRestNight = 0 #计数休息日夜班数量
self.excelStay = stay; #连留 , 一线医生
self.countStay = 0 #计算连留总数
self.excelDiagnosis = diagnosis ; #会诊; 二线医生
self.countDiagnosis = 0 #计数会诊总数
self.excelnoDiagnosis = noDiagnosis; #会诊例外日, 这个时间段不能会诊
self.excelNoWork = noWork #调休日期
self.indexNight = [] #上夜班的时序
self.indexDay =[] #休息日白班的时序
self.indexStay =[] #连留的时序
self.indexNightPermanent = listnightPer #上固定的夜班
self.indexDayPermanent = listdayPer #固定的休息日白班
self.column = -1 #列号
self.columnDay = -1# 二线白班的列号
self.columnNight = -1 #二线夜班的列号
self.columnDiagnosis = -1 #会诊的列号
################# 排班主程序 ##############################
class Arrange :
"""
变量初始化
"""
def __init__(self):
self.pathStaff = "" #员工表格路径
self.pathDay = "" #排班表格路径
self.ResultOne = True # 一线班排的结果
self.ResultTwo= True # 二线班排的结果
self.Resultdiagnosis = False # 会诊班排列结果
self.maxIter = 1 #10000*20 #最多排次班 , 墨菲定律 , 如果概率是 1 / 一千万, 找到该可能是 80%
self.nameStaff = "staff.xlsx" #该表格是员工信息
self.nameDay = "day.xlsx" #该表格是一个月班次
self.HeadTwo =[" 二线白班 "," 二线夜班 "," 会诊 "] #二线人员要上的班种类
self.Head = [] #表头
self.dictFixed ={} #指定班次
self.dictOne ={} #一线人员词典
self.dictTwo ={} #二线人员词典
self.listOne =[] #一线人员名字列表
self.listTwo =[] # 二线人员名字列表
self.listDay = []# a[0] 工作日 , 休息日 , a[1] 行号
self.listDiagnosis =[] #一线二线人员都可以是会诊人员 [name,type]
"""
初始化改变过的变量
Args
None
return
None
"""
def InitPara(self,DictInfo):
# print("\n *************** 重新初始化 ***************\n")
for name in DictInfo.keys():
#print("\n name ",name)
doctor = DictInfo[name] ##value
doctor.countWorkNight = 0 #工作日夜班
doctor.countRest = 0 #休息日白班
doctor.countRestNight = 0 #休息日夜班数量
doctor.countStay = 0 #连留上限
doctor.countDiagnosis = 0 #会诊上限
doctor.indexNight = [] #夜班时续联
doctor.indexDay = [] #白班时序
doctor.indexStay =[] #休息日白班的时序
DictInfo[name] = doctor
"""
清除排班表内容
Args
maxRow 最大行
maxCol 最大列
return
None
"""
def ClearExcel(self):
wb = load_workbook(self.pathDay)
sheet = wb["1"]
maxRow = sheet.max_row #员工数
maxCol = sheet.max_column #天数
for i in range(1,maxRow+1):
for j in range(3,maxCol+1):
sheet.cell(row =i, column = j).value = ""
wb.save(self.pathDay)
wb.close()
"""
字符串转为列表
Args
str
return
listStr
"""
def ConvertStr(self, strInfo):
listInfo =[]
if strInfo =="0":
return listInfo
if isinstance(strInfo, str):
listInfo = strInfo.split("/")
listInfo = list(map(int, listInfo))
return listInfo
"""
配置人员班次:
1: 一线班人员
2: 二线班人员
Args
filePath: Excel 表格
return
None
"""
def GetInfo(self):
self.numOne = 0 #一线线医生
self.numTwo = 0 #二线医生
wbStaff = load_workbook(self.pathStaff)
wbDay = load_workbook(self.pathDay)
sheetStaff = wbStaff["1"]
sheetDay = wbDay["1"]
numStaff = sheetStaff.max_row #员工数
numDay = sheetDay.max_row #本月情况
print("\n num",numStaff, "\n path: ",self.pathStaff)
########### 一个月的班次情况 ##################
weekendNum = 0
workingNum = 0
FridayNum = 0
for index in range(2, numDay+1):
cate = sheetDay.cell(row=index, column=1).value #类型 0: 工作日 ,1: 周末 2: 周五
day =Week(cate)
self.listDay.append([day,index])
if day is Week.Weekend :
weekendNum += 1
elif day is Week.Friday:
FridayNum +=1
else:
workingNum +=1
print("\n 工作日 ",workingNum,"\t 周五: ",FridayNum,"\t 周末 ",weekendNum)
################ 获取人员信息, 从第二行开始排 ###################
for i in range(2,numStaff+1):
name = sheetStaff.cell(row=i, column=1).value #姓名
staffType = sheetStaff.cell(row=i, column=2).value #一线二线
workNight = sheetStaff.cell(row=i, column=3).value #工作日夜班
restDay = sheetStaff.cell(row=i, column=4).value #休息日白班
restNight = sheetStaff.cell(row=i, column=5).value #休息日夜班
stay = sheetStaff.cell(row=i, column=6).value #连留
diagnosis = sheetStaff.cell(row=i, column=7).value #会诊
strNoDiagnosis = sheetStaff.cell(row=i, column=8).value #会诊例外日
strNoWork = sheetStaff.cell(row=i, column=9).value #休息日
strDayPer = sheetStaff.cell(row=i, column=10).value #固定白班
strNightPer = sheetStaff.cell(row=i, column=11).value #固定夜班
kind = DoctorKind(staffType)
if int(diagnosis)>=1: #有会诊
diagItem =[name,kind]
self.listDiagnosis.append(diagItem)
# print("\n name ",name,"\t diagnosis: ",diagnosis,"\t jobType: ",jobType)
listNoDiagnosis = []
listNoWork = []
listnightPer =[] #固定伤的夜班
listdayPer =[] #固定上的白班
listNoDiagnosis = self.ConvertStr(strNoDiagnosis) #会诊例外日
listNoWork = self.ConvertStr(strNoWork) #调休日
listdayPer = self.ConvertStr(strDayPer) #固定白班日期
listnightPer = self.ConvertStr(strNightPer) #固定夜班日期
dtr = Doctor(workNight,restDay, restNight,stay,diagnosis, listNoDiagnosis,listNoWork,listdayPer,listnightPer)
#print("\n name: ",name,"\t listNoWork: ",listNoWork)
if kind is DoctorKind.LineOne: #一线人员
self.dictOne[name]= dtr
self.listOne.append(name)
self.numOne +=1
#print("\t name ",name)
else: # 二线人员
self.dictTwo[name] = dtr
self.listTwo.append(name)
self.numTwo +=1
self.Head.extend(self.listOne) #表头
self.Head.extend(self.HeadTwo) #表头
"""
GetDesDays 获得对应固定上班的日期
Args
doctor: 医生词典
kind: 一线 , 二线医生
return
rowRet
"""
def GetDesDays(self, dictDoctor,kind):
rowRet =[]
for name in dictDoctor.keys():
doctor = dictDoctor[name]
listNight = doctor.indexNightPermanent #上固定的夜班
listDay = doctor.indexDayPermanent #固定的休息日白班
### 固定白班 ###
if len(listDay)>0: #固定白班 [日期 , 指定班次类型 , 名字]
for row in listDay:
if row<1:
continue
if kind is DoctorKind.LineOne: ## 一线医生
item = [row, AppointedDay.ONE_DAY, name]
else: #二线医生
item = [row, AppointedDay.TWO_DAY, name]
rowRet.append(item)
### 固定夜班 ###
if len(listNight)>0: #固定夜班 [日期 , 指定班次类型 , 名字]
if row<1:
continue
for row in listNight:
if kind is DoctorKind.LineOne: ## 一线医生
item = [row, AppointedDay.ONE_NIGHT, name]
else:
item = [row, AppointedDay.TWO_NIGHT, name]
rowRet.append(item)
return rowRet
"""
获得列表
Args
item: 原来列表
day: 工作日 | 周五 | 休息日
name: 姓名
Job: 工作类型
return
[0,0,0,0,0,0,0,0]
#一线白班标志位
#name
"""
def ConfigItem(self, item, day, name):
arg0 = item[0] #一线白班标志位
arg1 = item[1] #白班名字
arg2 = item[2] #一线夜班标志位
arg3 = item[3] #一线夜班名字
arg4 = item[4] #二线白班标志位
arg5 = item[5]# 二线白班名字
arg6 = item[6] #二线夜班标志位
arg7 = item[7]# 二线夜班名字
if day is AppointedDay.ONE_DAY:
arg0 = True
arg1 = name
elif day is AppointedDay.ONE_NIGHT:
arg2 = True
arg3 = name
#print("\n 一线夜班 ",name)
elif day is AppointedDay.TWO_DAY:
arg4 = True
arg5 = name
# print("\n 二线白班 ",name)
elif day is AppointedDay.TWO_NIGHT:
arg6 = True
arg7 = name
else:
print("==============ErrorItem==========")
# print("\n 二线夜班 ",name)
item = [arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7,-1]
return item
"""
获得指定班次
Args
None
return
self.listDay1: 已经有人上了固定的班
self.listDay2: 无人上固定的班次
"""
def GetDesignated(self):
rowMerge =[]
row1 = self.GetDesDays(self.dictOne,DoctorKind.LineOne)
row2 = self.GetDesDays(self.dictTwo,DoctorKind.LineSecond)
if len(row1)>1:
rowMerge.extend(row1)
if len(row2)>1:
rowMerge.extend(row2)
#[index,SPECDay.Night.value, name,cate]
for item in rowMerge:
row = item[0] #日期
day = item[1] #白班 | 夜班、
name =item[2] #姓名
retItem =[]
if row not in self.dictFixed:
curItem = [False,None,False,None,False,None,False,None,-1] #[一线白班,name, 一线夜班.name, " 二线白班 ",name, " 二线夜班 ",name,Day]
else:
curItem = self.dictFixed[row]
retItem = self.ConfigItem(curItem, day,name)
self.dictFixed[row] = retItem
"""
获得正常班次
Arg
None
return
None
"""
def GetNormal(self):
dayAppoint = self.dictFixed.keys()
self.listNorml =[]
for item in self.listDay:
day = item[0] #工作日 / 周五 / 休息日
row = item[1] #当前行号
if row not in dayAppoint:
self.listNorml.append(item)
else:
itemFixed = self.dictFixed[row]
itemFixed[-1]= day
self.dictFixed[row]=itemFixed
"""
更新一线, 二线人员的情况
写表头
Args
None
return
None
"""
def ExcelInit(self):
day_wb = load_workbook(self.pathDay)
sheet= day_wb["1"]
indexColumn= 3#[节假日 , 日期 , 一线人员]
m = len(self.listOne) #一线人员的个数
columnDay = indexColumn+m #二线人员休息日白班列
columnNight = columnDay+1 #二线夜班列
columnDiagnosis = columnNight+1# 会诊列
for name in self.listOne:
doctor = self.dictOne[name]
doctor.column = indexColumn #所在列
doctor.columnDiagnosis = columnDiagnosis# 会诊所在列
indexColumn = indexColumn+1
self.dictOne[name] = doctor
for name in self.listTwo:
doctor = self.dictTwo[name]
doctor.columnDay = columnDay # 二线白班的列号
doctor.columnNight = columnNight #二线夜班的列号
doctor.columnDiagnosis = columnDiagnosis# 会诊列号
self.dictTwo[name] = doctor
## 写表格头 ####
col =3
for name in self.Head:
sheet.cell(row =1, column = col).value = name
col = col+1
day_wb.save(self.pathDay)
day_wb.close()
"""
初始化
读取 day.xlsx,staff.xlsx,
写表格头 day.xlsx
Args
retCode
return
retCode
"""
def MainInit(self):
#获得文件路径
self.GetFile()
#清空表格
self.ClearExcel()
#获得一线, 二线人员情况
self.GetInfo()
#写表头, 以及配置一线二线人员信息
self.ExcelInit()
#获得指定班次
self.GetDesignated()
#获得正常班次
self.GetNormal()
print("\n ********** 配置信息读取完毕 **************\n")
"""
```` 获取 Excel 表格路径
````Args
retCode
return
self.pathDay: 排班表格
self.pathStaff: 员工表格
````"""
def GetFile(self):
self.pathStaff = os.path.abspath(self.nameStaff)
self.pathDay = os.path.abspath(self.nameDay)
if not os.path.exists(self.pathStaff):
print("\n 员工信息表格不存在 ")
if not os.path.exists(self.pathDay):
print("\n 排班日记表格不存在 ")
"""
Args
one: 一线人员名单
Two: 二线人员名单
return
retCode
"""
def Debug(self,dictDoctor):
#,"\t 列: ",doctor.column,": 二綫白班列 ",doctor.columnDay," 二綫夜班列: ",doctor.columnNight,": 診斷列 :",doctor.columnDiagnosis
for name in dictDoctor.keys():
doctor =dictDoctor[name]
print("\n Name: ",name,"\t 周末白班: ",doctor.excelRest, ": 实际 ",doctor.countRest)
"""
print("\n 夜班: ",doctor.excelWorkNight, ": 实际 ",doctor.countWorkNight,
"\t 周末白班: ",doctor.excelRest, ": 实际 ",doctor.countRest,
"\t 周末夜班: ",doctor.excelRestNight , ": 实际 ",doctor.countRestNight,
"\t 连留: ",doctor.excelStay, ": 实际 ",doctor.countStay,
"\t 会诊: ",doctor.excelDiagnosis, ": 实际 ",doctor.countDiagnosis
)
"""
#print("\n 二线 ",name, "\t 夜班: ",workNightCount,"\t 会诊: ",gcCount,"\t 休息白班 ",restDay,"\t 休息夜班 ",restNight)
"""
检查夜班条件 :
不能超过最大夜班数量
前一天不能夜班
前两天不能夜班
当天不调休
Args
cate: Night_Type
index: 当前天序号
Doctor: 医生情况
return
False: 不满足
True: 满足
"""
def CheckNight(self, cate, index, doctor):
if cate is Night_Type.WorkingDay: #工作日
cond1 = (doctor.countWorkNight < doctor.excelWorkNight)# 不超過 最大夜班数量
else:
cond1 = (doctor.countRestNight< doctor.excelRestNight)
if False == cond1:
return False
cond2 = ((index-1) not in doctor.indexNight)# 前一天不夜班
if False == cond2:
return False
cond3 = ((index-2) not in doctor.indexNight) #前兩天不夜班
if False == cond3:
return False
cond4 = (index not in doctor.excelNoWork) #调休日不夜班
if False ==cond4:
return False
return True
"""
周末白班
cond1: 不超过最大班次
cond2: 前一天不夜班
cond3: 当天没调休
cond4: 前一天白班
Args
index: 当天班次
doctor: 医生情况
return
False: 不满足
True: 满足
"""
def CheckWeekendDay(self, index, doctor):
cond1 = (doctor.countRest < doctor.excelRest) #不超过范围
if False == cond1:
return False
cond2 = (index-1 not in doctor.indexNight) and (index not in doctor.indexNight) #当天, 前一天不夜班
if False == cond2:
return False
cond3 = (index not in doctor.excelNoWork) #当前不休息
if False == cond3:
return False
cond4 = ((index-1) not in doctor.indexDay) #白班也不能连续上 , 要不然上十四天班了
if False == cond4:
return False
return True
"""
檢查会诊或者连留
不超过最大数量
当天不夜班
前一天不夜班
当天不休息
Args
kind: 0 连留 1 会诊
index: 当天班次
doctor: 医生情况
return
False: 不满足
True: 满足
"""
def CheckStayDiag(self, kind, index, doctor):
#### 一线连留 ####
if kind is CheckType.Stay:
cond1 = (doctor.countStay < doctor.excelStay) #连留在当天排班的时候已经过滤过夜班名单了
else:
cond1 = (doctor.countDiagnosis< doctor.excelDiagnosis) and (index not in doctor.indexNight) #不超过会诊上限 , 以及当天不夜班
if False == cond1:
return False
cond2 = (index-1 not in doctor.indexNight) #前一天, 当天不夜班
if False == cond2:
return False
cond3 = (index not in doctor.excelNoWork) #当前不休息
if False == cond3:
return False
return True
"""
排正常日期的班次
Args
retCode
return
Row[row,col,value] #排班表
"""
def SchedulingNormal(self):
result = Result.Success
rows =[]
retCode =""
for item in self.listNorml: #行号
day = item[0] #日期
index = item[1] #行号
if day is Week.WorkingDay: #### 排工作日 ######
#一线人员
result, columnNight,columnStay = self.GetOneWorking(index, False, None)
if result is Result.Success:
rows.append([index,columnNight," 夜 "])
rows.append([index,columnStay," 连留 "])
else:
return Result.Failure_ONE_Working,retCode
#二线人员
result, columnNight,nightName = self.GetSecondWorking(index,False,None)
if result is Result.Success:
rows.append([index,columnNight,nightName])
else:
return Result.Failure_TWO_Working,retCode
#会诊人员
result,columnDiagnosis,diagNosisName = self.GetDiagnosis(index)
if result is Result.Success:
rows.append([index,columnDiagnosis,diagNosisName])
else:
return Result.Failure_Dianosisi,None
elif day is Week.Weekend: #排周末 ########
#一线人员
result, columnNight,columnDay,nameNight,nameDay = self.GetOneWeekend(index,False, None, False, None)
if result is Result.Success:
rows.append([index,columnDay," 白 "])
rows.append([index,nameNight," 夜 "])
else:
return Result.Failure_ONE_WeekendDay,retCode
#二线人员
result, columnNight,columnDay,nameNight,nameDay = self.GetSecondWeekend(index,False,None,False,None)
if result is Result.Success:
rows.append([index,columnDay,nameDay])
rows.append([index,columnNight,nameNight])
else:
return Result.Failure_TWO_WeekEnd,retCode
else: ############## 排周五班次 ########################
#先一线
result, columnNight,columnStay = self.GetOneFriday(index, False, None)
if result is Result.Success:
rows.append([index,columnNight," 夜 "])
rows.append([index,columnStay," 连留 "])
else:
return result,retCode
#二线
result, columnNight,nightName = self.GetSecondFriday(index,False,None)
if result is Result.Success:
rows.append([index,columnNight,nightName])
else:
return Result.Failure_TWO_Friday,retCode
#会诊人员
result,columnDiagnosis,diagNosisName = self.GetDiagnosis(index)
if result is not Result.Success:
rows.append([index,columnDiagnosis,diagNosisName])
else:
return Result.Failure_Dianosisi,retCode
# print("\n 周五 ","\t : ",day,"\t ",index)
return Result.Success,rows
"""
排二线线工作日班次
工作日夜班
Args:
index: 当前天的序列号
isNight 夜班是否有固定人员上了
nightName: 名字
return
result: 是否查着成功
columnNight: 夜班列号
nameNight: 夜班人员名单
"""
def GetSecondWorking(self,index,isNight,nightName):
result = False
columnNight = -1
nameNight =""
##### 先夜班 ####
listNight = [] #夜班人员
if True == isNight:
nameNight = nightName
else:
for name in self.listTwo: ## 二线线人员名单
doctor = self.dictTwo[name] #当前信息
result = self.CheckNight(Night_Type.WorkingDay,index, doctor) #檢查夜班
if True == result:
listNight.append(name)
else:
continue
if len(listNight)>0:
np.random.shuffle(listNight)
nameNight = listNight[0]
else: #直接退出了 , 找不到
return Result.Failure_TWO_Fixed_Night, columnNight,nameNight
self.dictTwo[nameNight].countWorkNight = self.dictTwo[nameNight].countWorkNight +1
self.dictTwo[nameNight].indexNight.append(index)
columnNight = self.dictTwo[nameNight].columnNight
return Result.Success, columnNight,nameNight
"""
排二线周末班次
夜班
白班
Args:
index: 当前天的序列号
return
find: 是否查着成功
columnNight: 夜班列号
columnDay: 白班
"""
def GetSecondWeekend(self,index,isDay,dayName,isNight,nightName):
columnNight = -1
columnDay =-1
nameNight =""
nameDay =""
listNight = [] #夜班人员
listDay =[] #白班
##### 先夜班 ####
if isNight is True:# 夜班有人上了
nameNight = nightName
else:
for name in self.listTwo: ## 二线线人员名单
doctor = self.dictTwo[name] #当前信息
cond = self.CheckNight(Night_Type.Weekend,index, doctor) #檢查夜班
if cond:
listNight.append(name)
else:
continue
if len(listNight)>0:
np.random.shuffle(listNight)
nameNight = listNight[0]
else: #直接退出了
return Result.Failure_TWO_WeekendNight, columnNight,columnDay,nameNight,nameDay
###### 再排白班 #######
if isDay is True:
nameDay = dayName
else:
for name in self.listTwo:
if name == nameNight:
continue
doctor = self.dictTwo[name]
cond =self.CheckWeekendDay(index,doctor)
if True == cond:
listDay.append(name)
else:
continue
if len(listDay)>0:
np.random.shuffle(listDay)
nameDay = listDay[0]
else: #没有办法排班了
return Result.Failure_TWO_WeekendDay, columnNight,columnDay,nameNight,nameDay
self.dictTwo[nameNight].countRestNight = self.dictTwo[nameNight].countRestNight +1
self.dictTwo[nameNight].indexNight.append(index)
self.dictTwo[nameDay].countRest = self.dictTwo[nameDay].countRest+1
self.dictTwo[nameDay].indexDay.append(index)
columnNight = self.dictTwo[nameNight].columnNight
columnDay = self.dictTwo[nameDay].columnDay
return Result.Success, columnNight,columnDay,nameNight,nameDay
"""
排二线周五班次
夜班: 算周五班次
Args:
index: 当前天的序列号
return
find: 是否查着成功
columnNight: 夜班列号
columnDay: 白班
"""
def GetSecondFriday(self,index,isNight,nightName):
result = False
columnNight = -1
nameNight =""
listNight = [] #夜班人员
if True == isNight:
nameNight = nightName
else:
for name in self.listTwo: ## 二线线人员名单
doctor = self.dictTwo[name] #当前信息
result = self.CheckNight(Night_Type.Weekend,index, doctor) #檢查夜班
if True == result:
listNight.append(name)
else:
continue
if len(listNight)>0:
np.random.shuffle(listNight)
nameNight = listNight[0]
else: #直接退出了 , 找不到
return Result.Failure_TWO_Fixed_Night, columnNight,nameNight
self.dictTwo[nameNight].countRestNight = self.dictTwo[nameNight].countRestNight +1
self.dictTwo[nameNight].indexNight.append(index)
columnNight = self.dictTwo[nameNight].columnNight
return Result.Success, columnNight,nameNight
"""
排一线周五班
夜班: 算周末班次
连留: 一线连留
Args:
index: 当前天的序列号
isNight: 夜班是否
nightName: 夜班名字
return
find: 是否查着成功
columnNight: 夜班列号
columnDay: 白班
"""
def GetOneFriday(self,index,isNight,nightName):
result = False
columnNight = -1
columnStay =-1
listNight = [] #夜班人员
listStay =[] #连留人员
##### 先夜班 ####
if True == isNight: #是否已经有固定人上了
nameNight = nightName
else:
for name in self.listOne: ## 一线人员名单
doctor = self.dictOne[name] #当前信息
result = self.CheckNight(Night_Type.Weekend,index, doctor) #檢查夜班
if True == result:
listNight.append(name)
else:
continue
if len(listNight)>0: #可选人员列表
np.random.shuffle(listNight)
nameNight = listNight[0]
else: #直接退出
return Result.Failure_ONE_Fixed_WeekendNight, columnNight,columnStay
###### 再排连留 #######
for name in self.listOne:
if name == nameNight:
continue
doctor = self.dictOne[name]
result =self.CheckStayDiag(CheckType.Stay,index,doctor)
if True == result:
listStay.append(name)
else:
continue
if len(listStay)>0:
np.random.shuffle(listStay)
nameStay = listStay[0]
else: #没有办法排班了
return Result.Failure_ONE_Fixed_Stay, columnNight,columnStay
self.dictOne[nameNight].countRestNight = self.dictOne[nameNight].countRestNight +1 #工作日夜班
self.dictOne[nameNight].indexNight.append(index) #夜班时序
self.dictOne[nameStay].countStay = self.dictOne[nameStay].countStay+1
self.dictOne[nameStay].indexStay.append(index) #连留时序
columnNight = self.dictOne[nameNight].column
columnStay = self.dictOne[nameStay].column
return Result.Success, columnNight,columnStay
"""
排会诊班次
Args:
index: 当前天的序列号
return
Result: 结果
columnDiagnosis: 会诊列号
nameDiagnosis: 会诊人员名字
"""
def GetDiagnosis(self,index):
listDiagnosis =[]
columnDiagnosis = -1
retName = ""
###### 再排连留 ####### diagItem =[name,diagnosis,staffType]
for item in self.listDiagnosis:
name = item[0]
kind = item[1]
if kind is DoctorKind.LineOne: #一线医生
doctor = self.dictOne[name]
else:
doctor = self.dictTwo[name]
result =self.CheckStayDiag(CheckType.Diagnosis,index,doctor)
if True == result:
listDiagnosis.append(name)
else:
continue
if len(listDiagnosis)>0:
np.random.shuffle(listDiagnosis)
retName = listDiagnosis[0]
else: #没有办法排班了
return Result.Failure_Fixed_Dianosisi, columnDiagnosis,retName
if retName in self.listOne:
self.dictOne[retName].countDiagnosis = self.dictOne[retName].countDiagnosis +1 #会诊
columnDiagnosis = self.dictOne[retName].columnDiagnosis
else:
self.dictTwo[retName].countDiagnosis = self.dictTwo[retName].countDiagnosis +1 #会诊
columnDiagnosis = self.dictTwo[retName].columnDiagnosis
return Result.Success, columnDiagnosis,retName
"""
排一线工作日班次
工作日夜班
工作日连留
Args:
index: 当前天的序列号
isNight: 夜班已经有人上了
nightName: 夜班人员名字
return
result: 是否查着成功
columnNight: 夜班列号
columnDay: 白班
"""
def GetOneWorking(self,index,isNight,nightName):
result = False
columnNight = -1
columnStay =-1
listNight = [] #夜班人员
listStay =[] #连留人员
##### 先夜班 ####
if True == isNight: #是否已经有固定人上了
nameNight = nightName
else:
for name in self.listOne: ## 一线人员名单
doctor = self.dictOne[name] #当前信息
result = self.CheckNight(Night_Type.WorkingDay,index, doctor) #檢查夜班
if True == result:
listNight.append(name)
else:
continue
if len(listNight)>0: #可选人员列表
np.random.shuffle(listNight)
nameNight = listNight[0]
else: #直接退出
return Result.Failure_ONE_Fixed_Night, columnNight,columnStay
###### 再排连留 #######
for name in self.listOne:
if name == nameNight:
continue
doctor = self.dictOne[name]
result =self.CheckStayDiag(CheckType.Stay,index,doctor)
if True == result:
listStay.append(name)
else:
continue
if len(listStay)>0:
np.random.shuffle(listStay)
nameStay = listStay[0]
else: #没有办法排班了
return Result.Failure_ONE_Fixed_Stay, columnNight,columnStay
self.dictOne[nameNight].countWorkNight = self.dictOne[nameNight].countWorkNight +1 #工作日夜班
self.dictOne[nameNight].indexNight.append(index) #夜班时序
self.dictOne[nameStay].countStay = self.dictOne[nameStay].countStay+1
self.dictOne[nameStay].indexStay.append(index) #连留时序
columnNight = self.dictOne[nameNight].column
columnStay = self.dictOne[nameStay].column
return Result.Success, columnNight,columnStay
"""
排一线班次
白班
夜班
Args:
index: 当前天的序列号
isDay: 白班是否有人上了
dayName 白班
isNight 夜班是否有人上了
nightName 夜班名字
return
find: 是否查着成功
columnNight: 夜班列号
columnStay: 连留列号
"""
def GetOneWeekend(self,index,isDay,dayName,isNight,nightName):
columnNight = -1
columnDay =-1
nameNight =""
nameDay =""
listNight = [] #夜班人员
listDay =[] #白班
##### 先夜班 ####
if isNight is True:# 夜班有人上了
nameNight = nightName
else:
for name in self.listOne: ## 二线线人员名单
doctor = self.dictOne[name] #当前信息
cond = self.CheckNight(Night_Type.Weekend,index, doctor) #檢查夜班
if cond:
listNight.append(name)
else:
continue
if len(listNight)>0:
np.random.shuffle(listNight)
nameNight = listNight[0]
else: #直接退出了
return Result.Failure_ONE_WeekendNight, columnNight,columnDay,nameNight,nameDay
###### 再排白班 #######
if isDay is True:
nameDay = dayName
else:
for name in self.listOne:
if name == nameNight:
continue
doctor = self.dictOne[name]
cond =self.CheckWeekendDay(index,doctor)
if True == cond:
listDay.append(name)
else:
continue
if len(listDay)>0:
np.random.shuffle(listDay)
nameDay = listDay[0]
else: #没有办法排班了
return Result.Failure_ONE_WeekendDay, columnNight,columnDay,nameNight,nameDay
self.dictOne[nameNight].countRestNight = self.dictOne[nameNight].countRestNight +1
self.dictOne[nameNight].indexNight.append(index)
self.dictOne[nameDay].countRest = self.dictOne[nameDay].countRest+1
self.dictOne[nameDay].indexDay.append(index)
columnNight = self.dictOne[nameNight].columnNight
columnDay = self.dictOne[nameDay].columnDay
return Result.Success, columnNight,columnDay,nameNight,nameDay
"""
排固定日期的班次
Args
None: 这些天, 已经有人上指定的班次了
return
Row[row,col,value] #排班表
"""
def SchedulingFixed(self):
result = Result.Success
rows =[]
retCode =""
keys =self.dictFixed.keys()
if len(keys)<1:
return Result.Success,retCode
for index in keys: #行号
item = self.dictFixed[index]
isDayOne = item[0] #一线白班
dayNameOne = item[1] #name
isNightOne = item[2] #一线夜班
nightNameOne = item[3] #name
isDaySecond = item[4] #二线白班
dayNameSecond = item[5] #name
isNightSecond = item[6] #二线夜班
nightNameSecond = item[7] #name
day = item[8]#day
#print(" 一线白班 ",arg0,":",arg1," 一线夜班: ",arg2,": ",arg3,"\t 二线白班 ",arg4,": ",arg5," 二线夜班 ",arg6,": ",arg7)
if day is Week.WorkingDay: #### 排工作日 ######
#一线人员
result, columnNight,columnStay = self.GetOneWorking(index, isNightOne, nightNameOne)
if result is Result.Success:
rows.append([index,columnNight," 夜 "])
rows.append([index,columnStay," 连留 "])
else:
return Result.Failure_ONE_Working,retCode
#二线人员
result, columnNight,nightName = self.GetSecondWorking(index,isNightSecond,nightNameSecond)
if result is Result.Success:
rows.append([index,columnNight,nightName])
else:
return Result.Failure_TWO_Working,retCode
#会诊人员
result,columnDiagnosis,diagNosisName = self.GetDiagnosis(index)
if result is Result.Success:
rows.append([index,columnDiagnosis,diagNosisName])
else:
return Result.Failure_Dianosisi,retCode
elif day is Week.Weekend: #排周末 ########
#一线人员
result, columnNight,columnDay,nameNight,nameDay = self.GetOneWeekend(index,isDayOne, dayNameOne, isNightOne, nightNameOne)
if result is Result.Success:
rows.append([index,columnDay," 白 "])
rows.append([index,nameNight," 夜 "])
else:
return Result.Failure_ONE_Fixed_WeekendDay,retCode
#二线人员
result, columnNight,columnDay,nameNight,nameDay = self.GetSecondWeekend(index,isDaySecond,dayNameSecond,isNightSecond,nightNameSecond)
if result is Result.Success:
rows.append([index,columnDay,nameDay])
rows.append([index,columnNight,nameNight])
else:
return Result.Failure_TWO_Fixed_WeekendDay,retCode
else: ############## 排周五班次 ########################
### 先一线 ####
result, columnNight,columnStay = self.GetOneFriday(index, isNightOne, nightNameOne)
if result is not Result.Success:
return Result.Error,retCode
else:
rows.append([index,columnNight," 夜 "])
rows.append([index,columnStay," 连留 "])
#二线
result, columnNight,nightName = self.GetSecondFriday(index,isNightSecond,nightNameSecond)
if result is not Result.Success:
return Result.Failure_TWO_Friday,retCode
else:
rows.append([index,columnNight,nightName])
#会诊人员
result,columnDiagnosis,diagNosisName = self.GetDiagnosis(index)
if result is not Result.Success:
return Result.Failure_Dianosisi,retCode
else:
rows.append([index,columnDiagnosis,diagNosisName])
return Result.Success,rows
"""
排班
Args
None
return
result
"""
"""
保存内容
Args
rows: 要保存的内容
return
None
"""
def SaveExcel(self, rows):
wb = load_workbook(self.pathDay)
sheet = wb["1"]
for item in rows:
rowIndex = item[0]
columnIndex = item[1]
value = item[2]
sheet.cell(row =rowIndex, column = columnIndex).value = value
wb.save(self.pathDay)
"""
排班
Args
None
return
写表格
"""
def Scheduling(self):
result = Result.Success
rows =[]
retCode =""
#先排固定班次
result,rowFixed = self.SchedulingFixed()
#print("\n result",result,"\t rows " ,rowFixed)
if result is Result.Success:
rows.append(rowFixed)
else:
return result,retCode
result, rowsNormal = self.SchedulingNormal()
if result is Result.Success:
rows.append(rowsNormal)
else:
return result,retCode
return Result.Success,rows
"""
排班
Args
None
return
写表格
"""
def Run(self):
self.MainInit() #参数初始化 #FailCause.cause300.value
print("\n ========== 排班开始 ==========:")
for i in range(self.maxIter):
result,rows = self.Scheduling()
#print("\n result ",result)
if result is Result.Success:
self.SaveExcel(rows)
print("\n 排班成功了 ")
break
else:
self.InitPara(self.dictOne)
self.InitPara(self.dictTwo)
#print("\n result ",result)
print("\n ========== 排班结束 ==========:",i)
ag =Arrange()
ag.Run()
原文链接:https://blog.csdn.net/chengxf2/article/details/107788032