update pay function
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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}>
|
||||||
|
|||||||
Reference in New Issue
Block a user