From e30d4ad950cf129b01d1f42a6c67d05423ded9b5 Mon Sep 17 00:00:00 2001 From: eric Date: Mon, 16 Mar 2026 19:17:06 -0500 Subject: [PATCH] 's' --- app/api/join/by-wechat/route.ts | 61 +++++++++++++++----------- app/join/page.tsx | 76 ++++++++++++++++++++++++--------- 2 files changed, 92 insertions(+), 45 deletions(-) diff --git a/app/api/join/by-wechat/route.ts b/app/api/join/by-wechat/route.ts index ddbd95e..2d96cc0 100644 --- a/app/api/join/by-wechat/route.ts +++ b/app/api/join/by-wechat/route.ts @@ -13,29 +13,10 @@ const empty = { vip: false, }; -/** 按 wechatId 查询 solanRed 记录,优先 salonapi */ -export async function GET(request: NextRequest) { - const wechatId = request.nextUrl.searchParams.get("wechat_id")?.trim(); - if (!wechatId) { - return NextResponse.json(empty); - } - - try { - const { status, data } = await getSalonApi( - request, - `/api/salon/join/by-wechat?wechat_id=${encodeURIComponent(wechatId)}`, - { timeoutMs: 8000 } - ); - if (status === 200 && data && typeof data === "object") { - return NextResponse.json(data); - } - } catch { - // salonapi 不可用,回退到直连 PocketBase - } - +async function getPocketBaseJoinByWechat(wechatId: string) { const token = await getAdminToken(); if (!token) { - return NextResponse.json(empty); + return null; } const pb = getPocketBaseConfig(); @@ -45,7 +26,7 @@ export async function GET(request: NextRequest) { try { const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), 8000); + const timeoutId = setTimeout(() => controller.abort(), 4000); const res = await fetch( `${base}/api/collections/${pb.joinCollection}/records?filter=${filter}&sort=-created&perPage=1`, { @@ -54,7 +35,7 @@ export async function GET(request: NextRequest) { signal: controller.signal, } ).finally(() => clearTimeout(timeoutId)); - if (!res.ok) return NextResponse.json(empty); + if (!res.ok) return null; const data = await res.json(); const items = Array.isArray(data?.items) ? data.items : []; const rec = items[0] ?? null; @@ -66,7 +47,7 @@ export async function GET(request: NextRequest) { const isRejected = !!rec?.is_rejected; const vip = !!rec?.vip; - return NextResponse.json({ + return { hasRecord, record: rec, isComplete, @@ -74,8 +55,36 @@ export async function GET(request: NextRequest) { isApproved, isRejected, vip, - }); + }; } catch { - return NextResponse.json(empty); + return null; } } + +/** 按 wechatId 查询 solanRed 记录。优先 salonapi(记录由其创建,线上部署时更可靠),失败时回退直连 PocketBase */ +export async function GET(request: NextRequest) { + const wechatId = request.nextUrl.searchParams.get("wechat_id")?.trim(); + if (!wechatId) { + return NextResponse.json(empty); + } + + try { + const { status, data } = await getSalonApi( + request, + `/api/salon/join/by-wechat?wechat_id=${encodeURIComponent(wechatId)}`, + { timeoutMs: 6000 } + ); + if (status === 200 && data && typeof data === "object") { + return NextResponse.json(data); + } + } catch { + /* salonapi 不可用,回退直连 PocketBase */ + } + + const pbData = await getPocketBaseJoinByWechat(wechatId); + if (pbData) { + return NextResponse.json(pbData); + } + + return NextResponse.json(empty); +} diff --git a/app/join/page.tsx b/app/join/page.tsx index e88dfaa..fd7b44c 100644 --- a/app/join/page.tsx +++ b/app/join/page.tsx @@ -77,6 +77,28 @@ interface UserRecord { vip: boolean; } +const EMPTY_USER_RECORD: UserRecord = { + hasRecord: false, + record: null, + isComplete: false, + isWechatFriend: false, + isApproved: false, + isRejected: false, + vip: false, +}; + +function toUserRecord(data: Partial & { record?: UserRecord["record"] }): UserRecord { + return { + hasRecord: !!data.hasRecord, + record: data.record ?? null, + isComplete: !!data.isComplete, + isWechatFriend: !!data.isWechatFriend, + isApproved: !!data.isApproved, + isRejected: !!data.isRejected, + vip: !!data.vip, + }; +} + function UserProfileCard({ record, showVolunteerTag }: { record: UserRecord["record"]; showVolunteerTag?: boolean }) { if (!record || (!record.nickname && !record.media && !record.wechatId)) return null; const isVolunteer = showVolunteerTag && record.is_volunteer; @@ -146,23 +168,20 @@ export default function JoinPage() { const SUBMIT_THROTTLE_MS = 3000; const fetchByWechat = async (w: string) => { - if (!w.trim()) return; + if (!w.trim()) return null; setError(null); setCheckingWechat(true); try { - const res = await fetch(`/api/join/by-wechat?wechat_id=${encodeURIComponent(w.trim())}`); - const data = await res.json(); - setUserRecord({ - hasRecord: !!data.hasRecord, - record: data.record ?? null, - isComplete: !!data.isComplete, - isWechatFriend: !!data.isWechatFriend, - isApproved: !!data.isApproved, - isRejected: !!data.isRejected, - vip: !!data.vip, + const res = await fetch(`/api/join/by-wechat?wechat_id=${encodeURIComponent(w.trim())}`, { + cache: "no-store", }); + const data = await res.json(); + const nextRecord = toUserRecord(data); + setUserRecord(nextRecord); + return nextRecord; } catch { - setUserRecord({ hasRecord: false, record: null, isComplete: false, isWechatFriend: false, isApproved: false, isRejected: false, vip: false }); + setUserRecord(EMPTY_USER_RECORD); + return null; } finally { setCheckingWechat(false); } @@ -331,13 +350,23 @@ export default function JoinPage() { setQualify(qualify); setSubmitted(true); try { - await fetchByWechat(wechat.trim()); + localStorage.setItem(WECHAT_STORAGE_KEY, wechat.trim()); } catch { + /* ignore */ + } + let result = await fetchByWechat(wechat.trim()); + const maxRetries = 5; + const retryDelayMs = 1500; + for (let i = 0; i < maxRetries && !result?.hasRecord; i++) { + await new Promise((r) => setTimeout(r, retryDelayMs)); + result = await fetchByWechat(wechat.trim()); + } + if (!result?.hasRecord) { try { - localStorage.setItem(WECHAT_STORAGE_KEY, wechat.trim()); - } catch {} - window.location.replace("/join"); - return; + window.location.replace("/join"); + } catch { + /* ignore */ + } } } catch (err) { setError(err instanceof Error ? err.message : "网络错误,请重试"); @@ -618,6 +647,12 @@ export default function JoinPage() { 用于防止临时爽约

)} + {paying && ( +
+ + 正在跳转支付,请稍候… +
+ )}