高级排程
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

  1. package service
  2. import (
  3. "LAPP_AS/common"
  4. base_model "LAPP_AS/models/base"
  5. "LAPP_AS/utils"
  6. "errors"
  7. "fmt"
  8. "strconv"
  9. "time"
  10. )
  11. // 工位类型资源对象
  12. type WorkPlaceSrv struct{
  13. WorkPlaceId string
  14. WorkPlaceGrpId string // 工位组对象
  15. Wptab base_model.WorkPlace
  16. Status int // 工位可用状态默认不可用,通过时间模型的加载变为可用
  17. TimeCurve TimeCurveSrv // 加载完时间模型后的时间曲线
  18. UnTimeCurve TimeCurveSrv // 加载不可用时间模型后的时间曲线
  19. SchedTimeCurve TimeCurveSrv // 调度过程中动态计算的时间曲线
  20. WaitTaskArray []SchedTaskSrv // 任务等待队列
  21. SchedTaskArray []OperationSrv // 已计划任务队列
  22. DayModelArray []DayModelSrv
  23. DayModelIdxDict map[string]int
  24. WorkShiftEffDict map[string]base_model.WorkShiftEffLst // 产线排班表
  25. WorkShiftArray []WorkShiftSrv // 产线班次列表
  26. }
  27. // 可选工位资源对象
  28. type OptionalWorkPlaceSrv struct{
  29. WorkPlaceId string
  30. Priority int
  31. }
  32. // 初始化对象
  33. func(wps *WorkPlaceSrv)Init(wpid, wpgid string){
  34. wps.WorkPlaceId = wpid
  35. wps.WorkPlaceGrpId = wpgid
  36. wps.Status = common.RES_STATUS_UNAVAIL
  37. wps.TimeCurve = TimeCurveSrv{}
  38. wps.SchedTimeCurve = TimeCurveSrv{}
  39. wps.WaitTaskArray = []SchedTaskSrv{}
  40. wps.SchedTaskArray = []OperationSrv{}
  41. }
  42. // 初始化对象
  43. func(wps *WorkPlaceSrv)Create(wptab base_model.WorkPlace){
  44. wps.WorkPlaceId = wptab.WorkPlaceId
  45. wps.WorkPlaceGrpId = wptab.WorkPlaceGrpId
  46. wps.Wptab = wptab
  47. wps.Status = common.RES_STATUS_UNAVAIL
  48. wps.TimeCurve = TimeCurveSrv{}
  49. wps.SchedTimeCurve = TimeCurveSrv{}
  50. wps.WaitTaskArray = []SchedTaskSrv{}
  51. wps.SchedTaskArray = []OperationSrv{}
  52. }
  53. // 获取工位状态可用事件
  54. func(wps *WorkPlaceSrv)GetAvailEvent(t time.Time)(SchedEvent){
  55. var(
  56. wpet WorkPlaceEvent
  57. )
  58. wpet = WorkPlaceEvent{TriggerTime: t, EventType: EVENT_OBJ_WP, Event: EVENT_WP_STATUS_AVAIL}
  59. wpet.WorkPlaceId = wps.WorkPlaceId
  60. return SchedEvent(wpet)
  61. }
  62. // 获取工位状态可用事件
  63. func(wps *WorkPlaceSrv)GetUnAvailEvent(t time.Time)(SchedEvent){
  64. var(
  65. wpet WorkPlaceEvent
  66. )
  67. wpet = WorkPlaceEvent{TriggerTime: t, EventType: EVENT_OBJ_WP, Event: EVENT_WP_STATUS_UNAVAIL}
  68. wpet.WorkPlaceId = wps.WorkPlaceId
  69. return SchedEvent(wpet)
  70. }
  71. // 打印工位的调度任务结果集
  72. func(wps *WorkPlaceSrv)Print(){
  73. fmt.Println("调度工位:",wps.WorkPlaceId)
  74. for idx, op := range wps.SchedTaskArray{
  75. if idx == 0 {
  76. fmt.Printf("|%s<--%s(%d)-->%s|",op.PlanStartTime.Format("01-02 15:04"),op.OrderId,op.OperationNr,op.PlanEndTime.Format("01-02 15:04"))
  77. }else{
  78. fmt.Printf("%s<--%s(%d)-->%s|",op.PlanStartTime.Format("01-02 15:04"),op.OrderId,op.OperationNr,op.PlanEndTime.Format("01-02 15:04"))
  79. }
  80. }
  81. fmt.Printf("\n")
  82. }
  83. // 基于产线指定的周模型和工厂日历获取在指定时间范畴内的日模型列表
  84. func (wlsrv *WorkPlaceSrv) GetWorkDayList(tmsrv *TimeModelSrv) (err error) {
  85. var (
  86. dmsrv DayModelSrv
  87. wmsrv WeekModelSrv
  88. calsrv CalendarSrv
  89. i, idx, daymodelnr, days int
  90. ok bool
  91. )
  92. // 初始化
  93. wlsrv.DayModelArray = []DayModelSrv{}
  94. wlsrv.DayModelIdxDict = make(map[string]int)
  95. // 获取产线的周模型
  96. if wmsrv, ok = tmsrv.WeekModelDict[wlsrv.Wptab.WeekModelNr]; !ok {
  97. err = errors.New(fmt.Sprintf("产线%s的周模型%d不存在!", wlsrv.Wptab.WorkPlaceId, wlsrv.Wptab.WeekModelNr))
  98. return
  99. }
  100. // 获取产线的工作日历
  101. if calsrv, ok = tmsrv.CalendarDict[wlsrv.Wptab.WorkCalendarNr]; !ok {
  102. err = errors.New(fmt.Sprintf("产线%s的工作日历%d不存在!", wlsrv.Wptab.WorkPlaceId, wlsrv.Wptab.WorkCalendarNr))
  103. return
  104. }
  105. // 基于时间模型的起始时间点获取产线的日模型列表
  106. days = utils.GetCrossDays(tmsrv.StartDate, tmsrv.EndDate)
  107. for i = 0; i < days; i++ {
  108. tt := tmsrv.StartDate.Add(time.Duration(i*24) * time.Hour)
  109. daymodelnr = wmsrv.GetDayModelNrByDate(tt)
  110. if dmsrv, ok = tmsrv.DayModelDict[daymodelnr]; !ok {
  111. err = errors.New(fmt.Sprintf("周模型%d中指定的日模型%d不存在!", wmsrv.WeekModelNr, daymodelnr))
  112. return
  113. } else {
  114. dmsrv.StartTime = tt
  115. dmsrv.EndTime = tt.Add(24 * time.Hour)
  116. wlsrv.DayModelArray = append(wlsrv.DayModelArray, dmsrv)
  117. wlsrv.DayModelIdxDict[utils.GetYMDString(tt)] = i
  118. }
  119. }
  120. // 将产线工作日历指定的特殊日模型进行替换
  121. for i = 0; i < len(calsrv.WorkCalTab.WorkCalendarLstLi); i++ {
  122. WorkDate := calsrv.WorkCalTab.WorkCalendarLstLi[i].WorkDate
  123. if idx, ok = wlsrv.DayModelIdxDict[WorkDate]; ok {
  124. daymodelnr = calsrv.WorkCalTab.WorkCalendarLstLi[i].DayModelNr
  125. if dmsrv, ok = tmsrv.DayModelDict[daymodelnr]; !ok {
  126. err = errors.New(fmt.Sprintf("工作日历%d中在工作日%v指定的日模型%d不存在!", calsrv.CalendarNr, calsrv.WorkCalTab.WorkCalendarLstLi[i].WorkDate, daymodelnr))
  127. return
  128. } else {
  129. wlsrv.DayModelArray[idx] = dmsrv
  130. }
  131. }
  132. }
  133. return
  134. }
  135. // 基于产线指定的周模型和工厂日历生成时间曲线
  136. // 获取产线的班次列表,基于日模型关联的人工班次和班次出勤
  137. func (wlsrv *WorkPlaceSrv) GenerateTimeCurve(tmsrv *TimeModelSrv) {
  138. var (
  139. i, j int
  140. tlsrv TimeLineSrv
  141. dayStartTime time.Time
  142. dayEndTime time.Time
  143. nextStartTime time.Time
  144. day string
  145. )
  146. // 初始化
  147. wlsrv.SchedTimeCurve = TimeCurveSrv{}
  148. wlsrv.TimeCurve = TimeCurveSrv{}
  149. wlsrv.UnTimeCurve = TimeCurveSrv{}
  150. wlsrv.TimeCurve.TimeLineArray = []TimeLineSrv{}
  151. wlsrv.TimeCurve.StartTime = tmsrv.StartDate
  152. wlsrv.TimeCurve.EndTime = tmsrv.EndDate
  153. wlsrv.UnTimeCurve.StartTime = tmsrv.StartDate
  154. wlsrv.UnTimeCurve.EndTime = tmsrv.EndDate
  155. // 遍历日模型
  156. for i = 0; i < len(wlsrv.DayModelArray); i++ {
  157. dd, _ := time.ParseDuration(strconv.Itoa(i*24) + "h")
  158. dayStartTime = wlsrv.TimeCurve.StartTime.Add(dd)
  159. // 遍历日模型的每一条线段
  160. for j = 0; j < len(wlsrv.DayModelArray[i].LineArray); j++ {
  161. tlsrv = TimeLineSrv{}
  162. tlsrv.StartTime = dayStartTime.Add(time.Duration(wlsrv.DayModelArray[i].LineArray[j].StartSecond) * time.Second)
  163. tlsrv.EndTime = dayStartTime.Add(time.Duration(wlsrv.DayModelArray[i].LineArray[j].EndSecond) * time.Second)
  164. tlsrv.EffFactor = 1.0
  165. // 如果是人员班组产线,则基于计划出勤数据决定该时间段的效率因子
  166. if wlsrv.DayModelArray[i].DayModelTab.WorkShiftToggle {
  167. day = utils.GetYMDString(dayStartTime)
  168. tlsrv.EffFactor = float64(wlsrv.GetWorkShiftEff(day, wlsrv.DayModelArray[i].LineArray[j].WorkShiftNr, tmsrv))
  169. }
  170. tlsrv.Duration = tlsrv.GetDuration()
  171. wlsrv.TimeCurve.TimeLineArray = append(wlsrv.TimeCurve.TimeLineArray, tlsrv)
  172. }
  173. }
  174. //根据不可用时间推算出可用时间
  175. for i = 0; i < len(wlsrv.DayModelArray); i++ {
  176. dd, _ := time.ParseDuration(strconv.Itoa(i*24) + "h")
  177. dayStartTime = wlsrv.TimeCurve.StartTime.Add(dd)
  178. daydd, _ := time.ParseDuration("24h")
  179. dayEndTime = dayStartTime.Add(daydd)
  180. lenDay := len(wlsrv.DayModelArray[i].LineArray)
  181. nextStartTime = dayStartTime
  182. // 遍历日模型的每一条线段
  183. for j = 0; j <= lenDay; j++ {
  184. tlsrv = TimeLineSrv{}
  185. tlsrv.StartTime = nextStartTime
  186. if j == lenDay{
  187. tlsrv.EndTime = dayEndTime
  188. }else{
  189. tlsrv.EndTime = dayStartTime.Add(time.Duration(wlsrv.DayModelArray[i].LineArray[j].StartSecond) * time.Second)
  190. nextStartTime = dayStartTime.Add(time.Duration(wlsrv.DayModelArray[i].LineArray[j].EndSecond) * time.Second)
  191. }
  192. tlsrv.EffFactor = 1.0
  193. // 如果是人员班组产线,则基于计划出勤数据决定该时间段的效率因子
  194. if wlsrv.DayModelArray[i].DayModelTab.WorkShiftToggle {
  195. day = utils.GetYMDString(dayStartTime)
  196. tlsrv.EffFactor = float64(wlsrv.GetWorkShiftEff(day, wlsrv.DayModelArray[i].LineArray[j].WorkShiftNr, tmsrv))
  197. }
  198. tlsrv.Duration = tlsrv.GetDuration()
  199. wlsrv.UnTimeCurve.TimeLineArray = append(wlsrv.UnTimeCurve.TimeLineArray, tlsrv)
  200. }
  201. }
  202. //赋值
  203. wlsrv.SchedTimeCurve = wlsrv.TimeCurve
  204. // 获取产线的时间链表
  205. wlsrv.TimeCurve.GetLineList()
  206. wlsrv.SchedTimeCurve.GetLineList()
  207. wlsrv.UnTimeCurve.GetLineList()
  208. }
  209. // 基于产线排班信息获取指定日期和班次的班次效率,如果不存在则返回班次标准效率1.0
  210. func (wlsrv *WorkPlaceSrv) GetWorkShiftEff(day string, wsnr int, tmsrv *TimeModelSrv) (eff float64) {
  211. var (
  212. key string
  213. ok bool
  214. perqty int
  215. wlwsefftab base_model.WorkShiftEffLst
  216. wss WorkShiftSrv
  217. )
  218. eff = 1.0
  219. // 获取人员班组对象
  220. if wss, ok = tmsrv.WorkShiftDict[wsnr]; !ok {
  221. fmt.Println("指定人员班组:", wsnr, " 不存在!")
  222. return
  223. }
  224. key = day + strconv.Itoa(wsnr)
  225. if wlwsefftab, ok = wlsrv.WorkShiftEffDict[key]; ok {
  226. // 获取指定日期和人员班组号的排班人数 todo
  227. perqty = wlwsefftab.PlanPersonUclQty
  228. // 比较人数,获取效率值
  229. eff = wss.GetEffByPersonQty(perqty)
  230. return
  231. }
  232. return
  233. }