Implementation example of scan code payment in vue project (with demo)

Implementation example of scan code payment in vue project (with demo)

Demand background

There are two types of reports displayed in the market report list, one is free report and the other is paid report. Users can view free reports directly, while paid reports can only be viewed after users purchase them.

Thought Analysis

  • Click to view the paid report and a payment QR code will pop up.
  • Create an order, and the QR code will count down. After 5 seconds of display, it will start monitoring the payment callback result, with a frequency of once every five seconds.
  • The first countdown reaches 0 seconds, reminding the user that the QR code has expired and asking the user to click to refresh the QR code.
  • Continue the countdown and start monitoring payment callback results.
  • After refreshing, if the countdown reaches 0 seconds and no result is heard, the payment pop-up window will be closed to allow the user to re-initiate payment.

UI Display

The payment pop-up window looks like this if it has not expired.

The payment pop-up window expires like this

Get Started

The payment function is a public function of the project, so we encapsulate it in a separate component so that other modules can introduce it as a subcomponent when using it.

1. Write a payment component template

Below is the specific source code of the template. Since the style is not the focus of our consideration, the style code will not be displayed. You can add it as needed.

<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">
          Payment amount: <span class="small">¥</span
          ><span class="large">{{ pay.money }}</span>
        </p>
        <img
          class="pic"
          :style="{ opacity: btnDisabled ? 1 : 0.3 }"
          :src="pay.url"
        />
        <el-button
          class="btn"
          :class="btnDisabled ? 'disabled' : ''"
          type="primary"
          :disabled="btnDisabled"
          @click="handleRefreshCode"
          >{{ btnText }}</el-button
        >
      </div>
    </el-dialog>
  </div>
</template>

2. JS code and description of payment component

1. Monitor whether the payment pop-up window is displayed in the child component through the props attribute, and receive the value passed from the parent component in the child component. Use watch to monitor pay.show. The payment pop-up window will be displayed only when it is true, and the method of monitoring payment results will be executed after 5 seconds of display.

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

2. The QR code starts counting down. The QR code starts a 60-second countdown. When it reaches 0 second, click Refresh to get the QR code again and the countdown will continue. At this time, if it reaches 0 second, the payment pop-up window will be closed, and the user will be prompted to wait too long and please re-initiate payment.

handleCountDown() {
  if (this.second == 1) {
    if (this.refresh) {
      this.second = 60
      this.btnDisabled = false
      this.btnText = 'Click refresh to get the QR code again'
      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 left until the QR code expires`
    this.downTimer = setTimeout(() => {
      this.handleCountDown()
    }, 1000)
  }
},

3. Close the monitoring payment pop-up window

handleClosePay() {
  if (this.timer) {
    clearInterval(this.timer)
  }
  if (this.downTimer) {
    clearTimeout(this.downTimer)
  }
  this.$emit('closePay', { type: 'fail' })
  this.$message.warning('You have canceled payment')
},

4. There are two types of callback results for monitoring payment. If the monitoring is successful within the normal range, the fn passed by the parent component will be executed and the timer will be cleared. If the corresponding result is not obtained when the number of monitoring times reaches 12, the payment pop-up window will be closed, prompting the user that the waiting time is too long, please re-initiate payment, 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('Waiting time is too long, please re-initiate payment')
        }
      }, 5000)
    }

5. Clear the timer when the payment component is destroyed. This step is easy to overlook but needs to be done. Clear the timer in time when the component is destroyed.

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

Attachment: Complete source code of component JS

<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 QR code*/
    handleRefreshCode() {
      this.$bus.$emit('refreshCode')
      this.handleCountDown()
      this.handleReportPayNotify()
      this.refresh = false
    },
    /**
     * @descripttion: QR code countdown*/
    handleCountDown() {
      if (this.second == 1) {
        if (this.refresh) {
          this.second = 60
          this.btnDisabled = false
          this.btnText = 'Click refresh to get the QR code again'
          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 left until the QR code expires`
        this.downTimer = setTimeout(() => {
          this.handleCountDown()
        }, 1000)
      }
    },
    /**
     * @descripttion: listen for payment pop-up window closing*/
    handleClosePay() {
      if (this.timer) {
        clearInterval(this.timer)
      }
      if (this.downTimer) {
        clearTimeout(this.downTimer)
      }
      this.$emit('closePay', { type: 'fail' })
      this.$message.warning('You have canceled payment')
    },
    /**
     * @descripttion: monitor payment callback results*/
    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>

This concludes this article about the implementation example of QR code payment in the Vue project (with demo). For more relevant Vue QR code payment content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope you will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • Summary of using WeChat official account payment in vue project and the pitfalls encountered
  • Pitfalls encountered in implementing WeChat payment function in Vue
  • Vue imitates Alipay payment function
  • Vue.js WeChat payment front-end code sharing
  • How to get WeChat payment code in Vue and solve the problem of code being occupied
  • Payment function implementation in vue project (WeChat payment and Alipay payment)

<<:  Example analysis of mysql variable usage [system variables, user variables]

>>:  How to quickly build your own server detailed tutorial (Java environment)

Recommend

Simple web page code used in NetEase blog

How to use the code in NetEase Blog: First log in...

VMWare15 installs Mac OS system (graphic tutorial)

Installation Environment WIN10 VMware Workstation...

JavaScript article will show you how to play with web forms

1. Introduction Earlier we introduced the rapid d...

How to decrypt Linux version information

Displaying and interpreting information about you...

Detailed configuration of Nginx supporting both Http and Https

It is almost a standard feature for websites nowa...

MySQL optimization solution: enable slow query log

Table of contents Preface Setting up slow query l...

The difference and choice between datetime and timestamp in MySQL

Table of contents 1 Difference 1.1 Space Occupanc...

Tutorial on resetting the root password of Mac MySQL

Disclaimer: This password reset method can direct...

vue.js downloads pictures according to picture url

Recently, when I was working on a front-end vue.j...

9 ways to show and hide CSS elements

In web page production, displaying and hiding ele...

Small details of web front-end development

1 The select tag must be closed <select><...

Vue-Router installation process and principle detailed

Table of contents 1. Front-end routing implementa...

Detailed explanation of the process of using docker to build minio and java sdk

Table of contents 1minio is simple 2 Docker build...