124 lines
3.8 KiB
Go
124 lines
3.8 KiB
Go
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
|
||
}
|