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.
 

309 lines
9.6 KiB

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
}