import { NextRequest, NextResponse } from "next/server"; import { postSalonApi } from "@/app/lib/salonApi"; import { getAdminToken } from "@/app/lib/pocketbase/admin"; import { getPocketBaseConfig } from "@/config/services.config"; import { COOKIE_NAME } from "@/app/lib/auth-cookie"; function getUserIdFromCookie(request: NextRequest): string | null { const cookie = request.cookies.get(COOKIE_NAME)?.value; if (!cookie) return null; try { const payload = JSON.parse(Buffer.from(cookie, "base64url").toString("utf-8")); return payload?.userId ?? null; } catch { return null; } } function generateAnonId(): string { return "anon_" + crypto.randomUUID().replace(/-/g, ""); } export async function POST(request: NextRequest) { try { const body = await request.json(); const formData = body && typeof body === "object" ? body : {}; const nickname = String(formData.nickname || "").trim(); const city = String(formData.city || "").trim(); const session = String(formData.session || "").trim(); const ageRange = String(formData.age_range || "").trim(); const wechatOrPhone = String(formData.wechat_or_phone || "").trim(); const intro = String(formData.intro || "").trim(); const firstTime = String(formData.first_time || "").trim(); const agreeRules = !!formData.agree_rules; if (!nickname || !wechatOrPhone || !intro || !session || !agreeRules) { return NextResponse.json( { ok: false, error: "请填写必填项" }, { status: 400 } ); } const userId = getUserIdFromCookie(request) || generateAnonId(); const record = { user_id: userId, nickname, occupation: city, reason: intro, wechatId: wechatOrPhone, gender: "", education: "", gradYear: "", phone: wechatOrPhone, single: "", media: "", type: session, order_id: "", amount: 0, age_range: ageRange, first_time: firstTime, }; try { const { status, data } = await postSalonApi(request, "/api/salon/join", record); if (status >= 500) { const payload = typeof data === "object" && data !== null ? (data as Record) : {}; return NextResponse.json( { ok: false, error: (payload.detail as string) || (payload.error as string) || "提交失败" }, { status: 503 } ); } if (status >= 400) { const payload = typeof data === "object" && data !== null ? (data as Record) : {}; const errMsg = (payload.error as string) || (payload.detail as string) || "提交失败"; if (status === 401) { return tryPocketBaseDirect(record, errMsg); } return NextResponse.json({ ok: false, error: errMsg }, { status }); } return NextResponse.json({ ok: true }); } catch { return tryPocketBaseDirect(record, "服务暂时不可用"); } } catch (e) { const msg = e instanceof Error ? e.message : String(e); console.error("Join API error:", e); return NextResponse.json( { ok: false, error: `提交失败: ${msg}` }, { status: 500 } ); } } async function tryPocketBaseDirect( record: Record, fallbackError: string ): Promise { const token = await getAdminToken(); if (!token) { return NextResponse.json({ ok: false, error: fallbackError }, { status: 503 }); } const pb = getPocketBaseConfig(); const base = pb.url.replace(/\/$/, ""); const url = `${base}/api/collections/${pb.joinCollection}/records`; const body: Record = { user_id: record.user_id, nickname: record.nickname, occupation: record.occupation ?? "", reason: [record.reason, record.age_range, record.first_time].filter(Boolean).join(" | "), wechatId: record.wechatId ?? "", gender: record.gender ?? "", education: record.education ?? "", gradYear: record.gradYear ?? "", phone: record.phone ?? "", single: record.single ?? "", media: record.media ?? "", type: record.type ?? "", order_id: record.order_id ?? "", amount: record.amount ?? 0, }; try { const res = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json", Authorization: `Bearer ${token}`, }, body: JSON.stringify(body), }); if (!res.ok) { const errData = await res.json().catch(() => ({})); const msg = (errData as { message?: string }).message || fallbackError; return NextResponse.json({ ok: false, error: msg }, { status: res.status }); } return NextResponse.json({ ok: true }); } catch (e) { console.error("PocketBase direct write error:", e); return NextResponse.json( { ok: false, error: fallbackError }, { status: 503 } ); } }