feat: Introduce dashboard data types, utilities, market alert engine, and panel sections.

This commit is contained in:
2569718930@qq.com
2026-03-10 10:07:18 +08:00
parent 732b3c10a5
commit e5011c5c8f
4 changed files with 83 additions and 9 deletions
+3
View File
@@ -169,7 +169,10 @@ export interface SourceForecasts {
forecast_periods?: WeatherGovPeriod[];
};
meteoblue?: {
today_high?: number | null;
daily_highs?: Array<number | null>;
unit?: string | null;
url?: string | null;
};
}
+42 -2
View File
@@ -330,18 +330,58 @@ export function getProbabilityView(detail: CityDetail, targetDate?: string | nul
}
export function getModelView(detail: CityDetail, targetDate?: string | null) {
const pickMeteoblueForDate = (dateStr: string) => {
const meteoblue = detail.source_forecasts?.meteoblue;
if (!meteoblue) return null;
const dates = detail.forecast?.daily?.map((item) => item.date) || [];
const index = dates.findIndex((date) => date === dateStr);
const dailyHighs = Array.isArray(meteoblue.daily_highs)
? meteoblue.daily_highs
: [];
if (index >= 0) {
const byDailyHigh = Number(dailyHighs[index]);
if (Number.isFinite(byDailyHigh)) return byDailyHigh;
}
const todayHigh = Number(meteoblue.today_high);
if (
Number.isFinite(todayHigh) &&
(dateStr === detail.local_date || index === 0)
) {
return todayHigh;
}
return null;
};
const withMeteoblue = (
models: Record<string, number | null>,
dateStr: string,
) => {
const nextModels = { ...models };
if (!Number.isFinite(Number(nextModels.Meteoblue))) {
const meteoblueVal = pickMeteoblueForDate(dateStr);
if (Number.isFinite(Number(meteoblueVal))) {
nextModels.Meteoblue = Number(meteoblueVal);
}
}
return nextModels;
};
const date = targetDate || detail.local_date;
const daily = detail.multi_model_daily?.[date];
if (daily) {
return {
deb: daily.deb?.prediction ?? null,
models: daily.models || {},
models: withMeteoblue(daily.models || {}, date),
};
}
return {
deb: detail.deb?.prediction ?? null,
models: detail.multi_model || {},
models: withMeteoblue(detail.multi_model || {}, date),
};
}