本文介绍: app内前h5涉及到支付功能ios非实物商品实付需要使用ios原生支付方式,实物商品可以三方支付,主要的实现思路为后端返回跳转支付宝微信的支付scheme链接前端进行跳转支付,同时需要实时查询用户的支付状态。整个过程复杂部分在于查询用户支付状态体验方面,需要保证用户在支付成功、支付失败跳转支付宝微信回来或者没有跳转支付宝微信等未知的行为下的用户体验。为了防止用户在支付时间超过我们设置轮训时长情况,需要监听用户从支付app返回当前页面,来进行查询支付状态操作

一、功能梳理

app内前h5涉及到支付的功能,ios非实物商品实付需要使用ios原生支付方式,实物商品可以三方支付,主要的实现思路为后端返回跳转支付宝或微信的支付scheme链接,前端进行跳转支付,同时需要实时查询用户的支付状态

整个过程复杂部分在于查询用户支付状态体验方面,需要保证用户在支付成功、支付失败、跳转支付宝、微信回来或者没有跳转支付宝微信等未知的行为下的用户体验

组件内容底部升起的支付选择弹窗可以选择支付宝或者微信

二、实现步骤

  1. 用户进行下单操作,前端调用下单接口,成功则返回三方支付app跳转链接,前端进行跳转

  1. 跳转三方app同时进行查询订单接口轮训,实时获取订单状态,轮训时间定位30s,依据需求调整

  1. 用户如果支付时间超过了30s返回我们app的情况下,需要针对此种情况进行处理捕捉用户返回我们app的情况

三、组件可支配参数&事件设置

设置支持参数2个、事件4个,分别为

参数

successStatus: {
  default: '1'
}, // 支付成功的状态码,默认1
errorStatus: {
  default: '2'
} // 支付失败状态码,默认2

事件

@payMoney="payMoney" // 下单事件
@payStatus="payStatus" //查询支付状态事件
@succcessFunction="succcessFunction" // 成功支付操作
@errorFunction="errorFunction" // 失败实付操作

四、从支付app返回事件捕获方法

为了防止用户在支付时间超过我们设置轮训时长情况,需要监听用户从支付app返回当前页面,来进行查询支付状态操作。方法为监听页面显示or隐藏事件

reloadState () {
  // 添加监听器
  if (typeof document.hidden !== 'undefined') {
    this.hidden = 'hidden';
    this.visibilityChange = 'visibilitychange';
  } else if (typeof document.mozHidden !== 'undefined') {
    this.hidden = 'mozHidden';
    this.visibilityChange = 'mozvisibilitychange';
  } else if (typeof document.msHidden !== 'undefined') {
    this.hidden = 'msHidden';
    this.visibilityChange = 'msvisibilitychange';
  } else if (typeof document.webkitHidden !== 'undefined') {
    this.hidden = 'webkitHidden';
    this.visibilityChange = 'webkitvisibilitychange';
  }
  document.addEventListener(this.visibilityChange, this.forceUpdate);
},
forceUpdate () {
  if (document.visibilityChange === this.hidden) {
  } else {
    this.searchTimer();
  }
},

五、组件源码

<template>
    <div class="pay-info">
        <div class="pay-content">
            <span class="pay-left"><img class="pay-icon" src="../assets/zfb.png" alt=""> 支付宝支付</span>
            <img class="radio-icon" src="../assets/radio2.svg" alt="">
        </div>
        <div class="pay-content">
            <span class="pay-left"><img class="pay-icon" src="../assets/wx.png" alt=""> 微信支付</span>
            <img class="radio-icon" src="../assets/radio2.svg" alt="">
        </div>
        <div class="pay-button" @click="payFun"><span>支付</span></div>
        <div class="loading-dom" v-if="loadingPay">
          支付中
          <van-loading color="#ffffff" style="margin-left: 5px"/> 
        </div>
    </div>
</template>

