feat(钢卷跟踪): 从哪开始获取计划?一次性获取多少个计划?不同批次的顺序号相同怎么处理?
已实现的功能:
Systemcount+信号变化才算有效
状态机逻辑:信号1必须配合计数器变化才触发,然后等待信号2
信号2必须配合计数器变化+保持2秒才触发
第一批1-5,第二批2-6,第三批3-7
每次取5个钢卷,顺序号滑动+1
信号2触发时更新Oracle追踪表
OPC页面配置点位
信号1(入口钢卷)节点配置
信号2(焊接完成)节点配置
计数器节点配置
保存后自动重启OPC服务
前端操作中间表 ✅
TrackCoil页面可增删改查临时表
可手动调整顺序
模拟信号1/信号2按钮可测试
- 后端新增钢卷跟踪相关API和数据库表
- 前端添加钢卷跟踪管理页面
- OPC服务增加信号节点监控和状态机处理
- 实现钢卷跟踪的自动更新逻辑
This commit is contained in:
118
backend/main.py
118
backend/main.py
@@ -5,7 +5,8 @@ from contextlib import asynccontextmanager
|
||||
from typing import Optional
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from fastapi import FastAPI, HTTPException, Query
|
||||
from fastapi import FastAPI, HTTPException, Query, APIRouter
|
||||
import datetime
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
|
||||
load_dotenv()
|
||||
@@ -13,9 +14,14 @@ load_dotenv()
|
||||
from database import get_connection
|
||||
from models import PDIPLTMCreate, PDIPLTMUpdate, OpcConfig
|
||||
from opc_service import opc_service
|
||||
|
||||
router = APIRouter()
|
||||
from sqlite_sync import (
|
||||
init_db, sync_all_from_oracle,
|
||||
sqlite_upsert_pdi, sqlite_delete_pdi
|
||||
sqlite_upsert_pdi, sqlite_delete_pdi,
|
||||
sqlite_get_coil_track, sqlite_update_coil_track_item,
|
||||
sqlite_add_coil_track_item, sqlite_delete_coil_track_item,
|
||||
sqlite_clear_coil_track, sqlite_get_coils_by_sequencenb_range
|
||||
)
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
@@ -362,6 +368,8 @@ def get_opc_config():
|
||||
"counter_node": opc_service.counter_node,
|
||||
"trackmap_nodes": opc_service.trackmap_nodes,
|
||||
"poll_interval": opc_service.poll_interval,
|
||||
"signal1_node": opc_service.signal1_node,
|
||||
"signal2_node": opc_service.signal2_node,
|
||||
"running": opc_service.running,
|
||||
"last_counter": opc_service.last_counter,
|
||||
"last_update": opc_service.last_update,
|
||||
@@ -375,6 +383,8 @@ async def save_opc_config(config: OpcConfig):
|
||||
opc_service.counter_node = config.counter_node
|
||||
opc_service.trackmap_nodes = config.trackmap_nodes
|
||||
opc_service.poll_interval = config.poll_interval
|
||||
opc_service.signal1_node = config.signal1_node
|
||||
opc_service.signal2_node = config.signal2_node
|
||||
try:
|
||||
opc_service.save_config()
|
||||
except Exception as e:
|
||||
@@ -391,6 +401,7 @@ def opc_status():
|
||||
"last_counter": opc_service.last_counter,
|
||||
"last_update": opc_service.last_update,
|
||||
"log": opc_service.event_log[-50:],
|
||||
"track_state": opc_service.track_state,
|
||||
}
|
||||
|
||||
|
||||
@@ -471,7 +482,7 @@ def get_l2_model_grades():
|
||||
conn.close()
|
||||
|
||||
|
||||
@router.get("/api/pdi/next-numbers")
|
||||
@app.get("/api/pdi/next-numbers")
|
||||
def get_next_numbers():
|
||||
"""
|
||||
获取下一个可用的批次编号和顺序号
|
||||
@@ -536,3 +547,104 @@ def get_next_numbers():
|
||||
cursor.close()
|
||||
if 'conn' in locals():
|
||||
conn.close()
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# COIL_TRACK_TEMP 临时跟踪表 CRUD
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
@app.get("/api/track/coils")
|
||||
def get_track_coils():
|
||||
"""获取临时跟踪表中的钢卷列表"""
|
||||
coils = sqlite_get_coil_track()
|
||||
return {"data": coils}
|
||||
|
||||
|
||||
@app.post("/api/track/coils")
|
||||
def add_track_coil(data: dict):
|
||||
"""新增一个钢卷到临时跟踪表"""
|
||||
coilid = data.get("coilid")
|
||||
sequencenb = data.get("sequencenb")
|
||||
rollprogramnb = data.get("rollprogramnb")
|
||||
if not coilid:
|
||||
raise HTTPException(status_code=400, detail="coilid不能为空")
|
||||
sqlite_add_coil_track_item(coilid, sequencenb or 0, rollprogramnb or 0)
|
||||
return {"message": "添加成功"}
|
||||
|
||||
|
||||
@app.put("/api/track/coils/{id}")
|
||||
def update_track_coil(id: int, data: dict):
|
||||
"""更新临时跟踪表中的钢卷"""
|
||||
coilid = data.get("coilid")
|
||||
sequencenb = data.get("sequencenb", 0)
|
||||
rollprogramnb = data.get("rollprogramnb", 0)
|
||||
position = data.get("position", 1)
|
||||
if not coilid:
|
||||
raise HTTPException(status_code=400, detail="coilid不能为空")
|
||||
sqlite_update_coil_track_item(id, coilid, sequencenb, rollprogramnb, position)
|
||||
return {"message": "更新成功"}
|
||||
|
||||
|
||||
@app.delete("/api/track/coils/{id}")
|
||||
def delete_track_coil(id: int):
|
||||
"""删除临时跟踪表中的钢卷"""
|
||||
sqlite_delete_coil_track_item(id)
|
||||
return {"message": "删除成功"}
|
||||
|
||||
|
||||
@app.delete("/api/track/coils")
|
||||
def clear_track_coils():
|
||||
"""清空临时跟踪表"""
|
||||
sqlite_clear_coil_track()
|
||||
return {"message": "清空成功"}
|
||||
|
||||
|
||||
@app.get("/api/track/coils/range")
|
||||
def get_coils_by_range(start: int = Query(1), end: int = Query(5)):
|
||||
"""根据顺序号范围查询钢卷"""
|
||||
coils = sqlite_get_coils_by_sequencenb_range(start, end)
|
||||
return {"data": coils}
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# OPC Signal Configuration
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
@app.get("/api/opc/signals")
|
||||
def get_signal_config():
|
||||
"""获取信号节点配置"""
|
||||
return {
|
||||
"signal1_node": opc_service.signal1_node,
|
||||
"signal2_node": opc_service.signal2_node,
|
||||
}
|
||||
|
||||
|
||||
@app.post("/api/opc/signals")
|
||||
async def save_signal_config(data: dict):
|
||||
"""保存信号节点配置"""
|
||||
opc_service.signal1_node = data.get("signal1_node", opc_service.signal1_node)
|
||||
opc_service.signal2_node = data.get("signal2_node", opc_service.signal2_node)
|
||||
try:
|
||||
opc_service.save_config()
|
||||
except Exception as e:
|
||||
logger.warning("Save signal config failed: %s", e)
|
||||
raise HTTPException(status_code=500, detail=f"配置保存失败: {e}")
|
||||
return {"message": "信号节点配置已保存"}
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────
|
||||
# 模拟信号接口 (用于测试)
|
||||
# ─────────────────────────────────────────────
|
||||
|
||||
@app.post("/api/track/simulate/signal1")
|
||||
async def simulate_signal1():
|
||||
"""模拟信号1触发 - 获取下5个钢卷"""
|
||||
await opc_service._handle_signal1()
|
||||
return {"message": "信号1已触发"}
|
||||
|
||||
|
||||
@app.post("/api/track/simulate/signal2")
|
||||
async def simulate_signal2():
|
||||
"""模拟信号2触发 - 更新追踪表"""
|
||||
await opc_service._handle_signal2()
|
||||
return {"message": "信号2已触发"}
|
||||
|
||||
Reference in New Issue
Block a user