TradingAgents/web_dashboard/frontend/src/services/portfolioApi.js

67 lines
2.6 KiB
JavaScript

const BASE = '/api/portfolio';
const FETCH_TIMEOUT_MS = 15000; // 15s timeout per request
async function req(method, path, body) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
const opts = {
method,
headers: { 'Content-Type': 'application/json' },
signal: controller.signal,
};
if (body !== undefined) opts.body = JSON.stringify(body);
try {
const res = await fetch(`${BASE}${path}`, opts);
clearTimeout(timeout);
if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error(err.detail || `请求失败: ${res.status}`);
}
if (res.status === 204) return null;
return res.json();
} catch (e) {
clearTimeout(timeout);
if (e.name === 'AbortError') throw new Error('请求超时,请检查网络连接');
throw e;
}
}
export const portfolioApi = {
// Watchlist
getWatchlist: () => req('GET', '/watchlist'),
addToWatchlist: (ticker, name) => req('POST', '/watchlist', { ticker, name }),
removeFromWatchlist: (ticker) => req('DELETE', `/watchlist/${ticker}`),
// Accounts
getAccounts: () => req('GET', '/accounts'),
createAccount: (name) => req('POST', '/accounts', { account_name: name }),
deleteAccount: (name) => req('DELETE', `/accounts/${name}`),
// Positions
getPositions: (account) => req('GET', `/positions${account ? `?account=${encodeURIComponent(account)}` : ''}`),
addPosition: (data) => req('POST', '/positions', data),
removePosition: (ticker, positionId, account) => {
const params = new URLSearchParams({ ticker });
if (positionId) params.set('position_id', positionId);
if (account) params.set('account', account);
return req('DELETE', `/positions/${ticker}?${params}`);
},
exportPositions: (account) => {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
const url = `${BASE}/positions/export${account ? `?account=${encodeURIComponent(account)}` : ''}`;
return fetch(url, { signal: controller.signal })
.then(r => { clearTimeout(timeout); return r; })
.then(r => { if (!r.ok) throw new Error(`导出失败: ${r.status}`); return r.blob(); })
.catch(e => { clearTimeout(timeout); if (e.name === 'AbortError') throw new Error('请求超时'); throw e; });
},
// Recommendations
getRecommendations: (date) =>
req('GET', `/recommendations${date ? `?date=${date}` : ''}`),
getRecommendation: (date, ticker) => req('GET', `/recommendations/${date}/${ticker}`),
// Batch analysis
startAnalysis: () => req('POST', '/analyze'),
};