Files
Genarrative/src/services/payment/wechatJsapiPayment.ts
T
kdletters 542fb09365 接入微信 Native 充值与订单过期处理
调整网页端充值渠道,微信内浏览器在开放平台接入前走 Native 支付。

拆分 Native 支付二维码弹窗,展示金额和充值内容并取消无效 code_url 跳转。

修复微信 Native 下单 time_expire 秒级 RFC3339 格式,避免小数秒参数错误。

新增充值订单 5 分钟过期调度,过期前查询微信真实订单状态。

补充微信授权绑定、路由加载恢复和后台表时间显示等配套逻辑。

更新 SpacetimeDB schema、绑定和相关文档测试。
2026-07-08 21:35:02 +08:00

108 lines
2.6 KiB
TypeScript

import type {
WechatMiniProgramPayParams,
WechatMiniProgramVirtualPayParams,
} from '../../../packages/shared/src/contracts/runtime';
type WeixinJsBridgePaymentResult = {
err_msg?: string;
errMsg?: string;
};
type WeixinJsBridge = {
invoke: (
method: 'getBrandWCPayRequest',
params: Record<string, string>,
callback: (result: WeixinJsBridgePaymentResult) => void,
) => void;
};
function getWeixinJsBridge() {
const bridge = window.WeixinJSBridge;
if (
bridge &&
typeof bridge === 'object' &&
'invoke' in bridge &&
typeof bridge.invoke === 'function'
) {
return bridge as WeixinJsBridge;
}
return null;
}
function waitForWeixinJsBridge() {
const readyBridge = getWeixinJsBridge();
if (readyBridge) {
return Promise.resolve(readyBridge);
}
return new Promise<WeixinJsBridge>((resolve, reject) => {
const timeout = window.setTimeout(() => {
document.removeEventListener('WeixinJSBridgeReady', handleReady);
reject(new Error('微信 JSAPI 支付环境未就绪'));
}, 8000);
function handleReady() {
const bridge = getWeixinJsBridge();
if (!bridge) {
return;
}
window.clearTimeout(timeout);
document.removeEventListener('WeixinJSBridgeReady', handleReady);
resolve(bridge);
}
document.addEventListener('WeixinJSBridgeReady', handleReady, {
once: true,
});
});
}
export async function requestWechatJsapiPayment(
payload:
| WechatMiniProgramPayParams
| WechatMiniProgramVirtualPayParams
| null
| undefined,
) {
if (!payload) {
throw new Error('微信 JSAPI 支付参数缺失');
}
if (!('timeStamp' in payload)) {
throw new Error('微信 JSAPI 支付参数格式无效');
}
const appId = payload.appId?.trim();
if (!appId) {
throw new Error('微信 JSAPI 支付参数缺少 appId');
}
const bridge = await waitForWeixinJsBridge();
const result = await new Promise<WeixinJsBridgePaymentResult>((resolve) => {
bridge.invoke(
'getBrandWCPayRequest',
{
appId,
timeStamp: payload.timeStamp,
nonceStr: payload.nonceStr,
package: payload.package,
signType: payload.signType,
paySign: payload.paySign,
},
resolve,
);
});
const message = result.err_msg ?? result.errMsg ?? '';
const normalizedMessage = message.toLowerCase();
if (normalizedMessage.includes(':ok')) {
return;
}
if (normalizedMessage.includes(':cancel')) {
throw new Error('微信支付已取消');
}
throw new Error(message || '微信 JSAPI 支付调起失败');
}