feat: implement AI city forecast and market scan integration for terminal dashboard

This commit is contained in:
2569718930@qq.com
2026-04-26 11:08:58 +08:00
parent e374ad4bf0
commit 9b77a3a0e2
7 changed files with 117 additions and 26 deletions
@@ -32,6 +32,10 @@ import type {
ScanOpportunityRow,
ScanTerminalResponse,
} from "@/lib/dashboard-types";
import {
buildBrowserBackendHeaders,
resolveBackendApiUrl,
} from "@/lib/backend-api";
import { getLocalizedCityName } from "@/lib/dashboard-home-copy";
import { AiPinnedForecastView } from "@/components/dashboard/scan-terminal/AiPinnedForecastView";
import { CalendarView } from "@/components/dashboard/scan-terminal/CalendarView";
@@ -240,11 +244,19 @@ function ScanTerminalScreen() {
time_range: "today",
limit: "36",
});
fetch(`/api/scan/terminal?${params.toString()}`, {
cache: "no-store",
signal: controller.signal,
void buildBrowserBackendHeaders({
Accept: "application/json",
})
.then((headers) => {
if (cancelled) return null;
return fetch(resolveBackendApiUrl(`/api/scan/terminal?${params.toString()}`), {
cache: "no-store",
headers,
signal: controller.signal,
});
})
.then(async (response) => {
if (!response) return null;
if (!response.ok) {
let message = `HTTP ${response.status}`;
try {
@@ -258,6 +270,7 @@ function ScanTerminalScreen() {
return response.json() as Promise<ScanTerminalResponse>;
})
.then((payload) => {
if (!payload) return;
if (cancelled) return;
setTerminalData(payload);
setScanError(null);
@@ -6,6 +6,10 @@ import type {
AiCityForecastState,
} from "@/components/dashboard/scan-terminal/types";
import { useDashboardStore } from "@/hooks/useDashboardStore";
import {
buildBrowserBackendHeaders,
resolveBackendApiUrl,
} from "@/lib/backend-api";
import type { CityDetail, MarketScan } from "@/lib/dashboard-types";
import { normalizeCityKey } from "./decision-utils";
@@ -182,21 +186,26 @@ export function useAiCityForecast({
? "DeepSeek V4-Pro is reading the latest airport bulletin..."
: "DeepSeek V4-Pro 正在解读最新机场报文...",
});
fetch("/api/scan/terminal/ai-city", {
method: "POST",
headers: {
void buildBrowserBackendHeaders({
Accept: "application/json",
"Content-Type": "application/json",
},
cache: "no-store",
signal: controller.signal,
body: JSON.stringify({
city: detailCityName,
force_refresh: aiRefreshToken > 0,
locale,
}),
})
})
.then((headers) => {
if (cancelled) return null;
return fetch(resolveBackendApiUrl("/api/scan/terminal/ai-city"), {
method: "POST",
headers,
cache: "no-store",
signal: controller.signal,
body: JSON.stringify({
city: detailCityName,
force_refresh: aiRefreshToken > 0,
locale,
}),
});
})
.then(async (response) => {
if (!response) return null;
if (!response.ok) {
let detailMessage = "";
try {
@@ -226,6 +235,7 @@ export function useAiCityForecast({
return response.json() as Promise<AiCityForecastPayload>;
})
.then((payload) => {
if (!payload) return;
if (!cancelled) {
const usablePayload =
payload?.city_forecast