后端 生成 微信返回的 response 中的 code_url
将 URL 转换成 二维码 展示即可 或者 后端生成二维码 前端获取该二维码图片 展示
qrcodejs 二维码生成插件
支付结果通知 微信调用 后台接口 后台按照规范应答 或者 后台主动查询订单
对应 后端 Map 参数中 “notify_url”:“供 微信调用的后台接口”
支付完成 pay/callback 回调页展示 – XXXX/#/pay/callback
后端使用 goEasy 推送 给前端 前端跳转 pay/callback socket 发送 接收的 channel 名字 使用 唯一的 订单号
前端 轮询 后端 得到 跳转 指令 后 前端跳转 pay/callback http
let timer = null
if(timer) return
timer = setInterval(async()=>{
// 发请求获取用户支付状态
let result = await API.reqPayStatus(orderId)
// 如果code===200
if(result.code===200){
// 第一步:清除定时器
clearInterval(timer)
timer = null
// 保存支付成功返回的code
code.value = result.code
// 关闭弹出框
msgBox.close()
// 跳转到下一路由 查询订单操作
router.push('pay/callback')
}
},2000)
// 组件销毁 也要 清除定时器
onBeforeUnmount(()=>{
clearInterval(timer)
timer = null
})
1、跳转授权页
2、静默授权,只获取code,后端凭借code换取openId,也称静默授权 parking为静默
1 看 URL是否有 code 没有需要 授权获取 重定向为当前页 重新获取 code 就可以拿到 可以理解为 先静默后跳转
2 获取code
3 调用 后台接口 传递 code 并且获取 调起支付的 参数
// created阶段 微信内
let openId = null
const ua = window.navigator.userAgent.toLowerCase();
if(ua.match(/MicroMessenger/i) == 'micromessenger'){
getCode()
}
const getCode = () =>{
// 服务号id
const appid = 'XXX'
const local = window.location.href
// 截取路径中的 code,如果没有就去微信授权,如果已经获取到了就直接传code给后台获取openId
// 静默获取 code
openId = GetUrlParam('code')
// 获取不到 跳转授权
if (openId == null || openId === '') {
window.location.href =
'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' + appid + '&redirect_uri=' + encodeURIComponent(local) + '&response_type=code&scope=snsapi_base&state=#wechat_redirect'
}
}
// 注意 变量提升 应该放在调用之前
const GetUrlParam = code => {
var reg = new RegExp('(^|&)' + code + '=([^&]*)(&|$)')
let url = window.location.href.split("#")[0]
let search = url.split('?')[1]
if (search) {
var r = search.substr(0).match(reg)
if (r !== null) return unescape(r[2])
return null
} else {
return null
}
}
// 调用后台接口 传递 code + 其他参数 并且获取 调起支付的 参数
// 定义 调用 微信支付 的参数
let payInfo = null
// data 内包含 code--openId
findParkingInfo(data).then(({ data }) => {
if (!data) {
alert('数据错误,请联系管理员')
return
}
// 车牌 第二个 字符 插入 圆圈··· •
showInfo.carId = data.carid.replace(/^(.{2})/, '$1 · ')
showInfo.money = data.money
showInfo.parkName = data.parkname
// 赋值 微信支付 数据
payInfo = data.paystream
})
// onClick-->doPay(payInfo)
// 发起微信支付
const doPay = () => {
// btnDisabled.value = true
isIn ? inWeiXin(payInfo) : outWeiXin()
}
// 微信内支付
const inWeiXin = params => {
if (typeof WeixinJSBridge === 'undefined') {
if (document.addEventListener) {
document.addEventListener(
'WeixinJSBridgeReady',
onBridgeReady(params),
false
)
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady(params))
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady(params))
}
} else {
onBridgeReady(params)
}
}
// 搭桥onBridgeReady()
const onBridgeReady = weChatParameter => {
// const timestamp = Math.round(weChatParameter.timeStamp).toString()
window.WeixinJSBridge.invoke(
'getBrandWCPayRequest',
{
debug: false,
/*
appId: weChatParameter.appId, // 公众号名称,由商户传入
timeStamp: timestamp, // 时间戳,自1970年以来的秒数
nonceStr: weChatParameter.nonceStr, // 随机串
package: weChatParameter.package,
signType: weChatParameter.signType, // 微信签名方式:
paySign: weChatParameter.paySign, // 微信签名
*/
...weChatParameter,
jsApiList: ['chooseWXPay'],
},
function (res) {
// 使用以上方式判断前端返回,微信团队郑重提示:res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。
if (res.err_msg === 'get_brand_wcpay_request:ok') {
// 支付成功后的操作
// alert('支付成功')
router.replace({
path: '/success',
query: { message: '支付成功,一路顺风' },
})
} else if (res.err_msg === 'get_brand_wcpay_request:cancel') {
// 取消支付的操作
// 取消支付
router.replace({
path: '/success',
query: { message: '支付取消,请重新支付' },
})
} else {
// 支付失败
router.replace({
path: '/success',
query: { message: '支付失败,请重新支付' },
})
}
}
)
}
location.href 尽量用 replace
// 微信外支付
const outWeiXin = async () => {
// 项目支付相关的参数
// requestPay 后台接口 返回 跳转 URL
// const { params } = await requestPay()
// 返回成功 跳转
if (params) {
window.location.replace(params)
} else {
// '提交订单失败'
}
}
vue 哈希路由模式,微信回跳会把 # 后全部干掉,等于直回跳个域名,无法跳转 #/callback
解决方案: 可以自己拼接,把#省去,浏览器在访问时,会自动加上
// 同 QQ 登陆 AAAA-->127.0.0.1:8080
const redirect = encodeURIComponent(
'AAAA/pay/callback'
)
const payUrl = `${baseURL}pay/aliPay?orderId=${route.query.orderId}&redirect=${redirect}`
// 新开窗口 支付完后 跳转 AAAA/pay/callback
const aliPay = () => {
window.open(payUrl)
}
getApplyAliPay({
// 传递的其它参数
orderNumber: orderNumber,
// 支付成功之后重定向的地址
paySuccessUrl: 'xxx'
}).then(res => {
const div = document.createElement('div')
div.id = 'aliPay'
div.innerHTML = res
document.body.appendChild(div)
// 执行后会唤起支付宝
document.querySelector('#aliPay').children[0].submit()
})
// paySuccessUrl -- 查询订单操作