拆分 analysis_service:剩余工具函数全部移至 analysis_utils.py

提取 _mgm_hourly_high/_dedupe_forecast_daily/_format_observation_time_local/_parse_local_hour/_parse_utc_datetime/_metar_is_current_local_day/_is_plausible_city_temp。统一 parse_utc_datetime 副本。analysis_service 2082→1966 行。
This commit is contained in:
2569718930@qq.com
2026-05-25 17:51:10 +08:00
parent 812a4b2d32
commit 6b7a4575ad
12 changed files with 158 additions and 139 deletions
@@ -672,6 +672,8 @@ function ScanTerminalScreen() {
const userLocalTime = useUserLocalClock();
const { themeMode } = useScanTerminalTheme();
const [selectedRegionKey, setSelectedRegionKey] = useState<string>("east_asia");
const [localTimezoneOffsetSeconds, setLocalTimezoneOffsetSeconds] = useState<number | null>(null);
const [useLocalTimezoneDefault, setUseLocalTimezoneDefault] = useState(true);
useEffect(() => {
let cancelled = false;
@@ -743,12 +745,19 @@ function ScanTerminalScreen() {
useEffect(() => {
setSelectedRegionKey(detectLocalRegion());
setLocalTimezoneOffsetSeconds(-new Date().getTimezoneOffset() * 60);
}, []);
const selectRegionManually = useCallback((key: string) => {
setUseLocalTimezoneDefault(false);
setSelectedRegionKey(key);
}, []);
const { refreshScanTerminalManually, scanLoading, terminalData } =
useScanTerminalQuery({
isPro,
proAccessLoading: !hydrated || (proAccess.loading && !canUseLocalFullAccess),
timezoneOffsetSeconds: useLocalTimezoneDefault ? localTimezoneOffsetSeconds : null,
tradingRegion: selectedRegionKey,
});
const rows = useMemo(
@@ -831,7 +840,7 @@ function ScanTerminalScreen() {
selectedCity={selectedCity}
setSelectedCity={setSelectedCity}
selectedRegionKey={selectedRegionKey}
setSelectedRegionKey={setSelectedRegionKey}
setSelectedRegionKey={selectRegionManually}
/>
);
}
@@ -53,6 +53,7 @@ type AiCityStreamEvent = {
type TerminalQueryOptions = {
forceRefresh?: boolean;
signal?: AbortSignal;
timezoneOffsetSeconds?: number | null;
tradingRegion?: string;
};
@@ -254,6 +255,7 @@ async function readAiCityForecastStream(
async function getTerminal({
forceRefresh = false,
signal,
timezoneOffsetSeconds,
tradingRegion,
}: TerminalQueryOptions = {}) {
const params = new URLSearchParams({
@@ -271,6 +273,9 @@ async function getTerminal({
if (tradingRegion && tradingRegion !== "all") {
params.set("trading_region", tradingRegion);
}
if (Number.isFinite(timezoneOffsetSeconds)) {
params.set("timezone_offset_seconds", String(Math.trunc(Number(timezoneOffsetSeconds))));
}
if (forceRefresh) {
params.set("_ts", String(Date.now()));
}
@@ -13,10 +13,12 @@ import type { ScanTerminalResponse } from "@/lib/dashboard-types";
export function useScanTerminalQuery({
isPro,
proAccessLoading,
timezoneOffsetSeconds,
tradingRegion,
}: {
isPro: boolean;
proAccessLoading: boolean;
timezoneOffsetSeconds?: number | null;
tradingRegion?: string;
}) {
const {
@@ -50,12 +52,13 @@ export function useScanTerminalQuery({
scanTerminalClient.getTerminal({
forceRefresh,
signal,
timezoneOffsetSeconds,
tradingRegion,
}),
showLoading,
});
},
[isPro, proAccessLoading, run, tradingRegion],
[isPro, proAccessLoading, run, timezoneOffsetSeconds, tradingRegion],
);
useEffect(() => {
@@ -65,7 +68,7 @@ export function useScanTerminalQuery({
return;
}
void fetchScanTerminal({ forceRefresh: false, showLoading: true });
}, [fetchScanTerminal, isPro, proAccessLoading, reset, tradingRegion]);
}, [fetchScanTerminal, isPro, proAccessLoading, reset, timezoneOffsetSeconds, tradingRegion]);
const refreshScanTerminalManually = useCallback(() => {
if (