vue递归轮询实现扫码支付

本文是由Vue的SPA对接到外接设备的驱动进行交互,需要从后端接口获取支付链接传输到外接设备(大屏幕的智能设备)生成二维码。(当然也可以通过支付链接自己转成二维码)
首先定义一个单选组,有两种支付方式:“微信”,“支付宝”支付方式。paySucceed为true表示支付成功,则提示支付成功,隐藏掉支付单选

微信 支付宝

payWayChange校验 【vue递归轮询实现扫码支付】因为外接设备的电脑驱动服务主要是通过websocket进行数据交互的,所以需要在一开始通过webSocket.OPEN去验证websocket当前浏览器与驱动/设备是否正常连接中,如没连接上进行提示并中断当前的操作。
当然在校验的时候需要重置(初始化)外接设备、支付状态、定时器。
开始支付 获取支付的一些参数并通过接口(getPayStatus)获取到支付的url链接,调用openQRcode传递链接到外接设备上,显示出二维码进行支付(这里可以使用qrcode的js库转成二维码图片跳转页面的形式显示出二维码)。
在这里是调用openQRcode方法只是个举例,外接设备一般都会有提供自己驱动以及对接驱动的js,按照自己的实际情况来。
支付中(轮询) 当二维码成功显示后立即调用queryStatus()利用获取到的订单号为参数进入一个支付状态的查询(使用setTimeout轮询)
queryStatus内部是一个没经过包装的请求,当请求返回payStatus表示当前未支付完成,或在支付中,否则为支付成功。
每隔3秒轮询一次(尾递归queryStatus获取支付状态 成功 or 失败):
window.pollTimer = setTimeout(() => { return queryStatus(); //轮询查询支付状态3s }, 3000)

在queryStatus中的请求使用了axios,是因为这里的post包装请求pending过程中自动加上了“加载中。。。”的全屏界面动画,因为轮询是不断进行的不能显示加载动画,否则会造成每次获取状态都会一直出现加载动画关闭/显示的闪屏效果,所以这里使用原生axios
支付完成 支付成功后就进行提示,达成递归终止条件,清除掉计时器,重置支付的状态。最后5s计时器是为了给个小延迟,防止设备上支付成功后就秒关掉了界面 ,没有显示支付成功的问题
if ((res.payStatus == 2) || (res.payStatus == 1)) { //支付成功,关闭弹窗 that.paySucceed = true; window.pollTimer && window.clearTimeout(window.pollTimer); //支付成功后干些事情。。。 setTimeout(() => { that.common.cancelAll(); that.resetPay(); }, 5000) }

payWayChange (val) { //清除计时器轮询状态 clearTimeout(window.pollTimer); window.pollTimer = null; if (webSocket.readyState != webSocket.OPEN) { this.$message({ message: '请正确连接设备或设备驱动未启动,请检查', type: 'error' }); this.resetPay(); return; }this.common.cancelAll(); //关闭电子屏支付页//参数 let params = { type: val === 'wechat' ? 'WeChatPay' : 'AliPay', data: { paymentType:1, id:'123', payMoney: '30.0', payWay: this.payWay, } } let that = this; function queryStatus () { window.clearTimeout(window.pollTimer) axios({//使用axios,不显示加载中提示 method: 'post', url: 'getPayStatus', withCredentials: true, timeout: 0, hideLoading: true, headers: { "Content-Type": "application/json; charset=UTF-8", "token": sessionStorage.getItem('token') }, data: { typeCode: val === 'wechat' ? 'WeChat' : 'ali', token: sessionStorage.getItem('token'), data: { order: params.order, } },}).then((res) => { if (res.payStatus == 0) { window.pollTimer = setTimeout(() => { return queryStatus(); //轮询查询支付状态3s }, 3000) }if ((res.payStatus == 2) || (res.payStatus == 1)) { //支付成功,关闭弹窗that.paySucceed = true; window.pollTimer && window.clearTimeout(window.pollTimer) //支付成功后干些事情。。。 setTimeout(() => { that.common.cancelAll(); that.resetPay(); }, 5000) }}) }that.post({ params,//参数 }) .then(res => { //获取支付链接和订单信息 params = params.data; params.order = res.order; window.delayTimer = null; window.clearTimeout(window.delayTimer); window.delayTimer = setTimeout(() => { //打开支付二维码 this.common.openQRcode(encodeURI(JSON.stringify(params)) ,encodeURI(res.url))}, 1000); queryStatus(); //开始轮询支付的状态 }); },resetPay () { this.paySucceed = false; window.pollTimer && window.clearTimeout(window.pollTimer); //清除计时器轮询状态 },

    推荐阅读