From 1628efd9712d2cb78f5d4d5427be14f531b7e085 Mon Sep 17 00:00:00 2001 From: eric Date: Tue, 10 Mar 2026 12:37:36 -0500 Subject: [PATCH] 's' --- src/pages/book/index.tsx | 166 +++++++++++++++++++++++++++++++-------- src/utils/payEnv.ts | 27 +++++++ 2 files changed, 159 insertions(+), 34 deletions(-) create mode 100644 src/utils/payEnv.ts diff --git a/src/pages/book/index.tsx b/src/pages/book/index.tsx index c47c301..c5dc0b1 100755 --- a/src/pages/book/index.tsx +++ b/src/pages/book/index.tsx @@ -16,12 +16,47 @@ import { AtForm, AtMessage, AtDrawer, AtIcon } from "taro-ui"; import { marked } from "marked"; import infoText from "./info.md"; import bookText from "./book.md"; +import { getPayEnv, getDeviceFromEnv } from "../../utils/payEnv"; // import youtubeIco from "../../images/youtube.ico"; import hackrobot from "../../images/hackrobot.jpg"; // PocketBase 配置 const PB_URL = "https://pocketbase.hackrobot.cn"; const pb = new PocketBase(PB_URL); +/** PC 扫码支付:生成带二维码和轮询的 HTML 页面 */ +function buildQrcodePageHtml(imgSrc, orderId, returnUrl, apiBase) { + const esc = (s) => + String(s) + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); + const statusUrl = `${apiBase}/nomadvip/order_status?order_id=${encodeURIComponent(orderId)}`; + return `微信扫码支付 +
+

微信扫码支付

请使用微信扫描下方二维码完成支付

+
支付二维码

等待支付中...

