diff --git a/backend/opc_service.py b/backend/opc_service.py
index 0d2cd37..d172300 100644
--- a/backend/opc_service.py
+++ b/backend/opc_service.py
@@ -64,7 +64,10 @@ class OpcService:
self.signal2_last: Optional[int] = None
self.signal2_rise_time: Optional[datetime] = None
self.signal1_coils: List[Dict[str, Any]] = []
- self.current_seq_start: int = 1
+ self.first_coilid: str = ""
+ self.last_tracked_coilid: str = ""
+ self.end_coilid: str = ""
+ self.tracking_ended: bool = False
# 状态机: WAIT_S1=等待信号1, WAIT_S2=等待信号2
self.track_state: str = "WAIT_S1"
self.last_counter_at_state_change: Optional[Any] = None
@@ -274,58 +277,138 @@ class OpcService:
self.signal2_last = signal2_value
async def _handle_signal1(self):
- """Handle signal1: fetch next 5 coils from PDI and save to SQLite temp table."""
- from sqlite_sync import (
- sqlite_get_max_sequencenb,
- sqlite_get_coils_by_sequencenb_range,
- sqlite_save_coils_to_track
- )
+ """Handle signal1: fetch next 4 coils from Oracle PDI table and save to SQLite temp table."""
+ from sqlite_sync import sqlite_save_coils_to_track, sqlite_clear_coil_track
def _do_fetch():
- max_seq = sqlite_get_max_sequencenb()
- if max_seq is None or max_seq < 1:
- self._log("Signal1: No PDI data available")
+ # 如果追踪已结束,检查是否有新钢卷需要恢复追踪
+ self._log(f"Signal1: Called, first_coilid={repr(self.first_coilid)}, tracking_ended={self.tracking_ended}")
+ if self.tracking_ended:
+ try:
+ from database import get_connection
+ conn = get_connection()
+ cursor = conn.cursor()
+ try:
+ cursor.execute("SELECT COILID FROM PLTM.PDI_PLTM ORDER BY COILID ASC")
+ all_coil_ids = [r[0] for r in cursor.fetchall()]
+ # 使用 end_coilid 判断是否有新钢卷
+ check_coilid = self.end_coilid or self.last_tracked_coilid
+ if all_coil_ids and check_coilid:
+ has_new = any(cid > check_coilid for cid in all_coil_ids)
+ if has_new:
+ self._log("Signal1: New coils detected, resuming tracking")
+ self.tracking_ended = False
+ # 从最后一个追踪的钢卷之后继续
+ self.first_coilid = check_coilid
+ else:
+ self._log("Signal1: Tracking ended, no new coils, skip")
+ return
+ elif all_coil_ids and not check_coilid:
+ # 没有结束点记录但有计划,按首卷重新启动追踪
+ self._log("Signal1: Tracking ended without checkpoint, restarting from first plan")
+ self.tracking_ended = False
+ self.first_coilid = ""
+ else:
+ # 没有计划,保持结束状态
+ self._log("Signal1: Tracking ended, PDI empty, skip")
+ return
+ finally:
+ cursor.close()
+ conn.close()
+ except Exception as exc:
+ self._log(f"Signal1: Check new coils failed: {exc}")
+ return
+
+ try:
+ from database import get_connection
+ conn = get_connection()
+ cursor = conn.cursor()
+ try:
+ if self.first_coilid:
+ cursor.execute("""
+ SELECT COILID, SEQUENCENB, ROLLPROGRAMNB
+ FROM PLTM.PDI_PLTM
+ WHERE COILID >= :start_coilid
+ ORDER BY COILID ASC
+ """, {"start_coilid": self.first_coilid})
+ else:
+ cursor.execute("""
+ SELECT COILID, SEQUENCENB, ROLLPROGRAMNB
+ FROM PLTM.PDI_PLTM
+ ORDER BY COILID ASC
+ """)
+ rows = cursor.fetchmany(4)
+ coils = [{"coilid": r[0], "sequencenb": r[1], "rollprogramnb": r[2]} for r in rows]
+ finally:
+ cursor.close()
+ conn.close()
+ except Exception as exc:
+ self._log(f"Signal1: Failed to fetch from Oracle: {exc}")
return
- start_seq = self.current_seq_start
- end_seq = min(start_seq + 4, max_seq)
-
- if end_seq < start_seq:
- self._log(f"Signal1: Insufficient PDI data (max_seq={max_seq}, start={start_seq})")
- return
-
- coils = sqlite_get_coils_by_sequencenb_range(start_seq, end_seq)
if len(coils) == 0:
- self._log(f"Signal1: No coils found")
+ self._log("Signal1: No more coils in PDI, ending tracking")
+ sqlite_clear_coil_track()
+ self.tracking_ended = True
+ return
+
+ if len(coils) == 1 and coils[0]["coilid"] == self.first_coilid:
+ self._log("Signal1: Only the same coil exists, saving it and setting for next query")
+ self.signal1_coils = coils
+ sqlite_save_coils_to_track(coils)
+ # 保持 first_coilid 不变,下次查询会从同一个位置继续
+ # Signal2 触发后,检查是否还有更多钢卷
return
self.signal1_coils = coils
sqlite_save_coils_to_track(coils)
- self._log(f"Signal1: Saved {len(coils)} coils (seq {start_seq}-{end_seq}) to temp table")
+ if len(coils) >= 2:
+ self.first_coilid = coils[1]["coilid"]
+ else:
+ self.first_coilid = coils[0]["coilid"]
- self.current_seq_start = start_seq + 1
+ self.last_tracked_coilid = coils[0]["coilid"]
+
+ self._log(f"Signal1: Saved {len(coils)} coils, next_start: {self.first_coilid}, last_tracked: {self.last_tracked_coilid}")
loop = asyncio.get_event_loop()
await loop.run_in_executor(None, _do_fetch)
async def _handle_signal2(self):
"""Handle signal2: update CMPT_PL_TRACKMAP with temp table data."""
- from sqlite_sync import sqlite_get_coil_track
+ from sqlite_sync import sqlite_clear_coil_track, sqlite_get_coil_track
from database import get_connection
def _do_update():
coils = sqlite_get_coil_track()
- if not coils:
- self._log("Signal2: No coils in temp track table")
- return
try:
conn = get_connection()
cursor = conn.cursor()
try:
+ if not coils:
+ self._log("Signal2: No coils in temp track table, clearing all positions")
+ for pos in range(1, 11):
+ cursor.execute("SELECT COUNT(*) FROM PLTM.CMPT_PL_TRACKMAP WHERE POSITION = :pos", {"pos": pos})
+ if cursor.fetchone()[0] > 0:
+ cursor.execute("UPDATE PLTM.CMPT_PL_TRACKMAP SET COILID = NULL, TOM = SYSDATE WHERE POSITION = :pos", {"pos": pos})
+ conn.commit()
+ # 标记追踪结束
+ if self.signal1_coils:
+ self.end_coilid = self.signal1_coils[0]["coilid"]
+ self.tracking_ended = True
+ # 清空 first_coilid,下次 Signal1 触发时从头查询
+ self.first_coilid = ""
+ self._log(f"Signal2: Tracking ended (no coils), end_coilid={self.end_coilid}")
+ return
+
+ cursor.execute("SELECT COILID FROM PLTM.CMPT_PL_TRACKMAP WHERE POSITION = 1")
+ prev_pos1_coil = cursor.fetchone()
+ prev_pos1_coilid = prev_pos1_coil[0] if prev_pos1_coil else None
+
coil_count = len(coils)
- for i in range(5):
+ for i in range(4):
target_position = i + 1
coil_index = target_position - 1
if coil_index >= 0 and coil_index < coil_count:
@@ -357,8 +440,63 @@ class OpcService:
INSERT INTO PLTM.CMPT_PL_TRACKMAP (POSITION, COILID, TOM)
VALUES (:position, NULL, SYSDATE)
""", {"position": target_position})
+
+ for pos in range(5, 11):
+ cursor.execute("SELECT COUNT(*) FROM PLTM.CMPT_PL_TRACKMAP WHERE POSITION = :pos", {"pos": pos})
+ if cursor.fetchone()[0] > 0:
+ cursor.execute("UPDATE PLTM.CMPT_PL_TRACKMAP SET COILID = NULL, TOM = SYSDATE WHERE POSITION = :pos", {"pos": pos})
+
+ new_pos1_coil = coils[0]["coilid"] if coils else None
+ pos1_unchanged = prev_pos1_coilid and new_pos1_coil and prev_pos1_coilid == new_pos1_coil
+ if pos1_unchanged:
+ # 只在“末卷(单卷)重复信号”时清空,避免 6-7 阶段提前进入清空/重写循环
+ if coil_count == 1:
+ for pos in range(1, 11):
+ cursor.execute("SELECT COUNT(*) FROM PLTM.CMPT_PL_TRACKMAP WHERE POSITION = :pos", {"pos": pos})
+ if cursor.fetchone()[0] > 0:
+ cursor.execute("UPDATE PLTM.CMPT_PL_TRACKMAP SET COILID = NULL, TOM = SYSDATE WHERE POSITION = :pos", {"pos": pos})
+ sqlite_clear_coil_track()
+ self.end_coilid = coils[0]["coilid"]
+ self.last_tracked_coilid = self.end_coilid
+ self.tracking_ended = True
+ self.first_coilid = ""
+ self._log("Signal2: Final single coil repeated, cleared all positions and ended tracking")
+ else:
+ self._log("Signal2: Coil at position 1 unchanged but not final single-coil stage, keep tracking")
+
conn.commit()
- self._log(f"Signal2: Updated 5 positions (coils: {coil_count})")
+ self._log(f"Signal2: Updated 4 positions (coils: {coil_count})")
+
+ # 检查是否还有更多钢卷可以追踪
+ self._log(f"Signal2: Checking remaining coils, first_coilid={repr(self.first_coilid)}")
+
+ if self.first_coilid:
+ try:
+ cursor.execute("""
+ SELECT COILID FROM PLTM.PDI_PLTM
+ WHERE COILID >= :start_coilid
+ ORDER BY COILID ASC
+ """, {"start_coilid": self.first_coilid})
+ all_remaining = cursor.fetchall()
+ remaining_count = len(all_remaining)
+ self._log(f"Signal2: Check remaining after {self.first_coilid}: count={remaining_count}, coils={[r[0] for r in all_remaining]}")
+ if remaining_count == 0:
+ # 没有更多钢卷了,标记追踪结束
+ self.end_coilid = self.first_coilid
+ self.last_tracked_coilid = self.first_coilid
+ self.tracking_ended = True
+ self._log(f"Signal2: No more coils, tracking ended, end_coilid={self.end_coilid}")
+ elif remaining_count >= 2:
+ # 有2个以上钢卷,保持 first_coilid 不变,让 Signal1 处理
+ self._log(f"Signal2: >=2 coils remain, first_coilid unchanged, waiting for Signal1")
+ else:
+ # 只有一个钢卷时先展示为“7(1个)”,下一次重复信号再清空到 NULL
+ self._log(
+ f"Signal2: One coil remains ({all_remaining[0][0]}), "
+ "waiting one more cycle before final clear"
+ )
+ except Exception as exc:
+ self._log(f"Signal2: Check next coils failed: {exc}")
finally:
cursor.close()
conn.close()
diff --git a/backend/sqlite_sync.py b/backend/sqlite_sync.py
index 8c6e765..a60e79d 100644
--- a/backend/sqlite_sync.py
+++ b/backend/sqlite_sync.py
@@ -337,7 +337,7 @@ def sqlite_get_coils_by_sequencenb_range(start_seq: int, end_seq: int) -> List[D
SELECT COILID, SEQUENCENB, ROLLPROGRAMNB
FROM PDI_PLTM
WHERE SEQUENCENB >= ? AND SEQUENCENB <= ?
- ORDER BY SEQUENCENB DESC
+ ORDER BY COILID ASC
""", (start_seq, end_seq))
rows = cursor.fetchall()
return [{"coilid": r[0], "sequencenb": r[1], "rollprogramnb": r[2]} for r in rows]
@@ -345,12 +345,42 @@ def sqlite_get_coils_by_sequencenb_range(start_seq: int, end_seq: int) -> List[D
sc.close()
+def sqlite_get_coils_by_coilid(start_coilid: str, count: int = 4) -> List[Dict[str, Any]]:
+ sc = get_sqlite()
+ try:
+ cursor = sc.execute("""
+ SELECT COILID, SEQUENCENB, ROLLPROGRAMNB
+ FROM PDI_PLTM
+ WHERE COILID >= ?
+ ORDER BY COILID ASC
+ LIMIT ?
+ """, (start_coilid, count))
+ rows = cursor.fetchall()
+ return [{"coilid": r[0], "sequencenb": r[1], "rollprogramnb": r[2]} for r in rows]
+ finally:
+ sc.close()
+
+
+def sqlite_get_first_coils(count: int = 4) -> List[Dict[str, Any]]:
+ sc = get_sqlite()
+ try:
+ cursor = sc.execute("""
+ SELECT COILID, SEQUENCENB, ROLLPROGRAMNB
+ FROM PDI_PLTM
+ ORDER BY COILID ASC
+ LIMIT ?
+ """, (count,))
+ rows = cursor.fetchall()
+ return [{"coilid": r[0], "sequencenb": r[1], "rollprogramnb": r[2]} for r in rows]
+ finally:
+ sc.close()
+
+
def sqlite_save_coils_to_track(coils: List[Dict[str, Any]]):
sc = get_sqlite()
try:
sc.execute("DELETE FROM COIL_TRACK_TEMP")
- reversed_coils = list(reversed(coils))
- for i, coil in enumerate(reversed_coils):
+ for i, coil in enumerate(coils):
sc.execute("""
INSERT INTO COIL_TRACK_TEMP (COILID, SEQUENCENB, ROLLPROGRAMNB, POSITION)
VALUES (?, ?, ?, ?)
diff --git a/frontend/src/views/TrackCoil.vue b/frontend/src/views/TrackCoil.vue
index 5bee232..d59e7b1 100644
--- a/frontend/src/views/TrackCoil.vue
+++ b/frontend/src/views/TrackCoil.vue
@@ -7,7 +7,7 @@