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

1171 lines
35 KiB

package service
import (
"LAPP_AS/common"
base_dal "LAPP_AS/dao/base"
me_dal "LAPP_AS/dao/me"
om_dal "LAPP_AS/dao/om"
wm_dal "LAPP_AS/dao/wm"
"LAPP_AS/db"
meta "LAPP_AS/meta/om"
base_model "LAPP_AS/models/base"
me_model "LAPP_AS/models/me"
om_model "LAPP_AS/models/om"
wm_model "LAPP_AS/models/wm"
"fmt"
"github.com/pkg/errors"
"time"
)
/**调度引擎**/
type SchedulerSrv struct{
PlantNr int
StartDate time.Time
EndDate time.Time
WorkPlaceDict map[string]*WorkPlaceSrv // 所有的设备对象
WorkPlaceGrpDict map[string]*WorkPlaceGrpSrv
ToolDict map[string]*ToolSrv // 所有的工具对象
ToolGrpDict map[string]*ToolGrpSrv
ArticleDict map[string]*ArticleSrv // 所有的物料对象
SecResourceDict map[string]*SecondaryResourceSrv // 所有的次要资源对象
PersonDict map[int]*PersonSrv // 所有人员对象
SkillDict map[string]*SkillSrv // 所有技能对象
OrderDict map[string]*OrderSrv // 所有工单对象
OperationDict map[string]*OperationSrv // 所有订单工序对象
TmSrv TimeModelSrv // 时间模型
ProjDict map[string]me_model.Project // 激活的项目字典
SchedRule ScheduleRuleSrv // 调度规则
SchedEventQueue *SchedQueue // 调度事件队列
}
// 调度引擎初始化
func(se *SchedulerSrv)Init(plantnr int, stdate, eddate time.Time){
se.PlantNr = plantnr
se.StartDate = stdate
se.EndDate = eddate
se.WorkPlaceDict = make(map[string]*WorkPlaceSrv)
se.WorkPlaceGrpDict = make(map[string]*WorkPlaceGrpSrv)
se.ToolDict = make(map[string]*ToolSrv)
se.ToolGrpDict = make(map[string]*ToolGrpSrv)
se.ArticleDict = make(map[string]*ArticleSrv)
se.SecResourceDict = make(map[string]*SecondaryResourceSrv)
se.PersonDict = make(map[int]*PersonSrv)
se.SkillDict = make(map[string]*SkillSrv)
se.OrderDict = make(map[string]*OrderSrv)
se.OperationDict = make(map[string]*OperationSrv)
se.TmSrv = TimeModelSrv{PlantNr: plantnr}
se.SchedEventQueue = NewSchedQueue()
}
// 加载时间模型主数据
func(se *SchedulerSrv)LoadTimeModelData(){
// 加载指定日期范畴内的时间模型相关主数据
se.TmSrv.LoadBasicData(se.StartDate, se.EndDate)
// 生成日模型的时间线列表
se.TmSrv.GenDayModelLineArray()
}
// 加载激活的项目
func(se *SchedulerSrv)LoadProjectData()(err error){
var(
i int
projtablst []me_model.Project
)
// 初始化
se.ProjDict = make(map[string]me_model.Project )
// 读取激活的项目数据
engine := db.Eloquent.Master()
session := engine.NewSession()
defer session.Close()
me_dao := me_dal.NewProjectDAO(session, se.PlantNr, "scheduler")
if projtablst, err = me_dao.SelectActiveProjects(); err != nil{
err = errors.New(fmt.Sprintf("获取工厂%d的激活的项目失败%v !", se.PlantNr, err))
return
}
// 加载项目
for i = 0; i < len(projtablst); i++ {
se.ProjDict[projtablst[i].ProjectId] = projtablst[i]
}
return
}
// 加载工位主数据
func(se *SchedulerSrv)LoadWorkPlaceData()(err error){
var(
wp *WorkPlaceSrv
wpg *WorkPlaceGrpSrv
wptab base_model.WorkPlace
wptablst []base_model.WorkPlace
wpgtab base_model.WorkPlaceGrp
wpgtablst []base_model.WorkPlaceGrp
ok bool
)
engine := db.Eloquent.Master()
session := engine.NewSession()
defer session.Close()
WorkPlaceGrp_dao := base_dal.NewWorkPlaceGrpDAO(session, se.PlantNr, "scheduler")
// 加载并创建工位组对象
if wpgtablst, err = WorkPlaceGrp_dao.SelectAll(); err != nil{
err = errors.New(fmt.Sprintf("加载工位组主数据出错:%v",err))
return
}
for _, wpgtab = range wpgtablst {
wpg = &WorkPlaceGrpSrv{}
wpg.Create(wpgtab)
se.WorkPlaceGrpDict[wpg.WorkPlaceGrpId] = wpg
}
// 加载并创建工位对象
WorkPlace_dao := base_dal.NewWorkPlaceDAO(session, se.PlantNr, "scheduler")
if wptablst, err = WorkPlace_dao.SelectAll(); err != nil{
err = errors.New(fmt.Sprintf("加载工位主数据出错:%v",err))
return
}
for _, wptab = range wptablst {
wp = &WorkPlaceSrv{}
wp.Create(wptab)
// 生成工位的时间曲线 todo
err := wp.GetWorkDayList(&se.TmSrv)
if err != nil {
fmt.Println(err)
}
// 基于产线的时间模型和排班获取产线在指定时间区间内的时间线集合
wp.GenerateTimeCurve(&se.TmSrv)
// 获取工位组对象
if wpg, ok = se.WorkPlaceGrpDict[wp.WorkPlaceGrpId]; ok {
se.WorkPlaceDict[wp.WorkPlaceId] = wp
se.WorkPlaceGrpDict[wp.WorkPlaceGrpId].WorkPlaceDict[wp.WorkPlaceId] = wp
}
}
return
}
// 加载工具主数据
func(se *SchedulerSrv)LoadToolData()(err error){
var(
toolsrv *ToolSrv
toolgrpsrv *ToolGrpSrv
tooltab base_model.Tool
tooltablst []base_model.Tool
toolgrptab base_model.ToolGrp
toolgrptablst []base_model.ToolGrp
tavailtab base_model.ToolUnAvailTimeLst
tavailtablst []base_model.ToolUnAvailTimeLst
timelinesrv TimeLineSrv
ok bool
)
engine := db.Eloquent.Master()
session := engine.NewSession()
defer session.Close()
// 加载并创建工具组对象
toolGrp_Dao := base_dal.NewToolGrpDAO(session, se.PlantNr, "scheduler")
if toolgrptablst, err = toolGrp_Dao.SelectAll(); err != nil{
err = errors.New(fmt.Sprintf("加载工具组主数据出错:%v",err))
return
}
for _, toolgrptab = range toolgrptablst {
toolgrpsrv = &ToolGrpSrv{}
toolgrpsrv.Create(toolgrptab)
se.ToolGrpDict[toolgrpsrv.ToolGrpId] = toolgrpsrv
}
// 加载并创建工具对象
tool_Dao := base_dal.NewToolDAO(session, se.PlantNr, "scheduler")
if tooltablst, err = tool_Dao.SelectAll(); err != nil{
err = errors.New(fmt.Sprintf("加载工具组主数据出错:%v",err))
return
}
for _, tooltab = range tooltablst {
toolsrv = &ToolSrv{}
toolsrv.Create(tooltab)
// 更新工具组和工具的关联关系
if toolgrpsrv, ok = se.ToolGrpDict[toolsrv.ToolGrpId]; ok {
toolgrpsrv.ToolDict[toolsrv.ToolId] = toolsrv
}
// 插入工具
se.ToolDict[toolsrv.ToolId] = toolsrv
}
// 基于计划的指定计划时段加载工具的不可用时间数据
toolUnAvailTimeLst_Dao := base_dal.NewToolUnAvailTimeLstDAO(session, se.PlantNr, "scheduler")
if tavailtablst, err = toolUnAvailTimeLst_Dao.GetUnAvailTime(se.StartDate, se.EndDate); err != nil{
err = errors.New(fmt.Sprintf("加载工具不可用时间数据出错:%v",err))
return
}
for _, tavailtab = range tavailtablst {
if toolsrv, ok = se.ToolDict[tavailtab.ToolId]; ok{
timelinesrv = TimeLineSrv{}
timelinesrv.Init(tavailtab.BegTime.Restore(), tavailtab.EndTime.Restore())
toolsrv.UnAvailTimeLineArray = append(toolsrv.UnAvailTimeLineArray, timelinesrv)
}
}
return
}
// 加载物料主数据,包括库存及在途
func(se *SchedulerSrv)LoadArticleData()(err error){
var(
artsrv *ArticleSrv
arttab base_model.Article
arttablst []base_model.Article
artstocktab wm_model.Stock
artstocktablst []wm_model.Stock
arttransittab wm_model.TransitStock
arttransittablst []wm_model.TransitStock
ok bool
)
engine := db.Eloquent.Master()
session := engine.NewSession()
defer session.Close()
// 获取物料主数据
article_Dao := base_dal.NewArticleDAO(session, se.PlantNr, "scheduler")
if arttablst, err = article_Dao.SelectAll(); err != nil{
err = errors.New(fmt.Sprintf("加载物料主数据出错:%v",err))
return
}
// 创建物料对象
for _, arttab = range arttablst {
artsrv = &ArticleSrv{}
artsrv.Create(arttab)
se.ArticleDict[artsrv.ArtId] = artsrv
}
// 加载物料库存数据
stock_Dao := wm_dal.NewStockDAO(session, se.PlantNr, "scheduler")
if artstocktablst, err = stock_Dao.SelectAll(); err != nil{
err = errors.New(fmt.Sprintf("加载物料库存数据出错:%v",err))
return
}
for _, artstocktab = range artstocktablst {
if artsrv, ok = se.ArticleDict[artstocktab.ArtId]; ok {
artsrv.AvailQty = artstocktab.AvailableStock
}
}
// 加载物料在途数据
transitStock_Dao := wm_dal.NewTransitStockDAO(session, se.PlantNr, "scheduler")
if arttransittablst, err = transitStock_Dao.SelectAll(); err != nil{
err = errors.New(fmt.Sprintf("加载物料在途库存数据出错:%v",err))
return
}
for _, arttransittab = range arttransittablst {
if artsrv, ok = se.ArticleDict[artstocktab.ArtId]; ok {
artsrv.TransitStockLst = append(artsrv.TransitStockLst, arttransittab)
}
}
return
}
// 加载人员主数据,包括技能
func(se *SchedulerSrv)LoadPersonData()(err error){
var(
persrv *PersonSrv
skillsrv *SkillSrv
pertab base_model.Person
pertablst []base_model.Person
skilltab base_model.Skill
skilltablst []base_model.Skill
perskilltab base_model.PersonSkilllst
perskilltablst []base_model.PersonSkilllst
ok bool
)
engine := db.Eloquent.Master()
session := engine.NewSession()
defer session.Close()
// 加载人员主数据
person_Dao := base_dal.NewPersonDAO(session, se.PlantNr, "scheduler")
if pertablst, err = person_Dao.SelectAll(); err != nil{
err = errors.New(fmt.Sprintf("加载人员主数据出错:%v",err))
return
}
for _, pertab = range pertablst {
persrv = &PersonSrv{}
persrv.Create(pertab)
se.PersonDict[persrv.PersonNr] = persrv
}
// 加载技能数据
skill_Dao := base_dal.NewSkillDAO(session, se.PlantNr, "scheduler")
if skilltablst, err = skill_Dao.SelectAll(); err != nil{
err = errors.New(fmt.Sprintf("加载技能主数据出错:%v",err))
return
}
for _, skilltab = range skilltablst {
skillsrv = &SkillSrv{}
skillsrv.Create(skilltab)
se.SkillDict[skillsrv.SkillId] = skillsrv
}
// 加载技能的人员数据
personSkill_Dao := base_dal.NewPersonSkilllstDAO(session, se.PlantNr, "scheduler")
if perskilltablst, err = personSkill_Dao.SelectAll(); err != nil{
err = errors.New(fmt.Sprintf("加载人员技能主数据出错:%v",err))
return
}
for _, perskilltab = range perskilltablst {
if skillsrv, ok = se.SkillDict[perskilltab.SkillId]; !ok {
continue
}
if persrv, ok = se.PersonDict[perskilltab.PersonNr]; !ok {
continue
}
skillsrv.PersonDict[persrv.PersonNr] = persrv
}
return
}
// 加载辅助资源主数据
func(se *SchedulerSrv)LoadResourceData()(err error){
var(
resourcetab base_model.SecondaryResource
resourcetablst []base_model.SecondaryResource
secressrv *SecondaryResourceSrv
)
engine := db.Eloquent.Master()
session := engine.NewSession()
defer session.Close()
// 加载次要资源
secondaryResouce_Dao := base_dal.NewSecondaryResourceDAO(session, se.PlantNr, "scheduler")
if resourcetablst, err = secondaryResouce_Dao.SelectAll(); err != nil{
err = errors.New(fmt.Sprintf("加载次要资源数据出错:%v",err))
return
}
for _, resourcetab = range resourcetablst {
secressrv = &SecondaryResourceSrv{}
secressrv.Create(resourcetab)
se.SecResourceDict[secressrv.ResourceId] = secressrv
}
// 初始化次要资源的时间模型
return
}
// 加载订单主数据(未完成订单)
func(se *SchedulerSrv)LoadWorkOrderData()(err error){
var(
ordsrv *OrderSrv
opsrv *OperationSrv
vordtablst []om_model.VWorkorder
i int
)
engine := db.Eloquent.Master()
session := engine.NewSession()
defer session.Close()
// 加载所有未完成的订单
workOrder_dao := om_dal.NewWorkOrderDAO(session, se.PlantNr, "scheduler")
if vordtablst, err = workOrder_dao.SelectAllUnfinishedFullData(); err != nil {
err = errors.New(fmt.Sprintf("加载工单数据出错:%v",err))
return
}else{
WOOperation_dao := om_dal.NewWOOperationDAO(session, se.PlantNr, "scheduler")
// 获取订单工序数据
for i = 0; i < len(vordtablst); i++ {
session_OmWooperation := session.Table(meta.WOOperation.TableName)
if err = session_OmWooperation.Where("PlantNr = ? and WorkOrderId = ?",se.PlantNr,
vordtablst[i].WorkOrder.WorkOrderId).Asc("OperationNr", "SplitNr").Find(&vordtablst[i].WorkOrder.Operationlst); err != nil{
return
}
for j := 0; j < len(vordtablst[i].WorkOrder.Operationlst); j++ {
woOperationData, err := WOOperation_dao.SelectOne(vordtablst[i].WorkOrder.Operationlst[j].WorkOrderId,vordtablst[i].WorkOrder.Operationlst[j].OperationNr,vordtablst[i].WorkOrder.Operationlst[j].SplitNr)
if err != nil{
return err
}
vordtablst[i].WorkOrder.Operationlst[j] = *woOperationData
}
}
}
for i = 0; i < len(vordtablst); i++ {
ordsrv = &OrderSrv{}
ordsrv.Create(vordtablst[i].WorkOrder)
se.OrderDict[ordsrv.OrderId] = ordsrv
// 加载订单所有的工序对象
for _, opsrv = range ordsrv.OperationDict {
se.OperationDict[opsrv.GetOrdOpKey()] = opsrv
}
}
return
}
// 加载订单网络数据
func(se *SchedulerSrv)LoadOrderNetworkData()(err error){
// 加载订单网络
return
}
// 加载排程规则数据
func(se *SchedulerSrv)LoadScheduleRuleData()(err error){
return
}
// 启动调度引擎
func(se *SchedulerSrv)Run()(err error){
var(
set SchedEvent
)
// 从队列循环获取任务执行,直至队列为空
for se.SchedEventQueue.Length() > 0 {
set = se.SchedEventQueue.Pop()
switch set.GetEvent() {
case EVENT_TASK_SETUPBEG:
oppbet := set.(OperationEvent)
fmt.Println(fmt.Sprintf("订单:%s 工序:%d 换型开始:%s",oppbet.OrderId,oppbet.OperationNr,oppbet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedTaskSetupBeg(oppbet)
continue
case EVENT_TASK_SETUPEND:
oppbet := set.(OperationEvent)
fmt.Println(fmt.Sprintf("订单:%s 工序:%d 换型结束:%s",oppbet.OrderId,oppbet.OperationNr,oppbet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedTaskSetupEnd(oppbet)
continue
case EVENT_TASK_PLANBEG:
oppbet := set.(OperationEvent)
fmt.Println(fmt.Sprintf("订单:%s 工序:%d 计划开始:%s",oppbet.OrderId,oppbet.OperationNr,oppbet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedTaskPlanBeg(oppbet)
continue
case EVENT_TASK_PLANEND:
oppeet := set.(OperationEvent)
fmt.Println(fmt.Sprintf("订单:%s 工序:%d 计划结束:%s",oppeet.OrderId,oppeet.OperationNr,oppeet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedTaskPlanEnd(oppeet)
continue
case EVENT_TASK_POSTBEG:
oppbet := set.(OperationEvent)
fmt.Println(fmt.Sprintf("订单:%s 工序:%d 后处理开始:%s",oppbet.OrderId,oppbet.OperationNr,oppbet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedTaskPostBeg(oppbet)
continue
case EVENT_TASK_POSTEND:
oppbet := set.(OperationEvent)
fmt.Println(fmt.Sprintf("订单:%s 工序:%d 后处理结束:%s",oppbet.OrderId,oppbet.OperationNr,oppbet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedTaskPostEnd(oppbet)
continue
case EVENT_WP_STATUS_AVAIL:
wpet := set.(WorkPlaceEvent)
fmt.Println(fmt.Sprintf("|| 工位:%s 可使用时间:%s",wpet.WorkPlaceId, wpet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedWPAvail(wpet)
continue
case EVENT_WP_STATUS_UNAVAIL:
wpet := set.(WorkPlaceEvent)
fmt.Println(fmt.Sprintf("XX 工位:%s 不可使用时间:%s",wpet.WorkPlaceId, wpet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedWPUnAvail(wpet)
continue
case EVENT_TOOL_STATUS_AVAIL:
tet := set.(ToolEvent)
fmt.Println(fmt.Sprintf("|| 工具:%s 可使用时间:%s",tet.ToolId, tet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedToolAvail(tet)
continue
case EVENT_TOOL_STATUS_UNAVAIL:
tet := set.(ToolEvent)
fmt.Println(fmt.Sprintf("XX 工具:%s 不可使用时间:%s",tet.ToolId, tet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedToolUnAvail(tet)
continue
case EVENT_PERSON_STATUS_AVAIL:
pet := set.(PersonEvent)
fmt.Println(fmt.Sprintf("|| 人员:%d 可使用时间:%s",pet.PersonNr, pet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedPersonAvail(pet)
continue
case EVENT_PERSON_STATUS_UNAVAIL:
pet := set.(PersonEvent)
fmt.Println(fmt.Sprintf("|| 人员:%d 不可使用时间:%s",pet.PersonNr, pet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedPersonUnAvail(pet)
continue
case EVENT_ART_CONSUME:
aet := set.(ArticleEvent)
fmt.Println(fmt.Sprintf("|| 物料:%s 耗用时间:%s",aet.ArtId, aet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedArticleConsume(aet)
continue
case EVENT_ART_YIELD:
aet := set.(ArticleEvent)
fmt.Println(fmt.Sprintf("|| 物料:%s 产出时间:%s",aet.ArtId, aet.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedArticleYield(aet)
continue
case EVENT_SECRES_CONSUME:
sret := set.(SecondaryResourceEvent)
fmt.Println(fmt.Sprintf("|| 次要资源:%d 耗用时间:%s",sret.ResourceNr, sret.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedSecondaryResourceConsume(sret)
continue
case EVENT_SECRES_YIELD:
sret := set.(SecondaryResourceEvent)
fmt.Println(fmt.Sprintf("|| 次要资源:%d 耗用时间:%s",sret.ResourceNr, sret.TriggerTime.Format("2006-01-02 15:04:05")))
se.SchedSecondaryResourceYield(sret)
continue
}
}
return
}
// 对换型开始工序进行调度
func(se *SchedulerSrv)SchedTaskSetupBeg(opevent OperationEvent){
}
// 对换型结束工序进行调度
func(se *SchedulerSrv)SchedTaskSetupEnd(opevent OperationEvent){
}
// 对计划开始工序进行调度
func(se *SchedulerSrv)SchedTaskPlanBeg(opevent OperationEvent){
var(
order *OrderSrv
op *OperationSrv
wp *WorkPlaceSrv
wpg *WorkPlaceGrpSrv
t *ToolSrv
tg *ToolGrpSrv
newevent SchedEvent
optionalwplst []OptionalWorkPlaceSrv
optoollst []OptionalToolSrv
ok bool
)
// 获取工序订单对象
if order, ok = se.OrderDict[opevent.OrderId]; !ok {
fmt.Println(fmt.Sprintf("工序事件的订单: %s 不存在", opevent.OrderId))
return
}
// 获取工序对象
if op, ok = order.OperationDict[opevent.GetOpKey()]; !ok {
fmt.Println(fmt.Sprintf("工序事件的工序: %d 不存在于订单: %s 中", opevent.GetOpKey(), opevent.OrderId))
return
}
// 获取可用工位
optionalwplst = se.GetAvailWorkPlaceList(op.WorkPlaceGrpId)
if len(optionalwplst) <= 0 {
//fmt.Println("工位组:",op.WorkPlaceGrpNr," 无可用工位!")
// 获取工位组对象
if wpg, ok = se.WorkPlaceGrpDict[op.WorkPlaceGrpId]; !ok{
//fmt.Println("工位组:",op.WorkPlaceGrpNr," 不存在!")
return
}
// 无可用工位,则将任务放到工位组等待队列
wpg.WaitTaskArray = append(wpg.WaitTaskArray, *op)
return
}
if se.SchedRule.ToolConstraintToggle && op.ToolGrpId != ""{
// 获取可用工位
optoollst = se.GetAvailToolList(op.ToolGrpId)
if len(optoollst) <= 0 {
//fmt.Println("工具组:",op.ToolGrpId," 无可用工位!")
// 获取工具组对象
if tg, ok = se.ToolGrpDict[op.ToolGrpId]; !ok{
//fmt.Println("工具组:",op.ToolGrpId," 不存在!")
return
}
// 无可用工位,则将任务放到工位组等待队列
tg.WaitTaskArray = append(tg.WaitTaskArray, *op)
return
}
}
// 有可用工位,取第一个工位进行调度
op.PlanStartTime = opevent.TriggerTime
op.PlanEndTime = op.PlanStartTime.Add(op.PlanDuration)
op.PlanWorkPlaceId = optionalwplst[0].WorkPlaceId
if se.SchedRule.ToolConstraintToggle && op.ToolGrpId !="" {
op.PlanToolId = optoollst[0].ToolId
}
// 基于工序开始生成工序结束事件
fmt.Println(" 创建工序结束事件:",op.OrderId,op.OperationNr,op.PlanEndTime.Format("2006-01-02 15:04:05"))
newevent = op.GetPlanEndEvent(op.PlanEndTime)
se.SchedEventQueue.Insert(newevent)
// 基于工序开始生成设备事件,占用工位资源
if wp, ok = se.WorkPlaceDict[op.PlanWorkPlaceId]; ok {
newevent = wp.GetUnAvailEvent(opevent.TriggerTime)
se.SchedEventQueue.Insert(newevent)
wp.Status = common.RES_STATUS_UNAVAIL
wp.SchedTaskArray = append(wp.SchedTaskArray, *op)
}
// 考虑有限工具能力
if se.SchedRule.ToolConstraintToggle && op.ToolGrpId != ""{
if t, ok = se.ToolDict[op.PlanToolId]; ok {
newevent = t.GetUnAvailEvent(opevent.TriggerTime)
se.SchedEventQueue.Insert(newevent)
t.Status = common.RES_STATUS_UNAVAIL
t.SchedTaskArray = append(t.SchedTaskArray, *op)
}
}
}
// 对计划结束工序进行调度
func(se *SchedulerSrv)SchedTaskPlanEnd(opevent OperationEvent){
var(
order,nextorder *OrderSrv
op,nextop *OperationSrv
wp *WorkPlaceSrv
t *ToolSrv
newevent SchedEvent
nextoprel OperationRelSrv
ok bool
)
// 获取工序订单对象
if order, ok = se.OrderDict[opevent.OrderId]; !ok {
fmt.Println(fmt.Sprintf("工序事件的订单: %s 不存在", opevent.OrderId))
return
}
// 获取工序对象
if op, ok = order.OperationDict[opevent.GetOpKey()]; !ok {
fmt.Println(fmt.Sprintf("工序事件的工序: %d 不存在于订单: %s 中", opevent.GetOpKey(), opevent.OrderId))
return
}
// 获取占用工位并释放资源
if wp, ok = se.WorkPlaceDict[op.PlanWorkPlaceId]; ok {
newevent = wp.GetAvailEvent(opevent.TriggerTime)
se.SchedEventQueue.Insert(newevent)
wp.Status = common.RES_STATUS_AVAIL
}else{
fmt.Println(fmt.Sprintf("订单:%s 工序:%d 计划工位:%d 不存在!",op.OrderId,op.OperationNr,op.PlanWorkPlaceId))
return
}
if se.SchedRule.ToolConstraintToggle && op.ToolGrpId != ""{
if t, ok = se.ToolDict[op.PlanToolId]; ok{
newevent = t.GetAvailEvent(opevent.TriggerTime)
se.SchedEventQueue.Insert(newevent)
t.Status = common.RES_STATUS_AVAIL
}
}
// 激活后道工序
for _, nextoprel = range op.NextOpDict{
if nextorder, ok = se.OrderDict[nextoprel.OrderId]; ok{
if nextop, ok = nextorder.OperationDict[nextoprel.GetOpKey()]; ok{
newevent = nextop.GetPlanStartEvent(opevent.TriggerTime)
se.SchedEventQueue.Insert(newevent)
}
}else{
fmt.Println(fmt.Sprintf("订单:%s 不存在",nextoprel.OrderId))
continue
}
}
}
// 对工序后处理开始进行调度
func(se *SchedulerSrv)SchedTaskPostBeg(opevent OperationEvent){
}
// 对工序后处理结束进行调度
func(se *SchedulerSrv)SchedTaskPostEnd(opevent OperationEvent){
}
// 对工位可用进行调度
func(se *SchedulerSrv)SchedWPAvail(wpevent WorkPlaceEvent){
var (
wp *WorkPlaceSrv
wpg *WorkPlaceGrpSrv
op OperationSrv
newevent SchedEvent
ok bool
)
// 获取工位对象
if wp, ok = se.WorkPlaceDict[wpevent.WorkPlaceId]; !ok {
fmt.Println(fmt.Sprintf("SchedWPAvail: 工位:%s 不存在",wpevent.WorkPlaceId))
return
}
// 获取工位组对象
if wpg, ok = se.WorkPlaceGrpDict[wp.WorkPlaceGrpId]; !ok {
fmt.Println(fmt.Sprintf("工位组:%s 不存在",wp.WorkPlaceGrpId))
return
}
// 更新工位状态
wp.Status = common.RES_STATUS_AVAIL
//se.WorkPlaceDict[wp.WorkPlaceNr] = wp
// 将等待队列中的工序任务全部推入调度队列
for _, op = range wpg.WaitTaskArray {
fmt.Println("************ 获取等待队列中的等待任务:",op.OrderId,op.OperationNr)
newevent = op.GetPlanStartEvent(wpevent.TriggerTime)
se.SchedEventQueue.Insert(newevent)
}
wpg.WaitTaskArray = []OperationSrv{}
//se.WorkPlaceGrpDict[wpg.WorkPlaceGrpNr] = wpg
return
}
// 对工位不可用进行调度
func(se *SchedulerSrv)SchedWPUnAvail(wpevent WorkPlaceEvent){
var (
wp *WorkPlaceSrv
ok bool
)
// 获取工位对象
if wp, ok = se.WorkPlaceDict[wpevent.WorkPlaceId]; !ok {
fmt.Println(fmt.Sprintf("SchedWPUnAvail: 工位:%s 不存在",wpevent.WorkPlaceId))
return
}
// 更新工位状态
wp.Status = common.RES_STATUS_UNAVAIL
//se.WorkPlaceDict[wp.WorkPlaceNr] = wp
return
}
// 对工具可用进行调度
func(se *SchedulerSrv)SchedToolAvail(tevent ToolEvent){
var (
t *ToolSrv
tg *ToolGrpSrv
op OperationSrv
newevent SchedEvent
ok bool
)
// 获取工具对象
if t, ok = se.ToolDict[tevent.ToolId]; !ok {
fmt.Println(fmt.Sprintf("SchedToolAvail: 工具:%s 不存在",tevent.ToolId))
return
}
// 获取工具组对象
if tg, ok = se.ToolGrpDict[t.ToolGrpId]; !ok {
fmt.Println(fmt.Sprintf("工具组:%d 不存在",t.ToolGrpId))
return
}
// 更新工具状态
t.Status = common.RES_STATUS_AVAIL
// 将等待队列中的工序任务全部推入调度队列
for _, op = range tg.WaitTaskArray {
fmt.Println("************ 获取等待队列中的等待任务:",op.OrderId,op.OperationNr)
newevent = op.GetPlanStartEvent(tevent.TriggerTime)
se.SchedEventQueue.Insert(newevent)
}
tg.WaitTaskArray = []OperationSrv{}
return
}
// 对工具不可用进行调度
func(se *SchedulerSrv)SchedToolUnAvail(tevent ToolEvent){
var (
t *ToolSrv
ok bool
)
// 获取工位对象
if t, ok = se.ToolDict[tevent.ToolId]; !ok {
fmt.Println(fmt.Sprintf("SchedToolUnAvail: 工具:%s 不存在",tevent.ToolId))
return
}
// 更新工位状态
t.Status = common.RES_STATUS_UNAVAIL
return
}
// 对人员可用进行调度
func(se *SchedulerSrv)SchedPersonAvail(pevent PersonEvent){
}
// 对人员不可用进行调度
func(se *SchedulerSrv)SchedPersonUnAvail(pevent PersonEvent){
}
// 对物料耗用进行调度
func(se *SchedulerSrv)SchedArticleConsume(artevent ArticleEvent){
}
// 对物料产出进行调度
func(se *SchedulerSrv)SchedArticleYield(artevent ArticleEvent){
}
// 对次要资源耗用进行调度
func(se *SchedulerSrv)SchedSecondaryResourceConsume(srevent SecondaryResourceEvent){
}
// 对次要资源产出进行调度
func(se *SchedulerSrv)SchedSecondaryResourceYield(srevent SecondaryResourceEvent){
}
// 获取当前可用工位
func(se *SchedulerSrv)GetAvailWorkPlaceList(wpgid string)(optionalwplst []OptionalWorkPlaceSrv){
var(
wpid string
wp *WorkPlaceSrv
wpg *WorkPlaceGrpSrv
ok bool
)
// 获取工位组对象
if wpg, ok = se.WorkPlaceGrpDict[wpgid]; !ok {
fmt.Println(fmt.Sprintf("GetAvailWorkPlaceList: 工位组:%s 不存在",wpgid))
return
}
optionalwplst = []OptionalWorkPlaceSrv{}
for wpid, _ = range wpg.WorkPlaceDict{
if wp, ok = se.WorkPlaceDict[wpid]; !ok{
fmt.Println(fmt.Sprintf("GetAvailWorkPlaceList: 工位:%s 不存在",wpid))
return
}
if wp.Status == common.RES_STATUS_AVAIL {
optionalwp := OptionalWorkPlaceSrv{WorkPlaceId: wp.WorkPlaceId, Priority: 0}
optionalwplst = append(optionalwplst, optionalwp)
}
}
return
}
// 获取当前可用工具
func(se *SchedulerSrv)GetAvailToolList(tgid string)(opttoollst []OptionalToolSrv){
var(
tid string
t *ToolSrv
tg *ToolGrpSrv
ok bool
)
// 获取工位组对象
if tg, ok = se.ToolGrpDict[tgid]; !ok {
fmt.Println(fmt.Sprintf("GetAvailToolList: 工具组:%s 不存在",tgid))
return
}
fmt.Println("获取工具组的工具.......",tg.ToolGrpId)
opttoollst = []OptionalToolSrv{}
//todo
for tid, _ = range tg.ToolDict{
if t, ok = se.ToolDict[tid]; !ok{
fmt.Println(fmt.Sprintf("GetAvailToolList: 工位:%s 不存在",tid))
return
}
fmt.Println(" 工具:",t.ToolId," 状态:",t.Status)
if t.Status == common.RES_STATUS_AVAIL {
optionalt := OptionalToolSrv{ToolId: t.ToolId, Priority: 0}
opttoollst = append(opttoollst, optionalt)
}
}
return
}
// 初始化测试环境,创建一些测试数据
func LoadTestEnvData(se *SchedulerSrv)(err error){
var(
wp *WorkPlaceSrv
wpg *WorkPlaceGrpSrv
t *ToolSrv
tg *ToolGrpSrv
art *ArticleSrv
order *OrderSrv
prevop *OperationSrv
op *OperationSrv
opr OperationRelSrv
st,et time.Time
tls TimeLineSrv
)
// 初始化工厂号及计划区间
st = time.Now()
et = time.Now().Add(time.Hour*24*10)
se.Init(100, st, et)
// 创建工位组
wpg = &WorkPlaceGrpSrv{}
wpg.Init("10")
// 创建工位
wp = &WorkPlaceSrv{}
wp.Init("1","10")
st = time.Now()
et = time.Now().Add(time.Hour*24*10)
wp.TimeCurve.Init(st,et)
tls = TimeLineSrv{}
st = time.Now()
et = time.Now().Add(time.Hour*24)
tls.Init(st, et)
wp.TimeCurve.TimeLineArray = append(wp.TimeCurve.TimeLineArray, tls)
tls = TimeLineSrv{}
st = time.Now().Add(time.Hour*28)
et = time.Now().Add(time.Hour*48)
tls.Init(st, et)
wp.TimeCurve.TimeLineArray = append(wp.TimeCurve.TimeLineArray, tls)
se.WorkPlaceDict[wp.WorkPlaceId] = wp
wpg.WorkPlaceDict[wp.WorkPlaceId] = wp
wp = &WorkPlaceSrv{}
wp.Init("2","10")
st = time.Now()
et = time.Now().Add(time.Hour*24*10)
wp.TimeCurve.Init(st,et)
tls = TimeLineSrv{}
st = time.Now()
et = time.Now().Add(time.Hour*16)
tls.Init(st, et)
wp.TimeCurve.TimeLineArray = append(wp.TimeCurve.TimeLineArray, tls)
tls = TimeLineSrv{}
st = time.Now().Add(time.Hour*24)
et = time.Now().Add(time.Hour*46)
tls.Init(st, et)
wp.TimeCurve.TimeLineArray = append(wp.TimeCurve.TimeLineArray, tls)
se.WorkPlaceDict[wp.WorkPlaceId] = wp
wpg.WorkPlaceDict[wp.WorkPlaceId] = wp
se.WorkPlaceGrpDict[wpg.WorkPlaceGrpId] = wpg
wpg = &WorkPlaceGrpSrv{}
wpg.Init("20")
wp = &WorkPlaceSrv{}
wp.Init("3","20")
st = time.Now()
et = time.Now().Add(time.Hour*24*10)
wp.TimeCurve.Init(st,et)
tls = TimeLineSrv{}
st = time.Now()
et = time.Now().Add(time.Hour*20)
tls.Init(st, et)
wp.TimeCurve.TimeLineArray = append(wp.TimeCurve.TimeLineArray, tls)
tls = TimeLineSrv{}
st = time.Now().Add(time.Hour*22)
et = time.Now().Add(time.Hour*44)
tls.Init(st, et)
wp.TimeCurve.TimeLineArray = append(wp.TimeCurve.TimeLineArray, tls)
se.WorkPlaceDict[wp.WorkPlaceId] = wp
wpg.WorkPlaceDict[wp.WorkPlaceId] = wp
se.WorkPlaceGrpDict[wpg.WorkPlaceGrpId] = wpg
wpg = &WorkPlaceGrpSrv{}
wpg.Init("30")
wp = &WorkPlaceSrv{}
wp.Init("4","30")
st = time.Now()
et = time.Now().Add(time.Hour*24*15)
wp.TimeCurve.Init(st,et)
tls = TimeLineSrv{}
st = time.Now()
et = time.Now().Add(time.Hour*21)
tls.Init(st, et)
wp.TimeCurve.TimeLineArray = append(wp.TimeCurve.TimeLineArray, tls)
tls = TimeLineSrv{}
st = time.Now().Add(time.Hour*23)
et = time.Now().Add(time.Hour*50)
tls.Init(st, et)
wp.TimeCurve.TimeLineArray = append(wp.TimeCurve.TimeLineArray, tls)
se.WorkPlaceDict[wp.WorkPlaceId] = wp
wpg.WorkPlaceDict[wp.WorkPlaceId] = wp
wp = &WorkPlaceSrv{}
wp.Init("5","30")
st = time.Now()
et = time.Now().Add(time.Hour*24*10)
wp.TimeCurve.Init(st,et)
tls = TimeLineSrv{}
st = time.Now()
et = time.Now().Add(time.Hour*17)
tls.Init(st, et)
wp.TimeCurve.TimeLineArray = append(wp.TimeCurve.TimeLineArray, tls)
tls = TimeLineSrv{}
st = time.Now().Add(time.Hour*25)
et = time.Now().Add(time.Hour*52)
tls.Init(st, et)
wp.TimeCurve.TimeLineArray = append(wp.TimeCurve.TimeLineArray, tls)
se.WorkPlaceDict[wp.WorkPlaceId] = wp
wpg.WorkPlaceDict[wp.WorkPlaceId] = wp
se.WorkPlaceGrpDict[wpg.WorkPlaceGrpId] = wpg
// 创建工具
t = &ToolSrv{}
t.Init("1", "10")
tls = TimeLineSrv{}
st = time.Now().Add(time.Hour*5)
et = time.Now().Add(time.Hour*10)
t.UnAvailTimeLineArray = append(t.UnAvailTimeLineArray, tls)
se.ToolDict[t.ToolId] = t
// 创建工具组
tg = &ToolGrpSrv{}
tg.Init("10")
tg.ToolIdxDict[t.ToolId] = t.ToolId
se.ToolGrpDict[tg.ToolGrpId] = tg
// 创建工具
t = &ToolSrv{}
t.Init("2", "20")
tls = TimeLineSrv{}
st = time.Now().Add(time.Hour*6)
et = time.Now().Add(time.Hour*12)
t.UnAvailTimeLineArray = append(t.UnAvailTimeLineArray, tls)
se.ToolDict[t.ToolId] = t
// 创建工具组
tg = &ToolGrpSrv{}
tg.Init("20")
tg.ToolIdxDict[t.ToolId] = t.ToolId
se.ToolGrpDict[tg.ToolGrpId] = tg
// 创建物料
art = &ArticleSrv{}
art.Init("art001",100)
se.ArticleDict[art.ArtId] = art
// 创建工单及工序
order = &OrderSrv{OrderId: "100001", ProjectId: "G18"}
order.OperationArray = []OperationSrv{}
order.OperationDict = make(map[string]*OperationSrv)
op = &OperationSrv{OrderId: "100001",OperationNr: 10, SplitNr: 0,PlanQty: 10, WorkPlaceGrpId: "10", ToolGrpId: "10", PlanDuration: time.Hour * 4}
op.PrevOpDict = make(map[string]OperationRelSrv)
op.NextOpDict = make(map[string]OperationRelSrv)
order.OperationArray = append(order.OperationArray, *op)
order.OperationDict[op.GetOpKey()] = op
prevop = op
opr = OperationRelSrv{OrderId: "100001", OperationNr: 20, SplitNr: 0, Relation: OP_LINK_END_START}
prevop.NextOpDict[opr.GetFullKey()] = opr
op = &OperationSrv{OrderId: "100001",OperationNr: 20, SplitNr: 0,PlanQty: 10, WorkPlaceGrpId: "20", PlanDuration: time.Hour * 6}
op.PrevOpDict = make(map[string]OperationRelSrv)
opr = OperationRelSrv{OrderId: "100001", OperationNr: 10, SplitNr: 0, Relation: OP_LINK_END_START}
op.PrevOpDict[opr.GetFullKey()] = opr
op.NextOpDict = make(map[string]OperationRelSrv)
order.OperationArray = append(order.OperationArray, *op)
order.OperationDict[op.GetOpKey()] = op
prevop = op
opr = OperationRelSrv{OrderId: "100001", OperationNr: 30, SplitNr: 0, Relation: OP_LINK_END_START}
prevop.NextOpDict[opr.GetFullKey()] = opr
op = &OperationSrv{OrderId: "100001",OperationNr: 30, SplitNr: 0,PlanQty: 10, WorkPlaceGrpId: "30", PlanDuration: time.Hour * 8}
op.PrevOpDict = make(map[string]OperationRelSrv)
opr = OperationRelSrv{OrderId: "100001", OperationNr: 20, SplitNr: 0, Relation: OP_LINK_END_START}
op.PrevOpDict[opr.GetFullKey()] = opr
op.NextOpDict = make(map[string]OperationRelSrv)
order.OperationArray = append(order.OperationArray, *op)
order.OperationDict[op.GetOpKey()] = op
se.OrderDict[order.OrderId] = order
order = &OrderSrv{OrderId: "100002", ProjectId: "G18"}
order.OperationArray = []OperationSrv{}
order.OperationDict = make(map[string]*OperationSrv)
op = &OperationSrv{OrderId: "100002",OperationNr: 10, SplitNr: 0,PlanQty: 10, WorkPlaceGrpId: "10", ToolGrpId: "10", PlanDuration: time.Hour * 5}
op.PrevOpDict = make(map[string]OperationRelSrv)
op.NextOpDict = make(map[string]OperationRelSrv)
order.OperationArray = append(order.OperationArray, *op)
order.OperationDict[op.GetOpKey()] = op
prevop = op
opr = OperationRelSrv{OrderId: "100002", OperationNr: 20, SplitNr: 0, Relation: OP_LINK_END_START}
prevop.NextOpDict[opr.GetFullKey()] = opr
op = &OperationSrv{OrderId: "100002",OperationNr: 20, SplitNr: 0,PlanQty: 10, WorkPlaceGrpId: "20", PlanDuration: time.Hour * 7}
op.PrevOpDict = make(map[string]OperationRelSrv)
opr = OperationRelSrv{OrderId: "100002", OperationNr: 10, SplitNr: 0, Relation: OP_LINK_END_START}
op.PrevOpDict[opr.GetFullKey()] = opr
op.NextOpDict = make(map[string]OperationRelSrv)
order.OperationArray = append(order.OperationArray, *op)
order.OperationDict[op.GetOpKey()] = op
prevop = op
opr = OperationRelSrv{OrderId: "100002", OperationNr: 30, SplitNr: 0, Relation: OP_LINK_END_START}
prevop.NextOpDict[opr.GetFullKey()] = opr
op = &OperationSrv{OrderId: "100002",OperationNr: 30, SplitNr: 0,PlanQty: 10, WorkPlaceGrpId: "30", PlanDuration: time.Hour * 9}
op.PrevOpDict = make(map[string]OperationRelSrv)
opr = OperationRelSrv{OrderId: "100002", OperationNr: 20, SplitNr: 0, Relation: OP_LINK_END_START}
op.PrevOpDict[opr.GetFullKey()] = opr
op.NextOpDict = make(map[string]OperationRelSrv)
order.OperationArray = append(order.OperationArray, *op)
order.OperationDict[op.GetOpKey()] = op
se.OrderDict[order.OrderId] = order
// 初始化调度队列
se.SchedEventQueue = NewSchedQueue()
// 遍历设备时间曲线,生成设备状态事件,推入队列
for _, wp_p := range se.WorkPlaceDict{
for _, tls := range wp_p.TimeCurve.TimeLineArray{
evt1 := wp_p.GetAvailEvent(tls.StartTime)
se.SchedEventQueue.Insert(evt1)
evt2 := wp_p.GetUnAvailEvent(tls.EndTime)
se.SchedEventQueue.Insert(evt2)
}
}
// 载入订单首工序事件
for _, ord_p := range se.OrderDict{
for _, op_p := range ord_p.OperationDict {
if len(op_p.PrevOpDict) <= 0 {
evt := op_p.GetPlanStartEvent(time.Now())
opet := evt.(OperationEvent)
fmt.Println("压入订单工序事件:",opet.OrderId,opet.OperationNr, opet.TriggerTime)
se.SchedEventQueue.Insert(evt)
}
}
}
return
}