feat: add products/cases pages and lead-capture form block
- 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
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
import { notFound } from "next/navigation";
|
||||
import type { Metadata } from "next";
|
||||
import { getCaseStudyBySlug } from "@/services/case.service";
|
||||
import { BlockRenderer } from "@/blocks/BlockRenderer";
|
||||
|
||||
interface CaseStudyDetailPageProps {
|
||||
params: Promise<{ slug: string }>;
|
||||
}
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: CaseStudyDetailPageProps): Promise<Metadata> {
|
||||
const { slug } = await params;
|
||||
const item = await getCaseStudyBySlug(slug).catch(() => null);
|
||||
return { title: item?.title ?? "案例未找到" };
|
||||
}
|
||||
|
||||
export default async function CaseStudyDetailPage({
|
||||
params,
|
||||
}: CaseStudyDetailPageProps) {
|
||||
const { slug } = await params;
|
||||
const item = await getCaseStudyBySlug(slug).catch(() => null);
|
||||
|
||||
if (!item) {
|
||||
notFound();
|
||||
}
|
||||
|
||||
return (
|
||||
<article className="mx-auto max-w-3xl px-6 py-24">
|
||||
<h1 className="mb-2 text-4xl font-bold text-slate-900">{item.title}</h1>
|
||||
<p className="mb-12 text-sm text-slate-500">
|
||||
{item.client_name}
|
||||
{item.industry ? ` · ${item.industry}` : ""}
|
||||
</p>
|
||||
<BlockRenderer blocks={item.body} />
|
||||
</article>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import Link from "next/link";
|
||||
import type { Metadata } from "next";
|
||||
import { getCaseStudyList } from "@/services/case.service";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "客户案例",
|
||||
};
|
||||
|
||||
export default async function CaseStudyListPage() {
|
||||
const caseStudies = await getCaseStudyList().catch(() => []);
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-4xl px-6 py-24">
|
||||
<h1 className="mb-12 text-4xl font-bold text-slate-900">客户案例</h1>
|
||||
<ul className="space-y-6">
|
||||
{caseStudies.map((item) => (
|
||||
<li key={item.id} className="border-b border-slate-100 pb-6">
|
||||
<Link
|
||||
href={`/cases/${item.meta.slug}`}
|
||||
className="text-2xl font-semibold text-slate-900 hover:text-primary"
|
||||
>
|
||||
{item.title}
|
||||
</Link>
|
||||
<p className="mt-1 text-sm text-slate-500">
|
||||
{item.client_name}
|
||||
{item.industry ? ` · ${item.industry}` : ""}
|
||||
</p>
|
||||
{item.summary && (
|
||||
<p className="mt-2 text-slate-600">{item.summary}</p>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
{caseStudies.length === 0 && (
|
||||
<p className="text-slate-500">暂无案例,或后端服务未连接。</p>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user