diff --git a/frontend/components/dashboard/FutureForecastModal.tsx b/frontend/components/dashboard/FutureForecastModal.tsx index 28e79e50..99563036 100644 --- a/frontend/components/dashboard/FutureForecastModal.tsx +++ b/frontend/components/dashboard/FutureForecastModal.tsx @@ -534,6 +534,28 @@ export function FutureForecastModal() { ); const ai = parseAiAnalysis(detail.ai_analysis); const risk = detail.risk || {}; + const settlementSourceCode = String( + detail.current?.settlement_source || "", + ).toLowerCase(); + const isOfficialSettlementSource = + settlementSourceCode === "hko" || settlementSourceCode === "cwa"; + const settlementProfileLabel = isOfficialSettlementSource + ? locale === "en-US" + ? "Settlement source" + : "结算源" + : t("section.airport"); + const settlementProfileValue = + settlementSourceCode === "hko" + ? locale === "en-US" + ? "Hong Kong Observatory (HKO)" + : "香港天文台 (HKO)" + : settlementSourceCode === "cwa" + ? locale === "en-US" + ? "Central Weather Administration (CWA)" + : "交通部中央气象署 (CWA)" + : risk.airport + ? `${risk.airport}${risk.icao ? ` (${risk.icao})` : ""}` + : "--"; return (
- {t("section.airport")} - - - {risk.airport} - {risk.icao ? ` (${risk.icao})` : ""} + {settlementProfileLabel} + {settlementProfileValue}
diff --git a/frontend/lib/dashboard-utils.ts b/frontend/lib/dashboard-utils.ts index 64ecd66a..c8bcbe8c 100644 --- a/frontend/lib/dashboard-utils.ts +++ b/frontend/lib/dashboard-utils.ts @@ -1140,19 +1140,48 @@ export function getCityProfileStats(detail: CityDetail, locale: Locale = "zh-CN" const risk = detail.risk || {}; const current = detail.current || {}; const nearbyCount = Array.isArray(detail.mgm_nearby) ? detail.mgm_nearby.length : 0; + const sourceCode = getObservationSourceCode(detail); + const isOfficialSource = sourceCode === "hko" || sourceCode === "cwa"; + + const sourceDisplay = (() => { + if (sourceCode === "hko") { + return isEnglish(locale) + ? "Hong Kong Observatory (HKO)" + : "香港天文台 (HKO)"; + } + if (sourceCode === "cwa") { + return isEnglish(locale) + ? "Central Weather Administration (CWA)" + : "交通部中央气象署 (CWA)"; + } + const tag = getObservationSourceTag(detail); + if (sourceCode === "mgm") { + return isEnglish(locale) ? `MGM (${tag})` : `MGM (${tag})`; + } + if (risk.airport && risk.icao) return `${risk.airport} (${risk.icao})`; + if (risk.airport) return String(risk.airport); + return isEnglish(locale) ? "No profile" : "暂无档案"; + })(); return [ { - label: isEnglish(locale) ? "Settlement airport" : "结算机场", - value: - risk.airport && risk.icao - ? `${risk.airport} (${risk.icao})` - : isEnglish(locale) - ? "No profile" - : "暂无档案", + label: isOfficialSource + ? isEnglish(locale) + ? "Settlement source" + : "结算源" + : isEnglish(locale) + ? "Settlement airport" + : "结算机场", + value: sourceDisplay, }, { - label: isEnglish(locale) ? "Station distance" : "站点距离", + label: isOfficialSource + ? isEnglish(locale) + ? "Reference distance" + : "参考距离" + : isEnglish(locale) + ? "Station distance" + : "站点距离", value: risk.distance_km != null && Number.isFinite(Number(risk.distance_km)) ? `${risk.distance_km} km` @@ -1186,6 +1215,14 @@ export function getSettlementRiskNarrative( locale: Locale = "zh-CN", ) { const risk = detail.risk || {}; + const sourceCode = getObservationSourceCode(detail); + const stationTerm = sourceCode === "hko" || sourceCode === "cwa" + ? isEnglish(locale) + ? "settlement reference station" + : "结算参考站" + : isEnglish(locale) + ? "settlement airport" + : "结算机场"; const lines: string[] = []; if (risk.warning) { @@ -1200,20 +1237,20 @@ export function getSettlementRiskNarrative( if (risk.distance_km >= 60) { lines.push( isEnglish(locale) - ? "Settlement airport is far from urban core; market feel and settlement value may diverge significantly." - : "结算机场与城市核心区域距离偏大,盘面温度与结算值可能出现明显背离。", + ? `The ${stationTerm} is far from urban core; market feel and settlement value may diverge significantly.` + : `${stationTerm}与城市核心区域距离偏大,盘面温度与结算值可能出现明显背离。`, ); } else if (risk.distance_km >= 25) { lines.push( isEnglish(locale) - ? "Settlement airport has material distance from downtown; peak/overnight rhythm should prioritize airport station." - : "结算机场与城区存在可感知距离,午后峰值和夜间降温节奏需要优先看机场站。", + ? `The ${stationTerm} has material distance from downtown; peak/overnight rhythm should prioritize the settlement station.` + : `${stationTerm}与城区存在可感知距离,午后峰值和夜间降温节奏需要优先看结算站。`, ); } else { lines.push( isEnglish(locale) - ? "Settlement airport is close enough; city feel and settlement temperature are usually more synchronized." - : "结算机场距离较近,城市体感与结算温度通常更同步。", + ? `The ${stationTerm} is close enough; city feel and settlement temperature are usually more synchronized.` + : `${stationTerm}距离较近,城市体感与结算温度通常更同步。`, ); } } diff --git a/src/data_collection/city_registry.py b/src/data_collection/city_registry.py index fc187d09..ffb74761 100644 --- a/src/data_collection/city_registry.py +++ b/src/data_collection/city_registry.py @@ -60,8 +60,8 @@ CITY_REGISTRY = { }, "hong kong": { "name": "Hong Kong", - "lat": 22.3080, - "lon": 113.9185, + "lat": 22.3019, + "lon": 114.1742, "icao": "VHHH", "settlement_source": "hko", "tz_offset": 28800, @@ -69,14 +69,14 @@ CITY_REGISTRY = { "is_major": True, "risk_level": "medium", "risk_emoji": "🟡", - "airport_name": "Hong Kong 国际机场", - "distance_km": 31.0, + "airport_name": "香港天文台总部", + "distance_km": 2.0, "warning": "海风与地形共同作用,午后对流触发后温度回落可能偏快。", }, "taipei": { "name": "Taipei", - "lat": 25.0694, - "lon": 121.5526, + "lat": 25.0377, + "lon": 121.5149, "icao": "RCSS", "settlement_source": "cwa", "tz_offset": 28800, @@ -84,8 +84,8 @@ CITY_REGISTRY = { "is_major": True, "risk_level": "low", "risk_emoji": "🟢", - "airport_name": "台北松山机场", - "distance_km": 4.0, + "airport_name": "中央气象署台北站", + "distance_km": 1.5, "warning": "盆地地形叠加都市热岛,夏季午后对流前后温度波动较快。", }, "shanghai": {