diff --git a/web/src/App.tsx b/web/src/App.tsx index b53bcc0c..c547726d 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -170,9 +170,7 @@ function App() { ) { setCurrentPage('trader') // 如果 URL 中有 trader 参数(slug 格式),更新选中的 trader - if (traderParam) { - setSelectedTraderSlug(traderParam) - } + setSelectedTraderSlug(traderParam || undefined) } else if ( path === '/competition' || hash === 'competition' || @@ -200,7 +198,7 @@ function App() { // 获取trader列表(仅在用户登录时) const { data: traders, error: tradersError } = useSWR( user && token ? 'traders' : null, - api.getTraders, + () => api.getTraders(currentPage === 'trader'), { refreshInterval: 10000, shouldRetryOnError: false, // 避免在后端未运行时无限重试 @@ -219,19 +217,22 @@ function App() { // 当获取到traders后,根据 URL 中的 trader slug 设置选中的 trader,或默认选中第一个 useEffect(() => { - if (traders && traders.length > 0 && !selectedTraderId) { - if (selectedTraderSlug) { - // 通过 slug 找到对应的 trader - const trader = findTraderBySlug(selectedTraderSlug, traders) - if (trader) { - setSelectedTraderId(trader.trader_id) - } else { - // 如果找不到,选中第一个 - setSelectedTraderId(traders[0].trader_id) - } - } else { - setSelectedTraderId(traders[0].trader_id) + if (!traders || traders.length === 0) { + return + } + + if (selectedTraderSlug) { + // 通过 slug 找到对应的 trader + const trader = findTraderBySlug(selectedTraderSlug, traders) + const nextTraderId = trader?.trader_id || traders[0].trader_id + if (nextTraderId !== selectedTraderId) { + setSelectedTraderId(nextTraderId) } + return + } + + if (!selectedTraderId) { + setSelectedTraderId(traders[0].trader_id) } }, [traders, selectedTraderId, selectedTraderSlug]) @@ -240,7 +241,7 @@ function App() { currentPage === 'trader' && selectedTraderId ? `status-${selectedTraderId}` : null, - () => api.getStatus(selectedTraderId), + () => api.getStatus(selectedTraderId, true), { refreshInterval: 15000, // 15秒刷新(配合后端15秒缓存) revalidateOnFocus: false, // 禁用聚焦时重新验证,减少请求 @@ -303,7 +304,7 @@ function App() { currentPage === 'trader' && selectedTraderId ? `statistics-${selectedTraderId}` : null, - () => api.getStatistics(selectedTraderId), + () => api.getStatistics(selectedTraderId, true), { refreshInterval: 30000, // 30秒刷新(统计数据更新频率较低) revalidateOnFocus: false, @@ -520,7 +521,18 @@ function App() { { setSelectedTraderId(traderId) - window.history.pushState({}, '', '/dashboard') + const trader = traders?.find((item) => item.trader_id === traderId) + const url = new URL(window.location.href) + url.pathname = '/dashboard' + if (trader) { + const slug = getTraderSlug(trader) + url.searchParams.set('trader', slug) + setSelectedTraderSlug(slug) + } else { + url.searchParams.delete('trader') + setSelectedTraderSlug(undefined) + } + window.history.pushState({}, '', url.toString()) setRoute('/dashboard') setCurrentPage('trader') }} @@ -550,8 +562,10 @@ function App() { // 更新 URL 参数(使用 slug: name-id前4位) const trader = traders?.find(t => t.trader_id === traderId) if (trader) { + const slug = getTraderSlug(trader) + setSelectedTraderSlug(slug) const url = new URL(window.location.href) - url.searchParams.set('trader', getTraderSlug(trader)) + url.searchParams.set('trader', slug) window.history.replaceState({}, '', url.toString()) } }} diff --git a/web/src/components/charts/AdvancedChart.tsx b/web/src/components/charts/AdvancedChart.tsx index 1b2dc62a..42361708 100644 --- a/web/src/components/charts/AdvancedChart.tsx +++ b/web/src/components/charts/AdvancedChart.tsx @@ -153,7 +153,7 @@ export function AdvancedChart({ try { const limit = 1500 const klineUrl = `/api/klines?symbol=${symbol}&interval=${interval}&limit=${limit}&exchange=${exchange}` - const result = await httpClient.get(klineUrl) + const result = await httpClient.request(klineUrl, { silent: true }) if (!result.success || !result.data) { throw new Error('Failed to fetch kline data') @@ -243,7 +243,10 @@ export function AdvancedChart({ try { console.log('[AdvancedChart] Fetching orders for trader:', traderID, 'symbol:', symbol) // Fetch filled orders, up to 200 for more history - const result = await httpClient.get(`/api/orders?trader_id=${traderID}&symbol=${symbol}&status=FILLED&limit=200`) + const result = await httpClient.request( + `/api/orders?trader_id=${traderID}&symbol=${symbol}&status=FILLED&limit=200`, + { silent: true } + ) console.log('[AdvancedChart] Orders API response:', result) @@ -326,7 +329,10 @@ export function AdvancedChart({ const fetchOpenOrders = async (traderID: string, symbol: string): Promise => { try { console.log('[AdvancedChart] Fetching open orders for trader:', traderID, 'symbol:', symbol) - const result = await httpClient.get(`/api/open-orders?trader_id=${traderID}&symbol=${symbol}`) + const result = await httpClient.request( + `/api/open-orders?trader_id=${traderID}&symbol=${symbol}`, + { silent: true } + ) console.log('[AdvancedChart] Open orders API response:', result) diff --git a/web/src/components/charts/ChartWithOrders.tsx b/web/src/components/charts/ChartWithOrders.tsx index 7c0f6195..421c41bc 100644 --- a/web/src/components/charts/ChartWithOrders.tsx +++ b/web/src/components/charts/ChartWithOrders.tsx @@ -114,7 +114,7 @@ export function ChartWithOrders({ const limit = 2000 // Fetch recent 2000 candles (more historical data) const klineUrl = `/api/klines?symbol=${symbol}&interval=${interval}&limit=${limit}&exchange=${exchange}` - const result = await httpClient.get(klineUrl) + const result = await httpClient.request(klineUrl, { silent: true }) if (!result.success || !result.data) { throw new Error('Failed to fetch kline data from our service') @@ -142,7 +142,10 @@ export function ChartWithOrders({ const fetchOrders = async (traderID: string, symbol: string): Promise => { try { // Fetch filled orders for this trader from backend API - const result = await httpClient.get(`/api/orders?trader_id=${traderID}&symbol=${symbol}&status=FILLED&limit=50`) + const result = await httpClient.request( + `/api/orders?trader_id=${traderID}&symbol=${symbol}&status=FILLED&limit=50`, + { silent: true } + ) if (!result.success || !result.data) { console.warn('Failed to fetch orders:', result.message) diff --git a/web/src/components/charts/ChartWithOrdersSimple.tsx b/web/src/components/charts/ChartWithOrdersSimple.tsx index 529c95b8..81fd9af9 100644 --- a/web/src/components/charts/ChartWithOrdersSimple.tsx +++ b/web/src/components/charts/ChartWithOrdersSimple.tsx @@ -31,7 +31,7 @@ export function ChartWithOrdersSimple({ const klineUrl = `/api/klines?symbol=${symbol}&interval=${interval}&limit=${limit}` console.log('[ChartSimple] Fetching klines from our service:', klineUrl) - const klineResult = await httpClient.get(klineUrl) + const klineResult = await httpClient.request(klineUrl, { silent: true }) if (!klineResult.success || !klineResult.data) { throw new Error('Failed to fetch klines from our service') @@ -44,7 +44,7 @@ export function ChartWithOrdersSimple({ if (traderID) { const tradesUrl = `/api/trades?trader_id=${traderID}&symbol=${symbol}&limit=100` console.log('[ChartSimple] Fetching trades from:', tradesUrl) - const tradesResult = await httpClient.get(tradesUrl) + const tradesResult = await httpClient.request(tradesUrl, { silent: true }) if (tradesResult.success && tradesResult.data) { console.log('[ChartSimple] Received trades:', tradesResult.data.length) diff --git a/web/src/components/charts/EquityChart.tsx b/web/src/components/charts/EquityChart.tsx index 407baeda..76bbeb2f 100644 --- a/web/src/components/charts/EquityChart.tsx +++ b/web/src/components/charts/EquityChart.tsx @@ -43,7 +43,7 @@ export function EquityChart({ traderId, embedded = false }: EquityChartProps) { const { data: history, error, isLoading } = useSWR( user && token && traderId ? `equity-history-${traderId}` : null, - () => api.getEquityHistory(traderId), + () => api.getEquityHistory(traderId, true), { refreshInterval: 30000, // 30秒刷新(历史数据更新频率较低) revalidateOnFocus: false, @@ -53,7 +53,7 @@ export function EquityChart({ traderId, embedded = false }: EquityChartProps) { const { data: account } = useSWR( user && token && traderId ? `account-${traderId}` : null, - () => api.getAccount(traderId), + () => api.getAccount(traderId, true), { refreshInterval: 15000, // 15秒刷新(配合后端缓存) revalidateOnFocus: false, diff --git a/web/src/components/trader/PositionHistory.tsx b/web/src/components/trader/PositionHistory.tsx index 42303527..f501dd6c 100644 --- a/web/src/components/trader/PositionHistory.tsx +++ b/web/src/components/trader/PositionHistory.tsx @@ -359,7 +359,11 @@ export function PositionHistory({ traderId }: PositionHistoryProps) { setLoading(true) setError(null) // Fetch more data than needed to support filtering, but respect pageSize for initial load - const data = await api.getPositionHistory(traderId, Math.max(200, pageSize * 5)) + const data = await api.getPositionHistory( + traderId, + Math.max(200, pageSize * 5), + true + ) setPositions(data.positions || []) setStats(data.stats) setSymbolStats(data.symbol_stats || []) diff --git a/web/src/lib/api/data.ts b/web/src/lib/api/data.ts index 58345370..9ec9cf7d 100644 --- a/web/src/lib/api/data.ts +++ b/web/src/lib/api/data.ts @@ -10,11 +10,11 @@ import type { import { API_BASE, httpClient } from './helpers' export const dataApi = { - async getStatus(traderId?: string): Promise { + async getStatus(traderId?: string, silent?: boolean): Promise { const url = traderId ? `${API_BASE}/status?trader_id=${traderId}` : `${API_BASE}/status` - const result = await httpClient.get(url) + const result = await httpClient.request(url, { silent }) if (!result.success) throw new Error('Failed to fetch system status') return result.data! }, @@ -65,20 +65,20 @@ export const dataApi = { return result.data! }, - async getStatistics(traderId?: string): Promise { + async getStatistics(traderId?: string, silent?: boolean): Promise { const url = traderId ? `${API_BASE}/statistics?trader_id=${traderId}` : `${API_BASE}/statistics` - const result = await httpClient.get(url) + const result = await httpClient.request(url, { silent }) if (!result.success) throw new Error('Failed to fetch statistics') return result.data! }, - async getEquityHistory(traderId?: string): Promise { + async getEquityHistory(traderId?: string, silent?: boolean): Promise { const url = traderId ? `${API_BASE}/equity-history?trader_id=${traderId}` : `${API_BASE}/equity-history` - const result = await httpClient.get(url) + const result = await httpClient.request(url, { silent }) if (!result.success) throw new Error('Failed to fetch equity history') return result.data! }, @@ -114,9 +114,14 @@ export const dataApi = { return result.data! }, - async getPositionHistory(traderId: string, limit: number = 100): Promise { - const result = await httpClient.get( - `${API_BASE}/positions/history?trader_id=${traderId}&limit=${limit}` + async getPositionHistory( + traderId: string, + limit: number = 100, + silent?: boolean + ): Promise { + const result = await httpClient.request( + `${API_BASE}/positions/history?trader_id=${traderId}&limit=${limit}`, + { silent } ) if (!result.success) throw new Error('Failed to fetch position history') return result.data! diff --git a/web/src/lib/api/traders.ts b/web/src/lib/api/traders.ts index fecdb5ca..8971894c 100644 --- a/web/src/lib/api/traders.ts +++ b/web/src/lib/api/traders.ts @@ -16,8 +16,11 @@ function throwApiError( } export const traderApi = { - async getTraders(): Promise { - const result = await httpClient.get(`${API_BASE}/my-traders`) + async getTraders(silent?: boolean): Promise { + const result = await httpClient.request( + `${API_BASE}/my-traders`, + { silent } + ) if (!result.success) throw new Error('Failed to fetch trader list') return Array.isArray(result.data) ? result.data : [] },