diff --git a/app/[...slug]/page.jsx b/app/[...slug]/page.jsx index e82c78d..e8dc7cd 100644 --- a/app/[...slug]/page.jsx +++ b/app/[...slug]/page.jsx @@ -1,11 +1,38 @@ import Banner from "@/components/banner/Banner"; import Category from "@/components/sidebar/Category"; -import Pagination1 from "@/components/common/Pagination1"; import { getSiteSettings } from "@/utlis/siteSettings"; -import ListPageTemplate from "@/components/common/ListPageTemplate"; import { notFound } from 'next/navigation'; +import DynamicListPage from "@/components/common/DynamicListPage"; +import { Suspense } from 'react'; + +const LoadingSpinner = () => ( +
+
+
+); export const revalidate = 3600; +export const dynamicParams = true; + +export async function generateStaticParams() { + try { + const res = await fetch(`${process.env.SITE_URL}/api/get-all-slugs`); + if (!res.ok) { + throw new Error(`Failed to fetch slugs: ${res.status}`); + } + const slugs = await res.json(); + if (!Array.isArray(slugs)) { + console.error("generateStaticParams: received non-array from /api/get-all-slugs", slugs); + return []; + } + return slugs.map(slug => ({ + slug: slug, + })); + } catch (error) { + console.error("Could not generate static params:", error); + return []; + } +} export async function generateMetadata({ params }) { const resolvedParams = await params; @@ -35,20 +62,18 @@ export async function generateMetadata({ params }) { }; } -export default async function DynamicPage({ params, searchParams }) { +export default async function DynamicPage({ params }) { const resolvedParams = await params; - const resolvedSearchParams = await searchParams; const slugArr = resolvedParams.slug; - const currentPage = Number(resolvedSearchParams?.page) || 1; - // Get global site settings const siteSettings = await getSiteSettings(process.env.SITE_URL); const pageSize = Number(siteSettings.page_size) || 12; + // 始终获取第一页的数据用于静态生成 const res = await fetch(`${process.env.SITE_URL}/api/get-page-data`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ slug_list: slugArr, page: currentPage, page_size: pageSize }) + body: JSON.stringify({ slug_list: slugArr, page: 1, page_size: pageSize }) }); const result = await res.json(); const { data, error, total } = result; @@ -60,26 +85,9 @@ export default async function DynamicPage({ params, searchParams }) { const bannerComponentName = 'Banner-' + (slugArr[0] || 'home'); const categoryComponentName = 'Category-' + (slugArr[0] || 'home'); - // Infer pagetype and name from slugArr - const pagetype = slugArr?.[0] || ''; - const name = slugArr?.[1] || ''; - if (Array.isArray(data)) { const currentPath = '/' + (Array.isArray(slugArr) ? slugArr.join('/') : ''); - const lastSlug = Array.isArray(slugArr) ? slugArr[slugArr.length - 1] : ''; - const totalPages = Math.ceil((total || 0) / pageSize); - - // Adapt template required fields - const listItems = data.map(item => ({ - slug: item.slug, - title: item.title, - image: item.image || item.cover || item.img || '', - additional_title: item.additional_title || '', - subtitle: item.subtitle || item.content || '', - })); - - // 新增:允许通过变量控制列数,默认4 - const listColumns = 4; // 可根据需要改为变量 + const listColumns = 4; return ( <> @@ -89,14 +97,16 @@ export default async function DynamicPage({ params, searchParams }) {
- -
- }> + -
+
diff --git a/app/api/get-all-slugs/route.js b/app/api/get-all-slugs/route.js new file mode 100644 index 0000000..2433fb1 --- /dev/null +++ b/app/api/get-all-slugs/route.js @@ -0,0 +1,26 @@ +import axios from 'axios'; + +const JINGROW_SERVER_URL = process.env.JINGROW_SERVER_URL; + +export async function GET() { + try { + const response = await axios.get( + `${JINGROW_SERVER_URL}/api/method/jsite.api.v1.get_all_slugs` + ); + + const slugs = response.data.message?.data; + + if (!Array.isArray(slugs)) { + console.error('API did not return an array of slugs:', response.data); + return Response.json({ error: '返回的slugs格式不正确' }, { status: 500 }); + } + + return Response.json(slugs); + } catch (error) { + console.error('Error fetching slugs:', error.message, error?.response?.data); + return Response.json( + { error: '获取slugs失败', detail: error?.response?.data || error.message }, + { status: 500 } + ); + } +} \ No newline at end of file diff --git a/app/products/[...slug]/page.jsx b/app/products/[...slug]/page.jsx index c60ee83..ad942be 100644 --- a/app/products/[...slug]/page.jsx +++ b/app/products/[...slug]/page.jsx @@ -1,16 +1,24 @@ import Banner from "@/components/banner/Banner"; import Category from "@/components/sidebar/Category"; -import Pagination1 from "@/components/common/Pagination1"; import { getSiteSettings } from "@/utlis/siteSettings"; -import ListPageTemplate from "@/components/common/ListPageTemplate"; import { notFound } from 'next/navigation'; +import DynamicListPage from "@/components/common/DynamicListPage"; +import { Suspense } from 'react'; const baseSlug = 'products'; +const LoadingSpinner = () => ( +
+
+
+); + export const revalidate = 3600; export async function generateMetadata({ params }) { - const slugArr = [baseSlug, ...(params.slug ? (Array.isArray(params.slug) ? params.slug : [params.slug]) : [])]; + const resolvedParams = await params; + const slug = resolvedParams.slug || []; + const slugArr = [baseSlug, ...(Array.isArray(slug) ? slug : [slug])]; const res = await fetch(`${process.env.SITE_URL}/api/get-page-data`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -36,15 +44,19 @@ export async function generateMetadata({ params }) { }; } -export default async function Page({ params, searchParams }) { - const slugArr = [baseSlug, ...(params.slug ? (Array.isArray(params.slug) ? params.slug : [params.slug]) : [])]; - const currentPage = Number(searchParams?.page) || 1; +export default async function Page({ params }) { + const resolvedParams = await params; + const slug = resolvedParams.slug || []; + const slugArr = [baseSlug, ...(Array.isArray(slug) ? slug : [slug])]; + const siteSettings = await getSiteSettings(process.env.SITE_URL); const pageSize = Number(siteSettings.page_size) || 12; + + // Fetch only page 1 for initial static render const res = await fetch(`${process.env.SITE_URL}/api/get-page-data`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ slug_list: slugArr, page: currentPage, page_size: pageSize }) + body: JSON.stringify({ slug_list: slugArr, page: 1, page_size: pageSize }) }); const result = await res.json(); const { data, error, total } = result; @@ -54,14 +66,8 @@ export default async function Page({ params, searchParams }) { const bannerComponentName = 'Banner-' + baseSlug; const categoryComponentName = 'Category-' + baseSlug; if (Array.isArray(data)) { - const currentPath = '/' + [baseSlug, ...(params.slug ? (Array.isArray(params.slug) ? params.slug : [params.slug]) : [])].join('/'); - const totalPages = Math.ceil((total || 0) / pageSize); - const listItems = data.map(item => ({ - slug: item.slug, - title: item.title, - image: item.image || item.cover || item.img || '', - content: item.content || item.description || '', - })); + const currentPath = '/' + slugArr.join('/'); + const listColumns = 4; return ( <> @@ -70,14 +76,16 @@ export default async function Page({ params, searchParams }) {
- -
- }> + -
+
diff --git a/components/common/DynamicListPage.jsx b/components/common/DynamicListPage.jsx new file mode 100644 index 0000000..12a02a9 --- /dev/null +++ b/components/common/DynamicListPage.jsx @@ -0,0 +1,77 @@ +'use client'; + +import { useState, useEffect } from 'react'; +import { useSearchParams } from 'next/navigation'; +import ListPageTemplate from '@/components/common/ListPageTemplate'; +import Pagination1 from '@/components/common/Pagination1'; +import axios from 'axios'; + +const LoadingSpinner = () => ( +
+
+
+); + +export default function DynamicListPage({ initialItems, slugArr, basePath, columns, pageSize, totalItems }) { + const [items, setItems] = useState(initialItems); + const [total, setTotal] = useState(totalItems); + const [isLoading, setIsLoading] = useState(false); + const searchParams = useSearchParams(); + const page = searchParams.get('page'); + const currentPage = Number(page) || 1; + + useEffect(() => { + const fetchPageData = async () => { + if (currentPage === 1) { + setItems(initialItems); + setTotal(totalItems); + return; + } + setIsLoading(true); + try { + const res = await axios.post('/api/get-page-data', { + slug_list: slugArr, + page: currentPage, + page_size: pageSize, + }); + setItems(res.data.data); + setTotal(res.data.total); + } catch (error) { + console.error('Failed to fetch page data:', error); + // Optionally, handle the error in the UI + } finally { + setIsLoading(false); + } + }; + + fetchPageData(); + }, [currentPage, slugArr, pageSize, initialItems, totalItems]); + + const listItems = items.map(item => ({ + ...item, + slug: item.slug, + title: item.title, + image: item.image || item.cover || item.img || '', + additional_title: item.additional_title || '', + subtitle: item.subtitle || item.content || '', + })); + + const totalPages = Math.ceil((total || 0) / pageSize); + + return ( + <> + {isLoading ? ( + + ) : ( + + )} +
+ +
+ + ); +} \ No newline at end of file diff --git a/components/homes/home-15/SwiperItems.jsx b/components/homes/home-15/SwiperItems.jsx index 883d77b..62169a6 100644 --- a/components/homes/home-15/SwiperItems.jsx +++ b/components/homes/home-15/SwiperItems.jsx @@ -1,5 +1,5 @@ "use client"; -import { useEffect, useState, useRef } from "react"; +import { useEffect, useState } from "react"; import { Swiper, SwiperSlide } from "swiper/react"; import { Navigation, Pagination, Grid } from "swiper/modules"; import Link from "next/link"; @@ -24,9 +24,6 @@ export default function SwiperItems(props) { const rows = (data?.p1 && !isNaN(Number(data.p1))) ? Number(data.p1) : (props.rows || 1); const button_text = data?.button_text || props.button_text; - const prevRef = useRef(null); - const nextRef = useRef(null); - useEffect(() => { async function fetchComponentData() { try { @@ -192,13 +189,9 @@ export default function SwiperItems(props) { slidesPerGroup={columns * rows} grid={{ rows }} pagination={{ clickable: true, el: ".spdb15" }} - navigation={{ prevEl: prevRef.current, nextEl: nextRef.current }} - onInit={swiper => { - // Swiper 8+ 需要手动传递 ref.current - swiper.params.navigation.prevEl = prevRef.current; - swiper.params.navigation.nextEl = nextRef.current; - swiper.navigation.init(); - swiper.navigation.update(); + navigation={{ + prevEl: '.swiper-nav-prev-swiperitems', + nextEl: '.swiper-nav-next-swiperitems' }} breakpoints={{ 0: { slidesPerView: 1, slidesPerGroup: 1, grid: { rows: 1 } }, @@ -249,8 +242,7 @@ export default function SwiperItems(props) { {/* 美化后的导航按钮 */}