AwsLinker/app/components/products/ProductModal.tsx

203 lines
9.7 KiB
TypeScript
Raw Normal View History

2025-09-16 17:19:58 +08:00
'use client';
import { useState, useEffect } from 'react';
interface Product {
name: string;
desc: string;
price: string;
features: string[];
badge?: string;
popular?: boolean;
}
interface ProductModalProps {
product: Product | null;
isOpen: boolean;
onClose: () => void;
contactText: string;
locale: string;
}
export default function ProductModal({ product, isOpen, onClose, contactText, locale }: ProductModalProps) {
const [isVisible, setIsVisible] = useState(false);
useEffect(() => {
if (isOpen) {
setIsVisible(true);
// 保存原始的overflow值
const originalOverflow = document.body.style.overflow;
document.body.style.overflow = 'hidden';
return () => {
// 恢复原始的overflow值
document.body.style.overflow = originalOverflow || 'unset';
};
} else {
// 延迟恢复overflow允许动画完成
const timer = setTimeout(() => {
document.body.style.overflow = 'unset';
}, 300);
return () => {
clearTimeout(timer);
};
}
}, [isOpen]);
const handleClose = () => {
setIsVisible(false);
setTimeout(() => {
onClose();
}, 300);
};
if (!isOpen || !product) return null;
return (
<div className={`fixed inset-0 z-50 flex items-center justify-center p-4 transition-opacity duration-300 ${
isVisible ? 'opacity-100' : 'opacity-0'
}`}>
{/* 背景遮罩 */}
<div
className="absolute inset-0 bg-black bg-opacity-50 backdrop-blur-sm"
onClick={handleClose}
/>
{/* 模态框内容 */}
<div className={`relative bg-white rounded-2xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-y-auto transform transition-all duration-300 ${
isVisible ? 'scale-100 translate-y-0' : 'scale-95 translate-y-4'
}`}>
{/* 关闭按钮 */}
<button
onClick={handleClose}
title="关闭"
aria-label="关闭产品详情"
className="absolute top-4 right-4 z-10 w-8 h-8 bg-gray-100 hover:bg-gray-200 rounded-full flex items-center justify-center transition-colors duration-200"
>
<svg className="w-5 h-5 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
{/* 产品标签 */}
<div className="absolute top-4 left-4 z-10 flex gap-2">
{product.badge && (
<span className="bg-blue-600 text-white text-xs font-semibold px-3 py-1 rounded-full shadow-lg">
{product.badge}
</span>
)}
{product.popular && (
<span className="bg-gradient-to-r from-orange-400 to-red-500 text-white text-xs font-bold px-3 py-1 rounded-full shadow-lg">
🔥
</span>
)}
</div>
<div className="p-8 pt-16">
{/* 产品标题和价格 */}
<div className="mb-6">
<h2 className="text-3xl font-bold text-gray-900 mb-4">
{product.name}
</h2>
<div className="text-4xl font-bold text-blue-600 mb-4">
{product.price}
{product.price.includes('/月') && (
<span className="text-lg text-gray-500 ml-2 font-normal">
</span>
)}
</div>
</div>
{/* 产品描述 */}
<div className="mb-8">
<h3 className="text-lg font-semibold text-gray-900 mb-3"></h3>
<p className="text-gray-700 leading-relaxed">
{product.desc}
</p>
</div>
{/* 功能特性 */}
<div className="mb-8">
<h3 className="text-lg font-semibold text-gray-900 mb-4"></h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
{product.features.map((feature, index) => (
<div key={index} className="flex items-center">
<svg
className="w-5 h-5 text-green-500 mr-3 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="text-gray-700">{feature}</span>
</div>
))}
</div>
</div>
{/* 适用场景 */}
<div className="mb-8">
<h3 className="text-lg font-semibold text-gray-900 mb-3"></h3>
<div className="bg-blue-50 rounded-lg p-4">
<p className="text-blue-800 text-sm">
{getUseCases(product.name)}
</p>
</div>
</div>
{/* 操作按钮 */}
<div className="flex flex-col sm:flex-row gap-4">
<a
href={locale === 'zh-CN' ? '/contact' : `/${locale}/contact`}
className={`flex-1 py-4 px-6 rounded-lg font-semibold text-center transition-all duration-300 ${
product.popular
? '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}
</a>
<button
onClick={handleClose}
className="flex-1 py-4 px-6 border-2 border-gray-300 text-gray-700 rounded-lg font-semibold hover:bg-gray-50 transition-colors duration-300"
>
</button>
</div>
</div>
</div>
</div>
);
}
function getUseCases(productName: string): string {
const useCases: { [key: string]: string } = {
'轻量云服务器': '个人博客、小型企业官网、开发测试环境、学习实验、小型应用部署',
'EC2通用型服务器': 'Web应用、企业级应用、微服务架构、API服务、中等规模网站',
'EC2计算优化型': '科学计算、机器学习训练、高性能Web服务、数据分析、视频处理',
'站群服务器': 'SEO优化、多站点管理、内容分发、营销推广、大规模网站集群',
'高防服务器': '游戏服务器、金融应用、电商平台、直播平台、高价值业务系统',
'WAF Web防火墙': 'Web应用保护、API安全、电商网站、企业门户、在线服务平台',
'SSL证书服务': '网站HTTPS加密、API接口安全、移动应用、电商交易、数据传输保护',
'S3对象存储': '网站静态资源、数据备份归档、大数据分析、内容分发、移动应用存储',
'EBS块存储': '数据库存储、文件系统、企业应用、高IOPS应用、关键业务数据',
'EFS文件存储': '内容管理系统、Web服务、大数据分析、媒体处理、共享文件存储',
'RDS关系型数据库': '企业应用、电商系统、CRM系统、ERP系统、数据仓库',
'Redis缓存服务': '会话存储、实时排行榜、消息队列、计数器、高并发缓存',
'MongoDB文档数据库': '内容管理、物联网数据、实时分析、移动应用、社交平台',
'CDN内容分发': '网站加速、视频点播、游戏更新、软件下载、全球内容分发',
'负载均衡器': '高可用架构、流量分发、故障转移、弹性扩容、微服务架构',
'VPN专线服务': '企业组网、远程办公、数据中心互联、混合云架构、安全连接',
'机器学习平台': '模型训练、数据挖掘、预测分析、推荐系统、智能决策',
'图像识别API': '人脸识别、内容审核、智能相册、安防监控、医疗影像',
'语音识别API': '智能客服、语音助手、会议记录、语音翻译、语音控制'
};
return useCases[productName] || '适用于各种业务场景,具体请咨询我们的技术专家';
}