前言
微信、快手、h5支付步骤大致相同,只有抖音是有自己的支付组件
项目同时支持多个(微信、快手、h5)平台支付,后端那边代码可以封装的
各平台支付大致流程都是相同的,总结了一下分为五个步骤
- 点击支付
- 创建订单
- 生成密钥和支付所需要的参数
- 支付成功
- 查询订单状态
一、微信支付
1.支付按钮
<button@click="payTap">立即抢购</button>
2.支付事件
payTap(){let that =this// 这些参数后端一般要的let data ={openid:this.openId,//用户id 必需courseId:this.detailsObj.id,//课程id(商品id)必需promoterId:this.promoterShareId ?this.promoterShareId :'',// 分销员idcouponId:this.detailsObj.receiveCouponId ?this.detailsObj.receiveCouponId :'',// 优惠卷id}// 如果一个项目里有多个平台支付,可以用传值来区分// #ifdef MP-WEIXIN
data.platform =1// #endif// #ifdef MP-KUAISHOU
data.platform =2// #endif//创建订单createWendaoOrder(data).then(res=>{// 返回密钥createOrder({orderId: res.data.orderId,// 订单idopenid:this.openId,// 用户id}).then(res1=>{// #ifdef MP-WEIXINlet twoData = res1.data
// 微信支付api// 参数向后端要 要确保每个值就有
uni.requestPayment({appId: twoData.appId,timeStamp: twoData.timeStamp,nonceStr: twoData.nonceStr,package: twoData.packageValue,signType: twoData.signType,paySign: twoData.paySign,success(result){// 调起支付密码if(result.errMsg =="requestPayment:ok"){// 支付成功
uni.showLoading({title:'获取订单状态..',mask:true,})orderSuccess({openid: that.openId,// 用户idorderId: res.data.orderId // 订单id}).then(res=>{
uni.hideLoading();
uni.showToast({title:'支付成功',icon:'none'});// 重新请求下商品详情
that.detailFn()})}else{
uni.showModal({title:'',content:'支付失败',showCancel:false,icon:'none',success(res){}})}},fail(result){
console.log(result)
uni.showModal({title:'',content:'支付失败',showCancel:false,icon:'none',success(res){}})},})// #endif}).catch(res=>{
console.log(res)})})}
二、快手支付
1.支付按钮
<button@click="payTap">立即抢购</button>
2.支付事件
payTap(){let that =this// 这些参数后端一般要的let data ={openid:this.openId,//用户id 必需courseId:this.detailsObj.id,//课程id(商品id)必需promoterId:this.promoterShareId ?this.promoterShareId :'',// 分销员idcouponId:this.detailsObj.receiveCouponId ?this.detailsObj.receiveCouponId :'',// 优惠卷id}// 如果一个项目里有多个平台支付,可以用传值来区分// #ifdef MP-WEIXIN
data.platform =1// #endif// #ifdef MP-KUAISHOU
data.platform =2// #endif//创建订单createWendaoOrder(data).then(res=>{// 返回密钥createOrder({orderId: res.data.orderId,// 订单idopenid:this.openId,// 用户id}).then(res1=>{// 后端返回的是这些数据// res1.data = {// order_no: "1231xxxxxxxxxxxxxxx450" // order_info_token: "ChJrc01wUGF5LmxxxxxxxxxxxxxxxWYYeulijTrRyDdowh6Lvtp2MIm-t5nlq4s3xxxxxxxxxxxxxxxxxxxuh217_-giIIHDQ8yTqZqghjVraGC_NjxxxxxxxxxxxxxxKAUwAQ"// {// 快手支付api// #ifdef MP-KUAISHOU
ks.pay({serviceId:'1',orderInfo: res1.data,success:functionsuccess(res2){// 调起支付密码// 支付成功
uni.showLoading({title:'获取订单状态..',mask:true,})orderSuccess({openid: that.openId,// 用户idorderId: res.data.orderId // 订单id}).then(res=>{
uni.hideLoading();
uni.showToast({title:'支付成功',icon:'none'});// 重新请求下商品详情
that.detailFn()})},fail:functionfail(res){
uni.showToast({title:'支付失败',icon:'none'})}})// #endif}).catch(res=>{
console.log(res)})})}
三、抖音支付
抖音有自己的支付组件和自己的下单页面,所以需要创建一个专属于抖音的组件,并把需要的参数进行传递
1.创建组件
1.新建ttcomponents文件夹,创建完后在ttcomponents下面再新建DyPayButton文件夹,然后在DyPayButton下面创建四个文件,分别为index.js、index.json、index.ttml、index.ttss
2.要创建在App.vue同级
先在App.vue 写baseUrl和getPhoneNumber函数
<script>exportdefault{onLaunch:function(){},onShow:function(){
console.log('App Show')},onHide:function(){
console.log('App Hide')},methods:{// 这个是接口基地址baseUrl(){return'https://kspaycallback.wendao101.com/douyin'},/**
* desc: 获取手机号
* params:加密数据
* success:成功回调
* fail: 失败回调
*/// 这个是抖音下单页获取手机号调用的函数getPhoneNumber({
params,
success,
fail
}){const{
iv,
encryptedData
}= params;miniLogin().then(data=>{getTtOpen(data).then(data1=>{// 获取手机号函数savePhone({openid: data1.data.data.openId,
iv,
encryptedData
}).then(data4=>{miniLogin().then(data6=>{getTtOpen(data6).then(data5=>{const result ={phoneNumber: data5.data.data.telNumber,}// 回调前端模板success(result)})})})})})},},}</script><style lang="scss">
@import"@/uni_modules/uview-ui/index.scss";
@import'@/utlis/index.scss';/*每个页面公共css */</style>
下面是那四个文件的内容
index.js
// 可以调用到app.vue里的方法const app =getApp();Component({properties:{mode: Number,openId:{type:[String, Number],},orderStatus:{type:[String, Number],},detailsObj:{type: Object,},goodsId:{type: String,value:"",},promoterShareId: Number,},data:{},methods:{// 提交商品信息 这个函数一进页面就会调用的getGoodsInfo(event){const that =thisreturnnewPromise(resolve=>{// 定时器是为解决 优惠卷id获取不到问题setTimeout(()=>{
tt.getSystemInfo({success:(resPlatform)=>{let pay = that.data.detailsObj.price *100// 价格单位是分let promoterShareId = that.data.promoterShareId // 分销员idlet required = that.data.detailsObj.giveEntityIsNeedPhone // 是否强制获取手机号let CouponId = that.data.detailsObj.receiveCouponId // 优惠卷id// 用不到的值就不用传let data ={currentPrice: pay,GoodsLabel:[{type:'NON_REFUNDABLE'}],minLimits:1,maxLimits:1,dateRule:'周一至周日可用',extra:{promoterId: promoterShareId,receiveCouponId: CouponId
},validation:{phoneNumber:{required: required // 手机号是否必填}},marketingVersion:1,}// im客服需要提前开通// 判断如果用户手机是ios就走客服支付, 把imId传上就自动跳转im客服页面了,安卓不要传这个id,否则可能会导致支付不了if(resPlatform.platform =='ios'){
data.imId ='3xxxxxxxx42'}// 然后将商品信息传入 resolve 函数resolve(data);}});},600)})},onError(e){const{
errNo,
errMsg
}= e.detail;if(errNo ===21514){
tt.showToast({title:"失败",// 内容icon:"none",// 图标});}elseif(errNo ===21513){
tt.showToast({title:"获取中",// 内容icon:"none",// 图标});}},userLogin(event){const{
goodsId,
goodsType
}= event.detail
returnnewPromise((resolve, reject)=>{
tt.login({success(e){// 用户登录成功并获取信息,则调用 resolve 函数,跳转至提单页resolve();},fail(){// 用户登录失败,则跳转提单页失败
_this.showTost("登录失败")}});});},payError(event){this.showTost(event.errMsg)},// 继续支付handleContinutePay(event){const{ status, outOrderNo, result }= event.detail;if(status ==='success'){const{ code }= result;if(code ===0){// 继续支付成功// 刷新页面this.triggerEvent("refreshData")
tt.showToast({title:"支付成功",});}}else{// 继续支付失败
tt.showToast({title:"继续支付失败",icon:"none"});}},// 正式支付newButtonPay(event){const{
status,
orderId,
outOrderNo,
result
}= event.detail;if(status ==='success'){const{
code
}= result;if(code ===0){
tt.showLoading({title:"订单确认中...",});this.getOrderIsHaveData(outOrderNo)}else{// 支付失败(超时、取消、关闭)this.showTost('支付失败(超时、取消、关闭)')}}else{const{
errMsg
}= result;this.showTost(errMsg)}},showTost(tit, timeMs){let time = timeMs >0? timeMs :1500;
tt.showToast({title: tit,icon:"none",duration: time,});},// 重新订单getOrderIsHaveData(orderId){let data ={openid:this.data.openId,
orderId,}
tt.request({url: app.baseUrl()+"/order/order_success",method:'POST',
data,success:(res)=>{this.setOrderIsHaveData(res.data.orderStatus, orderId)}})},setOrderIsHaveData(data, orderId){if(data ==0){setTimeout(()=>{
_this.getOrderIsHaveData(orderId)},1000);}else{
tt.hideLoading();
tt.navigateBack(-1);this.triggerEvent("refreshData")}},// 退款onApplyrefund(event){
console.log(event)const{
orderId
}= event.detail;const extra ={
orderId
};// 开发者需要透传的参数,可自定义内容returnnewPromise(resolve=>{resolve(extra);});},onRefund(event){
console.log(event)const{
status,
result
}= event.detail;if(status ==='success'){const{
refundId,
outRefundNo
}= result;}else{const{
errMsg
}= result;
tt.showToast({title: e.detail.errMsg ? e.detail.errMsg :'失败',icon:"none"});}},refundError(e){
console.log(e)if(e.detail.errNo ==21531){
tt.showToast({title:"不符合退款要求",icon:"none"});}else{
tt.showToast({title: e.detail.errMsg ? e.detail.errMsg :'失败',icon:"none"});}},},});
index.json
{"component":true,"usingComponents":{}}
index.ttml
<!-- 立即抢购 --><blocktt:if="{{mode==2}}"><pay-buttonclass="{{classsname}}"mode="{{2}}"goods-id="{{detailsObj.productId}}"goods-type="{{1}}"biz-line="{{2}}"bind:getgoodsinfo="getGoodsInfo"bind:placeorder="userLogin"marketing-ready="{{true}}"bind:pay="newButtonPay"bind:error="onError"></pay-button></block><blocktt:if="{{mode==1}}"><!-- 继续支付 --><pay-buttontt:if="{{orderStatus==0}}"class="{{classsname}}"order-status="{{0}}"order-id="{{orderData.orderId}}"bind:pay="handleContinutePay"></pay-button><!-- 退款 --><pay-buttonclass="order_ljzf"mode="{{1}}"goods-type="{{1}}"order-status="{{1}}"order-id="{{orderData.orderId}}":refund-total-amount="{{orderData.coursePrice}}"biz-line="{{2}}"marketing-ready="{{true}}"catch:applyrefund="onApplyrefund"catch:refund="onRefund"catch:error="refundError"tt:if="{{orderData.orderStatus==1}}"></pay-button><!-- 退款状态 --><pay-buttonclass="order_tk"mode="{{1}}"goods-type="{{1}}"order-status="{{orderData.orderStatus=='4'?2:orderData.orderStatus=='2'?3:orderData.orderStatus=='5'?4:4 }}"refund-id="{{orderData.orderId}}"biz-line="{{2}}"marketing-ready="{{true}}"catch:applyrefund="onApplyrefund"catch:refund="onRefund"catch:error="refundError"tt:if="{{orderData.orderStatus!=1 && orderData.orderStatus!=0}}"></pay-button></block>
index.ttss
按钮样式根据自己的来
.save_one{width: 100%;height: 100%;}.payButton{display: flex;align-items: center;justify-content: center;width: 310rpx;height: 90rpx;border-radius: 45rpx;box-sizing: border-box;background-color: #E10000;color: #fff;border: 2rpx solid #E10000;}.payButtonItem{display: flex;align-items: center;justify-content: center;width: 183rpx;height: 57rpx;background: #E10000;border-radius: 29rpx;border: 1rpx solid #E10000;font-size: 26rpx;font-family:"Noto Sans SC";font-weight: 600;color: #fff;line-height: 37rpx;box-sizing: border-box;margin-right: 16rpx;}
2.在pages.json给商品详情页面注册组件
"pages":[{"path":"details/details","style":{// #ifdef MP-TOUTIAO// 这个是需要加的,否则显示不出来"usingComponents":{"zijie-pay-button":"/ttcomponents/DyPayButton/index"},//#endif"navigationBarTitleText":"xxxx","enablePullDownRefresh":false}}]
3.在商品详情页面中使用组件
components:{// #ifdef MP-TOUTIAO"zijie-pay-button":"../../ttcomponents/DyPayButton/index",//#endif}
<zijie-pay-buttonv-if="detailsObj.productId":openId="openId":mode='2':detailsObj="detailsObj":classsname="'save_one'":promoterShareId="promoterShareId"@refreshData="refreshData"></zijie-pay-button>
>
// v-if: 判断有没有商品id
// openId: 用户id
// mode: 商品类型
// detailsObj: 商品详情页的数据
// classsname: 按钮类名
// promoterShareId: 分销员id
// @refreshData: 用于支付成功回调刷新页面
4.h5支付
主要是为解决微信ios无法支付的问题,ios走h5支付渠道
1.创建按钮
// 这个按钮是uView组件
<u-buttontext="联系老师"v-if="isIosDouYin"shape="circle"color="#E10000":send-message-title="detailsObj.title?detailsObj.title:''":send-message-img="detailsObj.coverPicUrl":send-message-path="'/pages_details/details/details?courseId=' + detailsObj.id + '&promoterId=' + promoterShareId + '&couponId=' + detailsObj.receiveCouponId + '&appNameType=1&platform=1&openid=' + openId"show-message-card="true"open-type="contact"></u-button>
// isIosDouYin: 判断是否为ios系统
// send-message-title: 商品标题
// :send-message-img: 商品封面
// :send-message-path: 跳转路径
// show-message-card: 发送卡片
2.创建页面
在详情页同级目录创建一个页面detailsContact.vue,后端可以重定向到这个页面
var _this;exportdefault{data(){return{openid:'',// 用户idh5PayData:{},// h5提交的参数h5OrderId:''// 订单id}},onLoad(options){
_this =this// 页面一进来就调用支付 带上路径传的值this.payTap(options)},methods:{payTap(queryObj){let that =this
that.openid = queryObj.openid
let data ={openid: queryObj.openid,// 用户idcourseId: queryObj.courseId,// 课程idpromoterId: queryObj.promoterId ? queryObj.promoterId :0,// 推广员idcouponId: queryObj.couponId ? queryObj.couponId :0,// 优惠卷idappNameType: queryObj.appNameType,// 区分哪个小程序platform: queryObj.platform // 区分平台}createWendaoOrder1(data).then(res=>{createOrder1({orderId: res.data.orderId,openid: queryObj.openid,}).then(res1=>{// #ifdef H5
that.h5PayData = res1.data
that.h5OrderId = res.data.orderId
that.getWxOfficePay()// #endif}).catch(res=>{
console.log(res)})})},getWxOfficePay(){if(typeof WeixinJSBridge =="undefined"){if(document.addEventListener){
document.addEventListener('WeixinJSBridgeReady', _this.getWxOfficePayPage,false);}elseif(document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', _this.getWxOfficePayPage);
document.attachEvent('onWeixinJSBridgeReady', _this.getWxOfficePayPage);}}else{
_this.getWxOfficePayPage()}},getWxOfficePayPage(){const that =this
console.log("h5支付调起支付面板 ")
WeixinJSBridge.invoke('getBrandWCPayRequest',{appId: _this.h5PayData.appId,timeStamp: _this.h5PayData.timeStamp,nonceStr: _this.h5PayData.nonceStr,package: _this.h5PayData.packageValue,signType: _this.h5PayData.signType,paySign: _this.h5PayData.paySign,},function(res){if(res.err_msg =="get_brand_wcpay_request:ok"){
uni.showLoading({title:'获取订单状态..',mask:true,})// 确认订单
uni.request({url: app.baseUrl()+"/order/order_success",method:'POST',data:{openid: that.openId,orderId: that.h5OrderId
},success:(res)=>{
uni.hideLoading();
uni.showModal({title:'',content:'支付成功,请返回小程序查看课程',showCancel:false,icon:'none'})}})}else{
uni.showModal({title:'',content:'支付失败',showCancel:false,icon:'none',success(res){}})}});},}}
版权归原作者 伴梦123 所有, 如有侵权,请联系我们删除。