<script type="text/javascript">
export default {
  data () {
    return {
      isApp: !!browers.appUA,
      timer: null,
      loadingPay: false,
      orderNo: '', // 订单号
      payStatus: '' // 订单支付状态
    };
  },
  props: {
    successStatus: {
      default: '1'
    }, // 支付成功的状态码,默认1
    errorStatus: {
      default: '2'
    } // 支付失败的状态码,默认2
  },
  mounted () {
    this.$once('hook:beforeDestroy', () => {
      clearInterval(this.timer);
      this.timer = null;
    });
  },
  methods: {
    reloadState () {
      // 添加监听器
      if (typeof document.hidden !== 'undefined') {
        this.hidden = 'hidden';
        this.visibilityChange = 'visibilitychange';
      } else if (typeof document.mozHidden !== 'undefined') {
        this.hidden = 'mozHidden';
        this.visibilityChange = 'mozvisibilitychange';
      } else if (typeof document.msHidden !== 'undefined') {
        this.hidden = 'msHidden';
        this.visibilityChange = 'msvisibilitychange';
      } else if (typeof document.webkitHidden !== 'undefined') {
        this.hidden = 'webkitHidden';
        this.visibilityChange = 'webkitvisibilitychange';
      }
      document.addEventListener(this.visibilityChange, this.forceUpdate);
    },
    forceUpdate () {
      if (document.visibilityChange === this.hidden) {
      } else {
        this.searchTimer();
      }
    },
    payFun () {
      this.$emit('payMoney', (res) => {
        this.reloadState();
        // 下单接口回调执行轮训结果
        this.orderNo = res.order_no;
        this.loadingPay = true;
        this.searchPay();// 监听从其他app返回,为了解决从支付宝回来不轮训的问题
        setTimeout(() => {
          location.href = res.pay_address;
        }, 200);
      });
    },
    searchPay () {
      this.$emit('payStatus', (res) => {
        if (this.payStatus === '') {
          this.searchTimer();
        }
        // 下单接口回调执行轮训结果
        this.payStatus = res;
      });
    },
    searchTimer() {
      if (this.timer) {
        return;
      }
      if (this.orderNo) {
        let times = 0;
        this.searchPay();
        if (this.payStatus === '') {
          this.timer = setInterval(res => {
            times++;
            this.searchPay();
            if (this.payStatus === this.$props.successStatus) {
              clearInterval(this.timer);
              this.timer = null;
              this.loadingPay = false;
              document.removeEventListener(this.visibilityChange, this.forceUpdate);
              // 支付成功事件
              this.$emit('succcessFunction', (res) => {
              });
            }
            if (this.payStatus === this.$props.errorStatus) {
              clearInterval(this.timer);
              this.timer = null;
              this.loadingPay = false;
              document.removeEventListener(this.visibilityChange, this.forceUpdate);
              // 支付失败事件
              this.$emit('errorFunction', (res) => {
              });
            }
            if (times > 30) {
              this.$toast('未查询到支付状态,请重新支付');
              clearInterval(this.timer);
              this.timer = null;
              this.loadingPay = false;
              document.removeEventListener(this.visibilityChange, this.forceUpdate);
            }
          }, 1000);
        }
      }
    }
  }
};
</script>

<style lang="less" scoped>
.pay-info {
    .pay-content {
        background: #fff;
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 8px 0;
        font-size: 28px;
        color: #222;
        .pay-left {
            display: flex;
            align-items: center;
        }
        .pay-icon {
            width: 60px;
            height: 60px;
            margin-right: 10px
        }
        .radio-icon {
            width: 34px;
            height: 34px;
        }
    }
    .pay-button {
        width: 100%;
        text-align: center;
        margin-top: 30px;
        span {
            display: inline-block;
            background: #4e88f6;
            color: #fff;
            width: 100%;
            font-size: 32px;
            height: 88px;
            line-height: 88px;
            border-radius: 50px;
            display: inline-block;
        }
    }
    .loading-dom {
      width: 100%;
      height: 100vh;
      background: rgba(0,0,0,.5);
      color: #fff;
      text-align: center;
      font-size: 34px;
      font-weight: 500;
      position: fixed;
      display: flex;
      align-items: center;
      justify-content: center;
      top: 0;
      left: 0
    }
}
</style>

六、父组件调用

<Pay 
    @payMoney="payMoney"
    @payStatus="payStatus"
    @succcessFunction="succcessFunction"
    @errorFunction="errorFunction"
    :success-status='1'
    :error-status='2'
></Pay>
// 下单事件
    payMoney (callback) {
      this.$axios.post(`url`, params).then((res) => {
        let data = res.data;
        if (Number(data.code) === 0) {
            // 执行支付操作,跳转url结果回调给收银台组件
          this.currentOrder = data.data.order_no;
          callback(data.data);
        } else {
          this.$toast(data.message);
        }
      }).catch((e) => {
      });
    },
    // 轮训状态接口
    payStatus (callback) {
      this.$axios.get(`url`).then((res) => {
        let data = res.data;
        if (Number(data.code) === 0) {
            // 执行支付结果查询,结果回调给收银台组件
          callback(data.data.pay_result);
          if (data.data.list &amp;&amp; data.data.list.length) {
            this.resultData = data.data.list;
          }
        } else {
          this.$toast(data.message);
        }
      }).catch((e) => {
      });
    },
    succcessFunction () {
      // 支付成功父组件操作事件
      this.$toast('支付成功');
      // 先弹出支付成功提示延时1秒出结果弹窗
      setTimeout(() => {
        // 支付成功后刷新一下接口
      }, 1000);
    },
    errorFunction () {
      // 支付失败父组件操作事件
      this.$toast('支付失败,请重新发起支付');
    },

原文地址:https://blog.csdn.net/qq_38068508/article/details/129621317

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任

如若转载,请注明出处:http://www.7code.cn/show_33628.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注