'use client'; import { useState, Suspense } from 'react'; import { useSearchParams } from 'next/navigation'; import { z } from 'zod'; import { ScrollReveal } from '@/components/ui/scroll-reveal'; import { Button } from '@/components/ui/button'; import { LabeledInput as Input } from '@/components/ui/labeled-input'; import { LabeledTextarea as Textarea } from '@/components/ui/labeled-textarea'; import { Toast } from '@/components/ui/toast'; import { Mail, MapPin, Send, Loader2, Clock, HeadphonesIcon, CheckCircle2, HelpCircle, MessageSquare, ArrowRight, } from 'lucide-react'; import { COMPANY_INFO } from '@/lib/constants'; import { trackContactForm, trackConversion } from '@/lib/analytics'; import { BreadcrumbSchema } from '@/components/seo/structured-data'; import { LegacyTooltip as Tooltip } from '@/components/ui/tooltip'; import { cn } from '@/lib/utils'; const contactFormSchema = z.object({ name: z.string().min(2, '姓名至少需要2个字符'), phone: z.string().regex(/^1[3-9]\d{9}$/, '请输入有效的手机号码'), email: z.string().email('请输入有效的邮箱地址'), subject: z.string().min(2, '主题至少需要2个字符'), message: z.string().min(10, '留言内容至少需要10个字符'), }); type ContactFormData = z.infer; interface FormErrors { name?: string; phone?: string; email?: string; subject?: string; message?: string; } const FAQ_ITEMS = [ { q: '你们的服务流程是怎样的?', a: '通常分四步:需求沟通 → 方案评估 → 签约启动 → 敏捷交付。首次咨询免费,我们会在 2 个工作日内给出初步方案建议。', }, { q: '收费模式是怎样的?', a: '根据项目规模和合作模式灵活定价。项目制按里程碑付款,订阅制按月结算,长期陪跑模式可协商年度合作方案。', }, { q: '数据安全如何保障?', a: '我们严格遵守数据保护规范,签署保密协议,采用加密传输和权限隔离。项目结束后,客户数据按要求彻底清除。', }, { q: '项目周期一般多长?', a: '小型项目 2-4 周,中型项目 1-3 个月,大型项目按阶段推进。我们会在方案评估阶段给出明确的时间线。', }, ]; function GrainOverlay() { return (
); } function SectionLabel({ children, className = '' }: { children: React.ReactNode; className?: string }) { return (
{children}
); } function ContactFormContent() { const searchParams = useSearchParams(); const isSuccessFromRedirect = searchParams.get('success') === 'true'; const [showToast, setShowToast] = useState(isSuccessFromRedirect); const [toastMessage, setToastMessage] = useState( isSuccessFromRedirect ? '表单提交成功!我们会尽快与您联系。' : '' ); const [toastType, setToastType] = useState<'success' | 'error'>( isSuccessFromRedirect ? 'success' : 'success' ); const [isSubmitting, setIsSubmitting] = useState(false); const [isSubmitted, setIsSubmitted] = useState(isSuccessFromRedirect); const [formData, setFormData] = useState({ name: '', phone: '', email: '', subject: '', message: '', }); const [errors, setErrors] = useState({}); const validateField = (field: keyof ContactFormData, value: string) => { try { contactFormSchema.shape[field].parse(value); setErrors((prev) => ({ ...prev, [field]: undefined })); } catch (error) { if (error instanceof z.ZodError) { const fieldError = error.issues[0]; if (fieldError) { setErrors((prev) => ({ ...prev, [field]: fieldError.message })); } } } }; const handleChange = (field: keyof ContactFormData, value: string) => { setFormData((prev) => ({ ...prev, [field]: value })); if (errors[field]) { validateField(field, value); } }; const handleBlur = (field: keyof ContactFormData, value: string) => { validateField(field, value); }; async function handleSubmit(e: React.FormEvent) { e.preventDefault(); const result = contactFormSchema.safeParse(formData); if (!result.success) { const fieldErrors: FormErrors = {}; result.error.issues.forEach((issue) => { const field = issue.path[0] as keyof ContactFormData; fieldErrors[field] = issue.message; }); setErrors(fieldErrors); setToastMessage(`请检查表单:${Object.keys(fieldErrors).length} 项内容需要修正`); setToastType('error'); setShowToast(true); const firstErrorField = document.querySelector('[data-testid*="-input"][aria-invalid="true"]') as HTMLElement; firstErrorField?.scrollIntoView({ behavior: 'smooth', block: 'center' }); firstErrorField?.focus(); return; } setIsSubmitting(true); try { const formBody = new URLSearchParams(); formBody.append('name', formData.name); formBody.append('phone', formData.phone); formBody.append('email', formData.email); formBody.append('subject', formData.subject); formBody.append('message', formData.message); const response = await fetch('/api/contact', { method: 'POST', body: formBody, }); const data = await response.json(); if (response.ok && (data.success === 'true' || data.success === true)) { trackContactForm({ name: formData.name, email: formData.email, company: formData.subject, }); trackConversion('contact_form_submission'); setToastMessage('表单提交成功!我们会尽快与您联系。'); setToastType('success'); setShowToast(true); setIsSubmitted(true); setFormData({ name: '', phone: '', email: '', subject: '', message: '' }); setErrors({}); } else { const errorMsg = data.message || '提交失败,请稍后重试或直接发送邮件联系我们。'; if (errorMsg.includes('HTML files') || errorMsg.includes('web server')) { setToastMessage('表单服务需要在生产环境激活。部署后首次提交会发送确认邮件到 ' + COMPANY_INFO.email); } else { setToastMessage(errorMsg); } setToastType('error'); setShowToast(true); } } catch { setToastMessage('网络错误,请稍后重试。'); setToastType('error'); setShowToast(true); } finally { setIsSubmitting(false); } } return (
{showToast && ( setShowToast(false)} /> )} {/* Hero Section */}
Contact Us

工作日 2 小时内快速响应,首次咨询免费

随时欢迎 聊一聊

无论是一个明确的项目需求,还是一个模糊的想法,我们都愿意坐下来和您一起理清楚。没有任何销售压力。

{/* Form + Info Section */}
{/* Left: Contact Info */}

联系方式

地址

{COMPANY_INFO.address}

工作时间

周一至周五 9:00 - 18:00

我们的承诺

工作日 2 小时内快速响应您的咨询

提供免费的业务咨询和方案评估服务

根据您的需求量身定制最优解决方案

{/* Right: Form */}

发送消息

{isSubmitted ? (

消息已发送

感谢您的留言,我们会尽快与您联系!

) : (
姓名 } id="name" placeholder="请输入您的姓名" required value={formData.name} onChange={(e) => handleChange('name', e.target.value)} onBlur={(e) => handleBlur('name', e.target.value)} error={errors.name} className="bg-ink-light border-white/10 text-white placeholder:text-white/30 focus:border-brand/50" />
电话 } id="phone" type="tel" placeholder="请输入11位手机号" required value={formData.phone} onChange={(e) => handleChange('phone', e.target.value)} onBlur={(e) => handleBlur('phone', e.target.value)} error={errors.phone} className="bg-ink-light border-white/10 text-white placeholder:text-white/30 focus:border-brand/50" />
handleChange('email', e.target.value)} onBlur={(e) => handleBlur('email', e.target.value)} error={errors.email} className="bg-ink-light border-white/10 text-white placeholder:text-white/30 focus:border-brand/50" /> handleChange('subject', e.target.value)} onBlur={(e) => handleBlur('subject', e.target.value)} error={errors.subject} className="bg-ink-light border-white/10 text-white placeholder:text-white/30 focus:border-brand/50" />