修复图表预测曲线和机场观测标签

This commit is contained in:
2569718930@qq.com
2026-06-16 21:18:22 +08:00
parent 1aa4fab6d8
commit 4627a110bf
2 changed files with 185 additions and 8 deletions
@@ -159,6 +159,70 @@ export function runTests() {
`multi-model curves must use models_hourly.times instead of hourly.times; got ${independentModelPeak?.label}`,
);
const floatingIsoModelTimelineChart = buildFullDayChartData(
{
city: "paris",
local_date: "2026-06-14",
local_time: "12:00",
temp_symbol: "°C",
tz_offset_seconds: 2 * 3600,
} as any,
{
forecastTodayHigh: 24,
debPrediction: 24,
localDate: "2026-06-14",
localTime: "12:00",
times: ["00:00", "12:00", "23:00"],
temps: [18, 21, 16],
modelTimes: Array.from({ length: 24 }, (_, hour) => `2026-06-14T${String(hour).padStart(2, "0")}:00`),
modelCurves: {
ECMWF: Array.from({ length: 24 }, (_, hour) => hour),
},
} as any,
true,
);
const floatingIsoModelLatePoint = floatingIsoModelTimelineChart.data.find(
(point) => point.label === "23:00:00" && point.model_curve_ECMWF === 23,
);
assert(
floatingIsoModelLatePoint,
"floating ISO model times without an explicit timezone must stay on the city-local clock so late-day forecast points do not disappear",
);
const staleDetailWithCurrentRowChart = buildFullDayChartData(
{
city: "paris",
local_date: "2026-06-16",
local_time: "14:59",
temp_symbol: "°C",
tz_offset_seconds: 2 * 3600,
} as any,
{
forecastTodayHigh: 24,
debPrediction: 24,
localDate: "2026-06-14",
localTime: "11:00",
times: ["00:00", "12:00", "23:00"],
temps: [18, 21, 16],
modelTimes: Array.from({ length: 72 }, (_, index) => {
const date = index < 24 ? "2026-06-14" : index < 48 ? "2026-06-15" : "2026-06-16";
const hour = index % 24;
return `${date}T${String(hour).padStart(2, "0")}:00`;
}),
modelCurves: {
ECMWF: Array.from({ length: 72 }, (_, index) => index),
},
} as any,
true,
);
const currentDayModelLatePoint = staleDetailWithCurrentRowChart.data.find(
(point) => point.label === "23:00:00" && point.model_curve_ECMWF === 71,
);
assert(
currentDayModelLatePoint,
"chart should use the current scan row local date when cached detail localDate is older so today's model curve is drawn through 23:00",
);
const correctedDetailChart = getTemperatureChartData(
{
name: "shanghai",
@@ -571,6 +635,51 @@ export function runTests() {
"non-US airport-primary fallback without explicit source metadata must not default to NOAA MADIS",
);
const parisAirportDisplayNameChart = buildFullDayChartData(
{
city: "paris",
local_date: "2026-06-16",
local_time: "14:59",
tz_offset_seconds: 2 * 60 * 60,
airport: "Paris-Le Bourget 机场",
metar_context: {
station: "LFPB",
station_label: "Paris-Le Bourget Airport",
},
temp_symbol: "°C",
} as any,
{
localDate: "2026-06-16",
localTime: "14:59",
times: ["00:00", "12:00", "18:00"],
temps: [14, 20, 18],
settlementStationCode: "LFPB",
settlementStationLabel: "Paris-Le Bourget Airport",
airportPrimary: {
temp: 20.0,
obs_time: "2026-06-16T12:59:00Z",
},
airportPrimaryTodayObs: [
["2026-06-16T10:00:00Z", 18],
["2026-06-16T12:00:00Z", 20],
],
metarTodayObs: [
["2026-06-16T10:30:00Z", 18],
["2026-06-16T12:30:00Z", 20],
],
} as any,
false,
);
const parisAirportDisplayNameSeries = parisAirportDisplayNameChart.series.find((item) => item.key === "madis");
assert(
parisAirportDisplayNameSeries?.label === "LFPB METAR",
`airport-primary fallback must prefer station code over display name; got ${parisAirportDisplayNameSeries?.label}`,
);
assert(
!parisAirportDisplayNameChart.series.some((item) => item.key === "metar"),
"same-station airport-primary observations should suppress the redundant METAR line even when cadences differ",
);
const ankaraScanSeedChart = buildFullDayChartData(
{
city: "ankara",