hookehuyr

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>
......@@ -35,7 +35,7 @@ declare module 'vue' {
PdfPreview: typeof import('./src/components/PdfPreview.vue')['default']
Picker: typeof import('./src/components/time-picker-data/picker.vue')['default']
PlanFormContainer: typeof import('./src/components/PlanFormContainer.vue')['default']
PlanPopup: typeof import('./src/components/PlanPopup/index.vue')['default']
PlanPopup: typeof import('./src/components/PlanSchemes/PlanPopup.vue')['default']
PosterBuilder: typeof import('./src/components/PosterBuilder/index.vue')['default']
ProductCard: typeof import('./src/components/ProductCard.vue')['default']
QrCode: typeof import('./src/components/qrCode.vue')['default']
......
......@@ -59,8 +59,20 @@ onMounted(() => {
/**
* Handle back navigation
* @description 智能处理返回逻辑,避免导航栈为空时报错
*/
const goBack = () => {
const pages = Taro.getCurrentPages()
if (pages.length > 1) {
// 如果导航栈有多个页面,正常返回
Taro.navigateBack()
} else {
// 如果导航栈只有1页,跳转到首页(避免报错)
console.log('导航栈只有1页,跳转到首页')
Taro.reLaunch({
url: '/pages/index/index'
})
}
}
</script>
......
......@@ -69,6 +69,7 @@
import { reactive } from 'vue'
import Taro from '@tarojs/taro'
import { useUserStore } from '@/stores/user'
import { routerStore } from '@/stores/router'
import NavHeader from '@/components/NavHeader.vue'
const userStore = useUserStore()
......@@ -112,9 +113,32 @@ const handleLogin = async () => {
Taro.hideLoading()
Taro.showToast({ title: '登录成功', icon: 'success' })
// 延迟后跳转首页
// 延迟后跳转回原页面或首页
setTimeout(() => {
// 获取 router store 实例
const store = routerStore()
// 从 router store 获取之前保存的路径
const redirectUrl = store.url
if (redirectUrl) {
// 清空保存的路径
store.remove()
console.log('登录成功,跳转回原页面:', redirectUrl)
// 跳转回原页面
Taro.redirectTo({
url: redirectUrl
}).catch(() => {
// 如果跳转失败,则跳转到首页
console.warn('跳转回原页面失败,跳转到首页')
Taro.reLaunch({ url: '/pages/index/index' })
})
} else {
// 没有保存的路径,跳转到首页
console.log('登录成功,跳转到首页')
Taro.reLaunch({ url: '/pages/index/index' })
}
}, 1500)
} else {
Taro.hideLoading()
......
......@@ -9,6 +9,7 @@ import axios from 'axios-miniprogram'
import Taro from '@tarojs/taro'
import { parseQueryString } from './tools'
import BASE_URL, { REQUEST_DEFAULT_PARAMS } from './config'
import { routerStore } from '@/stores/router'
/**
* @description 获取 sessionid 的工具函数
......@@ -246,14 +247,41 @@ service.interceptors.response.use(
// 401 未授权处理
if (res.code === 401) {
// 跳转到登录页
Taro.navigateTo({
// 获取当前页面路径
const pages = Taro.getCurrentPages()
const currentPage = pages[pages.length - 1]
const currentPath = currentPage?.route || ''
// 保存当前路径到 router store(用于登录后跳转回原页面)
if (currentPath && currentPath !== 'pages/login/index') {
const store = routerStore() // 调用函数获取 store 实例
store.add('/' + currentPath)
console.log('401: 保存当前路径到 router store:', '/' + currentPath)
} else {
console.log('401: 当前路径为空或是登录页,不保存路径:', currentPath)
}
// 根据导航栈长度选择跳转方式
if (pages.length <= 1) {
// 如果导航栈只有1个页面,使用 reLaunch 清空栈并跳转到登录页
// 这样可以避免"cannot navigate back"错误
console.log('401: 导航栈只有1页,使用 reLaunch')
Taro.reLaunch({
url: '/pages/login/index'
}).catch(() => {
console.warn('reLaunch 到登录页失败')
})
} else {
// 如果导航栈有多个页面,使用 redirectTo 替换当前页面
console.log('401: 导航栈有多个页面,使用 redirectTo')
Taro.redirectTo({
url: '/pages/login/index'
}).catch(() => {
// 如果跳转失败(如已经在登录页),则忽略
console.warn('跳转登录页失败,可能已在登录页')
})
}
}
// 处理特殊消息(不需要显示的错误)
if (['预约ID不存在'].includes(res.msg)) {
......