From 46cff87f27579541248bfb1ceb026342264e98e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E7=BF=94?= Date: Tue, 21 Apr 2026 08:31:35 +0800 Subject: [PATCH] =?UTF-8?q?fix(contact):=20=E5=88=87=E6=8D=A2=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E6=9C=8D=E5=8A=A1=E5=88=B0=20FormSubmit=20=E5=B9=B6?= =?UTF-8?q?=E6=94=B9=E8=BF=9B=E9=94=99=E8=AF=AF=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 将表单提交服务从 Formspree 切换到 FormSubmit(无需 API Key) - 添加成功状态 URL 参数处理(?success=true) - 改进错误提示,区分开发环境和生产环境 - 添加 _next 参数支持成功后重定向 - 重构状态初始化避免 useEffect 中同步调用 setState --- src/app/(marketing)/contact/page.tsx | 55 +++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 10 deletions(-) diff --git a/src/app/(marketing)/contact/page.tsx b/src/app/(marketing)/contact/page.tsx index 57072c5..9d16202 100644 --- a/src/app/(marketing)/contact/page.tsx +++ b/src/app/(marketing)/contact/page.tsx @@ -1,6 +1,7 @@ 'use client'; import { useState, useEffect, useRef } from 'react'; +import { useSearchParams } from 'next/navigation'; import { z } from 'zod'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; @@ -28,12 +29,18 @@ interface FormErrors { } export default function ContactPage() { + const searchParams = useSearchParams(); + const isSuccessFromRedirect = searchParams.get('success') === 'true'; const [isVisible, setIsVisible] = useState(false); - const [showToast, setShowToast] = useState(false); - const [toastMessage, setToastMessage] = useState(''); - const [toastType, setToastType] = useState<'success' | 'error'>('success'); + 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(false); + const [isSubmitted, setIsSubmitted] = useState(isSuccessFromRedirect); const [formData, setFormData] = useState({ name: '', phone: '', @@ -43,6 +50,7 @@ export default function ContactPage() { }); const [errors, setErrors] = useState({}); const sectionRef = useRef(null); + const hasProcessedSuccess = useRef(isSuccessFromRedirect); useEffect(() => { requestAnimationFrame(() => { @@ -50,6 +58,13 @@ export default function ContactPage() { }); }, []); + useEffect(() => { + if (isSuccessFromRedirect && !hasProcessedSuccess.current) { + hasProcessedSuccess.current = true; + window.history.replaceState({}, '', '/contact'); + } + }, [isSuccessFromRedirect]); + const validateField = (field: keyof ContactFormData, value: string) => { try { contactFormSchema.shape[field].parse(value); @@ -92,21 +107,41 @@ export default function ContactPage() { setIsSubmitting(true); try { - const response = await fetch('https://formspree.io/f/' + process.env.NEXT_PUBLIC_FORMSPREE_ID, { + const formEndpoint = `https://formsubmit.co/${COMPANY_INFO.email}`; + 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); + formBody.append('_subject', `网站留言: ${formData.subject}`); + formBody.append('_captcha', 'false'); + formBody.append('_template', 'table'); + formBody.append('_next', `${window.location.origin}/contact?success=true`); + + const response = await fetch(formEndpoint, { method: 'POST', - headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' }, - body: JSON.stringify(formData), + headers: { 'Accept': 'application/json' }, + body: formBody, }); - if (response.ok) { + const data = await response.json(); + + if (response.ok && data.success === 'true') { setIsSubmitted(true); setToastMessage('表单提交成功!我们会尽快与您联系。'); setToastType('success'); setShowToast(true); setFormData({ name: '', phone: '', email: '', subject: '', message: '' }); } else { - setToastMessage('提交失败,请稍后重试或直接发送邮件联系我们。'); - setToastType('error'); + const errorMsg = data.message || '提交失败,请稍后重试或直接发送邮件联系我们。'; + if (errorMsg.includes('HTML files') || errorMsg.includes('web server')) { + setToastMessage('表单服务需要在生产环境激活。部署后首次提交会发送确认邮件到 ' + COMPANY_INFO.email); + setToastType('error'); + } else { + setToastMessage(errorMsg); + setToastType('error'); + } setShowToast(true); } } catch {