Files
bj_power/bj_power_mes/doc/new_recipe.sql
T

1139 lines
100 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- ============================================================================
-- 新架构全配置化流程引擎 - 配方种子数据
-- 版本: v3.0
-- 说明: 两个工艺路线(缸体/配油盘)的完整 recipe 配置
-- 磨床交互采用一步换料工艺:磨床有成品+机器人持毛坯 → 直接换料(M2050/M2059),磨床不停机
-- 所有业务逻辑通过 recipe_step 子表配置驱动,引擎无硬编码 step_type
--
-- 磨床换料核心设计(配置驱动,引擎零业务字符串):
-- 1. OP15_DECIDE 决策:磨床 done → 换料(OP20_EXCHANGE);磨床 empty → 放料(OP20_LOAD
-- 2. OP20_EXCHANGE 一步换料:acquire_mode='any' 抢占前任工件 done 槽位(记录前任 job),
-- PLC 一次完成 取成品+放毛坯;COMPLETE 阶段 handover 把 robot/temp_slot 锁转移给前任 job
-- 并推进其去清洗(成品由前任 job 带走)
-- 3. OP20_WAIT 磨床等待加工:hold_until_handover=true,完成后进入 holding 等下一件换料交接,
-- fallback_next_step='OP20_FALLBACK_UNLOAD'(最后一件无后继时自行取料收尾)
-- ============================================================================
-- 清理新引擎表数据
DELETE FROM recipe_step_decision;
DELETE FROM recipe_step_action;
DELETE FROM recipe_step_signal;
DELETE FROM recipe_step_resource;
DELETE FROM recipe_step;
DELETE FROM recipe WHERE id IN (1, 2);
-- ============================================================================
-- 一、工艺路线
-- ============================================================================
INSERT INTO recipe (id, name, code, version, is_active, "desc") VALUES
(1, '缸体工艺', 'GRINDER-RND', 1, true, '缸体标准工艺流程:接驳台取料→磨床决策→磨床换料/放料→等待加工(挂起交接)→最后一件自行取料→清洗→决策→全检/缓存→接驳台下料'),
(2, '配油盘工艺', 'GRINDER-SQR', 1, true, '配油盘标准工艺流程:接驳台取料→转换台换向→磨床决策→磨床换料/放料→等待加工(挂起交接)→最后一件自行取料→清洗→决策→全检/缓存→接驳台下料');
-- ============================================================================
-- 二、缸体工艺 (recipe_id=1) 步骤定义
-- 步骤索引顺序即流程顺序;OP20_WAIT(25) 之前的步骤 = 磨床前步骤(后继工件会来换料)
-- ============================================================================
-- OP10_LOAD: 接驳台取料(机器人持毛坯,准备去磨床)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(1, 1, 'OP10_LOAD', '接驳台取料', 10, '', '', 'OP15_DECIDE', 2, -1, FALSE, '', '从接驳台取毛坯:机器人+缓存槽+DOCK occupied槽位');
-- OP15_DECIDE: 磨床状态决策(done→换料,empty→放料,加工中→等待)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(2, 1, 'OP15_DECIDE', '磨床状态决策', 15, '', '', 'OP20_LOAD', 2, -1, FALSE, '', '决策:磨床有加工完成的槽位→换料;磨床空→放料;加工中→等待');
-- OP20_EXCHANGE: 磨床一步换料(取成品+放毛坯,磨床不停机)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(3, 1, 'OP20_EXCHANGE', '磨床换料', 20, '', '', 'OP20_WAIT', 2, -1, FALSE, '', '一步换料:acquire_mode=any 抢占前任工件done槽位,M2050一次取成品+放毛坯,handover交接成品给前任job');
-- OP20_LOAD: 磨床放料(磨床空闲时直接放毛坯)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(4, 1, 'OP20_LOAD', '磨床放料', 22, '', '', 'OP20_WAIT', 2, -1, FALSE, '', '放料到磨床空槽位:机器人+GRINDER empty');
-- OP20_WAIT: 磨床等待加工(完成后进入 holding,等下一件换料交接;最后一件走 fallback 自行取料)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(5, 1, 'OP20_WAIT', '磨床等待加工', 25, '', '', 'OP30_LOAD', 2, -1, TRUE, 'OP20_FALLBACK_UNLOAD', '等待 M3600 加工完成,GRINDER→done,进入 holding 挂起等下一件换料交接(handover 推进去清洗);最后一件走 fallback 自行取料');
-- OP20_FALLBACK_UNLOAD: 最后一件自行取料(无后继工件换料时收尾)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(6, 1, 'OP20_FALLBACK_UNLOAD', '磨床取料收尾', 28, '', '', 'OP30_LOAD', 1, -1, FALSE, '', '最后一件:从磨床 done 槽位自行取料,成品落缓存槽释放 robot,清洗步骤重新 acquire 去清洗');
-- OP30_LOAD: 清洗(robot/temp_slot 由 handover 转移或 fallback 取得后重新 acquire
-- 注:清洗模型 = 持料模型——机器人夹持工件在气吹机构(AirBlow-01)工位吹洗(气吹机构无放料位置),
-- M2139 完成时机器人仍持料不释放,carry 去 OP35 决策后的下一步(全检/缓存/换料),
-- 由放料步骤(OP40_LOAD/OP50_LOAD/OP60_EXCHANGE_LOAD)完成时释放 robot
-- acquire AIR_BLOW empty 保证单工位互斥(其他工件不能同时清洗),清洗期间槽位被本 job 持有
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(7, 1, 'OP30_LOAD', '清洗', 40, '', '', 'OP35_DECIDE', 2, -1, FALSE, '', '机器人持料至气吹机构清洗:完成时只释放 temp_slot,robot 不释放(持料模型,生产科室定),carry 去 OP35 决策后的取料/放料步骤');
-- OP35_DECIDE: 全检台容量判断(done→换料优先;空位→放料;满→缓存;全满无done→等待)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(8, 1, 'OP35_DECIDE', '全检台容量判断', 45, '', '', 'OP40_LOAD', 2, -1, FALSE, '', '决策步骤:全检台有检测完成(done)→OP40_EXCHANGE换料;有空位→OP40全检;已满→OP50缓存');
-- OP50_LOAD: 缓存暂存(全检台满时)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(9, 1, 'OP50_LOAD', '缓存暂存', 50, '', '', 'OP50_UNLOAD', 4, -1, FALSE, '', '全检台满时暂存到缓存台,完成后取料回全检');
-- OP50_UNLOAD: 缓存取料回流
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(10, 1, 'OP50_UNLOAD', '缓存取料', 55, '', '', 'OP40_LOAD', 4, -1, FALSE, 'OP40_BATCH_DECIDE', '全检台有空位时从缓存台取料,随后放全检台;被代做跳过时(handover_proxy)直接推进到批次请求决策');
-- OP40_LOAD: 全检台放料(释放 robot/temp_slotM2102 改由满槽或工单最后一件时在 OP40_BATCH_DECIDE/OP40_REQ 发送)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(11, 1, 'OP40_LOAD', '全检台放料', 60, '', '', 'OP40_BATCH_DECIDE', 3, -1, FALSE, '', '放料到全检台空槽位,不逐件发送 M2102(满槽或收尾时才请求检验)');
-- OP40_BATCH_DECIDE: 全检批次请求决策(满槽或工单最后一件 → 发 M2102 请求检验;否则 → 等待批次检测完成)
-- 注:必须保留 occupied<2 → OP40_WAIT 分支——它承担中间件进入等待的关键职责:
-- 满槽(=2)或收尾(remaining=0)由前两条分支处理;未满槽且未收尾时进入 OP40_WAIT
-- 等 M2098 批次广播(由满槽件/最后一件发 M2102 触发),否则中间件决策等待永不被唤醒(死锁)。
-- 不能用恒真分支(occupied>=0):恒真分支触发恒真 warn 且掩盖后续分支不可达的配置错误。
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(31, 1, 'OP40_BATCH_DECIDE', '全检批次请求决策', 61, '', '', 'OP40_WAIT', 3, -1, FALSE, '', '决策:全检台2槽全满(都是待检)或工单最后一件 → OP40_REQ 发M2102;未满槽且未收尾 → OP40_WAIT 等批次检测完成');
-- OP40_EXCHANGE: 全检台一步换料(M2080:机器人从气吹机构取待检件,到全检台取 done 成品+放待检,一次动作)
-- 触发:OP35_DECIDE 检测到全检台有 done 槽位(M2098 已到达)→ 换料,避免成品滞 留、减少机器人空跑
-- 交接:acquire_mode='any' 抢占前任 done 槽位记录 PrevJobIDCOMPLETE 时 handover 收尾前任 job
-- (成品由本 job 取走并 carry 去 OP60_EXCHANGE_LOAD 下料,锁不转移)
-- 后续:next_step_default=OP60_EXCHANGE_LOAD——先放下前任成品并释放 robot/temp_slot
-- 再回 OP40_BATCH_DECIDE 参与批次请求决策(最后一件走换料时必须发 M2102 收尾批次,
-- 否则全检台残留 done 工件永远无人取走,形成死锁)
-- 注意:禁止直接 next=OP40_BATCH_DECIDE——换料 job 持前任成品+robot 锁进决策会锁死全线
-- (决策/等待期间 robot 无法释放,其他 job 全部饿死),必须先下料再决策
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(35, 1, 'OP40_EXCHANGE', '全检台换料', 63, '', '', 'OP60_EXCHANGE_LOAD', 3, -1, FALSE, '', '全检台一步换料:气吹机构取待检件→M2080取done成品+放待检(原位),handover收尾前任job,成品carry去接驳台下料;下料后回批次请求决策');
-- OP40_REQ: 发送 M2102 请求检验,等 M2098 批次检测完成
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(32, 1, 'OP40_REQ', '全检批次请求检验', 62, '', '', 'OP40_UNLOAD', 3, -1, FALSE, '', '满槽或工单最后一件时发送 M2102 请求检验,等 M2098 批次检测完成(广播)');
-- OP40_WAIT: 全检台等待检测
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(12, 1, 'OP40_WAIT', '全检台等待检测', 65, '', '', 'OP40_UNLOAD', 2, -1, FALSE, '', '等待 M2098 批次检测完成信号(广播)');
-- OP40_UNLOAD: 全检台取料
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(13, 1, 'OP40_UNLOAD', '全检台取料', 70, '', '', 'OP60_LOAD', 3, -1, FALSE, '', '从全检台 done 槽位取料:机器人+temp_slot+FULL_CHECK done');
-- OP60_EXCHANGE_LOAD: 换料成品接驳台下料(OP40_EXCHANGE 的专属下一步)
-- 场景:换料完成后机器人夹爪上拿着前任 job 的成品(锁不转移,本 job 持有 robot/temp_slot),
-- 必须先放回接驳台并释放 robot/temp_slot,再回 OP40_BATCH_DECIDE 参与批次决策——
-- 否则持料进决策/等待会锁死 robot 导致全线死锁(2026-08-13 线上 M2089 后全线卡死事故)。
-- 资源/信号/action 与 OP60_LOAD (14) 完全一致,仅 next_step_default 不同(回决策 vs 流程结束)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(37, 1, 'OP60_EXCHANGE_LOAD', '换料成品接驳台下料', 75, '', '', 'OP61_DECIDE', 4, -1, FALSE, '', '换料后把前任成品放回接驳台空槽位,释放 robot/temp_slot;完成后回 OP61_DECIDE 判断缓存台是否需代取二次换料');
-- OP61_DECIDE: 换料下料后缓存回流决策(换料 job 连续代做的入口)
-- 场景:换料 job 把前任成品放接驳台后,缓存台若有待回流件(另一 job 暂存的),
-- 顺路代取并去全检台 2 号位二次换料(放缓存件+换下第二个检测完成件),
-- 一趟机器人完成两次换料两次下料,避免空跑。恒有出路:occupied>=1 → 代取;<1 → 直接回批次决策。
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(39, 1, 'OP61_DECIDE', '换料后缓存回流决策', 64, '', '', 'OP40_BATCH_DECIDE', 3, -1, FALSE, '', '决策:缓存台有待回流件→代取后全检台2号位二次换料;无→直接回批次请求决策');
-- OP50_EXCHANGE_TAKE: 缓存代取(换料 job 代做另一 job 的缓存回流取料)
-- acquire_mode='proxy' 抢占缓存台 occupied 槽位并记录被代做 jobProxyJobID),
-- 供 OP40_EXCHANGE_2ND 的 handover_proxy 交接(槽位归属转移+推进被代做 job)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(40, 1, 'OP50_EXCHANGE_TAKE', '缓存代取', 66, '', '', 'OP40_EXCHANGE_2ND', 4, -1, FALSE, '', '代取缓存台待回流件:M2110取料,acquire_mode=proxy记录被代做jobrobot持料carry去二次换料');
-- OP40_EXCHANGE_2ND: 全检台二次换料(缓存件放2号位 + 换下第二个检测完成件)
-- 完成时 handover 收尾第二个成品 job + handover_proxy 交接被代做 job(槽位归属转移+跳过其缓存取料步骤)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(41, 1, 'OP40_EXCHANGE_2ND', '全检台二次换料', 67, '', '', 'OP60_LOAD_2ND', 3, -1, FALSE, '', '缓存件放全检台2号位(原位换下检测完成件):M2080换料,handover收尾成品job+handover_proxy归属转移给被代做job');
-- OP60_LOAD_2ND: 二次换料成品下料(放 job2 回接驳台,释放锁后回批次决策)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(42, 1, 'OP60_LOAD_2ND', '二次换料成品下料', 68, '', '', 'OP40_BATCH_DECIDE', 4, -1, FALSE, '', '把二次换料换下的成品放回接驳台空槽位,释放 robot/temp_slot;完成后回 OP40_BATCH_DECIDE 发待检信号');
-- OP60_LOAD: 接驳台下料(流程结束)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(14, 1, 'OP60_LOAD', '接驳台下料', 80, '', '', '', 4, -1, FALSE, '', '成品放回接驳台空槽位,next_step_default='''' 表示流程结束');
-- ============================================================================
-- 三、配油盘工艺 (recipe_id=2) 步骤定义
-- ============================================================================
-- OP10_LOAD: 接驳台取料
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(15, 2, 'OP10_LOAD', '接驳台取料', 10, '', '', 'OP25_TURN_LOAD', 2, -1, FALSE, '', '从接驳台取毛坯');
-- OP25_TURN_LOAD: 转换台放料+旋转(PLC自动旋转,M2079含旋转完成)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(16, 2, 'OP25_TURN_LOAD', '转换台放料+旋转', 20, '', '', 'OP25_TURN_UNLOAD', 2, -1, FALSE, '', '放料到转换台,PLC自动旋转,M2079到达后直接取料');
-- OP25_TURN_UNLOAD: 转换台取料
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(17, 2, 'OP25_TURN_UNLOAD', '转换台取料', 30, '', '', 'OP15_DECIDE', 2, -1, FALSE, '', '从转换台 occupied 槽位取料');
-- OP15_DECIDE: 磨床状态决策
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(18, 2, 'OP15_DECIDE', '磨床状态决策', 35, '', '', 'OP20_LOAD', 2, -1, FALSE, '', '决策:磨床 done→换料;磨床 empty→放料;加工中→等待');
-- OP20_EXCHANGE: 磨床一步换料
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(19, 2, 'OP20_EXCHANGE', '磨床换料', 40, '', '', 'OP20_WAIT', 2, -1, FALSE, '', '一步换料:acquire_mode=any 抢占前任工件done槽位,M2050取成品+放毛坯,handover交接');
-- OP20_LOAD: 磨床放料
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(20, 2, 'OP20_LOAD', '磨床放料', 45, '', '', 'OP20_WAIT', 2, -1, FALSE, '', '放料到磨床空槽位');
-- OP20_WAIT: 磨床等待加工(holding + fallback
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(21, 2, 'OP20_WAIT', '磨床等待加工', 50, '', '', 'OP30_LOAD', 2, -1, TRUE, 'OP20_FALLBACK_UNLOAD', '等待 M3600 加工完成,进入 holding 等交接;最后一件走 fallback 自行取料');
-- OP20_FALLBACK_UNLOAD: 最后一件自行取料
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(22, 2, 'OP20_FALLBACK_UNLOAD', '磨床取料收尾', 53, '', '', 'OP30_LOAD', 1, -1, FALSE, '', '最后一件:从磨床 done 槽位自行取料,成品落缓存槽释放 robot,清洗步骤重新 acquire 去清洗');
-- OP30_LOAD: 清洗(同缸体:持料模型,机器人夹持工件吹洗,acquire AIR_BLOW empty 单工位互斥)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(23, 2, 'OP30_LOAD', '清洗', 60, '', '', 'OP35_DECIDE', 2, -1, FALSE, '', '机器人持料至气吹机构清洗:完成时只释放 temp_slot,robot 不释放(持料模型,生产科室定),carry 去 OP35 决策后的取料/放料步骤');
-- OP35_DECIDE: 全检台容量判断(同缸体)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(24, 2, 'OP35_DECIDE', '全检台容量判断', 65, '', '', 'OP40_LOAD', 2, -1, FALSE, '', '决策步骤:全检台有检测完成(done)→OP40_EXCHANGE换料;有空位→OP40全检;已满→OP50缓存');
-- OP50_LOAD: 缓存暂存
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(25, 2, 'OP50_LOAD', '缓存暂存', 70, '', '', 'OP50_UNLOAD', 4, -1, FALSE, '', '全检台满时暂存到缓存台');
-- OP50_UNLOAD: 缓存取料回流
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(26, 2, 'OP50_UNLOAD', '缓存取料', 75, '', '', 'OP40_LOAD', 4, -1, FALSE, 'OP40_BATCH_DECIDE', '全检台有空位时从缓存台取料;被代做跳过时(handover_proxy)直接推进到批次请求决策');
-- OP40_LOAD: 全检台放料
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(27, 2, 'OP40_LOAD', '全检台放料', 80, '', '', 'OP40_BATCH_DECIDE', 3, -1, FALSE, '', '放料到全检台空槽位,不逐件发送 M2102(满槽或收尾时才请求检验)');
-- OP40_BATCH_DECIDE: 全检批次请求决策(满槽或工单最后一件 → 发 M2102 请求检验;否则 → 等待批次检测完成)
-- 注:必须保留 occupied<2 → OP40_WAIT 分支——它承担中间件进入等待的关键职责:
-- 满槽(=2)或收尾(remaining=0)由前两条分支处理;未满槽且未收尾时进入 OP40_WAIT
-- 等 M2098 批次广播(由满槽件/最后一件发 M2102 触发),否则中间件决策等待永不被唤醒(死锁)。
-- 不能用恒真分支(occupied>=0):恒真分支触发恒真 warn 且掩盖后续分支不可达的配置错误。
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(33, 2, 'OP40_BATCH_DECIDE', '全检批次请求决策', 81, '', '', 'OP40_WAIT', 3, -1, FALSE, '', '决策:全检台2槽全满(都是待检)或工单最后一件 → OP40_REQ 发M2102;未满槽且未收尾 → OP40_WAIT 等批次检测完成');
-- OP40_EXCHANGE: 全检台一步换料(配油盘,同缸体;先下料再回批次请求决策,逻辑同缸体)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(36, 2, 'OP40_EXCHANGE', '全检台换料', 83, '', '', 'OP60_EXCHANGE_LOAD', 3, -1, FALSE, '', '全检台一步换料:气吹机构取待检件→M2080取done成品+放待检(原位),handover收尾前任job,成品carry去接驳台下料;下料后回批次请求决策');
-- OP40_REQ: 发送 M2102 请求检验,等 M2098 批次检测完成
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(34, 2, 'OP40_REQ', '全检批次请求检验', 82, '', '', 'OP40_UNLOAD', 3, -1, FALSE, '', '满槽或工单最后一件时发送 M2102 请求检验,等 M2098 批次检测完成(广播)');
-- OP40_WAIT: 全检台等待检测
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(28, 2, 'OP40_WAIT', '全检台等待检测', 85, '', '', 'OP40_UNLOAD', 2, -1, FALSE, '', '等待 M2098 批次检测完成信号(广播)');
-- OP40_UNLOAD: 全检台取料
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(29, 2, 'OP40_UNLOAD', '全检台取料', 90, '', '', 'OP60_LOAD', 3, -1, FALSE, '', '从全检台 done 槽位取料');
-- OP60_EXCHANGE_LOAD: 换料成品接驳台下料(配油盘,同缸体;回 OP40_BATCH_DECIDE 参与批次决策)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(38, 2, 'OP60_EXCHANGE_LOAD', '换料成品接驳台下料', 95, '', '', 'OP61_DECIDE', 4, -1, FALSE, '', '换料后把前任成品放回接驳台空槽位,释放 robot/temp_slot;完成后回 OP61_DECIDE 判断缓存台是否需代取二次换料');
-- OP61_DECIDE: 换料下料后缓存回流决策(配油盘,同缸体)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(43, 2, 'OP61_DECIDE', '换料后缓存回流决策', 84, '', '', 'OP40_BATCH_DECIDE', 3, -1, FALSE, '', '决策:缓存台有待回流件→代取后全检台2号位二次换料;无→直接回批次请求决策');
-- OP50_EXCHANGE_TAKE: 缓存代取(配油盘,同缸体)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(44, 2, 'OP50_EXCHANGE_TAKE', '缓存代取', 86, '', '', 'OP40_EXCHANGE_2ND', 4, -1, FALSE, '', '代取缓存台待回流件:M2110取料,acquire_mode=proxy记录被代做jobrobot持料carry去二次换料');
-- OP40_EXCHANGE_2ND: 全检台二次换料(配油盘,同缸体)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(45, 2, 'OP40_EXCHANGE_2ND', '全检台二次换料', 87, '', '', 'OP60_LOAD_2ND', 3, -1, FALSE, '', '缓存件放全检台2号位(原位换下检测完成件):M2080换料,handover收尾成品job+handover_proxy归属转移给被代做job');
-- OP60_LOAD_2ND: 二次换料成品下料(配油盘,同缸体)
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(46, 2, 'OP60_LOAD_2ND', '二次换料成品下料', 88, '', '', 'OP40_BATCH_DECIDE', 4, -1, FALSE, '', '把二次换料换下的成品放回接驳台空槽位,释放 robot/temp_slot;完成后回 OP40_BATCH_DECIDE 发待检信号');
-- OP60_LOAD: 接驳台下料
INSERT INTO recipe_step (id, recipe_id, step_id, step_name, step_index, step_type, resource_type, next_step_default, priority, timeout_seconds, hold_until_handover, fallback_next_step, "desc") VALUES
(30, 2, 'OP60_LOAD', '接驳台下料', 100, '', '', '', 4, -1, FALSE, '', '成品放回 接驳台');
-- ============================================================================
-- 四、缸体工艺 - 资源需求 (recipe_step_resource)
-- acquire_mode: 'self'=仅本job自持(默认);'any'=可跨job抢占(换料取前任done槽位)
-- ============================================================================
-- OP10_LOAD (1): 接驳台取料 - robot + temp_slot + DOCK occupied
-- 注:去掉旧配方的 GRINDER empty check——换料设计下磨床 done 时也必须取料去换料,
-- check 会阻断换料路径;且换料死锁由 handover 机制解决(不再需要该防死锁 check)。
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(1, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(1, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'),
(1, 'equipment_slot', 'acquire', 'DOCK', 'occupied', 1, 'self', '接驳台有工件可取的槽位');
-- OP15_DECIDE (2): 决策步骤 - 无固定资源需求(由 decision 表驱动)
-- OP20_EXCHANGE (3): 磨床换料 - robot + temp_slot(自持) + GRINDER done(跨job抢占)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(3, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(3, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '工件在缓存槽(本job毛坯,自持)'),
(3, 'equipment_slot', 'acquire', 'GRINDER', 'done', 1, 'any', '磨床加工完成的槽位(跨job抢占前任工件,记录前任job供handover交接)');
-- OP20_LOAD (4): 磨床放料 - robot + GRINDER empty
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(4, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(4, 'equipment_slot', 'acquire', 'GRINDER', 'empty', 1, 'self', '磨床空槽位');
-- OP20_WAIT (5): 磨床等待加工 - check GRINDER occupied(本job槽位)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(5, 'equipment_slot', 'check', 'GRINDER', 'occupied', 1, 'self', '确认工件在磨床上');
-- OP20_FALLBACK_UNLOAD (6): 最后一件取料 - robot + temp_slot + GRINDER done(自持)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(6, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(6, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'),
(6, 'equipment_slot', 'acquire', 'GRINDER', 'done', 1, 'self', '本工件磨床加工完成的槽位');
-- OP30_LOAD (7): 清洗 - acquire robot + temp_slot occupied + AIR_BLOW empty
-- 注:robot 在 acquire 列表内(清洗开始前重新 acquire)——handover 换料交接后成品落缓存槽、robot 已释放,
-- 此处重新 acquire 取缓存槽成品去清洗;acquire 失败(AIR_BLOW 忙)时事务回滚即释放 robot,
-- 避免"等气吹空位时持料"占用 robot 导致其他 job 无法取料(死锁);fallback 路径 robot 自持有幂等通过。
-- 清洗完成后为持料模型:robot 不释放,carry 去下一步(见 recipe_step_action)。
-- acquire AIR_BLOW empty 保证气吹机构单工位互斥;清洗期间槽位被本 job 持有(OCCUPIED+self),
-- 后续取料步骤(OP40/OP50/OP40_EXCHANGE)再取走并释放
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(7, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲(从缓存槽取成品去清洗)'),
(7, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '工件在缓存槽/机器人 手上(robot 由上一环节持有,carry 延续)'),
(7, 'equipment_slot', 'acquire', 'AIR_BLOW', 'empty', 1, 'self', '气吹机构空闲(单工位互斥,清洗期间槽位被本job持有)');
-- OP35_DECIDE (8): 决策步骤 - 无资源
-- OP50_LOAD (9): 缓存暂存 - robot + AIR_BLOW(自持) + CACHE empty(直连暂存,不经缓存槽,不占 temp_slot)
-- 注:temp_slot 在 OP30_LOAD 已释放;robot 清洗完成后 carry 持料(自持有幂等直接通过);AIR_BLOW occupied 自持确认
-- 工件在气吹机构(仅 OP35_DECIDE 来源),放料后释放气吹机构槽位
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(9, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(9, 'equipment_slot', 'acquire', 'AIR_BLOW', 'occupied', 1, 'self', '工件在气吹 机构(清洗完成待取,自持确认)'),
(9, 'equipment_slot', 'acquire', 'CACHE', 'empty', 1, 'self', '缓存台空槽位');
-- OP50_UNLOAD (10): 缓存取料 - robot + temp_slot + FULL_CHECK(empty check) + CACHE(occupied 自持)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(10, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(10, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'),
(10, 'equipment_slot', 'check', 'FULL_CHECK', 'empty', 1, 'self', '全检台有空位才取料'),
(10, 'equipment_slot', 'acquire', 'CACHE', 'occupied', 1, 'self', '本工件在缓存台的槽位');
-- OP40_LOAD (11): 全检台放料 - robot + FULL_CHECK empty(直连放料,不经缓存槽,不占用 temp_slot)
-- 注:清洗完成后机器人持料 carry(持料模型),放件全程机器人手上无缓存需求,
-- 无需 acquire temp_slot;避免与"持料等待"的 job(成品在缓存槽)互抢单把 temp_slot 锁形成死锁。
-- temp_slot 在 OP30_LOAD 已释放;robot 清洗完成后 carry 持料,自持有幂等直接通过
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(11, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(11, 'equipment_slot', 'acquire', 'FULL_CHECK', 'empty', 1, 'self', '全检台空槽 位');
-- OP40_WAIT (12): 全检台等待检测 - acquire FULL_CHECK occupied(自持待检槽位)
-- 注:必须用 acquire 而非 check——换料路径(OP40_EXCHANGE→OP60_EXCHANGE_LOAD)后 job 最近一次 acquire
-- 是 DOCK 下料槽位,check 步骤无分配记录,set_resource {allocated} 兜底会误把 DOCK 置 done
-- acquire 记录本 job 待检槽位分配,{allocated} 精确定位(acquire 幂等标记占用,不改变槽位归属)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(12, 'equipment_slot', 'acquire', 'FULL_CHECK', 'occupied', 1, 'self', '自持本 job 待检槽位(供 set_resource {allocated} 定位)');
-- OP40_REQ (32): 全检批次请求检验 - acquire FULL_CHECK occupied(自持待检槽位,理由同 OP40_WAIT)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(32, 'equipment_slot', 'acquire', 'FULL_CHECK', 'occupied', 1, 'self', '自持本 job 待检槽位(供 set_resource {allocated} 定位)');
-- OP40_EXCHANGE (35): 全检台换料 - robot + temp_slot + AIR_BLOW(自持) + FULL_CHECK done(跨job抢占)
-- 注:工件在气吹机构(OP35_DECIDE 来源),acquire AIR_BLOW occupied 自持确认;
-- 抢占 done 槽位记录 PrevJobIDCOMPLETE 时 handover 收尾前任 job(成品由本 job 带走下料)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(35, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(35, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'),
(35, 'equipment_slot', 'acquire', 'AIR_BLOW', 'occupied', 1, 'self', '工件在气吹机构(待检件,自持确认)'),
(35, 'equipment_slot', 'acquire', 'FULL_CHECK', 'done', 1, 'any', '全检台检测完成的槽位(跨job抢占前任工件,记录前任job供handover收尾)');
-- OP40_EXCHANGE (36): 全检台换料(配油盘,同缸体)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(36, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(36, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'),
(36, 'equipment_slot', 'acquire', 'AIR_BLOW', 'occupied', 1, 'self', '工件在气吹机构(待检件,自持确认)'),
(36, 'equipment_slot', 'acquire', 'FULL_CHECK', 'done', 1, 'any', '全检台检测完成的槽位(跨job抢占前任工件,记录前任job供handover收尾)');
-- OP40_UNLOAD (13): 全检台取料 - robot + temp_slot + FULL_CHECK done
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(13, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(13, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'),
(13, 'equipment_slot', 'acquire', 'FULL_CHECK', 'done', 1, 'self', '全检台检测完成的槽位');
-- OP60_LOAD (14): 接驳台下料 - temp_slot occupied(自持) + DOCK empty
-- 注:robot 不 acquire——OP40_UNLOAD 取料后机器人持料 carry 延续(同 OP30_LOAD/OP40_LOAD 模式),
-- 此时 robot 锁为 busy(本job持有)acquire idle 会自锁;完成动作后由 action 释放 robot。
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(14, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '成品在缓存槽'),
(14, 'equipment_slot', 'acquire', 'DOCK', 'empty', 1, 'self', '接驳台空槽位');
-- OP60_EXCHANGE_LOAD (37): 换料成品接驳台下料 - temp_slot occupied(自持) + DOCK empty(同 OP60_LOAD
-- 注:robot 不 acquire——OP40_EXCHANGE 换料后机器人持前任成品 carry 延续(锁不转移);
-- 完成动作后由 action 释放 robot,解除全线 robot 死锁。
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(37, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '前任成品在缓存槽(换料后锁转移至本job)'),
(37, 'equipment_slot', 'acquire', 'DOCK', 'empty', 1, 'self', '接驳台空槽位');
-- OP61_DECIDE (39): 决策步骤 - 无资源
-- OP50_EXCHANGE_TAKE (40): 缓存代取 - robot + temp_slot + CACHE occupied(跨job代取)
-- acquire_mode='proxy':抢占缓存台 occupied 槽位(其他 job 的待回流件),
-- 记录被代做 jobProxyJobID)供 OP40_EXCHANGE_2ND 的 handover_proxy 交接
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(40, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(40, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'),
(40, 'equipment_slot', 'acquire', 'CACHE', 'occupied', 1, 'proxy', '缓存台待回流件(跨job代取,记录被代做job)');
-- OP40_EXCHANGE_2ND (41): 全检台二次换料 - robot(自持) + temp_slot occupied(自持) + FULL_CHECK done(跨job抢占)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(41, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲(代取后 carry 延续,自持幂等)'),
(41, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '缓存件在机器人手上(自持)'),
(41, 'equipment_slot', 'acquire', 'FULL_CHECK', 'done', 1, 'any', '全检台检测完成的槽位(跨job抢占第二个成品job,记录前任供handover收尾)');
-- OP60_LOAD_2ND (42): 二次换料成品下料 - temp_slot occupied(自持) + DOCK empty(同 OP60_EXCHANGE_LOAD
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(42, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '二次换料成品在缓存槽(自持)'),
(42, 'equipment_slot', 'acquire', 'DOCK', 'empty', 1, 'self', '接驳台空槽位');
-- ============================================================================
-- 五、配油盘工艺 - 资源需求
-- ============================================================================
-- OP10_LOAD (15): 同缸体(无 GRINDER check
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(15, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(15, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'),
(15, 'equipment_slot', 'acquire', 'DOCK', 'occupied', 1, 'self', '接驳台有工件');
-- OP25_TURN_LOAD (16): 转换台放料+旋转 - robot + TURN_TABLE empty
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(16, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(16, 'equipment_slot', 'acquire', 'TURN_TABLE', 'empty', 1, 'self', '转换台空槽位');
-- OP25_TURN_UNLOAD (17): 转换台取料 - robot + temp_slot(自持) + TURN_TABLE occupied
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(17, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(17, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '缓存槽有料(转台事务期间本job保留)'),
(17, 'equipment_slot', 'acquire', 'TURN_TABLE', 'occupied', 1, 'self', '转换台有工件可取');
-- OP15_DECIDE (18): 决策步骤 - 无资源
-- OP20_EXCHANGE (19): 磨床换料 - temp_slot(自持) + GRINDER done(跨job抢占)
-- 注:robot 不 acquire——OP25_TURN_UNLOAD 取料后机器人持毛坯 carry 延续(同缸体 OP30/OP40 模式),
-- 此时 robot 锁为 busy(本job持有)acquire idle 会自锁;换料后由 handover 把锁转移给前任job。
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(19, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '工件在缓存槽(本job毛坯,自持)'),
(19, 'equipment_slot', 'acquire', 'GRINDER', 'done', 1, 'any', '磨床加工完成的槽位(跨job抢占,记录前任job)');
-- OP20_LOAD (20): 磨床放料 - GRINDER emptyrobot 不 acquirecarry 延续,完成后由 action 释放 robot
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(20, 'equipment_slot', 'acquire', 'GRINDER', 'empty', 1, 'self', '磨床空槽位');
-- OP20_WAIT (21): 磨床等待加工 - check GRINDER occupied
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(21, 'equipment_slot', 'check', 'GRINDER', 'occupied', 1, 'self', '确认工件在磨床上');
-- OP20_FALLBACK_UNLOAD (22): 最后一件取料
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(22, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(22, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'),
(22, 'equipment_slot', 'acquire', 'GRINDER', 'done', 1, 'self', '本工件磨床加工完成的槽位');
-- OP30_LOAD (23): 清洗 - acquire robot + temp_slot occupied + AIR_BLOW empty(同缸体:清洗完成后持料模型,robot 不释放)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(23, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲(从缓存槽取成品去清洗)'),
(23, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '工件在缓存槽/机器人手上'),
(23, 'equipment_slot', 'acquire', 'AIR_BLOW', 'empty', 1, 'self', '气吹机构空闲 (单工位互斥,清洗期间槽位被本job持有)');
-- OP35_DECIDE (24): 决策步骤 - 无资源
-- OP50_LOAD (25): 缓存暂存 - robot + AIR_BLOW(自持) + CACHE empty(同缸体,直连暂存不占 temp_slot)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(25, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(25, 'equipment_slot', 'acquire', 'AIR_BLOW', 'occupied', 1, 'self', '工件在气吹机构(清洗完成待取,自持确认)'),
(25, 'equipment_slot', 'acquire', 'CACHE', 'empty', 1, 'self', '缓存台空槽位');
-- OP50_UNLOAD (26): 缓存取料
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(26, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(26, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'),
(26, 'equipment_slot', 'check', 'FULL_CHECK', 'empty', 1, 'self', '全检台有空位才取料'),
(26, 'equipment_slot', 'acquire', 'CACHE', 'occupied', 1, 'self', '本工件在缓存台的槽位');
-- OP40_LOAD (27): 全检台放料 - robot + FULL_CHECK empty(同缸体,直连放料不占 temp_slot)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(27, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(27, 'equipment_slot', 'acquire', 'FULL_CHECK', 'empty', 1, 'self', '全检台空槽 位');
-- OP40_WAIT (28): 全检台等待检测 - acquire FULL_CHECK occupied(自持待检槽位,理由同缸体 OP40_WAIT)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(28, 'equipment_slot', 'acquire', 'FULL_CHECK', 'occupied', 1, 'self', '自持本 job 待检槽位(供 set_resource {allocated} 定位)');
-- OP40_REQ (34): 全检批次请求检验 - acquire FULL_CHECK occupied(自持待检槽位,理由同缸体 OP40_REQ)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(34, 'equipment_slot', 'acquire', 'FULL_CHECK', 'occupied', 1, 'self', '自持本 job 待检槽位(供 set_resource {allocated} 定位)');
-- OP40_UNLOAD (29): 全检台取料
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(29, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(29, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'),
(29, 'equipment_slot', 'acquire', 'FULL_CHECK', 'done', 1, 'self', '全检台检测完成');
-- OP60_LOAD (30): 接驳台下料 - temp_slot occupied(自持) + DOCK emptyrobot 不 acquirecarry 延续,同缸体)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(30, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '成品在缓存槽'),
(30, 'equipment_slot', 'acquire', 'DOCK', 'empty', 1, 'self', '接驳台空槽位');
-- OP60_EXCHANGE_LOAD (38): 换料成品接驳台下料(配油盘,同缸体)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(38, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '前任成品在缓存槽(换料后锁转移至本job)'),
(38, 'equipment_slot', 'acquire', 'DOCK', 'empty', 1, 'self', '接驳台空槽位');
-- OP61_DECIDE (43): 决策步骤 - 无资源
-- OP50_EXCHANGE_TAKE (44): 缓存代取(配油盘,同缸体)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(44, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲'),
(44, 'temp_slot', 'acquire', '', 'free', 1, 'self', '缓存槽空闲'),
(44, 'equipment_slot', 'acquire', 'CACHE', 'occupied', 1, 'proxy', '缓存台待回流件(跨job代取,记录被代做job)');
-- OP40_EXCHANGE_2ND (45): 全检台二次换料(配油盘,同缸体)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(45, 'robot', 'acquire', '', 'idle', 1, 'self', '机器人空闲(代取后 carry 延续,自持幂等)'),
(45, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '缓存件在机器人手上(自持)'),
(45, 'equipment_slot', 'acquire', 'FULL_CHECK', 'done', 1, 'any', '全检台检测完成的槽位(跨job抢占第二个成品job,记录前任供handover收尾)');
-- OP60_LOAD_2ND (46): 二次换料成品下料(配油盘,同缸体)
INSERT INTO recipe_step_resource (recipe_step_id, resource_type, action, equipment_type, expected_status, min_count, acquire_mode, description) VALUES
(46, 'temp_slot', 'acquire', '', 'occupied', 1, 'self', '二次换料成品在缓存槽(自持)'),
(46, 'equipment_slot', 'acquire', 'DOCK', 'empty', 1, 'self', '接驳台空槽位');
-- ============================================================================
-- 六、缸体工艺 - 信号序列 (recipe_step_signal)
-- ============================================================================
-- OP10_LOAD (1): M2022参数 → M2001位置 → M2002号 → M2000取料请求 → 等M2009取料完成
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(1, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型 byte'),
(1, 'DockFetchPos', 'param', '{dock_slot}', 2, 0, 'M2001 接驳台位置号'),
(1, 'DockFetchTray', 'param', '{dock_no}', 3, 1000, 'M2002 接驳台号'),
(1, 'DockFetchReq', 'req', '', 4, 0, 'M2000 取料请求'),
(1, 'DockFetchDone', 'done', '', 0, 0, 'M2009 取料完成 byte');
-- OP15_DECIDE (2): 决策步骤,无信号
-- OP20_EXCHANGE (3): M2022参数 → M2050换料请求 → 等M2059换料完成(PLC一次取成品+放毛坯)
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(3, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022 工件类型'),
(3, 'GrinderExchangeReq', 'req', '', 2, 0, 'M2050 换料请求(取成品+放毛坯一步完成)'),
(3, 'GrinderExchangeDone', 'done', '', 0, 0, 'M2059 换料完成 byte');
-- OP20_LOAD (4): M2022参数 → M2040放料请求 → 等M2049放料完成
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(4, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022 工件类型'),
(4, 'GrinderPlaceReq', 'req', '', 2, 0, 'M2040 放料请求'),
(4, 'GrinderPlaceDone', 'done', '', 0, 0, 'M2049 放料完成 byte');
-- OP20_WAIT (5): 只等 M3600.0,不发任何请求
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(5, 'GrinderMachiningDone', 'done', '', 0, 0, 'M3600.0 加工完成 bool');
-- OP20_FALLBACK_UNLOAD (6): M2022参数 → M2030取料请求 → 等M2039取料完成
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(6, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022 工件类型'),
(6, 'GrinderFetchReq', 'req', '', 2, 0, 'M2030 取料请求'),
(6, 'GrinderFetchDone', 'done', '', 0, 0, 'M2039 取料完成 byte');
-- OP30_LOAD (7): M2022参数 → M2130清洗请求 → 等M2139清洗完成
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(7, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022 工件类型'),
(7, 'WashStartReq', 'req', '', 2, 0, 'M2130 清洗请求'),
(7, 'AirBlowCompleteDone', 'done', '', 0, 0, 'M2139 清洗完成 byte');
-- OP35_DECIDE (8): 决策步骤,无信号
-- OP50_LOAD (9): M2022→M2121位置→M2120放料→等M2129放料完成
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(9, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'),
(9, 'CachePlacePos', 'param', '{allocated_slot}', 2, 1000, 'M2121 缓存台位置号'),
(9, 'CachePlaceReq', 'req', '', 3, 0, 'M2120 放料请求'),
(9, 'CachePlaceDone', 'done', '', 0, 0, 'M2129 放料完成 byte');
-- OP50_UNLOAD (10): M2022→M2111位置→M2110取料→等M2119取料完成
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(10, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'),
(10, 'CacheFetchPos', 'param', '{allocated_slot}', 2, 1000, 'M2111 缓存台取料位置号'),
(10, 'CacheFetchReq', 'req', '', 3, 0, 'M2110 取料请求'),
(10, 'CacheFetchDone', 'done', '', 0, 0, 'M2119 取料完成 byte');
-- OP40_LOAD (11): M2022参数 → M2101位置 → M2100放料请求 → 等M2109放料完成
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(11, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'),
(11, 'FullCheckPlacePos', 'param', '{allocated_slot}', 2, 1000, 'M2101 全检台放位置号'),
(11, 'FullCheckPlaceReq', 'req', '', 3, 0, 'M2100 放料请求'),
(11, 'FullCheckPlaceDone', 'done', '', 0, 0, 'M2109 放料完成 byte');
-- OP40_WAIT (12): 只等 M2098 检测完成(广播:一批多件同时完成)
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, broadcast, description) VALUES
(12, 'FullCheckInspectDone', 'done', '', 0, 0, TRUE, 'M2098 检测完成 byte(广播:一批多件同时完成)');
-- OP40_REQ (32): 满槽或工单最后一件时发送 M2102 请求检验,等 M2098 批次检测完成(广播)
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, broadcast, description) VALUES
(32, 'CameraWorkType', 'param', '{product_type}', 1, 1000, FALSE, 'M2022 工件类型'),
(32, 'FullCheckPlaceDoneRequestInspect', 'req', '', 2, 0, FALSE, 'M2102 软件_待检放料完成请求检验(满槽或工单最后一件时发送)'),
(32, 'FullCheckInspectDone', 'done', '', 0, 0, TRUE, 'M2098 批次检测完成(广播)');
-- OP40_EXCHANGE (35): M2022参数 → M2081取位置(原位) → M2082放位置(原位) → M2080换料请求 → 等M2089换料完成
-- 注:M2081/M2082 均写 {allocated_slot}(抢占的 done 槽位)→ 原位换料:取 done 成品后放待检到同一槽位
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(35, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'),
(35, 'FullCheckExchangeFetchPos', 'param', '{allocated_slot}', 2, 0, 'M2081 全检台取位置号(done 槽位)'),
(35, 'FullCheckExchangePlacePos', 'param', '{allocated_slot}', 3, 1000, 'M2082 全检台放位置号(原位)'),
(35, 'FullCheckExchangeReq', 'req', '', 4, 0, 'M2080 换料请求'),
(35, 'FullCheckExchangeDone', 'done', '', 0, 0, 'M2089 换料完成 byte');
-- OP40_EXCHANGE (36): 全检台换料(配油盘,同缸体)
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(36, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'),
(36, 'FullCheckExchangeFetchPos', 'param', '{allocated_slot}', 2, 0, 'M2081 全检台取位置号(done 槽位)'),
(36, 'FullCheckExchangePlacePos', 'param', '{allocated_slot}', 3, 1000, 'M2082 全检台放位置号(原位)'),
(36, 'FullCheckExchangeReq', 'req', '', 4, 0, 'M2080 换料请求'),
(36, 'FullCheckExchangeDone', 'done', '', 0, 0, 'M2089 换料完成 byte');
-- OP40_UNLOAD (13): M2022参数 → M2090取料请求+M2091位置 → 等M2099取料完成
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(13, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'),
(13, 'FullCheckFetchPos', 'param', '{allocated_slot}', 2, 1000, 'M2091 全检台取料位置号'),
(13, 'FullCheckFetchReq', 'req', '', 3, 0, 'M2090 取料请求'),
(13, 'FullCheckFetchDone', 'done', '', 0, 0, 'M2099 取料完成 byte');
-- OP60_LOAD (14): M2022参数 → M2011位置 → M2012号 → M2010放料请求 → 等M2019放料完成
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(14, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'),
(14, 'DockPlacePos', 'param', '{dock_slot}', 2, 0, 'M2011 接驳台位置号'),
(14, 'DockPlaceTray', 'param', '{dock_no}', 3, 1000, 'M2012 接驳台号'),
(14, 'DockPlaceReq', 'req', '', 4, 0, 'M2010 放料请求'),
(14, 'DockPlaceDone', 'done', '', 0, 0, 'M2019 放料完成 byte');
-- OP60_EXCHANGE_LOAD (37): 换料成品接驳台下料,信号序列同 OP60_LOADM2022→M2011→M2012→M2010→等M2019
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(37, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'),
(37, 'DockPlacePos', 'param', '{allocated_slot}', 2, 0, 'M2011 接驳台位置号(实际分配槽位,与 acquire 一致)'),
(37, 'DockPlaceTray', 'param', '{dock_no}', 3, 1000, 'M2012 接驳台号'),
(37, 'DockPlaceReq', 'req', '', 4, 0, 'M2010 放料请求'),
(37, 'DockPlaceDone', 'done', '', 0, 0, 'M2019 放料完成 byte');
-- OP61_DECIDE (39): 决策步骤,无信号
-- OP50_EXCHANGE_TAKE (40): 缓存代取 - M2022→M2111位置→M2110取料→等M2119(同 OP50_UNLOAD
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(40, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'),
(40, 'CacheFetchPos', 'param', '{allocated_slot}', 2, 1000, 'M2111 缓存台取料位置号'),
(40, 'CacheFetchReq', 'req', '', 3, 0, 'M2110 取料请求'),
(40, 'CacheFetchDone', 'done', '', 0, 0, 'M2119 取料完成 byte');
-- OP40_EXCHANGE_2ND (41): M2022→M2081取位置→M2082放位置→M2080换料→等M2089(同 OP40_EXCHANGE,原位换料)
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(41, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'),
(41, 'FullCheckExchangeFetchPos', 'param', '{allocated_slot}', 2, 0, 'M2081 全检台取位置号(done 槽位)'),
(41, 'FullCheckExchangePlacePos', 'param', '{allocated_slot}', 3, 1000, 'M2082 全检台放位置号(原位)'),
(41, 'FullCheckExchangeReq', 'req', '', 4, 0, 'M2080 换料请求'),
(41, 'FullCheckExchangeDone', 'done', '', 0, 0, 'M2089 换料完成 byte');
-- OP60_LOAD_2ND (42): 信号序列同 OP60_EXCHANGE_LOADM2022→M2011→M2012→M2010→等M2019
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(42, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'),
(42, 'DockPlacePos', 'param', '{allocated_slot}', 2, 0, 'M2011 接驳台位置号(实际分配槽位,与 acquire 一致)'),
(42, 'DockPlaceTray', 'param', '{dock_no}', 3, 1000, 'M2012 接驳台号'),
(42, 'DockPlaceReq', 'req', '', 4, 0, 'M2010 放料请求'),
(42, 'DockPlaceDone', 'done', '', 0, 0, 'M2019 放料完成 byte');
-- ============================================================================
-- 七、配油盘工艺 - 信号序列
-- ============================================================================
-- OP10_LOAD (15): 同缸体
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(15, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'),
(15, 'DockFetchPos', 'param', '{dock_slot}', 2, 0, 'M2001'),
(15, 'DockFetchTray', 'param', '{dock_no}', 3, 1000, 'M2002'),
(15, 'DockFetchReq', 'req', '', 4, 0, 'M2000'),
(15, 'DockFetchDone', 'done', '', 0, 0, 'M2009');
-- OP25_TURN_LOAD (16): 转换台放料+旋转 - M2022→M2070→等M2079(含旋转完成)
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(16, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022'),
(16, 'TurnTablePlaceReq', 'req', '', 2, 0, 'M2070 放料请求,PLC自动旋转'),
(16, 'TurnTablePlaceDone', 'done', '', 0, 0, 'M2079 放料+旋转完成 byte');
-- OP25_TURN_UNLOAD (17): 转换台取料 - M2022→M2060→等M2069
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(17, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022'),
(17, 'TurnTableFetchReq', 'req', '', 2, 0, 'M2060 取料请求'),
(17, 'TurnTableFetchDone', 'done', '', 0, 0, 'M2069 取料完成 byte');
-- OP15_DECIDE (18): 决策步骤,无信号
-- OP20_EXCHANGE (19): M2022→M2050换料→等M2059
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(19, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022'),
(19, 'GrinderExchangeReq', 'req', '', 2, 0, 'M2050 换料请求(取成品+放毛坯一步完成)'),
(19, 'GrinderExchangeDone', 'done', '', 0, 0, 'M2059 换料完成 byte');
-- OP20_LOAD (20): 磨床放料
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(20, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022'),
(20, 'GrinderPlaceReq', 'req', '', 2, 0, 'M2040'),
(20, 'GrinderPlaceDone', 'done', '', 0, 0, 'M2049');
-- OP20_WAIT (21): 等 M3600
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(21, 'GrinderMachiningDone', 'done', '', 0, 0, 'M3600.0');
-- OP20_FALLBACK_UNLOAD (22): 磨床取料收尾
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(22, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022'),
(22, 'GrinderFetchReq', 'req', '', 2, 0, 'M2030'),
(22, 'GrinderFetchDone', 'done', '', 0, 0, 'M2039');
-- OP30_LOAD (23): 清洗
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(23, 'CameraWorkType', 'param', '{product_type}', 1, 1000, 'M2022'),
(23, 'WashStartReq', 'req', '', 2, 0, 'M2130'),
(23, 'AirBlowCompleteDone', 'done', '', 0, 0, 'M2139');
-- OP35_DECIDE (24): 决策步骤,无信号
-- OP50_LOAD (25): 缓存暂存
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(25, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'),
(25, 'CachePlacePos', 'param', '{allocated_slot}', 2, 1000, 'M2121'),
(25, 'CachePlaceReq', 'req', '', 3, 0, 'M2120'),
(25, 'CachePlaceDone', 'done', '', 0, 0, 'M2129');
-- OP50_UNLOAD (26): 缓存取料
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(26, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'),
(26, 'CacheFetchPos', 'param', '{allocated_slot}', 2, 1000, 'M2111'),
(26, 'CacheFetchReq', 'req', '', 3, 0, 'M2110'),
(26, 'CacheFetchDone', 'done', '', 0, 0, 'M2119');
-- OP40_LOAD (27): 全检台放料
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(27, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'),
(27, 'FullCheckPlacePos', 'param', '{allocated_slot}', 2, 1000, 'M2101'),
(27, 'FullCheckPlaceReq', 'req', '', 3, 0, 'M2100'),
(27, 'FullCheckPlaceDone', 'done', '', 0, 0, 'M2109');
-- OP40_WAIT (28): 等 M2098(广播:一批多件同时完成)
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, broadcast, description) VALUES
(28, 'FullCheckInspectDone', 'done', '', 0, 0, TRUE, 'M2098(广播:一批多件同时完成)');
-- OP40_REQ (34): 满槽或工单最后一件时发送 M2102 请求检验,等 M2098 批次检测完成(广播)
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, broadcast, description) VALUES
(34, 'CameraWorkType', 'param', '{product_type}', 1, 1000, FALSE, 'M2022'),
(34, 'FullCheckPlaceDoneRequestInspect', 'req', '', 2, 0, FALSE, 'M2102 软件_待检放料完成请求检验(满槽或工单最后一件时发送)'),
(34, 'FullCheckInspectDone', 'done', '', 0, 0, TRUE, 'M2098 批次检测完成(广播)');
-- OP40_UNLOAD (29): 全检台取料
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(29, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'),
(29, 'FullCheckFetchPos', 'param', '{allocated_slot}', 2, 1000, 'M2091'),
(29, 'FullCheckFetchReq', 'req', '', 3, 0, 'M2090'),
(29, 'FullCheckFetchDone', 'done', '', 0, 0, 'M2099');
-- OP60_LOAD (30): 接驳台下料
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(30, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'),
(30, 'DockPlacePos', 'param', '{dock_slot}', 2, 0, 'M2011'),
(30, 'DockPlaceTray', 'param', '{dock_no}', 3, 1000, 'M2012'),
(30, 'DockPlaceReq', 'req', '', 4, 0, 'M2010'),
(30, 'DockPlaceDone', 'done', '', 0, 0, 'M2019');
-- OP60_EXCHANGE_LOAD (38): 换料成品接驳台下料(配油盘,信号序列同 OP60_LOAD)
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(38, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'),
(38, 'DockPlacePos', 'param', '{allocated_slot}', 2, 0, 'M2011'),
(38, 'DockPlaceTray', 'param', '{dock_no}', 3, 1000, 'M2012'),
(38, 'DockPlaceReq', 'req', '', 4, 0, 'M2010'),
(38, 'DockPlaceDone', 'done', '', 0, 0, 'M2019');
-- OP61_DECIDE (43): 决策步骤,无信号
-- OP50_EXCHANGE_TAKE (44): 缓存代取(配油盘,同缸体)
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(44, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'),
(44, 'CacheFetchPos', 'param', '{allocated_slot}', 2, 1000, 'M2111 缓存台取料位置号'),
(44, 'CacheFetchReq', 'req', '', 3, 0, 'M2110 取料请求'),
(44, 'CacheFetchDone', 'done', '', 0, 0, 'M2119 取料完成 byte');
-- OP40_EXCHANGE_2ND (45): 全检台二次换料(配油盘,同缸体)
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(45, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022 工件类型'),
(45, 'FullCheckExchangeFetchPos', 'param', '{allocated_slot}', 2, 0, 'M2081 全检台取位置号(done 槽位)'),
(45, 'FullCheckExchangePlacePos', 'param', '{allocated_slot}', 3, 1000, 'M2082 全检台放位置号(原位)'),
(45, 'FullCheckExchangeReq', 'req', '', 4, 0, 'M2080 换料请求'),
(45, 'FullCheckExchangeDone', 'done', '', 0, 0, 'M2089 换料完成 byte');
-- OP60_LOAD_2ND (46): 信号序列同 OP60_EXCHANGE_LOAD(配油盘)
INSERT INTO recipe_step_signal (recipe_step_id, signal_name, signal_role, param_value_expr, sort_order, wait_after_ms, description) VALUES
(46, 'CameraWorkType', 'param', '{product_type}', 1, 0, 'M2022'),
(46, 'DockPlacePos', 'param', '{allocated_slot}', 2, 0, 'M2011'),
(46, 'DockPlaceTray', 'param', '{dock_no}', 3, 1000, 'M2012'),
(46, 'DockPlaceReq', 'req', '', 4, 0, 'M2010'),
(46, 'DockPlaceDone', 'done', '', 0, 0, 'M2019');
-- ============================================================================
-- 八、缸体工艺 - 后置操作 (recipe_step_action)
-- ============================================================================
-- OP10_LOAD (1): 取料完成 → 释放 robot + temp_slot→occupied + DOCK→empty
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(1, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'),
(1, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 2, '缓存槽→occupied(工件在缓存槽)'),
(1, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 3, 'DOCK槽位→empty(取走工件)');
-- OP15_DECIDE (2): 决策步骤 - 由 recipe_step_decision 驱动跳转,action 留空
-- OP20_EXCHANGE (3): 换料完成 → GRINDER→occupied(本job毛坯上磨床) + handover(锁转移+推进前任去清洗)+ 释放 robot
-- 注:GRINDER done 槽位已被 acquire 置 OCCUPIED/current_job_id=本jobset_resource 幂等确认;
-- handover 只把 temp_slot 锁转移给前任 job(成品落缓存槽),robot 随即释放归位——
-- 前任 job 的清洗步骤(OP30_LOAD)自行 acquire robot,避免"持料空等"占用 robot 导致其他 job 无法取料(死锁)。
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(3, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 1, 'GRINDER→occupied(本job毛坯已上磨床加工)'),
(3, 'handover', '', '', '', 2, '换料交接:temp_slot 锁转移给前任job(成品落缓存槽),推进其去清洗'),
(3, 'release_resource', 'robot', 'robot', '', 3, '释放机器人(成品已在缓存槽,机器人归位)');
-- OP20_LOAD (4): 放料完成 → 释放 robot + temp_slot + GRINDER→occupied
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(4, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'),
(4, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽(工件在磨床上)'),
(4, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'GRINDER→occupied(工件在磨床加工中)');
-- OP20_WAIT (5): M3600 到达 → GRINDER→done(进入 holding 等交接/收尾)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(5, 'set_resource', 'equipment_slot', '{allocated}', 'done', 1, 'GRINDER→done(加工完成,等待换料交接)');
-- OP20_FALLBACK_UNLOAD (6): 取料完成 → temp_slot→occupied + GRINDER→empty + 释放 robot(成品落缓存槽,机器人归位)
-- 注:成品放下后 robot 释放,清洗步骤(OP30_LOAD)自行 acquire robot
-- 避免最后一件持料空等 AIR_BLOW 时占用 robot,导致其他 job 无法取料(死锁)。
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(6, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied(成品在缓存槽/机器人手上)'),
(6, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'GRINDER→empty (成品已取出,磨床空)'),
(6, 'release_resource', 'robot', 'robot', '', 3, '释放机器人(成品已在缓存槽,机器人归位)');
-- OP30_LOAD (7): 清洗完成 → 只释放 temp_slot(持料模型:气吹时机器人持料不放,无放料位置;
-- robot 由放料步骤 OP40_LOAD/OP50_LOAD/OP60_EXCHANGE_LOAD 完成时释放,carry 模式自持有幂等)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(7, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽(清洗后释放,后续步骤重新 acquire)');
-- OP50_LOAD (9): 缓存暂存完成 → 释放 robot + CACHE→occupied + 气吹机构→empty(工件已取走)
-- 注:release temp_slot 为尽力清理(本步骤不 acquire,回流/直连双路径持有状态不同),
-- 锁空闲或他人持有时引擎均跳过不报错,由真正持有者释放
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(9, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'),
(9, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽(工件在缓存台)'),
(9, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'CACHE→occupied(工件暂存在缓存台)'),
(9, 'set_resource', 'equipment_slot', 'AIR_BLOW:1', 'empty', 4, '气吹机构→empty(工件已从气吹机构取走)');
-- OP50_UNLOAD (10): 缓存取料完成 → temp_slot→occupied + CACHE→emptyrobot 持料去全检)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(10, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied(工件在机器人手上)'),
(10, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'CACHE→empty(工件已取走)');
-- OP40_LOAD (11): 全检放料完成 → 释放 robot + FULL_CHECK→occupied + 气吹机构→empty
-- 注:不再逐件发送 M2102——请求检验改由 OP40_BATCH_DECIDE 决策(满槽或工单收尾)后由 OP40_REQ 发送;
-- 回流路径(OP50_UNLOAD 来源)工件在机器人手上,气吹机构本就 empty,set empty 幂等无害;
-- release temp_slot 为尽力清理(直连路径不持有,回流路径 carry 持有,引擎对非持有跳过不报错)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(11, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'),
(11, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽(工件在全检台)'),
(11, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'FULL_CHECK→occupied(工件待检测)'),
(11, 'set_resource', 'equipment_slot', 'AIR_BLOW:1', 'empty', 4, '气吹机构→empty(工件已从气吹机构取走)');
-- OP40_WAIT (12): M2098 到达 → FULL_CHECK→done
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(12, 'set_resource', 'equipment_slot', '{allocated}', 'done', 1, 'FULL_CHECK→done(检测完成,等待取料)');
-- OP40_REQ (32): M2098 批次检测完成到达 → FULL_CHECK→done(本工件检测完成,等待取料)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(32, 'set_resource', 'equipment_slot', '{allocated}', 'done', 1, 'FULL_CHECK→done(本工件检测完成,等待取料)');
-- OP40_EXCHANGE (35): 换料完成 → FULL_CHECK→occupied(待检件已放) + 气吹机构→empty + handover(收尾前任 job
-- 注:不释放 robot/temp_slot——成品在机器人手上 carry 去 OP60_LOAD 下料;
-- handover 分支 3 收尾前任 job(跳过取料,成品由本 job 负责下料)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(35, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 1, 'FULL_CHECK→occupied(本job待检件已放,原位)'),
(35, 'set_resource', 'equipment_slot', 'AIR_BLOW:1', 'empty', 2, '气吹机构→empty(待检件已取走)'),
(35, 'handover', '', '', '', 3, '换料交接:前任job跳过取料直接收尾(成品由本job带去下料,锁不转移)');
-- OP40_EXCHANGE (36): 全检台换料(配油盘,同缸体)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(36, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 1, 'FULL_CHECK→occupied(本job待检件已放,原位)'),
(36, 'set_resource', 'equipment_slot', 'AIR_BLOW:1', 'empty', 2, '气吹机构→empty(待检件已取走)'),
(36, 'handover', '', '', '', 3, '换料交接:前任job跳过取料直接收尾(成品由本job带去下料,锁不转移)');
-- OP40_UNLOAD (13): 全检取料完成 → temp_slot→occupied + FULL_CHECK→emptyrobot 持料去下料)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(13, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied(成品在机器人手上)'),
(13, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'FULL_CHECK→empty(工件已取走)');
-- OP60_LOAD (14): 下料完成 → 释放 robot + temp_slot + DOCK→occupied(流程结束)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(14, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'),
(14, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'),
(14, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'DOCK→occupied(成品已放回接驳台,流程结束)');
-- OP60_EXCHANGE_LOAD (37): 换料下料完成 → 释放 robot + temp_slot + DOCK→occupied(回 OP40_BATCH_DECIDE 参与批次决策)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(37, 'release_resource', 'robot', 'robot', '', 1, '释放机器人(解除全线 robot 死锁)'),
(37, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'),
(37, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'DOCK→occupied(前任成品已放回接驳台)');
-- OP61_DECIDE (39): 决策步骤 - action 留空
-- OP50_EXCHANGE_TAKE (40): 缓存代取完成 → temp_slot→occupied + CACHE→emptyrobot 持料去二次换料)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(40, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied(缓存件在机器人手上)'),
(40, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'CACHE→empty(缓存件已代取走)');
-- OP40_EXCHANGE_2ND (41): 二次换料完成 → FULL_CHECK→occupied + handover(收尾第二个成品job+ handover_proxy(归属转移给被代做job
-- 注:不释放 robot/temp_slot——成品在机器人手上 carry 去 OP60_LOAD_2ND 下料;
-- handover 分支 3 收尾成品 job(跳过取料,成品由本 job 负责下料);
-- handover_proxy 把 2 号位槽位归属改为被代做 job 并推进其跳过缓存取料步骤
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(41, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 1, 'FULL_CHECK→occupied(缓存件已放2号位,原位)'),
(41, 'handover', '', '', '', 2, '换料交接:第二个成品job跳过取料直接收尾(成品由本job带去下料,锁不转移)'),
(41, 'handover_proxy', '', '', '', 3, '代做交接:槽位归属转移给被代做job并推进其跳过缓存取料步骤');
-- OP60_LOAD_2ND (42): 二次换料下料完成 → 释放 robot + temp_slot + DOCK→occupied(回 OP40_BATCH_DECIDE 发待检信号)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(42, 'release_resource', 'robot', 'robot', '', 1, '释放机器人(解除全线 robot 死锁)'),
(42, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'),
(42, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'DOCK→occupied(二次换料成品已放回接驳台)');
-- ============================================================================
-- 九、配油盘工艺 - 后置操作 (recipe_step_action)
-- ============================================================================
-- OP10_LOAD (15): 同缸体
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(15, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'),
(15, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 2, '缓存槽→occupied'),
(15, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 3, 'DOCK槽位→empty');
-- OP25_TURN_LOAD (16): 放料+旋转完成 → 释放 robot + TURN_TABLE→occupied
-- 注:temp_slot 不释放——转台单槽位,旋转期间本工件必须保留缓存槽(机器人手位)占有,
-- 防止其他工件抢占 temp_slot 后等待转台空位,与转台持有者形成循环等待死锁(与缸体从上料到磨床一直持有 temp_slot 同理)。
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(16, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'),
(16, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 2, 'TURN_TABLE→occupied(工件已旋转)');
-- OP25_TURN_UNLOAD (17): 转换台取料完成 → temp_slot→occupied + TURN_TABLE→emptyrobot 持料去磨床)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(17, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied(工件在机器人手上)'),
(17, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'TURN_TABLE→empty(工件已取走)');
-- OP20_EXCHANGE (19): 换料完成 → GRINDER→occupied + handovertemp_slot 转移)+ 释放 robot(同缸体)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(19, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 1, 'GRINDER→occupied(本job毛坯已上磨床加工)'),
(19, 'handover', '', '', '', 2, '换料交接:temp_slot 锁转移给前任job(成品落缓存槽),推进其去清洗'),
(19, 'release_resource', 'robot', 'robot', '', 3, '释放机器人(成品已在缓存槽,机器人归位)');
-- OP20_LOAD (20): 放料完成 → 释放 robot + temp_slot + GRINDER→occupied
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(20, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'),
(20, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'),
(20, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'GRINDER→occupied');
-- OP20_WAIT (21): M3600 到达 → GRINDER→done(进入 holding
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(21, 'set_resource', 'equipment_slot', '{allocated}', 'done', 1, 'GRINDER→done(加工完成,等待换料交接)');
-- OP20_FALLBACK_UNLOAD (22): 取料完成 → temp_slot→occupied + GRINDER→empty + 释放 robot(同缸体)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(22, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied'),
(22, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'GRINDER→empty'),
(22, 'release_resource', 'robot', 'robot', '', 3, '释放机器人(成品已在缓存槽,机器人归位)');
-- OP30_LOAD (23): 清洗完成 → 只释放 temp_slot(气吹时机器人持料不放,无放料位置;
-- robot 由放料步骤 OP40_LOAD/OP50_LOAD/OP60_EXCHANGE_LOAD 完成时释放,carry 模式自持有幂等)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(23, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽(清洗后释放,后续步骤重新 acquire)');
-- OP50_LOAD (25): 缓存暂存完成 → 释放 robot + CACHE→occupied + 气吹机构→empty(同缸体;release temp_slot 为尽力清理)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(25, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'),
(25, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'),
(25, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'CACHE→occupied'),
(25, 'set_resource', 'equipment_slot', 'AIR_BLOW:1', 'empty', 4, '气吹机构→empty(工件已取走)');
-- OP50_UNLOAD (26): 缓存取料完成 → temp_slot→occupied + CACHE→empty
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(26, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied'),
(26, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'CACHE→empty');
-- OP40_LOAD (27): 全检放料完成 → 释放 robot + FULL_CHECK→occupied + 气吹机构→empty(同缸体;release temp_slot 为尽力清理)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(27, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'),
(27, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'),
(27, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'FULL_CHECK→occupied'),
(27, 'set_resource', 'equipment_slot', 'AIR_BLOW:1', 'empty', 4, '气吹机构→empty(工件已从气吹机构取走)');
-- OP40_WAIT (28): M2098 到达 → FULL_CHECK→done
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(28, 'set_resource', 'equipment_slot', '{allocated}', 'done', 1, 'FULL_CHECK→done');
-- OP40_REQ (34): M2098 批次检测完成到达 → FULL_CHECK→done(本工件检测完成,等待取料)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(34, 'set_resource', 'equipment_slot', '{allocated}', 'done', 1, 'FULL_CHECK→done(本工件检测完成,等待取料)');
-- OP40_UNLOAD (29): 全检取料完成 → temp_slot→occupied + FULL_CHECK→empty
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(29, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied'),
(29, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'FULL_CHECK→empty');
-- OP60_LOAD (30): 下料完成 → 释放 robot + temp_slot + DOCK→occupied(流程结束)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(30, 'release_resource', 'robot', 'robot', '', 1, '释放机器人'),
(30, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'),
(30, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'DOCK→occupied(流程结束)');
-- OP60_EXCHANGE_LOAD (38): 换料下料完成 → 释放 robot + temp_slot + DOCK→occupied(配油盘,回 OP40_BATCH_DECIDE
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(38, 'release_resource', 'robot', 'robot', '', 1, '释放机器人(解除全线 robot 死锁)'),
(38, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'),
(38, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'DOCK→occupied(前任成品已放回接驳台)');
-- OP61_DECIDE (43): 决策步骤 - action 留空
-- OP50_EXCHANGE_TAKE (44): 缓存代取完成 → temp_slot→occupied + CACHE→empty(配油盘,同缸体)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(44, 'set_resource', 'resource_lock', 'temp_slot', 'occupied', 1, '缓存槽→occupied(缓存件在机器人手上)'),
(44, 'set_resource', 'equipment_slot', '{allocated}', 'empty', 2, 'CACHE→empty(缓存件已代取走)');
-- OP40_EXCHANGE_2ND (45): 二次换料完成 → FULL_CHECK→occupied + handover + handover_proxy(配油盘,同缸体)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(45, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 1, 'FULL_CHECK→occupied(缓存件已放2号位,原位)'),
(45, 'handover', '', '', '', 2, '换料交接:第二个成品job跳过取料直接收尾(成品由本job带去下料,锁不转移)'),
(45, 'handover_proxy', '', '', '', 3, '代做交接:槽位归属转移给被代做job并推进其跳过缓存取料步骤');
-- OP60_LOAD_2ND (46): 二次换料下料完成 → 释放 robot + temp_slot + DOCK→occupied(配油盘,同缸体)
INSERT INTO recipe_step_action (recipe_step_id, action_type, resource_type, resource_key, target_status, sort_order, description) VALUES
(46, 'release_resource', 'robot', 'robot', '', 1, '释放机器人(解除全线 robot 死锁)'),
(46, 'release_resource', 'temp_slot', 'temp_slot', '', 2, '释放缓存槽'),
(46, 'set_resource', 'equipment_slot', '{allocated}', 'occupied', 3, 'DOCK→occupied(二次换料成品已放回接驳台)');
-- ============================================================================
-- 十、决策分支 (recipe_step_decision)
-- ============================================================================
-- 缸体 OP15_DECIDE (2): 磨床有 done 槽位→换料;否则磨床空→放料;加工中→等待(不匹配任何分支时原地等待)
INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES
(2, 1, 'GRINDER', 'done', '>=', 1, 'OP20_EXCHANGE', '磨床有磨好的成品→一步换料(跨job交接)'),
(2, 2, 'GRINDER', 'empty', '>=', 1, 'OP20_LOAD', '磨床空→直接放料');
-- 缸体 OP35_DECIDE (8): done→换料优先(避免成品滞留);空位→全检放料;全检台满→缓存暂存;全都不满足→等待
INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES
(8, 1, 'FULL_CHECK', 'done', '>=', 1, 'OP40_EXCHANGE', '全检台有检测完成→一步换料(跨job交接:取done成品+放待检原位,避免成品滞留)'),
(8, 2, 'FULL_CHECK', 'empty', '>=', 1, 'OP40_LOAD', '全检台有空位→全检放料'),
(8, 3, 'CACHE', 'empty', '>=', 1, 'OP50_LOAD', '全检台满→缓存暂存');
-- 配油盘 OP15_DECIDE (18)
INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES
(18, 1, 'GRINDER', 'done', '>=', 1, 'OP20_EXCHANGE', '磨床有磨好的成品→一步换料'),
(18, 2, 'GRINDER', 'empty', '>=', 1, 'OP20_LOAD', '磨床空→直接放料');
-- 配油盘 OP35_DECIDE (24): 同缸体(done→换料优先;空位→全检;满→缓存)
INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES
(24, 1, 'FULL_CHECK', 'done', '>=', 1, 'OP40_EXCHANGE', '全检台有检测完成→一步换料(跨job交接:取done成品+放待检原位,避免成品滞留)'),
(24, 2, 'FULL_CHECK', 'empty', '>=', 1, 'OP40_LOAD', '全检台有空位→全检放料'),
(24, 3, 'CACHE', 'empty', '>=', 1, 'OP50_LOAD', '全检台满→缓存暂存');
-- 缸体 OP40_BATCH_DECIDE (31): 满槽或工单最后一件 → OP40_REQ 发 M2102;未满槽且未收尾 → OP40_WAIT 等批次广播
-- 注:occupied<2 分支承担中间件进入等待的关键职责——不满批场景(件数<2)中间件决策等待
-- 永不被唤醒(occupied 永不达 2 且 remaining>0),必须经 OP40_WAIT 等 M2098 广播
-- (由满槽件/最后一件发 M2102 触发)。不能用恒真分支(occupied>=0):恒真触发恒真 warn
-- 且掩盖后续分支不可达的配置错误;occupied==2 时 <2 为 false,本分支非恒真。
-- 等待唤醒闭环:第 2 件放料 set FULL_CHECK occupied → OnResourceReleased 精确唤醒 → occupied==2 匹配
-- → 跳 OP40_REQ 发 M2102;工单最后一件自身决策时 remaining==0 匹配;中间件在 OP40_WAIT 等 M2098 广播。
INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES
(31, 1, 'FULL_CHECK', 'occupied', '==', 2, 'OP40_REQ', '全检台2槽全满(都是待检)→ 发送 M2102 请求检验'),
(31, 2, 'JOB', 'remaining', '==', 0, 'OP40_REQ', '工单最后一件也到全检台(收尾)→ 发送 M2102 请求检验'),
(31, 3, 'FULL_CHECK', 'occupied', '<', 2, 'OP40_WAIT', '未满槽且未收尾→OP40_WAIT 等 M2098 批次广播(由满槽件/最后一件发 M2102 触发)');
-- 缸体 OP61_DECIDE (39): 换料下料后缓存回流决策——全检台满2件→立即回批次决策发M2102(防死锁);缓存台有待回流件→代取后二次换料;无→直接回批次决策
-- 恒有出路:满2件/occupied>=1 与 <1 覆盖全部取值,任何时刻决策不挂起。
-- 满2件分支必须优先级最高:换料 job 放完第2个待检件后若全检台已满,先回批次决策发 M2102 启动检测,
-- 否则所有 robot 等待方(缓存代取/全检台换料)互相等待形成死锁(2026-08-14 线上事故根因)。
INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES
(39, 0, 'FULL_CHECK', 'occupied', '==', 2, 'OP40_BATCH_DECIDE', '全检台2槽全满(都是待检)→立即回批次请求决策(发M2102启动检测,防满件死锁)'),
(39, 1, 'CACHE', 'occupied', '>=', 1, 'OP50_EXCHANGE_TAKE', '缓存台有待回流件→代取后全检台2号位二次换料(一趟机器人连续代做)'),
(39, 2, 'CACHE', 'occupied', '<', 1, 'OP40_BATCH_DECIDE', '缓存台无料→直接回批次请求决策(发待检信号)');
-- 配油盘 OP40_BATCH_DECIDE (33): 同缸体(等待唤醒闭环同缸体)
INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES
(33, 1, 'FULL_CHECK', 'occupied', '==', 2, 'OP40_REQ', '全检台2槽全满(都是待检)→ 发送 M2102 请求检验'),
(33, 2, 'JOB', 'remaining', '==', 0, 'OP40_REQ', '工单最后一件也到全检台(收尾)→ 发送 M2102 请求检验'),
(33, 3, 'FULL_CHECK', 'occupied', '<', 2, 'OP40_WAIT', '未满槽且未收尾→OP40_WAIT 等 M2098 批次广播(由满槽件/最后一件发 M2102 触发)');
-- 配油盘 OP61_DECIDE (43): 换料下料后缓存回流决策(同缸体)
-- 满2件分支必须优先级最高:换料 job 放完第2个待检件后若全检台已满,先回批次决策发 M2102 启动检测,
-- 否则所有 robot 等待方(缓存代取/全检台换料)互相等待形成死锁(2026-08-14 线上事故根因)。
INSERT INTO recipe_step_decision (recipe_step_id, priority, condition_equipment_type, condition_status, condition_operator, condition_value, target_next_step_id, description) VALUES
(43, 0, 'FULL_CHECK', 'occupied', '==', 2, 'OP40_BATCH_DECIDE', '全检台2槽全满(都是待检)→立即回批次请求决策(发M2102启动检测,防满件死锁)'),
(43, 1, 'CACHE', 'occupied', '>=', 1, 'OP50_EXCHANGE_TAKE', '缓存台有待回流件→代取后全检台2号位二次换料(一趟机器人连续代做)'),
(43, 2, 'CACHE', 'occupied', '<', 1, 'OP40_BATCH_DECIDE', '缓存台无料→直接回批次请求决策(发待检信号)');
-- ============================================================================
-- 十一、产品类型绑定配方
-- ============================================================================
UPDATE product_type SET recipe_id = 1 WHERE id BETWEEN 1 AND 4;
UPDATE product_type SET recipe_id = 2 WHERE id BETWEEN 5 AND 8;
-- ============================================================================
-- 十二、DOCK 槽位参数引用({dock_slot} 表达式解析用)
-- ============================================================================
UPDATE recipe_step_resource SET resource_key = '{dock_slot}'
WHERE recipe_step_id IN (1, 14, 15, 30) AND resource_type = 'equipment_slot' AND equipment_type = 'DOCK';
-- 注:OP60_EXCHANGE_LOAD37/38)与 OP60_LOAD_2ND42/46)刻意不用 {dock_slot}——
-- 换料 job 一趟要下两次料(前任成品 + 二次换料成品),绑定槽位只有一个,两次都放绑定槽位会自锁死;
-- 改用任意空槽位(引擎排除活跃 job 绑定槽位,不会抢其他 job 的接驳台槽位),
-- 信号 DockPlacePos 写 {allocated_slot}(实际分配槽位),保证引擎记账与 PLC 参数一致。
-- ============================================================================
-- 十三、序列重置
-- ============================================================================
SELECT setval('recipe_id_seq', (SELECT MAX(id) FROM recipe));
SELECT setval('recipe_step_id_seq', (SELECT MAX(id) FROM recipe_step));
SELECT setval('recipe_step_resource_id_seq', (SELECT MAX(id) FROM recipe_step_resource));
SELECT setval('recipe_step_signal_id_seq', (SELECT MAX(id) FROM recipe_step_signal));
SELECT setval('recipe_step_action_id_seq', (SELECT MAX(id) FROM recipe_step_action));
SELECT setval('recipe_step_decision_id_seq', (SELECT MAX(id) FROM recipe_step_decision));
-- ============================================================================
-- 十四、资源锁种子(引擎运行时状态初始化)
-- ============================================================================
-- resource_lock 唯一索引为部分索引(WHERE is_del=FALSE),ON CONFLICT 需带相同谓词。
INSERT INTO resource_lock (resource_type, resource_key, status, held_by_job_id) VALUES
('robot', 'robot', 'idle', 0),
('temp_slot', 'temp_slot', 'free', 0)
ON CONFLICT (resource_type, resource_key) WHERE is_del = FALSE DO NOTHING;
-- ============================================================================
-- 十五、机器人任务优先级配置种子(组合优先级,数值越小越优先)
-- ============================================================================
-- 组合配置:from_type/to_type NULL=通配;UNLOAD+TURN_TABLE=5 为换向取料
-- (换向机构与磨床同链,优先供料磨床,高于普通卸料 10)。
-- 与代码内置默认一致;调整"磨床优先"等策略直接 UPDATE 本表。
INSERT INTO robot_task_priority (task_kind, from_type, to_type, priority) VALUES
('EXCHANGE', NULL, NULL, 0),
('UNLOAD', 'TURN_TABLE', NULL, 5),
('LOAD', NULL, NULL, 10),
('UNLOAD', NULL, NULL, 10),
('WASH', NULL, NULL, 10),
('RELOAD', NULL, NULL, 20),
('TRANSFER', NULL, NULL, 30)
ON CONFLICT (task_kind, COALESCE(from_type, ''), COALESCE(to_type, ''))
WHERE is_del = FALSE DO NOTHING;