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