feat: add solutions list/detail pages

- types: SolutionPageSummary/Detail
- services/solution.service.ts
- app/solutions: list + detail pages
- Header nav: add 解决方案 link
This commit is contained in:
2026-08-06 16:24:08 +08:00
parent b5fe5e13ab
commit 73d2465ef2
5 changed files with 113 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
import { notFound } from "next/navigation";
import type { Metadata } from "next";
import { getSolutionBySlug } from "@/services/solution.service";
import { BlockRenderer } from "@/blocks/BlockRenderer";
interface SolutionDetailPageProps {
params: Promise<{ slug: string }>;
}
export async function generateMetadata({
params,
}: SolutionDetailPageProps): Promise<Metadata> {
const { slug } = await params;
const solution = await getSolutionBySlug(slug).catch(() => null);
return { title: solution?.title ?? "解决方案未找到" };
}
export default async function SolutionDetailPage({
params,
}: SolutionDetailPageProps) {
const { slug } = await params;
const solution = await getSolutionBySlug(slug).catch(() => null);
if (!solution) {
notFound();
}
return (
<article className="mx-auto max-w-3xl px-6 py-24">
<h1 className="mb-2 text-4xl font-bold text-slate-900">
{solution.title}
</h1>
{solution.industry && (
<p className="mb-12 text-sm text-slate-500">{solution.industry}</p>
)}
<BlockRenderer blocks={solution.body} />
</article>
);
}
+38
View File
@@ -0,0 +1,38 @@
import Link from "next/link";
import type { Metadata } from "next";
import { getSolutionList } from "@/services/solution.service";
export const metadata: Metadata = {
title: "解决方案",
};
export default async function SolutionListPage() {
const solutions = await getSolutionList().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">
{solutions.map((solution) => (
<li key={solution.id} className="border-b border-slate-100 pb-6">
<Link
href={`/solutions/${solution.meta.slug}`}
className="text-2xl font-semibold text-slate-900 hover:text-primary"
>
{solution.title}
</Link>
{solution.industry && (
<p className="mt-1 text-sm text-slate-500">{solution.industry}</p>
)}
{solution.summary && (
<p className="mt-2 text-slate-600">{solution.summary}</p>
)}
</li>
))}
{solutions.length === 0 && (
<p className="text-slate-500"></p>
)}
</ul>
</div>
);
}