diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index b59e96c..a0312f4 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -36,6 +36,15 @@ export interface InitStocksResponse { } } +export interface SyncStocksByExchangeResponse { + success: boolean + data: { + exchange: string + count: number + message: string + } +} + export function getToken(): string | null { try { return localStorage.getItem('access_token') @@ -118,4 +127,7 @@ export const api = { initStocks: () => request('/api/admin/data-sync/init-stocks', { method: 'POST' }), + + syncStocksByExchange: (exchange: string) => + request(`/api/admin/data-sync/stocks/${exchange}`, { method: 'POST' }), } diff --git a/frontend/src/pages/DataSync.tsx b/frontend/src/pages/DataSync.tsx index ddeac76..5750f36 100644 --- a/frontend/src/pages/DataSync.tsx +++ b/frontend/src/pages/DataSync.tsx @@ -2,16 +2,22 @@ import { useState } from 'react' import { Database, RefreshCw, CheckCircle, AlertCircle } from 'lucide-react' import { api } from '@/lib/api' +const EXCHANGES = [ + { code: 'SSE', name: '上交所' }, + { code: 'SZSE', name: '深交所' }, + { code: 'BSE', name: '北交所' }, +] + export function DataSync() { - const [loading, setLoading] = useState(false) - const [result, setResult] = useState<{ count: number; message: string } | null>(null) + const [loading, setLoading] = useState(null) + const [result, setResult] = useState<{ exchange?: string; count: number; message: string } | null>(null) const [error, setError] = useState('') const handleInitStocks = async () => { if (!confirm('确定要从 Tushare 初始化股票列表?这会清空现有股票数据。')) { return } - setLoading(true) + setLoading('init') setError('') setResult(null) try { @@ -20,7 +26,24 @@ export function DataSync() { } catch (err: any) { setError(err?.message || '初始化失败') } finally { - setLoading(false) + setLoading(null) + } + } + + const handleSyncByExchange = async (exchange: string, name: string) => { + if (!confirm(`确定要同步${name}(${exchange})股票数据?`)) { + return + } + setLoading(exchange) + setError('') + setResult(null) + try { + const res = await api.syncStocksByExchange(exchange) + setResult(res.data) + } catch (err: any) { + setError(err?.message || '同步失败') + } finally { + setLoading(null) } } @@ -46,7 +69,10 @@ export function DataSync() { {result && (
- {result.message},共 {result.count} 条记录 + + {result.message},共 {result.count} 条记录 + {result.exchange ? `(${result.exchange})` : ''} +
)} @@ -58,25 +84,50 @@ export function DataSync() { +
+
+

按交易所同步

+

按交易所分别同步,不影响其他交易所数据

+
+
+ {EXCHANGES.map(({ code, name }) => ( + + ))} +
+
+

说明

  • • 需要配置 TUSHARE_TOKEN 环境变量
  • -
  • • 每次同步会清空 stocks 表并重新写入
  • -
  • • 仅获取基础字段:代码、名称、交易所、行业等
  • +
  • • 初始化会清空 stocks 表并重新写入
  • +
  • • 按交易所同步采用 upsert 策略,以 ts_code 为唯一键更新或插入
  • +
  • • 同步字段包括:代码、名称、交易所、行业、上市状态、上市日期、实控人等