公司要求在uniapp上对接braintree支付,自己研究了一下
这是braintree官网 Braintree Developer Documentation (paypal.com)
话不多说,直接上代码
<template>
<view class="content">
<view class="top">
<view class="input-amount">
<view class="">
金额:
</view>
<input type="number" v-model="amount" id="amount" value="" placeholder="付款金额" />
</view>
<view class="card">
<view class="card-Number" id="cc-number"></view>
<view class="card-cvv" id="cc-cvv"></view>
<view class="card-date" id="cc-expiration-date"></view>
</view>
<view class="card-pay" id="card-pay">
</view>
</view>
<view class="bottom">
<view class="buttom-Card" @click="payCard()">
使用信用卡支付
</view>
<view class="buttom-PayPay" @click="payPaypal()">
使用paypal支付
</view>
</view>
</view>
</template>
<script>
export default {
data() {
return {
amount: 1.1,
cardNumberPlaceholder: "请输入你的信用卡号",
cardCVVPlaceholder: "请输入信用卡号背面3位号码",
cardDatePlaceholder: "请输入信用卡有效期",
client: null,
hostedFields: null,
threeDSecure: null,
paypal: null,
clientErr: null,
clientInstance: null,
hostedFieldsInstance: null
}
},
onLoad() {
this.client = require('@/lib/client.min.js');
this.hostedFields = require('@/lib/hosted-fields.min.js');
this.threeDSecure = require('@/lib/three-d-secure.min.js');
this.paypal = require('@/lib/paypal.min.js');
this.client.create({
authorization: "eyJ2ZXJzaW9uIjoyLCJhdXRob3JpemF0aW9uRmluZ2VycHJpbnQiOiJleUowZVhBaU9pSktWMVFpTENKaGJHY2lPaUpGVXpJMU5pSXNJbXRwWkNJNklqSXdNVGd3TkRJMk1UWXRjMkZ1WkdKdmVDSXNJbWx6Y3lJNkltaDBkSEJ6T2k4dllYQnBMbk5oYm1SaWIzZ3VZbkpoYVc1MGNtVmxaMkYwWlhkaGVTNWpiMjBpZlEuZXlKbGVIQWlPakUyTVRnME5UYzFPVFlzSW1wMGFTSTZJbU5pTW1Rek9UTXlMV0pqTW1VdE5ESTBOaTA1TjJaa0xUazJaVFprTmprMU16azVPU0lzSW5OMVlpSTZJbmgwZVRZek4yTnlhbXBpTm1jNVpEWWlMQ0pwYzNNaU9pSm9kSFJ3Y3pvdkwyRndhUzV6WVc1a1ltOTRMbUp5WVdsdWRISmxaV2RoZEdWM1lYa3VZMjl0SWl3aWJXVnlZMmhoYm5RaU9uc2ljSFZpYkdsalgybGtJam9pZUhSNU5qTTNZM0pxYW1JMlp6bGtOaUlzSW5abGNtbG1lVjlqWVhKa1gySjVYMlJsWm1GMWJIUWlPblJ5ZFdWOUxDSnlhV2RvZEhNaU9sc2liV0Z1WVdkbFgzWmhkV3gwSWwwc0luTmpiM0JsSWpwYklrSnlZV2x1ZEhKbFpUcFdZWFZzZENKZExDSnZjSFJwYjI1eklqcDdmWDAuX2xyWmh3VU95b01aTDEwdzJ1SkFtYlFYLXFVRzhUN3VqYWh4OEdaWFZRVFRfT0gzVlZZSkw4WldxVkFjLWJhN2R0VE93VGxrc3RVTE1MSmZuSWoxbEEiLCJjb25maWdVcmwiOiJodHRwczovL2FwaS5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tOjQ0My9tZXJjaGFudHMveHR5NjM3Y3JqamI2ZzlkNi9jbGllbnRfYXBpL3YxL2NvbmZpZ3VyYXRpb24iLCJncmFwaFFMIjp7InVybCI6Imh0dHBzOi8vcGF5bWVudHMuc2FuZGJveC5icmFpbnRyZWUtYXBpLmNvbS9ncmFwaHFsIiwiZGF0ZSI6IjIwMTgtMDUtMDgiLCJmZWF0dXJlcyI6WyJ0b2tlbml6ZV9jcmVkaXRfY2FyZHMiXX0sImNsaWVudEFwaVVybCI6Imh0dHBzOi8vYXBpLnNhbmRib3guYnJhaW50cmVlZ2F0ZXdheS5jb206NDQzL21lcmNoYW50cy94dHk2MzdjcmpqYjZnOWQ2L2NsaWVudF9hcGkiLCJlbnZpcm9ubWVudCI6InNhbmRib3giLCJtZXJjaGFudElkIjoieHR5NjM3Y3JqamI2ZzlkNiIsImFzc2V0c1VybCI6Imh0dHBzOi8vYXNzZXRzLmJyYWludHJlZWdhdGV3YXkuY29tIiwiYXV0aFVybCI6Imh0dHBzOi8vYXV0aC52ZW5tby5zYW5kYm94LmJyYWludHJlZWdhdGV3YXkuY29tIiwidmVubW8iOiJvZmYiLCJjaGFsbGVuZ2VzIjpbXSwidGhyZWVEU2VjdXJlRW5hYmxlZCI6dHJ1ZSwiYW5hbHl0aWNzIjp7InVybCI6Imh0dHBzOi8vb3JpZ2luLWFuYWx5dGljcy1zYW5kLnNhbmRib3guYnJhaW50cmVlLWFwaS5jb20veHR5NjM3Y3JqamI2ZzlkNiJ9LCJwYXlwYWxFbmFibGVkIjp0cnVlLCJwYXlwYWwiOnsiYmlsbGluZ0FncmVlbWVudHNFbmFibGVkIjp0cnVlLCJlbnZpcm9ubWVudE5vTmV0d29yayI6ZmFsc2UsInVudmV0dGVkTWVyY2hhbnQiOmZhbHNlLCJhbGxvd0h0dHAiOnRydWUsImRpc3BsYXlOYW1lIjoiY2hpbmEiLCJjbGllbnRJZCI6IkFXbjY0WnNIVTk2Q3dGY2VfSTlVUXFfTDdjUzZ1dlM0ei1QUTVSWWJjZmRkSFUxbnh2RDVrZjljNDJqS2xnQ25IMTBfRllSRDFPcGE5UFV3IiwicHJpdmFjeVVybCI6Imh0dHA6Ly9leGFtcGxlLmNvbS9wcCIsInVzZXJBZ3JlZW1lbnRVcmwiOiJodHRwOi8vZXhhbXBsZS5jb20vdG9zIiwiYmFzZVVybCI6Imh0dHBzOi8vYXNzZXRzLmJyYWludHJlZWdhdGV3YXkuY29tIiwiYXNzZXRzVXJsIjoiaHR0cHM6Ly9jaGVja291dC5wYXlwYWwuY29tIiwiZGlyZWN0QmFzZVVybCI6bnVsbCwiZW52aXJvbm1lbnQiOiJvZmZsaW5lIiwiYnJhaW50cmVlQ2xpZW50SWQiOiJtYXN0ZXJjbGllbnQzIiwibWVyY2hhbnRBY2NvdW50SWQiOiJjaGluYSIsImN1cnJlbmN5SXNvQ29kZSI6IlVTRCJ9fQ=="
}, (clientErr, clientInstance) => {
// console.log("clientErr:", clientErr)
// console.log("clientInstance:", clientInstance)
this.clientErr = clientErr
this.clientInstance = clientInstance
if (this.clientErr) {
console.error('Error creating client:', clientErr);
return;
}
this.showView()
console.warn("braintree init scuess!")
})
},
methods: {
showView() {
this.hostedFields.create({
client: this.clientInstance,
fields: {
number: {
selector: '#cc-number',
placeholder: this.cardNumberPlaceholder
},
cvv: {
selector: '#cc-cvv',
placeholder: this.cardCVVPlaceholder
},
expirationDate: {
selector: '#cc-expiration-date',
placeholder: this.cardDatePlaceholder
}
}
}, function(err, hostedFieldsInstance) {
if (err) {
console.error("this.hostedFields.create:", err);
return;
}
this.hostedFieldsInstance = hostedFieldsInstance
}.bind(this))
},
payCard() {
console.log("payCard")
this.hostedFieldsInstance.tokenize(function(err, payload) {
if (err) {
console.error(err);
return;
}
console.log("payload:", payload)
let cardType = payload.details.cardType;
let lastFour = payload.details.lastFour;
console.warn("payload.nonce :", payload.nonce);
let my3DSContainer;
this.threeDSecure.create({
client: this.clientInstance
}, function(threeDSecureErr, threeDSecure) {
if (threeDSecureErr) {
console.error("Error creating 3DSecure" + threeDSecureErr);
return;
}
console.log("threeDSecure:", threeDSecure)
threeDSecure.verifyCard({
nonce: payload.nonce,
amount: this.amount,
// bin: payload.details.bin,
addFrame: function(err, iframe) {
// Set up your UI and add the iframe.
my3DSContainer = document.createElement('div');
my3DSContainer.appendChild(iframe);
//document.body.appendChild(my3DSContainer);
document.querySelector("#card-pay").appendChild(my3DSContainer);
},
removeFrame: function() {
//Remove UI that you added in addFrame.
//document.body.removeChild(my3DSContainer);
document.querySelector("#card-pay").removeChild(my3DSContainer);
}
}, function(err, thpayload) {
if (err) {
console.error("verifyCard:", err);
return;
}
if (thpayload.liabilityShiftPossible) {
if (thpayload.liabilityShifted) {
//Liablity has shifted
//submitNonceToServer(payload.nonce);
//document.querySelector('#nonce').value = thpayload.nonce;
console.log('Card Got nonce:', thpayload.nonce);
console.log("payCard ->payload:支付成功 去服务端验证", payload.nonce)
} else {
console.log("Invalid Card!");
}
} else {
document.querySelector('#nonce').value = thpayload.nonce;
console.log('No3D nonce:', thpayload.nonce);
console.log("payCard ->payload:支付成功 去服务端验证", payload.nonce)
}
})
}.bind(this))
}.bind(this))
},
payPaypal() {
console.log("payPaypal")
console.log(" this.client:", this.client)
this.paypal.create({
client: this.clientInstance
}, function(paypalErr, paypalInstance) {
if (paypalErr) {
console.error('Error creating PayPal:', paypalErr);
return;
}
paypalInstance.tokenize({
flow: 'checkout',
amount: this.amount,
currency: 'USD'
}, function(tokenizeErr, payload) {
if (tokenizeErr) {
if (tokenizeErr.type !== 'CUSTOMER') {
console.log('Error tokenizing:', tokenizeErr);
}
return;
}
console.log("payPaypal ->payload:支付成功 去服务端验证", payload.nonce)
})
}.bind(this))
}
}
}
</script>
<style lang="scss">
.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.logo {
height: 200rpx;
width: 200rpx;
margin-top: 200rpx;
margin-left: auto;
margin-right: auto;
margin-bottom: 50rpx;
}
.text-area {
display: flex;
justify-content: center;
}
.title {
font-size: 36rpx;
color: #8f8f94;
}
.top {
display: flex;
flex-direction: column;
align-items: center;
background-color: #677a6e;
width: 100%;
height: 500rpx;
// justify-content: space-around;
.input-amount {
margin-top: 35rpx;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
width: 80%;
color: #FFFFFF;
input {
padding-left: 20rpx;
color: #000000;
margin-left: 20rpx;
width: 80%;
background-color: #c0beb0;
}
}
.card {
margin-top: 35rpx;
width: 80%;
height: 300rpx;
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: space-around;
.card-Number {
width: 100%;
border-radius: 15rpx;
padding-left: 20rpx;
height: 88rpx;
background-color: #dddddd;
}
.card-cvv {
width: 100%;
border-radius: 15rpx;
padding-left: 20rpx;
height: 88rpx;
background-color: #dddddd;
}
.card-date {
width: 100%;
border-radius: 15rpx;
padding-left: 20rpx;
height: 88rpx;
background-color: #dddddd;
}
}
}
.bottom {
position: absolute;
bottom: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
width: 100%;
height: 200rpx;
background-color: #b7d9a7;
.buttom-Card {
width: 80%;
height: 88rpx;
background-color: #007AFF;
border-radius: 30rpx;
text-align: center;
line-height: 88rpx;
color: #FFFFFF;
}
.buttom-PayPay {
width: 80%;
height: 88rpx;
background-color: #ff7139;
border-radius: 30rpx;
text-align: center;
line-height: 88rpx;
color: #FFFFFF;
}
}
</style>
lib目录
使用官网的测试卡号去支付 Testing and Go Live | Ruby - Braintree Developer Documentation (paypal.com)
最后把 authorization 换成自己的就可以了 (必须)
最终效果 (作者这边 authorization 是过期的,只有 authorization 有效的时候输入框才能输入,会显示请输入,authorization 无效则输入框则空白,就像作者一样)
觉得还可以的话点赞评论下