317 lines
11 KiB
JavaScript
317 lines
11 KiB
JavaScript
/**
|
||
* @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<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 }}
|
||
* @returns {Promise<*>}
|
||
* @private
|
||
*/
|
||
async function _doWechatPayRequest(data) {
|
||
return await wechatPay(data)
|
||
}
|