diff --git a/frontend/src/components/StatisticsView.jsx b/frontend/src/components/StatisticsView.jsx index e3f8b77..038aa66 100644 --- a/frontend/src/components/StatisticsView.jsx +++ b/frontend/src/components/StatisticsView.jsx @@ -360,7 +360,7 @@ export default function StatisticsView({ trades, holdings, stats, baseline_vw, e {/* Ticker Weights - Compact */} - {stats.tickerWeights && Object.keys(stats.tickerWeights).length > 0 && ( + {effectiveStats?.tickerWeights && Object.keys(effectiveStats.tickerWeights).length > 0 && (
- {Object.entries(stats.tickerWeights).map(([ticker, weight]) => { + {Object.entries(effectiveStats.tickerWeights).map(([ticker, weight]) => { const weightValue = Number(weight); const isNegative = weightValue < 0; const displayWeight = (weightValue * 100).toFixed(1); diff --git a/frontend/src/services/websocket.js b/frontend/src/services/websocket.js index 014fe02..0557b79 100644 --- a/frontend/src/services/websocket.js +++ b/frontend/src/services/websocket.js @@ -24,13 +24,13 @@ export async function fetchGatewayPort() { if (data.is_running && data.port) { cachedGatewayPort = data.port; cachedWsUrl = data.ws_url; - return { port: data.port, wsUrl: data.ws_url }; + return { status: "running", port: data.port, wsUrl: data.ws_url }; } - return null; + return { status: "stopped", port: data.port || null, wsUrl: data.ws_url || null }; } catch (error) { console.warn('[Gateway] Failed to fetch port:', error); - return null; + return { status: "unavailable", port: null, wsUrl: null }; } } @@ -86,15 +86,29 @@ export class ReadOnlyClient { // Resolve WebSocket URL if not set let targetUrl = this.wsUrl; if (!targetUrl) { - // Try to fetch from API first const gatewayInfo = await fetchGatewayPort(); - if (gatewayInfo) { + if (gatewayInfo?.status === "running" && gatewayInfo.wsUrl) { targetUrl = gatewayInfo.wsUrl; console.log(`[WebSocket] Resolved Gateway port: ${gatewayInfo.port}`); - } else { - // Fallback to default + } else if (gatewayInfo?.status === "unavailable") { targetUrl = WS_URL; console.log(`[WebSocket] Using default URL: ${targetUrl}`); + } else { + this.isConnecting = false; + this._safeEmit({ + type: "system", + content: "运行任务尚未启动,等待数据服务上线..." + }); + + if (this.shouldReconnect) { + if (this.reconnectTimer) { + clearTimeout(this.reconnectTimer); + } + this.reconnectTimer = setTimeout(() => { + this._connect(); + }, this.reconnectDelay); + } + return; } }