209 lines
11 KiB
TypeScript
209 lines
11 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import Link from 'next/link';
|
|
import ProductModal from './ProductModal';
|
|
|
|
interface Product {
|
|
name: string;
|
|
desc: string;
|
|
price: string;
|
|
features: string[];
|
|
badge?: string;
|
|
popular?: boolean;
|
|
}
|
|
|
|
interface Category {
|
|
title: string;
|
|
products: Product[];
|
|
}
|
|
|
|
interface ProductsClientComponentProps {
|
|
categories: Category[];
|
|
contactText: string;
|
|
locale: string;
|
|
}
|
|
|
|
export default function ProductsClientComponent({ categories, contactText, locale }: ProductsClientComponentProps) {
|
|
const [selectedProduct, setSelectedProduct] = useState<Product | null>(null);
|
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
const [clickedProduct, setClickedProduct] = useState<string | null>(null);
|
|
|
|
// 类别标题到锚点ID的映射
|
|
const getCategoryId = (title: string) => {
|
|
const mapping: { [key: string]: string } = {
|
|
'云服务器': 'cloud-server',
|
|
'雲服務器': 'cloud-server',
|
|
'Cloud Server': 'cloud-server',
|
|
'安全防护': 'security',
|
|
'安全防護': 'security',
|
|
'Security': 'security',
|
|
'存储服务': 'storage',
|
|
'存儲服務': 'storage',
|
|
'Storage': 'storage',
|
|
'数据库服务': 'database',
|
|
'數據庫服務': 'database',
|
|
'Database': 'database',
|
|
'网络服务': 'network',
|
|
'網絡服務': 'network',
|
|
'Network': 'network',
|
|
'人工智能': 'ai',
|
|
'人工智慧': 'ai',
|
|
'AI': 'ai'
|
|
};
|
|
return mapping[title] || title.toLowerCase().replace(/\s+/g, '-');
|
|
};
|
|
|
|
const handleProductClick = (product: Product) => {
|
|
setSelectedProduct(product);
|
|
setIsModalOpen(true);
|
|
};
|
|
|
|
const handleCardClick = (productName: string) => {
|
|
setClickedProduct(clickedProduct === productName ? null : productName);
|
|
};
|
|
|
|
const handleCloseModal = () => {
|
|
setIsModalOpen(false);
|
|
setSelectedProduct(null);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
{/* Products Section */}
|
|
<section className="py-20">
|
|
<div className="container mx-auto px-6">
|
|
{categories.map((category, categoryIndex) => (
|
|
<div key={categoryIndex} id={getCategoryId(category.title)} className="mb-20 scroll-mt-20">
|
|
<div className="text-center mb-16">
|
|
<h2 className="text-4xl font-bold text-gray-900 mb-4">
|
|
{category.title}
|
|
</h2>
|
|
<div className="w-24 h-1 bg-gradient-to-r from-blue-600 to-purple-600 mx-auto rounded-full"></div>
|
|
</div>
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8">
|
|
{category.products.map((product, productIndex) => (
|
|
<div
|
|
key={productIndex}
|
|
onClick={() => handleCardClick(product.name)}
|
|
className={`bg-white rounded-xl shadow-sm hover:shadow-xl transition-all duration-300 overflow-hidden hover:-translate-y-2 relative group cursor-pointer ${
|
|
clickedProduct === product.name ? 'ring-2 ring-blue-500 ring-opacity-50' : ''
|
|
}`}
|
|
>
|
|
{/* 产品标签 */}
|
|
{(product as any).badge && (
|
|
<div className="absolute top-3 left-3 z-10">
|
|
<span className="bg-blue-600 text-white text-xs font-semibold px-2 py-1 rounded-md shadow-lg">
|
|
{(product as any).badge}
|
|
</span>
|
|
</div>
|
|
)}
|
|
|
|
{/* 热门标签 */}
|
|
{(product as any).popular && (
|
|
<div className="absolute top-3 right-3 z-10">
|
|
<span className="bg-gradient-to-r from-orange-400 to-red-500 text-white text-xs font-bold px-2 py-1 rounded-md shadow-lg">
|
|
🔥 热门
|
|
</span>
|
|
</div>
|
|
)}
|
|
|
|
<div className="p-6 pt-10">
|
|
<div className="mb-4">
|
|
<h3 className="text-xl font-bold text-gray-900 mb-3 leading-tight group-hover:text-blue-600 transition-colors duration-300">
|
|
{product.name}
|
|
</h3>
|
|
<p className="text-gray-600 text-sm leading-relaxed overflow-hidden" style={{
|
|
display: '-webkit-box',
|
|
WebkitLineClamp: 3,
|
|
WebkitBoxOrient: 'vertical'
|
|
}}>
|
|
{product.desc}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="mb-6">
|
|
<div className="text-2xl font-bold text-blue-600 mb-4 flex items-baseline">
|
|
{product.price}
|
|
{product.price.includes('/月') && (
|
|
<span className="text-sm text-gray-500 ml-2 font-normal">
|
|
按月计费
|
|
</span>
|
|
)}
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
{product.features.slice(0, 4).map((feature, featureIndex) => (
|
|
<div
|
|
key={featureIndex}
|
|
className="flex items-center text-gray-700 text-sm"
|
|
>
|
|
<svg
|
|
className="w-4 h-4 text-green-500 mr-2 flex-shrink-0"
|
|
fill="currentColor"
|
|
viewBox="0 0 20 20"
|
|
>
|
|
<path
|
|
fillRule="evenodd"
|
|
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
|
|
clipRule="evenodd"
|
|
/>
|
|
</svg>
|
|
<span className="truncate">{feature}</span>
|
|
</div>
|
|
))}
|
|
{product.features.length > 4 && (
|
|
<div className="text-xs text-gray-500 mt-2">
|
|
+{product.features.length - 4} 更多功能
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-3">
|
|
<Link
|
|
href={
|
|
locale === 'zh-CN'
|
|
? '/contact'
|
|
: `/${locale}/contact`
|
|
}
|
|
onClick={(e) => e.stopPropagation()}
|
|
className={`w-full py-3 px-4 rounded-lg font-semibold transition-all duration-300 text-center block text-sm ${
|
|
clickedProduct === product.name
|
|
? 'bg-gradient-to-r from-blue-600 to-purple-600 text-white hover:from-blue-700 hover:to-purple-700 shadow-lg'
|
|
: 'bg-blue-600 text-white hover:bg-blue-700'
|
|
}`}
|
|
>
|
|
{contactText}
|
|
</Link>
|
|
|
|
<button
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
handleProductClick(product);
|
|
}}
|
|
className="w-full py-2 px-4 border border-gray-300 text-gray-700 rounded-lg font-medium hover:bg-gray-50 transition-colors duration-300 text-sm"
|
|
>
|
|
查看详情
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</section>
|
|
|
|
{/* 产品详情模态框 */}
|
|
<ProductModal
|
|
product={selectedProduct}
|
|
isOpen={isModalOpen}
|
|
onClose={handleCloseModal}
|
|
contactText={contactText}
|
|
locale={locale}
|
|
/>
|
|
</>
|
|
);
|
|
}
|