update pay function

This commit is contained in:
2025-11-23 14:25:38 +08:00
parent 4da1d580fc
commit f578969ee6

View File

@@ -46,6 +46,7 @@ import {
FaHistory,
FaNewspaper,
FaFileAlt,
FaClock,
} from 'react-icons/fa';
import { keyframes } from '@emotion/react';
@@ -58,6 +59,11 @@ const pulseAnimation = keyframes`
100% { transform: translate(-50%, -50%) scale(1); opacity: 0.5; }
`;
const shimmerAnimation = keyframes`
0% { transform: translateX(-100%); }
100% { transform: translateX(100%); }
`;
// API配置 - 与主文件保持一致
const API_BASE_URL = process.env.NODE_ENV === 'production'
? '/concept-api'
@@ -213,24 +219,35 @@ const ConceptTimelineModal = ({
// 如果有价格数据,添加价格事件
if (hasPriceData) {
const changePercent = item.price.avg_change_pct;
const isSignificantRise = changePercent >= 3; // 涨幅 >= 3% 为重大利好
let bgColor = '#e2e8f0';
let title = priceInfo.text;
if (priceInfo.color === 'red') {
bgColor = '#FC8181'; // 红色(上涨)
if (isSignificantRise) {
// 涨幅 >= 3%,使用醒目的橙红色 + 火焰图标
bgColor = '#F56565'; // 更深的红色
title = `🔥 ${priceInfo.text}`;
} else {
bgColor = '#FC8181'; // 普通红色(上涨)
}
} else if (priceInfo.color === 'green') {
bgColor = '#68D391'; // 绿色(下跌)
}
events.push({
id: `${item.date}-price`,
title: priceInfo.text,
title: title,
date: item.date,
start: item.date,
backgroundColor: bgColor,
borderColor: bgColor,
borderColor: isSignificantRise ? '#C53030' : bgColor, // 深红色边框强调
extendedProps: {
eventType: 'price',
priceInfo,
originalData: item,
isSignificantRise, // 标记重大涨幅
}
});
}
@@ -589,19 +606,46 @@ const ConceptTimelineModal = ({
<ModalOverlay />
<ModalContent maxW="1400px" m={4}>
<ModalHeader
bgGradient="linear(to-r, purple.500, pink.500)"
bgGradient="linear(135deg, purple.600 0%, purple.500 50%, pink.500 100%)"
color="white"
position="sticky"
top={0}
zIndex={10}
py={6}
boxShadow="lg"
>
<HStack spacing={4} flexWrap="wrap">
<Icon
as={FaChartLine}
boxSize={6}
filter="drop-shadow(0 2px 4px rgba(0,0,0,0.2))"
/>
<Text
fontSize="xl"
fontWeight="bold"
textShadow="0 2px 4px rgba(0,0,0,0.2)"
>
{conceptName} - 历史时间轴
</Text>
<Badge
colorScheme="yellow"
px={3}
py={1}
borderRadius="full"
fontSize="sm"
boxShadow="md"
>
<HStack spacing={3}>
<Icon as={FaChartLine} />
<Text>{conceptName} - 历史时间轴</Text>
<Badge colorScheme="yellow" ml={2}>
最近100天
</Badge>
<Badge colorScheme="purple" ml={2} fontSize="xs">
<Badge
bg="whiteAlpha.300"
color="white"
px={3}
py={1}
borderRadius="full"
fontSize="xs"
backdropFilter="blur(10px)"
>
🔥 Max版功能
</Badge>
</HStack>
@@ -638,22 +682,81 @@ const ConceptTimelineModal = ({
) : timelineData.length > 0 ? (
<Box position="relative" maxW="1200px" mx="auto" px={4}>
{/* 图例说明 */}
<Flex justify="center" mb={4} flexWrap="wrap" gap={3}>
<HStack spacing={2}>
<Box w={4} h={4} bg="#9F7AEA" borderRadius="sm" />
<Text fontSize="sm">有新闻/研报</Text>
<Flex justify="center" mb={6} flexWrap="wrap" gap={4}>
<HStack
spacing={2}
px={4}
py={2}
bg="purple.50"
borderRadius="lg"
border="1px solid"
borderColor="purple.200"
boxShadow="sm"
transition="all 0.2s"
_hover={{ transform: 'translateY(-2px)', boxShadow: 'md' }}
>
<Box w={3} h={3} bg="#9F7AEA" borderRadius="full" boxShadow="sm" />
<Text fontSize="sm" fontWeight="medium" color="gray.700">📰 新闻</Text>
</HStack>
<HStack spacing={2}>
<Box w={4} h={4} bg="#FC8181" borderRadius="sm" />
<Text fontSize="sm">上涨</Text>
<HStack
spacing={2}
px={4}
py={2}
bg="purple.50"
borderRadius="lg"
border="1px solid"
borderColor="purple.300"
boxShadow="sm"
transition="all 0.2s"
_hover={{ transform: 'translateY(-2px)', boxShadow: 'md' }}
>
<Box w={3} h={3} bg="#805AD5" borderRadius="full" boxShadow="sm" />
<Text fontSize="sm" fontWeight="medium" color="gray.700">📊 研报</Text>
</HStack>
<HStack spacing={2}>
<Box w={4} h={4} bg="#68D391" borderRadius="sm" />
<Text fontSize="sm">下跌</Text>
<HStack
spacing={2}
px={4}
py={2}
bg="red.50"
borderRadius="lg"
border="1px solid"
borderColor="red.200"
boxShadow="sm"
transition="all 0.2s"
_hover={{ transform: 'translateY(-2px)', boxShadow: 'md' }}
>
<Icon as={FaArrowUp} color="red.500" boxSize={3} />
<Text fontSize="sm" fontWeight="medium" color="gray.700">上涨</Text>
</HStack>
<HStack spacing={2}>
<Box w={4} h={4} bg="#e2e8f0" borderRadius="sm" />
<Text fontSize="sm">无数据</Text>
<HStack
spacing={2}
px={4}
py={2}
bg="green.50"
borderRadius="lg"
border="1px solid"
borderColor="green.200"
boxShadow="sm"
transition="all 0.2s"
_hover={{ transform: 'translateY(-2px)', boxShadow: 'md' }}
>
<Icon as={FaArrowDown} color="green.500" boxSize={3} />
<Text fontSize="sm" fontWeight="medium" color="gray.700">下跌</Text>
</HStack>
<HStack
spacing={2}
px={4}
py={2}
bg="orange.50"
borderRadius="lg"
border="1px solid"
borderColor="orange.200"
boxShadow="sm"
transition="all 0.2s"
_hover={{ transform: 'translateY(-2px)', boxShadow: 'md' }}
>
<Text fontSize="sm" fontWeight="bold">🔥</Text>
<Text fontSize="sm" fontWeight="medium" color="gray.700">涨3%+</Text>
</HStack>
</Flex>
@@ -748,28 +851,32 @@ const ConceptTimelineModal = ({
displayEventTime={false}
/>
</Box>
{/* 底部说明 */}
<Box textAlign="center" mt={6}>
<Badge
colorScheme="purple"
variant="subtle"
px={4}
py={2}
borderRadius="full"
fontSize="sm"
>
时间轴起始点
</Badge>
</Box>
</Box>
) : (
<Center py={20}>
<VStack spacing={4}>
<Icon as={FaHistory} boxSize={16} color="gray.300" />
<Text fontSize="lg" color="gray.500">
<Center py={24}>
<VStack
spacing={6}
bg="white"
p={12}
borderRadius="2xl"
boxShadow="xl"
border="2px dashed"
borderColor="purple.200"
>
<Icon
as={FaHistory}
boxSize={24}
color="purple.300"
opacity={0.5}
/>
<VStack spacing={2}>
<Text fontSize="2xl" fontWeight="bold" color="gray.700">
暂无历史数据
</Text>
<Text fontSize="md" color="gray.500">
该概念在最近100天内没有相关事件记录
</Text>
</VStack>
</VStack>
</Center>
)}
@@ -780,8 +887,24 @@ const ConceptTimelineModal = ({
</Box>
</ModalBody>
<ModalFooter borderTop="1px solid" borderColor="gray.200">
<Button colorScheme="purple" onClick={onClose}>
<ModalFooter
borderTop="2px solid"
borderColor="purple.100"
bg="gray.50"
py={4}
>
<Button
colorScheme="purple"
size="lg"
px={8}
onClick={onClose}
boxShadow="md"
_hover={{
transform: 'translateY(-2px)',
boxShadow: 'lg',
}}
transition="all 0.2s"
>
关闭
</Button>
</ModalFooter>
@@ -798,28 +921,69 @@ const ConceptTimelineModal = ({
scrollBehavior="inside"
>
<ModalOverlay />
<ModalContent>
<ModalHeader bgGradient="linear(to-r, purple.500, pink.500)" color="white">
<VStack align="start" spacing={2}>
<HStack>
<Icon as={CalendarIcon} />
<Text>{formatDateDisplay(selectedDate)}</Text>
<ModalContent borderRadius="2xl" overflow="hidden">
<ModalHeader
bgGradient="linear(135deg, purple.600 0%, purple.500 50%, pink.500 100%)"
color="white"
py={6}
position="relative"
_before={{
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
bgGradient: 'linear(to-r, transparent, whiteAlpha.200, transparent)',
animation: `${shimmerAnimation} 3s infinite`,
}}
>
<VStack align="start" spacing={3} position="relative" zIndex={1}>
<HStack spacing={3}>
<Icon
as={CalendarIcon}
boxSize={6}
filter="drop-shadow(0 2px 4px rgba(0,0,0,0.2))"
/>
<Text fontSize="xl" fontWeight="bold" textShadow="0 2px 4px rgba(0,0,0,0.2)">
{formatDateDisplay(selectedDate)}
</Text>
</HStack>
{selectedDateData.price && (
<HStack spacing={3} fontSize="sm">
<Badge colorScheme={getPriceInfo(selectedDateData.price).color} variant="solid" px={3} py={1}>
<HStack spacing={1}>
<HStack spacing={4} fontSize="sm" flexWrap="wrap">
<Badge
colorScheme={getPriceInfo(selectedDateData.price).color}
variant="solid"
px={4}
py={2}
borderRadius="full"
fontSize="md"
boxShadow="md"
>
<HStack spacing={2}>
{getPriceInfo(selectedDateData.price).icon && (
<Icon
as={getPriceInfo(selectedDateData.price).icon}
boxSize={3}
boxSize={4}
/>
<Text>{getPriceInfo(selectedDateData.price).text}</Text>
)}
<Text fontWeight="bold">
{getPriceInfo(selectedDateData.price).text}
</Text>
</HStack>
</Badge>
{selectedDateData.price.stock_count && (
<Text opacity={0.9}>
📊 统计股票: {selectedDateData.price.stock_count}
</Text>
<HStack
spacing={1}
bg="whiteAlpha.300"
px={3}
py={1}
borderRadius="full"
backdropFilter="blur(10px)"
>
<Text fontWeight="medium">📊 统计股票:</Text>
<Text fontWeight="bold">{selectedDateData.price.stock_count} </Text>
</HStack>
)}
</HStack>
)}
@@ -829,20 +993,85 @@ const ConceptTimelineModal = ({
<ModalBody py={6}>
{selectedDateData.events && selectedDateData.events.length > 0 ? (
<VStack align="stretch" spacing={4}>
<VStack align="stretch" spacing={6}>
{/* 统计卡片 */}
<HStack spacing={4} justifyContent="center">
<Box
px={6}
py={3}
bg="blue.50"
borderRadius="lg"
boxShadow="sm"
border="1px solid"
borderColor="blue.200"
>
<HStack spacing={2}>
<Icon as={FaNewspaper} color="blue.500" boxSize={5} />
<Text fontWeight="bold" fontSize="lg" color="blue.700">
{selectedDateData.events.filter(e => e.type === 'news').length}
</Text>
<Text fontSize="sm" color="gray.600">条新闻</Text>
</HStack>
</Box>
<Box
px={6}
py={3}
bg="green.50"
borderRadius="lg"
boxShadow="sm"
border="1px solid"
borderColor="green.200"
>
<HStack spacing={2}>
<Icon as={FaFileAlt} color="green.500" boxSize={5} />
<Text fontWeight="bold" fontSize="lg" color="green.700">
{selectedDateData.events.filter(e => e.type === 'report').length}
</Text>
<Text fontSize="sm" color="gray.600">篇研报</Text>
</HStack>
</Box>
</HStack>
{/* 事件列表 */}
<VStack align="stretch" spacing={5}>
{selectedDateData.events.map((event, eventIdx) => (
<Box
key={eventIdx}
p={4}
bg={event.type === 'news' ? 'blue.50' : 'green.50'}
borderRadius="lg"
borderLeft="4px solid"
borderLeftColor={event.type === 'news' ? 'blue.400' : 'green.400'}
p={5}
bgGradient={
event.type === 'news'
? 'linear(to-br, blue.50, blue.100)'
: 'linear(to-br, green.50, green.100)'
}
borderRadius="xl"
borderLeft="5px solid"
borderLeftColor={event.type === 'news' ? 'blue.500' : 'green.500'}
boxShadow="sm"
_hover={{
transform: 'translateX(4px)',
boxShadow: 'md',
transform: 'translateX(6px) translateY(-2px)',
boxShadow: 'lg',
borderLeftColor: event.type === 'news' ? 'blue.600' : 'green.600',
}}
transition="all 0.3s cubic-bezier(0.4, 0, 0.2, 1)"
cursor="pointer"
position="relative"
overflow="hidden"
_before={{
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: '3px',
bgGradient: event.type === 'news'
? 'linear(to-r, blue.400, blue.600, blue.400)'
: 'linear(to-r, green.400, green.600, green.400)',
opacity: 0,
transition: 'opacity 0.3s',
}}
_hover_before={{
opacity: 1,
}}
transition="all 0.2s"
>
<VStack align="start" spacing={3}>
<HStack spacing={2} flexWrap="wrap">
@@ -850,50 +1079,90 @@ const ConceptTimelineModal = ({
colorScheme={event.type === 'news' ? 'blue' : 'green'}
variant="solid"
fontSize="sm"
px={3}
py={1}
borderRadius="full"
boxShadow="sm"
>
{event.type === 'news' ? '📰 新闻' : '📊 研报'}
</Badge>
{event.source && (
<Badge variant="subtle" fontSize="xs">
{event.source}
</Badge>
)}
{event.publisher && (
<Badge colorScheme="purple" variant="subtle" fontSize="xs">
<Badge
colorScheme="purple"
variant="subtle"
fontSize="xs"
px={2}
py={1}
borderRadius="md"
>
{event.publisher}
</Badge>
)}
{event.rating && (
<Badge colorScheme="orange" variant="solid" fontSize="xs">
{event.rating}
<Badge
colorScheme="orange"
variant="solid"
fontSize="xs"
px={2}
py={1}
borderRadius="md"
>
{event.rating}
</Badge>
)}
{event.security_name && (
<Badge colorScheme="cyan" variant="subtle" fontSize="xs">
{event.security_name}
<Badge
colorScheme="cyan"
variant="subtle"
fontSize="xs"
px={2}
py={1}
borderRadius="md"
>
🏢 {event.security_name}
</Badge>
)}
</HStack>
<Text fontWeight="bold" fontSize="md" color="gray.800">
<Text
fontWeight="bold"
fontSize="lg"
color="gray.800"
lineHeight="1.4"
>
{event.title}
</Text>
<Text fontSize="sm" color="gray.600" noOfLines={4}>
<Text
fontSize="sm"
color="gray.600"
noOfLines={3}
lineHeight="1.6"
>
{event.content || '暂无内容'}
</Text>
<HStack spacing={4} w="100%" justify="space-between" align="center" mt={1}>
{event.time && (
<Text fontSize="xs" color="gray.500">
🕐 {formatDateTime(event.time)}
<HStack spacing={1}>
<Icon as={FaClock} color="gray.500" boxSize={3} />
<Text fontSize="xs" color="gray.500" fontWeight="medium">
{formatDateTime(event.time)}
</Text>
</HStack>
)}
<Button
size="sm"
colorScheme="blue"
variant="outline"
colorScheme={event.type === 'news' ? 'blue' : 'green'}
variant="solid"
leftIcon={<ViewIcon />}
boxShadow="sm"
_hover={{
transform: 'scale(1.05)',
boxShadow: 'md',
}}
transition="all 0.2s"
onClick={() => {
if (event.type === 'news') {
trackNewsClicked(event, selectedDate);
@@ -923,31 +1192,62 @@ const ConceptTimelineModal = ({
}
}}
>
查看全文
查看详情
</Button>
</HStack>
</VStack>
</Box>
))}
</VStack>
) : (
<Center py={12}>
<VStack spacing={4}>
<Icon as={FaHistory} boxSize={16} color="gray.300" />
<Text fontSize="lg" color="gray.500">
<Center py={16}>
<VStack
spacing={5}
bg="gray.50"
p={10}
borderRadius="2xl"
border="2px dashed"
borderColor="gray.300"
>
<Icon
as={FaHistory}
boxSize={20}
color="gray.400"
opacity={0.6}
/>
<VStack spacing={2}>
<Text fontSize="xl" fontWeight="bold" color="gray.600">
当日无新闻或研报
</Text>
{selectedDateData.price && (
<Text fontSize="sm" color="gray.400">
<Text fontSize="md" color="gray.500">
仅有涨跌幅数据
</Text>
)}
</VStack>
</VStack>
</Center>
)}
</ModalBody>
<ModalFooter borderTop="1px solid" borderColor="gray.200">
<Button colorScheme="purple" onClick={onDateDetailClose}>
<ModalFooter
borderTop="2px solid"
borderColor="gray.100"
bg="gray.50"
py={4}
>
<Button
colorScheme="purple"
size="lg"
px={8}
onClick={onDateDetailClose}
boxShadow="md"
_hover={{
transform: 'translateY(-2px)',
boxShadow: 'lg',
}}
transition="all 0.2s"
>
关闭
</Button>
</ModalFooter>