目录
gitee仓库地址:https://gitee.com/CMD-UROOT/sph-project/commits/master
gitee仓库地址:https://gitee.com/CMD-UROOT/sph-project/commits/master
大家根据上传历史进行查找你需要的代码
前言:
上一篇文章我们利用ElementUI已经实现了点击立即支付按钮,弹出弹出框的操作
业务需求1:实现二维码
我们需要在弹出框中生成一个二维码,市场上有许多插件,是可以生成二维码的
我们打开这个网址 npm
搜索qrcode 或者直接打开这个网址: qrcode - npm
1.安装qrcode
npm i qrcode --save
2.引入qrcode
在pages/Pay/index.vue中:引入qrcode
也就是我们需要使用qrcode的组件中去引用
3.使用qrcode
我们知道在我们的项目中
支付页面的数据中有一个payInfo里面有一个codeUrl数据是字符串,我们要利用这个字符串来生成二维码
在pages/Pay/index.vue中:
打印:点击立即支付控制台弹出二维码地址
点进地址:就是一个二维码了
4.二维码放入结构中
二维码需要在弹出框的中间进行展示
所以:
在pages/Pay/index.vue中:
5.扫码支付业务
扫码支付可能成功,也可能失败,如果成功需要跳转路由,如果失败需要提示支付失败,支付成功与失败,是后台返回的,所以我们需要发请求
那么需要发多少次请求呢,因为支付是用户行为,我们将来得向服务器问,用户支付成功还是失败,我们需要一直问
也就是说当弹出框弹出来的时候,就需要一直向后台询问,用户支付的情况
查询支付订单状态接口
请求地址:/api/payment/weixin/queryPayStatus/{orderId}
请求方式:get
参数:orderId
5.1写接口api
在api/index.js中:
知识点
长轮询 和短轮询是什么?
长轮询:
http 长轮询是服务器收到请求后如果有数据, 立刻响应请求; 如果没有数据就会 hold 一段时间,这段时间内如果有数据立刻响应请求; 如果时间到了还没有数据, 则响应 http 请求;浏览器受到 http 响应后立在发送一个同样http 请求查询是否有数据;
短轮询
http端轮询是服务器收到请求不管是否有数据都直接响应 http 请求; 浏览器受到 http 响应隔一段时间在发送同样的http 请求查询是否有数据;
两者相同点:
可以看出 http 长轮询和 http 短轮询的都会 hold 一段时间;两者不同点
间隔发生在服务端还是浏览器端: http 长轮询在服务端会 hold 一段时间, http 短轮询在浏览器端 “hold”一段时间;
5.2二维码展示出来需要做一件事长轮询
也就是说当弹出框弹出来的时候,就需要一直向后台询问,用户支付的情况
(有的人肯定会说,为什么不用户支付后点击确认这个点来判断用户是否支付成功,非要用什么长轮询,一直询问后台,那么麻烦,那你得思考一个问题,万一用户支付完了断网了,用户还需要重新支付一次再点击确定吗?)
在pages/Pay/index.vue中:定义一个timer
测试:
当我们点击立即支付按钮的时候,只要一弹出弹出框,就会一直向服务器发请求,我们这里利用的是定时器来控制发请求
如果我们扫描支付了,就会看到控制台出现:
5.3支付成功与失败的判断
如果支付成功,我们需要隐藏支付的弹出框,清除定时器 ,存储code为200,跳转路由
存储code是为了,验证用户是否支付成功,支付成功code为200,这个时候用户再点击已支付成功按钮,才能跳转到支付成功的页面
在pages/Pay/index.vue中:
完整代码:
// 弹出框
async open(){
//生成二维码(地址)
let url = await QRCode.toDataURL(this.payInfo.codeUrl)
// console.log(url)
this.$alert(`<img src=${url} />`, '请微信支付', {
dangerouslyUseHTMLString: true, //是否将 message 属性作为 HTML 片段处理
center:true, //是否居中布局
showCancelButton:true, //是否显示取消按钮
cancelButtonText:"支付遇见问题",//取消按钮的文本内容
confirmButtonText:"已支付成功",//支付按钮的文本内容
showClose:true,//右上角的叉子没了
});
//你需要知道支付成功|失败
//支付成功,路由跳转,如果支付失败,提示信息
//定时器没有,开启一个新的定时器
if(!this.timer){
this.timer = setInterval(async()=>{
//发请求获取用户支付状态
let result = await this.$API.reqPayStatus(this.orderId)
// console.log(result)
//如果code==200
if(result.code==200){
//第一步:清除定时器
clearInterval(this.timer)
this.timer = null
//保存支付成功返回的code
this.code = result.code
//关闭弹出框
this.$msgbox.close()
//跳转到下一路由
this.$router.push('/paysuccess')
}
},1000)
}
}
但是跳转下一路由我们这里还没写,我们这里写一下:
5.4paysuccess静态组件搭建
在pages文件下新建PaySuccess文件,里面在创建一个index.vue
pages/PaySucess/index.vue里面的完整代码:
<template>
<div class="paysuccess">
<div class="success">
<h3>
<img src="./images/right.png" width="48" height="48">
恭喜您,支付成功啦!
</h3>
<div class="paydetail">
<p class="button">
<router-link class="btn-look" to="/center">查看订单</router-link>
<router-link class="btn-goshop" to="/">继续购物</router-link>
</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'PaySuccess',
}
</script>
<style lang="less" scoped>
.paysuccess {
margin: 20px auto;
padding: 25px;
border: 1px solid rgb(211, 211, 211);
width: 1200px;
width: 1148px;
.success {
width: 500px;
margin: 0 auto;
h3 {
margin: 20px 0;
font-weight: 700;
font-size: 20px;
line-height: 30px;
img {
max-width: 100%;
vertical-align: middle;
border: 0;
margin-right: 14px;
}
}
.paydetail {
margin-left: 66px;
font-size: 15px;
.button {
margin: 30px 0;
line-height: 26px;
a {
display: inline-block;
box-sizing: border-box;
text-align: center;
vertical-align: middle;
cursor: pointer;
border-radius: 2px;
user-select: none;
font-size: 18px;
padding: 4px 20px;
line-height: 22px;
text-decoration: none;
&.btn-look {
margin-right: 13px;
color: #fff;
background-color: #e1251b;
border: 1px solid #e1251b;
}
&.btn-goshop {
color: #666;
background-color: #eee;
border: 1px solid #e1e1e1;
}
}
}
}
}
}
</style>
5.5paysuccess路由组件注册引入
测试一下:没问题,可以使用
5.6 问题出现
出现这个页面的时候,我们并没有支付的情况下,我们点击已支付成功, 弹出框也会消失,正常业务逻辑是要支付以后点击已支付成功,弹出框才会消失的
比如用户真的支付成功了,应该跳转到支付成功的页面
用户假的支付成功了,应该弹出一个让用户继续支付
用户点击支付遇见问题,应该弹一个联系管理员之类的
ElementUI官网:Element - The world's most popular Vue UI framework
这个时候我们利用ElementUI官网的MessageBox里面的beforeClose来解决这个问题,
因为上面提到的三种情况,都是在MessageBox关闭前执行的,所以这个方法,就是在关闭之前在帮你执行一些事情
在pages/Pay/index.vue中:
写上这个回调后,我们再点击支付遇见问题,和已支付成功,就不会关闭了,他要等待我们把里面的函数处理完了,才会进行下一步操作
但是问题来了,我们怎么知道我们点击的按钮是谁,我们得区分按钮
ElementUI那张图已经说的很清楚了
测试:
第一个参数是可以用户区分是哪个按钮
第二个参数:当前组件实例
第三个参数:关闭弹出框的方法
我们可以调用这个done(),可以让我们点击已支付成功和支付遇到问题的时候,关闭弹出框
完整代码:
// 弹出框
async open(){
//生成二维码(地址)
let url = await QRCode.toDataURL(this.payInfo.codeUrl)
// console.log(url)
this.$alert(`<img src=${url} />`, '请微信支付', {
dangerouslyUseHTMLString: true, //是否将 message 属性作为 HTML 片段处理
center:true, //是否居中布局
showCancelButton:true, //是否显示取消按钮
cancelButtonText:"支付遇见问题",//取消按钮的文本内容
confirmButtonText:"已支付成功",//支付按钮的文本内容
showClose:false,//右上角的叉子没了
//关闭弹出框的配置值
beforeClose:(type,instance,done)=>{
// console.log(type,instance,done)
//type:区分取消|确定按钮
//instance:当前组件实例
//done:关闭弹出框的方法
if(type=='cancel'){
alert('请联系管理员华哥')
//清除定时器
clearInterval(this.timer)
this.timer = null
//关闭弹出框
done()
}else{
//判断是否真的支付了
if(this.code==200){
clearInterval(this.timer)
this.timer = null
done()
//跳转到下一路由
this.$router.push('/paysuccess')
}
}
}
});
//你需要知道支付成功|失败
//支付成功,路由跳转,如果支付失败,提示信息
//定时器没有,开启一个新的定时器
if(!this.timer){
this.timer = setInterval(async()=>{
//发请求获取用户支付状态
let result = await this.$API.reqPayStatus(this.orderId)
// console.log(result)
//如果code==200
if(result.code==200){
//第一步:清除定时器
clearInterval(this.timer)
this.timer = null
//保存支付成功返回的code
this.code = result.code
//关闭弹出框
this.$msgbox.close()
//跳转到下一路由
this.$router.push('/paysuccess')
}
},1000)
}
}
注意上面完整代码中新增的代码,我截图放下面了
这个时候我们点击支付遇到问题:
不付款 点击已支付成功,不会有任何反应
付款后 点击已支付成功,会跳转到支付成功的页面:
还有一点就是我们可以不用支付,点击已支付成功跳转到支付成功的页面
开发人员:为了自己方便,这里的判断先不要了
到此微信支付功能就实现了