声明:本文只作学习研究,禁止用于非法用途,否则后果自负,如有侵权,请告知删除,谢谢!
💓 博客主页:这个头像胖嘟嘟
⏩ 收录文章:微信支付(微信公众号)
🎉欢迎大家点赞👍评论📝收藏⭐文章
前言
目录
前段时间公司项目需要接入微信支付,因此研究了一下如何使用微信支付。和支付宝支付相比,微信支付相对复杂一些,需要配置的东西更多,限制也更多。经过两天的研究,终于搞定微信支付,在这里对于使用微信支付的经验进行一些总结。
微信公众号中微信支付
我们这是一个微信公众号内的支付调起,不同于 h5支付,这个支付只能出现在公众号,在别的地方不能生效。
接到这个需求整个人是懵的,因为之前根本没有接触过或者做过微信公众号的支付,好在之前做过支付宝支付页面的调起,类比推理一下,还是感觉比较简单的。
项目需求思路
找到原来项目,复制一份,因为之前项目里面已经有支付宝支付了,我们要做公众号的微信制度,复制了一份代码,然后开始修改里面的代码
遇到问题
修改完结构以后发现,支付调起的时候报错,这是就要问比较熟悉这块业务的同事,我选择了,人美心善的静怡,她也是我们这月周会的负责人,我们每月的周会,是有我们小组里面每个成员轮流来负责的。
解决方案
会后负责人特别的负责人,让我去找她解决这个问题,因为之前没弄过导致了一些问题出现了沟通上的障碍
沟通问题梳理
1 .这个微信支付,不是走原来的那一套支付,虽然代码可以用,也可以调起但是存在细微差别,我一直在尝试看原来的一套代码逻辑能不能沿用,确没有跟他明确这个问题,静怡跟他沟通后才知道这块 h5的支付是不支持的。我没问清楚。
2.他让我调的接口里面有两个接口,一个是他新写的接口,一个是原来的接口,我只把注意力放到了他新让我调的接口,没有注意另外一个接口,而另外一个接口里面返回的数据,是我需要的数据,这个数据是要拿来配置微信支付的配置返回。
3.关于新一套里面 code 码,换取 open_id.他给我一个链接,这个链接要放在微信开发者工具上面才能看到 code 码,正常的浏览器上面是看不到的,我在获取 code 时就在使用这个工具,但是这个工具只能看到 code 码,却在上面修改代码,实时看到效果,需要把代码发到测试环境才可以看到我们写的东西对不对。
这个 code 码用过一次,5 分钟之后就会失效,要不断的从新拿到新的code 码才能看到效果,后端当时给我说了有一个 code 码一直都能返回值,有效,我当时由于没做过这个东西根本不知道他说的啥意思,后来静怡经过沟通以后知道了,这个可以 code 可以写死一直有效,就一直能获取到这个 open_id 的值。
4.我不能实时的看到我代码的效果,和接口是否返回了我需要的数据,这是我们需要在我们的代码上面加上一个工具,我们就可以看到这个发送接口的数据。这个工具是 VConsole,这个工具在 ssr 项目里面就有很多直接搜索就可以看到这个工具是怎么用的。
工具使用
步骤如下:
在项目的 index.html 里面引入 js 文件,和使用启动的代码,我当时没看清楚,以为放在 script 标签的下面就行了,我写在了 vue 里面结果导致报错,后来经过排查发现我的书写位置出错了,我又从新修改了书写的位置
<script src='https://s4.ssl.qhres2.com/static/4f2a7ad8aabc57ac.js'></script>
<script>
if(window.location.search.indexOf('debug=1') > -1 || window.location.host == 'activity.test.huajiao.com') {
var vConsole = new VConsole();
}
</script>
这个是代码应该书写的位置,写上后就可以看到你的强求结果,返回值,就可以进行调试了。
结构书写
书写结构,调试相关代码逻辑
<div class="submit" :class="{'inZFB': isInZFB}">
<button
v-if="!isInZFB"
class="btn wechat"
@click="handlerOpenModal('wechat', 0)"
>
<i class="icon wechat" />
<div class="btn-text">
<div class="btn-title">
微信支付
</div>
<div class="btn-note">
最高10,000元,秒到
</div>
</div>
</button>
<button
class="btn alipay"
@click="handlerOpenModal('alipay', 1)"
>
<i class="icon alipay" />
<div class="btn-text">
<div class="btn-title">
支付宝
</div>
<div class="btn-note">
最高200,000元,秒到
</div>
</div>
</button>
</div>
这个是微信支付,支付宝支付的相关结构,里面的样式问题我就不再粘贴,可以根据自己的需求进行书写
// 控制充值确认模态框显示隐藏
结构样式中的点击事件,提示和弹出模态框之类的操作。
handlerOpenModal(payment, index) {
if(!this.checked) {
this.$hf.ui.showToast('请勾选用户充值协议', 1500);
return;
}
if(!this.verifyRechargeForm(payment)) return;
this.currIndex = index;
this.modal.payment = payment;
this.modal.isVisible = true;
},
// 表单验证
verifyRechargeForm(payment) {
const result = [];
// 校验元气用户ID输入是否正确
if(!this.userInfo.uid) {
result.push('您的元气帐户有误');
}
console.log('payment channel:', payment);
if(result.length) {
const [message] = result;
this.$hf.ui.showToast(message, 1500);
return false;
}
return true;
},
模态框里面的表单校验事件
<!-- 确认支付模态框 -->
<Modal :is-visible="modal.isVisible">
<div class="modal-content">
<div class="modal-body">
<div class="description">
<p>您将为如下元气号充值{{ selectedChargepack.coin }}币</p>
<p>需支付{{ selectedChargepack.amount }}元</p>
</div>
<div class="user-info">
<div class="user-avatar">
<img
:src="userInfo.avatar || defaultAvatar"
alt=""
>
</div>
<div class="user-label">
<p class="user-nickname text-nowrap">
{{ userInfo.nickname }}
</p>
<p class="user-uid text-nowrap">
<template v-if="userInfo.display_uid">
元气靓号: {{ userInfo.display_uid }}
</template>
<template v-else>
元气号: {{ userInfo.uid }}
</template>
</p>
</div>
</div>
</div>
<div class="modal-action">
<button
class="btn cancel"
@click="handlerCloseModal"
>
再想想
</button>
<button
class="btn submit"
@click="submitRechargeForm(modal.payment)"
>
确认支付
</button>
</div>
</div>
</Modal>
这个是弹出模态框里面的模态框
// 提交表单
async submitRechargeForm(payment) {
const optionId = this.selectedChargepack.option_id || '';
const { uid } = this.userInfo;
const [err, res] = await this.$hf.req.rechargeSubmit({
option_id: optionId,
open_id: this.open_id || 'oNFsX6W9R09MBRYWoTzWKw6vC8kY',
trade_channel: this.paymentChannel[payment],
userid: uid,
deal_confirm: 1,
});
console.log(res.pay_info, 'payInfo');
if(!err) {
console.log('res', res);
if (this.open_id === '') {
window.location.href = res.pay_info;
}
const {
appid, noncestr, timestamp, sign, prepayid
} = JSON.parse(res.pay_info);
this.wxParams = {
// eslint-disable-next-line max-len
debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出,仅在pc端时才会打印。
appId: appid, // 必填,公众号的唯一标识
timestamp, // 必填,生成签名的时间戳
nonceStr: noncestr, // 必填,生成签名的随机串
signature: sign, // 必填,签名
package: `prepay_id=${prepayid}`
};
window.wx.config(this.wxParams);
debugger;
window.wx.ready(() => {
this.checkWXJsbridge(this.wxParams);
});
this.getRechargeStatus(res.order_id);
this.handlerCloseModal(); // 关闭支付二次确认弹窗
}
/* eslint-enable camelcase */
// if(!this.isInZFB) {
// Object.assign(params, { source, sourceType });
// await this.executeGeneralPay(params);
// } else {
// localStorage.setItem('lastRchargeUid', uid);
// this.executeZFBPay(params);
// }
},
这个是模态框里面的确认提交的事件,就是在这个接口里面要给他多加一个参数
open_id: this.open_id || 'oNFsX6W9R09MBRYWoTzWKw6vC8kY',
给这个参数的 open_id 取值需要新增加一个接口,在这个接口里面拿到我们需要的 open_id 的值
// 获取微信用户信息
async checkUserStatusWX() {
if(this.isRequireLogin && this.userInfo.uid) {
console.log(this.userInfo, 'this.userInfo');
const [err, data] = await this.$hf.req.getWeixinUserInfo({
weixin_code: this.$root.code
});
console.log(data.open_id, 'code是什么');
this.open_id = data?.open_id;
if(err) {
console.log('获取用户信息失败');
return false;
}
console.log(data);
// this.userType = data.user_type; // 不支持
}
},
在这个接口里面拿到 open_id
在提交表单的这个接口里面书写调起微信支付的逻辑,用 JSAPI 来调起,链接如下
https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml
在这个链接里面可以看到使用的方法,说明文档
https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/JS-SDK.html#58
Js-sdk说明文档
加载了微信的sdk之后window上就挂载了wx和weixinjsbridge了,所以这些方法应该都可以用
接口返回了我们需要的数据,把返回的数据解构出来,拿到想要的数据,配置微信支付的配置,需要传递的数据在下面的链接里面
https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml
wx.ready是微信JS-SDK提供的一个用于检测微信客户端是否准备就绪的回调函数,需要在微信配置文件中进行设置。
配置完成以后查看是否准备就绪,用 ready函数,在里面调用方法,把我们配置好的参数传递进去
checkWXJsbridge() {
console.log(typeof window.WeixinJSBridge);
if (typeof window.WeixinJSBridge === 'undefined') {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', this.readyWechatPay, false);
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', this.readyWechatPay);
document.attachEvent('onWeixinJSBridgeReady', this.readyWechatPay);
}
} else {
console.log('WX PAY');
this.readyWechatPay();
}
},
readyWechatPay() {
console.log('WX pay start');
window.WeixinJSBridge.invoke('getBrandWCPayRequest', {
...this.wxParams,
signType: 'RSA', // 微信签名方式:
paySign: this.wxParams.signature // 微信签名
},
(res) => {
if (res.err_msg === 'get_brand_wcpay_request:ok') {
console.log(res.err_msg);
}
});
},
这两个函数是官网里面配置的函数,直接在里面复制,然后拿过来使用即可。wx.ready 的使用博文参考文档这个地方在调用方法的时候要加上window,因为这个变量是绑定到window上的,直接写eslint可能会算他未定义。