187 lines
4.7 KiB
TypeScript
187 lines
4.7 KiB
TypeScript
import React, { useState, useEffect, useRef } from 'react';
|
||
import { Swiper, SwiperSlide } from 'swiper/react';
|
||
import { EffectCoverflow, Pagination, Autoplay, Navigation } from 'swiper/modules';
|
||
|
||
// 导入 Swiper 样式
|
||
import 'swiper/css';
|
||
import 'swiper/css/effect-coverflow';
|
||
import 'swiper/css/pagination';
|
||
import 'swiper/css/navigation';
|
||
|
||
// 模拟数据接口
|
||
interface Article {
|
||
id: number;
|
||
cover: string;
|
||
title: string;
|
||
relative_link: string;
|
||
}
|
||
|
||
interface OptionPage {
|
||
model_bg: {
|
||
url: string;
|
||
};
|
||
}
|
||
|
||
const CulturePage: React.FC = () => {
|
||
const [posts, setPosts] = useState<Article[]>([]);
|
||
const [isPostsFetching, setIsPostsFetching] = useState(true);
|
||
const [optionPage, setOptionPage] = useState<OptionPage | null>(null);
|
||
const [displayItems, setDisplayItems] = useState<Article[]>([]);
|
||
|
||
// 模拟数据获取
|
||
useEffect(() => {
|
||
// 模拟异步数据加载
|
||
const fetchData = async () => {
|
||
setIsPostsFetching(true);
|
||
|
||
// 模拟API延迟
|
||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||
|
||
// 模拟获取文章数据
|
||
const mockPosts: Article[] = [
|
||
{
|
||
id: 1,
|
||
cover: '/x4.png',
|
||
title: '烽火文化活动1',
|
||
relative_link: '/culture/1',
|
||
},
|
||
{
|
||
id: 2,
|
||
cover: '/x4.png',
|
||
title: '烽火文化活动2',
|
||
relative_link: '/culture/2',
|
||
},
|
||
{
|
||
id: 3,
|
||
cover: '/x4.png',
|
||
title: '烽火文化活动3',
|
||
relative_link: '/culture/3',
|
||
},
|
||
{
|
||
id: 4,
|
||
cover: '/x4.png',
|
||
title: '烽火文化活动4',
|
||
relative_link: '/culture/4',
|
||
},
|
||
{
|
||
id: 5,
|
||
cover: '/x4.png',
|
||
title: '烽火文化活动5',
|
||
relative_link: '/culture/5',
|
||
},
|
||
];
|
||
|
||
// 模拟选项页面数据
|
||
const mockOptionPage: OptionPage = {
|
||
model_bg: {
|
||
url: '/culture-bg.jpg',
|
||
},
|
||
};
|
||
|
||
setPosts(mockPosts);
|
||
setOptionPage(mockOptionPage);
|
||
setIsPostsFetching(false);
|
||
};
|
||
|
||
fetchData();
|
||
}, []);
|
||
|
||
// 监听posts变化,过滤有封面的文章
|
||
useEffect(() => {
|
||
if (posts.length > 0) {
|
||
const filteredItems = posts.filter((post: Article) => post.cover);
|
||
setDisplayItems(filteredItems);
|
||
}
|
||
}, [posts]);
|
||
|
||
// 空状态组件
|
||
const EmptyState = () => (
|
||
<div className="bg-white p-6 rounded-xl h-full flex items-center justify-center">
|
||
<div className="text-center text-gray-400">
|
||
<div className="text-6xl mb-4">📝</div>
|
||
<p className="text-lg">期待您的投稿!</p>
|
||
</div>
|
||
</div>
|
||
);
|
||
|
||
return (
|
||
<>
|
||
<div className="h-[80px] w-[1514px] mt-10 flex mx-auto relative">
|
||
<h1 className="pt-12 text-4xl font-bold absolute right-15 text-white italic">烽火文化</h1>
|
||
</div>
|
||
<div className="h-[610px] w-[1920px] mt-5 mx-auto relative">
|
||
{/* 加载状态 */}
|
||
{isPostsFetching && (
|
||
<div className="absolute inset-0 flex items-center justify-center rounded-xl">
|
||
<div className="text-center">
|
||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500 mx-auto mb-4"></div>
|
||
<p className="text-gray-600">加载中...</p>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* 空状态 */}
|
||
{!isPostsFetching && displayItems.length === 0 && <EmptyState />}
|
||
|
||
{/* 轮播图 */}
|
||
{!isPostsFetching && displayItems.length > 0 && (
|
||
<div
|
||
className="flex justify-center rounded items-center w-full py-5 h-full"
|
||
style={{
|
||
backgroundImage: optionPage?.model_bg.url ? `url(${optionPage.model_bg.url})` : 'none',
|
||
backgroundSize: 'cover',
|
||
backgroundPosition: 'center',
|
||
backgroundRepeat: 'no-repeat',
|
||
}}
|
||
>
|
||
<Swiper
|
||
effect="coverflow"
|
||
grabCursor={true}
|
||
centeredSlides={true}
|
||
slidesPerView={4}
|
||
spaceBetween={100}
|
||
loop={true}
|
||
coverflowEffect={{
|
||
rotate: 0,
|
||
stretch: 0,
|
||
depth: 100,
|
||
modifier: 1,
|
||
slideShadows: false,
|
||
}}
|
||
autoplay={{
|
||
delay: 3000,
|
||
disableOnInteraction: false,
|
||
}}
|
||
modules={[EffectCoverflow, Pagination, Autoplay, Navigation]}
|
||
className="mySwiper w-full h-full bg-cover bg-center "
|
||
>
|
||
{displayItems.map((item) => (
|
||
<SwiperSlide key={item.id}>
|
||
<a
|
||
href={item.relative_link}
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
className="block transition-transform duration-300 hover:scale-105 "
|
||
>
|
||
<img
|
||
className="ml-15 mx-auto object-fill select-none "
|
||
style={{ width: '395px', height: '515px' }}
|
||
src={item.cover}
|
||
alt={item.title}
|
||
onError={(e) => {
|
||
e.currentTarget.src = '/placeholder-image.jpg'; // 备用图片
|
||
}}
|
||
/>
|
||
</a>
|
||
</SwiperSlide>
|
||
))}
|
||
</Swiper>
|
||
</div>
|
||
)}
|
||
</div>
|
||
</>
|
||
);
|
||
};
|
||
|
||
export default CulturePage;
|