feat(wx): 启用微信分享API并优化OAuth流程
修复微信JSSDK签名URL包含hash导致的重复刷新问题 在OAuth流程中保留原始hash路由位置 重构路由守卫代码格式
Showing
4 changed files
with
75 additions
and
42 deletions
| 1 | <!-- | 1 | <!-- |
| 2 | * @Date: 2025-03-20 19:53:12 | 2 | * @Date: 2025-03-20 19:53:12 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-10-15 10:11:57 | 4 | + * @LastEditTime: 2025-12-09 16:43:21 |
| 5 | * @FilePath: /mlaj/src/App.vue | 5 | * @FilePath: /mlaj/src/App.vue |
| 6 | * @Description: 入口文件 | 6 | * @Description: 入口文件 |
| 7 | --> | 7 | --> |
| ... | @@ -27,22 +27,29 @@ import 'vant/es/toast/style' | ... | @@ -27,22 +27,29 @@ import 'vant/es/toast/style' |
| 27 | provideAuth(); // 提供全局认证状态 | 27 | provideAuth(); // 提供全局认证状态 |
| 28 | provideCart('single'); // 提供全局购物车状态,单一商品模式 | 28 | provideCart('single'); // 提供全局购物车状态,单一商品模式 |
| 29 | 29 | ||
| 30 | -// 初始化微信配置 | 30 | +/** |
| 31 | + * @function initWxConfig | ||
| 32 | + * @description 初始化微信 JSSDK 配置;签名 URL 必须使用不包含 hash 的完整地址,避免进入详情页在微信环境出现重复刷新。 | ||
| 33 | + * @returns {void} | ||
| 34 | + */ | ||
| 31 | const initWxConfig = async () => { | 35 | const initWxConfig = async () => { |
| 32 | - const raw_url = encodeURIComponent(location.pathname + location.hash); | 36 | + // 使用不带 hash 的完整 URL 参与签名,规避重复刷新问题 |
| 33 | - try { | 37 | + const sign_url = encodeURIComponent(window.location.href.split('#')[0]); |
| 34 | - const wxJs = await wxJsAPI({ url: raw_url }) | 38 | + try { |
| 35 | - wxJs.data.jsApiList = apiList | 39 | + const wxJs = await wxJsAPI({ url: sign_url }); |
| 36 | - wx.config(wxJs.data) | 40 | + wxJs.data.jsApiList = apiList; |
| 37 | - wx.ready(() => { | 41 | + wx.config(wxJs.data); |
| 38 | - wx.showAllNonBaseMenuItem() | 42 | + wx.ready(() => { |
| 39 | - }) | 43 | + // 微信 JSSDK 初始化完成,展示所有非基础菜单项 |
| 40 | - wx.error((err) => { | 44 | + wx.showAllNonBaseMenuItem(); |
| 41 | - console.warn('微信配置初始化失败:', err) | 45 | + }); |
| 42 | - }) | 46 | + wx.error((err) => { |
| 43 | - } catch (error) { | 47 | + // 微信 JSSDK 初始化失败日志 |
| 44 | - console.error('初始化微信配置失败:', error) | 48 | + console.warn('微信配置初始化失败:', err); |
| 45 | - } | 49 | + }); |
| 50 | + } catch (error) { | ||
| 51 | + console.error('初始化微信配置失败:', error); | ||
| 52 | + } | ||
| 46 | } | 53 | } |
| 47 | 54 | ||
| 48 | // 在非开发环境下初始化微信配置 | 55 | // 在非开发环境下初始化微信配置 | ... | ... |
| ... | @@ -6,8 +6,8 @@ | ... | @@ -6,8 +6,8 @@ |
| 6 | * @Description: 文件描述 | 6 | * @Description: 文件描述 |
| 7 | */ | 7 | */ |
| 8 | export const apiList = [ | 8 | export const apiList = [ |
| 9 | - // "updateAppMessageShareData", | 9 | + "updateAppMessageShareData", |
| 10 | - // "updateTimelineShareData", | 10 | + "updateTimelineShareData", |
| 11 | "onMenuShareTimeline", | 11 | "onMenuShareTimeline", |
| 12 | "onMenuShareAppMessage", | 12 | "onMenuShareAppMessage", |
| 13 | "onMenuShareQQ", | 13 | "onMenuShareQQ", | ... | ... |
| ... | @@ -38,5 +38,25 @@ app.config.warnHandler = () => null; | ... | @@ -38,5 +38,25 @@ app.config.warnHandler = () => null; |
| 38 | 38 | ||
| 39 | app.config.globalProperties.$http = axios; // 关键语句 | 39 | app.config.globalProperties.$http = axios; // 关键语句 |
| 40 | app.component('font-awesome-icon', FontAwesomeIcon) | 40 | app.component('font-awesome-icon', FontAwesomeIcon) |
| 41 | +/** | ||
| 42 | + * @function restoreHashAfterOAuth | ||
| 43 | + * @description 前端复原 OAuth 回跳的 hash 路由位置:当 URL 中存在 ret_hash 参数且当前无 hash 时,将其拼回地址栏。 | ||
| 44 | + * @returns {void} | ||
| 45 | + */ | ||
| 46 | +function restoreHashAfterOAuth() { | ||
| 47 | + const url = new URL(window.location.href); | ||
| 48 | + const ret_hash = url.searchParams.get('ret_hash'); | ||
| 49 | + if (ret_hash && !window.location.hash) { | ||
| 50 | + // 删除 ret_hash,保留其他查询参数 | ||
| 51 | + url.searchParams.delete('ret_hash'); | ||
| 52 | + const base = url.toString().split('#')[0]; | ||
| 53 | + const new_url = base + ret_hash; | ||
| 54 | + // 使用 replaceState 避免再次刷新与历史记录污染 | ||
| 55 | + window.history.replaceState(null, '', new_url); | ||
| 56 | + } | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +// 在安装路由前进行一次 hash 复原,确保初始路由正确 | ||
| 60 | +restoreHashAfterOAuth() | ||
| 41 | app.use(router) | 61 | app.use(router) |
| 42 | app.mount('#app') | 62 | app.mount('#app') | ... | ... |
| 1 | /* | 1 | /* |
| 2 | * @Date: 2025-03-20 20:36:36 | 2 | * @Date: 2025-03-20 20:36:36 |
| 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com | 3 | * @LastEditors: hookehuyr hookehuyr@gmail.com |
| 4 | - * @LastEditTime: 2025-12-04 11:08:58 | 4 | + * @LastEditTime: 2025-12-09 16:47:55 |
| 5 | * @FilePath: /mlaj/src/router/guards.js | 5 | * @FilePath: /mlaj/src/router/guards.js |
| 6 | * @Description: 路由守卫逻辑 | 6 | * @Description: 路由守卫逻辑 |
| 7 | */ | 7 | */ |
| ... | @@ -10,26 +10,26 @@ import { wxInfo } from "@/utils/tools" | ... | @@ -10,26 +10,26 @@ import { wxInfo } from "@/utils/tools" |
| 10 | 10 | ||
| 11 | // 需要登录才能访问的路由 | 11 | // 需要登录才能访问的路由 |
| 12 | export const authRequiredRoutes = [ | 12 | export const authRequiredRoutes = [ |
| 13 | - { | 13 | + { |
| 14 | - path: '/profile', | 14 | + path: '/profile', |
| 15 | - exact: false, | 15 | + exact: false, |
| 16 | - }, | 16 | + }, |
| 17 | - { | 17 | + { |
| 18 | - path: '/checkout', | 18 | + path: '/checkout', |
| 19 | - exact: true, | 19 | + exact: true, |
| 20 | - }, | 20 | + }, |
| 21 | - { | 21 | + { |
| 22 | - path: '/activities/[^/]+/signup', | 22 | + path: '/activities/[^/]+/signup', |
| 23 | - regex: true, | 23 | + regex: true, |
| 24 | - }, | 24 | + }, |
| 25 | - { | 25 | + { |
| 26 | - path: '/checkin', | 26 | + path: '/checkin', |
| 27 | - exact: false, | 27 | + exact: false, |
| 28 | - }, | 28 | + }, |
| 29 | - { | 29 | + { |
| 30 | - path: '/teacher', | 30 | + path: '/teacher', |
| 31 | - exact: false, | 31 | + exact: false, |
| 32 | - }, | 32 | + }, |
| 33 | ] | 33 | ] |
| 34 | 34 | ||
| 35 | /** | 35 | /** |
| ... | @@ -54,6 +54,11 @@ export const checkWxAuth = async () => { | ... | @@ -54,6 +54,11 @@ export const checkWxAuth = async () => { |
| 54 | * @description 手动发起微信授权登录(仅在用户点击微信图标时触发) | 54 | * @description 手动发起微信授权登录(仅在用户点击微信图标时触发) |
| 55 | * @returns {void} | 55 | * @returns {void} |
| 56 | */ | 56 | */ |
| 57 | +/** | ||
| 58 | + * @function startWxAuth | ||
| 59 | + * @description 手动发起微信授权登录;使用不含 hash 的完整 URL 作为回跳参数,避免微信浏览器对 hash 的处理差异导致回跳异常。 | ||
| 60 | + * @returns {void} | ||
| 61 | + */ | ||
| 57 | export const startWxAuth = async () => { | 62 | export const startWxAuth = async () => { |
| 58 | // 开发环境不触发微信授权 | 63 | // 开发环境不触发微信授权 |
| 59 | if (import.meta.env.DEV) { | 64 | if (import.meta.env.DEV) { |
| ... | @@ -77,9 +82,10 @@ export const startWxAuth = async () => { | ... | @@ -77,9 +82,10 @@ export const startWxAuth = async () => { |
| 77 | // 探测失败不影响授权流程,继续跳转 | 82 | // 探测失败不影响授权流程,继续跳转 |
| 78 | } | 83 | } |
| 79 | 84 | ||
| 80 | - // 跳转到微信授权地址 | 85 | + // 跳转到微信授权地址(签名与回跳使用不含 hash 的完整 URL),并通过 ret_hash 参数保留授权前页面位置 |
| 81 | - const raw_url = encodeURIComponent(location.href); | 86 | + const base_url = encodeURIComponent(window.location.href.split('#')[0]); |
| 82 | - const short_url = `/srv/?f=behalo&a=openid&res=${raw_url}`; | 87 | + const ret_hash = encodeURIComponent(window.location.hash || ''); |
| 88 | + const short_url = `/srv/?f=behalo&a=openid&res=${base_url}&ret_hash=${ret_hash}`; | ||
| 83 | location.href = short_url; | 89 | location.href = short_url; |
| 84 | } | 90 | } |
| 85 | 91 | ... | ... |
-
Please register or login to post a comment