This is the 7th day of my participation in the August More Text Challenge.

Demand background

The market report list shows two types of reports, one free and the other paid. Free reports can be viewed directly by users, while paid reports can only be viewed after users purchase them.

Thought analysis

  1. Click to view the payment report, the payment QR code pops up.
  2. The order is created, and the TWO-DIMENSIONAL code counts down. After 5 seconds of display, it starts to monitor the payment callback result, and the frequency is 5 seconds.
  3. The first countdown to 0 seconds, remind the qr code expired so that users click to refresh the QR code.
  4. Continue the countdown and start listening for payment callback results.
  5. If the result is not monitored in 0 seconds after refreshing, close the payment popup and let the user initiate payment again.

The UI display

The payment popup does not expire for a long time

Paying for popover expiration time looks like this

Begin to use

The payment function is a common feature of the project, so we package a component separately so that it can be introduced as a sub-component when used by other modules.

Write a payment component template

Below is the template specific source, because the style is not the focus of our consideration, so we will not show the style of the code, according to the need to add ha.

<template> <div> <el-dialog class="dialog-pay" title="" :visible.sync="dialogVisible" :show-close="false" @close="handleClosePay" > <div class="content"> <p class="tip">{{pay.title}}</p> <p class="tip"> <span class="small"> <span class="large">{{pay.money}}</span> </p> <img class=" PIC ":style="{opacity: opacity: opacity: opacity: opacity: opacity: opacity: opacity: opacity: opacity: opacity: opacity: opacity: opacity: opacity: opacity; btnDisabled ? SRC ="pay.url" /> <el-button class=" BTN ":class="btnDisabled? 'disabled' : ''" type="primary" :disabled="btnDisabled" @click="handleRefreshCode" >{{ btnText }}</el-button > </div> </el-dialog> </div> </template>Copy the code

JS related code and description of payment component

1. Monitor whether the payment popup is displayed

The child component receives values from the parent component in the child component via the props property. Use watch to listen on pay.show, and only display the payment popup when it is true, and execute the method to listen on the payment result after 5 seconds.

watch: {
    'pay.show': {
      handler(val) {
        if (val) {
          this.dialogVisible = this.pay.show
          setTimeout(this.handleReportPayNotify(), 5000)
        }
      },
      immediate: true
    }
},
Copy the code

2. The qr code starts counting down

The qr code starts to countdown for 60 seconds. When it reaches 0 seconds, click refresh to obtain the QR code again and continue the countdown. At this time, if it reaches 0 seconds, the payment popup window will close, prompting the user to wait too long, and please initiate payment again.

handleCountDown() { if (this.second == 1) { if (this.refresh) { this.second = 60 this.btnDisabled = false this.btnText = If (this.timer) {clearInterval(this.timer)}} else {this.$emit('closePay', {type: 'fail'}) clearInterval(this.timer) this.$message. Warning (' Waiting time is too long, Please re-initiate payment ')}} else {this.second -- this.btnDisabled = true this.btnText = '${this.second} seconds remaining before the qr code expires' this.downTimer =' setTimeout(() => { this.handleCountDown() }, 1000) } },Copy the code

3. The monitor payment popup closes

handleClosePay() { if (this.timer) { clearInterval(this.timer) } if (this.downTimer) { clearTimeout(this.downTimer) } $emit('closePay', {type: 'fail'}) this.$message. Warning (' you have cancelled payment ')},Copy the code

4. Listen for payment callback results

There are two callback results. If the listening succeeds within the normal range, the FN transmitted by the parent component will be executed and the timer will be cleared. If no corresponding result is obtained when the number of times monitored is 12, the payment popup window will be closed and the user will be reminded that the waiting time is too long. Please initiate payment again and clear the timer.

handleReportPayNotify() { let num = 0 this.timer = setInterval(() => { num++ this.pay.fn().then(res => { if (res.status == 111111) { this.$emit('closePay', { type: 'success' }) clearInterval(this.timer) } }) if (num == 12) { this.$emit('closePay', { type: 'fail'}) clearInterval(this.timer) this.$message. Warning (' Wait too long, please reinitiate payment ')}}, 5000)}Copy the code

5. Clear timer when payment component is destroyed

This step is easy to ignore, but it is also necessary to remove the timer when the component is destroyed.

  beforeDestroy() {
    if (this.timer) {
      clearInterval(this.timer)
    }
    if (this.downTimer) {
      clearTimeout(this.downTimer)
    }
  }
}

Copy the code

Attached: component JS complete source code

<script> export default { name: 'WechatPay', props: { pay: Object }, data() { return { dialogVisible: false, btnDisabled: true, btnText: '', second: 60, timer: null, refresh: true } }, watch: { 'pay.show': { handler(val) { if (val) { this.dialogVisible = this.pay.show setTimeout(this.handleReportPayNotify(), 5000) } }, immediate: true } }, mounted() { this.handleCountDown() }, methods: { /** * @descripttion: Refresh the qr code * / handleRefreshCode () {this. $bus. $emit (' refreshCode) enclosing handleCountDown () enclosing handleReportPayNotify () this.refresh = false }, /** * @descripttion: */ handleCountDown() {if (this.second == 1) {if (this.refresh) {this.second = 60 this.btnDisabled = false If (this.timer) {clearInterval(this.timer)}} else {this.$emit('closePay', {type: 'fail'}) clearInterval(this.timer) this.$message. Warning (' Waiting time is too long, Please re-initiate payment ')}} else {this.second -- this.btnDisabled = true this.btnText = '${this.second} seconds remaining before the qr code expires' this.downTimer =' setTimeout(() => { this.handleCountDown() }, 1000) } }, /** * @descripttion: */ handleClosePay() {if (this.timer) {clearInterval(this.timer)} if (this.downtimer) { clearTimeout(this.downTimer) } this.$emit('closePay', { type: 'fail'}) this.$message. Warning (' you have cancelled payment ')}, /** * @descripttion: */ handleReportPayNotify() {let num = 0 this.timer = setInterval(() => {num++ this.pay.fn().then(res => {if (res.status == 111111) { this.$emit('closePay', { type: 'success' }) clearInterval(this.timer) } }) if (num == 12) { this.$emit('closePay', { type: 'fail'}) clearInterval(this.timer) this.$message. Warning (' Waiting time is too long, Please re-initiate payment ')}}, 5000)}}, beforeDestroy() { if (this.timer) { clearInterval(this.timer) } if (this.downTimer) { clearTimeout(this.downTimer) } } }  </script>Copy the code