package schedule
|
|
|
|
import (
|
|
"container/list"
|
|
"errors"
|
|
"fmt"
|
|
"leit.com/LAPP_GAAS_GFrame/models"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
type WorklineSrv struct {
|
|
PlantNr int
|
|
WorklineId string
|
|
WorklineTab models.Workline
|
|
RelCtrlWay string
|
|
RelCtrlQty int // 下达控制数量
|
|
RelCtrlDura time.Duration // 下达控制时长,基于交货时间和计划结束时间的差值计算
|
|
DayModelArray []DayModelSrv
|
|
DayModelIdxDict map[string]int
|
|
SchedTaskList *list.List
|
|
SchedTaskArray []TaskSrv // 所有调度到当前产线的生产任务
|
|
TimeCurve TimeCurveSrv // 加载完时间模型后的时间曲线
|
|
SchedTimeCurve TimeCurveSrv // 调度过程中动态计算的时间曲线
|
|
WorkShiftEffDict map[string]models.Worklineworkshiftlst // 产线排班表
|
|
WorkShiftArray []WorkShiftSrv // 产线班次列表
|
|
WorkLoadArray []WorkLoadSrv // 产线负载
|
|
}
|
|
|
|
// 初始化产线对象
|
|
func(wlsrv *WorklineSrv)Init(wltab models.Workline){
|
|
wlsrv.PlantNr = wltab.Plantnr
|
|
wlsrv.WorklineId = wltab.Worklineid
|
|
wlsrv.WorklineTab = wltab
|
|
wlsrv.DayModelArray = []DayModelSrv{}
|
|
wlsrv.DayModelIdxDict = make(map[string]int)
|
|
wlsrv.WorkShiftEffDict = make(map[string]models.Worklineworkshiftlst)
|
|
wlsrv.SchedTaskArray = []TaskSrv{}
|
|
wlsrv.SchedTaskList = list.New()
|
|
wlsrv.TimeCurve = TimeCurveSrv{}
|
|
wlsrv.SchedTimeCurve = TimeCurveSrv{}
|
|
wlsrv.WorkShiftArray = []WorkShiftSrv{}
|
|
wlsrv.WorkLoadArray = []WorkLoadSrv{}
|
|
}
|
|
|
|
// 加载指定时段内的排班表:班次计划出勤数据
|
|
func(wlsrv *WorklineSrv)LoadWorkShiftData(startdate, enddate time.Time)(err error){
|
|
var(
|
|
i int
|
|
key, st,et string
|
|
wlwstab models.Worklineworkshiftlst
|
|
wlwstablst []models.Worklineworkshiftlst
|
|
)
|
|
st = GetYMDString(startdate)
|
|
et = GetYMDString(enddate)
|
|
// 初始化
|
|
wlsrv.WorkShiftEffDict = make(map[string]models.Worklineworkshiftlst)
|
|
// 加载指定日期范围内的产线排班数据
|
|
wlwstab = models.Worklineworkshiftlst{Plantnr: wlsrv.PlantNr}
|
|
if wlwstablst, err = wlwstab.GetWorkLineWorkShiftData(wlsrv.WorklineId, st, et); err != nil {
|
|
err = errors.New(fmt.Sprintf("无法获取产线%s的排班数据%v!",wlsrv.WorklineId, err))
|
|
return
|
|
}
|
|
for i = 0; i < len(wlwstablst); i++ {
|
|
key = wlwstablst[i].Workday + strconv.Itoa(wlwstablst[i].Workshiftnr)
|
|
wlsrv.WorkShiftEffDict[key] = wlwstablst[i]
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// 将任务数组转化成列表
|
|
func(wlsrv *WorklineSrv)GetLineTaskList(){
|
|
var(
|
|
task TaskSrv
|
|
)
|
|
|
|
// 初始化
|
|
wlsrv.SchedTaskList = list.New()
|
|
for _, task = range wlsrv.SchedTaskArray {
|
|
wlsrv.SchedTaskList.PushBack(&task)
|
|
}
|
|
}
|
|
|
|
// 将任务列表转化成数组
|
|
func(wlsrv *WorklineSrv)GetLineTaskArray(){
|
|
var(
|
|
e *list.Element
|
|
task *TaskSrv
|
|
)
|
|
|
|
// 初始化数组
|
|
wlsrv.SchedTaskArray = []TaskSrv{}
|
|
for e = wlsrv.SchedTaskList.Front(); e != nil; e = e.Next() {
|
|
task = e.Value.(*TaskSrv)
|
|
wlsrv.SchedTaskArray = append(wlsrv.SchedTaskArray, *task)
|
|
}
|
|
}
|
|
|
|
// 基于产线指定的周模型和工厂日历获取在指定时间范畴内的日模型列表
|
|
func(wlsrv *WorklineSrv)GetWorkDayList(tmsrv *TimeModelSrv)(err error){
|
|
var(
|
|
dmsrv DayModelSrv
|
|
wmsrv WeekModelSrv
|
|
calsrv CalendarSrv
|
|
i,idx,daymodelnr,days int
|
|
ok bool
|
|
)
|
|
|
|
// 初始化
|
|
wlsrv.DayModelArray = []DayModelSrv{}
|
|
wlsrv.DayModelIdxDict = make(map[string]int)
|
|
// 获取产线的周模型
|
|
if wmsrv, ok = tmsrv.WeekModelDict[wlsrv.WorklineTab.Weekmodelnr]; !ok {
|
|
err = errors.New(fmt.Sprintf("产线%s的周模型%d不存在!",wlsrv.WorklineTab.Worklineid,wlsrv.WorklineTab.Weekmodelnr))
|
|
return
|
|
}
|
|
// 获取产线的工作日历
|
|
if calsrv, ok = tmsrv.CalendarDict[wlsrv.WorklineTab.Workcalendarnr]; !ok {
|
|
err = errors.New(fmt.Sprintf("产线%s的工作日历%d不存在!",wlsrv.WorklineTab.Worklineid,wlsrv.WorklineTab.Workcalendarnr))
|
|
return
|
|
}
|
|
// 基于时间模型的起始时间点获取产线的日模型列表
|
|
days = GetCrossDays(tmsrv.StartDate, tmsrv.EndDate)
|
|
for i = 0 ; i < days; i++ {
|
|
tt := tmsrv.StartDate.Add(time.Duration(i*24)*time.Hour)
|
|
daymodelnr = wmsrv.GetDayModelNrByDate(tt)
|
|
if dmsrv, ok = tmsrv.DayModelDict[daymodelnr]; !ok{
|
|
err = errors.New(fmt.Sprintf("周模型%d中指定的日模型%d不存在!",wmsrv.WeekModelNr,daymodelnr))
|
|
return
|
|
}else{
|
|
dmsrv.StartTime = tt
|
|
dmsrv.EndTime = tt.Add(24*time.Hour)
|
|
wlsrv.DayModelArray = append(wlsrv.DayModelArray, dmsrv)
|
|
wlsrv.DayModelIdxDict[GetYMDString(tt)] = i
|
|
}
|
|
}
|
|
// 将产线工作日历指定的特殊日模型进行替换
|
|
for i = 0; i < len(calsrv.WorkCalTab.Itemlst); i++ {
|
|
if idx, ok = wlsrv.DayModelIdxDict[calsrv.WorkCalTab.Itemlst[i].Workdate]; ok{
|
|
daymodelnr = calsrv.WorkCalTab.Itemlst[i].Daymodelnr
|
|
if dmsrv, ok = tmsrv.DayModelDict[daymodelnr]; !ok{
|
|
err = errors.New(fmt.Sprintf("工作日历%d中在工作日%d指定的日模型%d不存在!",calsrv.CalendarNr,calsrv.WorkCalTab.Itemlst[i].Workdate,daymodelnr))
|
|
return
|
|
}else{
|
|
wlsrv.DayModelArray[idx] = dmsrv
|
|
}
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// 基于产线指定的周模型和工厂日历生成时间曲线
|
|
// 获取产线的班次列表,基于日模型关联的人工班次和班次出勤
|
|
func(wlsrv *WorklineSrv)GenerateTimeCurve(tmsrv *TimeModelSrv){
|
|
var(
|
|
i,j int
|
|
tlsrv TimeLineSrv
|
|
dayStartTime time.Time
|
|
day string
|
|
)
|
|
|
|
// 初始化
|
|
wlsrv.TimeCurve = TimeCurveSrv{}
|
|
wlsrv.TimeCurve.TimeLineArray = []TimeLineSrv{}
|
|
wlsrv.TimeCurve.StartTime = tmsrv.StartDate
|
|
wlsrv.TimeCurve.EndTime = tmsrv.EndDate
|
|
// 遍历日模型
|
|
for i = 0; i < len(wlsrv.DayModelArray); i++ {
|
|
dd, _ := time.ParseDuration(strconv.Itoa(i*24)+"h")
|
|
dayStartTime = wlsrv.TimeCurve.StartTime.Add(dd)
|
|
// 遍历日模型的每一条线段
|
|
for j = 0; j < len(wlsrv.DayModelArray[i].LineArray); j++ {
|
|
tlsrv = TimeLineSrv{}
|
|
tlsrv.StartTime = dayStartTime.Add(time.Duration(wlsrv.DayModelArray[i].LineArray[j].StartSecond)*time.Second)
|
|
tlsrv.EndTime = dayStartTime.Add(time.Duration(wlsrv.DayModelArray[i].LineArray[j].EndSecond)*time.Second)
|
|
tlsrv.EffFactor = 1.0
|
|
// 如果是人员班组产线,则基于计划出勤数据决定该时间段的效率因子
|
|
if wlsrv.DayModelArray[i].DayModelTab.Workshifttoggle > 0 {
|
|
day = GetYMDString(dayStartTime)
|
|
tlsrv.EffFactor = float64(wlsrv.GetWorkShiftEff(day, wlsrv.DayModelArray[i].LineArray[j].WorkShiftNr, tmsrv))
|
|
}
|
|
tlsrv.GetDuration()
|
|
wlsrv.TimeCurve.TimeLineArray = append(wlsrv.TimeCurve.TimeLineArray, tlsrv)
|
|
}
|
|
}
|
|
// 获取产线的时间链表
|
|
wlsrv.TimeCurve.GetLineList()
|
|
}
|
|
|
|
// 计算产线的日产能负荷
|
|
func(wlsrv *WorklineSrv)CalDailyWorkload(){
|
|
var (
|
|
i,crossDays int
|
|
y1,d1 int
|
|
m1 time.Month
|
|
startTime,t1,t2 time.Time
|
|
wloadsrv WorkLoadSrv
|
|
)
|
|
|
|
// 初始化
|
|
wlsrv.WorkLoadArray = []WorkLoadSrv{}
|
|
|
|
// 基于指定的时间区间按天遍历
|
|
crossDays = GetCrossDays(wlsrv.TimeCurve.StartTime, wlsrv.TimeCurve.EndTime)
|
|
y1,m1,d1 = wlsrv.TimeCurve.StartTime.Date()
|
|
startTime = time.Date(y1, m1, d1, 0, 0, 0, 0, time.UTC)
|
|
for i = 0; i < crossDays; i++ {
|
|
t1 = startTime.Add(time.Duration(i*24)*time.Hour)
|
|
t2 = t1.Add(24*time.Hour)
|
|
wloadsrv = WorkLoadSrv{}
|
|
wloadsrv.LoadType = WorkLoadType_Daily
|
|
wloadsrv.StartTime = t1
|
|
wloadsrv.EndTime = t2
|
|
wloadsrv.AvailCapacity = wlsrv.TimeCurve.CalDuration(t1, t2)
|
|
wloadsrv.RestCapacity = wlsrv.SchedTimeCurve.CalDuration(t1, t2)
|
|
wloadsrv.Init()
|
|
wlsrv.WorkLoadArray = append(wlsrv.WorkLoadArray, wloadsrv)
|
|
}
|
|
}
|
|
|
|
// 计算产线的班产能负荷
|
|
func(wlsrv *WorklineSrv)CalShifWorkload(){
|
|
var (
|
|
i int
|
|
t1,t2 time.Time
|
|
wloadsrv WorkLoadSrv
|
|
)
|
|
|
|
// 初始化
|
|
wlsrv.WorkLoadArray = []WorkLoadSrv{}
|
|
|
|
// 遍历产线班次
|
|
for i = 0; i < len(wlsrv.WorkShiftArray); i++ {
|
|
t1 = wlsrv.WorkShiftArray[i].StartTime
|
|
t2 = wlsrv.WorkShiftArray[i].EndTime
|
|
wloadsrv = WorkLoadSrv{}
|
|
wloadsrv.LoadType = WorkLoadType_Daily
|
|
wloadsrv.StartTime = t1
|
|
wloadsrv.EndTime = t2
|
|
wloadsrv.AvailCapacity = wlsrv.TimeCurve.CalDuration(t1, t2)
|
|
wloadsrv.RestCapacity = wlsrv.SchedTimeCurve.CalDuration(t1, t2)
|
|
wloadsrv.Init()
|
|
wlsrv.WorkLoadArray = append(wlsrv.WorkLoadArray, wloadsrv)
|
|
}
|
|
}
|
|
|
|
// 计算产线的小时产能负荷
|
|
func(wlsrv *WorklineSrv)CalHourlyWorkload(){
|
|
var (
|
|
i,j,crossDays int
|
|
y1,d1 int
|
|
m1 time.Month
|
|
startTime,t1,t2 time.Time
|
|
wloadsrv WorkLoadSrv
|
|
)
|
|
|
|
// 初始化
|
|
wlsrv.WorkLoadArray = []WorkLoadSrv{}
|
|
|
|
// 基于指定的时间区间按天遍历
|
|
crossDays = GetCrossDays(wlsrv.TimeCurve.StartTime, wlsrv.TimeCurve.EndTime)
|
|
y1,m1,d1 = wlsrv.TimeCurve.StartTime.Date()
|
|
startTime = time.Date(y1, m1, d1, 0, 0, 0, 0, time.UTC)
|
|
for i = 0; i < crossDays; i++ {
|
|
for j = 0; j < 24; j++ {
|
|
t1 = startTime.Add(time.Duration(i*24+j)*time.Hour)
|
|
t2 = t1.Add(1*time.Hour)
|
|
wloadsrv = WorkLoadSrv{}
|
|
wloadsrv.LoadType = WorkLoadType_Hourly
|
|
wloadsrv.StartTime = t1
|
|
wloadsrv.EndTime = t2
|
|
wloadsrv.AvailCapacity = wlsrv.TimeCurve.CalDuration(t1, t2)
|
|
wloadsrv.RestCapacity = wlsrv.SchedTimeCurve.CalDuration(t1, t2)
|
|
wloadsrv.Init()
|
|
wlsrv.WorkLoadArray = append(wlsrv.WorkLoadArray, wloadsrv)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 基于产线排班信息获取指定日期和班次的班次效率,如果不存在则返回班次标准效率1.0
|
|
func(wlsrv *WorklineSrv)GetWorkShiftEff(day string, wsnr int, tmsrv *TimeModelSrv)(eff float32){
|
|
var (
|
|
key string
|
|
ok bool
|
|
perqty int
|
|
wlwsefftab models.Worklineworkshiftlst
|
|
wss WorkShiftSrv
|
|
)
|
|
|
|
eff = 1.0
|
|
// 获取人员班组对象
|
|
if wss, ok = tmsrv.WorkShiftDict[wsnr]; !ok {
|
|
fmt.Println("指定人员班组:",wsnr," 不存在!")
|
|
return
|
|
}
|
|
key = day + strconv.Itoa(wsnr)
|
|
if wlwsefftab, ok = wlsrv.WorkShiftEffDict[key]; ok {
|
|
// 获取指定日期和人员班组号的排班人数
|
|
perqty = wlwsefftab.Personqty
|
|
// 比较人数,获取效率值
|
|
eff = wss.GetEffByPersonQty(perqty)
|
|
return
|
|
}
|
|
return
|
|
}
|
|
|
|
|