+
✅
支付成功
+
感谢您的支持,正在返回...
+`; +} + marked.setOptions({ breaks: true, // 是否回车换行 gfm: true, //使用经批准的 GitHub Flavored Markdown (GFM) 规范 @@ -242,26 +277,28 @@ const Book = () => { } }; - const payh51111 = (type, total_fee = 1000) => { + /** 微信内:xorpay 收银台 */ + const payWechatXorpay = (type, total_fee) => { + const userId = getOrCreateUserId(); + const returnUrl = window.location.href; Taro.request({ method: "POST", - url: `${process.env.TARO_API_API}/payh5`, + url: `${process.env.TARO_API_API}/nomadvip/payh5`, data: { - total_fee: total_fee, - type: type, - // callback_url 临时不传 - }, - header: { - "content-type": "application/json", + user_id: userId, + total_fee, + type, + channel: "wxpay", + return_url: returnUrl, + provider: "xorpay", }, + header: { "content-type": "application/json" }, success: (res) => { if (res.data?.status === "ok" && res.data?.xorpay_params) { - // 创建隐藏 form POST 到 XorPay const form = document.createElement("form"); form.method = "POST"; form.action = res.data.xorpay_url; form.style.display = "none"; - for (const key in res.data.xorpay_params) { const input = document.createElement("input"); input.type = "hidden"; @@ -269,25 +306,81 @@ const Book = () => { input.value = res.data.xorpay_params[key]; form.appendChild(input); } - document.body.appendChild(form); form.submit(); } else { - Taro.showToast({ - title: "支付发起失败", - icon: "none", - }); + Taro.showToast({ title: "支付发起失败", icon: "none" }); } }, - fail: () => { - Taro.showToast({ - title: "网络错误", - icon: "none", - }); - }, + fail: () => Taro.showToast({ title: "网络错误", icon: "none" }), }); }; + /** PC:zpay 扫码,新窗口展示二维码 */ + const payPcZpay = (type, total_fee) => { + const userId = getOrCreateUserId(); + const returnUrl = window.location.href; + Taro.request({ + method: "POST", + url: `${process.env.TARO_API_API}/nomadvip/payh5/redirect`, + data: { + user_id: userId, + total_fee, + type, + channel: "wxpay", + return_url: returnUrl, + device: "pc", + provider: "zpay", + }, + header: { "content-type": "application/json" }, + success: (res) => { + const d = res.data; + if (d?.status === "ok" && d?.qrcode_mode && d?.img) { + const apiBase = (process.env.TARO_API_API || "").replace(/\/$/, ""); + const html = buildQrcodePageHtml(d.img, d.order_id, d.return_url || returnUrl, apiBase); + const win = window.open("", "_blank"); + if (win) { + win.document.write(html); + win.document.close(); + } else { + Taro.showToast({ title: "请允许弹窗以显示支付二维码", icon: "none" }); + } + } else { + Taro.showToast({ title: "支付发起失败", icon: "none" }); + } + }, + fail: () => Taro.showToast({ title: "网络错误", icon: "none" }), + }); + }; + + /** 手机浏览器:zpay 唤醒微信,form 提交到 redirect 接口触发 302 */ + const payH5Zpay = (type, total_fee) => { + const userId = getOrCreateUserId(); + const returnUrl = window.location.href; + const form = document.createElement("form"); + form.method = "POST"; + form.action = `${(process.env.TARO_API_API || "").replace(/\/$/, "")}/nomadvip/payh5/redirect`; + form.style.display = "none"; + const fields = [ + ["user_id", userId], + ["total_fee", String(total_fee)], + ["type", type], + ["channel", "wxpay"], + ["return_url", returnUrl], + ["device", "h5"], + ["provider", "zpay"], + ]; + fields.forEach(([k, v]) => { + const input = document.createElement("input"); + input.type = "hidden"; + input.name = k; + input.value = v; + form.appendChild(input); + }); + document.body.appendChild(form); + form.submit(); + }; + // 生成或获取 userId(修改为无下划线) const getOrCreateUserId = () => { let userId = Taro.getStorageSync("userId"); @@ -300,8 +393,22 @@ const Book = () => { return userId; }; - const payh5 = (type, total_fee = 1000) => { - const userId = getOrCreateUserId(); // ← 新增:获取 userId + /** 统一支付入口:PC扫码(zpay) / 手机浏览器唤醒(zpay) / 微信内(xorpay) */ + const handlePay = (type, total_fee) => { + const env = getPayEnv(); + const device = getDeviceFromEnv(env); + if (device === "wechat") { + payWechatXorpay(type, total_fee); + } else if (device === "pc") { + payPcZpay(type, total_fee); + } else { + payH5Zpay(type, total_fee); + } + }; + + /* eslint-disable-next-line no-unused-vars */ + const _legacyPayh5 = (type, total_fee) => { + const userId = getOrCreateUserId(); Taro.request({ method: "POST", url: `${process.env.TARO_API_API}/payh5`, @@ -455,17 +562,8 @@ const Book = () => { size="normal" className="joinSalon" onClick={() => { - if (paidType == "book" || vipbook) { - return false; - } else { - if (!!isWeChat) { - //199元 - payh5("book", 19900); - // window.location.href = `https://vip.hackrobot.cn`; - } else { - window.location.href = `https://mp.weixin.qq.com/s/PBbnS8qC_kqhL9HJO5m-Iw`; - } - } + if (paidType == "book" || vipbook) return; + handlePay("book", 19900); }} > {`🔒阅读更多`} diff --git a/src/utils/payEnv.ts b/src/utils/payEnv.ts new file mode 100644 index 0000000..d832004 --- /dev/null +++ b/src/utils/payEnv.ts @@ -0,0 +1,27 @@ +/** + * 支付环境检测:PC / H5 / 微信浏览器 + * 参考 nomadvip app/lib/payEnv.ts + */ + +export function isWeChat() { + if (typeof navigator === "undefined") return false; + return /MicroMessenger/i.test(navigator.userAgent); +} + +export function isMobile() { + if (typeof navigator === "undefined") return false; + return /AppleWebKit.*Mobile|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( + navigator.userAgent + ); +} + +export function getPayEnv() { + if (isWeChat()) return "wechat"; + if (isMobile()) return "h5"; + return "pc"; +} + +export function getDeviceFromEnv(env) { + if (env === "wechat") return "wechat"; + return env === "pc" ? "pc" : "h5"; +}