二维码收款——前端UI
线下店铺一般使用的店铺收款码,有银行提供的,有通联的,结合语音播报,方便快捷,下面我们来做一个类似的属于自己收款系统
本系列文章分3部分
- 前端UI
- 后端系统
- 通知系统
UI界面直接借鉴微信(哈哈),如下图
前端使用Vue,3个文件,pay.html,pay.js,pay.css
简要说明
- 数字键盘使用table标签布局,可以完美的模拟微信键盘的效果,按键按下时有高亮效果,通过js控制只能输入有效的数值
- 请求时URL中带有商户号参数,例如xxx.com/pay.html?mercNo=xxx,mercNo就是商户号,商户信息包含商户名,商户LOGO,请求商户信息后,显示出来
<html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" /> <title>付款</title> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/vant@2.12/lib/index.css" /> <link rel="stylesheet" href="pay.css" /> <script src="../js/common.js"></script> <style type="text/css"> [v-cloak] { display: none; } </style> </head> <body> <div class="w-warp" id="main" v-cloak> <div class="info"> <div class="text"> <h4>付款给</h4> <p style="color: gray">{{mercInfo.mercName}}</p> </div> <div class="head"><img :src="mercInfo.mercLogo" width="60px" height="60px" /></div> </div> <div class="amount"> <h5>金额</h5> <div class="input"> <p class="symbol">¥</p> <p class="placeholder" v-if="!activeInput">输入金额</p> <p class="num" v-else>{{validNum}}</p> </div> </div> <div class="addmemo"> <p @click="showMemoDialog=true">{{memo.length>0 ? memo : '添加备注'}}</p> </div> <div class="keyboard"> <table cellspacing="8" > <tr> <td @click="onKeyboard(1)" @touchstart="keyHighlight['1']=true" @touchend="keyHighlight['1']=false" :class="{'keyhighlight': keyHighlight['1']}">1</td> <td @click="onKeyboard(2)" @touchstart="keyHighlight['2']=true" @touchend="keyHighlight['2']=false" :class="{'keyhighlight': keyHighlight['2']}">2</td> <td @click="onKeyboard(3)" @touchstart="keyHighlight['3']=true" @touchend="keyHighlight['3']=false" :class="{'keyhighlight': keyHighlight['3']}">3</td> <td style="width: 22%;" @click="onKeyboard('DEL')" @touchstart="keyHighlight['DEL']=true" @touchend="keyHighlight['DEL']=false" :class="{'keyhighlight': keyHighlight['DEL']}">DEL</td> </tr> <tr> <td @click="onKeyboard(4)" @touchstart="keyHighlight['4']=true" @touchend="keyHighlight['4']=false" :class="{'keyhighlight': keyHighlight['4']}">4</td> <td @click="onKeyboard(5)" @touchstart="keyHighlight['5']=true" @touchend="keyHighlight['5']=false" :class="{'keyhighlight': keyHighlight['5']}">5</td> <td @click="onKeyboard(6)" @touchstart="keyHighlight['6']=true" @touchend="keyHighlight['6']=false" :class="{'keyhighlight': keyHighlight['6']}">6</td> <td rowspan="3" class="paybtn" @click="onKeyboard('pay')" @touchstart="keyHighlight['pay']=true" @touchend="keyHighlight['pay']=false" :class="{'paybtnhighlight': keyHighlight['pay']}">付款</td> </tr> <tr> <td @click="onKeyboard(7)" @touchstart="keyHighlight['7']=true" @touchend="keyHighlight['7']=false" :class="{'keyhighlight': keyHighlight['7']}">7</td> <td @click="onKeyboard(8)" @touchstart="keyHighlight['8']=true" @touchend="keyHighlight['8']=false" :class="{'keyhighlight': keyHighlight['8']}">8</td> <td @click="onKeyboard(9)" @touchstart="keyHighlight['9']=true" @touchend="keyHighlight['9']=false" :class="{'keyhighlight': keyHighlight['9']}">9</td> </tr> <tr> <td colspan="2" @click="onKeyboard(0)" @touchstart="keyHighlight['0']=true" @touchend="keyHighlight['0']=false" :class="{'keyhighlight': keyHighlight['0']}">0</td> <td @click="onKeyboard('.')" @touchstart="keyHighlight['.']=true" @touchend="keyHighlight['.']=false" :class="{'keyhighlight': keyHighlight['.']}">.</td> </tr> </table> </div> <!-- 备注输入框 --> <van-dialog v-model="showMemoDialog" confirm-button-color='#1aad19'> <van-field v-model="memo" label="备注" placeholder="输入备注" size='large'/> </van-dialog> </div> </div> </body> <!-- 引入 Vue 和 Vant 的 JS 文件 --> <script src="https://cdn.jsdelivr.net/npm/vue@2.6/dist/vue.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/vant@2.12/lib/vant.min.js"></script> <script src="../js/config.js"></script> <script src="pay.js"></script> </html>
new Vue({ el: '#main', data: { activeInput: false, //激活输入 inputText: [], //输入的字符队列 validNum: 0, //有效的输入数字 keyHighlight: { 1: false, 2: false, 3: false, 4: false, 5: false, 6: false, 7: false, 8: false, 9: false, 0: false, '.': false, DEL: false, pay: false, }, //键盘高亮 showMemoDialog: false, //显示备注输入框 memo: '', mercInfo: {}, //商户信息 }, created() {}, mounted() { //商户号 let mercNo = getQueryVariable('mercNo'); refu.get(`/a/merc/info?mercNo=${mercNo}`).then((res) => { this.mercInfo = res.result; }); }, methods: { //验证金额是否有效 validNumber(t) { var reg = /((^[1-9]\d*)|^0)(\.\d{0,2}){0,1}$/; return reg.test(t); }, //点击键盘 onKeyboard(key) { if (key == 'DEL') { this.inputText.pop(); if (this.inputText.length > 0) { var s = this.inputText.join(''); this.validNum = s; } else { this.validNum = 0; this.activeInput = false; } return; } if (key == 'pay') { console.log('输入金额:', this.validNum); if (this.validNum == '0') return; let amount = parseFloat(this.validNum); if (!this.testWeixinOk()) { refu.toast('请在微信内打开'); return; } //发起支付请求 this.requestPay(this.mercInfo.mercNo, amount, this.memo).then((res) => { this.invokeWxpayJsApi(res.result); }); return; } this.inputText.push(key); var s = this.inputText.join(''); if (this.validNumber(s)) { this.validNum = s; this.activeInput = true; } else { this.inputText.pop(); } }, //发起支付请求 async requestPay(mercNo, amount, memo) { let param = { mercNo: mercNo, amount: amount, memo: memo, channel: 'wxpay', }; return await refu.post('/a/create/pay/order', param); }, //检测微信环境 testWeixinOk() { return typeof WeixinJSBridge != 'undefined'; }, //拉起微信支付 invokeWxpayJsApi(param) { WeixinJSBridge.invoke('getBrandWCPayRequest', param, function (res) { if (res.err_msg === 'get_brand_wcpay_request:ok') { // 使用以上方式判断前端返回,微信团队郑重提示: // res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。 window.location.href = SiteInfo.paySuccessRedirect; } }); }, }, filters: {}, computed: {}, });
body { background: #ededed; margin: 0; } p, h4 { margin: 0.5rem 0rem; } .w-warp { display: flex; flex-direction: column; height: 100%; } .info { display: flex; padding: 1rem 1rem; align-items: center; } .info .text { flex-grow: 1; } .info .head { flex-grow: 0; } .amount { flex-grow: 1; padding: 0.5rem 1rem; background-color: white; border-top-left-radius: 0.8rem; border-top-right-radius: 0.8rem; } .amount .input { display: flex; align-items: flex-end; font-size: 30px; font-weight: bold; border-bottom: solid 1px lightgray; } .input .symbol { margin: 0.5rem 0.6rem 0.5rem 0rem; } .input .placeholder { font-weight: normal; color: lightgray; } .addmemo { display: flex; justify-content: center; color: #726f89; background: white; padding: 1rem 0; font-size: 16px; } .keyboard table { width: 100%; } .keyboard td { font-size: 18; font-weight: bold; background: white; border-radius: 10px; border: none; text-align: center; padding: 0.8rem 0rem; } .keyboard .keyhighlight { background: #dedede; } .keyboard .paybtn { background: #1aad19; color: white; } .keyboard .paybtnhighlight { background: #07ae56; }
下一篇,后端API