/** * @name: 支付工具方法 * @author: kahu4 * @date: 2023-11-07 11:42 * @description:支付工具方法 请使用try catch抓取异常或者.catch抓取异常 * @update: 2023-11-07 11:42 * */ import { useInterface } from "@/hooks/useInterface"; import { createMessage, h5InWeChat } from "@/utils/index"; import { wechatPay } from "@/api/order"; import { CacheKey } from "@/utils/config"; import { useRouter } from "@/hooks/useRouter"; const {loading, hideLoading} = useInterface() const {push} = useRouter() // 微信支付的provider export const WechatProvider = 'wxpay' // 支付类型(后端用) export const ServiceFrom = { 'h5': 'h5', // H5(微信内h5、微信外H5) 'weixin': 'weixin_applet', // 微信小程序 'app': 'weixin_app', // 微信APP } export const ServicePayType = { 'h5': 'weixin_h5', // H5(微信外H5) 'weixin-h5': 'weixin', // h5 微信内h5 'weixin': 'weixin_applet', // 微信小程序 'app': 'weixin_app', // 微信APP 'yue': 'yue', // 微信APP } // 支付类型(前端用) export const PayType = { 0: 'wechat', // 微信支付 1: 'yue', // 余额支付 2: 'alipay', // 支付宝支付 } // 微信支付环境类型(前端用) export const WechatPayEnvType = { 0: 'app', // APP 1: 'miniProgram', // 小程序 2: 'h5InWechat', // 微信内H5 3: 'h5OutWechat' // 微信外H5 } /** * 获取当前环境 * @returns {*} WechatPayEnvType */ export function getEnvType() { let envType; // 0.APP 1.微信小程序 2.微信内H5 3.微信外H5 WechatPayEnvType // #ifdef APP-PLUS envType = WechatPayEnvType["0"] // #endif // #ifdef MP-WEIXIN envType = WechatPayEnvType["1"] // #endif // #ifdef H5 if (h5InWeChat()) { envType = WechatPayEnvType["2"] } else { envType = WechatPayEnvType["3"] } // #endif return envType } /** * @name: 支付 * @param options {{ type:any, payInfo:any }} * type PayType * payInfo 结算信息 */ export async function doPayment(options) { try { loading({title: '支付中...'}) return await _chooseEnvToPayment(options) } finally { hideLoading() } } /** * 区别环境调用支付 * @param options * @returns {Promise<{msg: *, data: *}>} * @private */ async function _chooseEnvToPayment(options) { const {type, payInfo, isGroup} = options let res; if (type === PayType[0]) { // 微信支付 switch (getEnvType()) { case WechatPayEnvType["0"]: res = await _appWechatPay(options) break; case WechatPayEnvType["1"]: res = await _miniProgramPay(options) break; case WechatPayEnvType["2"]: res = await _h5InWechatPay(options) break; case WechatPayEnvType["3"]: res = await _h5OutWechatPay(options) break; } } if (type === PayType["1"]) { // 余额支付 res = await _balancePay(options) } if (type === PayType["2"]) { // 支付宝 res = await _aliPay(payInfo) } return res } /** * APP微信支付 * @param options * @private * @docs https://pay.weixin.qq.com/docs/merchant/apis/in-app-payment/app-transfer-payment.html */ function _appWechatPay(options) { return new Promise(async (resolve, reject) => { const payData = { from: ServiceFrom['app'], payType: ServicePayType['app'], orderId: options.payInfo.orderId } // 请求线上获取 res:{ appId,timeStamp,nonceStr,paySign,package,signType,mwebUrl,codeUrl,merchant_id,out_trade_no } const res = await _doWechatPayRequest(payData) // 兼容性写法:防止电脑端用户支付后马上关闭支付弹窗导致失败 uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify({payData, options})) const orderInfo = { appid: res.appId, // 微信开放平台审核通过的移动应用AppID 。 prepayid: res.merchant_id, // 请填写商户号mchid对应的值。 timestamp: res.timeStamp, // 时间 sign: res.paySign, // 签名,使用字段AppID、timeStamp、nonceStr、prepayid计算得出的签名值 注意:取值RSA格式 partnerid: res.out_trade_no, // 微信返回的支付交易会话ID,该值有效期为2小时。 noncestr: res.nonceStr, // 随机字符串,不长于32位。推荐随机数生成算法。 package: 'Sign=WXPay', // 暂填写固定值Sign=WXPay } uni.requestPayment({ provider: WechatProvider, orderInfo, success: (res) => resolve(createMessage('用户支付成功', res)), fail: (error) => reject(createMessage('用户支付失败', error)) }) }) } /** * 微信小程序支付 * @param options * @private * @docs https://pay.weixin.qq.com/docs/merchant/apis/h5-payment/h5-transfer-payment.html */ async function _miniProgramPay(options) { return await new Promise(async (resolve, reject) => { const payData = { from: ServiceFrom['weixin'], payType: ServicePayType['weixin'], orderId: options.payInfo.orderId } // 请求线上获取 res:{ appId,timeStamp,nonceStr,paySign,package,signType,mwebUrl,codeUrl,merchant_id,out_trade_no } const res = await _doWechatPayRequest(payData) // 兼容性写法:防止电脑端用户支付后马上关闭支付弹窗导致失败 uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify({payData, options})) uni.requestPayment({ timeStamp: res.timeStamp, nonceStr: res.nonceStr, signType: res.signType, paySign: res.paySign, package: res.package, provider: WechatProvider, success: (res) => resolve(createMessage('用户支付成功', res)), fail: (error) => reject(createMessage('用户支付失败', error)) }) }) } /** * 微信内H5支付 * @param options * @private * @docs https://pay.weixin.qq.com/docs/merchant/apis/h5-payment/h5-transfer-payment.html */ async function _h5InWechatPay(options) { return new Promise(async (resolve, reject) => { const payData = { from: ServiceFrom['h5'], payType: ServicePayType['weixin-h5'], orderId: options.payInfo.orderId } // 请求线上获取 res:{ appId,timeStamp,nonceStr,paySign,package,signType,mwebUrl,codeUrl,merchant_id,out_trade_no } const res = await _doWechatPayRequest(payData) jweixin.config({ debug: false, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。 appId: res.appId, // 必填,公众号的唯一标识 timestamp: res.timeStamp, // 必填,生成签名的时间戳 nonceStr: res.nonceStr, // 必填,生成签名的随机串 signature: res.paySign, // 必填,签名,见附录1 jsApiList: ['chooseWXPay'] // 必填,需要使用的JS接口列表,所有JS接口列表见附录2 }); /** JS SDK 可使用状态 */ jweixin.ready(() => { /** 检查JS SDK API是否可用 */ jweixin.checkJsApi({ jsApiList: ['chooseWXPay'], // 需要检测的JS接口列表,所有JS接口列表见附录2, success: () => { uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify({payData, options})) /** 去拉起微信支付 */ jweixin.chooseWXPay({ timestamp: res.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符 nonceStr: res.nonceStr, // 支付签名随机串,不长于 32 位 package: res.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***) signType: res.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5' paySign: res.paySign, // 支付签名 success: (res) => { // 支付成功后的回调函数 return resolve(createMessage('用户支付成功', res)) }, cancel: (r) => { return reject(createMessage('用户取消支付', {})) }, fail: (error) => { return reject(createMessage('跳转微信支付失败', error)) } }); }, fail: (error) => { return reject(createMessage('微信版本过低,请升级微信版本', error)) } }); }); /** JS SDK发生错误 */ jweixin.error((error) => { return reject(createMessage('JS-SDK加载错误', error)) }); }) } /** * 微信外H5支付 * @param options * @private */ async function _h5OutWechatPay(options) { const payData = { from: ServiceFrom['h5'], payType: ServicePayType['h5'], orderId: options.payInfo.orderId } const res = await _doWechatPayRequest(payData) if (res && res.mwebUrl) { // 缓存支付订单数据 uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify({payData, options})) location.replace(res.mwebUrl) return Promise.resolve(createMessage('拉起支付成功', {type: 'h5'})) } else { return Promise.reject(createMessage('服务端拉起支付失败', {type: 'h5', error: res})) } } /** * 支付宝支付 * @param payInfo */ function _aliPay(payInfo) { return Promise.reject("暂不支持支付宝支付") } /** * 余额支付 * @return {Promise} * @private * @param options */ async function _balancePay(options) { let from // #ifdef MP-WEIXIN from = ServiceFrom['weixin'] // #endif // #ifdef H5 from = ServiceFrom['h5'] // #endif const payData = { from, payType: ServicePayType['yue'], orderId: options.payInfo.orderId } const res = await _doWechatPayRequest(payData) uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify({payData, options})) // 余额支付支付完直接跳转 push({url: '/pages/payStatus/index'}, {type: 'redirectTo'}) return res } /** * 请求服务端获取支付信息 下单接口 * @param data {{from:string, paytype: string, orderId: string }} * @returns {Promise<*>} * @private */ async function _doWechatPayRequest(data) { return await wechatPay(data) }