Clarify TAF intraday summaries
This commit is contained in:
@@ -1182,7 +1182,12 @@ export function FutureForecastModal() {
|
|||||||
</div>
|
</div>
|
||||||
{view.front.summary ? (
|
{view.front.summary ? (
|
||||||
<div className="future-trend-summary">
|
<div className="future-trend-summary">
|
||||||
{view.front.summary}
|
{Array.isArray(view.front.summaryLines) &&
|
||||||
|
view.front.summaryLines.length > 0
|
||||||
|
? view.front.summaryLines.map((line, index) => (
|
||||||
|
<div key={`${index}-${line}`}>{line}</div>
|
||||||
|
))
|
||||||
|
: view.front.summary}
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -832,6 +832,11 @@ export function computeFrontTrendSignal(
|
|||||||
const currentDew = Number(detail.current?.dewpoint);
|
const currentDew = Number(detail.current?.dewpoint);
|
||||||
|
|
||||||
if (!slice.length) {
|
if (!slice.length) {
|
||||||
|
const fallbackSummary =
|
||||||
|
backendSummary ||
|
||||||
|
(isEnglish(locale)
|
||||||
|
? "Insufficient intraday structured data. Keep baseline monitoring."
|
||||||
|
: "当日日内结构化数据不足,暂时只保留基础监控。");
|
||||||
return {
|
return {
|
||||||
confidence: "low",
|
confidence: "low",
|
||||||
label: isEnglish(locale) ? "Monitoring" : "监控中",
|
label: isEnglish(locale) ? "Monitoring" : "监控中",
|
||||||
@@ -845,11 +850,8 @@ export function computeFrontTrendSignal(
|
|||||||
upperAirSummary,
|
upperAirSummary,
|
||||||
precipMax: 0,
|
precipMax: 0,
|
||||||
score: 0,
|
score: 0,
|
||||||
summary:
|
summary: fallbackSummary,
|
||||||
backendSummary ||
|
summaryLines: [fallbackSummary],
|
||||||
(isEnglish(locale)
|
|
||||||
? "Insufficient intraday structured data. Keep baseline monitoring."
|
|
||||||
: "当日日内结构化数据不足,暂时只保留基础监控。"),
|
|
||||||
weatherGovPeriods: [] as ReturnType<typeof getForecastTextForDate>,
|
weatherGovPeriods: [] as ReturnType<typeof getForecastTextForDate>,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -918,6 +920,10 @@ export function computeFrontTrendSignal(
|
|||||||
const markerSummary = (
|
const markerSummary = (
|
||||||
marker:
|
marker:
|
||||||
| {
|
| {
|
||||||
|
marker_type?: string | null;
|
||||||
|
start_local?: string | null;
|
||||||
|
end_local?: string | null;
|
||||||
|
suppression_level?: string | null;
|
||||||
summary_zh?: string | null;
|
summary_zh?: string | null;
|
||||||
summary_en?: string | null;
|
summary_en?: string | null;
|
||||||
}
|
}
|
||||||
@@ -945,6 +951,66 @@ export function computeFrontTrendSignal(
|
|||||||
return start !== null && start > currentMinutes;
|
return start !== null && start > currentMinutes;
|
||||||
})
|
})
|
||||||
: null;
|
: null;
|
||||||
|
const sameMarker = (
|
||||||
|
left:
|
||||||
|
| { marker_type?: string | null; start_local?: string | null; end_local?: string | null }
|
||||||
|
| null
|
||||||
|
| undefined,
|
||||||
|
right:
|
||||||
|
| { marker_type?: string | null; start_local?: string | null; end_local?: string | null }
|
||||||
|
| null
|
||||||
|
| undefined,
|
||||||
|
) =>
|
||||||
|
!!left &&
|
||||||
|
!!right &&
|
||||||
|
String(left.marker_type || "") === String(right.marker_type || "") &&
|
||||||
|
String(left.start_local || "") === String(right.start_local || "") &&
|
||||||
|
String(left.end_local || "") === String(right.end_local || "");
|
||||||
|
const formatTafSegmentLine = (
|
||||||
|
marker:
|
||||||
|
| {
|
||||||
|
marker_type?: string | null;
|
||||||
|
start_local?: string | null;
|
||||||
|
end_local?: string | null;
|
||||||
|
suppression_level?: string | null;
|
||||||
|
}
|
||||||
|
| null
|
||||||
|
| undefined,
|
||||||
|
kind: "current" | "next" | "peak",
|
||||||
|
) => {
|
||||||
|
if (!marker) return "";
|
||||||
|
const range = `${normalizeHm(marker.start_local) || "--:--"}-${normalizeHm(marker.end_local) || "--:--"}`;
|
||||||
|
const typeLabel = formatTafMarkerType(
|
||||||
|
String(marker.marker_type || ""),
|
||||||
|
locale,
|
||||||
|
);
|
||||||
|
const level = String(marker.suppression_level || "low").toLowerCase();
|
||||||
|
const statusText = isEnglish(locale)
|
||||||
|
? level === "high"
|
||||||
|
? "shows shower or thunderstorm disruption"
|
||||||
|
: level === "medium"
|
||||||
|
? "shows cloud or light-rain disruption"
|
||||||
|
: "stays relatively stable"
|
||||||
|
: level === "high"
|
||||||
|
? "有阵雨或雷暴扰动"
|
||||||
|
: level === "medium"
|
||||||
|
? "有云量或弱降水扰动"
|
||||||
|
: "以稳定为主";
|
||||||
|
const prefix = isEnglish(locale)
|
||||||
|
? kind === "current"
|
||||||
|
? "Current TAF"
|
||||||
|
: kind === "next"
|
||||||
|
? "Next TAF"
|
||||||
|
: "Peak-window TAF"
|
||||||
|
: kind === "current"
|
||||||
|
? "当前 TAF"
|
||||||
|
: kind === "next"
|
||||||
|
? "下一段 TAF"
|
||||||
|
: "峰值窗口 TAF";
|
||||||
|
return isEnglish(locale)
|
||||||
|
? `${prefix}: ${typeLabel} (${range}), ${statusText}.`
|
||||||
|
: `${prefix}:${typeLabel}(${range}),${statusText}。`;
|
||||||
|
};
|
||||||
const peakWindowTafMarker =
|
const peakWindowTafMarker =
|
||||||
tafSignal.available &&
|
tafSignal.available &&
|
||||||
peakWindowStartMinutes !== null &&
|
peakWindowStartMinutes !== null &&
|
||||||
@@ -956,27 +1022,7 @@ export function computeFrontTrendSignal(
|
|||||||
return start <= peakWindowEndMinutes && end >= peakWindowStartMinutes;
|
return start <= peakWindowEndMinutes && end >= peakWindowStartMinutes;
|
||||||
})
|
})
|
||||||
: null;
|
: null;
|
||||||
const currentTafSummary = markerSummary(currentTafMarker);
|
|
||||||
const peakTafSummary = markerSummary(peakWindowTafMarker);
|
const peakTafSummary = markerSummary(peakWindowTafMarker);
|
||||||
const nextTafSummary = markerSummary(nextTafMarker);
|
|
||||||
const tafTimelineSummary =
|
|
||||||
tafSignal.available && dateStr === detail.local_date
|
|
||||||
? (() => {
|
|
||||||
if (currentTafMarker && currentTafSummary) {
|
|
||||||
const range = `${normalizeHm(currentTafMarker.start_local) || "--:--"}-${normalizeHm(currentTafMarker.end_local) || "--:--"}`;
|
|
||||||
return isEnglish(locale)
|
|
||||||
? `Current active TAF segment (${range}): ${currentTafSummary}`
|
|
||||||
: `当前生效的 TAF 时段(${range}):${currentTafSummary}`;
|
|
||||||
}
|
|
||||||
if (nextTafMarker && nextTafSummary) {
|
|
||||||
const range = `${normalizeHm(nextTafMarker.start_local) || "--:--"}-${normalizeHm(nextTafMarker.end_local) || "--:--"}`;
|
|
||||||
return isEnglish(locale)
|
|
||||||
? `Next TAF segment (${range}): ${nextTafSummary}`
|
|
||||||
: `下一段 TAF 时段(${range}):${nextTafSummary}`;
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
})()
|
|
||||||
: "";
|
|
||||||
const peakTafStillRelevant =
|
const peakTafStillRelevant =
|
||||||
peakWindowEndMinutes === null ||
|
peakWindowEndMinutes === null ||
|
||||||
currentMinutes === null ||
|
currentMinutes === null ||
|
||||||
@@ -984,19 +1030,19 @@ export function computeFrontTrendSignal(
|
|||||||
const effectivePeakTafSummary =
|
const effectivePeakTafSummary =
|
||||||
peakTafStillRelevant &&
|
peakTafStillRelevant &&
|
||||||
peakTafSummary &&
|
peakTafSummary &&
|
||||||
peakTafSummary !== currentTafSummary
|
!sameMarker(peakWindowTafMarker, currentTafMarker) &&
|
||||||
|
!sameMarker(peakWindowTafMarker, nextTafMarker)
|
||||||
? peakTafSummary
|
? peakTafSummary
|
||||||
: "";
|
: "";
|
||||||
const currentTafLine = tafTimelineSummary
|
const currentTafLine = currentTafMarker
|
||||||
? isEnglish(locale)
|
? formatTafSegmentLine(currentTafMarker, "current")
|
||||||
? `Current TAF: ${tafTimelineSummary}`
|
: nextTafMarker
|
||||||
: `当前 TAF:${tafTimelineSummary}`
|
? formatTafSegmentLine(nextTafMarker, "next")
|
||||||
: "";
|
: "";
|
||||||
const peakTafLine = effectivePeakTafSummary
|
const peakTafLine =
|
||||||
? isEnglish(locale)
|
effectivePeakTafSummary && peakWindowTafMarker
|
||||||
? `Peak-window TAF: ${effectivePeakTafSummary}`
|
? formatTafSegmentLine(peakWindowTafMarker, "peak")
|
||||||
: `峰值窗口 TAF:${effectivePeakTafSummary}`
|
: "";
|
||||||
: "";
|
|
||||||
const tafFallbackSummary =
|
const tafFallbackSummary =
|
||||||
currentTafLine || peakTafLine ? "" : tafSummary;
|
currentTafLine || peakTafLine ? "" : tafSummary;
|
||||||
upperAirSummary = [
|
upperAirSummary = [
|
||||||
@@ -1465,18 +1511,26 @@ export function computeFrontTrendSignal(
|
|||||||
return "";
|
return "";
|
||||||
})()
|
})()
|
||||||
: "";
|
: "";
|
||||||
const backendSupplement =
|
const tafSummaryLineBody = [
|
||||||
backendSummary && backendSummary !== summary ? backendSummary : "";
|
|
||||||
const combinedSummary = [
|
|
||||||
summary,
|
|
||||||
currentTafLine,
|
currentTafLine,
|
||||||
peakTafLine,
|
peakTafLine,
|
||||||
tafFallbackSummary,
|
tafFallbackSummary,
|
||||||
tafContrastSummary,
|
tafContrastSummary,
|
||||||
backendSupplement,
|
|
||||||
]
|
]
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(isEnglish(locale) ? " " : "");
|
.join(isEnglish(locale) ? " " : "");
|
||||||
|
const surfaceSummaryLine = summary
|
||||||
|
? isEnglish(locale)
|
||||||
|
? `Surface: ${summary}`
|
||||||
|
: `近地面:${summary}`
|
||||||
|
: "";
|
||||||
|
const tafSummaryLine = tafSummaryLineBody
|
||||||
|
? isEnglish(locale)
|
||||||
|
? `Airport TAF: ${tafSummaryLineBody}`
|
||||||
|
: `机场 TAF:${tafSummaryLineBody}`
|
||||||
|
: "";
|
||||||
|
const summaryLines = [surfaceSummaryLine, tafSummaryLine].filter(Boolean);
|
||||||
|
const combinedSummary = summaryLines.join(isEnglish(locale) ? " " : "");
|
||||||
const cloudNote = (() => {
|
const cloudNote = (() => {
|
||||||
if (cloudDelta >= 15 && tempDelta >= 0.8 && dewDelta >= 0.8) {
|
if (cloudDelta >= 15 && tempDelta >= 0.8 && dewDelta >= 0.8) {
|
||||||
return isEnglish(locale)
|
return isEnglish(locale)
|
||||||
@@ -1651,6 +1705,7 @@ export function computeFrontTrendSignal(
|
|||||||
precipMax,
|
precipMax,
|
||||||
score,
|
score,
|
||||||
summary: combinedSummary || backendSummary || summary,
|
summary: combinedSummary || backendSummary || summary,
|
||||||
|
summaryLines,
|
||||||
weatherGovPeriods,
|
weatherGovPeriods,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user