高级排程
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
8.8 KiB

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
}