Files
yshop-pro-uniapp/utils/paymentUtils.js

317 lines
11 KiB
JavaScript
Raw Permalink Normal View History

2023-11-14 17:21:03 +08:00
/**
* @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";
2023-11-14 17:21:03 +08:00
const {loading, hideLoading} = useInterface()
const {push} = useRouter()
2023-11-14 17:21:03 +08:00
// 微信支付的provider
export const WechatProvider = 'wxpay'
// 支付类型(后端用)
2023-11-15 19:59:37 +08:00
export const ServiceFrom = {
2023-11-17 20:55:32 +08:00
'h5': 'h5', // H5微信内h5、微信外H5
2023-11-15 19:59:37 +08:00
'weixin': 'weixin_applet', // 微信小程序
'app': 'weixin_app', // 微信APP
2023-11-15 19:59:37 +08:00
}
2023-11-14 17:21:03 +08:00
export const ServicePayType = {
'h5': 'weixin_h5', // H5微信外H5
'weixin-h5': 'weixin', // h5 微信内h5
2023-11-15 19:59:37 +08:00
'weixin': 'weixin_applet', // 微信小程序
'app': 'weixin_app', // 微信APP
'yue': 'yue', // 微信APP
2023-11-14 17:21:03 +08:00
}
// 支付类型(前端用)
export const PayType = {
0: 'wechat', // 微信支付
1: 'yue', // 余额支付
2023-11-14 17:21:03 +08:00
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()
}
2023-11-14 17:21:03 +08:00
}
/**
* 区别环境调用支付
* @param options
* @returns {Promise<{msg: *, data: *}>}
* @private
*/
async function _chooseEnvToPayment(options) {
const {type, payInfo, isGroup} = options
2023-11-14 17:21:03 +08:00
let res;
if (type === PayType[0]) {
// 微信支付
switch (getEnvType()) {
case WechatPayEnvType["0"]:
res = await _appWechatPay(options)
2023-11-14 17:21:03 +08:00
break;
case WechatPayEnvType["1"]:
res = await _miniProgramPay(options)
2023-11-14 17:21:03 +08:00
break;
case WechatPayEnvType["2"]:
res = await _h5InWechatPay(options)
2023-11-14 17:21:03 +08:00
break;
case WechatPayEnvType["3"]:
res = await _h5OutWechatPay(options)
2023-11-14 17:21:03 +08:00
break;
}
}
if (type === PayType["1"]) {
// 余额支付
res = await _balancePay(options)
2023-11-14 17:21:03 +08:00
}
if (type === PayType["2"]) {
// 支付宝
res = await _aliPay(payInfo)
}
return res
}
/**
* APP微信支付
* @param options
2023-11-14 17:21:03 +08:00
* @private
* @docs https://pay.weixin.qq.com/docs/merchant/apis/in-app-payment/app-transfer-payment.html
*/
function _appWechatPay(options) {
2023-11-14 17:21:03 +08:00
return new Promise(async (resolve, reject) => {
2023-11-15 19:59:37 +08:00
const payData = {
from: ServiceFrom['app'],
payType: ServicePayType['app'],
orderId: options.payInfo.orderId
2023-11-15 19:59:37 +08:00
}
// 请求线上获取 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}))
2023-11-14 17:21:03 +08:00
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
2023-11-14 17:21:03 +08:00
* @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) => {
2023-11-15 19:59:37 +08:00
const payData = {
from: ServiceFrom['weixin'],
payType: ServicePayType['weixin'],
orderId: options.payInfo.orderId
2023-11-15 19:59:37 +08:00
}
// 请求线上获取 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}))
2023-11-14 17:21:03 +08:00
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
2023-11-14 17:21:03 +08:00
* @private
* @docs https://pay.weixin.qq.com/docs/merchant/apis/h5-payment/h5-transfer-payment.html
*/
async function _h5InWechatPay(options) {
2023-11-14 17:21:03 +08:00
return new Promise(async (resolve, reject) => {
2023-11-15 19:59:37 +08:00
const payData = {
from: ServiceFrom['h5'],
payType: ServicePayType['weixin-h5'],
orderId: options.payInfo.orderId
2023-11-15 19:59:37 +08:00
}
// 请求线上获取 res:{ appId,timeStamp,nonceStr,paySign,package,signType,mwebUrl,codeUrl,merchant_id,out_trade_no }
const res = await _doWechatPayRequest(payData)
2023-11-14 17:21:03 +08:00
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))
}
});
2023-11-14 17:21:03 +08:00
},
fail: (error) => {
return reject(createMessage('微信版本过低,请升级微信版本', error))
}
});
2023-11-14 17:21:03 +08:00
});
/** JS SDK发生错误 */
jweixin.error((error) => {
return reject(createMessage('JS-SDK加载错误', error))
});
})
}
/**
* 微信外H5支付
* @param options
2023-11-14 17:21:03 +08:00
* @private
*/
async function _h5OutWechatPay(options) {
2023-11-15 19:59:37 +08:00
const payData = {
from: ServiceFrom['h5'],
payType: ServicePayType['h5'],
orderId: options.payInfo.orderId
2023-11-15 19:59:37 +08:00
}
const res = await _doWechatPayRequest(payData)
2023-11-14 17:21:03 +08:00
if (res && res.mwebUrl) {
// 缓存支付订单数据
uni.setStorageSync(CacheKey.PAY_INFO, JSON.stringify({payData, options}))
2023-11-14 17:21:03 +08:00
location.replace(res.mwebUrl)
return Promise.resolve(createMessage('拉起支付成功', {type: 'h5'}))
2023-11-14 17:21:03 +08:00
} else {
return Promise.reject(createMessage('服务端拉起支付失败', {type: 'h5', error: res}))
}
}
/**
* 支付宝支付
* @param payInfo
*/
function _aliPay(payInfo) {
return Promise.reject("暂不支持支付宝支付")
}
/**
* 余额支付
* @return {Promise<never>}
* @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 }}
2023-11-14 17:21:03 +08:00
* @returns {Promise<*>}
* @private
*/
async function _doWechatPayRequest(data) {
return await wechatPay(data)
}