新增实时滚动温度走势图:API端点+前端组件

后端 city_realtime_stream.py:循环缓冲区(deque maxlen=1440),best_temp() METAR优先。路由 /api/city/{name}/realtime-stream 返回 {points, thresholds}。前端 RealtimeScrollChart:每30秒轮询,一条温度线+多条阈值横线,横轴随时间推进。
This commit is contained in:
2569718930@qq.com
2026-05-25 06:43:42 +08:00
parent 414708794d
commit 9978ac3e01
4 changed files with 299 additions and 3 deletions
@@ -341,12 +341,20 @@ export function LiveTemperatureThresholdChart({
isEn: boolean;
row: ScanOpportunityRow | null;
}) {
const hourlyCache = new Map<string, { ts: number; data: HourlyForecast }>();
const HOURLY_CACHE_TTL_MS = 30 * 60 * 1000; // 30 min
const [hourly, setHourly] = useState<HourlyForecast>(null);
const city = String(row?.city || "").toLowerCase().trim();
useEffect(() => {
setHourly(null);
if (!city) return;
const cached = hourlyCache.get(city);
if (cached && Date.now() - cached.ts < HOURLY_CACHE_TTL_MS) {
setHourly(cached.data);
return;
}
setHourly(null);
let cancelled = false;
fetch(`/api/city/${encodeURIComponent(city)}/detail?depth=panel&force_refresh=false`, {
cache: "no-store",
@@ -358,13 +366,15 @@ export function LiveTemperatureThresholdChart({
})
.then((json) => {
if (cancelled || !json?.hourly) return;
setHourly({
const data: HourlyForecast = {
forecastTodayHigh: json.forecast?.today_high ?? null,
localTime: json.local_time || null,
times: json.hourly.times || [],
temps: json.hourly.temps || [],
modelCurves: json.models_hourly?.curves || undefined,
});
};
hourlyCache.set(city, { ts: Date.now(), data });
setHourly(data);
})
.catch(() => {});
return () => { cancelled = true; };