198 lines
5.3 KiB
JavaScript
198 lines
5.3 KiB
JavaScript
"use client";
|
||
|
||
import { useParams } from "next/navigation";
|
||
import { useEffect, useState } from "react";
|
||
import Image from "next/image";
|
||
import { useRouter } from "next/navigation";
|
||
import toast from "react-hot-toast";
|
||
import AddToCartModal from "@/components/AddToCartModal";
|
||
|
||
export default function ProductDetail() {
|
||
const params = useParams();
|
||
const [product, setProduct] = useState(null);
|
||
const [loading, setLoading] = useState(true);
|
||
const [error, setError] = useState(null);
|
||
const [quantity, setQuantity] = useState(1);
|
||
const router = useRouter();
|
||
const [showModal, setShowModal] = useState(false);
|
||
|
||
useEffect(() => {
|
||
const fetchProduct = async () => {
|
||
try {
|
||
const res = await fetch(`/api/products/${params.id}`);
|
||
if (!res.ok) {
|
||
throw new Error("获取商品详情失败");
|
||
}
|
||
const data = await res.json();
|
||
setProduct(data);
|
||
} catch (err) {
|
||
setError(err.message);
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
fetchProduct();
|
||
}, [params.id]);
|
||
|
||
const handleAddToCart = async () => {
|
||
try {
|
||
const token = localStorage.getItem("token");
|
||
if (!token) {
|
||
router.push("/login");
|
||
return;
|
||
}
|
||
|
||
const res = await fetch("/api/cart", {
|
||
method: "POST",
|
||
headers: {
|
||
"Content-Type": "application/json",
|
||
Authorization: `Bearer ${token}`,
|
||
},
|
||
body: JSON.stringify({
|
||
productId: params.id,
|
||
quantity: quantity,
|
||
}),
|
||
});
|
||
|
||
if (!res.ok) {
|
||
throw new Error("添加购物车失败");
|
||
}
|
||
|
||
toast.success("添加成功");
|
||
handleModalClose();
|
||
} catch (error) {
|
||
toast.error(error.message);
|
||
}
|
||
};
|
||
|
||
const handleBuyNow = () => {
|
||
const token = localStorage.getItem("token");
|
||
if (!token) {
|
||
router.push("/login");
|
||
return;
|
||
}
|
||
|
||
router.push(`/checkout?products=${params.id}&quantity=${quantity}`);
|
||
};
|
||
|
||
const handleAddToCartClick = () => {
|
||
const token = localStorage.getItem("token");
|
||
if (!token) {
|
||
router.push("/login");
|
||
return;
|
||
}
|
||
setShowModal(true);
|
||
};
|
||
|
||
const handleModalClose = () => {
|
||
setShowModal(false);
|
||
};
|
||
|
||
if (loading) {
|
||
return <div className="p-4">加载中...</div>;
|
||
}
|
||
|
||
if (error) {
|
||
return <div className="p-4 text-red-500">错误: {error}</div>;
|
||
}
|
||
|
||
if (!product) {
|
||
return <div className="p-4">商品不存在</div>;
|
||
}
|
||
|
||
return (
|
||
<div className="flex flex-col min-h-screen pb-20 bg-gray-50">
|
||
{/* 商品图片 */}
|
||
<div className="relative aspect-square">
|
||
<Image
|
||
src={product.imageUrl}
|
||
alt={product.title}
|
||
fill
|
||
className="object-cover"
|
||
/>
|
||
</div>
|
||
|
||
{/* 商品信息 */}
|
||
<div className="flex-1 p-4 bg-white">
|
||
<div className="flex items-center">
|
||
<span className="text-2xl text-red-500 font-bold">
|
||
¥{product.price}
|
||
</span>
|
||
{product.isVip && (
|
||
<span className="ml-2 px-2 py-0.5 text-xs text-yellow-600 border border-yellow-600 rounded">
|
||
VIP
|
||
</span>
|
||
)}
|
||
</div>
|
||
|
||
<h1 className="mt-2 text-lg font-medium">{product.title}</h1>
|
||
|
||
<div className="mt-2 text-sm text-gray-500">
|
||
<span>库存: {product.stock}件</span>
|
||
<span className="ml-4">销量: {product.sales}件</span>
|
||
</div>
|
||
|
||
{/* 配送信息 */}
|
||
<div className="mt-4 p-3 bg-gray-50 rounded-lg">
|
||
<div className="flex justify-between items-center">
|
||
<span className="text-gray-500">配送</span>
|
||
<span>{product.delivery}</span>
|
||
</div>
|
||
<div className="mt-2 flex justify-between items-center">
|
||
<span className="text-gray-500">服务</span>
|
||
<div className="flex gap-2">
|
||
{product.services.map((service, index) => (
|
||
<span key={index} className="text-sm text-gray-600">
|
||
{service}
|
||
</span>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 商品描述 */}
|
||
<div className="mt-6">
|
||
<h2 className="text-lg font-bold mb-2">商品详情</h2>
|
||
<p className="text-gray-600">{product.description}</p>
|
||
|
||
<h3 className="mt-4 font-bold">产品特点:</h3>
|
||
<ul className="mt-2 space-y-2">
|
||
{product.features.map((feature, index) => (
|
||
<li key={index} className="flex items-center text-gray-600">
|
||
<span className="mr-2">•</span>
|
||
{feature}
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 底部购买栏 */}
|
||
<div className="fixed bottom-0 left-0 right-0 flex items-center p-4 bg-white border-t">
|
||
<button
|
||
className="flex-1 bg-yellow-400 text-white py-2 rounded-full"
|
||
onClick={handleAddToCartClick}
|
||
>
|
||
加入购物车
|
||
</button>
|
||
<button
|
||
className="flex-1 ml-2 bg-red-500 text-white py-2 rounded-full"
|
||
onClick={handleBuyNow}
|
||
>
|
||
立即购买
|
||
</button>
|
||
</div>
|
||
|
||
<AddToCartModal
|
||
isOpen={showModal}
|
||
onClose={handleModalClose}
|
||
product={product}
|
||
quantity={quantity}
|
||
setQuantity={setQuantity}
|
||
onAddToCart={handleAddToCart}
|
||
/>
|
||
</div>
|
||
);
|
||
}
|