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 }