fix:登录增加记住密码 优化路由逻辑

This commit is contained in:
liangdong
2026-01-11 22:23:34 +08:00
parent 23a7285e29
commit 79e16909f0
3 changed files with 94 additions and 21 deletions

View File

@@ -110,12 +110,13 @@ const router = useRouter();
const route = useRoute(); const route = useRoute();
const userStore = useUserStore(); const userStore = useUserStore();
const tokenManager = TokenManager.getInstance(); const tokenManager = TokenManager.getInstance();
const KEEP_KEY = "keep_login_remember";
const loginFormRef = ref<FormInstance>(); const loginFormRef = ref<FormInstance>();
const loading = ref(false); const loading = ref(false);
const loginForm = reactive({ const loginForm = reactive({
username: "18280362106", username: "",
password: "123456789", password: "",
remember:false remember:false
}); });
@@ -159,22 +160,46 @@ const handleLogin = async () => {
userStore.setToken(refresh_token); userStore.setToken(refresh_token);
// 获取用户信息 // 获取用户信息
userStore.setUserInfo(userInfo); userStore.setUserInfo(userInfo);
// TODO:记住密码功能 // 记住密码功能
if (loginForm.remember) {
const saveInfo = {
username: loginForm.username,
password: loginForm.password // TODO:密码要加密才行
};
tokenManager.setToken(KEEP_KEY, JSON.stringify(saveInfo));
} else {
// 如果用户取消勾选,则移除
tokenManager.removeToken(KEEP_KEY);
}
ElMessage.success("登录成功"); ElMessage.success("登录成功");
// 跳转到首页或之前访问的页面 // 跳转到首页或之前访问的页面
const redirect = (route.query.redirect as string) || "/"; const redirect = (route.query.redirect as string);
router.push(redirect); router.push({path:'/',query:redirect});
} }
} catch (error: any) { } catch (error: any) {
console.error("Login error:", error); console.error("Login error:", error);
ElMessage.error(error.error || "登录失败,请稍后重试");
} finally { } finally {
loading.value = false; loading.value = false;
} }
}); });
}; };
onMounted(() => {
const savedInfo = tokenManager.getToken(KEEP_KEY);
if (savedInfo) {
try {
const { username, password } = JSON.parse(savedInfo);
loginForm.username = username;
loginForm.password = password;
loginForm.remember = true;
} catch (e) {
console.error("解析记住的密码失败", e);
}
}
});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -128,6 +128,29 @@ const transformRoutes = (
} }
}); });
}; };
/**
* 递归查找路由配置中的第一个有效路径(叶子节点)
*/
const getFirstValidPath = (routes: RouteRecordRaw[], parentPath: string = "") => {
for (const route of routes) {
// 拼接当前层级的完整路径
let currentPath = route.path.startsWith("/")
? route.path
: `${parentPath}/${route.path}`.replace(/\/+/g, "/");
// 如果有子路由,继续递归,并将当前路径传下去
if (route.children && route.children.length > 0) {
const childPath = getFirstValidPath(route.children, currentPath);
if (childPath) return childPath;
}
// 如果是叶子节点(有组件),返回拼接好的完整路径
if (route.component) {
return currentPath;
}
}
return "/";
};
// 添加动态路由 // 添加动态路由
const addDynamicRoutes = async () => { const addDynamicRoutes = async () => {
@@ -140,7 +163,7 @@ const addDynamicRoutes = async () => {
try { try {
// 从后端获取路由菜单数据 (这边需要区分 后台的菜单 和用户的菜单) // 从后端获取路由菜单数据 (这边需要区分 后台的菜单 和用户的菜单)
let allRoutes:any[] = []; let allRoutes: any[] = [];
if (userStore.isBackendUser) { if (userStore.isBackendUser) {
// const backendResponse = await getRouteMenus(); // const backendResponse = await getRouteMenus();
const backendResponse = []; const backendResponse = [];
@@ -149,10 +172,12 @@ const addDynamicRoutes = async () => {
code: "stage", code: "stage",
name: "管理中心", name: "管理中心",
icon: "", icon: "",
meta:{ meta: {
title:'管理中心' title: "管理中心",
}, },
children: Object.keys(backendResponse).length ? backendResponse : mockBackendMenuData, children: Object.keys(backendResponse).length
? backendResponse
: mockBackendMenuData,
}, },
]; ];
} else { } else {
@@ -222,7 +247,7 @@ router.beforeEach(async (to, _from, next) => {
// 未登录,重定向到登录页 // 未登录,重定向到登录页
next({ next({
path: "/login", path: "/login",
query: { redirect: to.fullPath }, // 保存当前路径,登录后可以跳转回来 query: { redirect: to.fullPath },
}); });
return; return;
} }
@@ -232,15 +257,29 @@ router.beforeEach(async (to, _from, next) => {
try { try {
// 加载动态路由 // 加载动态路由
await addDynamicRoutes(); await addDynamicRoutes();
// 路由加载完成后,重新导航到目标路由 console.log("当前完整路由表:", router.getRoutes());
next({ ...to, replace: true }); const redirect = to.query.redirect as string;
if (to.path === "/" || to.path === "/login") {
const redirect = to.query.redirect as string;
const firstPath = getFirstValidPath(userStore.routes);
const targetPath = (redirect && redirect !== '/') ? redirect : firstPath;
next({ path: targetPath, replace: true });
} else {
// 路由加载完成后,重新导航到目标路由
next({ ...to, replace: true });
}
} catch (error) { } catch (error) {
console.error("Route loading error:", error); console.error("Route loading error:", error);
next("/login"); next("/login");
} }
} else { } else {
// 路由已加载,直接放行 if (to.path === "/") {
next(); const firstPath = getFirstValidPath(userStore.routes);
next({ path: firstPath, replace: true });
} else {
next();
}
} }
}); });

View File

@@ -2,11 +2,16 @@ class TokenManager {
private static instance: TokenManager | null = null; private static instance: TokenManager | null = null;
private storage: Storage; private storage: Storage;
private constructor(storageType: 'localStorage' | 'sessionStorage' = 'localStorage') { private constructor(
this.storage = storageType === 'localStorage' ? localStorage : sessionStorage; storageType: "localStorage" | "sessionStorage" = "localStorage"
) {
this.storage =
storageType === "localStorage" ? localStorage : sessionStorage;
} }
public static getInstance(storageType: 'localStorage' | 'sessionStorage' = 'localStorage'): TokenManager { public static getInstance(
storageType: "localStorage" | "sessionStorage" = "localStorage"
): TokenManager {
if (!TokenManager.instance) { if (!TokenManager.instance) {
TokenManager.instance = new TokenManager(storageType); TokenManager.instance = new TokenManager(storageType);
} }
@@ -25,9 +30,13 @@ class TokenManager {
this.storage.removeItem(key); this.storage.removeItem(key);
} }
clearStorage(): void { clearStorage(): void {
this.storage.clear(); const PROTECT_PREFIX = "keep_";
Object.keys(this.storage).forEach((key) => {
if (!key.startsWith(PROTECT_PREFIX)) {
this.storage.removeItem(key);
}
});
} }
} }
export default TokenManager; export default TokenManager;