- {/* Placeholder Background - Always visible behind the image */}
-
setIsLoaded(true)}
- onError={() => {
- setHasError(true);
- setIsLoaded(true);
- }}
- loading="lazy"
- />
-
-
- {activity.status || getStatus(activity.start_time)}
-
-
{activity.title}
-
-
-
{formatDate(activity.start_time)}
+
+ {
+ e.target.src = 'https://images.unsplash.com/photo-1540575467063-178a50c2df87?w=600&h=400&fit=crop';
+ }}
+ />
+
+
+ {statusText}
+
+ }
+ style={{ height: '100%', display: 'flex', flexDirection: 'column', fontSize: 16 }}
+ styles={{ body: { flex: 1, display: 'flex', flexDirection: 'column', padding: 24 } }}
+ onClick={() => navigate(`/activity/${activity.id}`)}
+ >
+
+ {activity.title}
+
+
+
+ {activity.description || activity.subtitle || ''}
-
+
+
+
+
+ {activity.start_time && (
+
+
+
+ {formatDate(activity.start_time)}
+ {activity.end_time ? ` ~ ${formatDate(activity.end_time)}` : ''}
+
+
+ )}
+ {activity.location && (
+
+
+ {activity.location}
+
+ )}
+
+
);
};
diff --git a/frontend/src/components/activity/ActivityList.jsx b/frontend/src/components/activity/ActivityList.jsx
index 3badb43..dd174bc 100644
--- a/frontend/src/components/activity/ActivityList.jsx
+++ b/frontend/src/components/activity/ActivityList.jsx
@@ -1,109 +1,76 @@
-
-import React, { useState, useEffect } from 'react';
+import React, { useState } from 'react';
+import { Row, Col, Empty, Spin, Input, Select } from 'antd';
import { useQuery } from '@tanstack/react-query';
-import { motion, AnimatePresence } from 'framer-motion';
-import { RightOutlined, LeftOutlined } from '@ant-design/icons';
import { getActivities } from '../../api';
import ActivityCard from './ActivityCard';
-import styles from './activity.module.less';
-import { fadeInUp, staggerContainer } from '../../animation';
+
+const { Search } = Input;
+const { Option } = Select;
const ActivityList = () => {
+ const [search, setSearch] = useState('');
+ const [statusFilter, setStatusFilter] = useState('all');
+
const { data: activities, isLoading, error } = useQuery({
queryKey: ['activities'],
queryFn: async () => {
const res = await getActivities();
- // Handle different response structures
return Array.isArray(res.data) ? res.data : (res.data?.results || []);
},
- staleTime: 5 * 60 * 1000, // 5 minutes cache
+ staleTime: 5 * 60 * 1000,
});
- const [currentIndex, setCurrentIndex] = useState(0);
+ const filtered = (activities || []).filter(a => {
+ const matchSearch = !search || a.title?.includes(search);
+ const matchStatus = statusFilter === 'all' || a.status === statusFilter;
+ return matchSearch && matchStatus;
+ });
- // Auto-play for desktop carousel
- useEffect(() => {
- if (!activities || activities.length <= 1) return;
- const interval = setInterval(() => {
- setCurrentIndex((prev) => (prev + 1) % activities.length);
- }, 5000);
- return () => clearInterval(interval);
- }, [activities]);
-
- const nextSlide = () => {
- if (!activities) return;
- setCurrentIndex((prev) => (prev + 1) % activities.length);
- };
-
- const prevSlide = () => {
- if (!activities) return;
- setCurrentIndex((prev) => (prev - 1 + activities.length) % activities.length);
- };
-
- if (isLoading) return
Loading activities...
;
- if (error) return null; // Or error state
- if (!activities || activities.length === 0) return null;
+ if (isLoading) return (
+
+
+
+ );
+ if (error) return
;
return (
-
-
-
- 近期活动 / EVENTS
-
-
-
-
+
+
+
+
+
+ 全部状态
+ 报名中
+ 即将开始
+ 已结束
+
- {/* Desktop: Carousel (Show one prominent, but allows list structure if needed)
- User said: "Activity only shows one, and in the form of a sliding page"
- */}
-
-
-
-
-
-
-
-
- {activities.map((_, idx) => (
- setCurrentIndex(idx)}
- />
- ))}
-
-
-
- {/* Mobile: Vertical List/Scroll as requested "Mobile vertical scroll" */}
-
- {activities.map((item, index) => (
-
-
-
- ))}
-
-
+ {filtered.length > 0 ? (
+
+ {filtered.map((activity) => (
+
+
+
+ ))}
+
+ ) : (
+
+ )}
+
);
};
diff --git a/frontend/src/pages/Home.jsx b/frontend/src/pages/Home.jsx
index 87d78c9..1dac6a0 100644
--- a/frontend/src/pages/Home.jsx
+++ b/frontend/src/pages/Home.jsx
@@ -22,18 +22,15 @@ const Home = () => {
const [loading, setLoading] = useState(false);
const [typedText, setTypedText] = useState('');
const [isTypingComplete, setIsTypingComplete] = useState(false);
- const [currentSlide, setCurrentSlide] = useState(0);
const [currentSlide2, setCurrentSlide2] = useState(0);
const [currentSlide3, setCurrentSlide3] = useState(0);
const [homeConfig, setHomeConfig] = useState(null);
- const [carousel1Items, setCarousel1Items] = useState([]);
const [competitions, setCompetitions] = useState([]);
const [activities, setActivities] = useState([]);
const fullText = "未来已来 AI 核心驱动";
const defaultMainTitle = '"创赢未来"云南2026创业大赛';
const [mainTitleText, setMainTitleText] = useState(defaultMainTitle);
const navigate = useNavigate();
- const carouselRef = useRef(null);
const carouselRef2 = useRef(null);
const carouselRef3 = useRef(null);
@@ -66,9 +63,7 @@ const Home = () => {
const fetchHomePageConfig = async () => {
try {
const response = await getHomePageConfig();
- const data = response.data;
- setHomeConfig(data);
- setCarousel1Items(data.carousel1_items || []);
+ setHomeConfig(response.data);
} catch (error) {
console.error('Failed to fetch homepage config:', error);
}
@@ -159,135 +154,6 @@ const Home = () => {
/>
- {/* 轮播图 */}
-
- {/* 轮播图主体 */}
-
-
setCurrentSlide(next)}
- >
- {(carousel1Items.length > 0 ? carousel1Items : []).map((image, index) => (
-
-
-
{
- e.target.style.display = 'none';
- }}
- />
- {/* 渐变遮罩 */}
-
- {/* 标题区域 - 图片上方 */}
-
-
- {image.title}
-
-
- {image.subtitle}
-
-
- {/* 底部信息 */}
-
-
-
- {image.status}
-
- {image.location}
-
-
-
-
{image.title}
-
- 📅 {image.date}
- 📍 {image.location}
-
-
-
navigate('/competitions')}>
- 立即报名
-
-
-
-
-
- ))}
-
-
- {/* 自定义分页指示器 */}
-
- {(carousel1Items.length > 0 ? carousel1Items : []).map((_, index) => (
-
carouselRef.current?.goTo(index)}
- style={{
- width: currentSlide === index ? 32 : 10,
- height: 10,
- borderRadius: 5,
- background: currentSlide === index ? '#fff' : 'rgba(255,255,255,0.4)',
- cursor: 'pointer',
- transition: 'all 0.3s',
- }}
- />
- ))}
-
-
-
-
{/* 赛事中心轮播图 */}
{competitions.length > 0 && (
{
>
{competitions.map((competition, index) => (
-
+
navigate(`/competitions/${competition.id}`)}
+ style={{
+ height: 600,
+ position: 'relative',
+ overflow: 'hidden',
+ background: 'linear-gradient(135deg, #1890ff 0%, #69c0ff 100%)',
+ cursor: 'pointer',
+ }}>
{
📅 {competition.start_time?.split('T')[0]} ~ {competition.end_time?.split('T')[0]}
-
navigate(`/competitions/${competition.id}`)}>
+ { e.stopPropagation(); navigate(`/competitions/${competition.id}`); }}>
查看详情
@@ -528,12 +397,15 @@ const Home = () => {
>
{activities.map((activity, index) => (
-
+
navigate(`/activity/${activity.id}`)}
+ style={{
+ height: 600,
+ position: 'relative',
+ overflow: 'hidden',
+ background: 'linear-gradient(135deg, #1890ff 0%, #69c0ff 100%)',
+ cursor: 'pointer',
+ }}>
{
{activity.location &&
📍 {activity.location} }
-
navigate('/activities')}>
+ { e.stopPropagation(); navigate(`/activity/${activity.id}`); }}>
查看详情
diff --git a/frontend/src/pages/VCCourses.jsx b/frontend/src/pages/VCCourses.jsx
index 52d1753..04cd206 100644
--- a/frontend/src/pages/VCCourses.jsx
+++ b/frontend/src/pages/VCCourses.jsx
@@ -78,7 +78,7 @@ const VCCourses = () => {
{item.duration}
{item.lesson_count} 课时
-
{item.description}
+
{item.description}
点击报名