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}>
<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>

View File

@@ -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,56 +165,32 @@ 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>
<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="sm"
fontSize="xs"
>
{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={4} fontSize="xs" color="gray.500" flex={1} justify="center">
<HStack spacing={1}>
<TimeIcon boxSize={3} />
<Text>涨停: {formatStockTime(stock)}</Text>
@@ -244,9 +205,10 @@ const SectorDetails = ({ sortedSectors, totalStocks, onStockClick }) => {
)}
</HStack>
{/* 右侧:所属板块标签 */}
{stock.core_sectors && stock.core_sectors.length > 0 && (
<Wrap spacing={1} mt={1}>
{stock.core_sectors.slice(0, 5).map((s, i) => (
<Wrap spacing={1} justify="flex-end" maxW="300px">
{stock.core_sectors.slice(0, 4).map((s, i) => (
<WrapItem key={`${s}-${i}`}>
<Tag
size="sm"
@@ -257,28 +219,18 @@ const SectorDetails = ({ sortedSectors, totalStocks, onStockClick }) => {
</Tag>
</WrapItem>
))}
{stock.core_sectors.length > 5 && (
{stock.core_sectors.length > 4 && (
<WrapItem>
<Tag size="sm" colorScheme="gray">
<TagLabel fontSize="xs">
+{stock.core_sectors.length - 5}
+{stock.core_sectors.length - 4}
</TagLabel>
</Tag>
</WrapItem>
)}
</Wrap>
)}
</VStack>
<IconButton
icon={expandedStockReasons[stock.scode] ? <ChevronUpIcon /> : <ChevronDownIcon />}
size="sm"
variant="ghost"
colorScheme={colorScheme}
aria-label={expandedStockReasons[stock.scode] ? "收起原因" : "展开原因"}
onClick={() => toggleStockReason(stock.scode)}
/>
</Flex>
</HStack>
</Box>
))}
</VStack>

View File

@@ -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}>