微信h5、native、jsapi支付

835 阅读1分钟

一、微信h5支付(h5中使用)

/** 参考代码 
    1、流程
        微信h5支付调用接口得到一个支付地址,跳转调起支付 
    2、this.queryParams参数说明 
    this.queryParams={ 
        transitionId: 订单号,
        successCbPage: 支付成功回调地址(在微信成功页面时,用户点击【返回商家】跳转的页面)
        // successCbPage => 根据实际情况而定,若是始终跳转一个地址,直接由后端写死也可。
        // 不过还是建议传入,这样有两个好处:1、前端根据需要自由调整地址 2、当不同订单跳转不同页面也兼容 
    };
*/

private async comfirmPayment() {
    this.confirmPayBtnLoading = true;
        let res = await wechatH5Api(this.queryParams);
        let jumpUrl = res.resp_data.url;
        window.location.replace(jumpUrl);
    }catch(e) {
        throw e;
    }finally {
        this.confirmPayBtnLoading = false;
    }
  }
}

二、微信native支付(pc网站中使用)

vue-qr: 将地址生成二维码的第三方组件

<!-- 弹框展示支付二维码 -->
<template>
    <el-dialog
        width="300px"
        top="20vh"
        :visible.sync="wechatPayDialogVisible"
        :modal-append-to-body="false"
        :close-on-click-modal="false"
   >
        <h4 slot="title" class="text-center">微信支付</h4>
        <div>
          <vue-qr :text="wechatPayHref" :size="250" style="margin: 0 auto;display: block;"/>
        </div>
        <div class="order-number text-center">订单号: {{ orderInfo.outTradeNo }}</div>
     </el-dialog>
</template>
/** 参考代码 
    1、流程
        微信native支付调用接口得到一个二维码,使用vue-qr再弹框上展示二维码,用户使用微信扫码支付
    2、this.queryParams参数说明 
    this.queryParams={ 
        transitionId: 订单号
    };
    3、this.isPaySuccess()函数说明
        微信native支付没有支付成功回调地址,所以前端只能采用轮询: 每隔?s就查询订单状态,当订单支付成功时,关闭二维码弹框,并跳转到支付成功页面
*/
private async comfirmPayment() {
    this.confirmPayBtnLoading = true;
    try{
        let res = await wechatPayNativeApi(this.queryParams);
        this.wechatPayHref = res.resp_data.codeURL;
        this.wechatPayDialogVisible = true;

        await this.$nextTick();
        /**定时器不断查询订单支付结果,当订单支付成功后,关闭二维码对话框*/
        this.isPaySuccess();
    }catch(e) {
        throw e;
    }finally {
        this.confirmPayBtnLoading = false;
    }
}
private async isPaySuccess() {// 轮询查询订单状态
    await setTimeout(async() => {
      let res = await getOrderInfoApi(this.queryParams);
      let payState = res.resp_data.list.state as string;
      if(payState == 'SUCCESS') {//当订单状态等于 SUCCESS
        // 关闭微信Native二维码
        this.wechatPayDialogVisible = false;
        await this.$nextTick();
        
        // 跳转至聚合支付成功页面
        await this.$router.replace({
          path: '/payment-result/aggregate-pay',
          query: { transactionId: this.queryParams.transactionId as any}
        })
      }else {
        this.isPaySuccess();//递归查询订单状态
      }
    }, queryOrderTime)
  }

三、微信jsapi支付(微信公众号中使用)

step1|✨ 获取code 请参考

let queryString = require('query-string');

async created() {// vue created生命周期
    let queryObj = queryString.parse(location.href.split('?')[1]);

    if(queryObj.code) {
      // alert(queryObj.code + '-' + queryObj.state);
      this.wechatJsapiParams = {
        code: queryObj.code,
        transactionId: Number(queryObj.state) // state属性是【静默授权: 获取code】传递的订单号
      }
      //获取订单信息
      this.getMobileOrderInfo(Number(queryObj.state));
    }else{
      // 注意:我这个项目是多商户的,所以需要通过订单号去获取不同商户的appid。如果应用只有一个商户,直接写死appid即可,不需要这一步
      let res = await getAppIdApi({transactionId: Number(queryObj.transactionId)});
      // 静默授权: 获取code
      window.location.href = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + res.resp_data.appid + '&redirect_uri=' + encodeURIComponent(process.env.VUE_APP_JSAPI_REDIRECT_HREF as string )  + '&response_type=code&scope=snsapi_base&state=' + queryObj.transactionId +'#wechat_redirect';
    } 
  }

step2|✨调起支付 请参考

import { jsapiEntrance } from './utils/jsapi';

private async comfirmPayment() {
    this.confirmPayBtnLoading = true;
    try{
        // 封装调起jsapi支付
        await jsapiEntrance(this.wechatJsapiParams);
    }catch(e) {
        throw e;
    }finally {
        this.confirmPayBtnLoading = false;
    }
}

@/utils/jsapi

/**
 * jsapi支付入口
*/
export let jsapiEntrance = async (wechatJsapiParams: IWechatJsapiParams) => {

  /**1、发送请求(携带code与transactionId),获得jsapi调起支付所需参数*/
  let res = await wechatJsapiApi(wechatJsapiParams);

  /**2、jsapi调起支付的兼容写法*/
  //@ts-ignore
  if (typeof WeixinJSBridge === 'undefined') {
    if (document.addEventListener) {
      //@ts-ignore
      document.addEventListener('WeixinJSBridgeReady', onBridgeReady(res.resp_data.jsapi, wechatJsapiParams.transactionId), false)
      //@ts-ignore
    } else if (document.attachEvent) {
      //@ts-ignore
      document.attachEvent('WeixinJSBridgeReady', onBridgeReady(res.resp_data.jsapi, wechatJsapiParams.transactionId))
      //@ts-ignore
      document.attachEvent('onWeixinJSBridgeReady', onBridgeReady(res.resp_data.jsapi, wechatJsapiParams.transactionId))
    }
  } else {
    onBridgeReady(res.resp_data.jsapi, wechatJsapiParams.transactionId)
  }
}
/**
  * jsapi调起支付方法
*/
let onBridgeReady =  (params: IWechatJsapiRow, transactionId: number) => {
  let data = {
    appId: params.appId, // 公众号id
    nonceStr: params.nonceStr, // 支付签名随机串,不长于 32 位
    package: `prepay_id=${params.prepayId}`, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=\*\*\*)
    signType: params.signType, // 签名类型,默认为MD5,支持HMAC-SHA256和MD5(注意此处需与统一下单的签名类型一致)
    timeStamp: params.timeStamp, // 当前时间时间戳
    paySign: params.paySign
  }
  //@ts-ignore
  WeixinJSBridge.invoke(
    'getBrandWCPayRequest',
    { ...data },
    function (res: any) {
      if (res.err_msg === 'get_brand_wcpay_request:ok') {
        // console.log('支付成功!');
        // 跳转到支付成功结果页面
        window.location.replace(`${process.env.VUE_APP_JSAPI_PAY_SUCCESS_PAGE}/${transactionId}`);
      } else if (res.err_msg === 'get_brand_wcpay_request:fail') {
        // console.log('支付失败!');
      }
    }
  )
}