import { NextRequest, NextResponse } from "next/server"; import { getPaymentConfig } from "@/config/services.config"; import { SITE_URL } from "@/app/lib/env"; async function createPayOrder( user_id: string, return_url: string, total_fee?: number, type?: string, channel = "alipay" ) { const config = getPaymentConfig(); if (!config.apiUrl) throw new Error("未配置 PAYMENT_API_URL"); const payload = { user_id, site_id: "meetup", total_fee: Number(total_fee) || config.defaultAmount, type: type || config.defaultType, channel, return_url, }; const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 10000); const res = await fetch(`${config.apiUrl}/cnomadcna/payh5`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), signal: controller.signal, }).finally(() => clearTimeout(timeout)); const data = await res.json().catch(() => ({})); if (!res.ok || data?.status !== "ok") { throw new Error(data?.detail || data?.msg || data?.message || "支付创建失败"); } const params = data.params || data.xorpay_params || {}; const payUrl = data.pay_url || data.xorpay_url || config.zpaySubmitUrl; if (!params || typeof params !== "object") { throw new Error("payjsapi 未返回支付参数"); } return { params: JSON.parse(JSON.stringify(params)), payUrl }; } export async function POST(request: NextRequest) { try { let body: Record; const contentType = request.headers.get("content-type") || ""; if (contentType.includes("application/json")) { body = await request.json(); } else { const form = await request.formData(); body = Object.fromEntries(form.entries()) as Record; } const user_id = String(body?.user_id || "").trim(); const return_url = String(body?.return_url || "").trim() || `${SITE_URL}/zh/join/paid`; const total_fee = Number(body?.total_fee) || 100; const type = String(body?.type || "meetup"); const channel = String(body?.channel || "alipay"); const device = String(body?.device || "pc"); if (!user_id) { return NextResponse.json({ ok: false, error: "缺少 user_id" }, { status: 400 }); } const { params, payUrl } = await createPayOrder(user_id, return_url, total_fee, type, channel); const wantHtml = String(body?.html) === "1" || (request.headers.get("accept") || "").includes("text/html"); if (wantHtml) { const escapeAttr = (s: string) => String(s) .replace(/&/g, "&") .replace(/"/g, """) .replace(//g, ">"); const inputs = Object.entries(params as Record) .filter(([, v]) => v != null && String(v).trim() !== "") .map(([k, v]) => ``) .join("\n"); const orderId = String((params as Record)?.out_trade_no || "").trim(); const html = `跳转支付
${inputs}
`; const res = new NextResponse(html, { status: 200, headers: { "Content-Type": "text/html; charset=utf-8" } }); if (orderId) { res.cookies.set("join_pay_order", `${orderId}|${Date.now()}`, { path: "/", maxAge: 900 }); } return res; } return NextResponse.json({ ok: true, pay_url: payUrl, params, provider: "zpay" }); } catch (e) { const err = e instanceof Error ? e : new Error(String(e)); console.error("Pay API error:", err); return NextResponse.json({ ok: false, error: err.message }, { status: 500 }); } }