Files
sage-home/app/[locale]/workshop/[slug]/page.tsx
砂糖 86c20e5ef7 feat(ui): 更新车间和产品页面UI设计并添加新图片资源
更新多个页面的UI设计,包括产品卡片、车间详情页和列表页,采用现代化卡片设计和动画效果
添加新的车间图片资源并更新相关页面的图片引用路径
优化响应式布局和交互体验,增强视觉吸引力
2026-02-03 14:39:36 +08:00

126 lines
4.1 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 { constructMetadata } from "@/lib/metadata";
import { getWorkShop, getWorkShops } from "@/lib/workshop";
import { WorkShop } from "@/types/workShop";
import { Metadata } from "next";
import { Locale } from "next-intl";
// 固定 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);
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">
<img
src={coverSrc}
alt={coverAlt}
className="absolute inset-0 w-full h-full object-cover transition-transform duration-500 group-hover:scale-110"
loading="lazy"
decoding="async"
/>
<div className="absolute inset-0 bg-gradient-to-t from-black opacity-40"></div>
</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>
</div>
{/* 图片展示区域 */}
{workShop.images?.length > 0 && (
<div className="bg-white rounded-xl p-8 shadow-xl mt-12">
<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">
{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"
>
<img
src={img}
alt={imgAlt}
className="w-full h-full object-cover transition-transform duration-500 hover:scale-105"
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);
return [];
}
}