/* global wx, getCurrentPages */ function parsePayParams(rawValue) { try { const params = JSON.parse(decodeURIComponent(String(rawValue || ''))); if (!params || typeof params !== 'object') { return null; } return params; } catch (error) { console.error('[wechat-pay] parse params failed', error); return null; } } function isVirtualPaymentParams(payParams) { return ( typeof payParams.mode === 'string' && typeof payParams.signData === 'string' && typeof payParams.paySig === 'string' && typeof payParams.signature === 'string' ); } function safeCompareVersion(left, right) { const leftParts = String(left || '') .split('.') .map((part) => Number(part) || 0); const rightParts = String(right || '') .split('.') .map((part) => Number(part) || 0); const length = Math.max(leftParts.length, rightParts.length); for (let index = 0; index < length; index += 1) { const leftValue = leftParts[index] || 0; const rightValue = rightParts[index] || 0; if (leftValue > rightValue) { return 1; } if (leftValue < rightValue) { return -1; } } return 0; } function canUseVirtualPayment() { if (typeof wx === 'undefined') { return false; } if (typeof wx.canIUse === 'function' && wx.canIUse('requestVirtualPayment')) { return true; } const version = typeof wx.getSystemInfoSync === 'function' ? wx.getSystemInfoSync()?.SDKVersion || '' : ''; return safeCompareVersion(version, '2.19.2') >= 0; } function resolvePayStatus(error) { const errMsg = error && error.errMsg ? error.errMsg : ''; const errCode = Number(error && error.errCode); return errCode === -2 || /cancel/i.test(errMsg) ? 'cancel' : 'fail'; } function requestOrdinaryPayment(payParams) { return new Promise((resolve) => { wx.requestPayment({ timeStamp: String(payParams.timeStamp || ''), nonceStr: String(payParams.nonceStr || ''), package: String(payParams.package || ''), signType: payParams.signType || 'RSA', paySign: String(payParams.paySign || ''), success() { resolve('success'); }, fail(error) { resolve(resolvePayStatus(error)); }, }); }); } function requestVirtualPayment(payParams) { return new Promise((resolve) => { if (!canUseVirtualPayment() || typeof wx.requestVirtualPayment !== 'function') { resolve('fail'); return; } wx.requestVirtualPayment({ mode: String(payParams.mode || ''), signData: String(payParams.signData || ''), paySig: String(payParams.paySig || ''), signature: String(payParams.signature || ''), success() { resolve('success'); }, fail(error) { resolve(resolvePayStatus(error)); }, }); }); } function requestWechatPayment(payParams) { if (isVirtualPaymentParams(payParams)) { return requestVirtualPayment(payParams); } return requestOrdinaryPayment(payParams); } const PAY_RESULT_STORAGE_KEY = 'genarrative:wechat-pay-result'; function appendPayResult(url, requestId, status) { const value = `${requestId}:${status}`; const hashIndex = String(url || '').indexOf('#'); const baseUrl = hashIndex >= 0 ? String(url).slice(0, hashIndex) : String(url || ''); const rawHash = hashIndex >= 0 ? String(url).slice(hashIndex + 1) : ''; const nextHash = rawHash .split('&') .filter((part) => part && !part.startsWith('wx_pay_result=')) .concat(`wx_pay_result=${encodeURIComponent(value)}`) .join('&'); return `${baseUrl}#${nextHash}`; } function notifyPreviousWebView(requestId, status) { const result = `${requestId}:${status}`; wx.setStorageSync(PAY_RESULT_STORAGE_KEY, result); const pages = getCurrentPages(); const previousPage = pages.length >= 2 ? pages[pages.length - 2] : null; if (previousPage && typeof previousPage.setData === 'function') { previousPage.setData({ webViewUrl: appendPayResult( previousPage.data.webViewUrl, requestId, status, ), }); } } function createWechatPayPage(pageContext) { return { data: { title: '正在拉起支付', errorMessage: '', }, async onLoad(query) { const requestId = String(query.requestId || ''); const payParams = parsePayParams(query.payParams); if (!requestId || !payParams) { const page = pageContext ?? this; page.setData({ title: '支付失败', errorMessage: '缺少支付参数。', }); return; } const status = await requestWechatPayment(payParams); notifyPreviousWebView(requestId, status); wx.navigateBack(); }, handleBack() { wx.navigateBack(); }, }; } module.exports = { canUseVirtualPayment, PAY_RESULT_STORAGE_KEY, appendPayResult, createWechatPayPage, parsePayParams, safeCompareVersion, requestWechatPayment, requestVirtualPayment, };