fenghuo/apps/web/components/content/jcdt/fhwh/culture.tsx

187 lines
4.7 KiB
TypeScript
Raw Normal View History

2025-06-16 23:16:59 +08:00
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;