fix(auth): 修复401重定向死循环和返回报错问题
核心改动: 1. 401拦截器智能选择跳转方式 - 导航栈只有1页时使用 reLaunch(清空栈) - 导航栈有多页时使用 redirectTo(替换当前页) - 保存当前路径到 router store(用于登录后跳回) 2. NavHeader组件智能返回逻辑 - 检查导航栈长度 - 导航栈只有1页时跳转首页(避免返回报错) - 导航栈有多页时正常返回 3. 登录页智能跳转 - 登录成功后读取 router store 保存的路径 - 有保存路径则跳转回原页面 - 无保存路径则跳转到首页 解决问题: - ✅ 修复401重定向导致的死循环问题 - ✅ 修复登录页点击返回报错 "navigateBack:fail cannot navigate back at first page" - ✅ 提升用户体验(登录后回到原页面而非总是首页) 技术细节: - 正确使用 Pinia store:const store = routerStore() - 理解导航 API 差异:navigateTo(入栈)、redirectTo(替换)、reLaunch(清空栈) 影响文件: - src/utils/request.js - 401拦截器优化 - src/components/NavHeader.vue - 返回逻辑优化 - src/pages/login/index.vue - 登录成功后智能跳转 - components.d.ts - TypeScript声明自动更新 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Showing
4 changed files
with
75 additions
and
11 deletions
| ... | @@ -35,7 +35,7 @@ declare module 'vue' { | ... | @@ -35,7 +35,7 @@ declare module 'vue' { |
| 35 | PdfPreview: typeof import('./src/components/PdfPreview.vue')['default'] | 35 | PdfPreview: typeof import('./src/components/PdfPreview.vue')['default'] |
| 36 | Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] | 36 | Picker: typeof import('./src/components/time-picker-data/picker.vue')['default'] |
| 37 | PlanFormContainer: typeof import('./src/components/PlanFormContainer.vue')['default'] | 37 | PlanFormContainer: typeof import('./src/components/PlanFormContainer.vue')['default'] |
| 38 | - PlanPopup: typeof import('./src/components/PlanPopup/index.vue')['default'] | 38 | + PlanPopup: typeof import('./src/components/PlanSchemes/PlanPopup.vue')['default'] |
| 39 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] | 39 | PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default'] |
| 40 | ProductCard: typeof import('./src/components/ProductCard.vue')['default'] | 40 | ProductCard: typeof import('./src/components/ProductCard.vue')['default'] |
| 41 | QrCode: typeof import('./src/components/qrCode.vue')['default'] | 41 | QrCode: typeof import('./src/components/qrCode.vue')['default'] | ... | ... |
| ... | @@ -59,8 +59,20 @@ onMounted(() => { | ... | @@ -59,8 +59,20 @@ onMounted(() => { |
| 59 | 59 | ||
| 60 | /** | 60 | /** |
| 61 | * Handle back navigation | 61 | * Handle back navigation |
| 62 | + * @description 智能处理返回逻辑,避免导航栈为空时报错 | ||
| 62 | */ | 63 | */ |
| 63 | const goBack = () => { | 64 | const goBack = () => { |
| 64 | - Taro.navigateBack() | 65 | + const pages = Taro.getCurrentPages() |
| 66 | + | ||
| 67 | + if (pages.length > 1) { | ||
| 68 | + // 如果导航栈有多个页面,正常返回 | ||
| 69 | + Taro.navigateBack() | ||
| 70 | + } else { | ||
| 71 | + // 如果导航栈只有1页,跳转到首页(避免报错) | ||
| 72 | + console.log('导航栈只有1页,跳转到首页') | ||
| 73 | + Taro.reLaunch({ | ||
| 74 | + url: '/pages/index/index' | ||
| 75 | + }) | ||
| 76 | + } | ||
| 65 | } | 77 | } |
| 66 | </script> | 78 | </script> | ... | ... |
| ... | @@ -69,6 +69,7 @@ | ... | @@ -69,6 +69,7 @@ |
| 69 | import { reactive } from 'vue' | 69 | import { reactive } from 'vue' |
| 70 | import Taro from '@tarojs/taro' | 70 | import Taro from '@tarojs/taro' |
| 71 | import { useUserStore } from '@/stores/user' | 71 | import { useUserStore } from '@/stores/user' |
| 72 | +import { routerStore } from '@/stores/router' | ||
| 72 | import NavHeader from '@/components/NavHeader.vue' | 73 | import NavHeader from '@/components/NavHeader.vue' |
| 73 | 74 | ||
| 74 | const userStore = useUserStore() | 75 | const userStore = useUserStore() |
| ... | @@ -112,9 +113,32 @@ const handleLogin = async () => { | ... | @@ -112,9 +113,32 @@ const handleLogin = async () => { |
| 112 | Taro.hideLoading() | 113 | Taro.hideLoading() |
| 113 | Taro.showToast({ title: '登录成功', icon: 'success' }) | 114 | Taro.showToast({ title: '登录成功', icon: 'success' }) |
| 114 | 115 | ||
| 115 | - // 延迟后跳转到首页 | 116 | + // 延迟后跳转回原页面或首页 |
| 116 | setTimeout(() => { | 117 | setTimeout(() => { |
| 117 | - Taro.reLaunch({ url: '/pages/index/index' }) | 118 | + // 获取 router store 实例 |
| 119 | + const store = routerStore() | ||
| 120 | + | ||
| 121 | + // 从 router store 获取之前保存的路径 | ||
| 122 | + const redirectUrl = store.url | ||
| 123 | + | ||
| 124 | + if (redirectUrl) { | ||
| 125 | + // 清空保存的路径 | ||
| 126 | + store.remove() | ||
| 127 | + console.log('登录成功,跳转回原页面:', redirectUrl) | ||
| 128 | + | ||
| 129 | + // 跳转回原页面 | ||
| 130 | + Taro.redirectTo({ | ||
| 131 | + url: redirectUrl | ||
| 132 | + }).catch(() => { | ||
| 133 | + // 如果跳转失败,则跳转到首页 | ||
| 134 | + console.warn('跳转回原页面失败,跳转到首页') | ||
| 135 | + Taro.reLaunch({ url: '/pages/index/index' }) | ||
| 136 | + }) | ||
| 137 | + } else { | ||
| 138 | + // 没有保存的路径,跳转到首页 | ||
| 139 | + console.log('登录成功,跳转到首页') | ||
| 140 | + Taro.reLaunch({ url: '/pages/index/index' }) | ||
| 141 | + } | ||
| 118 | }, 1500) | 142 | }, 1500) |
| 119 | } else { | 143 | } else { |
| 120 | Taro.hideLoading() | 144 | Taro.hideLoading() | ... | ... |
| ... | @@ -9,6 +9,7 @@ import axios from 'axios-miniprogram' | ... | @@ -9,6 +9,7 @@ import axios from 'axios-miniprogram' |
| 9 | import Taro from '@tarojs/taro' | 9 | import Taro from '@tarojs/taro' |
| 10 | import { parseQueryString } from './tools' | 10 | import { parseQueryString } from './tools' |
| 11 | import BASE_URL, { REQUEST_DEFAULT_PARAMS } from './config' | 11 | import BASE_URL, { REQUEST_DEFAULT_PARAMS } from './config' |
| 12 | +import { routerStore } from '@/stores/router' | ||
| 12 | 13 | ||
| 13 | /** | 14 | /** |
| 14 | * @description 获取 sessionid 的工具函数 | 15 | * @description 获取 sessionid 的工具函数 |
| ... | @@ -246,13 +247,40 @@ service.interceptors.response.use( | ... | @@ -246,13 +247,40 @@ service.interceptors.response.use( |
| 246 | 247 | ||
| 247 | // 401 未授权处理 | 248 | // 401 未授权处理 |
| 248 | if (res.code === 401) { | 249 | if (res.code === 401) { |
| 249 | - // 跳转到登录页 | 250 | + // 获取当前页面路径 |
| 250 | - Taro.navigateTo({ | 251 | + const pages = Taro.getCurrentPages() |
| 251 | - url: '/pages/login/index' | 252 | + const currentPage = pages[pages.length - 1] |
| 252 | - }).catch(() => { | 253 | + const currentPath = currentPage?.route || '' |
| 253 | - // 如果跳转失败(如已经在登录页),则忽略 | 254 | + |
| 254 | - console.warn('跳转登录页失败,可能已在登录页') | 255 | + // 保存当前路径到 router store(用于登录后跳转回原页面) |
| 255 | - }) | 256 | + if (currentPath && currentPath !== 'pages/login/index') { |
| 257 | + const store = routerStore() // 调用函数获取 store 实例 | ||
| 258 | + store.add('/' + currentPath) | ||
| 259 | + console.log('401: 保存当前路径到 router store:', '/' + currentPath) | ||
| 260 | + } else { | ||
| 261 | + console.log('401: 当前路径为空或是登录页,不保存路径:', currentPath) | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + // 根据导航栈长度选择跳转方式 | ||
| 265 | + if (pages.length <= 1) { | ||
| 266 | + // 如果导航栈只有1个页面,使用 reLaunch 清空栈并跳转到登录页 | ||
| 267 | + // 这样可以避免"cannot navigate back"错误 | ||
| 268 | + console.log('401: 导航栈只有1页,使用 reLaunch') | ||
| 269 | + Taro.reLaunch({ | ||
| 270 | + url: '/pages/login/index' | ||
| 271 | + }).catch(() => { | ||
| 272 | + console.warn('reLaunch 到登录页失败') | ||
| 273 | + }) | ||
| 274 | + } else { | ||
| 275 | + // 如果导航栈有多个页面,使用 redirectTo 替换当前页面 | ||
| 276 | + console.log('401: 导航栈有多个页面,使用 redirectTo') | ||
| 277 | + Taro.redirectTo({ | ||
| 278 | + url: '/pages/login/index' | ||
| 279 | + }).catch(() => { | ||
| 280 | + // 如果跳转失败(如已经在登录页),则忽略 | ||
| 281 | + console.warn('跳转登录页失败,可能已在登录页') | ||
| 282 | + }) | ||
| 283 | + } | ||
| 256 | } | 284 | } |
| 257 | 285 | ||
| 258 | // 处理特殊消息(不需要显示的错误) | 286 | // 处理特殊消息(不需要显示的错误) | ... | ... |
-
Please register or login to post a comment