feat(linkage): 移动改为任意入口位置选择,仅上卷鞍座触发生产
- 计划新增 position 字段;新增 /plan/{id}/move?position=… 与 /plan/positions/all
- line_service.place_at_position:放到任意位置(位置唯一占用),上卷鞍座单独触发生产联动
- 入口跟踪:新增入口位置图(单一鞍座)显示占位;移动按钮弹出位置选择框
- 计划管理:移动按钮同样弹出位置选择框
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -17,12 +17,45 @@ from app.models.production import ProductionRecord
|
||||
from app.models.downtime import DowntimeRecord
|
||||
from app.models.line_state import LineState
|
||||
|
||||
# ── 入口位置 ──
|
||||
SADDLE_NAME = "上卷鞍座" # 唯一会触发生产联动的位置
|
||||
ENTRY_POSITIONS = [
|
||||
"1#上卷小车", "2#上卷小车",
|
||||
"1#称重位", "2#称重位",
|
||||
"1#地辊", "2#地辊",
|
||||
"1#倒卷小车", "2#倒卷小车",
|
||||
SADDLE_NAME,
|
||||
]
|
||||
|
||||
# ── 仿真参数 ──
|
||||
TARGET_LENGTH_M = 2000.0 # 带头目标长度(生产完成阈值)
|
||||
SIM_SPEED_M_MIN = 600.0 # 仿真线速度 m/min(2000m ≈ 200s)
|
||||
DOWNTIME_THRESHOLD_S = 600 # 速度为0持续超过该秒数判定停机(10min)
|
||||
|
||||
|
||||
async def place_at_position(db: AsyncSession, plan: ProductionPlan, position: str):
|
||||
"""把计划放到任意入口位置;位置唯一占用。上卷鞍座单独触发生产联动。"""
|
||||
if position not in ENTRY_POSITIONS:
|
||||
raise ValueError("未知入口位置")
|
||||
if position == SADDLE_NAME:
|
||||
await move_to_saddle(db, plan)
|
||||
return
|
||||
# 普通位置:清除同位置上的其它计划,移出鞍座(若在)
|
||||
res = await db.execute(
|
||||
select(ProductionPlan).where(ProductionPlan.position == position, ProductionPlan.id != plan.id)
|
||||
)
|
||||
for o in res.scalars():
|
||||
o.position = None
|
||||
plan.on_saddle = 0
|
||||
plan.run_started_at = None
|
||||
plan.run_speed = 0
|
||||
plan.run_length_m = 0
|
||||
plan.position = position
|
||||
if plan.status == "producing":
|
||||
plan.status = "online"
|
||||
await ensure_online(db)
|
||||
|
||||
|
||||
def _shift_of(dt: datetime) -> str:
|
||||
return "甲" if 8 <= dt.hour < 20 else "乙"
|
||||
|
||||
@@ -60,6 +93,7 @@ async def move_to_saddle(db: AsyncSession, plan: ProductionPlan):
|
||||
if occupied and occupied.id != plan.id:
|
||||
raise ValueError("上卷鞍座已被占用,请等待当前钢卷生产完成")
|
||||
plan.on_saddle = 1
|
||||
plan.position = SADDLE_NAME
|
||||
plan.saddle_at = datetime.now()
|
||||
plan.run_started_at = None
|
||||
plan.run_speed = 0
|
||||
@@ -86,6 +120,7 @@ async def _produce(db: AsyncSession, plan: ProductionPlan):
|
||||
plan.status = "produced"
|
||||
plan.produced_at = now
|
||||
plan.on_saddle = 0
|
||||
plan.position = None
|
||||
plan.run_speed = 0
|
||||
plan.run_length_m = TARGET_LENGTH_M
|
||||
|
||||
|
||||
Reference in New Issue
Block a user