update pay function
This commit is contained in:
@@ -138,7 +138,22 @@ export const AdvancedSearch = ({ onSearch, loading }) => {
|
||||
|
||||
<Box flex={1}>
|
||||
<Text fontSize="sm" mb={2} fontWeight="bold">搜索模式</Text>
|
||||
<Select value={searchMode} onChange={(e) => setSearchMode(e.target.value)}>
|
||||
<Select
|
||||
value={searchMode}
|
||||
onChange={(e) => setSearchMode(e.target.value)}
|
||||
bg="white"
|
||||
_dark={{ bg: 'gray.700' }}
|
||||
sx={{
|
||||
'& option': {
|
||||
bg: 'white',
|
||||
color: 'gray.800',
|
||||
_dark: {
|
||||
bg: 'gray.700',
|
||||
color: 'white'
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<option value="hybrid">智能搜索(推荐)</option>
|
||||
<option value="text">精确匹配</option>
|
||||
<option value="vector">语义搜索</option>
|
||||
|
||||
@@ -14,28 +14,21 @@ import {
|
||||
AccordionButton,
|
||||
AccordionPanel,
|
||||
AccordionIcon,
|
||||
IconButton,
|
||||
Flex,
|
||||
Circle,
|
||||
Tag,
|
||||
TagLabel,
|
||||
Wrap,
|
||||
WrapItem,
|
||||
Button,
|
||||
useColorModeValue,
|
||||
Collapse,
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react';
|
||||
import { StarIcon, ViewIcon, TimeIcon, ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons';
|
||||
import { getFormattedTextProps } from '../../../utils/textUtils';
|
||||
import { StarIcon, TimeIcon } from '@chakra-ui/icons';
|
||||
|
||||
const SectorDetails = ({ sortedSectors, totalStocks, onStockClick }) => {
|
||||
const SectorDetails = ({ sortedSectors, totalStocks }) => {
|
||||
// 使用 useRef 来维持展开状态,避免重新渲染时重置
|
||||
const expandedSectorsRef = useRef([]);
|
||||
const [expandedSectors, setExpandedSectors] = useState([]);
|
||||
const [isInitialized, setIsInitialized] = useState(false);
|
||||
// 新增:管理每个股票涨停原因的展开状态
|
||||
const [expandedStockReasons, setExpandedStockReasons] = useState({});
|
||||
|
||||
const cardBg = useColorModeValue('white', 'gray.800');
|
||||
|
||||
@@ -61,14 +54,6 @@ const SectorDetails = ({ sortedSectors, totalStocks, onStockClick }) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 新增:切换股票涨停原因的展开状态
|
||||
const toggleStockReason = (stockCode) => {
|
||||
setExpandedStockReasons(prev => ({
|
||||
...prev,
|
||||
[stockCode]: !prev[stockCode]
|
||||
}));
|
||||
};
|
||||
|
||||
const getSectorColorScheme = (sector) => {
|
||||
if (sector === '公告') return 'orange';
|
||||
if (sector === '其他') return 'gray';
|
||||
@@ -180,105 +165,72 @@ const SectorDetails = ({ sortedSectors, totalStocks, onStockClick }) => {
|
||||
.map((stock, idx) => (
|
||||
<Box
|
||||
key={`${stock.scode}-${idx}`}
|
||||
p={4}
|
||||
p={3}
|
||||
borderRadius="lg"
|
||||
bg="white"
|
||||
border="1px solid"
|
||||
borderColor="gray.200"
|
||||
borderLeft="4px solid"
|
||||
borderLeftColor={`${colorScheme}.400`}
|
||||
_hover={{
|
||||
transform: 'translateX(5px)',
|
||||
boxShadow: 'lg',
|
||||
borderLeftColor: `${colorScheme}.600`,
|
||||
bg: 'gray.50'
|
||||
}}
|
||||
transition="all 0.2s"
|
||||
cursor="pointer"
|
||||
onClick={() => onStockClick && onStockClick(stock)}
|
||||
>
|
||||
<Flex justify="space-between" align="start">
|
||||
<VStack align="start" spacing={2} flex={1}>
|
||||
<HStack spacing={2} wrap="wrap">
|
||||
<Text fontWeight="bold" fontSize="lg">{stock.sname}</Text>
|
||||
<Badge colorScheme="purple" fontSize="sm">{stock.scode}</Badge>
|
||||
{stock.continuous_days && (
|
||||
<Badge
|
||||
colorScheme={getContinuousDaysBadgeColor(stock.continuous_days)}
|
||||
variant="solid"
|
||||
fontSize="sm"
|
||||
>
|
||||
{stock.continuous_days}
|
||||
</Badge>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
<Collapse in={expandedStockReasons[stock.scode]}>
|
||||
<Box mt={2} p={3} bg="gray.50" borderRadius="md" border="1px solid" borderColor="gray.200">
|
||||
<Text fontSize="sm" color="gray.700" fontWeight="bold">
|
||||
涨停原因:
|
||||
</Text>
|
||||
<Text
|
||||
fontSize="sm"
|
||||
color="gray.600"
|
||||
noOfLines={3}
|
||||
{...getFormattedTextProps(stock.brief || stock.summary || '暂无涨停原因').props}
|
||||
>
|
||||
{getFormattedTextProps(stock.brief || stock.summary || '暂无涨停原因').children}
|
||||
</Text>
|
||||
</Box>
|
||||
</Collapse>
|
||||
|
||||
<HStack spacing={4} fontSize="xs" color="gray.500">
|
||||
<HStack spacing={1}>
|
||||
<TimeIcon boxSize={3} />
|
||||
<Text>涨停: {formatStockTime(stock)}</Text>
|
||||
</HStack>
|
||||
{stock.first_time && (
|
||||
<Text>首板: {stock.first_time.split(' ')[0]}</Text>
|
||||
)}
|
||||
{stock.change_pct && (
|
||||
<Text color="red.500" fontWeight="bold">
|
||||
涨幅: {stock.change_pct}%
|
||||
</Text>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
{stock.core_sectors && stock.core_sectors.length > 0 && (
|
||||
<Wrap spacing={1} mt={1}>
|
||||
{stock.core_sectors.slice(0, 5).map((s, i) => (
|
||||
<WrapItem key={`${s}-${i}`}>
|
||||
<Tag
|
||||
size="sm"
|
||||
colorScheme={getSectorColorScheme(s)}
|
||||
variant="subtle"
|
||||
>
|
||||
<TagLabel fontSize="xs">{s}</TagLabel>
|
||||
</Tag>
|
||||
</WrapItem>
|
||||
))}
|
||||
{stock.core_sectors.length > 5 && (
|
||||
<WrapItem>
|
||||
<Tag size="sm" colorScheme="gray">
|
||||
<TagLabel fontSize="xs">
|
||||
+{stock.core_sectors.length - 5}
|
||||
</TagLabel>
|
||||
</Tag>
|
||||
</WrapItem>
|
||||
)}
|
||||
</Wrap>
|
||||
<HStack justify="space-between" align="center" wrap="wrap" spacing={3}>
|
||||
{/* 左侧:股票基本信息 */}
|
||||
<HStack spacing={2} minW="200px">
|
||||
<Text fontWeight="bold" fontSize="md">{stock.sname}</Text>
|
||||
<Badge colorScheme="purple" fontSize="xs">{stock.scode}</Badge>
|
||||
{stock.continuous_days && (
|
||||
<Badge
|
||||
colorScheme={getContinuousDaysBadgeColor(stock.continuous_days)}
|
||||
variant="solid"
|
||||
fontSize="xs"
|
||||
>
|
||||
{stock.continuous_days}
|
||||
</Badge>
|
||||
)}
|
||||
</VStack>
|
||||
</HStack>
|
||||
|
||||
<IconButton
|
||||
icon={expandedStockReasons[stock.scode] ? <ChevronUpIcon /> : <ChevronDownIcon />}
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
colorScheme={colorScheme}
|
||||
aria-label={expandedStockReasons[stock.scode] ? "收起原因" : "展开原因"}
|
||||
onClick={() => toggleStockReason(stock.scode)}
|
||||
/>
|
||||
</Flex>
|
||||
{/* 中间:时间和涨幅信息 */}
|
||||
<HStack spacing={4} fontSize="xs" color="gray.500" flex={1} justify="center">
|
||||
<HStack spacing={1}>
|
||||
<TimeIcon boxSize={3} />
|
||||
<Text>涨停: {formatStockTime(stock)}</Text>
|
||||
</HStack>
|
||||
{stock.first_time && (
|
||||
<Text>首板: {stock.first_time.split(' ')[0]}</Text>
|
||||
)}
|
||||
{stock.change_pct && (
|
||||
<Text color="red.500" fontWeight="bold">
|
||||
涨幅: {stock.change_pct}%
|
||||
</Text>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
{/* 右侧:所属板块标签 */}
|
||||
{stock.core_sectors && stock.core_sectors.length > 0 && (
|
||||
<Wrap spacing={1} justify="flex-end" maxW="300px">
|
||||
{stock.core_sectors.slice(0, 4).map((s, i) => (
|
||||
<WrapItem key={`${s}-${i}`}>
|
||||
<Tag
|
||||
size="sm"
|
||||
colorScheme={getSectorColorScheme(s)}
|
||||
variant="subtle"
|
||||
>
|
||||
<TagLabel fontSize="xs">{s}</TagLabel>
|
||||
</Tag>
|
||||
</WrapItem>
|
||||
))}
|
||||
{stock.core_sectors.length > 4 && (
|
||||
<WrapItem>
|
||||
<Tag size="sm" colorScheme="gray">
|
||||
<TagLabel fontSize="xs">
|
||||
+{stock.core_sectors.length - 4}
|
||||
</TagLabel>
|
||||
</Tag>
|
||||
</WrapItem>
|
||||
)}
|
||||
</Wrap>
|
||||
)}
|
||||
</HStack>
|
||||
</Box>
|
||||
))}
|
||||
</VStack>
|
||||
|
||||
@@ -40,7 +40,7 @@ const API_URL = process.env.NODE_ENV === 'production' ? '/report-api' : 'http://
|
||||
// 恢复使用本页自带的轻量日历
|
||||
import EnhancedCalendar from './components/EnhancedCalendar';
|
||||
import SectorDetails from './components/SectorDetails';
|
||||
import { DataAnalysis, StockDetailModal } from './components/DataVisualizationComponents';
|
||||
import { DataAnalysis } from './components/DataVisualizationComponents';
|
||||
import { AdvancedSearch, SearchResultsModal } from './components/SearchComponents';
|
||||
|
||||
// 导航栏已由 MainLayout 提供,无需在此导入
|
||||
@@ -60,8 +60,6 @@ export default function LimitAnalyse() {
|
||||
const [wordCloudData, setWordCloudData] = useState([]);
|
||||
const [searchResults, setSearchResults] = useState(null);
|
||||
const [isSearchOpen, setIsSearchOpen] = useState(false);
|
||||
const [selectedStock, setSelectedStock] = useState(null);
|
||||
const [isStockDetailOpen, setIsStockDetailOpen] = useState(false);
|
||||
|
||||
const toast = useToast();
|
||||
|
||||
@@ -69,15 +67,7 @@ export default function LimitAnalyse() {
|
||||
const {
|
||||
trackDateSelected,
|
||||
trackDailyStatsViewed,
|
||||
trackSectorToggled,
|
||||
trackSectorClicked,
|
||||
trackLimitStockClicked,
|
||||
trackSearchInitiated,
|
||||
trackSearchResultClicked,
|
||||
trackHighPositionStocksViewed,
|
||||
trackSectorAnalysisViewed,
|
||||
trackDataRefreshed,
|
||||
trackStockDetailViewed,
|
||||
} = useLimitAnalyseEvents();
|
||||
|
||||
const bgColor = useColorModeValue('gray.50', 'gray.900');
|
||||
@@ -245,20 +235,6 @@ export default function LimitAnalyse() {
|
||||
}
|
||||
};
|
||||
|
||||
// 处理股票点击
|
||||
const handleStockClick = (stock) => {
|
||||
setSelectedStock(stock);
|
||||
setIsStockDetailOpen(true);
|
||||
// 🎯 追踪股票详情查看
|
||||
trackStockDetailViewed(stock.scode, stock.sname, 'sector_details');
|
||||
};
|
||||
|
||||
// 关闭股票详情弹窗
|
||||
const handleCloseStockDetail = () => {
|
||||
setIsStockDetailOpen(false);
|
||||
setSelectedStock(null);
|
||||
};
|
||||
|
||||
// 处理板块数据排序
|
||||
const getSortedSectorData = () => {
|
||||
if (!dailyData?.sector_data) return [];
|
||||
@@ -478,6 +454,18 @@ export default function LimitAnalyse() {
|
||||
{/* 高级搜索 */}
|
||||
<AdvancedSearch onSearch={handleSearch} loading={loading} />
|
||||
|
||||
{/* 数据分析 - 移到板块详情上方 */}
|
||||
{loading ? (
|
||||
<Skeleton height="500px" borderRadius="xl" mb={6} />
|
||||
) : (
|
||||
<Box mb={6}>
|
||||
<DataAnalysis
|
||||
dailyData={dailyData}
|
||||
wordCloudData={wordCloudData}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* 板块详情 - 核心内容 */}
|
||||
{loading ? (
|
||||
<Skeleton height="600px" borderRadius="xl" mb={6} />
|
||||
@@ -486,23 +474,12 @@ export default function LimitAnalyse() {
|
||||
<SectorDetails
|
||||
sortedSectors={getSortedSectorData()}
|
||||
totalStocks={dailyData?.total_stocks || 0}
|
||||
onStockClick={handleStockClick}
|
||||
/>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* 高位股统计 */}
|
||||
<HighPositionStocks dateStr={dateStr} />
|
||||
|
||||
{/* 数据分析 */}
|
||||
{loading ? (
|
||||
<Skeleton height="500px" borderRadius="xl" />
|
||||
) : (
|
||||
<DataAnalysis
|
||||
dailyData={dailyData}
|
||||
wordCloudData={wordCloudData}
|
||||
/>
|
||||
)}
|
||||
</Container>
|
||||
|
||||
{/* 弹窗 */}
|
||||
@@ -513,13 +490,6 @@ export default function LimitAnalyse() {
|
||||
onStockClick={() => {}}
|
||||
/>
|
||||
|
||||
{/* 股票详情弹窗 */}
|
||||
<StockDetailModal
|
||||
isOpen={isStockDetailOpen}
|
||||
onClose={handleCloseStockDetail}
|
||||
selectedStock={selectedStock}
|
||||
/>
|
||||
|
||||
{/* 浮动按钮 */}
|
||||
<Box position="fixed" bottom={8} right={8} zIndex={1000}>
|
||||
<VStack spacing={3}>
|
||||
|
||||
Reference in New Issue
Block a user