From 1326176a8530d1e7b467b7ddf2f9108ef4281eb2 Mon Sep 17 00:00:00 2001 From: "2569718930@qq.com" <2569718930@qq.com> Date: Mon, 18 May 2026 23:50:18 +0800 Subject: [PATCH] =?UTF-8?q?@=20=E4=BF=AE=E5=A4=8D=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E7=AB=AF=E5=9F=8E=E5=B8=82=E5=88=97=E8=A1=A8=E6=90=9C=E7=B4=A2?= =?UTF-8?q?=E6=97=A0=E6=95=B0=E6=8D=AE=E6=98=BE=E7=A4=BA=EF=BC=9A=E9=9D=9E?= =?UTF-8?q?=20Pro=20=E7=94=A8=E6=88=B7=E5=9B=9E=E9=80=80=E5=88=B0=E5=9F=BA?= =?UTF-8?q?=E7=A1=80=E5=9F=8E=E5=B8=82=E6=95=B0=E6=8D=AE=E6=BA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MobileCityPicker 原依赖扫描终端 API rows,该 API 仅 Pro 用户触发, 导致访客/免费用户 cityListRows 为空,所有城市被 pickCityRow 过滤掉。 现新增 cityListRows fallback:无 scan 数据时从 store.cities + citySummariesByName 构建行数据,保证所有用户可见并搜索城市列表。 Constraint: fallback rows 缺少 metar/target 字段,但 MobileCityPicker 仅消费 display/temp/deb/airport 字段,不影响渲染。 @ --- .../dashboard/ScanTerminalDashboard.tsx | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/frontend/components/dashboard/ScanTerminalDashboard.tsx b/frontend/components/dashboard/ScanTerminalDashboard.tsx index f57cbbcc..3f50cb10 100644 --- a/frontend/components/dashboard/ScanTerminalDashboard.tsx +++ b/frontend/components/dashboard/ScanTerminalDashboard.tsx @@ -136,6 +136,43 @@ function ScanTerminalScreen() { () => sortRowsByUserTime(terminalData?.rows || []), [terminalData?.rows], ); + + const cityListRows = useMemo(() => { + if (timeSortedRows.length > 0) return timeSortedRows; + return store.cities.map((city, index) => { + const cityKey = normalizeCityKey(city.name); + const summary = + store.citySummariesByName[cityKey] ?? + Object.values(store.citySummariesByName).find( + (s) => normalizeCityKey(s?.name) === cityKey, + ) ?? + null; + return { + id: `city-fallback:${cityKey}:${index}`, + city: cityKey, + city_display_name: city.display_name || city.name, + display_name: city.display_name || city.name, + temp_symbol: city.temp_unit === "fahrenheit" ? "°F" : "°C", + current_temp: summary?.current?.temp ?? null, + current_max_so_far: summary?.current?.temp ?? null, + deb_prediction: summary?.deb?.prediction ?? null, + airport: city.airport || null, + local_time: summary?.local_time ?? null, + risk_level: city.risk_level || "low", + market_slug: null, + market_question: null, + target_label: null, + side: null, + edge_percent: null, + final_score: null, + window_phase: null, + tradable: false, + active: false, + closed: false, + accepting_orders: false, + } satisfies ScanOpportunityRow; + }); + }, [timeSortedRows, store.cities, store.citySummariesByName]); const { addAiPinnedCity, aiPinnedCities, @@ -347,8 +384,8 @@ function ScanTerminalScreen() { return ( ); }