import sheep from '@/sheep'; // #ifdef H5 import $wxsdk from '@/sheep/libs/sdk-h5-weixin'; // #endif import { getRootUrl } from '@/sheep/helper'; import { h5Url } from '@/sheep/config'; import PayOrderApi from '@/sheep/api/pay/order'; import { openExternalUrl } from './h5-shell'; /** * 支付 * * @param {String} payment = ['wechat','alipay','wallet','mock'] - 支付方式 * @param {String} orderType = ['goods','recharge','groupon'] - 订单类型 * @param {String} id - 订单号 */ export default class SheepPay { constructor(payment, orderType, id, autoPay = true) { this.payment = payment; this.id = id; this.orderType = orderType; if (autoPay) { this.payAction(); } } static payH5(payment, orderType, id) { return new SheepPay(payment, orderType, id, false).h5PayAction(); } payAction() { const payAction = { WechatOfficialAccount: { wechat: () => { this.wechatOfficialAccountPay(); }, alipay: () => { this.redirectPay(); // 现在公众号可以直接跳转支付宝页面 }, wallet: () => { this.walletPay(); }, mock: () => { this.mockPay(); }, }, WechatMiniProgram: { wechat: () => { this.wechatMiniProgramPay(); }, alipay: () => { this.copyPayLink(); }, wallet: () => { this.walletPay(); }, mock: () => { this.mockPay(); }, }, App: { wechat: () => { this.wechatAppPay(); }, alipay: () => { this.alipay(); }, wallet: () => { this.walletPay(); }, mock: () => { this.mockPay(); }, }, H5: { wechat: () => { this.wechatWapPay(); }, alipay: () => { this.redirectPay(); }, wallet: () => { this.walletPay(); }, mock: () => { this.mockPay(); }, }, }; return payAction[sheep.$platform.name][this.payment](); } h5PayAction() { const payAction = { wechat: () => this.wechatWapPay(), alipay: () => this.redirectPay(), }; const action = payAction[this.payment]; if (!action) { return Promise.reject(new Error(`H5 支付不支持支付方式: ${this.payment}`)); } return action().then((started) => { if (!started) { throw new Error('H5 支付调起失败'); } return true; }); } // 预支付 async prepay(channel, returnUrl = '') { const data = { id: this.id, channelCode: channel, channelExtras: {}, }; if (returnUrl) { data.returnUrl = returnUrl; } // 特殊逻辑:微信公众号、小程序支付时,必须传入 openid if (['wx_pub', 'wx_lite'].includes(channel)) { const openid = await sheep.$platform.useProvider('wechat').getOpenid(true); // 如果获取不到 openid,微信无法发起支付,此时需要引导 if (!openid) { this.bindWeixin(); return { code: -1, data: null }; } data.channelExtras.openid = openid; } const res = await PayOrderApi.submitOrder(data); const message = res.msg || ''; if ( res.code !== 0 && (message.includes('无效的openid') || message.includes('下单账号与支付账号不一致')) ) { // https://developers.weixin.qq.com/community/develop/doc/00008c53c347804beec82aed051c00 this.bindWeixin(); } return res; } // #ifdef H5 // 微信公众号 JSSDK 支付 async wechatOfficialAccountPay() { let { code, data } = await this.prepay('wx_pub'); if (code !== 0) { return; } const payConfig = JSON.parse(data.displayContent); $wxsdk.wxpay(payConfig, { success: () => { this.payResult('success'); }, cancel: () => { sheep.$helper.toast('支付已手动取消'); }, fail: (error) => { if (error.errMsg.indexOf('chooseWXPay:没有此SDK或暂不支持此SDK模拟') >= 0) { sheep.$helper.toast( '发起微信支付失败,原因:可能是微信开发者工具不支持,建议使用微信打开网页后支付', ); return; } this.payResult('fail'); }, }); } // #endif // 微信 H5 支付 async wechatWapPay() { const returnUrl = this.getH5PayResultUrl(); const { code, data } = await this.prepay('wx_wap', returnUrl); if (code !== 0 || !data?.displayContent) { return false; } const separator = data.displayContent.includes('?') ? '&' : '?'; const payUrl = returnUrl ? `${data.displayContent}${separator}redirect_url=${encodeURIComponent(returnUrl)}` : data.displayContent; this.openH5PayUrl(payUrl, '微信支付'); return true; } // 支付链接(支付宝 wap 支付) async redirectPay() { const { code, data } = await this.prepay('alipay_wap', this.getH5PayResultUrl()); if (code !== 0 || !data?.displayContent) { return false; } this.openH5PayUrl(data.displayContent, '支付宝支付'); return true; } getH5PayResultUrl() { let rootUrl = getRootUrl(); if (!rootUrl && h5Url) { rootUrl = `${String(h5Url).replace(/\/+$/, '')}/#/`; } if (!rootUrl) { return ''; } return `${rootUrl}pages/profile/pay-result?id=${encodeURIComponent(this.id)}&payment=${encodeURIComponent( this.payment, )}&orderType=${encodeURIComponent(this.orderType)}`; } openH5PayUrl(url, title) { // #ifndef MP openExternalUrl(url, `h5-pay:${title}`); // #endif // #ifdef MP uni.showModal({ title, content: '请复制链接到手机浏览器完成支付', confirmText: '复制链接', success: (res) => { if (res.confirm) { sheep.$helper.copyText(url); } }, }); // #endif } // 微信小程序支付 async wechatMiniProgramPay() { // let that = this; let { code, data } = await this.prepay('wx_lite'); if (code !== 0) { return; } // 调用微信小程序支付 const payConfig = JSON.parse(data.displayContent); uni.requestPayment({ provider: 'wxpay', timeStamp: payConfig.timeStamp, nonceStr: payConfig.nonceStr, package: payConfig.packageValue, signType: payConfig.signType, paySign: payConfig.paySign, success: (res) => { this.payResult('success'); }, fail: (err) => { if (err.errMsg === 'requestPayment:fail cancel') { sheep.$helper.toast('支付已手动取消'); } else { this.payResult('fail'); } }, }); } // 余额支付 async walletPay() { const { code } = await this.prepay('wallet'); code === 0 && this.payResult('success'); } // 模拟支付 async mockPay() { const { code } = await this.prepay('mock'); code === 0 && this.payResult('success'); } // 支付宝复制链接支付(通过支付宝 wap 支付实现) async copyPayLink() { let { code, data } = await this.prepay('alipay_wap'); if (code !== 0) { return; } // 引入 showModal 点击确认:复制链接; uni.showModal({ title: '支付宝支付', content: '复制链接到外部浏览器', confirmText: '复制链接', success: (res) => { if (res.confirm) { sheep.$helper.copyText(data.displayContent); // uni.navigateTo({ url: '/pages/profile/alipay-webview?url=' + encodeURIComponent(data.displayContent) }) } }, }); } // 支付宝支付(App) async alipay() { let that = this; const { code, data } = await this.prepay('alipay_app'); if (code !== 0) { return; } // TODO @芋艿:【可优化】如果是沙箱支付,EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX),相关 https://t.zsxq.com/yjyJQ uni.requestPayment({ provider: 'alipay', orderInfo: data.displayContent, // 直接使用返回的支付参数 success: (res) => { that.payResult('success'); }, fail: (err) => { if (err.errMsg === 'requestPayment:fail [paymentAlipay:62001]user cancel') { sheep.$helper.toast('支付已手动取消'); } else { that.payResult('fail'); } }, }); } // 微信支付(App) async wechatAppPay() { let that = this; // 获取预支付信息 let { code, data } = await this.prepay('wx_app'); if (code !== 0) { sheep.$helper.toast('获取支付信息失败'); return; } // 解析支付参数 let payConfig = JSON.parse(data.displayContent); if (typeof payConfig.appId === 'undefined') { payConfig.appId = payConfig.appid; } if (typeof payConfig.nonceStr === 'undefined') { payConfig.nonceStr = payConfig.noncestr; } if (typeof payConfig.timeStamp === 'undefined') { payConfig.timeStamp = payConfig.timestamp; } // 调用微信支付 uni.requestPayment({ provider: 'wxpay', timeStamp: payConfig.timeStamp, nonceStr: payConfig.nonceStr, package: payConfig.packageValue, signType: payConfig.signType, paySign: payConfig.paySign, success: (res) => { that.payResult('success'); }, fail: (err) => { if (err.errMsg === 'requestPayment:fail cancel') { sheep.$helper.toast('支付已手动取消'); } else { sheep.$helper.toast('支付失败:' + err.errMsg); that.payResult('fail'); } }, }); } // 支付结果跳转,success:成功,fail:失败 payResult(resultType) { goPayResult(this.id, this.orderType, resultType); } // 引导绑定微信 bindWeixin() { goBindWeixin(); } } export function getPayMethods(channels) { const payMethods = [ { icon: '/static/img/shop/pay/wechat.png', title: '微信支付', value: 'wechat', disabled: true, }, { icon: '/static/img/shop/pay/alipay.png', title: '支付宝支付', value: 'alipay', disabled: true, }, { icon: '/static/img/shop/pay/wallet.png', title: '余额支付', value: 'wallet', disabled: true, }, { icon: '/static/img/shop/pay/apple.png', title: 'Apple Pay', value: 'apple', disabled: true, }, { icon: '/static/img/shop/pay/wallet.png', title: '模拟支付', value: 'mock', disabled: true, }, ]; const platform = sheep.$platform.name; // 1. 处理【微信支付】 const wechatMethod = payMethods[0]; if ( (platform === 'WechatOfficialAccount' && channels.includes('wx_pub')) || (platform === 'WechatMiniProgram' && channels.includes('wx_lite')) || (platform === 'App' && channels.includes('wx_app')) ) { wechatMethod.disabled = false; } // 2. 处理【支付宝支付】 const alipayMethod = payMethods[1]; if ( (platform === 'H5' && channels.includes('alipay_wap')) || (platform === 'WechatOfficialAccount' && channels.includes('alipay_wap')) || (platform === 'WechatMiniProgram' && channels.includes('alipay_wap')) || (platform === 'App' && channels.includes('alipay_app')) ) { alipayMethod.disabled = false; } // 3. 处理【余额支付】 const walletMethod = payMethods[2]; if (channels.includes('wallet')) { walletMethod.disabled = false; } // 4. 处理【苹果支付】TODO 芋艿:未来接入 // 5. 处理【模拟支付】 const mockMethod = payMethods[4]; if (channels.includes('mock')) { mockMethod.disabled = false; } return payMethods; } // 支付结果跳转,success:成功,fail:失败 export function goPayResult(id, orderType, resultType) { // const url = `/pages/pay/result?id=${id}&orderType=${orderType}&payState=${resultType}`; const url = `/pages/profile/pay-result?id=${id}&orderType=${orderType}&payState=${resultType}`; uni.redirectTo({ url: url }) } export function goBindWeixin() { uni.showModal({ title: '微信支付', content: '请先绑定微信再使用微信支付', success: function (res) { if (res.confirm) { sheep.$platform.useProvider('wechat').bind(); } }, }); } // 获取微信支付渠道码 export function getWeixinPayChannelCode() { const platform = sheep.$platform.name; switch (platform) { case 'WechatOfficialAccount': return 'wx_pub'; case 'WechatMiniProgram': return 'wx_lite'; case 'App': return 'wx_app'; case 'H5': return 'wx_wap'; default: return ''; } }