- 后端 Open-Meteo 请求加 past_days=1,小时数据从 00:00 开始 - 前端图表层填充完整 00:00-23:00 时间轴,缺失时段置空 - 城市深度分析门槛从 >1 降为 >=1,单模型城市不再被拦 - hydration 队列加最大重试 3 次,防止永久卡在等待模型补齐 - 移除右侧面板历史对账按钮
55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
import type { CityDetail } from "@/lib/dashboard-types";
|
|
import { normalizeCityKey } from "@/components/dashboard/scan-terminal/decision-utils";
|
|
|
|
export function findDetailForCity(
|
|
detailsByName: Record<string, CityDetail>,
|
|
cityName?: string | null,
|
|
) {
|
|
const target = normalizeCityKey(cityName);
|
|
if (!target) return null;
|
|
return (
|
|
Object.values(detailsByName).find((detail) =>
|
|
[detail?.name, detail?.display_name].some(
|
|
(value) => normalizeCityKey(value) === target,
|
|
),
|
|
) || null
|
|
);
|
|
}
|
|
|
|
export function countDetailModels(detail?: CityDetail | null, targetDate?: string | null) {
|
|
if (!detail) return 0;
|
|
const date = String(targetDate || detail.local_date || "").trim();
|
|
const dailyModels = date ? detail.multi_model_daily?.[date]?.models : null;
|
|
const models =
|
|
dailyModels && typeof dailyModels === "object"
|
|
? dailyModels
|
|
: detail.multi_model || {};
|
|
return Object.values(models).filter((value) =>
|
|
Number.isFinite(Number(value)),
|
|
).length;
|
|
}
|
|
|
|
export function countDetailForecastDays(detail?: CityDetail | null) {
|
|
const daily = detail?.forecast?.daily;
|
|
return Array.isArray(daily) ? daily.length : 0;
|
|
}
|
|
|
|
export function isFullEnoughForDeepAnalysis(detail?: CityDetail | null) {
|
|
if (!detail) return false;
|
|
if (detail.detail_depth && detail.detail_depth !== "full") return false;
|
|
const hourlyTimes = Array.isArray(detail.hourly?.times)
|
|
? detail.hourly?.times || []
|
|
: [];
|
|
const hourlyTemps = Array.isArray(detail.hourly?.temps)
|
|
? detail.hourly?.temps || []
|
|
: [];
|
|
if (!detail.local_time || hourlyTimes.length === 0 || hourlyTemps.length === 0) {
|
|
return false;
|
|
}
|
|
return (
|
|
countDetailModels(detail, detail.local_date) >= 1 &&
|
|
countDetailForecastDays(detail) >= 1
|
|
);
|
|
}
|
|
|