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": {