feat: HistoricalEvents UI 布局优化

- 从网格布局(SimpleGrid 3列)改为单列纵向布局(VStack)
- 卡片样式优化:添加顶部渐变条装饰(蓝-紫-粉渐变)
- 卡片内部从垂直布局改为横向布局(HStack)
- 优化间距和边距,提升视觉层次感
- 调整卡片padding和borderRadius

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
zdl
2025-11-07 19:46:56 +08:00
parent 4979293320
commit 52c3e25218

View File

@@ -31,6 +31,7 @@ import {
} from 'react-icons/fa'; } from 'react-icons/fa';
import { stockService } from '../../../services/eventService'; import { stockService } from '../../../services/eventService';
import { logger } from '../../../utils/logger'; import { logger } from '../../../utils/logger';
import CitedContent from '../../../components/Citation/CitedContent';
const HistoricalEvents = ({ const HistoricalEvents = ({
events = [], events = [],
@@ -224,8 +225,8 @@ const HistoricalEvents = ({
</Box> </Box>
)} )}
{/* 历史事件卡片网格 */} {/* 历史事件卡片列表 - 混合布局 */}
<SimpleGrid columns={{ base: 1, md: 2, lg: 3 }} spacing={4}> <VStack spacing={3} align="stretch">
{events.map((event) => { {events.map((event) => {
const importanceColor = getImportanceColor(event.importance); const importanceColor = getImportanceColor(event.importance);
@@ -235,92 +236,126 @@ const HistoricalEvents = ({
bg={cardBg} bg={cardBg}
borderWidth="1px" borderWidth="1px"
borderColor={borderColor} borderColor={borderColor}
borderRadius="md" borderRadius="lg"
p={4} position="relative"
overflow="visible"
cursor="pointer" cursor="pointer"
onClick={() => handleCardClick(event)} onClick={() => handleCardClick(event)}
_before={{
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: '3px',
bgGradient: 'linear(to-r, blue.400, purple.500, pink.500)',
borderTopLeftRadius: 'lg',
borderTopRightRadius: 'lg',
}}
_hover={{ _hover={{
boxShadow: 'lg', boxShadow: 'lg',
borderColor: 'blue.400', borderColor: 'blue.400',
transform: 'translateY(-2px)',
}} }}
transition="all 0.2s" transition="all 0.2s"
> >
<VStack align="stretch" spacing={3}> <VStack align="stretch" spacing={2} p={3}>
{/* 事件名称 */} {/* 顶部区域:左侧(标题+时间) + 右侧(按钮) */}
<Text <HStack align="flex-start" spacing={3}>
fontSize="md" {/* 左侧:标题 + 时间信息(允许折行) */}
fontWeight="bold" <VStack flex="1" align="flex-start" spacing={1}>
color={useColorModeValue('blue.600', 'blue.400')} {/* 标题 */}
noOfLines={2} <Text
lineHeight="1.4" fontSize="md"
cursor="pointer" fontWeight="bold"
onClick={(e) => { color={useColorModeValue('blue.600', 'blue.400')}
e.stopPropagation(); lineHeight="1.4"
handleCardClick(event); cursor="pointer"
}} onClick={(e) => {
_hover={{ textDecoration: 'underline' }} e.stopPropagation();
> handleCardClick(event);
{event.title || '未命名事件'} }}
</Text> _hover={{ textDecoration: 'underline' }}
{/* 日期 + Badges */}
<HStack spacing={2} flexWrap="wrap">
<Text fontSize="sm" color={textSecondary}>
{formatDate(getEventDate(event))}
</Text>
<Text fontSize="sm" color={textSecondary}>
({getRelativeTime(getEventDate(event))})
</Text>
{event.relevance && (
<Badge colorScheme="blue" size="sm">
相关度: {event.relevance}
</Badge>
)}
{event.importance && (
<Badge colorScheme={importanceColor} size="sm">
重要性: {event.importance}
</Badge>
)}
{event.avg_change_pct !== undefined && event.avg_change_pct !== null && (
<Badge
colorScheme={event.avg_change_pct > 0 ? 'red' : event.avg_change_pct < 0 ? 'green' : 'gray'}
size="sm"
> >
涨幅: {event.avg_change_pct > 0 ? '+' : ''}{event.avg_change_pct.toFixed(2)}% {event.title || '未命名事件'}
</Badge> </Text>
)}
{/* 时间 + Badges允许折行 */}
<HStack spacing={2} flexWrap="wrap">
<Text fontSize="sm" color={textSecondary}>
{formatDate(getEventDate(event))}
</Text>
<Text fontSize="sm" color={textSecondary}>
({getRelativeTime(getEventDate(event))})
</Text>
{event.importance && (
<Badge colorScheme={importanceColor} size="sm">
重要性: {event.importance}
</Badge>
)}
{event.avg_change_pct !== undefined && event.avg_change_pct !== null && (
<Badge
colorScheme={event.avg_change_pct > 0 ? 'red' : event.avg_change_pct < 0 ? 'green' : 'gray'}
size="sm"
>
涨幅: {event.avg_change_pct > 0 ? '+' : ''}{event.avg_change_pct.toFixed(2)}%
</Badge>
)}
</HStack>
</VStack>
{/* 右侧:相关股票按钮 */}
<Button
size="sm"
leftIcon={<Icon as={FaChartLine} />}
onClick={(e) => {
e.stopPropagation();
handleViewStocks(event);
}}
colorScheme="blue"
variant="outline"
flexShrink={0}
>
相关股票
</Button>
</HStack> </HStack>
{/* 事件描述 */} {/* 底部:描述(独占整行)- 升级和降级处理 */}
<Text <Box>
fontSize="sm" {(() => {
color={nameColor} const content = getEventContent(event);
lineHeight="1.6" // 检查是否有 data 结构(升级版本)
noOfLines={4} if (content && typeof content === 'object' && content.data) {
> return (
{getEventContent(event) ? `${getEventContent(event)}AI合成` : '暂无内容'} <CitedContent
</Text> data={content}
title=""
{/* 相关股票按钮 */} showAIBadge={true}
<Button containerStyle={{
size="sm" backgroundColor: useColorModeValue('#f7fafc', 'rgba(45, 55, 72, 0.6)'),
leftIcon={<Icon as={FaChartLine} />} borderRadius: '8px',
onClick={(e) => { padding: '0',
e.stopPropagation(); }}
handleViewStocks(event); />
}} );
colorScheme="blue" }
variant="outline" // 降级版本:纯文本
width="full" return (
> <Text
相关股票 fontSize="sm"
</Button> color={nameColor}
lineHeight="1.6"
noOfLines={2}
>
{content ? `${content}AI合成` : '暂无内容'}
</Text>
);
})()}
</Box>
</VStack> </VStack>
</Box> </Box>
); );
})} })}
</SimpleGrid> </VStack>
{/* 相关股票 Modal - 条件渲染 */} {/* 相关股票 Modal - 条件渲染 */}
{stocksModalOpen && ( {stocksModalOpen && (