"use client"; import { useState, useEffect } from "react"; import { Swiper, SwiperSlide } from "swiper/react"; import { Navigation, Pagination, Grid } from "swiper/modules"; import Link from "next/link"; import Image from "next/image"; import PropTypes from "prop-types"; // This is now a "dumb" component. It receives all data via props and is only // responsible for rendering the UI. All data fetching logic has been moved // to the parent server component. export default function SwiperItemsUI({ data, items, ...props }) { const [isMounted, setIsMounted] = useState(false); useEffect(() => { // This effect runs only on the client, after the component has mounted. setIsMounted(true); }, []); // Field mapping from data, with props as fallback. const title = data?.title || props.title; const subtitle = data?.subtitle || props.subtitle; const category_slug = data?.t3 || props.category_slug || ""; const columns = data?.t5 || props.columns || 4; const button_text = data?.button_text || props.button_text || "Read More"; const rows = (data?.p1 && !isNaN(Number(data.p1))) ? Number(data.p1) : (props.rows || 1); // Loading and error states are now handled by the server component and React Suspense. // We only need to handle the case where there are no items to show. if (!items || items.length === 0) { return (
{(title || subtitle) && (
{title &&

{title}

} {subtitle &&

{subtitle}

}
)}
暂无数据
); } // Helper functions for rendering. They are pure and belong with the UI. function renderCardImage(post, idx) { // 多图轮播 if (Array.isArray(post.images) && post.images.length > 1) { return ( {post.images.map((img, i) => ( {post.title ))} ); } // 视频 if (post.video_src || post.videoId) { if (post.video_src && (post.video_src.endsWith('.mp4') || post.video_src.startsWith('/files/'))) { return ( ); } const vid = post.videoId || (post.video_src && post.video_src.includes('youtube') ? post.video_src.split('embed/')[1] : null); if (vid) { return (