支付宝内置H5支付

最近开发一个功能,用户使用支付宝扫app商家的二维码跳指定的付款页面,然后进行付款。

整体流程是,首先设置生成二维码,使用UQRCode生成二维码,传入线上的链接,页面路径及页面上所需要展示的参数,封装二维码组件可参考另一篇文章 封装二维码组件

第一步:获取支付宝code

为了让用户无感知进行授权,我们需要使用支付宝的静默授权,使用url拼接,请求获取到code,url的的拼接参数

参数说明:

参数名 是否必须 长度 描述
app_id 16 开发者应用的app_id; 相同支付宝账号下,不同的app_id获取的token切忌混用。
scope 不定,取决于请求授权时scope个数 接口权限值,目前只支持auth_user(获取用户信息、网站支付宝登录)、auth_base(用户信息授权)、auth_ecard(商户会员卡)、auth_invoice_info(支付宝闪电开票)、auth_puc_charge(生活缴费)五个值;多个scope时用","分隔,如scope为"auth_user,auth_ecard"时,此时获取到的access_token,既可以用来获取用户信息,又可以给用户发送会员卡。
redirect_uri 100 授权回调地址,是经过URLENCODE转义 的url链接(url必须以http或者https开头); 在请求之前,开发者需要先到开发者中心对应应用内,配置授权回调地址。 redirect_uri与应用配置的授权回调地址域名部分必须一致。
state 100 商户自定义参数,用户授权后,重定向到redirect_uri时会原样回传给商户。 为防止CSRF攻击,建议开发者请求授权时传入state参数,该参数要做到既不可预测,又可以证明客户端和当前第三方网站的登录认证状态存在关联。

示例代码

js 复制代码
// 授权成功的回调地址
let hdurl = encodeURIComponent('...域名.../#/page_wallet/payuser/paymoney');
let appId = '2021004122656497';
window.location.href =`https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=${appId}&scope=auth_user&redirect_uri=${hdurl}`;

第二步:获取code 授权成功后,会返回到我们填写的回调地址的页面,code是以参数的形式返回的,我们可以直接在url取到code

第三步:请求接口,将所需的参数传给后端,拿到我们需要的数据,再监听事件,调起支付

接下来附上完整的代码: 个人的代码可能与大家的实际场景需求不一样,请根据需求修改。

我这段代码,页面就是一个付款页面,扫码后直接进入这个页面,回调里面填的也是这个页面 用到了一个名为 lzc-keyboard 的控件

之所以用了v-show,是因为授权的过程中会有一个跳转的过程,使用初始进入页面的时候,页面是空白的,当授权成功拿到code后,再进行展示

js 复制代码
<template>
  <view v-show="show">
    <view class="code-box">
      <view>
        <view style="font-weight: bold">{{ user ? user.name : '' }}</view>
        <view>付款给{{ user ? user.type : '' }}</view>
      </view>
      <view>
       <!--  <image :src="user ? user.avatar : ''"></image> -->
      </view>
    </view>
    <view class="je" :style="{ height: 'calc(100vh - ' + allHeight + 'px)' }">
      <view>金额</view>
      <view class="zhi">
        <view class="bs">¥</view>
        <view class="jes">
          {{ form.price }}
          <view class="blink">|</view>
        </view>
      </view>
    </view>
    <lzc-keyboard
      ref="lzckeyboard"
      :defaultValue="form.price"
      confirmText="付款"
      :confirmStyle="confirmStyle"
      @change="change"
      @confirm="confirm"
    ></lzc-keyboard>
  </view>
</template>

<script>
import lzcKeyboard from '@/components/lzc-keyboard/lzc-keyboard.vue';
import { payment_code } from '@/api/wallet';

