diff --git a/app/api/join/route.ts b/app/api/join/route.ts index 0f696fe..2541393 100644 --- a/app/api/join/route.ts +++ b/app/api/join/route.ts @@ -133,6 +133,28 @@ async function tryPocketBaseDirect( const pb = getPocketBaseConfig(); const base = pb.url.replace(/\/$/, ""); + const wechatId = String(record.wechatId ?? "").trim(); + if (wechatId) { + const escaped = wechatId.replace(/\\/g, "\\\\").replace(/"/g, '\\"'); + const filter = encodeURIComponent(`wechatId = "${escaped}"`); + const checkRes = await fetch( + `${base}/api/collections/${pb.joinCollection}/records?filter=${filter}&perPage=1`, + { + headers: { Authorization: `Bearer ${token}` }, + cache: "no-store", + } + ); + if (checkRes.ok) { + const checkData = await checkRes.json(); + if (Array.isArray((checkData as { items?: unknown[] }).items) && (checkData as { items: unknown[] }).items.length > 0) { + return NextResponse.json( + { ok: false, error: "该微信号已报名,请勿重复提交" }, + { status: 400 } + ); + } + } + } + const url = `${base}/api/collections/${pb.joinCollection}/records`; const qualify = !!(record.qualify ?? false); diff --git a/app/join/page.tsx b/app/join/page.tsx index 24133d8..e88dfaa 100644 --- a/app/join/page.tsx +++ b/app/join/page.tsx @@ -142,7 +142,8 @@ export default function JoinPage() { const [paying, setPaying] = useState(false); const initialWechatCheckDone = useRef(false); const lastSubmitTime = useRef(0); - const SUBMIT_THROTTLE_MS = 2000; + const submittingRef = useRef(false); + const SUBMIT_THROTTLE_MS = 3000; const fetchByWechat = async (w: string) => { if (!w.trim()) return; @@ -247,24 +248,12 @@ export default function JoinPage() { setError(null); const now = Date.now(); - if (now - lastSubmitTime.current < SUBMIT_THROTTLE_MS) { - return; - } + if (submittingRef.current) return; + if (now - lastSubmitTime.current < SUBMIT_THROTTLE_MS) return; if (userRecord?.hasRecord) { setError("该微信号已报名,请勿重复提交"); return; } - try { - const checkRes = await fetch(`/api/join/by-wechat?wechat_id=${encodeURIComponent(wechat.trim())}`, { cache: "no-store" }); - const checkData = await checkRes.json(); - if (checkData?.hasRecord) { - setError("该微信号已报名,请勿重复提交"); - fetchByWechat(wechat.trim()); - return; - } - } catch { - /* 校验失败时继续提交,由后端兜底 */ - } if (xiaohongshuUrl.trim() && urlError) { setError("请先修正小红书链接"); return; @@ -285,9 +274,22 @@ export default function JoinPage() { setError("请选择性别"); return; } + + submittingRef.current = true; lastSubmitTime.current = now; setSubmitting(true); + try { + const checkRes = await fetch(`/api/join/by-wechat?wechat_id=${encodeURIComponent(wechat.trim())}`, { cache: "no-store" }); + const checkData = await checkRes.json(); + if (checkData?.hasRecord) { + setError("该微信号已报名,请勿重复提交"); + fetchByWechat(wechat.trim()); + submittingRef.current = false; + setSubmitting(false); + return; + } + const formGenderFemale = gender === "女" || gender === "female"; const postCountOk = (profile?.postCount ?? 0) > 10; const qualify = formGenderFemale && postCountOk; @@ -318,7 +320,7 @@ export default function JoinPage() { why_join: "", region: "", available_time: "", - qualify, // 女性且小红书帖子>10 时自动通过审核 + qualify, is_volunteer: fromVolunteer, }), }); @@ -328,11 +330,19 @@ export default function JoinPage() { } setQualify(qualify); setSubmitted(true); - // 提交成功后立即按微信号查询,用真实记录状态展示(审核中/审核通过等),避免刷新后状态不一致 - fetchByWechat(wechat.trim()); + try { + await fetchByWechat(wechat.trim()); + } catch { + try { + localStorage.setItem(WECHAT_STORAGE_KEY, wechat.trim()); + } catch {} + window.location.replace("/join"); + return; + } } catch (err) { setError(err instanceof Error ? err.message : "网络错误,请重试"); } finally { + submittingRef.current = false; setSubmitting(false); } };