feat: Introduce dashboard data types, utilities, market alert engine, and panel sections.
This commit is contained in:
@@ -550,7 +550,7 @@ export function ModelForecast({
|
||||
hideTitle?: boolean;
|
||||
targetDate?: string | null;
|
||||
}) {
|
||||
const { t } = useI18n();
|
||||
const { locale, t } = useI18n();
|
||||
const view = getModelView(detail, targetDate);
|
||||
const modelEntries = Object.entries(view.models).filter(([, value]) =>
|
||||
Number.isFinite(Number(value)),
|
||||
@@ -565,6 +565,14 @@ export function ModelForecast({
|
||||
? Math.max(...comparisonValues) + 1
|
||||
: 1;
|
||||
const range = Math.max(maxValue - minValue, 1);
|
||||
const getModelDisplayName = (name: string) => {
|
||||
if (String(name).trim().toLowerCase() === "meteoblue") {
|
||||
return locale === "en-US"
|
||||
? "Meteoblue (Daily Max)"
|
||||
: "Meteoblue (日最高温)";
|
||||
}
|
||||
return name;
|
||||
};
|
||||
|
||||
return (
|
||||
<section className="models-section">
|
||||
@@ -587,7 +595,7 @@ export function ModelForecast({
|
||||
return (
|
||||
<div key={name} className="model-row">
|
||||
<div className="model-name" title={name}>
|
||||
{name}
|
||||
{getModelDisplayName(name)}
|
||||
</div>
|
||||
<div className="model-bar-track">
|
||||
<div
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user