支付宝兼容

This commit is contained in:
2026-03-09 09:07:58 +08:00
parent 069677957e
commit b3836b8bf2
31 changed files with 2382 additions and 307 deletions
+183 -51
View File
@@ -78,6 +78,10 @@
} from '@dcloudio/uni-app'
import {
queryById,
createWxPayment,
getWxPaymentStatus,
createAliPayment,
getAliPaymentStatus,
createAntomPayment,
getAntomPaymentMethods,
getAntomPaymentStatus
@@ -107,9 +111,9 @@
const countdown = ref(15 * 60) // 15分钟 = 900秒
let countdownTimer = null
// 支付方式相关
// 支付方式相关(微信/支付宝/H5-Antom 多平台)
const paymentMethods = ref([])
const selectedPaymentMethod = ref('ALIPAY') // 默认选择支付宝
const selectedPaymentMethod = ref('WECHAT') // 默认微信
// 地点名称(可以从设备信息中获取,这里先用默认值)
const locationName = ref('澎创办公室')
@@ -197,11 +201,11 @@
deviceNo.value = orderData.deviceNo;
await loadDeviceInfo();
await loadPaymentMethods();
// #ifdef H5
// 如果订单状态是等待支付,启动相应的支付状态轮询
if(orderInfo.value.orderStatus=='waiting_for_payment'){
// 使用当前选中的支付方式类型进行轮询
startPaymentStatusPolling();
}
// #endif
} else {
throw new Error(t('order.getOrderFailed'))
}
@@ -253,35 +257,46 @@
}
}
// 加载支付方式列表
// 加载支付方式列表(根据平台决定可选项)
const loadPaymentMethods = async () => {
if (!orderInfo.value.orderNo) return;
const methods = []
try {
const osType = getOsType();
console.log('当前系统类型:', osType);
// 小程序环境下:微信 / 支付宝
// #ifdef MP-WEIXIN
methods.push({ paymentMethodType: 'WECHAT', paymentMethodName: '微信支付' })
// #endif
// #ifdef MP-ALIPAY
methods.push({ paymentMethodType: 'ALIPAY', paymentMethodName: '支付宝支付' })
// #endif
const res = await getAntomPaymentMethods(orderInfo.value.orderNo, osType);
if (res.code === 200 && res.data && res.data.paymentOptions) {
paymentMethods.value = res.data.paymentOptions;
console.log('支付方式列表:', paymentMethods.value);
// 如果有支付方式,默认选择第一个
if (paymentMethods.value.length > 0) {
selectedPaymentMethod.value = paymentMethods.value[0].paymentMethodType;
// H5 环境:使用 Antom 聚合支付(多通道)
// #ifdef H5
if (orderInfo.value.orderNo) {
try {
const osType = getOsType();
const res = await getAntomPaymentMethods(orderInfo.value.orderNo, osType);
if (res.code === 200 && res.data && res.data.paymentOptions) {
res.data.paymentOptions.forEach(item => {
methods.push({
paymentMethodType: item.paymentMethodType,
paymentMethodName: item.paymentMethodName || item.paymentMethodType
});
});
}
} catch (error) {
console.error('获取 Antom 支付方式失败:', error);
}
} catch (error) {
console.error('获取支付方式失败:', error);
// 如果获取失败,使用默认支付方式
paymentMethods.value = [{
paymentMethodType: 'ALIPAY',
paymentMethodName: '支付'
},
{
paymentMethodType: 'WECHATPAY',
paymentMethodName: '微信支付'
}
];
}
// #endif
// 兜底:至少保留一个微信
if (!methods.length) {
methods.push({ paymentMethodType: 'WECHAT', paymentMethodName: '微信支付' })
}
paymentMethods.value = methods
if (paymentMethods.value.length > 0) {
selectedPaymentMethod.value = paymentMethods.value[0].paymentMethodType
}
}
@@ -315,8 +330,85 @@
title: t('common.processing')
})
const method = selectedPaymentMethod.value
// 微信小程序支付押金
// #ifdef MP-WEIXIN
if (method === 'WECHAT') {
const wxRes = await createWxPayment(orderInfo.value.orderNo)
if (wxRes.code === 200 && wxRes.data) {
const payData = wxRes.data
await new Promise((resolve, reject) => {
wx.requestPayment({
...payData,
success: resolve,
fail: reject
})
})
// 支付成功后轮询微信支付状态
startPaymentStatusPolling('WECHAT')
return
} else {
throw new Error(wxRes.msg || t('payment.createPayOrderFailed'))
}
}
// #endif
// 支付宝小程序支付押金
// #ifdef MP-ALIPAY
if (method === 'ALIPAY') {
const aliRes = await createAliPayment(orderInfo.value.orderNo)
if (aliRes.code === 200 && aliRes.data) {
// 后端当前实际返回结构示例:
// { code:200, msg:'操作成功', data:{ tradeNo:'xxx', outTradeNo:'yyy' } }
const tradeNO = aliRes.data.tradeNo || aliRes.data.outTradeNo
const payForm = aliRes.data.payForm || aliRes.data.orderStr
if (!tradeNO && !payForm) {
throw new Error('未获取到支付宝支付参数')
}
// 优先使用 tradeNO 方式,其次兼容老的 orderStr 方式
if (tradeNO) {
my.tradePay({
tradeNO,
success: (res) => {
if (res.resultCode === '9000') {
startPaymentStatusPolling('ALIPAY')
} else {
uni.showToast({ title: t('payment.paymentFailed'), icon: 'none' })
}
},
fail: () => {
uni.showToast({ title: t('payment.paymentFailed'), icon: 'none' })
}
})
} else {
my.tradePay({
orderStr: payForm,
success: (res) => {
if (res.resultCode === '9000') {
startPaymentStatusPolling('ALIPAY')
} else {
uni.showToast({ title: t('payment.paymentFailed'), icon: 'none' })
}
},
fail: () => {
uni.showToast({ title: t('payment.paymentFailed'), icon: 'none' })
}
})
}
return
} else {
throw new Error(aliRes.msg || t('payment.createPayOrderFailed'))
}
}
// #endif
// H5 + Antom 聚合支付
// #ifdef H5
const osType = getOsType();
const res = await createAntomPayment(orderInfo.value.orderNo, selectedPaymentMethod.value, osType)
const res = await createAntomPayment(orderInfo.value.orderNo, method, osType)
if (res && res.code === 200 && res.data) {
const paymentUrl = res.data.h5Url;
@@ -326,21 +418,16 @@
}
uni.hideLoading();
// #ifdef H5
uni.setStorageSync('pendingPaymentNo', orderId.value);
// 跳转到支付页面
// uni.navigateTo({
// url: `/pages/webview/index?url=${encodeURIComponent(paymentUrl)}&title=支付`
// });
window.open(paymentUrl);
// #endif
// 开始轮询支付状态
startPaymentStatusPolling();
// 开始轮询支付状态(传入当前选中的支付方式类型)
startPaymentStatusPolling(method);
return
} else {
throw new Error(res?.msg || t('payment.createPayOrderFailed'))
}
// #endif
} catch (error) {
console.error('支付失败:', error)
uni.showToast({
@@ -352,14 +439,22 @@
}
}
// 轮询支付状态
// 轮询定时器
let pollingTimer = null;
const startPaymentStatusPolling = () => {
/**
* 统一的支付状态轮询方法
* @param {string} paymentMethodType - 支付方式类型,如 'WECHAT' | 'ALIPAY' | 'WECHATPAY' 等,与 selectedPaymentMethod 保持一致
*/
const startPaymentStatusPolling = (paymentMethodType = null) => {
// 清除之前的定时器
if (pollingTimer) {
clearInterval(pollingTimer);
}
// 如果没有传入支付方式类型,使用当前选中的支付方式
const methodType = paymentMethodType || selectedPaymentMethod.value;
let pollCount = 0;
const maxPollCount = 60; // 最多轮询60次(5分钟)
@@ -376,32 +471,64 @@
}
try {
let res;
let status, successStatus, failStatuses;
// #ifdef H5
// H5 环境统一使用 Antom 聚合支付 API
const osType = getOsType();
const res = await getAntomPaymentStatus(orderInfo.value.orderNo, osType);
res = await getAntomPaymentStatus(orderInfo.value.orderNo, osType);
if (res && res.code === 200 && res.data) {
const paymentStatus = res.data.paymentStatus;
status = res.data.paymentStatus;
successStatus = 'SUCCESS';
failStatuses = ['FAIL', 'CANCELLED'];
}
// #endif
// #ifdef MP-WEIXIN
// 微信小程序:根据支付方式类型判断
if (methodType === 'WECHAT' || methodType === 'WECHATPAY') {
res = await getWxPaymentStatus(orderInfo.value.orderNo);
if (res && res.code === 200 && res.data) {
status = res.data.tradeStatus;
successStatus = 'SUCCESS';
failStatuses = ['FAIL', 'CANCELLED'];
}
}
// #endif
// #ifdef MP-ALIPAY
// 支付宝小程序
if (methodType === 'ALIPAY') {
res = await getAliPaymentStatus(orderInfo.value.orderNo);
if (res && res.code === 200 && res.data) {
status = res.data.tradeStatus;
successStatus = 'TRADE_SUCCESS';
failStatuses = ['TRADE_FAIL', 'TRADE_CANCELLED'];
}
}
// #endif
if (paymentStatus === 'SUCCESS') {
// 处理支付状态结果
if (res && res.code === 200 && res.data && status) {
// 支付成功
if (status === successStatus) {
clearInterval(pollingTimer);
// uni.showToast({
// title: t('payment.paymentSuccess'),
// icon: 'success'
// });
try {
await updateUserBalance(orderId.value);
} catch (error) {
console.warn('更新用户余额失败:', error);
}
console.log(orderInfo);
setTimeout(() => {
uni.redirectTo({
url: `/pages/order/success?orderId=${orderId.value}&deviceId=${orderInfo.value.deviceNo}`
});
}, 1500);
} else if (paymentStatus === 'FAIL' || paymentStatus === 'CANCELLED') {
}
// 支付失败
else if (failStatuses && failStatuses.includes(status)) {
clearInterval(pollingTimer);
uni.showToast({
title: '支付失败,请重新支付',
@@ -410,11 +537,16 @@
}
}
} catch (error) {
console.error('查询支付状态失败:', error);
const errorMsg = methodType === 'ALIPAY' ? '支付宝' : (methodType === 'WECHAT' || methodType === 'WECHATPAY') ? '微信' : '支付';
console.error(`查询${errorMsg}支付状态失败:`, error);
}
}, 5000); // 每5秒查询一次
}
// 兼容性方法:保持原有函数名,内部调用统一方法
const startWxPaymentStatusPolling = () => startPaymentStatusPolling('WECHAT');
const startAliPaymentStatusPolling = () => startPaymentStatusPolling('ALIPAY');
// 更新导航栏倒计时
const updateNavBarCountdown = () => {
const minutes = Math.floor(countdown.value / 60).toString().padStart(2, '0')