场景
- 给用户一个订单二维码,然后用户扫描二维码,如果是在微信中扫码,则进行微信支付,如果是在支付宝中扫码,则进行支付宝支付
- 给用户一个支付链接,当用户在微信打开这个链接时,进行微信支付,当用户在支付宝中打开时,进行支付宝支付
聚合支付的定义
- 聚合支付是指通过搭建一个h5的小程序,然后用户进入到这个小程序进行商品选择准备支付后,在小程序的内部判断用户此时是在微信打开这个小程序,还是在支付宝打开,如果是在微信打开,则调起微信JSAPI支付,如果是在支付宝打开,则调起支付宝JSAPI支付
- 用户通过微信打开支付链接时,微信内部其实做了一个中转,才会跳回我们自己的h5小程序,这个需要后端进行处理
- 判断用户是在微信打开,还是在支付宝打开,是通过判断当前用户打开这个支付链接的浏览器类型来实现
- 综上,其实聚合支付就是将两种支付融合进一个h5小程序,在支付时通过判断打开这个h5小程序的浏览器环境,然后调起相应环境的JSAPI支付
微信和支付宝的JSAPI支付
引入支付宝支付APIap
<script src="https://gw.alipayobjects.com/as/g/h5-lib/alipayjsapi/3.1.1/alipayjsapi.inc.min.js"></script>
- 通过uniapp开发h5,引入第三方script文件可以通过自定义模板实现 uniapp自定义h5模板
判断支付链接是在微信打开还是在支付宝打开
//由于微信和支付宝浏览器不支持Symbol类型,所以使用1,2代替
const wxSymbol = 1
const aliSymbol = 2
function judgeBrowser() {
const browser = navigator.userAgent.toLowerCase();
// 支付宝
if (browser.match(/Alipay/i) == "alipay") {
return aliSymbol;
// 微信
} else if (browser.match(/MicroMessenger/i) == "micromessenger") {
return wxSymbol;
}
}
export {
wxSymbol, aliSymbol, judgeBrowser
}
通过路径参数获取订单编号
getQueryString(type) {
//获取查询字符串
const search = location.search;
const urlSearchParams = new URLSearchParams(search);
// 将查询字符串转换为对象
this.orderOptions = Object.fromEntries(urlSearchParams.entries());
if (type === aliSymbol) {
if (this.orderOptions.orderNo) {
this.orderOptions.state = this.orderOptions.orderNo;
} else {
const urlFragment = location.href.split("/");
this.orderOptions.state = urlFragment[urlFragment.length - 1];
}
return;
}
},
根据orderNo获取订单详细信息
支付宝环境下需要用户授权获取code
onGetAuthCode() {
return new Promise((resolve, reject) => {
// 已经授权过的,直接授权信息返回
if (this.authInfo) {
return resolve(this.authInfo);
}
ap.getAuthCode({ appId: "开放平台应用 id", scopes: ["授权类型"] }, (res) => {
if (!res.error) {
return resolve(res);
}
reject(res.error);
});
});
}
判断支付环境,然后调用相应的支付环境的统一下单接口
async onPayment() {
const browserType = judgeBrowser();
if (browserType === aliSymbol) {
//支付宝先授权,再调用统一下单接口
const authInfo = await this.onGetAuthCode();
this.authInfo = authInfo;
this.onAliPayUnifiedOrder();
} else if (browserType === wxSymbol) {
this.onWxPayUnifiedOrder();
}
},
支付宝环境下的统一下单以及支付
async onAliPayUnifiedOrder() {
let result = {};
// 统一下单
if (this.apiPayResult.payParam) {
//已经调用过统一下单接口获取到支付所需要参数,不需要再次调用统一下单接口
result = this.apiPayResult;
} else {
//判断是否已经授权,只有授权才能调用统计下单接口
if (this.authInfo?.authCode) {
//接口参数
const params = {
code: this.authInfo?.authCode,
orderNo: this.orderOptions.state,
payType: "alipay",
};
//调用后端提供的统一下单接口
const res = await this.$u.api.aliPayUnifiedOrder(params);
if (res.code === 200) {
result = res.data;
//保存统一下单接口返回的数据
this.apiPayResult = res.data;
}
}
}
// 支付
if (this.apiPayResult.payParam) {
ap.tradePay({ tradeNO: this.apiPayResult.payParam }, (res) => {
//支付完成的逻辑
if (res.resultCode == 9000) {
this.$emit("accomplish");
}
});
}
}
微信环境下的统一下单以及支付
async onWxPayUnifiedOrder() {
let result = {};
if (this.wxPayResult.appId) {
//已经调用过统一下单接口获取到支付所需要参数,不需要再次调用统一下单接口
result = this.wxPayResult;
} else {
const params = {
code: this.orderOptions.code,
orderNo: this.orderOptions.state,
payType: "weChat",
};
//调用后端提供的统一下单接口
const res = await this.$u.api.wxPayUnifiedOrder(params);
if (res.code === 200) {
result = res.data.result;
//保存统一下单接口返回的数据
this.wxPayResult = res.data.result;
}
}
// 支付
if (result.appId) {
WeixinJSBridge.invoke(
"getBrandWCPayRequest",
{
...result,
},
// 支付完成回调函数,支付完成后没有执行,不知道是什么原因
function (payRes) {
this.result = payRes;
//支付完成的逻辑
if (res.err_msg == "get_brand_wcpay_request:ok") {
this.$emit("success");
}
}
);
}
},
- 微信支付成功后,返回支付拉起页面,测试发现没有执行支付完成回调函数,暂时不清楚是什么原因
- 微信支付参考文档
支付流程图
如何在vue生成二维码
下载依赖包
npm install qrcodejs2 -S
创建二维码
<template>
<button @click="onCreateQrcodeHandle">生成二维码</button>
<button @click="onClearQrcodeHandle">清除</button>
<div class="box" ref="boxRef"></div>
</template>
<script lang="ts" setup>
import { ref, shallowRef } from "vue";
import QRCode from "qrcodejs2";
const boxRef = ref();
const qrcode= shallowRef<InstanceType<typeof QRCode>>()
const onCreateQrcodeHandle = () => {
qrcode.value = new QRCode(boxRef.value, {
text: "你好",
// 指定二维码的宽高
width:150,
height:150,
// 二维码背景颜色
colorLight:"#00ff00",
// 二维码前景颜色
colorDark:"#ff0000",
// 二维码容错级别
correctLevel:QRCode.CorrectLevel.L
});
};
//清除二维码
const onClearQrcodeHandle = ()=>{
qrcode.value.clear();
}
</script>
参数API
QRCode参数
new QRCode(element, option)
| 名称 | 默认值 | 说明 |
|---|---|---|
| element | - | 承载二维码的DOM元素的ID |
| option | - | 参数设置 |
Option参数
| 名称 | 默认值 | 说明 | 备注 |
|---|---|---|---|
| text | - | 二维码承载的信息 | 如果是string那没有什么好说的。 如果是url的话,为了微信和QQ可以识别,连接中的中文使用encodeURIComponent进行编码 |
| width | 256 | 二维码宽度 | 单位像素(百分比不行) |
| height | 256 | 二维码高度 | 单位像素(百分比不行) |
| colorDark | '#000000' | 二维码前景色 | 英文\十六进制\rgb\rgba\transparent都可以 |
| colorLight | '#ffffff' | 二维码背景色 | 英文\十六进制\rgb\rgba\transparent都可以 |
| correctLevel | QRCode.CorrectLevel.L | 容错级别 | 由低到高 QRCode.CorrectLevel.L QRCode.CorrectLevel.M QRCode.CorrectLevel.Q QRCode.CorrectLevel.H |
API接口
| 名称 | 参数 | 说明 | 使用 |
|---|---|---|---|
| clear | - | 清除二维码 | qrcode.clear() |
| makeCode | string | 替换二维码(参数里面是新的二维码内容) | qrcode.makeCode('new content') |
清除二维码的方式
方案1
qrcode.clear():测试发现没有反应,希望得到大家帮忙处理这个问题
方案2
qrcode.value = null
boxRef.value.innerHTML = ""