Normalize Wunderground labels to METAR
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
getRiskBadgeLabel,
|
||||
getTemperatureChartData,
|
||||
} from "@/lib/dashboard-utils";
|
||||
import { normalizeObservationSourceLabel } from "@/lib/source-labels";
|
||||
|
||||
function DetailMiniTemperatureChart({ detail }: { detail: CityDetail }) {
|
||||
const { locale, t } = useI18n();
|
||||
@@ -178,17 +179,20 @@ export function DetailPanel() {
|
||||
() => getTodayPolymarketUrl(detail, locale),
|
||||
[detail, locale],
|
||||
);
|
||||
const basicSettlementLabel =
|
||||
const basicSettlementLabel = normalizeObservationSourceLabel(
|
||||
selectedSummary?.current?.settlement_source_label ||
|
||||
selectedCityItem?.settlement_source_label ||
|
||||
selectedCityItem?.settlement_source ||
|
||||
(locale === "en-US" ? "Settlement source pending" : "结算口径待确认");
|
||||
selectedCityItem?.settlement_source_label ||
|
||||
selectedCityItem?.settlement_source,
|
||||
locale === "en-US" ? "Settlement source pending" : "结算口径待确认",
|
||||
);
|
||||
const basicAirportLabel =
|
||||
selectedCityItem?.airport ||
|
||||
selectedSummary?.icao ||
|
||||
(locale === "en-US" ? "Airport pending" : "机场待确认");
|
||||
const heroSettlementLabel =
|
||||
detail?.current?.settlement_source_label || basicSettlementLabel;
|
||||
const heroSettlementLabel = normalizeObservationSourceLabel(
|
||||
detail?.current?.settlement_source_label,
|
||||
basicSettlementLabel,
|
||||
);
|
||||
const heroAirportLabel = detail?.risk?.airport || basicAirportLabel;
|
||||
const isSparsePanelDetail = Boolean(
|
||||
detail &&
|
||||
|
||||
@@ -32,6 +32,10 @@ import {
|
||||
getWeatherSummary,
|
||||
} from "@/lib/dashboard-utils";
|
||||
import { dashboardClient } from "@/lib/dashboard-client";
|
||||
import {
|
||||
normalizeObservationSourceCode,
|
||||
normalizeObservationSourceLabel,
|
||||
} from "@/lib/source-labels";
|
||||
import type { IntradayMeteorologySignal, MarketScan } from "@/lib/dashboard-types";
|
||||
|
||||
function normalizeMarketValue(value?: number | null) {
|
||||
@@ -1331,9 +1335,9 @@ export function FutureForecastModal() {
|
||||
String(intradayMeteorology.peak_window || "").trim() ||
|
||||
paceView?.peakWindowText ||
|
||||
"--";
|
||||
const settlementSourceCode = String(
|
||||
const settlementSourceCode = normalizeObservationSourceCode(
|
||||
detail.current?.settlement_source || "",
|
||||
).trim().toLowerCase();
|
||||
);
|
||||
const settlementStationCode = String(
|
||||
detail.current?.station_code || detail.risk?.icao || "",
|
||||
)
|
||||
@@ -1345,19 +1349,20 @@ export function FutureForecastModal() {
|
||||
(locale === "en-US" ? "Anchor station" : "锚点站");
|
||||
const airportMetarAnchor =
|
||||
settlementSourceCode === "metar" ||
|
||||
settlementSourceCode === "wunderground" ||
|
||||
Boolean(settlementStationCode && /^[A-Z]{4}$/.test(settlementStationCode));
|
||||
const anchorSourceLabel = airportMetarAnchor
|
||||
? settlementStationCode
|
||||
? `${settlementStationCode} METAR`
|
||||
: "METAR"
|
||||
: detail.current?.settlement_source_label ||
|
||||
detail.current?.settlement_source ||
|
||||
(locale === "en-US" ? "Official observation" : "官方观测");
|
||||
: normalizeObservationSourceLabel(
|
||||
detail.current?.settlement_source_label ||
|
||||
detail.current?.settlement_source,
|
||||
locale === "en-US" ? "Official observation" : "官方观测",
|
||||
);
|
||||
const anchorRuleText = airportMetarAnchor
|
||||
? locale === "en-US"
|
||||
? `Airport contract anchor: use the ${anchorSourceLabel} reports. Wunderground is only a history display page when present.`
|
||||
: `机场合约锚点:以 ${anchorSourceLabel} 报文为准;若出现 Wunderground,它只是历史展示页面。`
|
||||
? `Airport contract anchor: use the ${anchorSourceLabel} reports. Third-party history pages are display-only when present.`
|
||||
: `机场合约锚点:以 ${anchorSourceLabel} 报文为准;第三方历史页只作为展示入口。`
|
||||
: locale === "en-US"
|
||||
? `Official anchor: use ${anchorSourceLabel} observations for this contract.`
|
||||
: `官方锚点:该合约按 ${anchorSourceLabel} 观测口径判断。`;
|
||||
|
||||
@@ -20,6 +20,10 @@ import {
|
||||
getTemperatureChartData,
|
||||
getWeatherSummary,
|
||||
} from "@/lib/dashboard-utils";
|
||||
import {
|
||||
normalizeObservationSourceCode,
|
||||
normalizeObservationSourceLabel,
|
||||
} from "@/lib/source-labels";
|
||||
|
||||
function EmptyState({ text }: { text: string }) {
|
||||
return (
|
||||
@@ -548,22 +552,21 @@ export function HeroSummary() {
|
||||
const { weatherIcon, weatherText } = getWeatherSummary(data, locale);
|
||||
const metaItems = getHeroMetaItems(data, locale);
|
||||
const current = data.current || {};
|
||||
const settlementSourceCode = String(current.settlement_source || "metar")
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
const settlementSourceCode = normalizeObservationSourceCode(
|
||||
current.settlement_source || "metar",
|
||||
);
|
||||
const settlementIcao = String(
|
||||
current.station_code || data.risk?.icao || "",
|
||||
)
|
||||
.trim()
|
||||
.toUpperCase();
|
||||
const settlementSource =
|
||||
settlementSourceCode === "wunderground"
|
||||
? settlementIcao
|
||||
? `${settlementIcao} METAR`
|
||||
: "METAR"
|
||||
: String(current.settlement_source_label || current.settlement_source || "METAR")
|
||||
.trim()
|
||||
.toUpperCase();
|
||||
settlementSourceCode === "metar" && settlementIcao
|
||||
? `${settlementIcao} METAR`
|
||||
: normalizeObservationSourceLabel(
|
||||
current.settlement_source_label || current.settlement_source,
|
||||
"METAR",
|
||||
).toUpperCase();
|
||||
const isMax =
|
||||
current.max_so_far != null &&
|
||||
current.temp != null &&
|
||||
|
||||
@@ -20,6 +20,7 @@ import type {
|
||||
CitySummary,
|
||||
RiskLevel,
|
||||
} from "@/lib/dashboard-types";
|
||||
import { normalizeObservationSourceLabel } from "@/lib/source-labels";
|
||||
|
||||
const loadHistoryModal = () =>
|
||||
import("@/components/dashboard/HistoryModal").then(
|
||||
@@ -214,10 +215,12 @@ function HomeIntelligencePanel({ snapshots }: { snapshots: CitySnapshot[] }) {
|
||||
detail?.risk?.level;
|
||||
const deviation = summary?.deviation_monitor || detail?.deviation_monitor;
|
||||
const observationSource =
|
||||
summary?.current?.settlement_source_label ||
|
||||
detail?.current?.settlement_source_label ||
|
||||
city.settlement_source_label ||
|
||||
city.airport;
|
||||
normalizeObservationSourceLabel(
|
||||
summary?.current?.settlement_source_label ||
|
||||
detail?.current?.settlement_source_label ||
|
||||
city.settlement_source_label,
|
||||
"METAR",
|
||||
);
|
||||
const probabilityBuckets =
|
||||
detail?.probabilities?.distribution ||
|
||||
(detail?.local_date
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { CityDetail } from "@/lib/dashboard-types";
|
||||
import { normalizeObservationSourceLabel } from "@/lib/source-labels";
|
||||
|
||||
export type OfficialSourceLink = {
|
||||
label: string;
|
||||
@@ -749,7 +750,10 @@ export function getOfficialSourceLinks(detail: CityDetail): OfficialSourceLink[]
|
||||
}),
|
||||
};
|
||||
}
|
||||
return link;
|
||||
return {
|
||||
...link,
|
||||
label: normalizeObservationSourceLabel(link.label, link.label),
|
||||
};
|
||||
});
|
||||
const seen = new Set<string>();
|
||||
return links.filter((link) => {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
HistoryPoint,
|
||||
NearbyStation,
|
||||
} from "@/lib/dashboard-types";
|
||||
import { normalizeObservationSourceLabel } from "@/lib/source-labels";
|
||||
|
||||
const METAR_WX_MAP: Record<
|
||||
string,
|
||||
@@ -98,7 +99,10 @@ function getObservationSourceCode(detail: CityDetail): string {
|
||||
}
|
||||
|
||||
function getObservationSourceTag(detail: CityDetail): string {
|
||||
const label = String(detail.current?.settlement_source_label || "")
|
||||
const label = normalizeObservationSourceLabel(
|
||||
detail.current?.settlement_source_label,
|
||||
"",
|
||||
)
|
||||
.trim()
|
||||
.toUpperCase();
|
||||
if (label) return label;
|
||||
|
||||
@@ -63,9 +63,9 @@ const MESSAGES: Record<Locale, Record<string, string>> = {
|
||||
"history.loading": "正在获取历史数据...",
|
||||
"history.error": "获取历史信息失败",
|
||||
"history.empty": "近 15 天暂无该城市历史数据",
|
||||
"history.hitRate": "DEB 结算胜率 (WU)",
|
||||
"history.hitRate": "DEB 结算胜率 (METAR)",
|
||||
"history.mae": "DEB MAE",
|
||||
"history.debHitRate": "DEB 结算胜率 (WU)",
|
||||
"history.debHitRate": "DEB 结算胜率 (METAR)",
|
||||
"history.debMae": "DEB MAE",
|
||||
"history.muMae": "μ MAE",
|
||||
"history.bestModelMae": "最佳单模型 MAE",
|
||||
@@ -230,9 +230,9 @@ const MESSAGES: Record<Locale, Record<string, string>> = {
|
||||
"history.loading": "Loading historical data...",
|
||||
"history.error": "Failed to load historical data",
|
||||
"history.empty": "No historical records for this city in the last 15 days",
|
||||
"history.hitRate": "DEB Settlement Hit Rate (WU)",
|
||||
"history.hitRate": "DEB Settlement Hit Rate (METAR)",
|
||||
"history.mae": "DEB MAE",
|
||||
"history.debHitRate": "DEB Settlement Hit Rate (WU)",
|
||||
"history.debHitRate": "DEB Settlement Hit Rate (METAR)",
|
||||
"history.debMae": "DEB MAE",
|
||||
"history.muMae": "μ MAE",
|
||||
"history.bestModelMae": "Best Single-model MAE",
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
export function normalizeObservationSourceLabel(
|
||||
value?: string | null,
|
||||
fallback = "METAR",
|
||||
) {
|
||||
const raw = String(value || "").trim();
|
||||
if (!raw) return fallback;
|
||||
const lowered = raw.toLowerCase();
|
||||
if (
|
||||
lowered === "wu" ||
|
||||
lowered === "wunderground"
|
||||
) {
|
||||
return "METAR";
|
||||
}
|
||||
if (lowered.includes("wunderground")) {
|
||||
return raw.replace(/wunderground/gi, "METAR");
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
export function normalizeObservationSourceCode(value?: string | null) {
|
||||
const code = String(value || "").trim().toLowerCase();
|
||||
if (code === "wu" || code === "wunderground") return "metar";
|
||||
return code;
|
||||
}
|
||||
Reference in New Issue
Block a user