's'
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# NomadVIP | 异度星球
|
||||
|
||||
VIP 会员解锁页,集成 PocketBase 支付校验、ZPAY 支付。
|
||||
VIP 会员解锁页,集成 PocketBase 支付校验、XorPay/ZPAY 支付。
|
||||
|
||||
## 服务配置(参考 desktop digital)
|
||||
|
||||
@@ -10,7 +10,9 @@ ZPAY、PocketBase、MinIO 配置与 `C:\project\digital` 保持一致,复制 `
|
||||
|------|------|--------|
|
||||
| `NEXT_PUBLIC_POCKETBASE_URL` | PocketBase 地址 | `https://pocketbase.hackrobot.cn` |
|
||||
| `NEXT_PUBLIC_API_URL` / `PAYMENT_API_URL` | payjsapi 地址 | `https://api.hackrobot.cn` |
|
||||
| `PAYMENT_PROVIDER` | 支付提供商 | `zpay` |
|
||||
| `PAYMENT_PROVIDER` | 支付提供商(payjsapi 环境变量) | `xorpay` / `zpay` |
|
||||
|
||||
**XorPay**:直接调用 payh5,无 redirect 中转,表单提交至 xorpay 收银台。payjsapi 需设置 `PAYMENT_PROVIDER=xorpay`。
|
||||
| `MINIO_ENDPOINT` | MinIO 端点 | `minioweb.hackrobot.cn` |
|
||||
| `MINIO_BUCKET` | 存储桶 | `hackrobot` |
|
||||
|
||||
|
||||
@@ -91,11 +91,17 @@ async function createPayOrder(
|
||||
if (!res.ok || data?.status !== "ok") {
|
||||
throw new Error(data?.detail || data?.msg || "支付创建失败");
|
||||
}
|
||||
const params = data.params || {};
|
||||
// xorpay: xorpay_params + xorpay_url | zpay: params + pay_url
|
||||
const params = (data.xorpay_params ?? data.params) || {};
|
||||
const payUrl = data.xorpay_url || data.pay_url || "";
|
||||
if (!params || typeof params !== "object") {
|
||||
throw new Error("payjsapi 未返回支付参数");
|
||||
}
|
||||
return { params: params as Record<string, string>, payUrl: data.pay_url || "" };
|
||||
return {
|
||||
params: params as Record<string, string>,
|
||||
payUrl,
|
||||
provider: data.provider || "zpay",
|
||||
};
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
@@ -153,7 +159,7 @@ export async function POST(request: NextRequest) {
|
||||
request.headers.get("x-real-ip") ||
|
||||
"";
|
||||
|
||||
const { params } = await createPayOrder(
|
||||
const { params, payUrl, provider } = await createPayOrder(
|
||||
apiUrl,
|
||||
user_id,
|
||||
finalReturnUrl,
|
||||
@@ -173,6 +179,22 @@ export async function POST(request: NextRequest) {
|
||||
return NextResponse.json({ ok: false, error: "支付参数为空" }, { status: 500 });
|
||||
}
|
||||
|
||||
// xorpay:直接 payh5 返回收银台参数,无需 redirect 中转
|
||||
const submitUrl = provider === "xorpay" ? payUrl : payConfig.zpaySubmitUrl;
|
||||
if (provider === "xorpay") {
|
||||
const orderId = String(params?.order_id || params?.out_trade_no || "").trim();
|
||||
const html = buildPayHtml(submitUrl, params as Record<string, unknown>, {
|
||||
directToCashier: device === "wechat" || device === "h5",
|
||||
});
|
||||
const res = new NextResponse(html, {
|
||||
status: 200,
|
||||
headers: { "Content-Type": "text/html; charset=utf-8" },
|
||||
});
|
||||
if (orderId) setPayOrderCookie(res, orderId);
|
||||
return res;
|
||||
}
|
||||
|
||||
// zpay:需要 redirect 获取 device 相关跳转
|
||||
const redirectPayload = {
|
||||
user_id,
|
||||
total_fee,
|
||||
@@ -209,7 +231,7 @@ export async function POST(request: NextRequest) {
|
||||
|
||||
if (redirectRes.status === 200 && resData?.use_form) {
|
||||
const orderId = String(params?.out_trade_no || "").trim();
|
||||
const html = buildPayHtml(payConfig.zpaySubmitUrl, params as Record<string, unknown>, {
|
||||
const html = buildPayHtml(submitUrl, params as Record<string, unknown>, {
|
||||
directToCashier: device === "wechat",
|
||||
});
|
||||
const res = new NextResponse(html, {
|
||||
|
||||
@@ -11,8 +11,9 @@ export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 25000);
|
||||
// 使用 order_status 通用接口(xorpay 查 PocketBase,zpay 查 ZPAY)
|
||||
const res = await fetch(
|
||||
`${apiUrl}/nomadvip/zpay_order_status?out_trade_no=${encodeURIComponent(orderId)}`,
|
||||
`${apiUrl}/nomadvip/order_status?order_id=${encodeURIComponent(orderId)}`,
|
||||
{ cache: "no-store", signal: controller.signal }
|
||||
).finally(() => clearTimeout(timeout));
|
||||
const data = await res.json().catch(() => ({}));
|
||||
|
||||
Reference in New Issue
Block a user