前言
微信、快手、h5支付步驟大致相同,只有抖音是有自己的支付組件
項目同時支持多個(微信、快手、h5)平臺支付,后端那邊代碼可以封裝的
各平臺支付大致流程都是相同的,總結(jié)了一下分為五個步驟
- 點擊支付
- 創(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
}
// 如果一個項目里有多個平臺支付,可以用傳值來區(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ù)向后端要 要確保每個值就有
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'
});
// 重新請求下商品詳情
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
}
// 如果一個項目里有多個平臺支付,可以用傳值來區(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'
});
// 重新請求下商品詳情
that.detailFn()
})
},
fail: function fail(res) {
uni.showToast({
title: '支付失敗',
icon: 'none'
})
}
})
// #endif
}).catch(res => {
console.log(res)
})
})
}
三、抖音支付
抖音有自己的支付組件和自己的下單頁面,所以需要創(chuàng)建一個專屬于抖音的組件,并把需要的參數(shù)進(jìn)行傳遞
1.創(chuàng)建組件
1.新建ttcomponents文件夾,創(chuàng)建完后在ttcomponents下面再新建DyPayButton文件夾,然后在DyPayButton下面創(chuàng)建四個文件,分別為index.js、index.json、index.ttml、index.ttss
2.要創(chuàng)建在App.vue同級
先在App.vue 寫baseUrl和getPhoneNumber函數(shù)
<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:加密數(shù)據(jù)
* success:成功回調(diào)
* fail: 失敗回調(diào)
*/
// 這個是抖音下單頁獲取手機號調(diào)用的函數(shù)
getPhoneNumber({
params,
success,
fail
}) {
const {
iv,
encryptedData
} = params;
miniLogin().then(data=>{
getTtOpen(data).then(data1 => {
// 獲取手機號函數(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';
/*每個頁面公共css */
</style>
下面是那四個文件的內(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: {
// 提交商品信息 這個函數(shù)一進(jìn)頁面就會調(diào)用的
getGoodsInfo(event) {
const that = this
return new Promise(resolve => {
// 定時器是為解決 優(yōu)惠卷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 // 優(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 // 手機號是否必填
}
},
marketingVersion: 1,
}
// im客服需要提前開通
// 判斷如果用戶手機是ios就走客服支付, 把imId傳上就自動跳轉(zhuǎn)im客服頁面了,安卓不要傳這個id,否則可能會導(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 {
// 支付失敗(超時、取消、關(guān)閉)
this.showTost('支付失?。ǔ瑫r、取消、關(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給商品詳情頁面注冊組件
"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-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支付渠道文章來源:http://www.zghlxwxcb.cn/news/detail-787483.html
1.創(chuàng)建按鈕
// 這個按鈕是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)建頁面
在詳情頁同級目錄創(chuàng)建一個頁面detailsContact.vue,后端可以重定向到這個頁面文章來源地址http://www.zghlxwxcb.cn/news/detail-787483.html
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ū)分哪個小程序
platform : queryObj.platform // 區(qū)分平臺
}
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: '支付成功,請返回小程序查看課程',
showCancel: false,
icon: 'none'
})
}
})
} else {
uni.showModal({
title: '',
content: '支付失敗',
showCancel: false,
icon: 'none',
success(res) {}
})
}
}
);
},
}
}
到了這里,關(guān)于uniapp前端支付篇(微信、抖音、快手、h5)四個平臺支付的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!