update pay ui
This commit is contained in:
@@ -73,9 +73,10 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
const [useCustomRange, setUseCustomRange] = useState(false);
|
||||
const toast = useToast();
|
||||
|
||||
const bg = useColorModeValue('white', 'gray.800');
|
||||
const cardBg = useColorModeValue('gray.50', 'gray.700');
|
||||
const borderColor = useColorModeValue('gray.200', 'gray.600');
|
||||
// 深色主题颜色(固定使用深色模式)
|
||||
const bg = 'rgba(15, 23, 42, 0.8)';
|
||||
const cardBg = 'rgba(15, 23, 42, 0.6)';
|
||||
const borderColor = 'whiteAlpha.100';
|
||||
|
||||
// 获取统计数据
|
||||
const fetchStatsData = async (days = timeRange, startDate = null, endDate = null) => {
|
||||
@@ -250,21 +251,21 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
return 'gray.500';
|
||||
};
|
||||
|
||||
// 统计卡片组件 - 美化版
|
||||
// 统计卡片组件 - 深色主题版
|
||||
const StatsCard = ({ title, icon, color, data, renderItem, isLoading }) => (
|
||||
<Box p={4}>
|
||||
{isLoading ? (
|
||||
<VStack spacing={3} align="stretch">
|
||||
{[1, 2, 3, 4, 5].map((i) => (
|
||||
<HStack key={i} justify="space-between" p={3} bg="gray.50" borderRadius="lg">
|
||||
<HStack key={i} justify="space-between" p={3} bg="whiteAlpha.50" borderRadius="lg">
|
||||
<HStack spacing={2} flex={1}>
|
||||
<Skeleton height="20px" width="20px" borderRadius="full" />
|
||||
<Skeleton height="20px" width="20px" borderRadius="full" startColor="whiteAlpha.100" endColor="whiteAlpha.200" />
|
||||
<VStack align="start" spacing={1} flex={1}>
|
||||
<Skeleton height="14px" width="80%" />
|
||||
<Skeleton height="12px" width="60%" />
|
||||
<Skeleton height="14px" width="80%" startColor="whiteAlpha.100" endColor="whiteAlpha.200" />
|
||||
<Skeleton height="12px" width="60%" startColor="whiteAlpha.100" endColor="whiteAlpha.200" />
|
||||
</VStack>
|
||||
</HStack>
|
||||
<Skeleton height="20px" width="50px" borderRadius="md" />
|
||||
<Skeleton height="20px" width="50px" borderRadius="md" startColor="whiteAlpha.100" endColor="whiteAlpha.200" />
|
||||
</HStack>
|
||||
))}
|
||||
</VStack>
|
||||
@@ -275,15 +276,15 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
width: '4px',
|
||||
},
|
||||
'&::-webkit-scrollbar-track': {
|
||||
background: '#f1f1f1',
|
||||
background: 'rgba(255,255,255,0.05)',
|
||||
borderRadius: '10px',
|
||||
},
|
||||
'&::-webkit-scrollbar-thumb': {
|
||||
background: '#c1c1c1',
|
||||
background: 'rgba(255,255,255,0.2)',
|
||||
borderRadius: '10px',
|
||||
},
|
||||
'&::-webkit-scrollbar-thumb:hover': {
|
||||
background: '#a8a8a8',
|
||||
background: 'rgba(255,255,255,0.3)',
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -309,14 +310,14 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
align="center"
|
||||
p={3}
|
||||
borderRadius="xl"
|
||||
bg={index < 3 ? 'red.50' : 'gray.50'}
|
||||
bg={index < 3 ? 'rgba(239, 68, 68, 0.15)' : 'whiteAlpha.50'}
|
||||
border="1px solid"
|
||||
borderColor={index < 3 ? 'red.100' : 'gray.200'}
|
||||
borderColor={index < 3 ? 'red.500' : 'whiteAlpha.100'}
|
||||
_hover={{
|
||||
transform: 'translateY(-1px)',
|
||||
shadow: 'md',
|
||||
cursor: 'pointer',
|
||||
bg: index < 3 ? 'red.100' : 'gray.100'
|
||||
bg: index < 3 ? 'rgba(239, 68, 68, 0.25)' : 'whiteAlpha.100'
|
||||
}}
|
||||
transition="all 0.2s"
|
||||
onClick={() => onConceptClick?.(null, item.name)}
|
||||
@@ -324,8 +325,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
<HStack spacing={3} flex={1}>
|
||||
<Box position="relative">
|
||||
<Badge
|
||||
colorScheme={index === 0 ? 'yellow' : index === 1 ? 'orange' : index === 2 ? 'red' : 'gray'}
|
||||
variant="solid"
|
||||
bg={index === 0 ? 'yellow.500' : index === 1 ? 'orange.500' : index === 2 ? 'red.500' : 'whiteAlpha.200'}
|
||||
color="white"
|
||||
borderRadius="full"
|
||||
minW="24px"
|
||||
h="24px"
|
||||
@@ -344,16 +345,16 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
position="absolute"
|
||||
top="-8px"
|
||||
right="-8px"
|
||||
color="yellow.500"
|
||||
color="yellow.400"
|
||||
boxSize={3}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<VStack align="start" spacing={0} flex={1}>
|
||||
<Text fontSize="sm" fontWeight="bold" noOfLines={1} color="gray.800">
|
||||
<Text fontSize="sm" fontWeight="bold" noOfLines={1} color="white">
|
||||
{item.name}
|
||||
</Text>
|
||||
<HStack spacing={2} fontSize="xs" color="gray.600">
|
||||
<HStack spacing={2} fontSize="xs" color="whiteAlpha.600">
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaChartLine} boxSize={2.5} />
|
||||
<Text>{item.stock_count}股</Text>
|
||||
@@ -367,8 +368,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
</VStack>
|
||||
</HStack>
|
||||
<Badge
|
||||
colorScheme="red"
|
||||
variant="solid"
|
||||
bg="red.500"
|
||||
color="white"
|
||||
borderRadius="lg"
|
||||
fontSize="xs"
|
||||
fontWeight="bold"
|
||||
@@ -392,22 +393,22 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
align="center"
|
||||
p={3}
|
||||
borderRadius="xl"
|
||||
bg={index < 3 ? 'green.50' : 'gray.50'}
|
||||
bg={index < 3 ? 'rgba(34, 197, 94, 0.15)' : 'whiteAlpha.50'}
|
||||
border="1px solid"
|
||||
borderColor={index < 3 ? 'green.100' : 'gray.200'}
|
||||
borderColor={index < 3 ? 'green.500' : 'whiteAlpha.100'}
|
||||
_hover={{
|
||||
transform: 'translateY(-1px)',
|
||||
shadow: 'md',
|
||||
cursor: 'pointer',
|
||||
bg: index < 3 ? 'green.100' : 'gray.100'
|
||||
bg: index < 3 ? 'rgba(34, 197, 94, 0.25)' : 'whiteAlpha.100'
|
||||
}}
|
||||
transition="all 0.2s"
|
||||
onClick={() => onConceptClick?.(null, item.name)}
|
||||
>
|
||||
<HStack spacing={3} flex={1}>
|
||||
<Badge
|
||||
colorScheme={index < 3 ? 'green' : 'gray'}
|
||||
variant="solid"
|
||||
bg={index < 3 ? 'green.500' : 'whiteAlpha.200'}
|
||||
color="white"
|
||||
borderRadius="full"
|
||||
minW="24px"
|
||||
h="24px"
|
||||
@@ -421,10 +422,10 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
{index + 1}
|
||||
</Badge>
|
||||
<VStack align="start" spacing={0} flex={1}>
|
||||
<Text fontSize="sm" fontWeight="bold" noOfLines={1} color="gray.800">
|
||||
<Text fontSize="sm" fontWeight="bold" noOfLines={1} color="white">
|
||||
{item.name}
|
||||
</Text>
|
||||
<HStack spacing={2} fontSize="xs" color="gray.600">
|
||||
<HStack spacing={2} fontSize="xs" color="whiteAlpha.600">
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaChartLine} boxSize={2.5} />
|
||||
<Text>{item.stock_count}股</Text>
|
||||
@@ -438,8 +439,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
</VStack>
|
||||
</HStack>
|
||||
<Badge
|
||||
colorScheme="green"
|
||||
variant="solid"
|
||||
bg="green.500"
|
||||
color="white"
|
||||
borderRadius="lg"
|
||||
fontSize="xs"
|
||||
fontWeight="bold"
|
||||
@@ -463,14 +464,14 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
align="center"
|
||||
p={3}
|
||||
borderRadius="xl"
|
||||
bg={index < 3 ? 'orange.50' : 'gray.50'}
|
||||
bg={index < 3 ? 'rgba(251, 146, 60, 0.15)' : 'whiteAlpha.50'}
|
||||
border="1px solid"
|
||||
borderColor={index < 3 ? 'orange.100' : 'gray.200'}
|
||||
borderColor={index < 3 ? 'orange.500' : 'whiteAlpha.100'}
|
||||
_hover={{
|
||||
transform: 'translateY(-1px)',
|
||||
shadow: 'md',
|
||||
cursor: 'pointer',
|
||||
bg: index < 3 ? 'orange.100' : 'gray.100'
|
||||
bg: index < 3 ? 'rgba(251, 146, 60, 0.25)' : 'whiteAlpha.100'
|
||||
}}
|
||||
transition="all 0.2s"
|
||||
onClick={() => onConceptClick?.(null, item.name)}
|
||||
@@ -478,8 +479,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
<HStack spacing={3} flex={1}>
|
||||
<Box position="relative">
|
||||
<Badge
|
||||
colorScheme={index === 0 ? 'orange' : index < 3 ? 'yellow' : 'gray'}
|
||||
variant="solid"
|
||||
bg={index === 0 ? 'orange.500' : index < 3 ? 'yellow.500' : 'whiteAlpha.200'}
|
||||
color="white"
|
||||
borderRadius="full"
|
||||
minW="24px"
|
||||
h="24px"
|
||||
@@ -498,16 +499,16 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
position="absolute"
|
||||
top="-8px"
|
||||
right="-8px"
|
||||
color="orange.500"
|
||||
color="orange.400"
|
||||
boxSize={3}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<VStack align="start" spacing={0} flex={1}>
|
||||
<Text fontSize="sm" fontWeight="bold" noOfLines={1} color="gray.800">
|
||||
<Text fontSize="sm" fontWeight="bold" noOfLines={1} color="white">
|
||||
{item.name}
|
||||
</Text>
|
||||
<HStack spacing={2} fontSize="xs" color="gray.600">
|
||||
<HStack spacing={2} fontSize="xs" color="whiteAlpha.600">
|
||||
<HStack spacing={1}>
|
||||
<Icon as={FaNewspaper} boxSize={2.5} />
|
||||
<Text>{item.news_count}</Text>
|
||||
@@ -521,8 +522,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
</VStack>
|
||||
</HStack>
|
||||
<Badge
|
||||
colorScheme="orange"
|
||||
variant="solid"
|
||||
bg="orange.500"
|
||||
color="white"
|
||||
borderRadius="lg"
|
||||
fontSize="xs"
|
||||
fontWeight="bold"
|
||||
@@ -546,14 +547,14 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
align="center"
|
||||
p={3}
|
||||
borderRadius="xl"
|
||||
bg={index < 3 ? 'purple.50' : 'gray.50'}
|
||||
bg={index < 3 ? 'rgba(168, 85, 247, 0.15)' : 'whiteAlpha.50'}
|
||||
border="1px solid"
|
||||
borderColor={index < 3 ? 'purple.100' : 'gray.200'}
|
||||
borderColor={index < 3 ? 'purple.500' : 'whiteAlpha.100'}
|
||||
_hover={{
|
||||
transform: 'translateY(-1px)',
|
||||
shadow: 'md',
|
||||
cursor: 'pointer',
|
||||
bg: index < 3 ? 'purple.100' : 'gray.100'
|
||||
bg: index < 3 ? 'rgba(168, 85, 247, 0.25)' : 'whiteAlpha.100'
|
||||
}}
|
||||
transition="all 0.2s"
|
||||
onClick={() => onConceptClick?.(null, item.name)}
|
||||
@@ -561,8 +562,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
<HStack spacing={3} flex={1}>
|
||||
<Box position="relative">
|
||||
<Badge
|
||||
colorScheme={index < 3 ? 'purple' : 'gray'}
|
||||
variant="solid"
|
||||
bg={index < 3 ? 'purple.500' : 'whiteAlpha.200'}
|
||||
color="white"
|
||||
borderRadius="full"
|
||||
minW="24px"
|
||||
h="24px"
|
||||
@@ -581,23 +582,23 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
position="absolute"
|
||||
top="-8px"
|
||||
right="-8px"
|
||||
color="purple.500"
|
||||
color="purple.400"
|
||||
boxSize={3}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<VStack align="start" spacing={0} flex={1}>
|
||||
<Text fontSize="sm" fontWeight="bold" noOfLines={1} color="gray.800">
|
||||
<Text fontSize="sm" fontWeight="bold" noOfLines={1} color="white">
|
||||
{item.name}
|
||||
</Text>
|
||||
<Text fontSize="xs" color="gray.600">
|
||||
<Text fontSize="xs" color="whiteAlpha.600">
|
||||
均幅 {formatChange(item.avg_change)}
|
||||
</Text>
|
||||
</VStack>
|
||||
</HStack>
|
||||
<Badge
|
||||
colorScheme="purple"
|
||||
variant="solid"
|
||||
bg="purple.500"
|
||||
color="white"
|
||||
borderRadius="lg"
|
||||
fontSize="xs"
|
||||
fontWeight="bold"
|
||||
@@ -621,14 +622,14 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
align="center"
|
||||
p={3}
|
||||
borderRadius="xl"
|
||||
bg={index < 3 ? 'cyan.50' : 'gray.50'}
|
||||
bg={index < 3 ? 'rgba(34, 211, 238, 0.15)' : 'whiteAlpha.50'}
|
||||
border="1px solid"
|
||||
borderColor={index < 3 ? 'cyan.100' : 'gray.200'}
|
||||
borderColor={index < 3 ? 'cyan.500' : 'whiteAlpha.100'}
|
||||
_hover={{
|
||||
transform: 'translateY(-1px)',
|
||||
shadow: 'md',
|
||||
cursor: 'pointer',
|
||||
bg: index < 3 ? 'cyan.100' : 'gray.100'
|
||||
bg: index < 3 ? 'rgba(34, 211, 238, 0.25)' : 'whiteAlpha.100'
|
||||
}}
|
||||
transition="all 0.2s"
|
||||
onClick={() => onConceptClick?.(null, item.name)}
|
||||
@@ -636,8 +637,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
<HStack spacing={3} flex={1}>
|
||||
<Box position="relative">
|
||||
<Badge
|
||||
colorScheme={index === 0 ? 'cyan' : index < 3 ? 'blue' : 'gray'}
|
||||
variant="solid"
|
||||
bg={index === 0 ? 'cyan.500' : index < 3 ? 'blue.500' : 'whiteAlpha.200'}
|
||||
color="white"
|
||||
borderRadius="full"
|
||||
minW="24px"
|
||||
h="24px"
|
||||
@@ -656,23 +657,23 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
position="absolute"
|
||||
top="-8px"
|
||||
right="-8px"
|
||||
color="cyan.500"
|
||||
color="cyan.400"
|
||||
boxSize={3}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
<VStack align="start" spacing={0} flex={1}>
|
||||
<Text fontSize="sm" fontWeight="bold" noOfLines={1} color="gray.800">
|
||||
<Text fontSize="sm" fontWeight="bold" noOfLines={1} color="white">
|
||||
{item.name}
|
||||
</Text>
|
||||
<Text fontSize="xs" color="gray.600">
|
||||
<Text fontSize="xs" color="whiteAlpha.600">
|
||||
累计 {formatChange(item.total_change)}
|
||||
</Text>
|
||||
</VStack>
|
||||
</HStack>
|
||||
<Badge
|
||||
colorScheme="cyan"
|
||||
variant="solid"
|
||||
bg="cyan.500"
|
||||
color="white"
|
||||
borderRadius="lg"
|
||||
fontSize="xs"
|
||||
fontWeight="bold"
|
||||
@@ -689,14 +690,17 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{/* 顶部标题卡片 */}
|
||||
{/* 顶部标题卡片 - 深色玻璃态 */}
|
||||
<Box
|
||||
bg="linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
|
||||
bg="rgba(15, 23, 42, 0.8)"
|
||||
backdropFilter="blur(20px)"
|
||||
p={4}
|
||||
borderRadius="xl"
|
||||
mb={4}
|
||||
position="relative"
|
||||
overflow="hidden"
|
||||
border="1px solid"
|
||||
borderColor="whiteAlpha.100"
|
||||
>
|
||||
{/* 背景装饰 */}
|
||||
<Box
|
||||
@@ -706,8 +710,9 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
width="80px"
|
||||
height="80px"
|
||||
borderRadius="full"
|
||||
bg="whiteAlpha.200"
|
||||
filter="blur(10px)"
|
||||
bg="purple.500"
|
||||
opacity={0.2}
|
||||
filter="blur(20px)"
|
||||
/>
|
||||
<Box
|
||||
position="absolute"
|
||||
@@ -716,15 +721,16 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
width="60px"
|
||||
height="60px"
|
||||
borderRadius="full"
|
||||
bg="whiteAlpha.100"
|
||||
filter="blur(8px)"
|
||||
bg="cyan.500"
|
||||
opacity={0.15}
|
||||
filter="blur(15px)"
|
||||
/>
|
||||
|
||||
<VStack align="start" spacing={3} position="relative" w="full">
|
||||
<Flex justify="space-between" align="center" w="full">
|
||||
<HStack spacing={2}>
|
||||
<Box p={2} bg="whiteAlpha.200" borderRadius="lg">
|
||||
<Icon as={FaChartLine} color="white" boxSize={4} />
|
||||
<Box p={2} bg="whiteAlpha.100" borderRadius="lg" border="1px solid" borderColor="cyan.500">
|
||||
<Icon as={FaChartLine} color="cyan.400" boxSize={4} />
|
||||
</Box>
|
||||
<VStack align="start" spacing={0}>
|
||||
<Heading size="sm" color="white" fontWeight="bold">
|
||||
@@ -868,8 +874,8 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
</VStack>
|
||||
</Box>
|
||||
|
||||
{/* 主内容卡片 */}
|
||||
<Box bg={bg} borderRadius="xl" border="1px" borderColor={borderColor} shadow="sm" overflow="hidden">
|
||||
{/* 主内容卡片 - 深色玻璃态 */}
|
||||
<Box bg={bg} backdropFilter="blur(20px)" borderRadius="xl" border="1px" borderColor={borderColor} overflow="hidden">
|
||||
<Tabs
|
||||
index={activeTab}
|
||||
onChange={(index) => {
|
||||
@@ -882,7 +888,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
size="sm"
|
||||
>
|
||||
<TabList
|
||||
bg="gray.50"
|
||||
bg="rgba(15, 23, 42, 0.6)"
|
||||
borderBottom="1px"
|
||||
borderColor={borderColor}
|
||||
overflowX="auto"
|
||||
@@ -902,6 +908,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
px={3}
|
||||
py={3}
|
||||
whiteSpace="nowrap"
|
||||
color="whiteAlpha.700"
|
||||
_selected={{
|
||||
bg: `${tab.color}.500`,
|
||||
color: 'white',
|
||||
@@ -917,7 +924,7 @@ const ConceptStatsPanel = ({ apiBaseUrl, onConceptClick }) => {
|
||||
bg: `${tab.color}.500`,
|
||||
}
|
||||
}}
|
||||
_hover={{ bg: `${tab.color}.50` }}
|
||||
_hover={{ bg: 'whiteAlpha.100', color: 'white' }}
|
||||
transition="all 0.2s"
|
||||
>
|
||||
<HStack spacing={1}>
|
||||
|
||||
Reference in New Issue
Block a user