diff --git a/src/views/Company/components/CompanyHeader/constants.ts b/src/views/Company/components/CompanyHeader/constants.ts new file mode 100644 index 00000000..07254c11 --- /dev/null +++ b/src/views/Company/components/CompanyHeader/constants.ts @@ -0,0 +1,70 @@ +/** + * CompanyHeader 组件常量 + */ + +import { FUI_COLORS, FUI_GLOW, FUI_ANIMATION } from '../../theme/fui'; + +/** 下拉菜单样式 */ +export const DROPDOWN_STYLE: React.CSSProperties = { + backgroundColor: FUI_COLORS.bg.elevated, + borderRadius: '6px', + border: `1px solid ${FUI_COLORS.gold[400]}`, + boxShadow: '0 4px 20px rgba(0, 0, 0, 0.5)', +}; + +/** 搜索图标样式 */ +export const SEARCH_ICON_STYLE: React.CSSProperties = { + color: FUI_COLORS.gold[400], + fontSize: 16, + cursor: 'pointer', +}; + +/** 输入框样式 */ +export const INPUT_STYLE: React.CSSProperties = { + backgroundColor: 'transparent', + borderColor: FUI_COLORS.gold[400], + borderRadius: 6, + height: 44, + color: FUI_COLORS.gold[400], +}; + +/** AutoComplete 宽度样式 */ +export const AUTOCOMPLETE_STYLE: React.CSSProperties = { + width: 320, +}; + +/** 搜索框容器样式 */ +export const SEARCH_BOX_SX = { + '.ant-select': { + width: '320px !important', + }, + '.ant-input-affix-wrapper': { + backgroundColor: 'transparent !important', + borderColor: `${FUI_COLORS.gold[400]} !important`, + borderWidth: '1px !important', + borderRadius: '6px !important', + height: '44px !important', + padding: '0 12px !important', + transition: `all ${FUI_ANIMATION.duration.fast} ${FUI_ANIMATION.easing.default}`, + '&:hover': { + borderColor: `${FUI_COLORS.gold[300]} !important`, + boxShadow: FUI_GLOW.gold.sm, + }, + '&:focus-within, &.ant-input-affix-wrapper-focused': { + borderColor: `${FUI_COLORS.gold[300]} !important`, + boxShadow: `${FUI_GLOW.gold.md} !important`, + }, + }, + '.ant-input': { + backgroundColor: 'transparent !important', + color: `${FUI_COLORS.gold[400]} !important`, + fontSize: '14px !important', + '&::placeholder': { + color: `${FUI_COLORS.gold[400]} !important`, + opacity: '0.7 !important', + }, + }, + '.ant-input-prefix': { + marginRight: '8px !important', + }, +} as const; diff --git a/src/views/Company/components/CompanyHeader/index.tsx b/src/views/Company/components/CompanyHeader/index.tsx index 05e2bc9f..6e8f7d01 100644 --- a/src/views/Company/components/CompanyHeader/index.tsx +++ b/src/views/Company/components/CompanyHeader/index.tsx @@ -1,71 +1,41 @@ /** * Company 页面顶部搜索栏组件 - FUI 科幻风格 - * - * 设计特点: - * - 左侧固定标题 + 副标题 - * - 右侧简洁搜索框 - * - 深色背景 + 金色强调色 */ import React, { memo, useMemo, useCallback, useState } from 'react'; -import { - Box, - Flex, - HStack, - VStack, - Text, -} from '@chakra-ui/react'; +import { Box, Flex, HStack, VStack, Text } from '@chakra-ui/react'; import { AutoComplete, Input, Spin } from 'antd'; import { SearchOutlined } from '@ant-design/icons'; import { useStockSearch } from '@hooks/useStockSearch'; import { THEME } from '../../config'; -import { FUI_COLORS, FUI_GLOW, FUI_ANIMATION, FUI_GLASS } from '../../theme/fui'; +import { FUI_COLORS, FUI_GLOW } from '../../theme/fui'; import type { CompanyHeaderProps, StockSearchResult } from '../../types'; +import { + DROPDOWN_STYLE, + SEARCH_ICON_STYLE, + INPUT_STYLE, + AUTOCOMPLETE_STYLE, + SEARCH_BOX_SX, +} from './constants'; -/** - * 页面标题组件 - */ -const PageTitle = memo(() => ( - - - 个股详情 - - - 查看股票实时行情、财务数据和盈利预测 - - -)); +// ============================================ +// SearchBox 子组件 +// ============================================ -PageTitle.displayName = 'PageTitle'; - -/** - * 搜索框组件(状态自管理,减少父组件重渲染) - */ const SearchBox = memo<{ - stockCode: string; onStockChange: (value: string) => void; -}>(({ - stockCode, - onStockChange, -}) => { - // 输入状态 - 默认为空,显示 placeholder +}>(({ onStockChange }) => { const [inputCode, setInputCode] = useState(''); - // 股票搜索 Hook - const searchHook = useStockSearch({ + const { + searchResults, + isSearching, + handleSearch: doSearch, + clearSearch, + } = useStockSearch({ limit: 10, debounceMs: 300, - onSearch: () => {}, // 空回调,追踪在父组件处理 + onSearch: () => {}, }) as { searchResults: StockSearchResult[]; isSearching: boolean; @@ -73,11 +43,8 @@ const SearchBox = memo<{ clearSearch: () => void; }; - const { searchResults, isSearching, handleSearch: doSearch, clearSearch } = searchHook; - - // 转换为 AutoComplete options - const stockOptions = useMemo(() => { - return searchResults.map((stock: StockSearchResult) => ({ + const stockOptions = useMemo(() => ( + searchResults.map((stock: StockSearchResult) => ({ value: stock.stock_code, label: ( @@ -92,62 +59,31 @@ const SearchBox = memo<{ )} ), - })); - }, [searchResults]); + })) + ), [searchResults]); + + const handleSearch = useCallback(() => { + if (inputCode) { + onStockChange(inputCode); + } + }, [inputCode, onStockChange]); - // 选中股票 const handleSelect = useCallback((value: string) => { clearSearch(); setInputCode(value); - if (value !== stockCode) { - onStockChange(value); - } - }, [clearSearch, stockCode, onStockChange]); + onStockChange(value); + }, [clearSearch, onStockChange]); - // 键盘事件 - 回车搜索 const handleKeyDown = useCallback((e: React.KeyboardEvent) => { - if (e.key === 'Enter' && inputCode && inputCode !== stockCode) { - onStockChange(inputCode); - } - }, [inputCode, stockCode, onStockChange]); + if (e.key === 'Enter') handleSearch(); + }, [handleSearch]); + + const searchIcon = useMemo(() => ( + + ), [handleSearch]); return ( - + : null} > } + prefix={searchIcon} onKeyDown={handleKeyDown} - style={{ - backgroundColor: 'transparent', - borderColor: FUI_COLORS.gold[400], - borderRadius: 6, - height: 44, - color: FUI_COLORS.gold[400], - }} + style={INPUT_STYLE} /> @@ -183,42 +108,45 @@ const SearchBox = memo<{ SearchBox.displayName = 'SearchBox'; -/** - * Company 页面顶部组件 - */ -const CompanyHeader: React.FC = memo(({ - stockCode, - onStockChange, -}) => { - return ( - - - {/* 左侧:页面标题 */} - +// ============================================ +// CompanyHeader 主组件 +// ============================================ - {/* 右侧:搜索框 */} - - - - ); -}); +const CompanyHeader: React.FC = memo(({ onStockChange }) => ( + + + + + 个股详情 + + + 查看股票实时行情、财务数据和盈利预测 + + + + + +)); CompanyHeader.displayName = 'CompanyHeader'; diff --git a/src/views/Company/index.tsx b/src/views/Company/index.tsx index 0430e004..431915bb 100644 --- a/src/views/Company/index.tsx +++ b/src/views/Company/index.tsx @@ -354,16 +354,12 @@ const CompanyIndex: React.FC = () => { CompanyHeader 组件 负责展示: - 左侧:页面标题和副标题 - - 右侧:股票搜索框 (支持代码/名称搜索) + - 右侧:股票搜索框 (支持代码/名称搜索,点击图标可搜索) Props 说明: - - stockCode: 当前股票代码,用于搜索框默认值 - onStockChange: 股票切换回调 */} - + {/* ======================================== diff --git a/src/views/Company/types.ts b/src/views/Company/types.ts index b2f1787a..19d36e86 100644 --- a/src/views/Company/types.ts +++ b/src/views/Company/types.ts @@ -110,7 +110,6 @@ export interface UseCompanyDataReturn { // ============================================ export interface CompanyHeaderProps { - stockCode: string; onStockChange: (code: string) => void; }