AwsLinker/app/components/products/ProductModal.tsx
2025-09-16 17:19:58 +08:00

203 lines
9.7 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.

'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] || '适用于各种业务场景,具体请咨询我们的技术专家';
}