详情页主图支持多图显示
@ -4,7 +4,8 @@ import { getSiteSettings } from "@/utils/data";
|
||||
import { notFound } from 'next/navigation';
|
||||
import DynamicListPage from "@/components/common/DynamicListPage";
|
||||
import { Suspense } from 'react';
|
||||
import { getPageData, getAllSlugs } from "@/utils/data";
|
||||
import { getPageData } from "@/utils/data";
|
||||
import ProductImageGallery from "@/components/products/ProductImageGallery";
|
||||
|
||||
const LoadingSpinner = () => (
|
||||
<div className="flex justify-center items-center p-8">
|
||||
@ -12,29 +13,13 @@ const LoadingSpinner = () => (
|
||||
</div>
|
||||
);
|
||||
|
||||
// Using a static value to comply with Next.js 15 build requirements.
|
||||
// On-demand revalidation will be handled via the API route.
|
||||
export const revalidate = 3600;
|
||||
|
||||
export async function generateStaticParams() {
|
||||
try {
|
||||
const slugs = await getAllSlugs();
|
||||
return slugs.map(slug => ({
|
||||
slug: slug,
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error("Failed to generate static params:", error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }) {
|
||||
const resolvedParams = await params;
|
||||
const slugArr = resolvedParams.slug;
|
||||
const { data, error, page_info } = await getPageData({
|
||||
slug_list: slugArr,
|
||||
downloadFiles: false // Do not download files for metadata
|
||||
});
|
||||
const slug = resolvedParams.slug || [];
|
||||
const slugArr = Array.isArray(slug) ? slug : [slug];
|
||||
const { data, error, page_info } = await getPageData({ slug_list: slugArr });
|
||||
const siteSettings = await getSiteSettings();
|
||||
const siteTitle = siteSettings.site_title || '';
|
||||
const siteName = siteSettings.site_name || '';
|
||||
@ -76,31 +61,30 @@ export async function generateMetadata({ params }) {
|
||||
};
|
||||
}
|
||||
|
||||
export default async function DynamicPage({ params, searchParams }) {
|
||||
export default async function Page({ params, searchParams }) {
|
||||
const resolvedParams = await params;
|
||||
const slugArr = resolvedParams.slug;
|
||||
const slug = resolvedParams.slug || [];
|
||||
const slugArr = Array.isArray(slug) ? slug : [slug];
|
||||
|
||||
const siteSettings = await getSiteSettings();
|
||||
const pageSize = Number(siteSettings.page_size) || 12;
|
||||
|
||||
// 始终获取第一页的数据用于静态生成
|
||||
const { data, error, total } = await getPageData({
|
||||
slug_list: slugArr,
|
||||
page: 1,
|
||||
page_size: pageSize,
|
||||
downloadFiles: true // Download files for page rendering
|
||||
downloadFiles: true,
|
||||
});
|
||||
|
||||
if (error) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
const bannerComponentName = 'Banner-' + (slugArr[0] || 'home');
|
||||
const categoryComponentName = 'Category-' + (slugArr[0] || 'home');
|
||||
|
||||
const pageSlugBase = slugArr.length ? slugArr[slugArr.length - 1] : '';
|
||||
const bannerComponentName = `Banner-${pageSlugBase}`;
|
||||
const categoryComponentName = `Category-${pageSlugBase}`;
|
||||
if (Array.isArray(data)) {
|
||||
const currentPath = '/' + (Array.isArray(slugArr) ? slugArr.join('/') : '');
|
||||
const listColumns = 4;
|
||||
|
||||
const currentPath = '/' + slugArr.join('/');
|
||||
const listColumns = 4;
|
||||
return (
|
||||
<>
|
||||
<Banner componentName={bannerComponentName} />
|
||||
@ -138,31 +122,30 @@ export default async function DynamicPage({ params, searchParams }) {
|
||||
<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 className="flex flex-col md:flex-row gap-4 md:gap-10 mb-6 md:mb-8 items-center md:items-start w-full max-w-full">
|
||||
{/* 图片轮播区块 */}
|
||||
<ProductImageGallery data={data} />
|
||||
|
||||
<div className="flex-1 min-w-0">
|
||||
{/* 产品标题 */}
|
||||
{data.title && (
|
||||
<h1 className="text-2xl md:text-3xl font-bold text-gray-900 mb-10 md:mb-10 leading-tight">
|
||||
{data.title}
|
||||
</h1>
|
||||
)}
|
||||
{/* 产品副标题 */}
|
||||
{data.subtitle && (
|
||||
<div className="bg-gray-50 whitespace-pre-line text-gray-700 w-full max-w-full prose prose-sm pt-6">
|
||||
{data.subtitle}
|
||||
</div>
|
||||
)}
|
||||
</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 className="">
|
||||
<div className="prose max-w-none text-gray-700 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 || '' }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -173,4 +156,4 @@ export default async function DynamicPage({ params, searchParams }) {
|
||||
} else {
|
||||
notFound();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
public/files/aidc6054er_d92979cb.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
public/files/alv6ce8dj3_33b57c55.png
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
public/files/aohums8vsl_3bd3733b.png
Normal file
|
After Width: | Height: | Size: 883 KiB |
BIN
public/files/aohums8vsl_ba6de487.png
Normal file
|
After Width: | Height: | Size: 620 KiB |
BIN
public/files/at05gkd37k_c02c70ce.png
Normal file
|
After Width: | Height: | Size: 646 KiB |
BIN
public/files/e7hkd4aq3m_17f58530.png
Normal file
|
After Width: | Height: | Size: 802 KiB |
BIN
public/files/e7shufki1s_12f8024e.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
public/files/ef0g85canc_afd8ca27.png
Normal file
|
After Width: | Height: | Size: 1.3 MiB |
BIN
public/files/ehng0ni35f_a6847c82.png
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
public/files/ek5pp8snc0_cf17fef5.png
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
public/files/o2gnd8a1io_ce51fbd5.png
Normal file
|
After Width: | Height: | Size: 518 KiB |