Files
Genarrative/miniprogram/pages/wechat-pay/index.shared.js

185 lines
4.9 KiB
JavaScript

/* 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,
};