vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > uniapp前端微信、抖音、快手、h5支付

uniapp前端支付篇之微信、抖音、快手、h5四个平台支付功能

作者:伴梦123

支付功能在我们日常开发中经常会遇到,下面这篇文章主要给大家介绍了关于uniapp前端支付篇之微信、抖音、快手、h5四个平台支付功能的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

微信、快手、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 : '', // 分销员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)
		})
	})
}

二、快手支付

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 : '', // 分销员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.创建组件

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;
}

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: 商品详情页的数据
// classsname: 按钮类名
// promoterShareId: 分销员id
// @refreshData: 用于支付成功回调刷新页面

4.h5支付

主要是为解决微信ios无法支付的问题,ios走h5支付渠道

1.创建按钮

// 这个按钮是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: 发送卡片

2.创建页面

在详情页同级目录创建一个页面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) {}
							})
						}
					}
				);
			},
		}
	}

总结 

到此这篇关于uniapp前端支付篇之微信、抖音、快手、h5四个平台支付功能的文章就介绍到这了,更多相关uniapp前端微信、抖音、快手、h5支付内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文