/** * 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<{ inputCode: string; onInputChange: (value: string) => void; onSearch: () => void; onSelect: (value: string) => void; isInWatchlist: boolean; watchlistLoading: boolean; onWatchlistToggle: () => void; }>(({ inputCode, onInputChange, onSearch, onSelect, isInWatchlist, watchlistLoading, onWatchlistToggle, }) => { // 股票搜索 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 handleSelect = useCallback((value: string) => { clearSearch(); onSelect(value); }, [clearSearch, onSelect]); // 键盘事件 const handleKeyDown = useCallback((e: React.KeyboardEvent) => { if (e.key === 'Enter') { onSearch(); } }, [onSearch]); return ( {/* 搜索框 - FUI 风格 */} : null} onKeyDown={handleKeyDown} /> {/* 搜索按钮 - 发光效果 */} {/* 自选按钮 - FUI 风格 */} ); }); SearchActions.displayName = 'SearchActions'; /** * Company 页面顶部组件 */ const CompanyHeader: React.FC = memo(({ stockCode, stockInfo, stockInfoLoading, isInWatchlist, watchlistLoading, onStockChange, onWatchlistToggle, }) => { const [inputCode, setInputCode] = useState(stockCode); // 处理搜索 const handleSearch = useCallback(() => { if (inputCode && inputCode !== stockCode) { onStockChange(inputCode); } }, [inputCode, stockCode, onStockChange]); // 处理选中 const handleSelect = useCallback((value: string) => { setInputCode(value); if (value !== stockCode) { onStockChange(value); } }, [stockCode, onStockChange]); // 同步 stockCode 变化 React.useEffect(() => { setInputCode(stockCode); }, [stockCode]); return ( {/* 环境光效果 - James Turrell 风格 */} {/* 顶部发光线 */} {/* 左侧:股票信息 */} {/* 右侧:搜索和操作 */} ); }); CompanyHeader.displayName = 'CompanyHeader'; export default CompanyHeader;