fix:登录增加记住密码 优化路由逻辑
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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 () => {
|
||||||
@@ -150,9 +173,11 @@ const addDynamicRoutes = async () => {
|
|||||||
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,16 +257,30 @@ router.beforeEach(async (to, _from, next) => {
|
|||||||
try {
|
try {
|
||||||
// 加载动态路由
|
// 加载动态路由
|
||||||
await addDynamicRoutes();
|
await addDynamicRoutes();
|
||||||
|
console.log("当前完整路由表:", router.getRoutes());
|
||||||
|
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 });
|
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 === "/") {
|
||||||
|
const firstPath = getFirstValidPath(userStore.routes);
|
||||||
|
next({ path: firstPath, replace: true });
|
||||||
|
} else {
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|||||||
@@ -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;
|
||||||
Reference in New Issue
Block a user