重构跑道观测系统:全跑道展示、结算跑道标注、热力模型、风场分析
This commit is contained in:
@@ -403,6 +403,35 @@ class DBManager:
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_airport_obs_log_icao_time ON airport_obs_log(icao, created_at DESC)"
|
||||
)
|
||||
conn.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS runway_obs_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
icao TEXT NOT NULL,
|
||||
city TEXT NOT NULL,
|
||||
runway TEXT NOT NULL,
|
||||
tdz_temp REAL,
|
||||
mid_temp REAL,
|
||||
end_temp REAL,
|
||||
target_runway_max REAL,
|
||||
wind_dir INTEGER,
|
||||
wind_speed REAL,
|
||||
rvr INTEGER,
|
||||
mor REAL,
|
||||
humidity REAL,
|
||||
otime_utc TEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
"""
|
||||
)
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_runway_obs_log_icao_otime "
|
||||
"ON runway_obs_log(icao, otime_utc DESC)"
|
||||
)
|
||||
conn.execute(
|
||||
"CREATE INDEX IF NOT EXISTS idx_runway_obs_log_city_time "
|
||||
"ON runway_obs_log(city, created_at DESC)"
|
||||
)
|
||||
self._ensure_column(conn, "users", "daily_points", "INTEGER DEFAULT 0")
|
||||
self._ensure_column(conn, "users", "daily_points_date", "TEXT")
|
||||
self._ensure_column(conn, "users", "weekly_points", "INTEGER DEFAULT 0")
|
||||
@@ -2202,3 +2231,71 @@ class DBManager:
|
||||
(str(icao).strip().upper(), str(-int(minutes))),
|
||||
).fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
def append_runway_obs(
|
||||
self,
|
||||
icao: str,
|
||||
city: str,
|
||||
runway: str,
|
||||
tdz_temp: Optional[float] = None,
|
||||
mid_temp: Optional[float] = None,
|
||||
end_temp: Optional[float] = None,
|
||||
target_runway_max: Optional[float] = None,
|
||||
wind_dir: Optional[int] = None,
|
||||
wind_speed: Optional[float] = None,
|
||||
rvr: Optional[int] = None,
|
||||
mor: Optional[float] = None,
|
||||
humidity: Optional[float] = None,
|
||||
otime_utc: str = "",
|
||||
) -> None:
|
||||
"""Insert one runway observation row (deduplicated by icao+runway+otime_utc)."""
|
||||
safe_icao = str(icao or "").strip().upper()
|
||||
safe_city = str(city or "").strip().lower()
|
||||
safe_runway = str(runway or "").strip().upper()
|
||||
safe_otime = str(otime_utc or "").strip()
|
||||
if not safe_icao or not safe_runway or not safe_otime:
|
||||
return
|
||||
with self._get_connection() as conn:
|
||||
existing = conn.execute(
|
||||
"SELECT id FROM runway_obs_log WHERE icao=? AND runway=? AND otime_utc=? LIMIT 1",
|
||||
(safe_icao, safe_runway, safe_otime),
|
||||
).fetchone()
|
||||
if existing:
|
||||
return
|
||||
conn.execute(
|
||||
"""
|
||||
INSERT INTO runway_obs_log (
|
||||
icao, city, runway,
|
||||
tdz_temp, mid_temp, end_temp, target_runway_max,
|
||||
wind_dir, wind_speed, rvr, mor, humidity,
|
||||
otime_utc
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
safe_icao, safe_city, safe_runway,
|
||||
tdz_temp, mid_temp, end_temp, target_runway_max,
|
||||
wind_dir, wind_speed, rvr, mor, humidity,
|
||||
safe_otime,
|
||||
),
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
def get_runway_obs_recent(
|
||||
self, icao: str, minutes: int = 60
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Get recent runway observations for trend analysis."""
|
||||
with self._get_connection() as conn:
|
||||
conn.row_factory = sqlite3.Row
|
||||
rows = conn.execute(
|
||||
"""
|
||||
SELECT icao, city, runway,
|
||||
tdz_temp, mid_temp, end_temp, target_runway_max,
|
||||
wind_dir, wind_speed, rvr, mor, humidity,
|
||||
otime_utc, created_at
|
||||
FROM runway_obs_log
|
||||
WHERE icao = ? AND created_at >= datetime('now', ? || ' minutes')
|
||||
ORDER BY created_at ASC
|
||||
""",
|
||||
(str(icao).strip().upper(), str(-int(minutes))),
|
||||
).fetchall()
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
Reference in New Issue
Block a user