/* 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) { logWechatPayFailure('parse params failed', error); return null; } } function logWechatPayFailure(label, _error) { console.error(`[wechat-pay] ${label}`); } 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 normalizePayError() { return 'wechat payment unavailable'; } 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({ status: 'success', errorMessage: '' }); }, fail(error) { resolve({ status: resolvePayStatus(error), errorMessage: normalizePayError(error), }); }, }); }); } function requestVirtualPayment(payParams) { return new Promise((resolve) => { if (!canUseVirtualPayment() || typeof wx.requestVirtualPayment !== 'function') { logWechatPayFailure('requestVirtualPayment unavailable'); resolve({ status: 'fail', errorMessage: '当前微信基础库不支持 requestVirtualPayment', }); return; } wx.requestVirtualPayment({ mode: String(payParams.mode || ''), signData: String(payParams.signData || ''), paySig: String(payParams.paySig || ''), signature: String(payParams.signature || ''), success() { resolve({ status: 'success', errorMessage: '' }); }, fail(error) { logWechatPayFailure('requestVirtualPayment failed', error); resolve({ status: resolvePayStatus(error), errorMessage: normalizePayError(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, result) { 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(result)}`) .join('&'); return `${baseUrl}#${nextHash}`; } function buildPayResultValue(requestId, orderId, payResult) { const segments = [requestId, payResult.status, orderId || '']; if (payResult.errorMessage) { segments.push(encodeURIComponent(payResult.errorMessage)); } return segments.join(':'); } function notifyPreviousWebView(requestId, orderId, payResult) { const result = buildPayResultValue(requestId, orderId, payResult); 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, result), }); } } module.exports = { canUseVirtualPayment, PAY_RESULT_STORAGE_KEY, appendPayResult, buildPayResultValue, normalizePayError, notifyPreviousWebView, parsePayParams, safeCompareVersion, requestWechatPayment, requestVirtualPayment, };