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
+5 -1
View File
@@ -49,6 +49,10 @@ export function createWeixinSdk(config: WeixinSdkConfig) {
chooseImages: (options?: Parameters<typeof chooseWechatImages>[1]) =>
chooseWechatImages(config, options),
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 { 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> {
return new Promise((resolve, reject) => {
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(
prepay: WechatJsapiPrepayParams,
config?: { apiBase?: string; clientApp?: string },
config?: WechatPayInvokeConfig,
): Promise<void> {
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<void>((resolve) => {
if (window.WeixinJSBridge) resolve();
else document.addEventListener('WeixinJSBridgeReady', () => resolve(), { once: true });
});
return invokeBridgePay(prepay);
}
}
throw new Error('当前环境不支持微信支付');
+6 -1
View File
@@ -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;