*-- 广州分公司司机/送货员排班系统
*-- 程序员:红虎 于 2001年7月5日
*-- 前提条件:
* 建立临时表:排班表和员工表
* 每个司机只能送2条车线
* 车线名称:R1,R2,R3,... Rn
* 驾 驶 员:D1,D2,D3,... Dn
* 搬 运 工:L1,L2,L3,... Ln
#define nRouteNum 9 && 最多车线数
#define nDriverNum 14 && 最多驾驶员
#define nLiftNum 13 && 最多搬运工
#define cDriverType "D" && 表示驾驶员
#define cLiftType "L" && 表示搬运工
#define nWeekDays 5 && 一周上班数
lnFreeDays = 7 - nWeekDays && 每周休息日
ldDateFrom = {^2001.07.01} && 排班开始日
ldDateto = {^2001.07.31} && 排班结束日
lnTotalDays = ldDateTo - ldDateFrom + 1 && 共有的上班天数
lnMaxWorkDays = 21 && 一段时间(月)最大上班数
*-- 程序思路:
* 在每一个车线中,有驾驶员和搬运工2个工种,
* 字段名称以此规律:R1_D,R1_L, R2_D,R2_L....
ShowProcessBar("创建排班数据表...",nRouteNum)
*-- 创建排班表:
Create cursor cursor_works (date d) && 日期字段
For n= 1 to nRouteNum
showbar(n)
*-- 加入车线字段
cn = allt(str(n))
lcFieldName = "R" + cn + "_D"
alter table cursor_works add column &lcFieldName c (6) && 6位字段宽度可用来填写驾驶员姓名
lcFieldName = "R" + cn + "_L"
alter table cursor_works add column &lcFieldName c (6) && 6位字段宽度可用来填写搬运工姓名
Endfor
ShowProcessBar("创建员工数据表...",nDriverNum+nLiftNum)
*-- 创建员工表:
Create cursor cursor_personal ( ;
姓名 c (6) ,;
类型 c (2) ,;
天数 n (3) ,;
车线1 n (3) ,;
车线2 n (3) ,;
连续 n (3) ,;
休息 n (3) ,;
已排 l )
For n=1 to nDriverNum
showbar(n)
*-- 加入驾驶员记录
lcName = cDriverType + allt(str(n))
appe blank
repl 姓名 with lcName ,;
类型 with cDriverType && D = Driver = 司机
Endfor
For n=1 to nLiftNum
showbar(nDriverNum+n)
*-- 加入搬运工记录
lcName = cLiftType + allt(str(n))
appe blank
repl 姓名 with lcName ,;
类型 with cLiftType && L = Lift = 搬运工
Endfor
*-- 注意:每一个司机最多送2条车线,
* 如果共有司机 14 个,那么可以送 14*2 = 28 条车线人
* 假设现在有 9 条车线,那么 28/9 = 3.1111
* 每天车线在14个人中需要出现 3.11 次才够
*-- 将车线根据 1、2、3、4...N、1、2、3...N、1、2、....的规律排列
ShowProcessBar("计算每位司机所送货的2条车线...",nDriverNum*2)
dime laRouteList(nDriverNum*2)
For n=1 to nDriverNum*2
showbar(n)
laRouteList(n) = mod(n,nRouteNum)
if laRouteList(n) = 0
laRouteList(n) = nRouteNum
endif
Endfor
*-- 将排列出来的车线在员工表中根据:
* 记录1的车线1、车线2,记录2的车线1、车线2...记录N的车线1、车线2 依次填充
sele cursor_personal
ShowProcessBar("计算每位司机所送货的2条车线...",nDriverNum)
scan for 类型 = cDriverType
showbar(recn())
repl 车线1 with laRouteList( recn() * 2 - 1 )
repl 车线2 with laRouteList( recn() * 2 )
endscan
*!* acti scre
*!* brow for 类型 = cDriverType ;
*!* field 姓名,车线1,车线2 ;
*!* title "请修改司机姓名以及他们所送的2条车线,保证每条车线被排至少3次 按 Ctrl+W 存盘!"
*-- 开始进行排班
*-- 从日期范围 ldDateFrom 到 ldDateTo 进行循环处理
ShowProcessBar("正在处理排班...",lnTotalDays)
For d=1 to lnTotalDays
showbar(d,"排 "+dtoc(ldDateFrom+d-1) +" 这天的班...")
*-- 重新刷新员工表
sele cursor_personal
repl 已排 with .F. all
go top
*-- 在
工作表中添加一天的记录
sele cursor_works
appe blank
repl date with ldDateFrom + d - 1
*-- 先排司机的班次 =======================================================
For r=1 to nRouteNum
lcFieldName = "R" + allt(str(r)) + "_D"
sele cursor_personal
sele recn() as rec_no,* from cursor_personal ;
where 类型 = cDriverType ;
and 天数 < lnMaxWorkDays ;
and !已排 ;
and inlist(r,车线1,车线2) ;
order by 天数 ;
into cursor temp
llFound = iif(_tally>0,.T.,.F.)
If llFound
sele cursor_personal
goto temp.rec_no
repl 已排 with .T.
if inlist(r,车线1,车线2) && 满足车线服务
repl 天数 with 天数 + 1
repl 连续 with 连续 + 1
lcCurName = allt(姓名)
sele cursor_works
repl &lcFieldName with lcCurName
sele cursor_personal
else
repl 休息 with 休息 + 1
r = r - 1
endif
sele cursor_personal
if 连续 >= nWeekDays or 休息 >= lnFreeDays
repl 连续 with 0
repl 休息 with 0
endif
Endif
Endfor
*-- 司机的班次排结束 =====================================================
*-- 接着排送货员的班次 ====================================================
For r=1 to nRouteNum
lcFieldName = "R" + allt(str(r)) + "_L"
sele cursor_personal
sele recn() as rec_no,* from cursor_personal ;
where 天数 < lnMaxWorkDays ;
and !已排 ;
order by 天数 ;
into cursor temp
llFound = iif(_tally>0,.T.,.F.)
If llFound
sele cursor_personal
goto temp.rec_no
repl 已排 with .T.
repl 天数 with 天数 + 1
repl 连续 with 连续 + 1
lcCurName = allt(姓名)
sele cursor_works
repl &lcFieldName with lcCurName
sele cursor_personal
sele cursor_personal
if 连续 >= nWeekDays or 休息 >= lnFreeDays
repl 连续 with 0
repl 休息 with 0
endif
Endif
Endfor
*-- 送货员排班结束 =====================================================
Endfor
sele cursor_works
go top
brow nowait
说明:程序中的ShowProcessBar()和Showbar()是用来显示进度条的,如果没有,可以注释掉!