import sheep from '@/sheep'; // #ifdef H5 import $wxsdk from '@/sheep/libs/sdk-h5-weixin'; // #endif import { getRootUrl } from '@/sheep/helper'; import CcbLifePlatform from './provider/ccblife/index'; import ccbApi from './provider/ccblife/api'; /** * 支付 * * @param {String} payment = ['wechat','alipay','wallet','offline'] - 支付方式 * @param {String} orderType = ['goods','recharge','groupon'] - 订单类型 * @param {String} orderSN - 订单号 */ export default class SheepPay { constructor(payment, orderType, orderSN) { this.payment = payment; this.orderSN = orderSN; this.orderType = orderType; this.payAction(); } payAction() { // 调试日志:打印当前平台和支付方式 console.log('[支付调试] 当前平台:', sheep.$platform.name, '支付方式:', this.payment); const payAction = { WechatOfficialAccount: { wechat: () => { this.wechatOfficialAccountPay(); }, alipay: () => { this.redirectPay(); // 现在公众号可以直接跳转支付宝页面 }, ccb: () => { this.ccbPay(); // 建行支付 }, money: () => { this.moneyPay(); }, offline: () => { this.offlinePay(); } }, WechatMiniProgram: { wechat: () => { this.wechatMiniProgramPay(); }, alipay: () => { this.copyPayLink(); }, ccb: () => { sheep.$helper.toast('小程序暂不支持建行支付'); }, money: () => { this.moneyPay(); }, offline: () => { this.offlinePay(); } }, App: { wechat: () => { this.wechatAppPay(); }, alipay: () => { this.alipay(); }, ccb: () => { this.ccbPay(); // 建行支付 }, money: () => { this.moneyPay(); }, offline: () => { this.offlinePay(); } }, H5: { wechat: () => { // 如果在建行App内,使用建行支付 if (CcbLifePlatform.isInCcbApp) { this.ccbPay(); } else { this.wechatWapPay(); } }, alipay: () => { this.redirectPay(); }, ccb: () => { this.ccbPay(); // 建行支付 }, money: () => { this.moneyPay(); }, offline: () => { this.offlinePay(); } }, // ⭐ 建行生活平台(CcbLife) CcbLife: { wechat: () => { this.ccbPay(); // 在建行生活内使用建行支付 }, alipay: () => { sheep.$helper.toast('请使用建行支付'); }, ccb: () => { this.ccbPay(); // 建行支付 }, money: () => { this.moneyPay(); }, offline: () => { this.offlinePay(); } }, }; // 防御性检查:确保平台配置存在 if (!payAction[sheep.$platform.name]) { console.error('[支付错误] 未知平台:', sheep.$platform.name); sheep.$helper.toast('当前平台不支持该支付方式'); return; } // 防御性检查:确保支付方式存在 if (!payAction[sheep.$platform.name][this.payment]) { console.error('[支付错误] 平台不支持该支付方式:', { platform: sheep.$platform.name, payment: this.payment }); sheep.$helper.toast(`当前平台不支持${this.payment}支付`); return; } return payAction[sheep.$platform.name][this.payment](); } // 预支付 prepay() { return new Promise((resolve, reject) => { let data = { order_sn: this.orderSN, payment: this.payment, }; if (uni.getStorageSync('openid')) { data.openid = uni.getStorageSync('openid'); } sheep.$api.pay.prepay(data).then((res) => { res.code === 1 && resolve(res); if (res.data === -1 && res.msg === 'miss_openid') { uni.showModal({ title: '微信支付', content: '请先绑定微信再使用微信支付', success: function (res) { if (res.confirm) { sheep.$platform.useProvider('wechat').bind(); } }, }); } }); }); } // #ifdef H5 // 微信公众号JSSDK支付 async wechatOfficialAccountPay() { let that = this; let { code, data, msg } = await this.prepay(); if (code !== 1) { console.log('支付错误', msg); return; } $wxsdk.wxpay(data.pay_data, { success: () => { that.payResult('success'); }, cancel: () => { sheep.$helper.toast('支付已手动取消'); }, fail: () => { that.payResult('fail'); }, }); } //浏览器微信H5支付 async wechatWapPay() { const { code, data } = await this.prepay(); if (code === 1) { const redirect_url = `${getRootUrl()}pages/pay/result?orderSN=${this.orderSN}&payment=${this.payment }&orderType=${this.orderType}`; location.href = `${data.pay_data.h5_url}&redirect_url=${encodeURIComponent(redirect_url)}`; } } // 支付链接 async redirectPay() { let { code, data } = await this.prepay(); if (code === 1) { const redirect_url = `${getRootUrl()}pages/pay/result?orderSN=${this.orderSN}&payment=${this.payment }&orderType=${this.orderType}`; location.href = data.pay_data + encodeURIComponent(redirect_url); } } // #endif // 微信小程序支付 async wechatMiniProgramPay() { let that = this; let result = await this.prepay(); uni.requestPayment({ provider: 'wxpay', ...result.data.pay_data, success: (res) => { that.payResult('success'); }, fail: (err) => { if (err.errMsg === 'requestPayment:fail cancel') { sheep.$helper.toast('支付已手动取消'); } else { that.payResult('fail'); } }, }); } // 余额支付 async moneyPay() { const { code } = await this.prepay(); code === 1 && this.payResult('success'); } // 货到付款 async offlinePay() { const { code } = await this.prepay(); code === 1 && this.payResult('success'); } // 支付宝复制链接支付 async copyPayLink() { let that = this; let { code, data } = await this.prepay(); if (code === 1) { // 引入showModal 点击确认 复制链接; uni.showModal({ title: '支付宝支付', content: '复制链接到外部浏览器', confirmText: '复制链接', success: (res) => { if (res.confirm) { sheep.$helper.copyText(data.pay_data); } }, }); } } // 支付宝支付 async alipay() { let that = this; const { code, data } = await this.prepay(); if (code === 1) { uni.requestPayment({ provider: 'alipay', orderInfo: data.pay_data, //支付宝订单数据 success: (res) => { that.payResult('success'); }, fail: (err) => { if (err.errMsg === 'requestPayment:fail [paymentAlipay:62001]user cancel') { sheep.$helper.toast('支付已手动取消'); } else { that.payResult('fail'); } }, }); } } // 微信支付 async wechatAppPay() { let that = this; let { code, data } = await this.prepay(); if (code === 1) { uni.requestPayment({ provider: 'wxpay', orderInfo: data.pay_data, //微信订单数据(官方说是string。实测为object) success: (res) => { that.payResult('success'); }, fail: (err) => { err.errMsg !== 'requestPayment:fail cancel' && that.payResult('fail'); }, }); } } // 建行生活支付 async ccbPay() { let that = this; console.log('[建行支付] ========== 开始建行支付流程 =========='); console.log('[建行支付] 订单号:', this.orderSN); console.log('[建行支付] 订单类型:', this.orderType); // 检查是否在建行App内 console.log('[建行支付] 检查建行App环境...'); console.log('[建行支付] isInCcbApp:', CcbLifePlatform.isInCcbApp); console.log('[建行支付] User Agent:', navigator.userAgent); console.log('[建行支付] URL参数:', location.search); if (!CcbLifePlatform.isInCcbApp) { console.error('[建行支付] ❌ 不在建行App内'); sheep.$helper.toast('请在建行生活App内使用建行支付'); return; } console.log('[建行支付] ✅ 确认在建行App内'); // 获取订单ID(从订单号查询) console.log('[建行支付] 步骤1: 查询订单信息...'); try { const orderInfo = await sheep.$api.order.detail(this.orderSN); console.log('[建行支付] 订单查询结果:', orderInfo); if (!orderInfo || orderInfo.code !== 1) { console.error('[建行支付] ❌ 获取订单信息失败:', orderInfo); sheep.$helper.toast('获取订单信息失败'); return; } const orderId = orderInfo.data.id; console.log('[建行支付] ✅ 订单ID:', orderId); console.log('[建行支付] 订单金额:', orderInfo.data.pay_fee); console.log('[建行支付] 订单状态:', orderInfo.data.status); // 调用后端生成支付串 console.log('[建行支付] 步骤2: 调用后端生成支付串...'); console.log('[建行支付] 请求参数:', { order_id: orderId }); const paymentResult = await ccbApi.createPayment(orderId); console.log('[建行支付] 支付串生成结果:', paymentResult); if (paymentResult.code !== 1) { console.error('[建行支付] ❌ 生成支付串失败:', paymentResult); console.error('[建行支付] 错误信息:', paymentResult.msg); console.error('[建行支付] 完整响应:', JSON.stringify(paymentResult)); sheep.$helper.toast(paymentResult.msg || '生成支付串失败'); return; } console.log('[建行支付] ✅ 支付串生成成功'); console.log('[建行支付] 支付串长度:', paymentResult.data.payment_string?.length); console.log('[建行支付] 支付流水号:', paymentResult.data.pay_flow_id); console.log('[建行支付] 支付金额:', paymentResult.data.amount); } catch (error) { console.error('[建行支付] ❌ 异常:', error); console.error('[建行支付] 错误堆栈:', error.stack); sheep.$helper.toast('支付准备失败: ' + error.message); return; } // 调起建行支付 console.log('[建行支付] 步骤3: 调起建行收银台...'); try { const paymentParams = { payment_string: paymentResult.data.payment_string, order_id: orderId, order_sn: this.orderSN }; console.log('[建行支付] 调起参数:', { order_id: paymentParams.order_id, order_sn: paymentParams.order_sn, payment_string_length: paymentParams.payment_string?.length }); const result = await CcbLifePlatform.payment(paymentParams); console.log('[建行支付] 收银台调起结果:', result); if (result.code === 0) { // ✅ 支付调起成功,开始轮询查询订单状态 console.log('[建行支付] ✅ 支付调起成功,开始轮询查询订单状态'); // 显示加载提示 uni.showLoading({ title: '支付确认中...', mask: true }); // 轮询查询订单状态(最多30次,每次间隔2秒,总共60秒) let pollCount = 0; const MAX_POLL_COUNT = 30; const POLL_INTERVAL = 2000; // 2秒 const pollPaymentStatus = async () => { pollCount++; console.log(`[建行支付] 轮询查询 ${pollCount}/${MAX_POLL_COUNT} 次...`); try { const statusResult = await ccbApi.queryPaymentStatus(orderId); console.log('[建行支付] 查询结果:', statusResult); if (statusResult.code === 1 && statusResult.data.is_paid) { // ✅ 支付成功 uni.hideLoading(); console.log('[建行支付] ✅ 订单已支付 order_id:' + orderId); console.log('[建行支付] 支付时间:', statusResult.data.paid_time); that.payResult('success'); return; } console.log('[建行支付] 订单状态:', statusResult.data.status); console.log('[建行支付] 是否已支付:', statusResult.data.is_paid); // 未支付,继续轮询 if (pollCount < MAX_POLL_COUNT) { console.log(`[建行支付] ${POLL_INTERVAL/1000}秒后继续查询...`); setTimeout(pollPaymentStatus, POLL_INTERVAL); } else { // 超时 console.warn('[建行支付] ⚠️ 轮询超时,可能支付未完成'); uni.hideLoading(); uni.showModal({ title: '提示', content: '支付确认超时,请稍后在订单列表中查看支付状态', showCancel: false, confirmText: '知道了', success: () => { // 跳转到订单列表 sheep.$router.redirect('/pages/order/list'); } }); } } catch (error) { console.error('[建行支付] ❌ 查询状态失败:', error); console.error('[建行支付] 错误详情:', error.message); // 继续轮询(网络错误不中断) if (pollCount < MAX_POLL_COUNT) { setTimeout(pollPaymentStatus, POLL_INTERVAL); } else { uni.hideLoading(); sheep.$helper.toast('支付状态查询失败,请稍后在订单列表中查看'); that.payResult('fail'); } } }; // 延迟1秒后开始轮询(给建行异步通知留点时间) setTimeout(pollPaymentStatus, 1000); } else { // 支付失败或取消 console.error('[建行支付] ❌ 支付未成功:', result); if (result.msg && result.msg.includes('取消')) { console.log('[建行支付] 用户取消支付'); sheep.$helper.toast('支付已取消'); } else { console.error('[建行支付] 支付失败原因:', result.msg); sheep.$helper.toast(result.msg || '支付失败'); that.payResult('fail'); } } } catch (error) { console.error('[建行支付] ❌ 异常错误:', error); console.error('[建行支付] 错误类型:', error.name); console.error('[建行支付] 错误信息:', error.message); console.error('[建行支付] 错误堆栈:', error.stack); sheep.$helper.toast('支付失败: ' + error.message); that.payResult('fail'); } console.log('[建行支付] ========== 建行支付流程结束 =========='); } // 支付结果跳转,success:成功,fail:失败 payResult(resultType) { sheep.$router.redirect('/pages/pay/result', { orderSN: this.orderSN, payment: this.payment, //重新支付的时候使用 payState: resultType, orderType: this.orderType, }); } }