This commit is contained in:
2026-02-13 23:45:48 +08:00
parent 286306e11c
commit 6824c7248b

View File

@@ -1,13 +1,15 @@
import React from 'react';
import React, { useState } from 'react';
import { motion } from 'framer-motion';
import { CalendarOutlined, RightOutlined } from '@ant-design/icons';
import { CalendarOutlined } from '@ant-design/icons';
import { useNavigate } from 'react-router-dom';
import styles from './activity.module.less';
import { hoverScale, imageFadeIn } from '../../animation';
import { hoverScale } from '../../animation';
const ActivityCard = ({ activity, index }) => {
const ActivityCard = ({ activity }) => {
const navigate = useNavigate();
const [isLoaded, setIsLoaded] = useState(false);
const [hasError, setHasError] = useState(false);
const handleCardClick = () => {
navigate(`/activity/${activity.id}`);
@@ -17,7 +19,6 @@ const ActivityCard = ({ activity, index }) => {
const now = new Date();
const start = new Date(startTime);
if (now < start) return '即将开始';
// Simple logic, can be enhanced
return '报名中';
};
@@ -27,6 +28,10 @@ const ActivityCard = ({ activity, index }) => {
return date.toLocaleDateString('zh-CN', { month: 'long', day: 'numeric' });
};
const imgSrc = hasError
? 'https://via.placeholder.com/600x400?text=No+Image'
: (activity.display_banner_url || activity.banner_url || activity.cover_image || 'https://via.placeholder.com/600x400');
return (
<motion.div
className={styles.activityCard}
@@ -37,13 +42,31 @@ const ActivityCard = ({ activity, index }) => {
style={{ willChange: 'transform' }}
>
<div className={styles.imageContainer}>
{/* Placeholder / Skeleton Background */}
<div
style={{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
backgroundColor: '#f0f0f0',
opacity: isLoaded ? 0 : 1,
transition: 'opacity 0.5s ease'
}}
/>
<motion.img
src={activity.display_banner_url || activity.banner_url || activity.cover_image || 'https://via.placeholder.com/600x400'}
src={imgSrc}
alt={activity.title}
variants={imageFadeIn}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
initial={{ opacity: 0 }}
animate={{ opacity: isLoaded ? 1 : 0 }}
transition={{ duration: 0.5 }}
onLoad={() => setIsLoaded(true)}
onError={() => {
setHasError(true);
setIsLoaded(true); // Show placeholder image
}}
loading="lazy"
/>
<div className={styles.overlay}>