Merge branch 'feature_bugfix/251201_vf_h5_ui' into feature_bugfix/251201_py_h5_ui

* feature_bugfix/251201_vf_h5_ui:
  feat: Company 页面搜索框添加股票模糊搜索功能
  fix: 个股中心bug修复
This commit is contained in:
zdl
2025-12-10 14:26:36 +08:00
3 changed files with 70 additions and 25 deletions

View File

@@ -544,11 +544,19 @@ const InvestmentCalendar = () => {
render: (concepts) => ( render: (concepts) => (
<Space wrap> <Space wrap>
{concepts && concepts.length > 0 ? ( {concepts && concepts.length > 0 ? (
concepts.slice(0, 3).map((concept, index) => ( concepts.slice(0, 3).map((concept, index) => {
// 兼容多种数据格式:字符串、数组、对象
const conceptName = typeof concept === 'string'
? concept
: Array.isArray(concept)
? concept[0]
: concept?.concept || concept?.name || '';
return (
<Tag key={index} icon={<TagsOutlined />}> <Tag key={index} icon={<TagsOutlined />}>
{Array.isArray(concept) ? concept[0] : concept} {conceptName}
</Tag> </Tag>
)) );
})
) : ( ) : (
<Text type="secondary"></Text> <Text type="secondary"></Text>
)} )}

View File

@@ -2426,7 +2426,7 @@ const CompanyAnalysisComplete = ({ stockCode: propStockCode }) => {
<> <>
{event.keywords.slice(0, 4).map((keyword, kidx) => ( {event.keywords.slice(0, 4).map((keyword, kidx) => (
<Tag key={kidx} size="sm" colorScheme="cyan" variant="subtle"> <Tag key={kidx} size="sm" colorScheme="cyan" variant="subtle">
{keyword} {typeof keyword === 'string' ? keyword : keyword.concept}
</Tag> </Tag>
))} ))}
</> </>

View File

@@ -1,5 +1,9 @@
import React, { useState, useEffect, useCallback } from 'react'; import React, { useState, useEffect, useCallback } from 'react';
import { useSearchParams } from 'react-router-dom'; 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 { import {
Container, Container,
Heading, Heading,
@@ -12,10 +16,7 @@ import {
TabPanel, TabPanel,
HStack, HStack,
VStack, VStack,
Input,
Button, Button,
InputGroup,
InputLeftElement,
Text, Text,
Badge, Badge,
Divider, Divider,
@@ -41,10 +42,22 @@ const CompanyIndex = () => {
const [searchParams, setSearchParams] = useSearchParams(); const [searchParams, setSearchParams] = useSearchParams();
const [stockCode, setStockCode] = useState(searchParams.get('scode') || '000001'); const [stockCode, setStockCode] = useState(searchParams.get('scode') || '000001');
const [inputCode, setInputCode] = useState(stockCode); const [inputCode, setInputCode] = useState(stockCode);
const [stockOptions, setStockOptions] = useState([]);
const { colorMode, toggleColorMode } = useColorMode(); const { colorMode, toggleColorMode } = useColorMode();
const toast = useToast(); const toast = useToast();
const { isAuthenticated } = useAuth(); 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 事件追踪 // 🎯 PostHog 事件追踪
const { const {
trackStockSearched, 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 () => { const handleWatchlistToggle = async () => {
if (!stockCode) { if (!stockCode) {
logger.warn('CompanyIndex', 'handleWatchlistToggle', '无效的股票代码', { stockCode }); logger.warn('CompanyIndex', 'handleWatchlistToggle', '无效的股票代码', { stockCode });
@@ -190,22 +228,21 @@ const CompanyIndex = () => {
</VStack> </VStack>
<HStack spacing={3}> <HStack spacing={3}>
<InputGroup size="lg" maxW="300px"> <AutoComplete
<InputLeftElement pointerEvents="none">
<SearchIcon color="gray.400" />
</InputLeftElement>
<Input
placeholder="输入股票代码"
value={inputCode} value={inputCode}
onChange={(e) => setInputCode(e.target.value)} options={stockOptions}
onKeyPress={handleKeyPress} onSearch={handleStockSearch}
borderRadius="md" onSelect={handleStockSelect}
_focus={{ onChange={(value) => setInputCode(value)}
borderColor: 'blue.500', placeholder="输入股票代码或名称"
boxShadow: '0 0 0 1px #3182ce' style={{ width: 260 }}
size="large"
onKeyDown={(e) => {
if (e.key === 'Enter') {
handleSearch();
}
}} }}
/> />
</InputGroup>
<Button <Button
colorScheme="blue" colorScheme="blue"
size="lg" size="lg"