# OPERATION 复合步骤设计 ## 目标 将 recipe 中每个工站的 LOAD → EXECUTE → UNLOAD 三元组合并为一个 OPERATION 步骤。LOAD/UNLOAD 降级为步骤的入口/出口动作,由 resource_type 自动推导。24 步 → 12 步。 ## 核心概念变化 ### 旧模型 ``` LOAD(CNC) → MACHINING → UNLOAD(CNC) → LOAD(Washer) → WASH → UNLOAD(Washer) → ... ``` 每个工站占 3 个 recipe_step,step_index 推进 3 次。 ### 新模型 ``` OPERATION(resource=CNC) → OPERATION(resource=Washer) → ... ``` 每个工站 1 个 recipe_step。步骤内有三个子阶段,由 job.status 驱动: ``` ON_BUFFER ──Load──→ PROCESSING ──MachineDone──→ WAITING_UNLOAD ──Unload──→ 下一步 ``` step_index 只在 Unload 完成后推进一次。 ## recipe_step 变更 ### step_type 枚举 新增 `OPERATION`: ``` OPERATION ← 新增 DECISION ← 保留 JUDGE ← 保留 FINAL_SCAN ← 保留 LASER_MARK ← 保留 UNLOAD ← 保留(OP110 下料接驳台) 删除: LOAD, MACHINING, WASH, DEBURR, RUST_WASH, INSPECTION(被 OPERATION + resource_type 替代) ``` ### resource_type 复用 现有 `resourceType` 字段直接用于 OPERATION 步骤区分设备类型。Generator 根据 resource_type 推断 Load/Unload 动作类型: | resource_type | Load Action | Unload Action | |---|---|---| | CNC | ActionLoadCNC | ActionUnloadCNC | | WASHER_HP | ActionLoadWasher | ActionUnloadWasher | | CLEANING_LINE | ActionLoadCleaning | ActionUnloadCleaning | | DEBURR | ActionLoadDeburr | ActionUnloadDeburr | | INSPECTION | ActionLoadInspection | ActionUnloadInspection | | SAMPLING | ActionLoadSampling | ActionUnloadSampling | ### 迁移后数据 ``` step_index step_id step_type resource_type step_name ──────────────────────────────────────────────────────────── 1 OP10 OPERATION CNC CNC加工 2 OP20 OPERATION WASHER_HP 高压清洗 3 OP30 OPERATION INSPECTION 内窥镜检测 4 OP40 JUDGE 检测判断 5 OP50 OPERATION DEBURR 热能去毛刺 6 OP60 OPERATION CLEANING_LINE 除锈清洗 7 OP70 FINAL_SCAN 终检扫码 8 OP80 DECISION 打标判断 9 OP90 LASER_MARK 激光打标 10 OP100 DECISION 抽检判断 11 OP110 OPERATION SAMPLING 抽检 12 OP120 UNLOAD 下料接驳台 ``` nextStepBranches 示例: - OP40 branch `MEASURE_NG: OP110` - OP80 branch `NEED_MARKING: OP90` - OP100 branch `NEED_SAMPLING: OP110` ## job 状态机 OPERATION 步骤内 status 驱动,现有枚举不变: ``` ON_BUFFER → Worker Load → PROCESSING → MachineDone → WAITING_UNLOAD → Worker Unload → OnBuffer + AdvanceStep ``` ### 检测设备 (INSPECTION/SAMPLING) 特殊路径 ``` PROCESSING → MachineDone(inspectionPass=true) → WAITING_UNLOAD → Worker Unload → AdvanceStep PROCESSING → MachineDone(inspectionPass=false) → Scrapped(不卸载) ``` `handleInspectionDone` 变更:pass=true 时不调 `AdvanceStep`,改为 `SetJobWaitingUnload`,等待调度器生成 Unload 候选由 Worker 卸下。Unload 完成后才 `AdvanceStep` 推进到下一步。 ## 调度器变更 ### JobView 扩展 Generator 需要区分 OPERATION 步骤内的子阶段。JobView 新增 `RawStatus` 字段: ```go type JobView struct { // ...existing... RawStatus string // "ON_BUFFER" / "PROCESSING" / "WAITING_UNLOAD" } ``` ### Generator ```go case constants.StepType_Operation: switch job.RawStatus { case "ON_BUFFER": candidates = append(candidates, CandidateTask{ Action: g.loadActionFor(step.ResourceType), TargetID: 0, // findIdleMachine 在 trySchedule 中分配 Priority: PriorityNormal, }) case "PROCESSING": candidates = append(candidates, CandidateTask{ Action: ActionLoadCNC, // 占位 TargetID: job.CurrentStep.TargetID, Meta: map[string]any{"machineWait": true}, }) case "WAITING_UNLOAD": candidates = append(candidates, CandidateTask{ Action: g.unloadActionFor(step.ResourceType), TargetID: job.CurrentStep.TargetID, Priority: PriorityHigh, }) } ``` ### findExchangePair 更新 ```go if bufSnap.StepType == constants.StepType_Operation && bufSnap.Status == "ON_BUFFER" && bufSnap.PositionType == string(constants.PositionType_OnBuffer) && bufSnap.ResourceType == unloadSnap.ResourceType { return bufSnap.JobID } ``` ### Filter / Policy / Exchange 不变。 ## 事件循环变更 ### Load 完成后 ```go if stepType == OPERATION { l.db.SetJobProcessing(ctx, jobID, machineID, slotNo) } else { l.db.AdvanceStep(ctx, jobID, nil, OnEquipment, "eq:slot") } ``` 新增 `DBState.SetJobProcessing`:status=PROCESSING、position=OnEquipment、version+1。 ### MachineDone(handleMachineDone / handleMachineWaitCandidate) ```go if stepType == OPERATION { l.db.SetJobWaitingUnload(ctx, jobID) } else { l.db.AdvanceStep(ctx, jobID, nil, "", "") } ``` 新增 `DBState.SetJobWaitingUnload`:status=WAITING_UNLOAD、version+1。 ### MachineDone → InspectionResult(handleInspectionDone) ```go if pass { l.db.SetJobWaitingUnload(ctx, jobID) } else { l.db.CompleteStep(ctx, jobID, job.CurrentStepIndex, map[string]any{"inspectionPass": false}) l.db.RaiseAlarm(...) l.db.FinishJob(ctx, jobID, job.WorkOrderId, Scrapped) l.db.SetEquipmentSlot(ctx, machineID, slotNo, Done, Empty, 0) } ``` ### Unload 完成后 不变。`AdvanceStep` 推进到下一步。 ### 清洗机批量编排 WASHER_HP 的 2 槽位 Load/Unload 批量逻辑不变。Load 完成后 `SetJobProcessing`,MachineDone 时 `SetJobWaitingUnload`。 ## 数据库迁移 `schema/tools/data.go` 中删除旧步骤,插入新步骤。不存在活跃 job 兼容问题——dev 环境,清空 job 表后执行。 ## 移除的常量 ```go // 删除: StepType_Load, StepType_Machining StepType_Wash, StepType_Deburr, StepType_RustWash, StepType_Inspection // 新增: StepType_Operation StepType = "OPERATION" ``` ## 测试 - Generator: OPERATION 步骤在 ON_BUFFER/PROCESSING/WAITING_UNLOAD 三个状态下生成正确 Action - 事件循环: Load→SetJobProcessing, MachineDone→SetJobWaitingUnload, Unload→AdvanceStep - findExchangePair: OPERATION+ON_BUFFER 匹配正确 - 检测设备: InspectionResult 合格→WAITING_UNLOAD→Unload→AdvanceStep;不合格→Scrapped - 清洗机: 2 槽位批量 Load/Unload 保持正常