update pay function

This commit is contained in:
2025-11-29 09:42:41 +08:00
parent 42fdb7d754
commit 34323cc63d
3 changed files with 88 additions and 151 deletions

View File

@@ -138,7 +138,22 @@ export const AdvancedSearch = ({ onSearch, loading }) => {
<Box flex={1}> <Box flex={1}>
<Text fontSize="sm" mb={2} fontWeight="bold">搜索模式</Text> <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="hybrid">智能搜索推荐</option>
<option value="text">精确匹配</option> <option value="text">精确匹配</option>
<option value="vector">语义搜索</option> <option value="vector">语义搜索</option>

View File

@@ -14,28 +14,21 @@ import {
AccordionButton, AccordionButton,
AccordionPanel, AccordionPanel,
AccordionIcon, AccordionIcon,
IconButton,
Flex, Flex,
Circle, Circle,
Tag, Tag,
TagLabel, TagLabel,
Wrap, Wrap,
WrapItem, WrapItem,
Button,
useColorModeValue, useColorModeValue,
Collapse,
useDisclosure,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { StarIcon, ViewIcon, TimeIcon, ChevronDownIcon, ChevronUpIcon } from '@chakra-ui/icons'; import { StarIcon, TimeIcon } from '@chakra-ui/icons';
import { getFormattedTextProps } from '../../../utils/textUtils';
const SectorDetails = ({ sortedSectors, totalStocks, onStockClick }) => { const SectorDetails = ({ sortedSectors, totalStocks }) => {
// 使用 useRef 来维持展开状态,避免重新渲染时重置 // 使用 useRef 来维持展开状态,避免重新渲染时重置
const expandedSectorsRef = useRef([]); const expandedSectorsRef = useRef([]);
const [expandedSectors, setExpandedSectors] = useState([]); const [expandedSectors, setExpandedSectors] = useState([]);
const [isInitialized, setIsInitialized] = useState(false); const [isInitialized, setIsInitialized] = useState(false);
// 新增:管理每个股票涨停原因的展开状态
const [expandedStockReasons, setExpandedStockReasons] = useState({});
const cardBg = useColorModeValue('white', 'gray.800'); 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) => { const getSectorColorScheme = (sector) => {
if (sector === '公告') return 'orange'; if (sector === '公告') return 'orange';
if (sector === '其他') return 'gray'; if (sector === '其他') return 'gray';
@@ -180,56 +165,32 @@ const SectorDetails = ({ sortedSectors, totalStocks, onStockClick }) => {
.map((stock, idx) => ( .map((stock, idx) => (
<Box <Box
key={`${stock.scode}-${idx}`} key={`${stock.scode}-${idx}`}
p={4} p={3}
borderRadius="lg" borderRadius="lg"
bg="white" bg="white"
border="1px solid" border="1px solid"
borderColor="gray.200" borderColor="gray.200"
borderLeft="4px solid" borderLeft="4px solid"
borderLeftColor={`${colorScheme}.400`} 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"> <HStack justify="space-between" align="center" wrap="wrap" spacing={3}>
<VStack align="start" spacing={2} flex={1}> {/* 左侧:股票基本信息 */}
<HStack spacing={2} wrap="wrap"> <HStack spacing={2} minW="200px">
<Text fontWeight="bold" fontSize="lg">{stock.sname}</Text> <Text fontWeight="bold" fontSize="md">{stock.sname}</Text>
<Badge colorScheme="purple" fontSize="sm">{stock.scode}</Badge> <Badge colorScheme="purple" fontSize="xs">{stock.scode}</Badge>
{stock.continuous_days && ( {stock.continuous_days && (
<Badge <Badge
colorScheme={getContinuousDaysBadgeColor(stock.continuous_days)} colorScheme={getContinuousDaysBadgeColor(stock.continuous_days)}
variant="solid" variant="solid"
fontSize="sm" fontSize="xs"
> >
{stock.continuous_days} {stock.continuous_days}
</Badge> </Badge>
)} )}
</HStack> </HStack>
<Collapse in={expandedStockReasons[stock.scode]}> {/* 中间:时间和涨幅信息 */}
<Box mt={2} p={3} bg="gray.50" borderRadius="md" border="1px solid" borderColor="gray.200"> <HStack spacing={4} fontSize="xs" color="gray.500" flex={1} justify="center">
<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}> <HStack spacing={1}>
<TimeIcon boxSize={3} /> <TimeIcon boxSize={3} />
<Text>涨停: {formatStockTime(stock)}</Text> <Text>涨停: {formatStockTime(stock)}</Text>
@@ -244,9 +205,10 @@ const SectorDetails = ({ sortedSectors, totalStocks, onStockClick }) => {
)} )}
</HStack> </HStack>
{/* 右侧:所属板块标签 */}
{stock.core_sectors && stock.core_sectors.length > 0 && ( {stock.core_sectors && stock.core_sectors.length > 0 && (
<Wrap spacing={1} mt={1}> <Wrap spacing={1} justify="flex-end" maxW="300px">
{stock.core_sectors.slice(0, 5).map((s, i) => ( {stock.core_sectors.slice(0, 4).map((s, i) => (
<WrapItem key={`${s}-${i}`}> <WrapItem key={`${s}-${i}`}>
<Tag <Tag
size="sm" size="sm"
@@ -257,28 +219,18 @@ const SectorDetails = ({ sortedSectors, totalStocks, onStockClick }) => {
</Tag> </Tag>
</WrapItem> </WrapItem>
))} ))}
{stock.core_sectors.length > 5 && ( {stock.core_sectors.length > 4 && (
<WrapItem> <WrapItem>
<Tag size="sm" colorScheme="gray"> <Tag size="sm" colorScheme="gray">
<TagLabel fontSize="xs"> <TagLabel fontSize="xs">
+{stock.core_sectors.length - 5} +{stock.core_sectors.length - 4}
</TagLabel> </TagLabel>
</Tag> </Tag>
</WrapItem> </WrapItem>
)} )}
</Wrap> </Wrap>
)} )}
</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>
</Box> </Box>
))} ))}
</VStack> </VStack>

View File

@@ -40,7 +40,7 @@ const API_URL = process.env.NODE_ENV === 'production' ? '/report-api' : 'http://
// 恢复使用本页自带的轻量日历 // 恢复使用本页自带的轻量日历
import EnhancedCalendar from './components/EnhancedCalendar'; import EnhancedCalendar from './components/EnhancedCalendar';
import SectorDetails from './components/SectorDetails'; import SectorDetails from './components/SectorDetails';
import { DataAnalysis, StockDetailModal } from './components/DataVisualizationComponents'; import { DataAnalysis } from './components/DataVisualizationComponents';
import { AdvancedSearch, SearchResultsModal } from './components/SearchComponents'; import { AdvancedSearch, SearchResultsModal } from './components/SearchComponents';
// 导航栏已由 MainLayout 提供,无需在此导入 // 导航栏已由 MainLayout 提供,无需在此导入
@@ -60,8 +60,6 @@ export default function LimitAnalyse() {
const [wordCloudData, setWordCloudData] = useState([]); const [wordCloudData, setWordCloudData] = useState([]);
const [searchResults, setSearchResults] = useState(null); const [searchResults, setSearchResults] = useState(null);
const [isSearchOpen, setIsSearchOpen] = useState(false); const [isSearchOpen, setIsSearchOpen] = useState(false);
const [selectedStock, setSelectedStock] = useState(null);
const [isStockDetailOpen, setIsStockDetailOpen] = useState(false);
const toast = useToast(); const toast = useToast();
@@ -69,15 +67,7 @@ export default function LimitAnalyse() {
const { const {
trackDateSelected, trackDateSelected,
trackDailyStatsViewed, trackDailyStatsViewed,
trackSectorToggled,
trackSectorClicked,
trackLimitStockClicked,
trackSearchInitiated, trackSearchInitiated,
trackSearchResultClicked,
trackHighPositionStocksViewed,
trackSectorAnalysisViewed,
trackDataRefreshed,
trackStockDetailViewed,
} = useLimitAnalyseEvents(); } = useLimitAnalyseEvents();
const bgColor = useColorModeValue('gray.50', 'gray.900'); 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 = () => { const getSortedSectorData = () => {
if (!dailyData?.sector_data) return []; if (!dailyData?.sector_data) return [];
@@ -478,6 +454,18 @@ export default function LimitAnalyse() {
{/* 高级搜索 */} {/* 高级搜索 */}
<AdvancedSearch onSearch={handleSearch} loading={loading} /> <AdvancedSearch onSearch={handleSearch} loading={loading} />
{/* 数据分析 - 移到板块详情上方 */}
{loading ? (
<Skeleton height="500px" borderRadius="xl" mb={6} />
) : (
<Box mb={6}>
<DataAnalysis
dailyData={dailyData}
wordCloudData={wordCloudData}
/>
</Box>
)}
{/* 板块详情 - 核心内容 */} {/* 板块详情 - 核心内容 */}
{loading ? ( {loading ? (
<Skeleton height="600px" borderRadius="xl" mb={6} /> <Skeleton height="600px" borderRadius="xl" mb={6} />
@@ -486,23 +474,12 @@ export default function LimitAnalyse() {
<SectorDetails <SectorDetails
sortedSectors={getSortedSectorData()} sortedSectors={getSortedSectorData()}
totalStocks={dailyData?.total_stocks || 0} totalStocks={dailyData?.total_stocks || 0}
onStockClick={handleStockClick}
/> />
</Box> </Box>
)} )}
{/* 高位股统计 */} {/* 高位股统计 */}
<HighPositionStocks dateStr={dateStr} /> <HighPositionStocks dateStr={dateStr} />
{/* 数据分析 */}
{loading ? (
<Skeleton height="500px" borderRadius="xl" />
) : (
<DataAnalysis
dailyData={dailyData}
wordCloudData={wordCloudData}
/>
)}
</Container> </Container>
{/* 弹窗 */} {/* 弹窗 */}
@@ -513,13 +490,6 @@ export default function LimitAnalyse() {
onStockClick={() => {}} onStockClick={() => {}}
/> />
{/* 股票详情弹窗 */}
<StockDetailModal
isOpen={isStockDetailOpen}
onClose={handleCloseStockDetail}
selectedStock={selectedStock}
/>
{/* 浮动按钮 */} {/* 浮动按钮 */}
<Box position="fixed" bottom={8} right={8} zIndex={1000}> <Box position="fixed" bottom={8} right={8} zIndex={1000}>
<VStack spacing={3}> <VStack spacing={3}>