package processor import ( "sync" "bj_power_mes/constants" ) // StepRuntime 工序运行时(内存表示,从 RecipeStep DB 记录构建) type StepRuntime struct { StepID int // 步骤 ID StepIdStr string // 业务步骤ID(stepId 字段) StepIndex int // 步骤索引(从 0 开始) StepName string // 步骤名称 StepType constants.StepType // 步骤类型 ResourceType string // 工站设备类型编码(CNC/WASHER_HP/...),手持操作为空 ToolType string // 手持工具类型:SCANNER/LASER,工站操作为空 AllowedResources []string // 允许的设备ID列表 ProcessingParams map[string]any // 加工参数 NextStepDefault string // 默认下一步 stepId(空=顺序+1) NextStepBranches map[string]string // 条件分支:条件名→stepId RestoreStep int // 恢复时回退步数(-1=不回退) StepTimeout int // 工序超时秒数 } // RecipeRuntime 工艺路线运行时 type RecipeRuntime struct { RecipeID int RecipeCode string TotalSteps int Steps []StepRuntime stepIndexMap map[int]int // stepIndex → Steps 切片下标 mu sync.RWMutex } // NewRecipeRuntime 从步骤列表构建 RecipeRuntime,建立 stepIndex→下标 索引 func NewRecipeRuntime(recipeID int, recipeCode string, steps []StepRuntime) *RecipeRuntime { rr := &RecipeRuntime{ RecipeID: recipeID, RecipeCode: recipeCode, TotalSteps: len(steps), Steps: steps, stepIndexMap: make(map[int]int, len(steps)), } for i, s := range steps { rr.stepIndexMap[s.StepIndex] = i } return rr } // GetStep 按步骤序号(stepIndex)获取 StepRuntime func (rr *RecipeRuntime) GetStep(stepIndex int) (StepRuntime, bool) { rr.mu.RLock() defer rr.mu.RUnlock() idx, ok := rr.stepIndexMap[stepIndex] if !ok { return StepRuntime{}, false } return rr.Steps[idx], true } // GetStepById 按业务 stepId 查找 StepRuntime func (rr *RecipeRuntime) GetStepById(stepId string) (StepRuntime, bool) { rr.mu.RLock() defer rr.mu.RUnlock() for _, s := range rr.Steps { if s.StepIdStr == stepId { return s, true } } return StepRuntime{}, false } // IsLastStep 判断当前步骤是否为工艺路线的最后一步(比较实际最大 stepIndex,而非 Steps 长度) func (rr *RecipeRuntime) IsLastStep(stepIndex int) bool { rr.mu.RLock() defer rr.mu.RUnlock() if len(rr.Steps) == 0 { return true } // 用最后一个步骤的 StepIndex,而非 TotalSteps,因为 stepIndex 可能不连续 maxIdx := rr.Steps[len(rr.Steps)-1].StepIndex for _, s := range rr.Steps { if s.StepIndex > maxIdx { maxIdx = s.StepIndex } } return stepIndex >= maxIdx } // IsStationStep 判断是否为工站操作步骤(ResourceType 非空) func (s *StepRuntime) IsStationStep() bool { return s.ResourceType != "" } // IsToolStep 判断是否为手持工具步骤(ToolType 非空) func (s *StepRuntime) IsToolStep() bool { return s.ToolType != "" } // IsWaitStep 判断是否为设备等待步骤 func (s *StepRuntime) IsWaitStep() bool { return s.StepType == constants.StepType_Operation } // IsUnloadStep 判断是否为下料步骤(Unload 类型) func (s *StepRuntime) IsUnloadStep() bool { return s.StepType == constants.StepType_UnloadDock } // IsDecisionStep 判断是否为判断/决策步骤(Judge/Decision 类型) func (s *StepRuntime) IsDecisionStep() bool { return s.StepType == constants.StepType_Judge || s.StepType == constants.StepType_Decision } // FirstStepIndex returns the StepIndex of the first step, or 0 if empty. func (rr *RecipeRuntime) FirstStepIndex() int { if len(rr.Steps) == 0 { return 0 } return rr.Steps[0].StepIndex }