jingrow/app/[...slug]/page.jsx

164 lines
6.5 KiB
JavaScript

import Banner from "@/components/banner/Banner";
import Category from "@/components/sidebar/Category";
import { getSiteSettings } from "@/utlis/siteSettings";
import { notFound } from 'next/navigation';
import DynamicListPage from "@/components/common/DynamicListPage";
import { Suspense } from 'react';
const LoadingSpinner = () => (
<div className="flex justify-center items-center p-8">
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div>
</div>
);
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;
const slugArr = resolvedParams.slug;
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 })
});
const json = await res.json();
const { data, error, page_info } = json;
if (error) {
return {
title: error.title || 'Page Error',
description: error.message || '',
};
}
if (Array.isArray(data) && page_info) {
return {
title: page_info.meta_title || page_info.title || '',
description: page_info.meta_description || '',
};
}
return {
title: data?.meta_title || data?.title || '',
description: data?.meta_description || '',
};
}
export default async function DynamicPage({ params }) {
const resolvedParams = await params;
const slugArr = resolvedParams.slug;
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: 1, page_size: pageSize })
});
const result = await res.json();
const { data, error, total } = result;
if (error) {
notFound();
}
const bannerComponentName = 'Banner-' + (slugArr[0] || 'home');
const categoryComponentName = 'Category-' + (slugArr[0] || 'home');
if (Array.isArray(data)) {
const currentPath = '/' + (Array.isArray(slugArr) ? slugArr.join('/') : '');
const listColumns = 4;
return (
<>
<Banner componentName={bannerComponentName} />
<div className="wrapper !bg-[#ffffff]">
<div className="container py-[4.5rem] xl:!py-24 lg:!py-24 md:!py-24">
<div className="flex flex-col md:flex-row mx-[-15px] xl:mx-[-35px] lg:mx-[-20px]">
<Category componentName={categoryComponentName} />
<div className="flex-1 min-w-0 !px-[15px] max-w-full md:!px-[20px] lg:!px-[20px] xl:!px-[35px]">
<Suspense fallback={<LoadingSpinner />}>
<DynamicListPage
initialItems={data}
slugArr={slugArr}
basePath={currentPath}
columns={listColumns}
pageSize={pageSize}
totalItems={total}
/>
</Suspense>
</div>
</div>
</div>
</div>
</>
);
} else if (data) {
return (
<>
<Banner componentName={bannerComponentName} />
<div className="wrapper !bg-[#ffffff]">
<div className="container py-[4.5rem] xl:!py-24 lg:!py-24 md:!py-24">
<div className="flex flex-col md:flex-row mx-[-15px] xl:mx-[-35px] lg:mx-[-20px]">
<Category componentName={categoryComponentName} />
<div className="flex-1 min-w-0 !px-[15px] max-w-full md:!px-[20px] lg:!px-[20px] xl:!px-[35px]">
<div className="bg-white rounded-lg shadow-md p-6 md:p-10">
{/* 图片和附加信息并排显示,响应式优化 */}
{(data.image || data.subtitle) && (
<div className="flex flex-col md:flex-row gap-4 md:gap-8 mb-6 md:mb-8 items-center md:items-start w-full max-w-full">
{data.image && (
<div className="flex-shrink-0 w-full md:w-72 flex justify-center md:justify-start mb-4 md:mb-0 max-w-full">
<img
src={data.image}
alt={data.title}
className="w-full max-w-[320px] md:max-w-full max-h-60 md:max-h-72 rounded-xl shadow-lg object-contain"
/>
</div>
)}
{data.subtitle && (
<div className="bg-gray-50 rounded-md p-3 md:p-4 whitespace-pre-line text-gray-700 w-full shadow-sm max-w-full prose prose-sm">
{data.subtitle}
</div>
)}
</div>
)}
{/* Product Description 标题 */}
<div className="prose max-w-none text-gray-700 mb-6 md:mb-8 px-1 md:px-0 prose-img:max-w-full prose-img:h-auto prose-table:border prose-table:border-gray-300 prose-th:border prose-th:border-gray-300 prose-td:border prose-td:border-gray-300 prose-th:bg-gray-50 prose-table:rounded-lg prose-table:overflow-hidden" dangerouslySetInnerHTML={{ __html: data.content || '' }} />
{data.additional_content && (
<>
{/* Testing Report 标题 */}
<div className="prose max-w-none text-gray-700 mt-6 md:mt-8 px-1 md:px-0 prose-img:max-w-full prose-img:h-auto prose-table:border prose-table:border-gray-300 prose-th:border prose-th:border-gray-300 prose-td:border prose-td:border-gray-300 prose-th:bg-gray-50 prose-table:rounded-lg prose-table:overflow-hidden" dangerouslySetInnerHTML={{ __html: data.additional_content }} />
</>
)}
</div>
</div>
</div>
</div>
</div>
</>
);
} else {
notFound();
}
}