You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
8.4 KiB
8.4 KiB
🚨 优惠券支付问题分析
问题描述
用户选择优惠券后支付失败,但系统仍然提示"支付成功",这是一个严重的用户体验问题。
🔍 问题分析
1. 支付流程问题
当前支付流程
// OrderConfirm.tsx - onPay函数
const onPay = async (goods: ShopGoods) => {
try {
setPayLoading(true)
// 构建订单数据
const orderData = buildSingleGoodsOrder(
goods.goodsId!,
quantity,
address.id,
{
comments: goods.name,
deliveryType: 0,
buyerRemarks: orderRemark,
couponId: selectedCoupon ? selectedCoupon.id : undefined // ⚠️ 问题点1
}
);
// 执行支付
await PaymentHandler.pay(orderData, paymentType);
// ❌ 问题点2:无论支付是否真正成功,都会显示成功
Taro.showToast({
title: '支付成功',
icon: 'success'
})
} catch (error) {
// ❌ 问题点3:错误处理不够详细
Taro.showToast({
title: '支付失败,请重试',
icon: 'error'
})
}
};
2. PaymentHandler问题
支付处理逻辑缺陷
// payment.ts - PaymentHandler.pay
static async pay(orderData, paymentType, callback?) {
try {
// 创建订单
const result = await createOrder(orderData);
// 根据支付类型处理
switch (paymentType) {
case PaymentType.WECHAT:
await this.handleWechatPay(result);
break;
case PaymentType.BALANCE:
await this.handleBalancePay(result); // ⚠️ 问题点4
break;
}
// ❌ 问题点5:无论实际支付结果如何,都显示成功
Taro.showToast({
title: '支付成功',
icon: 'success'
});
// ❌ 问题点6:自动跳转,用户无法确认实际状态
setTimeout(() => {
Taro.navigateTo({ url: '/user/order/order' });
}, 2000);
} catch (error) {
// 错误处理
}
}
3. 余额支付逻辑问题
余额支付处理不完善
// payment.ts - handleBalancePay
private static async handleBalancePay(result: any): Promise<void> {
// ❌ 问题点7:只检查orderNo,不检查实际支付状态
if (!result || !result.orderNo) {
throw new Error('余额支付失败');
}
// ❌ 问题点8:没有验证余额是否足够,支付是否真正成功
}
4. 优惠券相关问题
优惠券ID传递问题
// OrderConfirm.tsx
couponId: selectedCoupon ? selectedCoupon.id : undefined
// ⚠️ 问题点9:selectedCoupon.id可能是字符串或其他类型
// 后端可能期望数字类型的couponId
🚨 根本原因分析
1. 双重成功提示
OrderConfirm.onPay() → 显示"支付成功"
↓
PaymentHandler.pay() → 再次显示"支付成功"
结果: 即使支付失败,用户也会看到成功提示!
2. 支付状态验证缺失
- 没有验证后端返回的实际支付状态
- 没有检查优惠券是否成功应用
- 没有验证最终扣款金额是否正确
3. 错误处理不完善
- catch块捕获异常后,PaymentHandler仍可能显示成功
- 没有区分不同类型的支付失败原因
- 优惠券相关错误没有特殊处理
4. 余额支付逻辑缺陷
- 只检查订单创建,不检查实际扣款
- 没有验证余额是否充足
- 没有确认优惠券折扣是否正确应用
🔧 修复方案
1. 修复双重提示问题
修改OrderConfirm.tsx
const onPay = async (goods: ShopGoods) => {
try {
setPayLoading(true)
const orderData = buildSingleGoodsOrder(/*...*/);
// ✅ 不在这里显示成功提示,让PaymentHandler统一处理
await PaymentHandler.pay(orderData, paymentType);
// ❌ 删除这里的成功提示
// Taro.showToast({
// title: '支付成功',
// icon: 'success'
// })
} catch (error) {
console.error('支付失败:', error)
// ✅ 只处理PaymentHandler未处理的错误
if (!error.handled) {
Taro.showToast({
title: error.message || '支付失败,请重试',
icon: 'error'
})
}
} finally {
setPayLoading(false)
}
};
2. 完善PaymentHandler
修改payment.ts
static async pay(orderData, paymentType, callback?) {
Taro.showLoading({ title: '支付中...' });
try {
// 创建订单
const result = await createOrder(orderData);
if (!result) {
throw new Error('创建订单失败');
}
// ✅ 验证订单创建结果
if (!result.orderNo) {
throw new Error('订单号获取失败');
}
let paymentSuccess = false;
// 根据支付类型处理
switch (paymentType) {
case PaymentType.WECHAT:
await this.handleWechatPay(result);
paymentSuccess = true;
break;
case PaymentType.BALANCE:
paymentSuccess = await this.handleBalancePay(result);
break;
}
// ✅ 只有确认支付成功才显示成功提示
if (paymentSuccess) {
Taro.showToast({
title: '支付成功',
icon: 'success'
});
callback?.onSuccess?.();
setTimeout(() => {
Taro.navigateTo({ url: '/user/order/order' });
}, 2000);
} else {
throw new Error('支付未完成');
}
} catch (error: any) {
console.error('支付失败:', error);
const errorMessage = error.message || '支付失败';
Taro.showToast({
title: errorMessage,
icon: 'error'
});
// ✅ 标记错误已处理
error.handled = true;
callback?.onError?.(errorMessage);
throw error;
} finally {
Taro.hideLoading();
callback?.onComplete?.();
}
}
3. 完善余额支付处理
private static async handleBalancePay(result: any): Promise<boolean> {
if (!result || !result.orderNo) {
throw new Error('余额支付参数错误');
}
// ✅ 检查支付状态字段
if (result.payStatus === false || result.payStatus === 0) {
throw new Error('余额不足或支付失败');
}
// ✅ 检查订单状态
if (result.orderStatus !== 1) {
throw new Error('订单状态异常');
}
// ✅ 验证实际扣款金额
if (result.payPrice && parseFloat(result.payPrice) <= 0) {
throw new Error('支付金额异常');
}
return true;
}
4. 优惠券ID类型修复
// OrderConfirm.tsx
const orderData = buildSingleGoodsOrder(
goods.goodsId!,
quantity,
address.id,
{
comments: goods.name,
deliveryType: 0,
buyerRemarks: orderRemark,
// ✅ 确保couponId是数字类型
couponId: selectedCoupon ? Number(selectedCoupon.id) : undefined
}
);
5. 增强错误处理
// 在PaymentHandler中添加详细错误分类
private static getErrorMessage(error: any): string {
if (error.message?.includes('余额不足')) {
return '账户余额不足,请充值后重试';
}
if (error.message?.includes('优惠券')) {
return '优惠券使用失败,请重新选择';
}
if (error.message?.includes('库存')) {
return '商品库存不足,请减少购买数量';
}
return error.message || '支付失败,请重试';
}
🧪 测试验证
1. 测试场景
- 使用优惠券 + 余额支付
- 使用优惠券 + 微信支付
- 余额不足的情况
- 优惠券失效的情况
- 网络异常的情况
2. 验证要点
- 支付成功时只显示一次成功提示
- 支付失败时显示具体失败原因
- 优惠券折扣正确应用
- 最终扣款金额正确
- 订单状态正确更新
🎯 修复优先级
🔥 紧急修复
- 移除双重成功提示 - 避免误导用户
- 完善支付状态验证 - 确保支付真正成功
- 修复余额支付逻辑 - 检查实际扣款状态
🔶 重要改进
- 优化错误提示 - 提供具体失败原因
- 优惠券ID类型修复 - 确保数据类型正确
- 增强日志记录 - 便于问题排查
🚨 临时解决方案
在完整修复之前,可以:
- 禁用优惠券功能 - 避免支付问题
- 添加支付确认步骤 - 让用户确认支付结果
- 增加订单状态检查 - 支付后验证订单状态
建议立即修复此问题,避免用户资金损失和投诉! 🚨