Files
sage-home/app/[locale]/single/[slug]/page.tsx
砂糖 70f337bb92 init
2026-01-24 16:54:44 +08:00

135 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { LOCALES } from "@/i18n/routing";
import { getLine, getLines } from "@/lib/lines";
import { constructMetadata } from "@/lib/metadata";
import { Line } from "@/types/line";
import { Metadata } from "next";
import { Locale } from "next-intl";
// 强制静态渲染
export const dynamic = "force-static";
// 固定 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 line = await getLine(locale, slug);
console.log(line);
console.log(line?.slug);
if (!line) {
return constructMetadata({
title: "404 - 产线不存在",
description: "请求的产线页面未找到",
noIndex: true,
locale: locale as Locale,
path: `/line/${slug}`,
canonicalUrl: `/line/${slug}`,
});
}
return constructMetadata({
title: line.title,
description: line.desc,
locale: locale as Locale,
path: `/line/${slug}`,
canonicalUrl: `/line/${slug}`,
});
}
// 页面主组件 - 仅保留字段展示+修复 Hydration 错误
export default async function ProductDetailPage({ params }: { params: Params }) {
// 🔴 核心修复1移除不必要的 awaitparams 是同步对象)
const { locale, slug } = await params;
const line = await getLine(locale, slug);
if (!line) return null;
// 兜底处理:避免字段为空导致属性不匹配
const coverSrc = line.cover || "";
const coverAlt = line.title || "产线封面";
const lineDesc = line.desc || "暂无产线描述";
return (
<div className="min-h-screen bg-gray-50 py-10 px-4 sm:px-6 lg:px-8">
<div className="max-w-6xl mx-auto">
{/* 封面图区域 - 🔴 修复布局属性不一致 */}
<div className="relative rounded-2xl overflow-hidden shadow-lg h-[400px] sm:h-[500px] mb-8">
<img
src={coverSrc}
alt={coverAlt}
className="absolute inset-0 w-full h-full object-cover transition-transform hover:scale-105 duration-700"
// 显式设置属性,确保服务端/客户端一致
loading="lazy"
decoding="async"
/>
</div>
{/* 标题+描述区域 */}
<div className="bg-white rounded-xl p-8 shadow-sm mb-10">
<h1 className="text-3xl sm:text-4xl font-bold text-gray-900 mb-6">
{line.title}
</h1>
<p className="text-lg text-gray-700 leading-relaxed">
{lineDesc}
</p>
</div>
{line.images.length > 0 && (
<div className="bg-white rounded-xl p-8 shadow-sm">
<h2 className="text-2xl font-semibold text-gray-800 mb-6 border-b pb-3 border-gray-200">
</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{line.images.map((img, index) => {
const stableKey = `line-${slug}-img-${index}-${img.slice(-8)}`;
const imgAlt = `${line.title}-图片${index + 1}`;
return (
<div
key={stableKey}
className="relative rounded-lg overflow-hidden shadow-md h-64 hover:shadow-xl transition-all duration-300"
>
<img
src={img}
alt={imgAlt}
className="absolute inset-0 w-full h-full object-cover transition-transform hover:scale-110 duration-500"
loading="lazy"
decoding="async"
/>
</div>
);
})}
</div>
</div>
)}
</div>
</div>
);
}
export async function generateStaticParams() {
try {
const defaultLocale = LOCALES[0];
const workShops: Line[] = await getLines(defaultLocale);
return LOCALES.flatMap((locale) =>
workShops.map((workShop) => ({
locale,
slug: workShop.slug as string,
}))
);
} catch (error) {
console.error("生成产品静态参数失败:", error);
return [];
}
}