Files
vf_react/src/views/Community/components/HotEvents.js
2025-10-27 17:22:03 +08:00

180 lines
6.8 KiB
JavaScript

// src/views/Community/components/HotEvents.js
import React, { useState } from 'react';
import { Card, Badge, Tag, Empty, Carousel, Tooltip } from 'antd';
import { ArrowUpOutlined, ArrowDownOutlined, LeftOutlined, RightOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
import moment from 'moment';
import './HotEvents.css';
import defaultEventImage from '../../../assets/img/default-event.jpg'
// 自定义箭头组件
const CustomArrow = ({ className, style, onClick, direction }) => {
const Icon = direction === 'left' ? LeftOutlined : RightOutlined;
return (
<div
className={`${className} custom-carousel-arrow`}
style={{
...style,
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
onClick={onClick}
>
<Icon style={{ fontSize: '20px', color: '#1890ff' }} />
</div>
);
};
const HotEvents = ({ events, onPageChange }) => {
const navigate = useNavigate();
const [currentSlide, setCurrentSlide] = useState(0);
const renderPriceChange = (value) => {
if (value === null || value === undefined) {
return <Tag color="default">--</Tag>;
}
const isPositive = value > 0;
const icon = isPositive ? <ArrowUpOutlined /> : <ArrowDownOutlined />;
const color = isPositive ? '#ff4d4f' : '#52c41a';
return (
<Tag color={color}>
{icon} {Math.abs(value).toFixed(2)}%
</Tag>
);
};
const getImportanceColor = (importance) => {
const colors = {
S: 'red',
A: 'orange',
B: 'blue',
C: 'green'
};
return colors[importance] || 'default';
};
const handleCardClick = (eventId) => {
navigate(`/event-detail/${eventId}`);
};
// 计算总页数
const totalPages = Math.ceil((events?.length || 0) / 4);
// Carousel 配置
const carouselSettings = {
dots: false, // 隐藏圆点导航
infinite: true, // 始终启用无限循环,确保箭头显示
speed: 500,
slidesToShow: 4,
slidesToScroll: 1,
arrows: true, // 保留左右箭头
prevArrow: <CustomArrow direction="left" />,
nextArrow: <CustomArrow direction="right" />,
autoplay: false,
beforeChange: (_current, next) => {
// 计算实际页码(考虑无限循环)
const actualPage = next % totalPages;
setCurrentSlide(actualPage);
// 通知父组件页码变化
if (onPageChange) {
onPageChange(actualPage + 1, totalPages);
}
},
responsive: [
{
breakpoint: 1200,
settings: {
slidesToShow: 3,
slidesToScroll: 1,
}
},
{
breakpoint: 992,
settings: {
slidesToShow: 2,
slidesToScroll: 1,
}
},
{
breakpoint: 576,
settings: {
slidesToShow: 1,
slidesToScroll: 1,
}
}
]
};
return (
<div className="hot-events-section">
{events && events.length > 0 ? (
<Carousel {...carouselSettings} className="hot-events-carousel">
{events.map((event, index) => (
<div key={event.id} className="carousel-item">
<Card
hoverable
className="hot-event-card"
onClick={() => handleCardClick(event.id)}
cover={
<div className="event-cover">
<img
alt={event.title}
src={`/images/events/${['first', 'second', 'third', 'fourth'][index] || 'first'}.jpg`}
onError={e => {
e.target.onerror = null;
e.target.src = defaultEventImage;
}}
/>
{event.importance && (
<Badge
className="importance-badge"
color={getImportanceColor(event.importance)}
text={`${event.importance}`}
/>
)}
</div>
}
>
{/* Custom layout without Card.Meta */}
<div className="event-header">
<Tooltip title={event.title}>
<span className="event-title">
{event.title}
</span>
</Tooltip>
<span className="event-tag">
{renderPriceChange(event.related_avg_chg)}
</span>
</div>
<Tooltip title={event.description}>
<div className="event-description">
{event.description}
</div>
</Tooltip>
<div className="event-footer">
<span className="creator">{event.creator?.username || 'Anonymous'}</span>
<span className="time">
<span className="time-date">{moment(event.created_at).format('YYYY-MM-DD')}</span>
{' '}
<span className="time-hour">{moment(event.created_at).format('HH:mm')}</span>
</span>
</div>
</Card>
</div>
))}
</Carousel>
) : (
<Card>
<Empty description="暂无热点信息" />
</Card>
)}
</div>
);
};
export default HotEvents;