之前做过的支付 在pc上一般是拿到订单id 等一些数据给后端 拿到一个二维码后在一定时间内做轮询去查订单状态 在移动端(uniapp项目)上调用的是 uni.requestPayment这个方法用来唤起支付宝 / 微信应用 前段时间在做第三方支付的时候发现和这些还是有些差距的。
前端支付流程
// 不管是 什么支付 在唤起支付app的时候 先做的一件事就是要把当前的订单数据给到后端
// 下面是一个封装好的函数 他会根据不同的code值 来告诉前端 具体操作哪种支付方式
prepay({
from: this.from,
order_id: this.order_id, // 给后端的订单id
pay_way: this.payway, // 支付方式 后端需要根据不同的支付方式去拿第三方的值
})
.then(({
code,
data
}) => {
switch (code) {
case 1:
this.handleWechatPay(data); // 微信支付
break;
case 10001:
this.handleAlipayPay(data); // 支付宝支付
break;
case 20001:
this.handleWalletPay(); // 品台内支付
break;
case 30001:
this.handleThirdPartyPay(data); //第三方 富友支付
break;
}
})
.catch((err) => {})
.finally(() => {
setTimeout(() => {
this.loadingPay = false;
}, 500);
});
直接对接微信或支付宝的话 用框架提供的requestPayment这个方法就可以了 部分代码逻辑如下:
微信
// 微信支付
handleWechatPay(data) {
wxpay(data)
.then((res) => {
// console.log(res);
this.handPayResult(res);
})
.catch((err) => {
// console.log(err);
});
}
// 微信支付具体实现
export function wxpay(opt) {
//#ifdef H5
if (isWeixinClient()) { //isWeixinClient 函数用来判断是否为微信环境
return wechath5.wxPay(opt);
} else {
console.log(opt);
location.href = opt;
}
// #endif
//#ifndef H5
return new Promise((resolve, reject) => {
// #ifdef MP-WEIXIN
const params = {
timeStamp: opt.timeStamp,
// 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。
//但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
nonceStr: opt.nonceStr,
// 支付签名随机串,不长于 32 位
package: opt.package,
// 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
signType: opt.signType,
// 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
paySign: opt.paySign,
};
// #endif
// #ifdef APP-PLUS
const params = {
orderInfo: opt,
};
// #endif
console.log(params);
uni.requestPayment({
provider: "wxpay",
...params,
success: (res) => {
resolve("success");
},
cancel: (res) => {
resolve("fail");
},
fail: (res) => {
resolve("fail");
},
});
});
// #endif
}
支付宝
// 支付宝支付
handleAlipayPay(data) {
alipay(data)
.then((res) => {
this.handPayResult(res);
})
.catch((err) => {
// console.log(err);
});
}
// 支付宝具体实现
export function alipay(opt) {
//#ifdef H5
const div = document.createElement("div");
console.log(opt);
/* 此处form就是后台返回接收到的数据 */
div.innerHTML = opt;
document.body.appendChild(div);
document.forms[0].submit();
return;
// #endif
// #ifdef APP-PLUS
return new Promise((resolve, reject) => {
const params = {
orderInfo: opt,
};
uni.requestPayment({
provider: "alipay",
...params,
success: (res) => {
resolve("success");
},
cancel: (res) => {
resolve("fail");
},
fail: (res) => {
resolve("fail");
},
});
});
// #endif
}
到这里的话 一般唤起微信 支付宝 支付 是没什么问题的了 可见他们在app内唤起应用都是要借助requestPayment这个接口来实现的 下面我们来看一看第三方富友支付 这里对接的是第三方 然后跳转到支付宝的
富友支付
首先 我们在使用第三方支付时 前面流程是一样的 给后端订单id 支付方式 等参数 拿到第三方支付返回链接时 我们是需要借助 webview 组件进行app内部跳转到第三方网页的
可能大概是这样的:
<template>
<view class="page-body">
<web-view :src="url"></web-view>
</view>
</template>
<script>
export default {
data() {
return {
url: ''
};
},
onLoad: function(options) {
this.url = this.$Route.query.url
},
};
</script>
但是在对接 富有支付 的时候遇到了一些问题
- 部分机型因为兼容是打不开这个链接的
- 在支付宝支付成功后我是没办法通过第三方拿到订单状态的
具体解决方法:
问题一:
不使用webview组件跳转 在app内 使用 plus.runtime.openWeb去跳转 具体代码如下:
handleThirdPartyPay(data) {
uni.setStorageSync('par_order_options', JSON.stringify({
form: data.from,
order_id: data.order_id
}))
// 针对webview组件不兼容问题
// #ifdef H5
window.location.href = data.pay_url
// #endif
// #ifdef APP-PLUS
plus.runtime.openWeb(data.pay_url);
// #endif
}
问题二:
我们在当前付款方式支付跳转前 去存储一个字段 我们在每次页面onShow的时候去尝试获取这个字段 如果有的话 代表我们是从支付宝页面回来的 需要拿这个字段去请求订单详情接口 没有的话 代表我们是从购物车页面进来的 我们在离开这个页面的时候需要手动remove掉这个字段 避免请求上一个订单的状态 具体代码如下:
// 每次页面显示的时候都会查本地这个字段
async onShow() {
let order_options = uni.getStorageSync('par_order_options')
if (order_options) {
// 如果有这个字段 代表我们在支付页面回来的
// 我们需要在这里去请求订单状态
}
}
// ==================== ====================//
// 富友支付
handleThirdPartyPay(data) {
// 在每次去支付页面前 在本地存储当前订单id
// 以便于我们返回来查询订单状态 到底支付成功没有
uni.setStorageSync('par_order_options', JSON.stringify({
form: data.from,
order_id: data.order_id
}))
// #ifdef H5
window.location.href = data.pay_url
// #endif
// #ifdef APP-PLUS
plus.runtime.openWeb(data.pay_url);
// #endif
}
// ==================== ====================//
//不能忘记 在离开页面的时候 清空状态
onUnload(){
uni.removeStorageSync('par_order_options')
}
plus.runtime.openWeb 并不会触发当前页面的onUnload事件 所以跳转回来 当前页面存储的还是当前订单的一个数据 并不会被清空。
对了,记得在 manifest.json 里面去配置 App模块配置。