feat: Company 页面搜索框添加股票模糊搜索功能
- 添加 AutoComplete 组件替换原 Input,支持下拉选择 - 集成 stockService.fuzzySearch 实现按代码/名称模糊匹配 - 从 Redux 获取 allStocks 数据,自动加载保障 - 选中股票自动触发查询并更新 URL 参数 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import { loadAllStocks } from '@store/slices/stockSlice';
|
||||
import { AutoComplete } from 'antd';
|
||||
import { stockService } from '@services/stockService';
|
||||
import {
|
||||
Container,
|
||||
Heading,
|
||||
@@ -12,10 +16,7 @@ import {
|
||||
TabPanel,
|
||||
HStack,
|
||||
VStack,
|
||||
Input,
|
||||
Button,
|
||||
InputGroup,
|
||||
InputLeftElement,
|
||||
Text,
|
||||
Badge,
|
||||
Divider,
|
||||
@@ -41,10 +42,22 @@ const CompanyIndex = () => {
|
||||
const [searchParams, setSearchParams] = useSearchParams();
|
||||
const [stockCode, setStockCode] = useState(searchParams.get('scode') || '000001');
|
||||
const [inputCode, setInputCode] = useState(stockCode);
|
||||
const [stockOptions, setStockOptions] = useState([]);
|
||||
const { colorMode, toggleColorMode } = useColorMode();
|
||||
const toast = useToast();
|
||||
const { isAuthenticated } = useAuth();
|
||||
|
||||
// 从 Redux 获取股票列表数据
|
||||
const dispatch = useDispatch();
|
||||
const allStocks = useSelector((state) => state.stock.allStocks);
|
||||
|
||||
// 确保股票数据已加载
|
||||
useEffect(() => {
|
||||
if (!allStocks || allStocks.length === 0) {
|
||||
dispatch(loadAllStocks());
|
||||
}
|
||||
}, [dispatch, allStocks]);
|
||||
|
||||
// 🎯 PostHog 事件追踪
|
||||
const {
|
||||
trackStockSearched,
|
||||
@@ -113,6 +126,31 @@ const CompanyIndex = () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 模糊搜索股票(由 onSearch 触发)
|
||||
const handleStockSearch = (value) => {
|
||||
if (!value || !allStocks || allStocks.length === 0) {
|
||||
setStockOptions([]);
|
||||
return;
|
||||
}
|
||||
const results = stockService.fuzzySearch(value, allStocks, 10);
|
||||
const options = results.map((stock) => ({
|
||||
value: stock.code,
|
||||
label: `${stock.code} ${stock.name}`,
|
||||
}));
|
||||
setStockOptions(options);
|
||||
};
|
||||
|
||||
// 选中股票
|
||||
const handleStockSelect = (value) => {
|
||||
setInputCode(value);
|
||||
setStockOptions([]);
|
||||
if (value !== stockCode) {
|
||||
trackStockSearched(value, stockCode);
|
||||
setStockCode(value);
|
||||
setSearchParams({ scode: value });
|
||||
}
|
||||
};
|
||||
|
||||
const handleWatchlistToggle = async () => {
|
||||
if (!stockCode) {
|
||||
logger.warn('CompanyIndex', 'handleWatchlistToggle', '无效的股票代码', { stockCode });
|
||||
@@ -190,22 +228,21 @@ const CompanyIndex = () => {
|
||||
</VStack>
|
||||
|
||||
<HStack spacing={3}>
|
||||
<InputGroup size="lg" maxW="300px">
|
||||
<InputLeftElement pointerEvents="none">
|
||||
<SearchIcon color="gray.400" />
|
||||
</InputLeftElement>
|
||||
<Input
|
||||
placeholder="输入股票代码"
|
||||
<AutoComplete
|
||||
value={inputCode}
|
||||
onChange={(e) => setInputCode(e.target.value)}
|
||||
onKeyPress={handleKeyPress}
|
||||
borderRadius="md"
|
||||
_focus={{
|
||||
borderColor: 'blue.500',
|
||||
boxShadow: '0 0 0 1px #3182ce'
|
||||
options={stockOptions}
|
||||
onSearch={handleStockSearch}
|
||||
onSelect={handleStockSelect}
|
||||
onChange={(value) => setInputCode(value)}
|
||||
placeholder="输入股票代码或名称"
|
||||
style={{ width: 260 }}
|
||||
size="large"
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
handleSearch();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</InputGroup>
|
||||
<Button
|
||||
colorScheme="blue"
|
||||
size="lg"
|
||||
|
||||
Reference in New Issue
Block a user