登录过期重复跳转问题彻底修复

This commit is contained in:
jianzhichu
2026-01-15 01:14:07 +08:00
parent ff80250012
commit f376498fe5
5 changed files with 45 additions and 110 deletions
-70
View File
@@ -3,76 +3,6 @@ import { LogoutOutlined } from '@ant-design/icons-vue';
import { onMounted, onUnmounted, computed } from 'vue';
import { ThemeProvider, alert } from 'stepin';
import http from '@/store/http';
import { useRouter, useRoute } from 'vue-router';
const router = useRouter();
const route = useRoute();
// 核心:精准判断是否为手机浏览器(多重校验)
const isMobileBrowser = computed(() => {
if (typeof navigator === 'undefined' || typeof window === 'undefined') {
return false;
}
const userAgent = navigator.userAgent.toLowerCase();
// 1. 匹配手机UA特征(排除平板/桌面端)
const mobileUA = /android|iphone|ipod|blackberry|windows phone|iemobile|opera mini/i.test(userAgent);
const isTablet = /ipad|tablet|playbook|kindle|android 3\.|android 4\.[0-3]/.test(userAgent); // 排除平板
// 2. 触摸设备校验(手机核心特征)
const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
// 3. 屏幕尺寸兜底(适配响应式/模拟器)
const isMobileScreen = window.innerWidth <= 768 && window.innerHeight <= 1024;
// 最终判定:UA是手机 + 触摸设备 或 小屏触摸设备(覆盖所有手机场景)
return (mobileUA && !isTablet && isTouchDevice) || (isMobileScreen && isTouchDevice);
});
// 路由守卫:手机端强制拦截所有路由,仅允许/mobile
const enforceMobileRoute = () => {
const targetMobilePath = '/mobile';
const currentPath = route.path.toLowerCase().trim();
// 核心规则:手机浏览器 → 强制跳转到/mobile(无论当前路由是什么)
if (isMobileBrowser.value) {
if (currentPath !== targetMobilePath) {
// 替换路由(禁止返回上一页,避免用户回退到其他路由)
router.replace({ path: targetMobilePath, replace: true });
}
} else {
// PC端:禁止访问mobile路由,强制跳转到dashboard
if (currentPath === targetMobilePath) {
router.replace({ path: '/dashboard', replace: true });
}
}
};
// 监听路由变化:确保跳转后仍拦截(防止手动输入URL)
const routerGuard = router.afterEach(() => {
if (http.checkAuthorization()) {
// 仅登录后生效
enforceMobileRoute();
}
});
onMounted(() => {
// 1. 登录状态校验
if (http.checkAuthorization()) {
// 2. 初始化立即拦截路由
enforceMobileRoute();
// 3. 监听窗口大小变化(适配手机横屏/竖屏切换、模拟器调整尺寸)
window.addEventListener('resize', enforceMobileRoute);
} else {
// 未登录先跳登录页,登录后再拦截
router.push('/login');
}
});
// 组件卸载:清理监听,防止内存泄漏
onUnmounted(() => {
window.removeEventListener('resize', enforceMobileRoute);
// 移除路由守卫
routerGuard();
});
</script>
<template>
+27 -24
View File
@@ -13,7 +13,6 @@ interface NaviGuard {
after?: NavigationHookAfter;
}
// ========== 新增:移动端检测核心函数 ==========
/**
* 检测是否为移动端设备(UA + 屏幕宽度双检测)
*/
@@ -27,44 +26,49 @@ const isMobile = (): boolean => {
// 标记是否已跳转到移动端路由,防止无限循环
let hasRedirectedToMobile = false;
// ========== 新增:移动端跳转守卫(已集成登录状态判断) ==========
// 优化后的移动端跳转守卫(登录优先)
const MobileRedirectGuard: NavigationGuard = function (to, from, next) {
// 1. 排除/mobile路由本身,避免无限循环
if (to.path === '/mobile') {
// 1. 排除移动端路由和登录页,避免逻辑干扰
const isMobileRoute = to.path === '/mobile';
const isLoginRoute = to.path === '/login';
if (isMobileRoute) {
hasRedirectedToMobile = true;
next();
return;
}
// 2. 排除/login路由,避免登录页被移动端跳转逻辑覆盖
if (to.path === '/login') {
if (isLoginRoute) {
// 登录页无需移动端跳转,直接放行
hasRedirectedToMobile = false; // 重置标记,登录后可正常跳转移动端
next();
return;
}
// 3. 检测是否为移动端
if (isMobile() && !hasRedirectedToMobile) {
// 4. 核心判断:检查登录状态
// 2. 移动端检测
if (isMobile()) {
const isAuthorized = http.checkAuthorization();
if (!isAuthorized) {
// 未登录:优先跳转到登录页
hasRedirectedToMobile = false; // 重置标记,不影响后续登录后的跳转
// 未登录:优先跳登录(保持原有优先级)
next('/login');
} else {
// 已登录:跳转到移动端路由
hasRedirectedToMobile = true;
next({ path: '/mobile' });
// 已登录:跳移动端(防止重复跳转)
if (!hasRedirectedToMobile) {
hasRedirectedToMobile = true;
next({ path: '/mobile' });
} else {
next();
}
}
} else {
// 非移动端/已跳转:重置标记并执行原有逻辑
// 非移动端:重置标记,不影响后续操作
hasRedirectedToMobile = false;
next();
}
};
// ========== 原有守卫逻辑(无修改) ==========
// 原有守卫逻辑(无修改)
const loginGuard: NavigationGuard = function (to, from, next) {
// 补充next参数,保证守卫链正常执行
if (!http.checkAuthorization() && !/^\/(init|login|home|mobile)?$/.test(to.fullPath)) {
console.log(to.fullPath)
const account = useAccountStore();
@@ -89,7 +93,6 @@ const dynamicinitRoute = {
};
const InitGuard: NavigationGuard = function (to, from, next) {
// 补充next参数
if (to.fullPath != '/login') {
if (!router.hasRoute('login')) {
router.addRoute(dynamicinitRoute);
@@ -104,7 +107,7 @@ const InitGuard: NavigationGuard = function (to, from, next) {
const ProgressGuard: NaviGuard = {
before(to, from, next) {
NProgress.start();
next(); // 补充next参数
next();
},
after(to, from) {
NProgress.done();
@@ -134,7 +137,7 @@ const ForbiddenGuard: NaviGuard = {
delete to.query.permission;
delete to.query.path;
}
next(); // 补充next参数
next();
},
};
@@ -145,16 +148,16 @@ const NotFoundGuard: NaviGuard = {
if (to.meta._is404Page && loading) {
to.params.loading = true as any;
}
next(); // 补充next参数
next();
},
};
// ========== 页面刷新时的移动端检测(已集成登录状态判断) ==========
// 优化后的页面刷新移动端检测(登录优先)
window.addEventListener('load', () => {
if (isMobile() && window.location.pathname !== '/mobile') {
// 检查登录状态:未登录则跳登录,已登录则跳移动端
const isAuthorized = http.checkAuthorization();
if (!isAuthorized) {
// 未登录:跳登录(避免重复跳转)
if (window.location.pathname !== '/login') {
router.push('/login').catch(err => {
if (!err.message.includes('NavigationDuplicated')) {
@@ -163,6 +166,7 @@ window.addEventListener('load', () => {
});
}
} else {
// 已登录:跳移动端
router.push('/mobile').catch(err => {
if (!err.message.includes('NavigationDuplicated')) {
console.error('刷新时跳转移动端路由失败:', err);
@@ -173,7 +177,6 @@ window.addEventListener('load', () => {
});
export default {
// 把MobileRedirectGuard放在最前面,优先执行移动端检测
before: [ProgressGuard.before, MobileRedirectGuard, loginGuard, AuthGuard.before, ForbiddenGuard.before, NotFoundGuard.before],
after: [ProgressGuard.after],
};
+16 -14
View File
@@ -47,22 +47,24 @@ http.interceptors.response.use(
const accountStore = useAccountStore();
accountStore.setLogged(false);
message.warning('登录状态已过期,请重新登录');
setTimeout(() => {
const redirectPath = router.currentRoute.value.fullPath;
if (redirectPath !== '/login') {
router.push({
path: '/login',
query: { redirect: redirectPath }
}).then(() => {
console.log('跳转登录页成功');
}).catch((err) => {
console.error('跳转登录页失败:', err);
}).finally(() => {
const redirectPath = router.currentRoute.value.fullPath;
if (redirectPath !== '/login') {
router.push({
path: '/login',
query: { redirect: redirectPath }
}).then(() => {
console.log('跳转登录页成功');
}).catch((err) => {
console.error('跳转登录页失败:', err);
}).finally(() => {
isRedirecting = false;
});
} else {
isRedirecting = false;
});
} else {
isRedirecting = false;
}
}
}, 100);
}
// 新增结束
} else {