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";
+}