支付对接
This commit is contained in:
@@ -0,0 +1,508 @@
|
||||
<!--#
|
||||
layout("/mobile/platform.html"){
|
||||
#-->
|
||||
|
||||
<style>
|
||||
#app{
|
||||
background-color: #E4E7ED !important;
|
||||
}
|
||||
|
||||
.order-info-container {
|
||||
width: 100%;
|
||||
padding-top: 10px;
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
}
|
||||
|
||||
.order-info-container .orderNo{
|
||||
color: #909399;
|
||||
font-size: 15px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.order-info-container .orderMoney{
|
||||
font-weight: bold;
|
||||
font-size: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.order-info-container .orderMoney .moneyRmb {
|
||||
font-size: 15px;
|
||||
line-height: 2.9;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.order-info-container .expiredTime{
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
margin-right: 25px;
|
||||
margin-top: 15px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.order-info-container .orderRemark{
|
||||
color: #909399;
|
||||
font-size: 10px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.order-payment-methods {
|
||||
position: fixed;
|
||||
top: 190px;
|
||||
width: 100%;
|
||||
height: 60%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.order-payment-methods .payment-methods-card {
|
||||
width: 90%;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
border-radius: 10px;
|
||||
background-color: white;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.order-payment-methods .payment-methods-card .payment-methods-card-header {
|
||||
height: 100px;
|
||||
border-radius: 10px 10px 0px 0px;
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
padding-top: 25px;
|
||||
padding-left: 15px;
|
||||
color: #2f8ff5;
|
||||
background-color: rgb(198, 226, 255);
|
||||
}
|
||||
|
||||
.order-payment-methods .payment-methods-card .payment-methods-card-list{
|
||||
background-color: white;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 1001001;
|
||||
position: absolute;
|
||||
top: 55px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.payment-methods-card-list .van-cell {
|
||||
border-bottom: 1px solid #e2e2e2;
|
||||
}
|
||||
|
||||
.payment-methods-py-channel {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.payment-methods-py-channel .payment-methods-channel-icon {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.payment-methods-py-channel .payment-methods-channel-cell {
|
||||
width: 100%;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.van-btn-container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
height: 120px;
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
border-top: 1px solid #DCDFE6;
|
||||
background-color: #DCDFE6;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.van-btn-container .van-button {
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
background: #fff;
|
||||
background-color: rgb(255, 255, 255);
|
||||
border: 1px solid #dcdfe6;
|
||||
border-top-color: rgb(220, 223, 230);
|
||||
border-right-color: rgb(220, 223, 230);
|
||||
border-bottom-color: rgb(220, 223, 230);
|
||||
border-left-color: rgb(220, 223, 230);
|
||||
font-family: inherit;
|
||||
color: #606266;
|
||||
-webkit-appearance: none;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
margin: 0;
|
||||
margin-left: 0px;
|
||||
transition: .1s;
|
||||
font-weight: 500;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
padding: 12px 20px;
|
||||
font-size: 14px;
|
||||
border-radius: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
.van-btn-container .surePayOrderBtn {
|
||||
color: #fff;
|
||||
background-color: #67c23a;
|
||||
border-color: #67c23a;
|
||||
}
|
||||
.van-btn-container .backSpecifyBtn {
|
||||
border-color: #909399;
|
||||
}
|
||||
|
||||
.w60 {
|
||||
width: 60%;
|
||||
}
|
||||
.w100 {
|
||||
width: 100%;
|
||||
}
|
||||
.mb20px {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div id="app" v-cloak>
|
||||
<van-nav-bar title="确认订单" left-arrow placeholder fixed @click-left="backSpecify"></van-nav-bar>
|
||||
<div class="order-info-container">
|
||||
<div class="orderNo"><span>订单号:</span>{{ urlParams.orderNo }}</div>
|
||||
<div class="expiredTime" v-if="expiredTime.enable">订单有效期
|
||||
<span style="margin-left: 10px;">
|
||||
<span v-if="expiredTime.hoursEnable">{{ expiredTime.hours }}:</span>
|
||||
<span v-if="expiredTime.minutesEnable">{{ expiredTime.minutes }}:</span>
|
||||
<span>{{ expiredTime.seconds }}s</span>
|
||||
</span></div>
|
||||
<div class="orderMoney"><span class="moneyRmb">¥</span>{{ urlParams.money }}</div>
|
||||
<div class="orderRemark">{{ urlParams.remark || '您正在为当前业务缴费' }}</div>
|
||||
</div>
|
||||
<div class="order-payment-methods">
|
||||
<div class="payment-methods-card">
|
||||
<div class="payment-methods-card-header">
|
||||
<div>支付方式</div>
|
||||
</div>
|
||||
<div class="payment-methods-card-list">
|
||||
<div v-for="(item, index) in paymentMethods" :key="index">
|
||||
<div class="payment-methods-py-channel">
|
||||
<div class="payment-methods-channel-icon">
|
||||
<van-icon :name="item.icon" size="25"/>
|
||||
</div>
|
||||
<div class="payment-methods-channel-cell">
|
||||
<van-cell :title="item.title" is-link>
|
||||
<template slot="right-icon">
|
||||
<van-radio-group v-model="form.payChannel">
|
||||
<van-radio :name="item.channelType" checked-color="#409EFF"></van-radio>
|
||||
</van-radio-group>
|
||||
</template>
|
||||
</van-cell>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-btn-container">
|
||||
<div class="w60">
|
||||
<div class="w100 mb20px">
|
||||
<van-button class="surePayOrderBtn" @click="surePayOrder">确认支付</van-button>
|
||||
</div>
|
||||
<div class="w100">
|
||||
<van-button class="backSpecifyBtn" @click="backSpecify">取消支付</van-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const vue = new Vue({
|
||||
el: "#app",
|
||||
mixins: [mobileMixins],
|
||||
data() {
|
||||
return {
|
||||
urlParams: {
|
||||
backUrl: null,
|
||||
orderNo: null,
|
||||
businessType: null,
|
||||
businessId: null,
|
||||
remark: null,
|
||||
money: 0.00
|
||||
},
|
||||
expiredTime: {
|
||||
enable: false,
|
||||
hoursEnable: false,
|
||||
minutesEnable: false,
|
||||
hours: 0,
|
||||
minutes: 2,
|
||||
seconds: 0,
|
||||
},
|
||||
paymentMethods: [{
|
||||
title: '微信',
|
||||
type: 'wx',
|
||||
payChannel: 1,
|
||||
channelType: 1,
|
||||
icon: '/assets/mobile/svg/pay/weixin.svg',
|
||||
}],
|
||||
form: {
|
||||
payChannel: 1,
|
||||
businessType: null,
|
||||
businessId: null,
|
||||
channelType: null
|
||||
},
|
||||
wxConfig: {
|
||||
appId: 'wxf89af07964aabaac',
|
||||
timestamp: '', // 时间戳
|
||||
nonceStr: '', // 随机字符串
|
||||
signature: '', // 签名
|
||||
jsApiList: ['chooseWXPay'] // 需要使用的JS接口列表
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$nextTick(() => {
|
||||
// 加载订单参数
|
||||
this.loadUrlParams();
|
||||
// 开始订单有效期倒计时
|
||||
this.startOrderExpiredTimeCountdown()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
// 确认支付订单
|
||||
async surePayOrder() {
|
||||
let loading = null
|
||||
vant.Dialog.confirm({
|
||||
title: '提示',
|
||||
message: '您确认要支付当前订单吗?',
|
||||
}).then(async () => {
|
||||
loading = this.$toast({
|
||||
duration: 0,
|
||||
message: '正在拉起支付,请稍候',
|
||||
forbidClick: true,
|
||||
loadingType: 'spinner',
|
||||
type: 'loading',
|
||||
overlay: true
|
||||
});
|
||||
|
||||
const paymentMethod = this.paymentMethods.filter(item => item.payChannel === this.form.payChannel)[0]
|
||||
this.form.channelType = paymentMethod.channelType
|
||||
this.form.businessType = this.urlParams.businessType
|
||||
this.form.businessId = this.urlParams.businessId
|
||||
this.form.remark = this.urlParams.remark
|
||||
this.form.money = this.urlParams.money
|
||||
console.log('创建支付订单参数->', this.form)
|
||||
// 创建支付订单 获取支付信息 拉起支付页面
|
||||
const { code, data, msg } = await $.post('/member/pay/record/pay', this.form)
|
||||
if(code !== 0) {
|
||||
loading.close()
|
||||
vant.Toast.fail(msg)
|
||||
} else {
|
||||
loading.close()
|
||||
if(!data.requestResult) {
|
||||
vant.Toast.fail("订单支付拉起失败")
|
||||
return;
|
||||
}
|
||||
|
||||
// 微信支付 初始化微信JS-SDK配置
|
||||
if(paymentMethod.type === 'wx') {
|
||||
await this.loadWxJsConfig();
|
||||
|
||||
wx.ready(function () {
|
||||
|
||||
// 中国银行 微信APP支付
|
||||
if(data.payChannel === 1 && data.channelType === 1) {
|
||||
const payParams = JSON.parse(data.requestResult)
|
||||
console.log("服务端获取的支付参数payParams->", payParams)
|
||||
const prepayData = {
|
||||
appId: payParams.wcPayDataAppId, // 自己的APPID
|
||||
timeStamp: payParams.wcPayDataTimeStamp, // 时间戳
|
||||
nonceStr: payParams.wcPayDataNonceStr, // 随机字符串
|
||||
package: payParams.wcPayDataPrepayId, // 预支付订单号
|
||||
signType: payParams.wcPayDataSignType, // 签名类型
|
||||
paySign: payParams.wcPayDataPaySign // 签名
|
||||
};
|
||||
console.log("调用微信API支付参数->", prepayData)
|
||||
// 调用微信支付API
|
||||
wx.chooseWXPay({
|
||||
timestamp: prepayData.timeStamp,
|
||||
nonceStr: prepayData.nonceStr,
|
||||
package: prepayData.package,
|
||||
signType: prepayData.signType,
|
||||
paySign: prepayData.paySign,
|
||||
success: function(res) {
|
||||
// 支付成功后的操作
|
||||
console.log('支付成功');
|
||||
setTimeout(()=> {
|
||||
this.paySuccess(res, data.goodsTradeCode)
|
||||
}, 500);
|
||||
},
|
||||
cancel: function(res) {
|
||||
// 用户取消支付的操作
|
||||
console.log('支付取消');
|
||||
},
|
||||
fail: function(res) {
|
||||
// 支付失败的操作
|
||||
console.log('支付失败');
|
||||
this.payFail(res, data.goodsTradeCode)
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}).catch((e) => {
|
||||
if(loading) {
|
||||
loading.close()
|
||||
}
|
||||
console.log("用户支付失败->", e)
|
||||
vant.Toast("用户支付失败")
|
||||
});
|
||||
},
|
||||
|
||||
// 支付成功
|
||||
async paySuccess(res, goodsTradeCode) {
|
||||
await $.post('/member/pay/record/check/pay/code?payCode=' + goodsTradeCode)
|
||||
|
||||
const loading = this.$toast({
|
||||
duration: 0,
|
||||
message: '订单支付查询中...',
|
||||
forbidClick: true,
|
||||
loadingType: 'spinner',
|
||||
type: 'loading',
|
||||
overlay: true
|
||||
});
|
||||
|
||||
// 循环拉取支付订单信息
|
||||
await this.repeatQueryPay(loading, goodsTradeCode)
|
||||
},
|
||||
|
||||
// 循环拉取支付订单信息
|
||||
async repeatQueryPay(loading, goodsTradeCode) {
|
||||
setTimeout(async () => {
|
||||
const res = await $.post('/member/pay/record/get/by/code?goodsTradeCode=' + goodsTradeCode)
|
||||
if(res.code !== 0) {
|
||||
loading.close()
|
||||
vant.Toast.fail(msg)
|
||||
} else {
|
||||
const payRecord = res.data
|
||||
|
||||
// 支付成功
|
||||
if(payRecord.status === 1) {
|
||||
loading.close()
|
||||
// 支付失败
|
||||
} else if(payRecord.status === 2) {
|
||||
loading.close()
|
||||
} else {
|
||||
await this.repeatQueryPay(loading, goodsTradeCode)
|
||||
}
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
// 支付失败
|
||||
async payFail(res, goodsTradeCode) {
|
||||
await $.post('/member/pay/record/del/check/pay/code?payCode=' + goodsTradeCode)
|
||||
},
|
||||
|
||||
// 返回指定页面
|
||||
async backSpecify() {
|
||||
if(!this.urlParams.backUrl) {
|
||||
this.urlParams.backUrl = '/mobile/index'
|
||||
}
|
||||
pjaxReplace(this.urlParams.backUrl)
|
||||
},
|
||||
|
||||
// 加载地址参数
|
||||
async loadUrlParams() {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
console.log('支付请求地址参数--->', urlParams)
|
||||
const backUrl = urlParams.get('backUrl');
|
||||
const orderNo = urlParams.get('orderNo');
|
||||
const businessType = urlParams.get('businessType');
|
||||
const businessId = urlParams.get('businessId');
|
||||
const money = urlParams.get('money');
|
||||
const orderRemark = urlParams.get('remark');
|
||||
this.urlParams.backUrl = backUrl;
|
||||
this.urlParams.orderNo = orderNo;
|
||||
this.urlParams.businessType = businessType;
|
||||
this.urlParams.businessId = businessId;
|
||||
this.urlParams.money = money;
|
||||
this.urlParams.remark = orderRemark;
|
||||
},
|
||||
|
||||
// 开始订单有效期倒计时
|
||||
async startOrderExpiredTimeCountdown() {
|
||||
let startTime = 0
|
||||
if(this.expiredTime.hours > 0 && this.expiredTime.minutes <= 0) {
|
||||
this.expiredTime.minutes = 59
|
||||
this.expiredTime.hours = this.expiredTime.hours - 1
|
||||
}
|
||||
if(this.expiredTime.minutes > 0 && this.expiredTime.seconds <= 0) {
|
||||
this.expiredTime.seconds = 59
|
||||
this.expiredTime.minutes = this.expiredTime.minutes -1
|
||||
}
|
||||
if(this.expiredTime.seconds > 0) {
|
||||
startTime = this.expiredTime.seconds
|
||||
}
|
||||
if(startTime > 0) {
|
||||
this.expiredTime.enable = true
|
||||
if(this.expiredTime.hours > 0) {
|
||||
this.expiredTime.hoursEnable = true
|
||||
}
|
||||
if(this.expiredTime.minutes > 0) {
|
||||
this.expiredTime.minutesEnable = true
|
||||
}
|
||||
await this.startExpiredTimeCountdown(startTime)
|
||||
} else {
|
||||
this.expiredTime.enable = false
|
||||
}
|
||||
},
|
||||
async startExpiredTimeCountdown(seconds) {
|
||||
setTimeout(() => {
|
||||
if((seconds -1) === 0 && this.expiredTime.minutes > 0) {
|
||||
this.expiredTime.minutes = this.expiredTime.minutes - 1
|
||||
this.expiredTime.seconds = 59
|
||||
} else {
|
||||
this.expiredTime.seconds = seconds - 1
|
||||
}
|
||||
|
||||
if(this.expiredTime.hours > 0 && this.expiredTime.minutes <= 0) {
|
||||
this.expiredTime.minutes = 59
|
||||
this.expiredTime.hours = this.expiredTime.hours -1
|
||||
}
|
||||
|
||||
if(this.expiredTime.seconds > 0) {
|
||||
this.startExpiredTimeCountdown(this.expiredTime.seconds)
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
|
||||
// 加载微信JS-SDK配置
|
||||
async loadWxJsConfig() {
|
||||
await wx.config({
|
||||
debug: false,
|
||||
appId: this.wxConfig.appId,
|
||||
timestamp: this.wxConfig.timestamp,
|
||||
nonceStr: this.wxConfig.nonceStr,
|
||||
signature: this.wxConfig.signature,
|
||||
jsApiList: this.wxConfig.jsApiList,
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!--#
|
||||
}
|
||||
#-->
|
||||
Reference in New Issue
Block a user