Files
PolyWeather/frontend/components/dashboard/monitoring/monitor-temperature.ts
T
2569718930@qq.com 96676e7097 修正市场监控温度数据源:接入 NOAA MADIS 5分钟高频数据并优化展示
- 首尔/釜山:隐藏大号跑道温度值,改为"跑道温度"标签(跑道表面温度 ≠ 空气温度)
- US 城市:MADIS HFMETAR 5分钟小数温度接入 airport_primary,前端优先读取
- 其他城市:整数值不再强制 toFixed(1) 追加虚假 .0 精度
- 后端:weather_sources.py 注入 madis_hfmetar_current 到 results
- 后端:country_networks.py 的 _airport_primary_from_raw 新增 MADIS 优先分支
- 文档:更新 AIRPORT_REALTIME_SOURCES.md 新增 11 个 US 城市
- 文档:更新 CLAUDE.md 补充市场监控、高频数据管道、Country Network Provider 架构

Tested: npx tsc --noEmit ✓  ruff check . ✓
2026-05-14 16:00:55 +08:00

69 lines
2.0 KiB
TypeScript

import type { CityDetail } from "@/lib/dashboard-types";
export type MonitorTemperatureSource =
| "amos_runway_median"
| "amos_runway"
| "amos"
| "airport_primary"
| "airport_current"
| "current"
| "missing";
export type MonitorTemperature = {
source: MonitorTemperatureSource;
value: number | null;
};
function finiteNumber(value: unknown): number | null {
const num = Number(value);
return Number.isFinite(num) ? num : null;
}
function median(values: number[]) {
if (!values.length) return null;
const sorted = [...values].sort((a, b) => a - b);
const mid = Math.floor(sorted.length / 2);
return sorted.length % 2 === 1
? sorted[mid]
: (sorted[mid - 1] + sorted[mid]) / 2;
}
export function getAmosRunwayTemperature(detail?: CityDetail | null) {
const runwayTemps =
detail?.amos?.runway_obs?.temperatures ||
detail?.amos?.runway_temps ||
[];
const values = runwayTemps
.map((pair) => finiteNumber(pair?.[0]))
.filter((value): value is number => value != null);
const value = median(values);
if (value == null) return null;
return {
source: values.length > 1 ? "amos_runway_median" : "amos_runway",
value,
} satisfies MonitorTemperature;
}
export function resolveMonitorTemperature(
detail?: CityDetail | null,
): MonitorTemperature {
const runway = getAmosRunwayTemperature(detail);
if (runway) return runway;
const amosTemp = finiteNumber(detail?.amos?.temp ?? detail?.amos?.temp_c);
if (amosTemp != null && detail?.amos?.temp_source === "runway_median") {
return { source: "amos", value: amosTemp };
}
const airportPrimary = finiteNumber(detail?.airport_primary?.temp);
if (airportPrimary != null) return { source: "airport_primary", value: airportPrimary };
const airport = finiteNumber(detail?.airport_current?.temp);
if (airport != null) return { source: "airport_current", value: airport };
const current = finiteNumber(detail?.current?.temp);
if (current != null) return { source: "current", value: current };
return { source: "missing", value: null };
}