- types: Product/CaseStudy page types, CaseStudyBlockValue, FormBlockValue - services: product.service.ts, case.service.ts - app/products, app/cases: list + detail pages - blocks: CaseStudyCard, LeadForm (submits to /api/v1/custom/leads/) - Header nav: add 产品/案例 links
40 lines
1.1 KiB
TypeScript
40 lines
1.1 KiB
TypeScript
import { notFound } from "next/navigation";
|
|
import type { Metadata } from "next";
|
|
import { getProductBySlug } from "@/services/product.service";
|
|
import { BlockRenderer } from "@/blocks/BlockRenderer";
|
|
|
|
interface ProductDetailPageProps {
|
|
params: Promise<{ slug: string }>;
|
|
}
|
|
|
|
export async function generateMetadata({
|
|
params,
|
|
}: ProductDetailPageProps): Promise<Metadata> {
|
|
const { slug } = await params;
|
|
const product = await getProductBySlug(slug).catch(() => null);
|
|
return { title: product?.title ?? "产品未找到" };
|
|
}
|
|
|
|
export default async function ProductDetailPage({
|
|
params,
|
|
}: ProductDetailPageProps) {
|
|
const { slug } = await params;
|
|
const product = await getProductBySlug(slug).catch(() => null);
|
|
|
|
if (!product) {
|
|
notFound();
|
|
}
|
|
|
|
return (
|
|
<article className="mx-auto max-w-3xl px-6 py-24">
|
|
<h1 className="mb-4 text-4xl font-bold text-slate-900">
|
|
{product.title}
|
|
</h1>
|
|
{product.summary && (
|
|
<p className="mb-12 text-lg text-slate-600">{product.summary}</p>
|
|
)}
|
|
<BlockRenderer blocks={product.body} />
|
|
</article>
|
|
);
|
|
}
|