|
|
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge">
<!--jquery为了调用服务端获取token--> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.2.1/jquery.min.js"></script> <script src="https://js.braintreegateway.com/web/3.71.0/js/client.js"></script> <script src="https://js.braintreegateway.com/web/3.71.0/js/hosted-fields.js"></script> <script src="https://js.braintreegateway.com/web/3.71.0/js/data-collector.min.js"></script>
<!-- Latest compiled and minified CSS --> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<!-- Optional theme --> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">
<title>Payment</title> <style> body { background-color: #efecec; }
button { width: 97px; height: 40px; padding: 10px; font-size: 16px; color: #fff; background-color: #47A2FF; border: none; border-radius: 5px; }
.loading { margin: 20% auto; text-align: center; border: 16px solid #f3f3f3; border-radius: 50%; border-top: 16px solid #3498db; width: 120px; height: 120px; -webkit-animation: spin 2s linear infinite; animation: spin 2s linear infinite; z-index: 1000; display: none; }
@-webkit-keyframes spin { 0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); } }
@keyframes spin { 0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); } }
.main { margin: 50px auto; width: 90%; max-width: 800px; background-color: #fff; padding: 10px 20px; min-height: 500px; border-radius: 10px; } /*.btn{width:100%;text-align: center;display: none;}*/ /*hosted field*/ body { background-color: #fff; padding: 15px; }
.toast { position: fixed; top: 15px; right: 15px; z-index: 9999; }
.bootstrap-basic { background: white; }
/* Braintree Hosted Fields styling classes*/ .braintree-hosted-fields-focused { color: #495057; background-color: #fff; border-color: #80bdff; outline: 0; box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25); }
.braintree-hosted-fields-focused.is-invalid { border-color: #dc3545; box-shadow: 0 0 0 0.2rem rgba(220, 53, 69, 0.25); }
.row { margin-bottom: 40px; }
.alert-fixed { position: fixed; top: 10px; left: 50%; width: 10%; z-index: 9999; border-radius: 0px; padding: 5px; } </style>
</head> <body>
<input type="hidden" name="_token" id="_token" value="{{.Authorization}}" /> <input type="hidden" name="_submitUrl" id="_submitUrl" value="http://localhost:17764/api/homeapi/process" /> <input type="hidden" name="_amt" id="_amt" value="{{.Amt}}" /> <input type="hidden" name="_cur" id="_cur" value="{{.Currency}}" /> <input type="hidden" name="_intent" id="_intent" value="{{.Intent}}" /> <input type="hidden" name="_flow" id="_flow" value="{{.Flow}}" /> <input type="hidden" name="_transactionNo" id="_transactionNo" value="{{.TransactionNo}}" /> <input type="hidden" name="_vendor" id="_vendor" value="{{.Vendor}}" />
<div class="alert-primary alert-fixed" style="text-align: center; display: none;" role="alert"> <i class="fa fa-check-circle-o" aria-hidden="true" style="padding: 0 5px;"></i>Apply successfully! </div> <div class="loading" id="loading"></div> <div class="main" id="main"> <div class="info"> <p>Transaction No: {{.TransactionNo}}</p> <p>Amount: {{.Amt}}</p> <p>Currency: {{.Currency}}</p> </div> <div class="bootstrap-basic"> <form class="needs-validation" novalidate=""> <div class="row"> <div class="form-item col-sm-12 mb-3 is-required"> <label for="first-name">First Name</label> <input class="form-control" id="first-name"> <!-- <small class="text-muted">First name as displayed on card</small>--> <div class="invalid-feedback"> First Name is required </div> </div> <div class="form-item col-sm-12 mb-3 is-required"> <label for="last-name">Last Name</label> <input class="form-control" id="last-name"> <!-- <small class="text-muted">Last name as displayed on card</small>--> <div class="invalid-feedback"> Last Name is required </div> </div> <div class="form-item col-sm-12 mb-3 is-required"> <label for="email">Email</label> <input type="email" class="form-control" id="email" placeholder="[email protected]"> <div class="invalid-feedback"> Please enter a valid email </div> </div> <div class="form-item col-sm-12 mb-3 "> <label for="countryId">Country</label> <select class="countries form-control" id="countryId"> <option value="">Select Country</option> </select> <div class="invalid-feedback"> Please select country. </div> </div> <!--<div class="form-item col-sm-12 mb-3 is-required">--> <!--<label for="phone">Phone</label>--> <!--<input class="form-control" id="phone">--> <!--<div class="invalid-feedback">--> <!--Please enter phone.--> <!--</div>--> <!--</div>--> <div class="form-item col-sm-12 mb-3 "> <label for="stateId">State</label> <select class="states form-control" id="stateId"> <option value="">Select State</option> </select> <div class="invalid-feedback"> Please select state. </div> </div> <div class="form-item col-sm-12 mb-3 "> <label for="cityId">City</label> <select class="cities form-control" id="cityId"> <option value="">Select City</option> </select> <div class="invalid-feedback"> Please select city. </div> </div> <div class="form-item col-sm-12 mb-3 is-required"> <label for="streetAddress">StreetAddress</label> <input class="form-control" id="streetAddress"> <div class="invalid-feedback"> Please enter streetAddress. </div> </div> <div class="form-item col-sm-12 mb-3"> <label for="streetAddress2">StreetAddress2</label> <input class="form-control" id="streetAddress2"> <div class="invalid-feedback"> Please enter streetAddress. </div> </div> <div class="form-item col-sm-12 mb-3 is-required"> <label for="postal-code">Post Code</label> <input class="form-control" id="postal-code"> <div class="invalid-feedback"> Please enter postal code. </div> </div> <div class="form-item col-sm-12 mb-3 is-required"> <label for="cc-number">Credit card number</label> <div class="form-control" id="cc-number"></div> <div class="invalid-feedback"> Credit card number is required </div> </div> <div class="form-item col-sm-12 mb-3 is-required"> <label for="cc-expiration">Expiration</label> <div class="form-control" id="cc-expiration"></div> <div class="invalid-feedback"> Expiration date required </div> </div> <div class="form-item col-sm-12 mb-3 is-required"> <label for="cc-expiration">CVV</label> <div class="form-control" id="cc-cvv"></div> <div class="invalid-feedback"> Security code required </div> </div> </div> <hr class="mb-4"> <div class="text-center"> <!-- <button class="btn btn-primary btn-lg" type="submit">Pay with <span id="card-brand">Card</span></button>--> <button class="btn btn-primary btn-lg" type="submit">Pay</button> </div> </form> </div> </div>
<script> // 数据 let curPaymentMethod = ''; const paymentMethods = { 'CreditCard': 'credit_card', 'PayPalAccount': 'paypal_account', 'VenmoAccount': 'venmo_account', 'ApplePayCard': 'apple_pay_card', 'AndroidPayCard': 'android_pay_card', //google pay } const token = document.getElementById('_token').value; const amount = document.getElementById('_amt').value; const intent = document.getElementById('_intent').value; const currency = document.getElementById('_cur').value; const transactionNo = document.getElementById('_transactionNo').value; // const url = document.getElementById("_submitUrl").value; const vendor = document.getElementById("_vendor").value; const url = '/bt/process'; // const vendor = 'creditcard';
//方法
function ajaxObject() { let xmlHttp; try { // Firefox, Opera 8.0+, Safari xmlHttp = new XMLHttpRequest(); } catch (e) { // Internet Explorer try { xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { alert("您的浏览器不支持AJAX!"); return false; } } } return xmlHttp; }
function ajaxPost(url, data, fnSucceed) { $.ajax({ type: "POST", url: url, data: data, contentType: "application/x-www-form-urlencoded", dataType: "json", success: function (data) { console.log("success"); fnSucceed(data); }, error: function (data) { console.log("error"); }, })
}
function getVendor() { // 根据vendor 配置braintree 的支付渠道 let curVendor = null; console.log('vendor is: ', vendor); switch (vendor) { case 'paypal': curVendor = { paypal: { flow: 'checkout', amount: amount, currency: currency }, // paypalCredit: { // flow: 'checkout', // amount: amount, // currency: currency // }, }; break case 'venmo': curVendor = { venmo: { // 只会在移动端出现 allowNewBrowserTab: false } }; break case 'googlepay': curVendor = { card: false, // 不显示信用卡 googlePay: { // googlePayVersion: 2, // merchantId: 'merchant-id-from-google', transactionInfo: { totalPriceStatus: 'FINAL', totalPrice: amount, currencyCode: currency }, allowedPaymentMethods: [{ type: 'CARD', parameters: { // We recommend collecting and passing billing address information with all Google Pay // transactions as a best practice. billingAddressRequired: true, billingAddressParameters: { format: 'FULL' } } }] }, }; break case 'applepay': curVendor = { applePay: { displayName: 'Merchant Name', paymentRequest: { label: 'Localized Name', currencyCode: '', merchantCapabilities: '', total: amount } }, }; break case 'creditcard': break default: console.log('vendor is: ', vendor); } console.log('curVendor info: ', curVendor); return curVendor }
function handleIdElementStyle(id, attr, val) { const el = document.getElementById(id); if (el) { el.style[attr] = val; } }
function initClient() { const curVendor = getVendor(); const options = { authorization: token, container: '#dropin-container', ...curVendor }; console.log('options', options);
var form = $('form');
braintree.client.create({ authorization: token, }, function (err, clientInstance) { if (err) { console.error(err); alert('clientInstance: ' + JSON.stringify(err)); return; } braintree.dataCollector.create({ client: clientInstance, paypal: true }, function (err, dataCollectorInstance) { if (err) { // Handle error in creation of data collector console.error(err); alert('clientInstance: ' + JSON.stringify(err)); return; } // At this point, you should access the dataCollectorInstance.deviceData value and provide it // to your server, e.g. by injecting it into your form as a hidden input. var deviceData = dataCollectorInstance.deviceData;
braintree.hostedFields.create({ client: clientInstance, styles: { input: { // change input styles to match // bootstrap styles 'font-size': '1rem', color: '#495057' } }, fields: { // cardholderName: { // selector: '#cc-name', // placeholder: 'Name as it appears on your card' // }, number: { selector: '#cc-number', placeholder: '4111 1111 1111 1111' }, cvv: { selector: '#cc-cvv', placeholder: '123' }, expirationDate: { selector: '#cc-expiration', placeholder: 'MM / YYYY' } } }, function (err, hostedFieldsInstance) { if (err) { console.error('hostedFieldsInstance: ' + err); return; } function createInputChangeEventListener(element) { return function () { validateInput(element); } }
function setValidityClasses(element, validity) { if (validity) { element.removeClass('is-invalid'); element.addClass('is-valid'); } else { element.addClass('is-invalid'); element.removeClass('is-valid'); } }
function validateInput(element) { // very basic validation, if the // fields are empty, mark them // as invalid, if not, mark them // as valid
if (!element.val().trim()) { setValidityClasses(element, false);
return false; }
setValidityClasses(element, true);
return true; } var email = $('#email'); function validateEmail() { var baseValidity = validateInput(email);
if (!baseValidity) { return false; }
if (email.val().indexOf('@') === -1) { setValidityClasses(email, false); return false; }
setValidityClasses(email, true); return true; }
$('.form-item.is-required input').on('blur change', function () { var $this = $(this); if ($this.type == 'email') { validateEmail($this); } validateInput($this); })
$('.form-item.is-required select').on('blur change', function () { var $this = $(this); validateInput($this); })
hostedFieldsInstance.on('validityChange', function (event) { var field = event.fields[event.emittedBy];
// Remove any previously applied error or warning classes $(field.container).removeClass('is-valid'); $(field.container).removeClass('is-invalid');
if (field.isValid) { $(field.container).addClass('is-valid'); } else if (field.isPotentiallyValid) { // skip adding classes if the field is // not valid, but is potentially valid } else { $(field.container).addClass('is-invalid'); } });
hostedFieldsInstance.on('cardTypeChange', function (event) { var cardBrand = $('#card-brand'); var cvvLabel = $('[for="cc-cvv"]');
if (event.cards.length === 1) { var card = event.cards[0];
// change pay button to specify the type of card // being used cardBrand.text(card.niceType); // update the security code label cvvLabel.text(card.code.name); } else { // reset to defaults cardBrand.text('Card'); cvvLabel.text('CVV'); } });
form.submit(function (event) { event.preventDefault(); //显示loading handleIdElementStyle('loading', 'display', 'block');
var formIsInvalid = false;
// perform validations on the non-Hosted Fields // inputs if (!validateEmail()) { formIsInvalid = true; } var $inputs = $('.form-item.is-required input') for (var i = 0; i < $inputs.length; i++) { if (!validateInput($inputs.eq(i))) { formIsInvalid = true } }
var $selects = $('.form-item.is-required select') for (var i = 0; i < $selects.length; i++) { if (!validateInput($selects.eq(i))) { formIsInvalid = true } } var state = hostedFieldsInstance.getState(); // Loop through the Hosted Fields and check // for validity, apply the is-invalid class // to the field container if invalid Object.keys(state.fields).forEach(function (field) { if (!state.fields[field].isValid) { $(state.fields[field].container).addClass('is-invalid'); formIsInvalid = true; } });
if (formIsInvalid) { // skip tokenization request if any fields are invalid //隐藏loading handleIdElementStyle('loading', 'display', 'none'); return; } const firstName = document.getElementById('first-name').value; const lastName = document.getElementById('last-name').value; const countryName = document.getElementById('countryId').value; const stateName = document.getElementById('stateId').value; const city = document.getElementById('cityId').value; const address = document.getElementById('streetAddress').value; const address2 = document.getElementById('streetAddress2').value; let streetAddressArr = [] stateName && streetAddressArr.push(streetAddressArr) city && streetAddressArr.push(city) address && streetAddressArr.push(address) address2 && streetAddressArr.push(address2) const postalCode = document.getElementById('postal-code').value; const email = document.getElementById('email').value; const tokenizeOption = { cardholderName: firstName + ' ' + lastName, billingAddress: { firstName: firstName, lastName: lastName, cardholderName: '2333', // company: 'Company', streetAddress: streetAddressArr.join(','), postalCode: postalCode, // extendedAddress: 'Unit 1', // passing just one of the country options is sufficient to // associate the card details with a particular country // valid country names and codes can be found here: // https://developers.braintreepayments.com/reference/general/countries/ruby#list-of-countries countryName: 'United States', countryCodeAlpha2: 'US', countryCodeAlpha3: 'USA', countryCodeNumeric: '840' } }; hostedFieldsInstance.tokenize(tokenizeOption, function (err, payload) { if (err) { console.error(err); alert('payload: ' + JSON.stringify(err)); //隐藏loading handleIdElementStyle('loading', 'display', 'none'); return; }
// This is where you would submit payload.nonce to your server // $('.toast').toast('show');
// you can either send the form values with the payment // method nonce via an ajax request to your server, // or add the payment method nonce to a hidden inpiut // on your form and submit the form programatically // $('#payment-method-nonce').val(payload.nonce); // form.submit()
// 通过payload来给curPaymentMethod赋值 curPaymentMethod = paymentMethods[payload.type]; // Submit payload.nonce to your server const temp = payload; const params = "paymentMethodNonce="+payload.nonce+"&transactionNo="+transactionNo+ "&paymentMethod="+curPaymentMethod+"&firstName="+firstName+"&lastName="+ lastName+"&addressLine1="+streetAddress+"&postalCode="+postalCode+"&email="+email+ "&deviceData=" + deviceData; ajaxPost(url, params, function (data) { const result = data; if ("success" === result.result.status) { handleIdElementStyle('loading', 'display', 'none');
$('.alert-primary').show(500); setTimeout(function () { // handleIdElementStyle('main','display','block'); window.location.href = ""; }, 1500); } else { handleIdElementStyle('loading', 'display', 'none'); handleIdElementStyle('main', 'display', 'block'); alert(result.ret_msg) location.reload(); } }) }); }); }); }); });
} //=====================start project======================= // initClient()
</script> <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script> <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</body> </html>
|