fix(user): correct WeChat JSAPI pay invoke params and JSSDK init

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-03 16:04:01 +08:00
parent cabc9e6ebb
commit def3ed5175
4 changed files with 49 additions and 15 deletions
-1
View File
@@ -121,7 +121,6 @@ export default function PayPage() {
if (result.mode === 'jsapi' && result.prepay) { if (result.mode === 'jsapi' && result.prepay) {
setMockMode(false); setMockMode(false);
await weixinSdk.init();
await weixinSdk.pay(result.prepay); await weixinSdk.pay(result.prepay);
const paid = await waitOrderPaid(orderId); const paid = await waitOrderPaid(orderId);
if (!paid) { if (!paid) {
+5 -1
View File
@@ -49,6 +49,10 @@ export function createWeixinSdk(config: WeixinSdkConfig) {
chooseImages: (options?: Parameters<typeof chooseWechatImages>[1]) => chooseImages: (options?: Parameters<typeof chooseWechatImages>[1]) =>
chooseWechatImages(config, options), chooseWechatImages(config, options),
pay: (prepay: Parameters<typeof invokeWechatPay>[0]) => pay: (prepay: Parameters<typeof invokeWechatPay>[0]) =>
invokeWechatPay(prepay, { apiBase: config.apiBase, clientApp: config.clientApp }), invokeWechatPay(prepay, {
apiBase: config.apiBase ?? '/api/v1',
clientApp: config.clientApp,
getAccessToken: config.getAccessToken,
}),
}; };
} }
+38 -12
View File
@@ -2,6 +2,23 @@ import type { WechatJsapiPrepayParams } from '@dukang/shared-types';
import { getRuntimePlatform } from './env'; import { getRuntimePlatform } from './env';
import { ensureJssdkReady } from './jssdk'; 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<void> { function invokeBridgePay(params: WechatJsapiPrepayParams): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const bridge = window.WeixinJSBridge; const bridge = window.WeixinJSBridge;
@@ -29,10 +46,19 @@ function invokeBridgePay(params: WechatJsapiPrepayParams): Promise<void> {
}); });
} }
async function waitForWeixinBridge(): Promise<void> {
if (window.WeixinJSBridge) return;
if (typeof document === 'undefined') return;
await new Promise<void>((resolve) => {
if (window.WeixinJSBridge) resolve();
else document.addEventListener('WeixinJSBridgeReady', () => resolve(), { once: true });
});
}
/** 调起微信支付 */ /** 调起微信支付 */
export async function invokeWechatPay( export async function invokeWechatPay(
prepay: WechatJsapiPrepayParams, prepay: WechatJsapiPrepayParams,
config?: { apiBase?: string; clientApp?: string }, config?: WechatPayInvokeConfig,
): Promise<void> { ): Promise<void> {
const platform = getRuntimePlatform(); const platform = getRuntimePlatform();
@@ -55,28 +81,28 @@ export async function invokeWechatPay(
await ensureJssdkReady({ await ensureJssdkReady({
apiBase: config.apiBase ?? '/api/v1', apiBase: config.apiBase ?? '/api/v1',
clientApp: config.clientApp, 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) { if (window.wx?.chooseWXPay) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
window.wx!.chooseWXPay!({ window.wx!.chooseWXPay!({
...prepay, ...toChooseWxPayOptions(prepay),
success: () => resolve(), success: () => resolve(),
fail: (err) => reject(new Error(err.errMsg || '支付失败')), fail: (err) => reject(new Error(err.errMsg || '支付失败')),
cancel: () => reject(new Error('用户取消支付')), cancel: () => reject(new Error('用户取消支付')),
}); });
}); });
} }
if (window.WeixinJSBridge) {
return invokeBridgePay(prepay);
}
if (typeof document !== 'undefined') {
await new Promise<void>((resolve) => {
if (window.WeixinJSBridge) resolve();
else document.addEventListener('WeixinJSBridgeReady', () => resolve(), { once: true });
});
return invokeBridgePay(prepay);
}
} }
throw new Error('当前环境不支持微信支付'); throw new Error('当前环境不支持微信支付');
+6 -1
View File
@@ -31,7 +31,12 @@ export type WxApi = {
success?: (res: { resultStr: string }) => void; success?: (res: { resultStr: string }) => void;
fail?: (res: { errMsg: string }) => void; fail?: (res: { errMsg: string }) => void;
}) => void; }) => void;
chooseWXPay: (options: WechatJsapiPrepayParams & { chooseWXPay: (options: {
timestamp: string;
nonceStr: string;
package: string;
signType: string;
paySign: string;
success?: () => void; success?: () => void;
fail?: (res: { errMsg: string }) => void; fail?: (res: { errMsg: string }) => void;
cancel?: () => void; cancel?: () => void;