Files
sage-home/app/[locale]/workshop/[slug]/page.tsx

128 lines
4.3 KiB
TypeScript
Raw Normal View History

2026-01-24 16:54:44 +08:00
import { LOCALES } from "@/i18n/routing";
import { constructMetadata } from "@/lib/metadata";
import { getWorkShop, getWorkShops } from "@/lib/workshop";
import { WorkShop } from "@/types/workShop";
import { Metadata } from "next";
import { Locale } from "next-intl";
import { getTranslations } from "next-intl/server";
2026-01-24 16:54:44 +08:00
// 固定 Params 类型为普通对象Next.js 原生传参无异步)
type Params = {
locale: string;
slug: string;
};
type MetadataProps = {
params: Params;
};
export async function generateMetadata({
params,
}: MetadataProps): Promise<Metadata> {
const { locale, slug } = await params;
const workShop = await getWorkShop(locale, slug);
if (!workShop) {
return constructMetadata({
title: "404 - 车间不存在",
description: "请求的车间页面未找到",
noIndex: true,
locale: locale as Locale,
path: `/workshop/${slug}`,
canonicalUrl: `/workshop/${slug}`,
});
}
return constructMetadata({
title: workShop.title,
description: workShop.desc,
locale: locale as Locale,
path: `/workshop/${slug}`,
canonicalUrl: `/workshop/${slug}`,
});
}
// 页面主组件 - 仅保留字段展示+修复 Hydration 错误
export default async function WorkshopDetailPage({ params }: { params: Params }) {
const { locale, slug } = await params;
const workShop = await getWorkShop(locale, slug);
const t = await getTranslations({ locale, namespace: "Workshop" });
2026-01-24 16:54:44 +08:00
if (!workShop) return null;
// 兜底处理:避免字段为空导致属性不匹配
const coverSrc = workShop.cover || "";
const coverAlt = workShop.title || "车间封面";
const workshopDesc = workShop.desc || "暂无车间描述";
return (
<div className="min-h-screen bg-gray-50 py-16 px-6 sm:px-8 lg:px-10">
<div className="max-w-7xl mx-auto space-y-12">
{/* 封面图区域 - 强化背景效果 */}
<div className="relative rounded-xl overflow-hidden shadow-lg h-[500px] sm:h-[600px] mb-12 group">
2026-01-24 16:54:44 +08:00
<img
src={coverSrc}
alt={coverAlt}
className="absolute inset-0 w-full h-full object-cover transition-transform duration-500 group-hover:scale-110"
2026-01-24 16:54:44 +08:00
loading="lazy"
decoding="async"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black opacity-40"></div>
2026-01-24 16:54:44 +08:00
</div>
{/* 标题+描述区域 */}
<div className="bg-white rounded-xl p-8 shadow-xl">
<h1 className="text-3xl sm:text-4xl font-bold text-gray-900 mb-6">{workShop.title}</h1>
<p className="text-lg sm:text-xl text-gray-700 leading-relaxed mb-6">{workshopDesc}</p>
2026-01-24 16:54:44 +08:00
</div>
{/* 图片展示区域 */}
2026-01-24 16:54:44 +08:00
{workShop.images?.length > 0 && (
<div className="bg-white rounded-xl p-8 shadow-xl mt-12">
2026-01-24 16:54:44 +08:00
<h2 className="text-2xl font-semibold text-gray-800 mb-6 border-b pb-3 border-gray-200">
{t("pageImages")}
2026-01-24 16:54:44 +08:00
</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{workShop.images.map((img, index) => {
const stableKey = `workshop-${slug}-img-${index}-${img.slice(-8)}`;
const imgAlt = `${workShop.title}-图片${index + 1}`;
return (
<div
key={stableKey}
className="relative rounded-xl overflow-hidden shadow-lg hover:shadow-2xl transition-all duration-300"
2026-01-24 16:54:44 +08:00
>
<img
src={img}
alt={imgAlt}
className="w-full h-full object-cover transition-transform duration-500 hover:scale-105"
2026-01-24 16:54:44 +08:00
loading="lazy"
decoding="async"
/>
</div>
);
})}
</div>
</div>
)}
</div>
</div>
);
}
export async function generateStaticParams() {
try {
const defaultLocale = LOCALES[0];
const workShops: WorkShop[] = await getWorkShops(defaultLocale);
return LOCALES.flatMap((locale) =>
workShops.map((workShop) => ({
locale,
slug: workShop.slug as string,
}))
);
} catch (error) {
console.error("生成车间静态参数失败:", error);
2026-01-24 16:54:44 +08:00
return [];
}
}