Vue项目中常见问题(56)微信支付业务的实现

目录

gitee仓库地址:https://gitee.com/CMD-UROOT/sph-project/commits/master

前言:

 业务需求1:实现二维码

 1.安装qrcode

 2.引入qrcode

 3.使用qrcode

 4.二维码放入结构中

 5.扫码支付业务

  查询支付订单状态接口

  5.1写接口api

 长轮询 和短轮询是什么?

 5.2二维码展示出来需要做一件事长轮询

 5.3支付成功与失败的判断

 5.4paysuccess静态组件搭建

 5.5paysuccess路由组件注册引入

 5.6 问题出现

完整代码:


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)
        }
      }

注意上面完整代码中新增的代码,我截图放下面了

这个时候我们点击支付遇到问题:

不付款 点击已支付成功,不会有任何反应

付款后 点击已支付成功,会跳转到支付成功的页面:

 还有一点就是我们可以不用支付,点击已支付成功跳转到支付成功的页面

开发人员:为了自己方便,这里的判断先不要了

到此微信支付功能就实现了

猜你喜欢

转载自blog.csdn.net/qq_46368050/article/details/124964457#comments_21978407