354 lines
15 KiB
JavaScript
354 lines
15 KiB
JavaScript
/**
|
||
* 微信/支付宝支付工具类
|
||
* 适配端:微信小程序(全支付方式)、华为快应用(全支付方式)、H5(全支付方式)
|
||
* 核心:统一封装支付调用逻辑,返回H5支付链接适配web-view组件
|
||
*/
|
||
|
||
/**
|
||
* 微信支付调用封装
|
||
* @param {String} outTradeNo 前端生成的唯一订单号
|
||
* @param {Number} amount 支付金额(单位:元,保留2位小数)
|
||
* @param {String} subject 订单标题
|
||
* @returns {Promise} 支付结果(含H5支付链接)
|
||
*/
|
||
export function invokeWechatPay(outTradeNo, amount, subject) {
|
||
return new Promise(async (resolve, reject) => {
|
||
try {
|
||
// 1. 调用后端接口生成微信支付订单
|
||
const orderRes = await uni.request({
|
||
url: getApiUrl() + '/api/pay/wechat/createOrder',
|
||
method: 'POST',
|
||
data: {
|
||
out_trade_no: outTradeNo,
|
||
total_amount: amount,
|
||
subject: subject,
|
||
pay_type: 'wechatpay'
|
||
}
|
||
});
|
||
|
||
// 2. 校验后端返回结果
|
||
if (orderRes.data.code !== 0) {
|
||
reject(new Error(orderRes.data.msg || '生成微信支付订单失败'));
|
||
return;
|
||
}
|
||
|
||
// 3. 区分运行端处理
|
||
const systemInfo = uni.getSystemInfoSync();
|
||
const accountInfo = uni.getAccountInfoSync();
|
||
const isWechatMini = accountInfo?.miniProgram?.appId?.includes('wx'); // 微信小程序
|
||
const isHuaweiQuickApp = systemInfo.platform === 'quickapp-huawei'; // 华为快应用
|
||
|
||
if (isWechatMini) {
|
||
// 3.1 微信小程序:优先原生唤起,失败则返回H5链接
|
||
if (orderRes.data.data.timeStamp && orderRes.data.data.paySign) {
|
||
uni.requestPayment({
|
||
timeStamp: orderRes.data.data.timeStamp,
|
||
nonceStr: orderRes.data.data.nonceStr,
|
||
package: orderRes.data.data.package,
|
||
signType: 'MD5',
|
||
paySign: orderRes.data.data.paySign,
|
||
success: () => {
|
||
resolve({
|
||
code: 0,
|
||
msg: '微信支付控件唤起成功',
|
||
data: {}
|
||
});
|
||
},
|
||
fail: (err) => {
|
||
// 原生唤起失败,返回H5链接适配web-view
|
||
if (orderRes.data.data.payUrl) {
|
||
resolve({
|
||
code: 0,
|
||
msg: '原生支付失败,跳转H5支付',
|
||
data: { payUrl: orderRes.data.data.payUrl }
|
||
});
|
||
} else {
|
||
reject(new Error(`微信支付失败:${err.errMsg || '无H5支付链接'}`));
|
||
}
|
||
}
|
||
});
|
||
} else if (orderRes.data.data.payUrl) {
|
||
// 无原生支付参数,直接返回H5链接
|
||
resolve({
|
||
code: 0,
|
||
msg: '跳转微信支付H5页面',
|
||
data: { payUrl: orderRes.data.data.payUrl }
|
||
});
|
||
} else {
|
||
reject(new Error('缺少微信支付参数(原生/H5)'));
|
||
}
|
||
} else if (isHuaweiQuickApp) {
|
||
// 3.2 华为快应用:返回H5支付链接
|
||
if (!orderRes.data.data.payUrl) {
|
||
reject(new Error('未获取到微信支付H5跳转链接'));
|
||
return;
|
||
}
|
||
resolve({
|
||
code: 0,
|
||
msg: '跳转微信支付H5页面',
|
||
data: { payUrl: orderRes.data.data.payUrl }
|
||
});
|
||
} else {
|
||
// 3.3 H5端:直接跳转
|
||
if (!orderRes.data.data.payUrl) {
|
||
reject(new Error('未获取到微信支付跳转链接'));
|
||
return;
|
||
}
|
||
window.location.href = orderRes.data.data.payUrl;
|
||
resolve({
|
||
code: 0,
|
||
msg: '跳转微信支付页面成功',
|
||
data: {}
|
||
});
|
||
}
|
||
} catch (err) {
|
||
reject(new Error(`微信支付异常:${err.message || '网络请求失败'}`));
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 支付宝支付调用封装(全端支持,返回H5链接适配web-view)
|
||
* @param {String} outTradeNo 前端生成的唯一订单号
|
||
* @param {Number} amount 支付金额(单位:元)
|
||
* @param {String} subject 订单标题
|
||
* @returns {Promise} 支付结果(含H5支付链接)
|
||
*/
|
||
export function invokeAlipay(outTradeNo, amount, subject) {
|
||
return new Promise(async (resolve, reject) => {
|
||
try {
|
||
// 1. 调用后端接口生成支付宝支付订单
|
||
const orderRes = await uni.request({
|
||
url: getApiUrl() + '/api/pay/alipay/createOrder',
|
||
method: 'POST',
|
||
data: {
|
||
out_trade_no: outTradeNo,
|
||
total_amount: amount,
|
||
subject: subject,
|
||
pay_type: 'alipay'
|
||
}
|
||
});
|
||
|
||
// 2. 校验后端返回结果
|
||
if (orderRes.data.code !== 0) {
|
||
reject(new Error(orderRes.data.msg || '生成支付宝支付订单失败'));
|
||
return;
|
||
}
|
||
|
||
// 3. 区分运行端处理(全端返回H5链接)
|
||
const accountInfo = uni.getAccountInfoSync();
|
||
const isWechatMini = accountInfo?.miniProgram?.appId?.includes('wx');
|
||
const isHuaweiQuickApp = uni.getSystemInfoSync().platform === 'quickapp-huawei';
|
||
|
||
if (!orderRes.data.data.payUrl) {
|
||
reject(new Error('未获取到支付宝支付H5跳转链接'));
|
||
return;
|
||
}
|
||
|
||
if (isWechatMini || isHuaweiQuickApp) {
|
||
// 3.1 微信小程序/华为快应用:返回H5链接(适配web-view)
|
||
resolve({
|
||
code: 0,
|
||
msg: '跳转支付宝支付H5页面',
|
||
data: { payUrl: orderRes.data.data.payUrl }
|
||
});
|
||
} else {
|
||
// 3.2 H5端:直接跳转
|
||
window.location.href = orderRes.data.data.payUrl;
|
||
resolve({
|
||
code: 0,
|
||
msg: '跳转支付宝支付页面成功',
|
||
data: {}
|
||
});
|
||
}
|
||
} catch (err) {
|
||
reject(new Error(`支付宝支付异常:${err.message || '网络请求失败'}`));
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 统一支付状态校验(和huaweiPay.js的checkPayStatus对齐)
|
||
* @param {String} outTradeNo 前端生成的订单号
|
||
* @returns {Promise} 校验结果(包含订单实际支付状态)
|
||
*/
|
||
export function checkPayStatus(outTradeNo) {
|
||
return new Promise(async (resolve, reject) => {
|
||
try {
|
||
// 统一调用后端状态校验接口(适配所有支付类型)
|
||
const checkRes = await uni.request({
|
||
url: getApiUrl() + '/api/pay/checkStatus', // 和huaweiPay.js使用同一接口
|
||
method: 'POST',
|
||
data: {
|
||
out_trade_no: outTradeNo
|
||
}
|
||
});
|
||
|
||
resolve(checkRes.data);
|
||
} catch (err) {
|
||
reject(new Error(`校验支付状态失败:${err.message || '网络请求失败'}`));
|
||
}
|
||
});
|
||
}
|
||
/**
|
||
* 华为支付调用封装(适配全端:微信小程序/H5/华为快应用)
|
||
* @param {String} outTradeNo 前端生成的唯一订单号
|
||
* @param {Number} amount 支付金额(单位:元,保留2位小数)
|
||
* @param {String} subject 订单标题
|
||
* @returns {Promise} 支付结果(含H5支付链接/原生支付状态)
|
||
*/
|
||
export function invokeHuaweiPay(outTradeNo, amount, subject) {
|
||
return new Promise(async (resolve, reject) => {
|
||
try {
|
||
// ===== 1. 模拟后端返回合法凭证(跳过真实接口调用)=====
|
||
// 注释掉真实请求后端的代码,直接模拟返回正确格式的凭证
|
||
// const orderRes = await uni.request({
|
||
// url: getApiUrl() + '/api/pay/huawei/createOrder',
|
||
// method: 'POST',
|
||
// data: {
|
||
// out_trade_no: outTradeNo,
|
||
// total_amount: amount,
|
||
// subject: subject,
|
||
// pay_type: 'huaweipay'
|
||
// }
|
||
// });
|
||
// 模拟后端返回的合法数据(重点:code=0,有orderInfo和payUrl)
|
||
const orderRes = {
|
||
data: {
|
||
code: 0,
|
||
msg: '生成华为支付订单成功',
|
||
data: {
|
||
orderInfo: 'test_order_info_123456', // 模拟华为原生SDK需要的参数
|
||
payUrl: 'https://pay.huawei.com/cashier/test' // 模拟H5支付链接
|
||
}
|
||
}
|
||
};
|
||
// =====================================================
|
||
|
||
// ===== 2. 加日志:打印模拟的凭证,看是否拿到数据 =====
|
||
console.log('【华为支付测试】模拟后端返回的凭证:', orderRes.data);
|
||
|
||
// 3. 校验后端返回结果
|
||
if (orderRes.data.code !== 0) {
|
||
reject(new Error(orderRes.data.msg || '生成华为支付订单失败'));
|
||
return;
|
||
}
|
||
|
||
// 4. 区分运行端处理
|
||
const accountInfo = uni.getAccountInfoSync();
|
||
const systemInfo = uni.getSystemInfoSync();
|
||
const isWechatMini = accountInfo?.miniProgram?.appId?.includes('wx'); // 微信小程序
|
||
const isHuaweiQuickApp = systemInfo.platform === 'quickapp-huawei'; // 华为快应用
|
||
|
||
if (isHuaweiQuickApp) {
|
||
// ===== 3. 加日志:标记进入华为快应用逻辑 =====
|
||
console.log('【华为支付测试】进入华为快应用逻辑,尝试调起原生SDK');
|
||
|
||
// 3.1 华为快应用:优先原生SDK调起,失败则降级H5
|
||
if (orderRes.data.data.orderInfo) { // 后端返回华为支付SDK所需的orderInfo
|
||
try {
|
||
const huaweiPay = require('@service.pay.huawei'); // 华为快应用支付SDK
|
||
console.log('【华为支付测试】开始调用华为原生支付SDK');
|
||
huaweiPay.pay({
|
||
orderInfo: orderRes.data.data.orderInfo, // 后端返回的原生支付参数
|
||
success: (res) => {
|
||
console.log('【华为支付测试】原生SDK调起成功', res);
|
||
resolve({
|
||
code: 0,
|
||
msg: '华为支付原生控件唤起成功',
|
||
data: {}
|
||
});
|
||
},
|
||
fail: (err) => {
|
||
console.log('【华为支付测试】原生SDK调起失败,降级到H5', err);
|
||
// 原生唤起失败,降级返回H5链接
|
||
if (orderRes.data.data.payUrl) {
|
||
resolve({
|
||
code: 0,
|
||
msg: '原生支付失败,跳转H5支付',
|
||
data: { payUrl: orderRes.data.data.payUrl }
|
||
});
|
||
} else {
|
||
reject(new Error(`华为支付失败:${err.message || '无H5支付链接'}`));
|
||
}
|
||
}
|
||
});
|
||
} catch (sdkErr) {
|
||
console.log('【华为支付测试】SDK加载失败,降级到H5', sdkErr);
|
||
// SDK加载失败,直接返回H5链接
|
||
if (orderRes.data.data.payUrl) {
|
||
resolve({
|
||
code: 0,
|
||
msg: 'SDK加载失败,跳转H5支付',
|
||
data: { payUrl: orderRes.data.data.payUrl }
|
||
});
|
||
} else {
|
||
reject(new Error('华为支付SDK异常且无H5链接'));
|
||
}
|
||
}
|
||
} else if (orderRes.data.data.payUrl) {
|
||
console.log('【华为支付测试】无原生参数,直接返回H5链接');
|
||
// 无原生参数,直接返回H5链接
|
||
resolve({
|
||
code: 0,
|
||
msg: '跳转华为支付H5页面',
|
||
data: { payUrl: orderRes.data.data.payUrl }
|
||
});
|
||
} else {
|
||
reject(new Error('缺少华为支付参数(原生/H5)'));
|
||
}
|
||
} else if (isWechatMini) {
|
||
// ===== 4. 加日志:标记进入微信小程序逻辑 =====
|
||
console.log('【华为支付测试】进入微信小程序逻辑,返回H5链接');
|
||
|
||
// 3.2 微信小程序:返回H5链接(适配web-view)
|
||
if (!orderRes.data.data.payUrl) {
|
||
reject(new Error('未获取到华为支付H5跳转链接'));
|
||
return;
|
||
}
|
||
resolve({
|
||
code: 0,
|
||
msg: '跳转华为支付H5页面',
|
||
data: { payUrl: orderRes.data.data.payUrl }
|
||
});
|
||
} else {
|
||
// ===== 5. 加日志:标记进入H5端逻辑 =====
|
||
console.log('【华为支付测试】进入H5端逻辑,直接跳转');
|
||
|
||
// 3.3 H5端:直接跳转
|
||
if (!orderRes.data.data.payUrl) {
|
||
reject(new Error('未获取到华为支付跳转链接'));
|
||
return;
|
||
}
|
||
window.location.href = orderRes.data.data.payUrl;
|
||
resolve({
|
||
code: 0,
|
||
msg: '跳转华为支付页面成功',
|
||
data: {}
|
||
});
|
||
}
|
||
} catch (err) {
|
||
console.error('【华为支付测试】整体异常:', err);
|
||
reject(new Error(`华为支付异常:${err.message || '网络请求失败'}`));
|
||
}
|
||
});
|
||
}
|
||
/**
|
||
* 获取API基础URL
|
||
*/
|
||
function getApiUrl() {
|
||
// 尝试获取配置的API地址
|
||
try {
|
||
// #ifdef H5
|
||
const config = require('@/common/js/config.js').default;
|
||
return config.baseUrl || '';
|
||
// #endif
|
||
// #ifndef H5
|
||
const config = require('@/common/js/config.js').default;
|
||
return config.baseUrl || '';
|
||
// #endif
|
||
} catch (e) {
|
||
console.warn('获取API配置失败,使用空字符串');
|
||
return '';
|
||
}
|
||
} |