feat: 添加 AoyagiReisho 书法字体并优化表单反馈
- 使用 next/font/local 加载 AoyagiReisho.ttf 字体 - 为标题红色高亮文字应用书法字体样式 - 优化联系表单提交反馈,添加成功/失败提示 - 修复 section 参数滚动定位的时序问题
This commit is contained in:
@@ -50,7 +50,6 @@ function ContactFormContent() {
|
||||
});
|
||||
const [errors, setErrors] = useState<FormErrors>({});
|
||||
const sectionRef = useRef<HTMLElement>(null);
|
||||
const hasProcessedSuccess = useRef(isSuccessFromRedirect);
|
||||
|
||||
useEffect(() => {
|
||||
requestAnimationFrame(() => {
|
||||
@@ -58,13 +57,6 @@ function ContactFormContent() {
|
||||
});
|
||||
}, []);
|
||||
|
||||
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);
|
||||
@@ -106,8 +98,9 @@ function ContactFormContent() {
|
||||
}
|
||||
|
||||
setIsSubmitting(true);
|
||||
|
||||
try {
|
||||
const formEndpoint = `https://formsubmit.co/${COMPANY_INFO.email}`;
|
||||
const formEndpoint = `https://formsubmit.co/ajax/${COMPANY_INFO.email}`;
|
||||
const formBody = new URLSearchParams();
|
||||
formBody.append('name', formData.name);
|
||||
formBody.append('phone', formData.phone);
|
||||
@@ -117,31 +110,30 @@ function ContactFormContent() {
|
||||
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: { 'Accept': 'application/json' },
|
||||
body: formBody,
|
||||
});
|
||||
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (response.ok && data.success === 'true') {
|
||||
setIsSubmitted(true);
|
||||
|
||||
if (response.ok && (data.success === 'true' || data.success === true)) {
|
||||
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);
|
||||
setToastType('error');
|
||||
} else {
|
||||
setToastMessage(errorMsg);
|
||||
setToastType('error');
|
||||
}
|
||||
setToastType('error');
|
||||
setShowToast(true);
|
||||
}
|
||||
} catch {
|
||||
@@ -180,7 +172,7 @@ function ContactFormContent() {
|
||||
<span className="text-sm text-[#5C5C5C] tracking-wide" data-testid="page-badge">联系我们</span>
|
||||
</div>
|
||||
<h1 className="text-4xl md:text-5xl font-bold text-[#1C1C1C] mb-4">
|
||||
开启 <span className="text-[#C41E3A]">合作</span>
|
||||
开启 <span className="text-[#C41E3A] font-calligraphy">合作</span>
|
||||
</h1>
|
||||
<p className="mt-4 text-[#5C5C5C] max-w-2xl" data-testid="page-description">
|
||||
无论您有任何问题或合作意向,我们都很乐意与您交流
|
||||
|
||||
@@ -51,17 +51,31 @@ function HomeContent() {
|
||||
|
||||
useEffect(() => {
|
||||
const section = searchParams.get('section');
|
||||
if (section) {
|
||||
const timer = setTimeout(() => {
|
||||
const targetElement = document.getElementById(section);
|
||||
if (targetElement) {
|
||||
targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
}
|
||||
}, 100);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
return undefined;
|
||||
if (!section) {return;}
|
||||
|
||||
const maxAttempts = 50;
|
||||
const interval = 100;
|
||||
let attempts = 0;
|
||||
|
||||
const scrollToSection = () => {
|
||||
const targetElement = document.getElementById(section);
|
||||
if (targetElement) {
|
||||
targetElement.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (scrollToSection()) {return;}
|
||||
|
||||
const timer = setInterval(() => {
|
||||
attempts++;
|
||||
if (scrollToSection() || attempts >= maxAttempts) {
|
||||
clearInterval(timer);
|
||||
}
|
||||
}, interval);
|
||||
|
||||
return () => clearInterval(timer);
|
||||
}, [searchParams]);
|
||||
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user