菜单布局等初步完成
This commit is contained in:
@@ -8,6 +8,7 @@ import { Module } from 'vuex';
|
||||
import { LoginDomain, SysMenu, SysPermission } from '@/types';
|
||||
import { authApi } from '@/apis/auth';
|
||||
import router from '@/router';
|
||||
import { getFirstAccessibleMenuUrl, buildMenuTree } from '@/utils/route-generator';
|
||||
|
||||
// State接口定义
|
||||
export interface AuthState {
|
||||
@@ -23,17 +24,48 @@ export interface AuthState {
|
||||
routesLoaded: boolean;
|
||||
}
|
||||
|
||||
// 从localStorage恢复状态的辅助函数
|
||||
function getStoredState(): Partial<AuthState> {
|
||||
try {
|
||||
const token = localStorage.getItem('token');
|
||||
const loginDomainStr = localStorage.getItem('loginDomain');
|
||||
const menusStr = localStorage.getItem('menus');
|
||||
const permissionsStr = localStorage.getItem('permissions');
|
||||
|
||||
return {
|
||||
token: token || null,
|
||||
loginDomain: loginDomainStr ? JSON.parse(loginDomainStr) : null,
|
||||
menus: menusStr ? JSON.parse(menusStr) : [],
|
||||
permissions: permissionsStr ? JSON.parse(permissionsStr) : [],
|
||||
routesLoaded: false, // 路由始终需要重新加载
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('从localStorage恢复状态失败:', error);
|
||||
return {
|
||||
token: null,
|
||||
loginDomain: null,
|
||||
menus: [],
|
||||
permissions: [],
|
||||
routesLoaded: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 认证模块
|
||||
const authModule: Module<AuthState, any> = {
|
||||
namespaced: true,
|
||||
|
||||
state: (): AuthState => ({
|
||||
loginDomain: null,
|
||||
token: localStorage.getItem('token') || null,
|
||||
menus: [],
|
||||
permissions: [],
|
||||
routesLoaded: false,
|
||||
}),
|
||||
state: (): AuthState => {
|
||||
// 从localStorage恢复状态
|
||||
const storedState = getStoredState();
|
||||
return {
|
||||
loginDomain: storedState.loginDomain || null,
|
||||
token: storedState.token || null,
|
||||
menus: storedState.menus || [],
|
||||
permissions: storedState.permissions || [],
|
||||
routesLoaded: false,
|
||||
};
|
||||
},
|
||||
|
||||
getters: {
|
||||
// 是否已登录
|
||||
@@ -85,10 +117,19 @@ const authModule: Module<AuthState, any> = {
|
||||
state.menus = loginDomain.menus || [];
|
||||
state.permissions = loginDomain.permissions || [];
|
||||
|
||||
// 存储token到localStorage
|
||||
// 持久化到localStorage
|
||||
if (state.token) {
|
||||
localStorage.setItem('token', state.token);
|
||||
}
|
||||
if (loginDomain) {
|
||||
localStorage.setItem('loginDomain', JSON.stringify(loginDomain));
|
||||
}
|
||||
if (state.menus.length > 0) {
|
||||
localStorage.setItem('menus', JSON.stringify(state.menus));
|
||||
}
|
||||
if (state.permissions.length > 0) {
|
||||
localStorage.setItem('permissions', JSON.stringify(state.permissions));
|
||||
}
|
||||
},
|
||||
|
||||
// 设置Token
|
||||
@@ -104,11 +145,17 @@ const authModule: Module<AuthState, any> = {
|
||||
// 设置菜单
|
||||
SET_MENUS(state, menus: SysMenu[]) {
|
||||
state.menus = menus;
|
||||
if (menus.length > 0) {
|
||||
localStorage.setItem('menus', JSON.stringify(menus));
|
||||
}
|
||||
},
|
||||
|
||||
// 设置权限
|
||||
SET_PERMISSIONS(state, permissions: SysPermission[]) {
|
||||
state.permissions = permissions;
|
||||
if (permissions.length > 0) {
|
||||
localStorage.setItem('permissions', JSON.stringify(permissions));
|
||||
}
|
||||
},
|
||||
|
||||
// 设置路由加载状态
|
||||
@@ -123,13 +170,18 @@ const authModule: Module<AuthState, any> = {
|
||||
state.menus = [];
|
||||
state.permissions = [];
|
||||
state.routesLoaded = false;
|
||||
|
||||
// 清除localStorage
|
||||
localStorage.removeItem('token');
|
||||
localStorage.removeItem('loginDomain');
|
||||
localStorage.removeItem('menus');
|
||||
localStorage.removeItem('permissions');
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
// 登录
|
||||
async login({ commit, dispatch }, loginParam) {
|
||||
async login({ commit, dispatch, state }, loginParam) {
|
||||
try {
|
||||
const loginDomain = await authApi.login(loginParam);
|
||||
|
||||
@@ -138,8 +190,14 @@ const authModule: Module<AuthState, any> = {
|
||||
|
||||
// 生成动态路由
|
||||
await dispatch('generateRoutes');
|
||||
console.log(router.getRoutes())
|
||||
// 获取第一个可访问的菜单URL,用于登录后跳转
|
||||
const firstMenuUrl = getFirstAccessibleMenuUrl(state.menus);
|
||||
|
||||
return Promise.resolve(loginDomain);
|
||||
return Promise.resolve({
|
||||
loginDomain,
|
||||
redirectUrl: firstMenuUrl || '/home' // 如果没有菜单,跳转到首页
|
||||
});
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
@@ -163,11 +221,49 @@ const authModule: Module<AuthState, any> = {
|
||||
}
|
||||
},
|
||||
|
||||
// 恢复登录状态(页面刷新时使用)
|
||||
async restoreAuth({ state, commit, dispatch }) {
|
||||
try {
|
||||
// 如果没有token,无法恢复
|
||||
if (!state.token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果已经有完整的登录信息,直接生成路由
|
||||
if (state.loginDomain && state.menus.length > 0) {
|
||||
console.log('从localStorage恢复登录状态');
|
||||
await dispatch('generateRoutes');
|
||||
return true;
|
||||
}
|
||||
|
||||
// 如果只有token,需要从后端重新获取用户信息
|
||||
// console.log('Token存在,重新获取用户信息');
|
||||
// const loginDomain = await authApi.getUserInfo(); // 需要后端提供这个接口
|
||||
|
||||
// commit('SET_LOGIN_DOMAIN', loginDomain);
|
||||
// await dispatch('generateRoutes');
|
||||
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('恢复登录状态失败:', error);
|
||||
// 恢复失败,清除认证信息
|
||||
commit('CLEAR_AUTH');
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// 生成动态路由
|
||||
async generateRoutes({ state, commit }) {
|
||||
try {
|
||||
// 如果路由已经加载,避免重复生成
|
||||
if (state.routesLoaded) {
|
||||
console.log('路由已加载,跳过生成');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state.menus || state.menus.length === 0) {
|
||||
console.warn('用户菜单为空,无法生成路由');
|
||||
commit('SET_ROUTES_LOADED', true); // 标记为已加载,避免重复尝试
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -206,56 +302,6 @@ const authModule: Module<AuthState, any> = {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 构建菜单树结构
|
||||
* @param menus 菜单列表
|
||||
* @returns 菜单树
|
||||
*/
|
||||
function buildMenuTree(menus: SysMenu[]): SysMenu[] {
|
||||
if (!menus || menus.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const menuMap = new Map<string, SysMenu>();
|
||||
const rootMenus: SysMenu[] = [];
|
||||
|
||||
// 创建菜单映射
|
||||
menus.forEach(menu => {
|
||||
if (menu.menuID) {
|
||||
menuMap.set(menu.menuID, { ...menu, children: [] });
|
||||
}
|
||||
});
|
||||
|
||||
// 构建树结构
|
||||
menus.forEach(menu => {
|
||||
const menuNode = menuMap.get(menu.menuID!);
|
||||
if (!menuNode) return;
|
||||
|
||||
if (!menu.parentID || menu.parentID === '0') {
|
||||
// 根菜单
|
||||
rootMenus.push(menuNode);
|
||||
} else {
|
||||
// 子菜单
|
||||
const parent = menuMap.get(menu.parentID);
|
||||
if (parent) {
|
||||
parent.children = parent.children || [];
|
||||
parent.children.push(menuNode);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 按orderNum排序
|
||||
const sortMenus = (menus: SysMenu[]): SysMenu[] => {
|
||||
return menus
|
||||
.sort((a, b) => (a.orderNum || 0) - (b.orderNum || 0))
|
||||
.map(menu => ({
|
||||
...menu,
|
||||
children: menu.children ? sortMenus(menu.children) : []
|
||||
}));
|
||||
};
|
||||
|
||||
return sortMenus(rootMenus);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置路由
|
||||
|
||||
Reference in New Issue
Block a user