From 40cbda117db7290461139d81cf686fc6df3c1901 Mon Sep 17 00:00:00 2001 From: Snowykami Date: Wed, 10 Sep 2025 21:36:35 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E7=A0=81=E7=BB=84=E4=BB=B6=EF=BC=8C=E6=B7=BB=E5=8A=A0=20onAbor?= =?UTF-8?q?t=20=E5=A4=84=E7=90=86=EF=BC=8C=E4=BC=98=E5=8C=96=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E7=8A=B6=E6=80=81=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web/src/components/common/captcha/index.tsx | 1 + .../components/common/captcha/turnstile.tsx | 22 +++++++++++++++---- web/src/components/login/login-form.tsx | 15 +++++++++---- web/src/components/user/user-profile.tsx | 6 ++--- web/src/locales/zh-CN.json | 2 +- 5 files changed, 33 insertions(+), 13 deletions(-) diff --git a/web/src/components/common/captcha/index.tsx b/web/src/components/common/captcha/index.tsx index 88a9b3a..174df66 100644 --- a/web/src/components/common/captcha/index.tsx +++ b/web/src/components/common/captcha/index.tsx @@ -15,6 +15,7 @@ export type CaptchaProps = { url?: string; onSuccess: (token: string) => void; onError: (error: string) => void; + onAbort?: () => void; }; export function ReCaptchaWidget(props: CaptchaProps) { diff --git a/web/src/components/common/captcha/turnstile.tsx b/web/src/components/common/captcha/turnstile.tsx index c6be410..dc3b4a6 100644 --- a/web/src/components/common/captcha/turnstile.tsx +++ b/web/src/components/common/captcha/turnstile.tsx @@ -1,7 +1,9 @@ -import { useState } from "react"; +import { useEffect, useState } from "react"; import { CaptchaProps } from "."; import { Turnstile } from "@marsidev/react-turnstile"; import { useTranslations } from "next-intl"; + +const TURNSTILE_TIMEOUT = 15 // 简单的转圈圈动画 function Spinner() { return ( @@ -39,14 +41,14 @@ function ErrorMark() { export function OfficialTurnstileWidget(props: CaptchaProps) { return
- +
; } -// 自定义包装组件 export function TurnstileWidget(props: CaptchaProps) { const t = useTranslations("Captcha"); const [status, setStatus] = useState<'loading' | 'success' | 'error'>('loading'); + const [error, setError] = useState(null); // 只在验证通过时才显示勾 const handleSuccess = (token: string) => { @@ -56,15 +58,27 @@ export function TurnstileWidget(props: CaptchaProps) { const handleError = (error: string) => { setStatus('error'); + setError(error); props.onError && props.onError(error); }; + useEffect(() => { + const timer = setTimeout(() => { + if (status === 'loading') { + setStatus('error'); + setError('timeout'); + props.onError && props.onError('timeout'); + } + }, TURNSTILE_TIMEOUT * 1000); + return () => clearTimeout(timer); + }) + return (
{status === 'loading' && } {status === 'success' && } {status === 'error' && } -
{status === 'success' ? t("success") : (status === 'error' ? t("error") : t("doing"))}
+
{status === 'success' ? t("success") : (status === 'error' ? t("error") : t("doing"))} {error && t(error)}
diff --git a/web/src/components/login/login-form.tsx b/web/src/components/login/login-form.tsx index 495e985..0e641c7 100644 --- a/web/src/components/login/login-form.tsx +++ b/web/src/components/login/login-form.tsx @@ -34,6 +34,7 @@ export function LoginForm({ } | null>(null) const [captchaToken, setCaptchaToken] = useState(null) const [captchaError, setCaptchaError] = useState(null) + const [refreshCaptchaKey, setRefreshCaptchaKey] = useState(0) const [{ username, password }, setCredentials] = useState({ username: '', password: '' }) const router = useRouter() const searchParams = useSearchParams() @@ -58,7 +59,7 @@ export function LoginForm({ .catch((error) => { console.error("Error fetching captcha config:", error) }) - }, []) + }, [refreshCaptchaKey]) const handleLogin = async (e: React.FormEvent) => { e.preventDefault() @@ -71,6 +72,14 @@ export function LoginForm({ } } + const handleCaptchaError = (error: string) => { + setCaptchaError(error); + // 刷新验证码 + setTimeout(() => { + setRefreshCaptchaKey(k => k + 1); + }, 1500); + } + return (
@@ -148,11 +157,9 @@ export function LoginForm({
{captchaProps &&
- +
} - {captchaError &&
- {t("captcha_error")}
}
); } \ No newline at end of file diff --git a/web/src/locales/zh-CN.json b/web/src/locales/zh-CN.json index 8240ba3..2903ec7 100644 --- a/web/src/locales/zh-CN.json +++ b/web/src/locales/zh-CN.json @@ -4,7 +4,7 @@ }, "Captcha": { "doing": "正在检测你是不是机器人...", - "error": "验证失败,请重试。", + "error": "验证失败", "success": "恭喜,你是人类!" }, "Comment": {