542fb09365
调整网页端充值渠道,微信内浏览器在开放平台接入前走 Native 支付。 拆分 Native 支付二维码弹窗,展示金额和充值内容并取消无效 code_url 跳转。 修复微信 Native 下单 time_expire 秒级 RFC3339 格式,避免小数秒参数错误。 新增充值订单 5 分钟过期调度,过期前查询微信真实订单状态。 补充微信授权绑定、路由加载恢复和后台表时间显示等配套逻辑。 更新 SpacetimeDB schema、绑定和相关文档测试。
108 lines
2.6 KiB
TypeScript
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 支付调起失败');
|
|
}
|