export default {
  components: {
    lzcKeyboard
  },
   data() {
    return {
      show: true, // 控制是否显示内容
      allHeight: 0, // 高度
      user: {}, // 页面展示的信息
      // 请求的参数
      form: { price: '', type: 0, code: null, receiver_id: null },
      // 样式
      confirmStyle: {
        backgroundColor: '#FF1B36'
      },
      // 掉起支付所需要的数据,后端返回的
      paydata: {}
    };
  },
  // 设置下高度 不重要
  onReady() {
    let q = uni.createSelectorQuery();
    let headerHeight = 0;
    headerHeight = 200;
    let statusBarHeight = 0;
    uni.getSystemInfo({
      success: (e) => {
        statusBarHeight = e.windowBottom;
      }
    });
    setTimeout(() => {
      this.allHeight = statusBarHeight + headerHeight + 45;
    }, 100);
  },
  // 收起
  onShow() {
    uni.hideKeyboard();
  },
  
  onLoad(e) {
     // 首次扫码进入携带的参数是有id的,需要将这些存本地一下(目的是第二次进入的授权成功进入该页面时,这些信息会消失的)
    if(e.id){
      this.user = {
        name: e.name,
        id: e.id,
        type: e.tp
      };
      this.form.receiver_id = e.id;
      uni.setStorageSync('userpay', this.user);
    }else{
      // 第二次进入,从本地取出信息
      let data = uni.getStorageSync('userpay');
      this.user = {
        name: data.name,
        id: data.id,
        type: data.type
      };
      this.form.price = data.price;
      this.form.receiver_id = data.id;
      
      // 重点,第二次进入的时候,路径上已经携带了授权成功的code了
      this.form.code = this.getUrlParam('auth_code');
      this.$forceUpdate();
    }
    this.judgefacility();
  },
  methods:{
   // 授权方法
   handlAccredit(){
      let ua = window.navigator.userAgent.toLowerCase();
      // //判断是不是支付宝
      if (ua.match(/AlipayClient/i) == 'alipayclient') {
        // 如果当前code没有值的话,就去跳转去授权
        if (this.form.code == null || this.form.code === '') {
          let hdurl = encodeURIComponent(
            'http://zhyweb.first.xinzhidi.cn/#/page_wallet/payuser/paymoney'
          );
          let appId = '2021004122656497';
          window.location.href = `https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=${appId}&scope=auth_user&redirect_uri=${hdurl}`;
        } else {
          // 如果当前code有值了,那就将页面信息显示出来
          this.show = true;
        }
        // 这里是后端要求的支付宝传2
        this.form.type = 2;
      }
   },
   
   // 价格改变
   change(e) {
      if (e < 999999999) {
        this.$set(this.form,'price',e)
      }
      console.log('数字改变', e);
    },
    
   async confirm(e) {
       uni.showLoading({});
       // 请求接口
       uni.$u.http.post('/api...接口地址',this.form).then(res=>{
           uni.hideLoading();
           this.paydata = res.data.data;
           let that = this;
           // 如果是支付宝支付的话
            if (this.form.type == 2) {
              if (window.AlipayJSBridge) {
              that.alPay();
            } else {
              // 如果没有注入则监听注入的事件
              document.addEventListener('AlipayJSBridgeReady', that.alPay, false);
            }
          }
       }).catch((err) => {
          // 如果接口调用出错的话,将值重新写入,重新授权一次,因为可能存在code已经被使用的情况
          this.user.price = this.form.price;
          uni.setStorageSync('userpay', this.user);
          this.form.code = null;
          this.handlAccredit();
        });
   },
   alPay() {
      let that = this;
      // 调起支付,传入后端返回的订单号即可
      AlipayJSBridge.call(
        'tradePay',
        {
          tradeNO: that.paydata.tradeNO
        },
        function (result) {
          // 关闭当前h5页面
          window.AlipayJSBridge.call('closeWebview');
        }
      );
    },
   
    
  }
  
}
</script>

注意事项:我这个申请的是生活号,还有需要将回调的域名再控制台进行填写,不然跳转的时候可能会报找不到页面

代码因为是项目需求不同,所以可能和各位的对不上,可供参考部分逻辑,也可留言一起交流,谢谢!

相关推荐
lyc2333331 分钟前
鸿蒙IME Kit高级开发:共享沙箱与跨进程数据传输🚀
前端
lyc2333331 分钟前
鸿蒙UTD详解:标准化数据类型的跨端协作密钥🔑
前端
Hilaku2 分钟前
用好了 defineProps 才叫会用 Vue3,90% 的写法都错了
前端·javascript·vue.js
古夕2 分钟前
前端模块化与Webpack打包原理详解
前端·webpack
lyc2333332 分钟前
鸿蒙自定义编辑框:与输入法交互的3个核心步骤📝
前端
英宋4 分钟前
ckeditor5的研究 (2):对 CKEditor5 进行设计,并封装成一个可用的 vue 组件
前端·javascript
古夕4 分钟前
搞定滚动穿透
前端·javascript
英宋5 分钟前
ckeditor5的研究 (3):初步使用 CKEditor5 的 事件系统 和 API
前端·javascript
lyc23333310 分钟前
鸿蒙多子类型输入法:3步实现输入模式自由切换🔤
前端
Danta10 分钟前
从 0 开始学习 Three.js(2)😁
前端·javascript·three.js