uniapp前端支付篇之微信、抖音、快手、h5四個(gè)平臺(tái)支付功能
前言
微信、快手、h5支付步驟大致相同,只有抖音是有自己的支付組件
項(xiàng)目同時(shí)支持多個(gè)(微信、快手、h5)平臺(tái)支付,后端那邊代碼可以封裝的
各平臺(tái)支付大致流程都是相同的,總結(jié)了一下分為五個(gè)步驟
- 點(diǎn)擊支付
- 創(chuàng)建訂單
- 生成密鑰和支付所需要的參數(shù)
- 支付成功
- 查詢訂單狀態(tài)
一、微信支付
1.支付按鈕
<button @click="payTap">立即搶購</button>
2.支付事件
payTap() { let that = this // 這些參數(shù)后端一般要的 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 : '', // 優(yōu)惠卷id } // 如果一個(gè)項(xiàng)目里有多個(gè)平臺(tái)支付,可以用傳值來區(qū)分 // #ifdef MP-WEIXIN data.platform = 1 // #endif // #ifdef MP-KUAISHOU data.platform = 2 // #endif //創(chuàng)建訂單 createWendaoOrder(data).then(res => { // 返回密鑰 createOrder({ orderId: res.data.orderId, // 訂單id openid: this.openId, // 用戶id }).then(res1 => { // #ifdef MP-WEIXIN let twoData = res1.data // 微信支付api // 參數(shù)向后端要 要確保每個(gè)值就有 uni.requestPayment({ appId: twoData.appId, timeStamp: twoData.timeStamp, nonceStr: twoData.nonceStr, package: twoData.packageValue, signType: twoData.signType, paySign: twoData.paySign, success(result) { // 調(diào)起支付密碼 if (result.errMsg == "requestPayment:ok") { // 支付成功 uni.showLoading({ title: '獲取訂單狀態(tài)..', mask: true, }) orderSuccess({ openid: that.openId, // 用戶id orderId: res.data.orderId // 訂單id }).then(res=>{ uni.hideLoading(); uni.showToast({ title: '支付成功', icon: 'none' }); // 重新請(qǐng)求下商品詳情 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 // 這些參數(shù)后端一般要的 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 : '', // 優(yōu)惠卷id } // 如果一個(gè)項(xiàng)目里有多個(gè)平臺(tái)支付,可以用傳值來區(qū)分 // #ifdef MP-WEIXIN data.platform = 1 // #endif // #ifdef MP-KUAISHOU data.platform = 2 // #endif //創(chuàng)建訂單 createWendaoOrder(data).then(res => { // 返回密鑰 createOrder({ orderId: res.data.orderId, // 訂單id openid: this.openId, // 用戶id }).then(res1 => { // 后端返回的是這些數(shù)據(jù) // 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) { // 調(diào)起支付密碼 // 支付成功 uni.showLoading({ title: '獲取訂單狀態(tài)..', mask: true, }) orderSuccess({ openid: that.openId, // 用戶id orderId: res.data.orderId // 訂單id }).then(res=>{ uni.hideLoading(); uni.showToast({ title: '支付成功', icon: 'none' }); // 重新請(qǐng)求下商品詳情 that.detailFn() }) }, fail: function fail(res) { uni.showToast({ title: '支付失敗', icon: 'none' }) } }) // #endif }).catch(res => { console.log(res) }) }) }
三、抖音支付
抖音有自己的支付組件和自己的下單頁面,所以需要?jiǎng)?chuàng)建一個(gè)專屬于抖音的組件,并把需要的參數(shù)進(jìn)行傳遞
1.創(chuàng)建組件
1.新建ttcomponents文件夾,創(chuàng)建完后在ttcomponents下面再新建DyPayButton文件夾,然后在DyPayButton下面創(chuàng)建四個(gè)文件,分別為index.js、index.json、index.ttml、index.ttss
2.要?jiǎng)?chuàng)建在App.vue同級(jí)
先在App.vue 寫baseUrl和getPhoneNumber函數(shù)
<script> export default { onLaunch: function() { }, onShow: function() { console.log('App Show') }, onHide: function() { console.log('App Hide') }, methods: { // 這個(gè)是接口基地址 baseUrl(){ return 'https://kspaycallback.wendao101.com/douyin' }, /** * desc: 獲取手機(jī)號(hào) * params:加密數(shù)據(jù) * success:成功回調(diào) * fail: 失敗回調(diào) */ // 這個(gè)是抖音下單頁獲取手機(jī)號(hào)調(diào)用的函數(shù) getPhoneNumber({ params, success, fail }) { const { iv, encryptedData } = params; miniLogin().then(data=>{ getTtOpen(data).then(data1 => { // 獲取手機(jī)號(hào)函數(shù) savePhone({ openid: data1.data.data.openId, iv, encryptedData }).then(data4 => { miniLogin().then(data6=>{ getTtOpen(data6).then(data5 => { const result = { phoneNumber: data5.data.data.telNumber, } // 回調(diào)前端模板 success(result) }) }) }) }) }) }, }, } </script> <style lang="scss"> @import "@/uni_modules/uview-ui/index.scss"; @import '@/utlis/index.scss'; /*每個(gè)頁面公共css */ </style>
下面是那四個(gè)文件的內(nèi)容
index.js
// 可以調(diào)用到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: { // 提交商品信息 這個(gè)函數(shù)一進(jìn)頁面就會(huì)調(diào)用的 getGoodsInfo(event) { const that = this return new Promise(resolve => { // 定時(shí)器是為解決 優(yōu)惠卷id獲取不到問題 setTimeout(()=>{ tt.getSystemInfo({ success: (resPlatform)=> { let pay = that.data.detailsObj.price * 100 // 價(jià)格單位是分 let promoterShareId = that.data.promoterShareId // 分銷員id let required = that.data.detailsObj.giveEntityIsNeedPhone // 是否強(qiáng)制獲取手機(jī)號(hào) let CouponId = that.data.detailsObj.receiveCouponId // 優(yōu)惠卷id // 用不到的值就不用傳 let data = { currentPrice: pay, GoodsLabel: [{ type: 'NON_REFUNDABLE' } ], minLimits: 1, maxLimits: 1, dateRule: '周一至周日可用', extra: { promoterId: promoterShareId, receiveCouponId: CouponId }, validation: { phoneNumber: { required: required // 手機(jī)號(hào)是否必填 } }, marketingVersion: 1, } // im客服需要提前開通 // 判斷如果用戶手機(jī)是ios就走客服支付, 把imId傳上就自動(dòng)跳轉(zhuǎn)im客服頁面了,安卓不要傳這個(gè)id,否則可能會(huì)導(dǎo)致支付不了 if(resPlatform.platform == 'ios'){ data.imId = '3xxxxxxxx42' } // 然后將商品信息傳入 resolve 函數(shù) resolve(data); } }); },600) }) }, onError(e) { const { errNo, errMsg } = e.detail; if (errNo === 21514) { tt.showToast({ title: "失敗", // 內(nèi)容 icon: "none", // 圖標(biāo) }); } else if (errNo === 21513) { tt.showToast({ title: "獲取中", // 內(nèi)容 icon: "none", // 圖標(biāo) }); } }, userLogin(event) { const { goodsId, goodsType } = event.detail return new Promise((resolve, reject) => { tt.login({ success(e) { // 用戶登錄成功并獲取信息,則調(diào)用 resolve 函數(shù),跳轉(zhuǎn)至提單頁 resolve(); }, fail() { // 用戶登錄失敗,則跳轉(zhuǎn)提單頁失敗 _this.showTost("登錄失敗") } }); }); }, payError(event) { this.showTost(event.errMsg) }, // 繼續(xù)支付 handleContinutePay(event) { const { status, outOrderNo, result } = event.detail; if (status === 'success') { const { code } = result; if (code === 0) { // 繼續(xù)支付成功 // 刷新頁面 this.triggerEvent("refreshData") tt.showToast({ title: "支付成功", }); } } else { // 繼續(xù)支付失敗 tt.showToast({ title: "繼續(xù)支付失敗", icon: "none" }); } }, // 正式支付 newButtonPay(event) { const { status, orderId, outOrderNo, result } = event.detail; if (status === 'success') { const { code } = result; if (code === 0) { tt.showLoading({ title: "訂單確認(rèn)中...", }); this.getOrderIsHaveData(outOrderNo) } else { // 支付失?。ǔ瑫r(shí)、取消、關(guān)閉) this.showTost('支付失?。ǔ瑫r(shí)、取消、關(guān)閉)') } } 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 }; // 開發(fā)者需要透傳的參數(shù),可自定義內(nèi)容 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}}"> <!-- 繼續(xù)支付 --> <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> <!-- 退款狀態(tài) --> <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
按鈕樣式根據(jù)自己的來
.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給商品詳情頁面注冊(cè)組件
"pages": [{ "path": "details/details", "style": { // #ifdef MP-TOUTIAO // 這個(gè)是需要加的,否則顯示不出來 "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-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: 商品詳情頁的數(shù)據(jù) // classsname: 按鈕類名 // promoterShareId: 分銷員id // @refreshData: 用于支付成功回調(diào)刷新頁面
4.h5支付
主要是為解決微信ios無法支付的問題,ios走h(yuǎn)5支付渠道
1.創(chuàng)建按鈕
// 這個(gè)按鈕是uView組件 <u-button text="聯(lián)系老師" 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系統(tǒng) // send-message-title: 商品標(biāo)題 // :send-message-img: 商品封面 // :send-message-path: 跳轉(zhuǎn)路徑 // show-message-card: 發(fā)送卡片
2.創(chuàng)建頁面
在詳情頁同級(jí)目錄創(chuàng)建一個(gè)頁面detailsContact.vue,后端可以重定向到這個(gè)頁面
var _this; export default { data() { return { openid: '', // 用戶id h5PayData:{}, // h5提交的參數(shù) h5OrderId: '' // 訂單id } }, onLoad(options) { _this = this // 頁面一進(jìn)來就調(diào)用支付 帶上路徑傳的值 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, // 優(yōu)惠卷id appNameType: queryObj.appNameType, // 區(qū)分哪個(gè)小程序 platform : queryObj.platform // 區(qū)分平臺(tái) } 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支付調(diào)起支付面板 ") 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: '獲取訂單狀態(tài)..', mask: true, }) // 確認(rèn)訂單 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: '支付成功,請(qǐng)返回小程序查看課程', showCancel: false, icon: 'none' }) } }) } else { uni.showModal({ title: '', content: '支付失敗', showCancel: false, icon: 'none', success(res) {} }) } } ); }, } }
總結(jié)
到此這篇關(guān)于uniapp前端支付篇之微信、抖音、快手、h5四個(gè)平臺(tái)支付功能的文章就介紹到這了,更多相關(guān)uniapp前端微信、抖音、快手、h5支付內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談vue websocket nodeJS 進(jìn)行實(shí)時(shí)通信踩到的坑
這篇文章主要介紹了淺談vue websocket nodeJS 進(jìn)行實(shí)時(shí)通信踩到的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09vue生命周期beforeDestroy和destroyed調(diào)用方式
這篇文章主要介紹了vue生命周期beforeDestroy和destroyed調(diào)用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06Vue3.2?新增指令?v-memo?用法詳解(提高性能利器)
v-memo 接受一個(gè)依賴的數(shù)組,依賴的數(shù)組變化,v-memo 所對(duì)應(yīng)的 DOM 包括子集將會(huì)重新渲染,這篇文章主要介紹了Vue3.2?新增指令?v-memo?用法,提高性能的又一利器,需要的朋友可以參考下2022-09-09vue打包后,用后端接口報(bào)錯(cuò)304、404問題
這篇文章主要介紹了vue打包后,用后端接口報(bào)錯(cuò)304、404問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-05-05vue實(shí)現(xiàn)列表倒計(jì)時(shí)
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)列表倒計(jì)時(shí),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-09-09vue實(shí)現(xiàn)某元素吸頂或固定位置顯示(監(jiān)聽滾動(dòng)事件)
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)某元素吸頂或固定位置顯示,監(jiān)聽滾動(dòng)事件,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12vue3中使用print-js組件實(shí)現(xiàn)打印操作步驟
文章介紹了在Vue?3中使用print-js組件實(shí)現(xiàn)打印操作的步驟,包括安裝依賴、創(chuàng)建打印組件和處理打印預(yù)覽界面,文章還提到打印預(yù)覽界面的樣式調(diào)整對(duì)打印效果的影響,并展示了HTML展示和打印預(yù)覽效果,最后,文章鼓勵(lì)讀者繼續(xù)瀏覽相關(guān)文章并支持腳本之家2025-02-02