// src/hooks/useWatchlist.js // 自选股管理自定义 Hook import { useState, useCallback } from 'react'; import { useToast } from '@chakra-ui/react'; import { logger } from '../utils/logger'; import { getApiBase } from '../utils/apiConfig'; const WATCHLIST_PAGE_SIZE = 10; /** * 自选股管理 Hook * 提供自选股加载、分页、移除等功能 * * @returns {{ * watchlistQuotes: Array, * watchlistLoading: boolean, * watchlistPage: number, * setWatchlistPage: Function, * WATCHLIST_PAGE_SIZE: number, * loadWatchlistQuotes: Function, * handleRemoveFromWatchlist: Function * }} */ export const useWatchlist = () => { const toast = useToast(); const [watchlistQuotes, setWatchlistQuotes] = useState([]); const [watchlistLoading, setWatchlistLoading] = useState(false); const [watchlistPage, setWatchlistPage] = useState(1); // 加载自选股实时行情 const loadWatchlistQuotes = useCallback(async () => { try { setWatchlistLoading(true); const base = getApiBase(); const resp = await fetch(base + '/api/account/watchlist/realtime', { credentials: 'include', cache: 'no-store', headers: { 'Cache-Control': 'no-cache' } }); if (resp.ok) { const data = await resp.json(); if (data && data.success && Array.isArray(data.data)) { setWatchlistQuotes(data.data); } else { setWatchlistQuotes([]); } } else { setWatchlistQuotes([]); } } catch (e) { logger.warn('useWatchlist', '加载自选股实时行情失败', { error: e.message }); setWatchlistQuotes([]); } finally { setWatchlistLoading(false); } }, []); // 从自选股移除 const handleRemoveFromWatchlist = useCallback(async (stockCode) => { try { const base = getApiBase(); const resp = await fetch(base + `/api/account/watchlist/${stockCode}`, { method: 'DELETE', credentials: 'include' }); const data = await resp.json().catch(() => ({})); if (resp.ok && data && data.success !== false) { setWatchlistQuotes((prev) => { const normalize6 = (code) => { const m = String(code || '').match(/(\d{6})/); return m ? m[1] : String(code || ''); }; const target = normalize6(stockCode); const updated = (prev || []).filter((x) => normalize6(x.stock_code) !== target); const newMaxPage = Math.max(1, Math.ceil((updated.length || 0) / WATCHLIST_PAGE_SIZE)); setWatchlistPage((p) => Math.min(p, newMaxPage)); return updated; }); toast({ title: '已从自选股移除', status: 'info', duration: 1500 }); } else { toast({ title: '移除失败', status: 'error', duration: 2000 }); } } catch (e) { toast({ title: '网络错误,移除失败', status: 'error', duration: 2000 }); } }, [toast]); return { watchlistQuotes, watchlistLoading, watchlistPage, setWatchlistPage, WATCHLIST_PAGE_SIZE, loadWatchlistQuotes, handleRemoveFromWatchlist }; };