feat: 创建纵向模式的横向卡片组件

This commit is contained in:
zdl
2025-11-05 08:26:05 +08:00
parent c51d3811e5
commit e0cfa6fab2

View File

@@ -0,0 +1,204 @@
// src/views/Community/components/EventCard/HorizontalDynamicNewsEventCard.js
// 横向布局的动态新闻事件卡片组件(时间在左,卡片在右)
import React from 'react';
import {
HStack,
Card,
CardBody,
VStack,
Box,
Text,
Popover,
PopoverTrigger,
PopoverContent,
PopoverBody,
PopoverArrow,
Portal,
useColorModeValue,
} from '@chakra-ui/react';
import { getImportanceConfig, getAllImportanceLevels } from '../../../../constants/importanceLevels';
// 导入子组件
import EventTimeline from './EventTimeline';
import EventFollowButton from './EventFollowButton';
import StockChangeIndicators from '../../../../components/StockChangeIndicators';
/**
* 横向布局的动态新闻事件卡片组件
* @param {Object} props
* @param {Object} props.event - 事件对象
* @param {number} props.index - 事件索引
* @param {boolean} props.isFollowing - 是否已关注
* @param {number} props.followerCount - 关注数
* @param {boolean} props.isSelected - 是否被选中
* @param {Function} props.onEventClick - 卡片点击事件
* @param {Function} props.onTitleClick - 标题点击事件
* @param {Function} props.onToggleFollow - 切换关注事件
* @param {Object} props.timelineStyle - 时间轴样式配置
* @param {string} props.borderColor - 边框颜色
*/
const HorizontalDynamicNewsEventCard = ({
event,
index,
isFollowing,
followerCount,
isSelected = false,
onEventClick,
onTitleClick,
onToggleFollow,
timelineStyle,
borderColor,
}) => {
const importance = getImportanceConfig(event.importance);
const cardBg = useColorModeValue('white', 'gray.800');
const linkColor = useColorModeValue('blue.600', 'blue.400');
return (
<HStack align="stretch" spacing={3} w="full">
{/* 左侧时间轴 */}
<EventTimeline
createdAt={event.created_at}
timelineStyle={timelineStyle}
borderColor={borderColor}
minHeight="60px"
/>
{/* 右侧事件卡片 */}
<Card
flex="1"
position="relative"
bg={isSelected
? useColorModeValue('blue.50', 'blue.900')
: (index % 2 === 0 ? cardBg : useColorModeValue('gray.50', 'gray.750'))
}
borderWidth={isSelected ? "2px" : "1px"}
borderColor={isSelected
? useColorModeValue('blue.500', 'blue.400')
: borderColor
}
borderRadius="md"
boxShadow={isSelected ? "lg" : "sm"}
overflow="hidden"
_hover={{
boxShadow: 'xl',
transform: 'translateY(-2px)',
borderColor: isSelected ? 'blue.600' : importance.color,
}}
transition="all 0.3s ease"
cursor="pointer"
onClick={() => onEventClick?.(event)}
>
<CardBody p={3}>
{/* 左上角:重要性矩形角标(镂空边框样式) */}
<Popover trigger="hover" placement="right" isLazy>
<PopoverTrigger>
<Box
position="absolute"
top={0}
left={0}
zIndex={1}
bg="transparent"
color={importance.badgeBg}
borderWidth="2px"
borderColor={importance.badgeBg}
fontSize="11px"
fontWeight="bold"
px={1.5}
py={0.5}
minW="auto"
display="flex"
alignItems="center"
justifyContent="center"
lineHeight="1"
borderBottomRightRadius="md"
cursor="help"
>
{importance.label}
</Box>
</PopoverTrigger>
<Portal>
<PopoverContent width="auto" maxW="350px">
<PopoverArrow />
<PopoverBody p={3}>
<VStack align="stretch" spacing={2}>
<Text fontSize="sm" fontWeight="bold" mb={1}>
重要性等级说明
</Text>
{getAllImportanceLevels().map(item => (
<HStack key={item.level} spacing={2} align="flex-start">
<Box
w="20px"
h="20px"
borderWidth="2px"
borderColor={item.badgeBg}
color={item.badgeBg}
fontSize="9px"
fontWeight="bold"
display="flex"
alignItems="center"
justifyContent="center"
borderRadius="sm"
flexShrink={0}
>
{item.level}
</Box>
<Text fontSize="xs" flex={1}>
<Text as="span" fontWeight="bold">
{item.label}
</Text>
{item.description}
</Text>
</HStack>
))}
</VStack>
</PopoverBody>
</PopoverContent>
</Portal>
</Popover>
{/* 右上角:关注按钮 */}
<Box position="absolute" top={2} right={2} zIndex={1}>
<EventFollowButton
isFollowing={isFollowing}
followerCount={followerCount}
onToggle={() => onToggleFollow?.(event.id)}
size="xs"
showCount={false}
/>
</Box>
<VStack align="stretch" spacing={2}>
{/* 标题 - 最多两行,添加上边距避免与角标重叠 */}
<Box
cursor="pointer"
onClick={(e) => onTitleClick?.(e, event)}
mt={1}
paddingRight="10px"
>
<Text
fontSize="md"
fontWeight="semibold"
color={linkColor}
lineHeight="1.4"
noOfLines={2}
_hover={{ textDecoration: 'underline' }}
>
{event.title}
</Text>
</Box>
{/* 第二行:涨跌幅数据 */}
<StockChangeIndicators
avgChange={event.related_avg_chg}
maxChange={event.related_max_chg}
weekChange={event.related_week_chg}
/>
</VStack>
</CardBody>
</Card>
</HStack>
);
};
export default HorizontalDynamicNewsEventCard;