fix: align hong kong compact hko stat

This commit is contained in:
2569718930@qq.com
2026-06-06 17:01:39 +08:00
parent 2766b6463c
commit 89f77b8db4
4 changed files with 103 additions and 3 deletions
@@ -31,6 +31,7 @@ import {
normObs,
prefersHighFrequencyRunwayResolution,
readSessionCache,
selectCompactSecondaryTemp,
selectDisplayRunwayTemp,
seedHourlyForecastFromRow,
shouldPollLiveChart,
@@ -635,6 +636,7 @@ export function LiveTemperatureThresholdChart({
}, [chartSeries, userToggledKeys, city, showRunwayDetails]);
const {
isHKO,
isShenzhen,
metarHeaderLabel,
metarHighLabel,
@@ -642,11 +644,17 @@ export function LiveTemperatureThresholdChart({
runwayHighLabel,
} = useMemo(() => getLiveObservationLabels(row, chartHourly), [row, chartHourly]);
const { currentRunwayTemp, observedHighMetar, observedHighRunway } = useMemo(
const { currentMetarTemp, currentRunwayTemp, observedHighMetar, observedHighRunway } = useMemo(
() => getObservationDisplayMetrics(row, chartHourly, settlementPlate),
[row, chartHourly, settlementPlate],
);
const displayRunwayTemp = selectDisplayRunwayTemp(liveTemp, currentRunwayTemp, hasRunwayData);
const displayMetarTemp = selectCompactSecondaryTemp({
isHKO,
isShenzhen,
displayMetarTemp: currentMetarTemp,
observedHighMetar,
});
const wundergroundDailyHigh = getWundergroundDailyHigh(chartHourly);
const localDateStr = chartLocalDate || new Date().toISOString().slice(0, 10);
@@ -805,6 +813,7 @@ export function LiveTemperatureThresholdChart({
visible_series: activeSeries.map((item) => item.key),
live_temp: liveTemp,
current_runway_temp: currentRunwayTemp,
current_metar_temp: currentMetarTemp,
observed_high_metar: observedHighMetar,
observed_high_runway: observedHighRunway,
});
@@ -814,6 +823,7 @@ export function LiveTemperatureThresholdChart({
chartSeries,
city,
compact,
currentMetarTemp,
currentRunwayTemp,
detailError,
hasRunwayData,
@@ -960,6 +970,7 @@ export function LiveTemperatureThresholdChart({
metarHighLabel={metarHighLabel}
isShenzhen={isShenzhen}
displayRunwayTemp={displayRunwayTemp}
displayMetarTemp={displayMetarTemp}
observedHighMetar={observedHighMetar}
observedHighRunway={observedHighRunway}
wundergroundDailyHigh={wundergroundDailyHigh}
@@ -1034,4 +1045,5 @@ export const __getInitialDetailLoadDelayMsForTest = getInitialDetailLoadDelayMs;
export const __shouldFetchCityDetailForChartForTest = shouldFetchCityDetailForChart;
export const __shouldPollLiveChartForTest = shouldPollLiveChart;
export const __mergePatchIntoHourlyForTest = mergePatchIntoHourly;
export const __selectCompactSecondaryTempForTest = selectCompactSecondaryTemp;
export const __selectDisplayRunwayTempForTest = selectDisplayRunwayTemp;
@@ -76,6 +76,7 @@ export function TemperatureStatsBars({
metarHighLabel,
isShenzhen,
displayRunwayTemp,
displayMetarTemp,
observedHighMetar,
observedHighRunway,
wundergroundDailyHigh,
@@ -97,6 +98,7 @@ export function TemperatureStatsBars({
metarHighLabel: string;
isShenzhen: boolean;
displayRunwayTemp: number | null;
displayMetarTemp: number | null;
observedHighMetar: number | null;
observedHighRunway: number | null;
wundergroundDailyHigh: number | null;
@@ -129,7 +131,7 @@ export function TemperatureStatsBars({
<span className="text-slate-300">|</span>
<span className="font-semibold text-slate-500">
{labels.compactSecondary}:{" "}
<strong className="text-blue-600 font-mono">{temp(observedHighMetar, tempSymbol)}</strong>
<strong className="text-blue-600 font-mono">{temp(displayMetarTemp, tempSymbol)}</strong>
</span>
</div>
) : (
@@ -9,6 +9,7 @@ import {
__getVisibleTemperatureSeriesForTest,
__isTemperatureSeriesVisibleByDefaultForTest,
__mergePatchIntoHourlyForTest,
__selectCompactSecondaryTempForTest,
__selectDisplayRunwayTempForTest,
} from "@/components/dashboard/scan-terminal/LiveTemperatureThresholdChart";
import { __buildTemperatureTooltipRowsForTest } from "@/components/dashboard/scan-terminal/TemperatureTooltipContent";
@@ -976,6 +977,68 @@ export function runTests() {
"runway header should prefer runway-history current temp even when the latest detail payload lacks runway_obs snapshot",
);
const hongKongMetrics = __getObservationDisplayMetricsForTest(
{
city: "hong kong",
local_date: "2026-06-06",
local_time: "16:48",
tz_offset_seconds: 8 * 60 * 60,
current_temp: 30.4,
current_max_so_far: 30.4,
temp_symbol: "°C",
} as any,
{
localTime: "16:48",
times: ["00:00", "12:00", "18:00", "23:00"],
temps: [28.0, 31.0, 29.0, 28.0],
settlementTodayObs: [
{ time: "14:00", temp: 30.4 },
{ time: "16:40", temp: 28.1 },
],
airportPrimary: {
temp: 28.7,
obs_time: "2026-06-06T16:48:00+08:00",
source_code: "cowin_obs",
source_label: "CoWIN 6087",
},
airportPrimaryTodayObs: [
{ time: "16:47", temp: 28.6 },
{ time: "16:48", temp: 28.7 },
],
} as any,
null,
);
assert(
hongKongMetrics.currentRunwayTemp === 28.7,
"Hong Kong primary compact stat should stay on the latest CoWIN reference-station point",
);
assert(
(hongKongMetrics as any).currentMetarTemp === 28.1,
"Hong Kong secondary compact stat should have the latest HKO point separate from the HKO daily high",
);
assert(
hongKongMetrics.observedHighMetar === 30.4,
"Hong Kong HKO daily high should still be available for expanded daily-high summaries",
);
assert(
__selectCompactSecondaryTempForTest({
isHKO: true,
isShenzhen: false,
displayMetarTemp: (hongKongMetrics as any).currentMetarTemp,
observedHighMetar: hongKongMetrics.observedHighMetar,
}) === 28.1,
"Hong Kong compact HKO stat should render the latest HKO point, not the HKO daily high",
);
assert(
__selectCompactSecondaryTempForTest({
isHKO: false,
isShenzhen: false,
displayMetarTemp: 72.0,
observedHighMetar: 73.9,
}) === 73.9,
"non-HKO compact secondary stat should keep the existing daily-high behavior",
);
const wuhanRunwayChart = __buildTemperatureChartDataForTest(
{
city: "wuhan",
@@ -845,9 +845,14 @@ function getObservationDisplayMetrics(
null;
}
const currentMetarTemp =
latestSettlement ??
latestMetar ??
airportCurrentTemp ??
null;
const observedHighMetar = airportHigh ?? highSettlement ?? highMetar ?? rowMetarHigh ?? null;
return { currentRunwayTemp, observedHighMetar, observedHighRunway };
return { currentMetarTemp, currentRunwayTemp, observedHighMetar, observedHighRunway };
}
function selectDisplayRunwayTemp(
@@ -859,6 +864,23 @@ function selectDisplayRunwayTemp(
return liveTemp;
}
function selectCompactSecondaryTemp({
isHKO,
isShenzhen,
displayMetarTemp,
observedHighMetar,
}: {
isHKO: boolean;
isShenzhen: boolean;
displayMetarTemp: number | null;
observedHighMetar: number | null;
}) {
if (isHKO && !isShenzhen && displayMetarTemp !== null) {
return displayMetarTemp;
}
return observedHighMetar;
}
function isSettlementRunway(row: ScanOpportunityRow | null, rwy: string) {
const cityKey = normalizeCityKey(row?.city);
const settlementPairs = SETTLEMENT_RUNWAY_PAIRS[cityKey] || [];
@@ -2485,6 +2507,7 @@ export {
normalizeCityKey,
prefersHighFrequencyRunwayResolution,
readSessionCache,
selectCompactSecondaryTemp,
selectDisplayRunwayTemp,
seedHourlyForecastFromRow,
seriesStats,