"use client"; import clsx from "clsx"; import { temp } from "@/components/dashboard/scan-terminal/utils"; const OBSERVATION_LABEL_EN: Record = { "参考站点 (1分钟)": "Reference Station (1m)", "天文台实测 (10分钟)": "HKO Live (10m)", "机场气象站 (10分钟)": "Airport Weather Station (10m)", "航站楼温度": "Terminal Temperature", "官方机场观测 (15分钟)": "Official Airport Obs (15m)", "CWA (10分钟)": "CWA (10m)", "气象站实测": "Weather Station Live", "跑道实测 (1分钟)": "Runway Live (1m)", "跑道实测 (3分钟)": "Runway Live (3m)", "机场报文": "Airport METAR", "METAR 结算 (30分钟)": "METAR Settlement (30m)", }; const HIGH_LABEL_EN: Record = { "参考站点": "Reference Station", "天文台实测": "HKO Live", "天文台": "HKO", "机场气象站": "Airport Weather Station", "航站楼": "Terminal", "官方机场观测": "Official Airport Obs", "气象站": "Weather Station", "跑道实测": "Runway", "机场报文": "Airport METAR", "METAR 官方": "Official METAR", }; function observationLabel(label: string, isEn: boolean) { return isEn ? (OBSERVATION_LABEL_EN[label] || label) : label; } function highLabel(label: string, isEn: boolean) { return isEn ? (HIGH_LABEL_EN[label] || label) : label; } type DebQuality = { quality_tier?: string | null; recommendation?: string | null; recent_hit_rate?: number | null; recent_samples?: number | null; }; function debQualityLabel(quality: DebQuality | null | undefined, isEn: boolean) { const recommendation = quality?.recommendation; if (recommendation === "primary") return isEn ? "Primary" : "主用"; if (recommendation === "supporting") return isEn ? "Support" : "辅助"; if (recommendation === "context_only") return isEn ? "Context" : "参考"; if (recommendation === "insufficient") return isEn ? "Thin" : "样本少"; return ""; } function debQualityClass(quality: DebQuality | null | undefined) { const tier = quality?.quality_tier; if (tier === "high") return "border-emerald-200 bg-emerald-50 text-emerald-700"; if (tier === "medium") return "border-amber-200 bg-amber-50 text-amber-700"; if (tier === "low") return "border-rose-200 bg-rose-50 text-rose-700"; return "border-slate-200 bg-slate-50 text-slate-500"; } function DebQualityBadge({ quality, isEn }: { quality?: DebQuality | null; isEn: boolean }) { const label = debQualityLabel(quality, isEn); if (!label) return null; const hitRate = quality?.recent_hit_rate; const samples = quality?.recent_samples; const titleParts = [ isEn ? `DEB recommendation: ${label}` : `DEB 建议:${label}`, hitRate == null ? null : `${hitRate.toFixed(0)}%`, samples == null ? null : `n=${samples}`, ].filter(Boolean); return ( {label} ); } function buildStatsLabels({ isEn, isShenzhen, runwayHeaderLabel, metarHeaderLabel, runwayHighLabel, metarHighLabel, }: { isEn: boolean; isShenzhen: boolean; runwayHeaderLabel: string; metarHeaderLabel: string; runwayHighLabel: string; metarHighLabel: string; }) { const primary = observationLabel(runwayHeaderLabel, isEn); const secondaryObservation = observationLabel(metarHeaderLabel, isEn); const dailyHigh = isEn ? "Daily High" : "当日最高"; return { primary, compactSecondary: isShenzhen ? dailyHigh : secondaryObservation, expandedSecondary: `${secondaryObservation} · ${dailyHigh}`, dailyPeakTitle: isEn ? "Daily Peak" : "当日最高气温", runwayHigh: highLabel(runwayHighLabel, isEn), metarHigh: highLabel(metarHighLabel, isEn), }; } export function TemperatureStatsBars({ isEn, compact, timeframe, tempSymbol, runwayHeaderLabel, metarHeaderLabel, runwayHighLabel, metarHighLabel, isShenzhen, displayRunwayTemp, displayMetarTemp, observedHighMetar, observedHighRunway, wundergroundDailyHigh, debVal, debQuality, modelMin, modelMax, spread, spreadLabel, spreadLabelEn, formattedUpdateTime, }: { isEn: boolean; compact: boolean; timeframe: string; tempSymbol: string; runwayHeaderLabel: string; metarHeaderLabel: string; runwayHighLabel: string; metarHighLabel: string; isShenzhen: boolean; displayRunwayTemp: number | null; displayMetarTemp: number | null; observedHighMetar: number | null; observedHighRunway: number | null; wundergroundDailyHigh: number | null; debVal: number | null; debQuality?: DebQuality | null; modelMin: number | null; modelMax: number | null; spread: number | null; spreadLabel: string; spreadLabelEn: string; formattedUpdateTime: string; }) { const labels = buildStatsLabels({ isEn, isShenzhen, runwayHeaderLabel, metarHeaderLabel, runwayHighLabel, metarHighLabel, }); if (compact) { return (
{timeframe === "1D" ? (
{labels.primary}:{" "} {temp(displayRunwayTemp, tempSymbol)} | {labels.compactSecondary}:{" "} {temp(displayMetarTemp, tempSymbol)}
) : (
DEB: {temp(debVal, tempSymbol)} {modelMin !== null && modelMax !== null && ( <> | {isEn ? "Models" : "多模型"}:{" "} {temp(modelMin, tempSymbol)} - {temp(modelMax, tempSymbol)} )}
)}
{timeframe === "1D" && formattedUpdateTime.includes(" ") ? formattedUpdateTime.split(" ")[1].slice(0, 5) : ""}
); } return (
{timeframe === "1D" ? (
{labels.primary} {temp(displayRunwayTemp, tempSymbol)}
{labels.expandedSecondary} {temp(observedHighMetar, tempSymbol)}
) : (
DEB Max {temp(debVal, tempSymbol)}
{isEn ? "Model Range" : "多模型区间"} {modelMin !== null && modelMax !== null ? `${temp(modelMin, tempSymbol)} - ${temp(modelMax, tempSymbol)}` : "--"}
)}
{labels.dailyPeakTitle}
{labels.runwayHigh}: {temp(observedHighRunway, tempSymbol)} | {labels.metarHigh}: {temp(observedHighMetar, tempSymbol)} {wundergroundDailyHigh !== null && ( <> | WU: {temp(wundergroundDailyHigh, tempSymbol)} )}
{timeframe === "1D" && (
{isEn ? "Model Range" : "模型区间"} {modelMin !== null && modelMax !== null ? `${temp(modelMin, tempSymbol)} - ${temp(modelMax, tempSymbol)}` : "--"}
DEB {temp(debVal, tempSymbol)}
{isEn ? "Spread" : "分歧"} {spread !== null ? `${spread.toFixed(1)}${tempSymbol}` : "--"} {spreadLabel && ` · ${isEn ? spreadLabelEn : spreadLabel}`}
{isEn ? "Updated" : "更新时间"} {formattedUpdateTime}
)}
); } export const __buildTemperatureStatsLabelsForTest = buildStatsLabels; export const __buildDebQualityLabelForTest = debQualityLabel;