Initial commit
This commit is contained in:
368
src/views/EventDetail/components/EventHeader.js
Normal file
368
src/views/EventDetail/components/EventHeader.js
Normal file
@@ -0,0 +1,368 @@
|
||||
// src/views/EventDetail/components/EventHeader.js - 改进的事件头部信息组件
|
||||
|
||||
import React from 'react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
HStack,
|
||||
VStack,
|
||||
Text,
|
||||
Button,
|
||||
Badge,
|
||||
Avatar,
|
||||
Icon,
|
||||
Tag,
|
||||
TagLabel,
|
||||
Wrap,
|
||||
WrapItem,
|
||||
useColorModeValue,
|
||||
Divider,
|
||||
SimpleGrid,
|
||||
Stat,
|
||||
StatLabel,
|
||||
StatNumber,
|
||||
StatHelpText,
|
||||
StatArrow
|
||||
} from '@chakra-ui/react';
|
||||
import {
|
||||
FaHeart,
|
||||
FaRegHeart,
|
||||
FaEye,
|
||||
FaComment,
|
||||
FaUsers,
|
||||
FaClock,
|
||||
FaCalendarAlt,
|
||||
FaChartLine
|
||||
} from 'react-icons/fa';
|
||||
|
||||
const EventHeader = ({ event, onFollowToggle }) => {
|
||||
// 颜色主题
|
||||
const bgGradient = useColorModeValue(
|
||||
'linear(to-r, blue.50, purple.50)',
|
||||
'linear(to-r, blue.900, purple.900)'
|
||||
);
|
||||
const textPrimary = useColorModeValue('gray.800', 'white');
|
||||
const textSecondary = useColorModeValue('gray.600', 'gray.300');
|
||||
const borderColor = useColorModeValue('gray.200', 'gray.600');
|
||||
const statBg = useColorModeValue('white', 'gray.700');
|
||||
|
||||
// 格式化日期
|
||||
const formatDate = (dateString) => {
|
||||
if (!dateString) return '--';
|
||||
return new Date(dateString).toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: '2-digit',
|
||||
day: '2-digit',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
});
|
||||
};
|
||||
|
||||
// 格式化数字
|
||||
const formatNumber = (num) => {
|
||||
if (!num && num !== 0) return '0';
|
||||
if (num >= 10000) {
|
||||
return (num / 10000).toFixed(1) + 'w';
|
||||
} else if (num >= 1000) {
|
||||
return (num / 1000).toFixed(1) + 'k';
|
||||
}
|
||||
return num.toString();
|
||||
};
|
||||
|
||||
// 获取超预期分数颜色
|
||||
const getScoreColor = (score) => {
|
||||
if (score >= 80) return 'red';
|
||||
if (score >= 60) return 'orange';
|
||||
if (score >= 40) return 'yellow';
|
||||
return 'green';
|
||||
};
|
||||
|
||||
if (!event) {
|
||||
return <Box>加载中...</Box>;
|
||||
}
|
||||
|
||||
return (
|
||||
<Box>
|
||||
{/* 主要信息区域 */}
|
||||
<Box
|
||||
bgGradient={bgGradient}
|
||||
borderRadius="xl"
|
||||
p={6}
|
||||
mb={6}
|
||||
position="relative"
|
||||
overflow="hidden"
|
||||
>
|
||||
{/* 装饰性背景图案 */}
|
||||
<Box
|
||||
position="absolute"
|
||||
top="-50px"
|
||||
right="-50px"
|
||||
width="200px"
|
||||
height="200px"
|
||||
bg="whiteAlpha.100"
|
||||
borderRadius="full"
|
||||
opacity={0.3}
|
||||
/>
|
||||
|
||||
<Flex direction={{ base: 'column', lg: 'row' }} gap={6} position="relative">
|
||||
{/* 左侧内容 */}
|
||||
<VStack align="flex-start" spacing={4} flex="1">
|
||||
{/* 事件类型和状态 */}
|
||||
<HStack spacing={3} flexWrap="wrap">
|
||||
<Badge
|
||||
colorScheme="blue"
|
||||
size="lg"
|
||||
px={4}
|
||||
py={2}
|
||||
borderRadius="full"
|
||||
fontSize="sm"
|
||||
fontWeight="bold"
|
||||
>
|
||||
{event.event_type || '未分类'}
|
||||
</Badge>
|
||||
<Badge
|
||||
colorScheme={event.status === 'active' ? 'green' : 'gray'}
|
||||
size="lg"
|
||||
px={4}
|
||||
py={2}
|
||||
borderRadius="full"
|
||||
fontSize="sm"
|
||||
>
|
||||
{event.status === 'active' ? '进行中' : '已结束'}
|
||||
</Badge>
|
||||
{event.expectation_surprise_score && (
|
||||
<Badge
|
||||
colorScheme={getScoreColor(event.expectation_surprise_score)}
|
||||
size="lg"
|
||||
px={4}
|
||||
py={2}
|
||||
borderRadius="full"
|
||||
fontSize="sm"
|
||||
fontWeight="bold"
|
||||
>
|
||||
超预期: {event.expectation_surprise_score}分
|
||||
</Badge>
|
||||
)}
|
||||
</HStack>
|
||||
|
||||
{/* 事件标题 */}
|
||||
<Text
|
||||
fontSize={{ base: '2xl', md: '3xl' }}
|
||||
fontWeight="bold"
|
||||
lineHeight="1.2"
|
||||
color={textPrimary}
|
||||
>
|
||||
{event.title}
|
||||
</Text>
|
||||
|
||||
{/* 创建者和时间信息 */}
|
||||
<HStack spacing={6} flexWrap="wrap">
|
||||
<HStack spacing={3}>
|
||||
<Avatar
|
||||
size="sm"
|
||||
src={event.creator?.avatar_url}
|
||||
name={event.creator?.username || '未知用户'}
|
||||
/>
|
||||
<VStack align="flex-start" spacing={0}>
|
||||
<Text fontWeight="medium" fontSize="sm" color={textPrimary}>
|
||||
{event.creator?.username || '系统'}
|
||||
</Text>
|
||||
<Text fontSize="xs" color={textSecondary}>
|
||||
创建者
|
||||
</Text>
|
||||
</VStack>
|
||||
</HStack>
|
||||
|
||||
<HStack spacing={3}>
|
||||
<Icon as={FaCalendarAlt} color={textSecondary} />
|
||||
<VStack align="flex-start" spacing={0}>
|
||||
<Text fontSize="sm" color={textPrimary}>
|
||||
{formatDate(event.created_at)}
|
||||
</Text>
|
||||
<Text fontSize="xs" color={textSecondary}>
|
||||
发布时间
|
||||
</Text>
|
||||
</VStack>
|
||||
</HStack>
|
||||
</HStack>
|
||||
</VStack>
|
||||
|
||||
{/* 右侧关注按钮 */}
|
||||
<Flex align="flex-start" justify="center">
|
||||
<Button
|
||||
leftIcon={<Icon as={event.is_following ? FaHeart : FaRegHeart} />}
|
||||
colorScheme={event.is_following ? "red" : "blue"}
|
||||
variant={event.is_following ? "solid" : "outline"}
|
||||
size="lg"
|
||||
onClick={onFollowToggle}
|
||||
borderRadius="full"
|
||||
px={8}
|
||||
py={6}
|
||||
fontSize="md"
|
||||
fontWeight="bold"
|
||||
bg={event.is_following ? undefined : 'white'}
|
||||
_hover={{
|
||||
transform: 'translateY(-2px)',
|
||||
shadow: 'lg'
|
||||
}}
|
||||
transition="all 0.2s"
|
||||
>
|
||||
{event.is_following ? '已关注' : '关注事件'}
|
||||
</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
</Box>
|
||||
|
||||
{/* 统计数据卡片 */}
|
||||
<SimpleGrid columns={{ base: 2, md: 4 }} spacing={4} mb={6}>
|
||||
<Stat
|
||||
px={4}
|
||||
py={3}
|
||||
bg={statBg}
|
||||
borderRadius="lg"
|
||||
border="1px solid"
|
||||
borderColor={borderColor}
|
||||
textAlign="center"
|
||||
>
|
||||
<StatLabel fontSize="xs" color={textSecondary}>
|
||||
<HStack justify="center" spacing={1}>
|
||||
<Icon as={FaEye} />
|
||||
<Text>浏览量</Text>
|
||||
</HStack>
|
||||
</StatLabel>
|
||||
<StatNumber fontSize="lg" color={textPrimary}>
|
||||
{formatNumber(event.view_count)}
|
||||
</StatNumber>
|
||||
</Stat>
|
||||
|
||||
<Stat
|
||||
px={4}
|
||||
py={3}
|
||||
bg={statBg}
|
||||
borderRadius="lg"
|
||||
border="1px solid"
|
||||
borderColor={borderColor}
|
||||
textAlign="center"
|
||||
>
|
||||
<StatLabel fontSize="xs" color={textSecondary}>
|
||||
<HStack justify="center" spacing={1}>
|
||||
<Icon as={FaComment} />
|
||||
<Text>回复数</Text>
|
||||
</HStack>
|
||||
</StatLabel>
|
||||
<StatNumber fontSize="lg" color={textPrimary}>
|
||||
{formatNumber(event.post_count)}
|
||||
</StatNumber>
|
||||
</Stat>
|
||||
|
||||
<Stat
|
||||
px={4}
|
||||
py={3}
|
||||
bg={statBg}
|
||||
borderRadius="lg"
|
||||
border="1px solid"
|
||||
borderColor={borderColor}
|
||||
textAlign="center"
|
||||
>
|
||||
<StatLabel fontSize="xs" color={textSecondary}>
|
||||
<HStack justify="center" spacing={1}>
|
||||
<Icon as={FaUsers} />
|
||||
<Text>关注数</Text>
|
||||
</HStack>
|
||||
</StatLabel>
|
||||
<StatNumber fontSize="lg" color={textPrimary}>
|
||||
{formatNumber(event.follower_count)}
|
||||
</StatNumber>
|
||||
</Stat>
|
||||
|
||||
<Stat
|
||||
px={4}
|
||||
py={3}
|
||||
bg={statBg}
|
||||
borderRadius="lg"
|
||||
border="1px solid"
|
||||
borderColor={borderColor}
|
||||
textAlign="center"
|
||||
>
|
||||
<StatLabel fontSize="xs" color={textSecondary}>
|
||||
<HStack justify="center" spacing={1}>
|
||||
<Icon as={FaChartLine} />
|
||||
<Text>热度分</Text>
|
||||
</HStack>
|
||||
</StatLabel>
|
||||
<StatNumber fontSize="lg" color={textPrimary}>
|
||||
{event.hot_score ? event.hot_score.toFixed(1) : '0.0'}
|
||||
</StatNumber>
|
||||
</Stat>
|
||||
</SimpleGrid>
|
||||
|
||||
{/* 事件描述 */}
|
||||
{event.description && (
|
||||
<Box mb={6}>
|
||||
<Text fontSize="md" fontWeight="bold" mb={3} color={textPrimary}>
|
||||
事件描述
|
||||
</Text>
|
||||
<Box
|
||||
p={4}
|
||||
bg={useColorModeValue('gray.50', 'gray.700')}
|
||||
borderRadius="lg"
|
||||
borderLeft="4px solid"
|
||||
borderLeftColor="blue.500"
|
||||
>
|
||||
<Box
|
||||
dangerouslySetInnerHTML={{ __html: event.description }}
|
||||
sx={{
|
||||
'& p': { mb: 2, lineHeight: '1.6' },
|
||||
'& p:last-child': { mb: 0 },
|
||||
'& h1, & h2, & h3, & h4, & h5, & h6': {
|
||||
fontWeight: 'bold',
|
||||
mb: 2,
|
||||
color: textPrimary
|
||||
},
|
||||
'& ul, & ol': {
|
||||
pl: 4,
|
||||
mb: 2
|
||||
},
|
||||
'& li': {
|
||||
mb: 1
|
||||
},
|
||||
color: textSecondary
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* 相关标签 */}
|
||||
{event.keywords_list && event.keywords_list.length > 0 && (
|
||||
<Box>
|
||||
<Text fontSize="md" fontWeight="bold" mb={3} color={textPrimary}>
|
||||
相关标签
|
||||
</Text>
|
||||
<Wrap spacing={2}>
|
||||
{event.keywords_list.map((tag, index) => (
|
||||
<WrapItem key={index}>
|
||||
<Tag
|
||||
size="md"
|
||||
variant="subtle"
|
||||
colorScheme="blue"
|
||||
cursor="pointer"
|
||||
borderRadius="full"
|
||||
_hover={{
|
||||
bg: useColorModeValue('blue.100', 'blue.700'),
|
||||
transform: 'translateY(-1px)'
|
||||
}}
|
||||
transition="all 0.2s"
|
||||
>
|
||||
<TagLabel px={2}>{tag}</TagLabel>
|
||||
</Tag>
|
||||
</WrapItem>
|
||||
))}
|
||||
</Wrap>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
export default EventHeader;
|
||||
Reference in New Issue
Block a user