package service import ( "LAPP_AS/common" base_model "LAPP_AS/models/base" "LAPP_AS/utils" "errors" "fmt" "strconv" "time" ) // 工位类型资源对象 type WorkPlaceSrv struct{ WorkPlaceId string WorkPlaceGrpId string // 工位组对象 Wptab base_model.WorkPlace Status int // 工位可用状态默认不可用,通过时间模型的加载变为可用 TimeCurve TimeCurveSrv // 加载完时间模型后的时间曲线 UnTimeCurve TimeCurveSrv // 加载不可用时间模型后的时间曲线 SchedTimeCurve TimeCurveSrv // 调度过程中动态计算的时间曲线 WaitTaskArray []SchedTaskSrv // 任务等待队列 SchedTaskArray []OperationSrv // 已计划任务队列 DayModelArray []DayModelSrv DayModelIdxDict map[string]int WorkShiftEffDict map[string]base_model.WorkShiftEffLst // 产线排班表 WorkShiftArray []WorkShiftSrv // 产线班次列表 } // 可选工位资源对象 type OptionalWorkPlaceSrv struct{ WorkPlaceId string Priority int } // 初始化对象 func(wps *WorkPlaceSrv)Init(wpid, wpgid string){ wps.WorkPlaceId = wpid wps.WorkPlaceGrpId = wpgid wps.Status = common.RES_STATUS_UNAVAIL wps.TimeCurve = TimeCurveSrv{} wps.SchedTimeCurve = TimeCurveSrv{} wps.WaitTaskArray = []SchedTaskSrv{} wps.SchedTaskArray = []OperationSrv{} } // 初始化对象 func(wps *WorkPlaceSrv)Create(wptab base_model.WorkPlace){ wps.WorkPlaceId = wptab.WorkPlaceId wps.WorkPlaceGrpId = wptab.WorkPlaceGrpId wps.Wptab = wptab wps.Status = common.RES_STATUS_UNAVAIL wps.TimeCurve = TimeCurveSrv{} wps.SchedTimeCurve = TimeCurveSrv{} wps.WaitTaskArray = []SchedTaskSrv{} wps.SchedTaskArray = []OperationSrv{} } // 获取工位状态可用事件 func(wps *WorkPlaceSrv)GetAvailEvent(t time.Time)(SchedEvent){ var( wpet WorkPlaceEvent ) wpet = WorkPlaceEvent{TriggerTime: t, EventType: EVENT_OBJ_WP, Event: EVENT_WP_STATUS_AVAIL} wpet.WorkPlaceId = wps.WorkPlaceId return SchedEvent(wpet) } // 获取工位状态可用事件 func(wps *WorkPlaceSrv)GetUnAvailEvent(t time.Time)(SchedEvent){ var( wpet WorkPlaceEvent ) wpet = WorkPlaceEvent{TriggerTime: t, EventType: EVENT_OBJ_WP, Event: EVENT_WP_STATUS_UNAVAIL} wpet.WorkPlaceId = wps.WorkPlaceId return SchedEvent(wpet) } // 打印工位的调度任务结果集 func(wps *WorkPlaceSrv)Print(){ fmt.Println("调度工位:",wps.WorkPlaceId) for idx, op := range wps.SchedTaskArray{ if idx == 0 { fmt.Printf("|%s<--%s(%d)-->%s|",op.PlanStartTime.Format("01-02 15:04"),op.OrderId,op.OperationNr,op.PlanEndTime.Format("01-02 15:04")) }else{ fmt.Printf("%s<--%s(%d)-->%s|",op.PlanStartTime.Format("01-02 15:04"),op.OrderId,op.OperationNr,op.PlanEndTime.Format("01-02 15:04")) } } fmt.Printf("\n") } // 基于产线指定的周模型和工厂日历获取在指定时间范畴内的日模型列表 func (wlsrv *WorkPlaceSrv) 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.Wptab.WeekModelNr]; !ok { err = errors.New(fmt.Sprintf("产线%s的周模型%d不存在!", wlsrv.Wptab.WorkPlaceId, wlsrv.Wptab.WeekModelNr)) return } // 获取产线的工作日历 if calsrv, ok = tmsrv.CalendarDict[wlsrv.Wptab.WorkCalendarNr]; !ok { err = errors.New(fmt.Sprintf("产线%s的工作日历%d不存在!", wlsrv.Wptab.WorkPlaceId, wlsrv.Wptab.WorkCalendarNr)) return } // 基于时间模型的起始时间点获取产线的日模型列表 days = utils.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[utils.GetYMDString(tt)] = i } } // 将产线工作日历指定的特殊日模型进行替换 for i = 0; i < len(calsrv.WorkCalTab.WorkCalendarLstLi); i++ { WorkDate := calsrv.WorkCalTab.WorkCalendarLstLi[i].WorkDate if idx, ok = wlsrv.DayModelIdxDict[WorkDate]; ok { daymodelnr = calsrv.WorkCalTab.WorkCalendarLstLi[i].DayModelNr if dmsrv, ok = tmsrv.DayModelDict[daymodelnr]; !ok { err = errors.New(fmt.Sprintf("工作日历%d中在工作日%v指定的日模型%d不存在!", calsrv.CalendarNr, calsrv.WorkCalTab.WorkCalendarLstLi[i].WorkDate, daymodelnr)) return } else { wlsrv.DayModelArray[idx] = dmsrv } } } return } // 基于产线指定的周模型和工厂日历生成时间曲线 // 获取产线的班次列表,基于日模型关联的人工班次和班次出勤 func (wlsrv *WorkPlaceSrv) GenerateTimeCurve(tmsrv *TimeModelSrv) { var ( i, j int tlsrv TimeLineSrv dayStartTime time.Time dayEndTime time.Time nextStartTime time.Time day string ) // 初始化 wlsrv.SchedTimeCurve = TimeCurveSrv{} wlsrv.TimeCurve = TimeCurveSrv{} wlsrv.UnTimeCurve = TimeCurveSrv{} wlsrv.TimeCurve.TimeLineArray = []TimeLineSrv{} wlsrv.TimeCurve.StartTime = tmsrv.StartDate wlsrv.TimeCurve.EndTime = tmsrv.EndDate wlsrv.UnTimeCurve.StartTime = tmsrv.StartDate wlsrv.UnTimeCurve.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 { day = utils.GetYMDString(dayStartTime) tlsrv.EffFactor = float64(wlsrv.GetWorkShiftEff(day, wlsrv.DayModelArray[i].LineArray[j].WorkShiftNr, tmsrv)) } tlsrv.Duration = tlsrv.GetDuration() wlsrv.TimeCurve.TimeLineArray = append(wlsrv.TimeCurve.TimeLineArray, tlsrv) } } //根据不可用时间推算出可用时间 for i = 0; i < len(wlsrv.DayModelArray); i++ { dd, _ := time.ParseDuration(strconv.Itoa(i*24) + "h") dayStartTime = wlsrv.TimeCurve.StartTime.Add(dd) daydd, _ := time.ParseDuration("24h") dayEndTime = dayStartTime.Add(daydd) lenDay := len(wlsrv.DayModelArray[i].LineArray) nextStartTime = dayStartTime // 遍历日模型的每一条线段 for j = 0; j <= lenDay; j++ { tlsrv = TimeLineSrv{} tlsrv.StartTime = nextStartTime if j == lenDay{ tlsrv.EndTime = dayEndTime }else{ tlsrv.EndTime = dayStartTime.Add(time.Duration(wlsrv.DayModelArray[i].LineArray[j].StartSecond) * time.Second) nextStartTime = dayStartTime.Add(time.Duration(wlsrv.DayModelArray[i].LineArray[j].EndSecond) * time.Second) } tlsrv.EffFactor = 1.0 // 如果是人员班组产线,则基于计划出勤数据决定该时间段的效率因子 if wlsrv.DayModelArray[i].DayModelTab.WorkShiftToggle { day = utils.GetYMDString(dayStartTime) tlsrv.EffFactor = float64(wlsrv.GetWorkShiftEff(day, wlsrv.DayModelArray[i].LineArray[j].WorkShiftNr, tmsrv)) } tlsrv.Duration = tlsrv.GetDuration() wlsrv.UnTimeCurve.TimeLineArray = append(wlsrv.UnTimeCurve.TimeLineArray, tlsrv) } } //赋值 wlsrv.SchedTimeCurve = wlsrv.TimeCurve // 获取产线的时间链表 wlsrv.TimeCurve.GetLineList() wlsrv.SchedTimeCurve.GetLineList() wlsrv.UnTimeCurve.GetLineList() } // 基于产线排班信息获取指定日期和班次的班次效率,如果不存在则返回班次标准效率1.0 func (wlsrv *WorkPlaceSrv) GetWorkShiftEff(day string, wsnr int, tmsrv *TimeModelSrv) (eff float64) { var ( key string ok bool perqty int wlwsefftab base_model.WorkShiftEffLst 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 { // 获取指定日期和人员班组号的排班人数 todo perqty = wlwsefftab.PlanPersonUclQty // 比较人数,获取效率值 eff = wss.GetEffByPersonQty(perqty) return } return }