feat: Implement Wunderground data integration, enhance dashboard weather data processing, and add future forecast modal.

This commit is contained in:
2569718930@qq.com
2026-03-25 18:03:56 +08:00
parent fd210ac730
commit 7589fd74bf
6 changed files with 331 additions and 32 deletions
+20
View File
@@ -66,6 +66,25 @@ export interface CurrentConditions {
dewpoint?: number | null;
}
export interface AirportCurrentConditions {
temp: number | null;
obs_time: string | null;
max_so_far?: number | null;
max_temp_time?: string | null;
obs_age_min?: number | null;
report_time?: string | null;
receipt_time?: string | null;
obs_time_epoch?: number | null;
wind_speed_kt?: number | null;
wind_dir?: number | null;
humidity?: number | null;
cloud_desc?: string | null;
visibility_mi?: number | null;
wx_desc?: string | null;
raw_metar?: string | null;
source_label?: string | null;
}
export interface NearbyStation {
name?: string;
icao?: string;
@@ -271,6 +290,7 @@ export interface CityDetail {
local_date: string;
risk: DashboardRisk;
current: CurrentConditions;
airport_current?: AirportCurrentConditions;
mgm?: MgmData;
mgm_nearby?: NearbyStation[];
nearby_source?: string;
+32
View File
@@ -284,6 +284,10 @@ export function getTemperatureChartData(
? metarObservationSource
: officialObservationSource
: metarObservationSource;
const airportMetarSource =
settlementSource && observationCode === "wunderground"
? metarObservationSource
: [];
const metarFallbackTag = (() => {
const icao = String(detail.risk?.icao || "").trim().toUpperCase();
if (!icao) return "METAR";
@@ -314,6 +318,20 @@ export function getTemperatureChartData(
existing == null ? temp : Math.max(Number(existing), Number(temp));
}
});
const airportMetarPoints = new Array(times.length).fill(null);
airportMetarSource.forEach((item) => {
const parts = String(item.time || "").split(":");
const hour = Number.parseInt(parts[0], 10);
if (Number.isNaN(hour)) return;
const key = `${String(hour).padStart(2, "0")}:00`;
const index = times.indexOf(key);
const temp = item.temp ?? null;
if (index >= 0 && temp != null) {
const existing = airportMetarPoints[index];
airportMetarPoints[index] =
existing == null ? temp : Math.max(Number(existing), Number(temp));
}
});
const mgmPoints = new Array(times.length).fill(null);
if (detail.mgm?.temp != null && detail.mgm?.time) {
@@ -344,6 +362,7 @@ export function getTemperatureChartData(
const allValues = [
...debTemps.filter((value) => value != null),
...metarPoints.filter((value) => value != null),
...airportMetarPoints.filter((value) => value != null),
...mgmPoints.filter((value) => value != null),
...mgmHourlyPoints.filter((value) => value != null),
] as number[];
@@ -414,6 +433,18 @@ export function getTemperatureChartData(
.join(" -> ");
legendParts.push(`${observationDisplayTag}: ${recentText}`);
}
if (airportMetarSource.length > 0) {
const airportRecentText = [...airportMetarSource]
.slice(-4)
.reverse()
.map((item) => `${item.temp}${detail.temp_symbol}@${item.time}`)
.join(" -> ");
legendParts.push(
isEnglish(locale)
? `${metarFallbackTag}: ${airportRecentText}`
: `${metarFallbackTag}: ${airportRecentText}`,
);
}
if (shouldUseMetarFallback) {
legendParts.push(
isEnglish(locale)
@@ -453,6 +484,7 @@ export function getTemperatureChartData(
return {
datasets: {
airportMetarPoints,
debFuture,
debPast,
hasMgmHourly,