/** * Company 页面顶部搜索栏组件 - FUI 科幻风格 * * 设计特点: * - Glassmorphism 毛玻璃背景 * - 发光效果和微动画 * - Ash Thorp 风格的数据展示 * - James Turrell 柔和光影 */ import React, { memo, useMemo, useCallback, useState } from 'react'; import { Box, Flex, HStack, VStack, Text, Button, Icon, Skeleton, } from '@chakra-ui/react'; import { AutoComplete, Spin } from 'antd'; import { Search, Star, TrendingUp, TrendingDown } from 'lucide-react'; import { useStockSearch } from '@hooks/useStockSearch'; import { THEME, getSearchBoxStyles } from '../../config'; import { FUI_COLORS, FUI_GLOW, FUI_ANIMATION, FUI_GLASS } from '../../theme/fui'; import type { CompanyHeaderProps, StockSearchResult } from '../../types'; /** * 股票信息展示组件 - FUI 风格 */ const StockInfoDisplay = memo<{ stockCode: string; stockName?: string; price?: number | null; change?: number | null; loading: boolean; }>(({ stockCode, stockName, price, change, loading }) => { if (loading) { return ( ); } const isPositive = change !== null && change !== undefined && change >= 0; const TrendIcon = isPositive ? TrendingUp : TrendingDown; return ( {/* 股票代码 & 名称 */} {stockCode} {stockName && ( {stockName} )} {/* 价格 & 涨跌幅 */} {price !== null && price !== undefined && ( {/* 价格 */} Price ¥{price.toFixed(2)} {/* 涨跌幅 Badge */} {change !== null && change !== undefined && ( {isPositive ? '+' : ''}{change.toFixed(2)}% )} )} ); }); StockInfoDisplay.displayName = 'StockInfoDisplay'; /** * 搜索操作区组件(状态自管理,减少父组件重渲染) */ const SearchActions = memo<{ stockCode: string; onStockChange: (value: string) => void; isInWatchlist: boolean; watchlistLoading: boolean; onWatchlistToggle: () => void; }>(({ stockCode, onStockChange, isInWatchlist, watchlistLoading, onWatchlistToggle, }) => { // 输入状态自管理(避免父组件重渲染) const [inputCode, setInputCode] = useState(stockCode); // 同步外部 stockCode 变化 React.useEffect(() => { setInputCode(stockCode); }, [stockCode]); // 股票搜索 Hook const searchHook = useStockSearch({ limit: 10, debounceMs: 300, onSearch: () => {}, // 空回调,追踪在父组件处理 }) as { searchResults: StockSearchResult[]; isSearching: boolean; handleSearch: (query: string) => void; clearSearch: () => void; }; const { searchResults, isSearching, handleSearch: doSearch, clearSearch } = searchHook; // 转换为 AutoComplete options const stockOptions = useMemo(() => { return searchResults.map((stock: StockSearchResult) => ({ value: stock.stock_code, label: ( {stock.stock_code} {stock.stock_name} {stock.pinyin_abbr && ( {stock.pinyin_abbr.toUpperCase()} )} ), })); }, [searchResults]); // 处理搜索按钮点击 const handleSearch = useCallback(() => { if (inputCode && inputCode !== stockCode) { onStockChange(inputCode); } }, [inputCode, stockCode, onStockChange]); // 选中股票 const handleSelect = useCallback((value: string) => { clearSearch(); setInputCode(value); if (value !== stockCode) { onStockChange(value); } }, [clearSearch, stockCode, onStockChange]); // 键盘事件 const handleKeyDown = useCallback((e: React.KeyboardEvent) => { if (e.key === 'Enter') { handleSearch(); } }, [handleSearch]); return ( {/* 搜索框 - FUI 风格 */} : null} onKeyDown={handleKeyDown} /> {/* 搜索按钮 - 发光效果 */} {/* 自选按钮 - FUI 风格 */} ); }); SearchActions.displayName = 'SearchActions'; /** * Company 页面顶部组件 */ const CompanyHeader: React.FC = memo(({ stockCode, stockInfo, stockInfoLoading, isInWatchlist, watchlistLoading, onStockChange, onWatchlistToggle, }) => { return ( {/* 顶部发光线(环境光效果由全局 AmbientGlow 提供) */} {/* 左侧:股票信息 */} {/* 右侧:搜索和操作 */} ); }); CompanyHeader.displayName = 'CompanyHeader'; export default CompanyHeader;