From def3ed51750bc86b3742175f4fd66a5c3245877e Mon Sep 17 00:00:00 2001 From: jacy-dukang Date: Fri, 3 Jul 2026 16:04:01 +0800 Subject: [PATCH] fix(user): correct WeChat JSAPI pay invoke params and JSSDK init Co-authored-by: Cursor --- apps/h5-user/src/pages/PayPage.tsx | 1 - packages/weixin-sdk/src/index.ts | 6 +++- packages/weixin-sdk/src/pay.ts | 50 +++++++++++++++++++++++------- packages/weixin-sdk/src/types.ts | 7 ++++- 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/apps/h5-user/src/pages/PayPage.tsx b/apps/h5-user/src/pages/PayPage.tsx index 9c720dd..080b156 100644 --- a/apps/h5-user/src/pages/PayPage.tsx +++ b/apps/h5-user/src/pages/PayPage.tsx @@ -121,7 +121,6 @@ export default function PayPage() { if (result.mode === 'jsapi' && result.prepay) { setMockMode(false); - await weixinSdk.init(); await weixinSdk.pay(result.prepay); const paid = await waitOrderPaid(orderId); if (!paid) { diff --git a/packages/weixin-sdk/src/index.ts b/packages/weixin-sdk/src/index.ts index 574f4c6..79531f3 100644 --- a/packages/weixin-sdk/src/index.ts +++ b/packages/weixin-sdk/src/index.ts @@ -49,6 +49,10 @@ export function createWeixinSdk(config: WeixinSdkConfig) { chooseImages: (options?: Parameters[1]) => chooseWechatImages(config, options), pay: (prepay: Parameters[0]) => - invokeWechatPay(prepay, { apiBase: config.apiBase, clientApp: config.clientApp }), + invokeWechatPay(prepay, { + apiBase: config.apiBase ?? '/api/v1', + clientApp: config.clientApp, + getAccessToken: config.getAccessToken, + }), }; } diff --git a/packages/weixin-sdk/src/pay.ts b/packages/weixin-sdk/src/pay.ts index 922a045..c600dfe 100644 --- a/packages/weixin-sdk/src/pay.ts +++ b/packages/weixin-sdk/src/pay.ts @@ -2,6 +2,23 @@ import type { WechatJsapiPrepayParams } from '@dukang/shared-types'; import { getRuntimePlatform } from './env'; import { ensureJssdkReady } from './jssdk'; +export type WechatPayInvokeConfig = { + apiBase?: string; + clientApp?: string; + getAccessToken?: () => string | null; +}; + +/** wx.chooseWXPay 要求 timestamp 小写;服务端签名与 Bridge 使用 timeStamp */ +function toChooseWxPayOptions(prepay: WechatJsapiPrepayParams) { + return { + timestamp: prepay.timeStamp, + nonceStr: prepay.nonceStr, + package: prepay.package, + signType: prepay.signType, + paySign: prepay.paySign, + }; +} + function invokeBridgePay(params: WechatJsapiPrepayParams): Promise { return new Promise((resolve, reject) => { const bridge = window.WeixinJSBridge; @@ -29,10 +46,19 @@ function invokeBridgePay(params: WechatJsapiPrepayParams): Promise { }); } +async function waitForWeixinBridge(): Promise { + if (window.WeixinJSBridge) return; + if (typeof document === 'undefined') return; + await new Promise((resolve) => { + if (window.WeixinJSBridge) resolve(); + else document.addEventListener('WeixinJSBridgeReady', () => resolve(), { once: true }); + }); +} + /** 调起微信支付 */ export async function invokeWechatPay( prepay: WechatJsapiPrepayParams, - config?: { apiBase?: string; clientApp?: string }, + config?: WechatPayInvokeConfig, ): Promise { const platform = getRuntimePlatform(); @@ -55,28 +81,28 @@ export async function invokeWechatPay( await ensureJssdkReady({ apiBase: config.apiBase ?? '/api/v1', clientApp: config.clientApp, + getAccessToken: config.getAccessToken, + url: typeof window !== 'undefined' ? window.location.href.split('#')[0] : undefined, + jsApiList: ['chooseWXPay'], }); } + + // Bridge 参数与商户签名一致,优先于 chooseWXPay + await waitForWeixinBridge(); + if (window.WeixinJSBridge) { + return invokeBridgePay(prepay); + } + if (window.wx?.chooseWXPay) { return new Promise((resolve, reject) => { window.wx!.chooseWXPay!({ - ...prepay, + ...toChooseWxPayOptions(prepay), success: () => resolve(), fail: (err) => reject(new Error(err.errMsg || '支付失败')), cancel: () => reject(new Error('用户取消支付')), }); }); } - if (window.WeixinJSBridge) { - return invokeBridgePay(prepay); - } - if (typeof document !== 'undefined') { - await new Promise((resolve) => { - if (window.WeixinJSBridge) resolve(); - else document.addEventListener('WeixinJSBridgeReady', () => resolve(), { once: true }); - }); - return invokeBridgePay(prepay); - } } throw new Error('当前环境不支持微信支付'); diff --git a/packages/weixin-sdk/src/types.ts b/packages/weixin-sdk/src/types.ts index e92270c..5842c5a 100644 --- a/packages/weixin-sdk/src/types.ts +++ b/packages/weixin-sdk/src/types.ts @@ -31,7 +31,12 @@ export type WxApi = { success?: (res: { resultStr: string }) => void; fail?: (res: { errMsg: string }) => void; }) => void; - chooseWXPay: (options: WechatJsapiPrepayParams & { + chooseWXPay: (options: { + timestamp: string; + nonceStr: string; + package: string; + signType: string; + paySign: string; success?: () => void; fail?: (res: { errMsg: string }) => void; cancel?: () => void;