222 lines
6.1 KiB
JavaScript
222 lines
6.1 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 normalizePayError(error) {
|
|
if (!error) {
|
|
return '';
|
|
}
|
|
if (typeof error === 'string') {
|
|
return error;
|
|
}
|
|
try {
|
|
return JSON.stringify({
|
|
errCode: error.errCode,
|
|
errMsg: error.errMsg,
|
|
});
|
|
} catch (_error) {
|
|
return String(error.errMsg || error);
|
|
}
|
|
}
|
|
|
|
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') {
|
|
console.error('[wechat-pay] requestVirtualPayment unavailable', {
|
|
canUseVirtualPayment: canUseVirtualPayment(),
|
|
hasRequestVirtualPayment: typeof wx.requestVirtualPayment === 'function',
|
|
});
|
|
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) {
|
|
console.error('[wechat-pay] 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),
|
|
});
|
|
}
|
|
}
|
|
|
|
function createWechatPayPage(pageContext) {
|
|
return {
|
|
data: {
|
|
title: '正在拉起支付',
|
|
errorMessage: '',
|
|
},
|
|
|
|
async onLoad(query) {
|
|
const requestId = String(query.requestId || '');
|
|
const orderId = String(query.orderId || '');
|
|
const payParams = parsePayParams(query.payParams);
|
|
if (!requestId || !payParams) {
|
|
const page = pageContext ?? this;
|
|
page.setData({
|
|
title: '支付失败',
|
|
errorMessage: '缺少支付参数。',
|
|
});
|
|
return;
|
|
}
|
|
|
|
const payResult = await requestWechatPayment(payParams);
|
|
notifyPreviousWebView(requestId, orderId, payResult);
|
|
wx.navigateBack();
|
|
},
|
|
|
|
handleBack() {
|
|
wx.navigateBack();
|
|
},
|
|
};
|
|
}
|
|
|
|
module.exports = {
|
|
canUseVirtualPayment,
|
|
PAY_RESULT_STORAGE_KEY,
|
|
appendPayResult,
|
|
buildPayResultValue,
|
|
createWechatPayPage,
|
|
normalizePayError,
|
|
parsePayParams,
|
|
safeCompareVersion,
|
|
requestWechatPayment,
|
|
requestVirtualPayment,
|
|
};
|