赞
踩
微信、快手、h5支付步骤大致相同,只有抖音是有自己的支付组件
项目同时支持多个(微信、快手、h5)平台支付,后端那边代码可以封装的
<button @click="payTap">立即抢购</button>
payTap() { let that = this // 这些参数后端一般要的 let data = { openid: this.openId, //用户id 必需 courseId: this.detailsObj.id, //课程id(商品id)必需 promoterId: this.promoterShareId ? this.promoterShareId : '', // 分销员id couponId: 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, // 订单id openid: this.openId, // 用户id }).then(res1 => { // #ifdef MP-WEIXIN let 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, // 用户id orderId: 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) }) }) }
<button @click="payTap">立即抢购</button>
payTap() { let that = this // 这些参数后端一般要的 let data = { openid: this.openId, //用户id 必需 courseId: this.detailsObj.id, //课程id(商品id)必需 promoterId: this.promoterShareId ? this.promoterShareId : '', // 分销员id couponId: 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, // 订单id openid: 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: function success(res2) { // 调起支付密码 // 支付成功 uni.showLoading({ title: '获取订单状态..', mask: true, }) orderSuccess({ openid: that.openId, // 用户id orderId: res.data.orderId // 订单id }).then(res=>{ uni.hideLoading(); uni.showToast({ title: '支付成功', icon: 'none' }); // 重新请求下商品详情 that.detailFn() }) }, fail: function fail(res) { uni.showToast({ title: '支付失败', icon: 'none' }) } }) // #endif }).catch(res => { console.log(res) }) }) }
抖音有自己的支付组件和自己的下单页面,所以需要创建一个专属于抖音的组件,并把需要的参数进行传递
1.新建ttcomponents文件夹,创建完后在ttcomponents下面再新建DyPayButton文件夹,然后在DyPayButton下面创建四个文件,分别为index.js、index.json、index.ttml、index.ttss
2.要创建在App.vue同级
先在App.vue 写baseUrl和getPhoneNumber函数
<script> export default { 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 = this return new Promise(resolve => { // 定时器是为解决 优惠卷id获取不到问题 setTimeout(()=>{ tt.getSystemInfo({ success: (resPlatform)=> { let pay = that.data.detailsObj.price * 100 // 价格单位是分 let promoterShareId = that.data.promoterShareId // 分销员id let 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", // 图标 }); } else if (errNo === 21513) { tt.showToast({ title: "获取中", // 内容 icon: "none", // 图标 }); } }, userLogin(event) { const { goodsId, goodsType } = event.detail return new Promise((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 }; // 开发者需要透传的参数,可自定义内容 return new Promise(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
<!-- 立即抢购 --> <block tt:if="{{mode==2}}"> <pay-button class="{{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> <block tt:if="{{mode==1}}"> <!-- 继续支付 --> <pay-button tt:if="{{orderStatus==0}}" class="{{classsname}}" order-status="{{0}}" order-id="{{orderData.orderId}}" bind:pay="handleContinutePay"></pay-button> <!-- 退款 --> <pay-button class="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-button class="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; }
"pages": [{
"path": "details/details",
"style": {
// #ifdef MP-TOUTIAO
// 这个是需要加的,否则显示不出来
"usingComponents": {
"zijie-pay-button": "/ttcomponents/DyPayButton/index"
},
//#endif
"navigationBarTitleText": "xxxx",
"enablePullDownRefresh": false
}
}]
components:{
// #ifdef MP-TOUTIAO
"zijie-pay-button": "../../ttcomponents/DyPayButton/index",
//#endif
}
<zijie-pay-button v-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: 用于支付成功回调刷新页面
主要是为解决微信ios无法支付的问题,ios走h5支付渠道
// 这个按钮是uView组件 <u-button text="联系老师" 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: 发送卡片
在详情页同级目录创建一个页面detailsContact.vue,后端可以重定向到这个页面
var _this; export default { data() { return { openid: '', // 用户id h5PayData:{}, // 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, // 用户id courseId: queryObj.courseId, // 课程id promoterId: queryObj.promoterId ? queryObj.promoterId : 0, // 推广员id couponId: queryObj.couponId ? queryObj.couponId : 0, // 优惠卷id appNameType: 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); } else if (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) {} }) } } ); }, } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。