前端启动成功
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import { createStore } from "vuex";
|
||||
import authModule from './modules/auth';
|
||||
|
||||
export default createStore({
|
||||
state: {},
|
||||
getters: {},
|
||||
mutations: {},
|
||||
actions: {},
|
||||
modules: {},
|
||||
modules: {
|
||||
auth: authModule
|
||||
},
|
||||
});
|
||||
|
||||
270
schoolNewsWeb/src/store/modules/auth.ts
Normal file
270
schoolNewsWeb/src/store/modules/auth.ts
Normal file
@@ -0,0 +1,270 @@
|
||||
/**
|
||||
* @description 认证相关状态管理
|
||||
* @author yslg
|
||||
* @since 2025-10-07
|
||||
*/
|
||||
|
||||
import { Module } from 'vuex';
|
||||
import { LoginDomain, SysMenu, SysPermission } from '@/types';
|
||||
import { authApi } from '@/apis/auth';
|
||||
import router from '@/router';
|
||||
|
||||
// State接口定义
|
||||
export interface AuthState {
|
||||
// 用户信息
|
||||
loginDomain: LoginDomain | null;
|
||||
// 用户Token
|
||||
token: string | null;
|
||||
// 用户菜单
|
||||
menus: SysMenu[];
|
||||
// 用户权限
|
||||
permissions: SysPermission[];
|
||||
// 动态路由是否已加载
|
||||
routesLoaded: boolean;
|
||||
}
|
||||
|
||||
// 认证模块
|
||||
const authModule: Module<AuthState, any> = {
|
||||
namespaced: true,
|
||||
|
||||
state: (): AuthState => ({
|
||||
loginDomain: null,
|
||||
token: localStorage.getItem('token') || null,
|
||||
menus: [],
|
||||
permissions: [],
|
||||
routesLoaded: false,
|
||||
}),
|
||||
|
||||
getters: {
|
||||
// 是否已登录
|
||||
isAuthenticated: (state): boolean => {
|
||||
return !!(state.token && state.loginDomain);
|
||||
},
|
||||
|
||||
// 获取用户信息
|
||||
userInfo: (state) => {
|
||||
return state.loginDomain?.user || null;
|
||||
},
|
||||
|
||||
// 获取用户角色
|
||||
userRoles: (state) => {
|
||||
return state.loginDomain?.roles || [];
|
||||
},
|
||||
|
||||
// 检查是否有指定权限
|
||||
hasPermission: (state) => (permissionCode: string): boolean => {
|
||||
if (!state.permissions || state.permissions.length === 0) {
|
||||
return false;
|
||||
}
|
||||
return state.permissions.some(permission =>
|
||||
permission.code === permissionCode
|
||||
);
|
||||
},
|
||||
|
||||
// 检查是否有任意一个权限
|
||||
hasAnyPermission: (state, getters) => (permissionCodes: string[]): boolean => {
|
||||
return permissionCodes.some(code => getters.hasPermission(code));
|
||||
},
|
||||
|
||||
// 检查是否有所有权限
|
||||
hasAllPermissions: (state, getters) => (permissionCodes: string[]): boolean => {
|
||||
return permissionCodes.every(code => getters.hasPermission(code));
|
||||
},
|
||||
|
||||
// 获取菜单树结构
|
||||
menuTree: (state): SysMenu[] => {
|
||||
return buildMenuTree(state.menus);
|
||||
}
|
||||
},
|
||||
|
||||
mutations: {
|
||||
// 设置登录信息
|
||||
SET_LOGIN_DOMAIN(state, loginDomain: LoginDomain) {
|
||||
state.loginDomain = loginDomain;
|
||||
state.token = loginDomain.token || null;
|
||||
state.menus = loginDomain.menus || [];
|
||||
state.permissions = loginDomain.permissions || [];
|
||||
|
||||
// 存储token到localStorage
|
||||
if (state.token) {
|
||||
localStorage.setItem('token', state.token);
|
||||
}
|
||||
},
|
||||
|
||||
// 设置Token
|
||||
SET_TOKEN(state, token: string | null) {
|
||||
state.token = token;
|
||||
if (token) {
|
||||
localStorage.setItem('token', token);
|
||||
} else {
|
||||
localStorage.removeItem('token');
|
||||
}
|
||||
},
|
||||
|
||||
// 设置菜单
|
||||
SET_MENUS(state, menus: SysMenu[]) {
|
||||
state.menus = menus;
|
||||
},
|
||||
|
||||
// 设置权限
|
||||
SET_PERMISSIONS(state, permissions: SysPermission[]) {
|
||||
state.permissions = permissions;
|
||||
},
|
||||
|
||||
// 设置路由加载状态
|
||||
SET_ROUTES_LOADED(state, loaded: boolean) {
|
||||
state.routesLoaded = loaded;
|
||||
},
|
||||
|
||||
// 清除认证信息
|
||||
CLEAR_AUTH(state) {
|
||||
state.loginDomain = null;
|
||||
state.token = null;
|
||||
state.menus = [];
|
||||
state.permissions = [];
|
||||
state.routesLoaded = false;
|
||||
localStorage.removeItem('token');
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
// 登录
|
||||
async login({ commit, dispatch }, loginParam) {
|
||||
try {
|
||||
const loginDomain = await authApi.login(loginParam);
|
||||
|
||||
// 保存登录信息
|
||||
commit('SET_LOGIN_DOMAIN', loginDomain);
|
||||
|
||||
// 生成动态路由
|
||||
await dispatch('generateRoutes');
|
||||
|
||||
return Promise.resolve(loginDomain);
|
||||
} catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
},
|
||||
|
||||
// 登出
|
||||
async logout({ commit }) {
|
||||
try {
|
||||
await authApi.logout();
|
||||
} catch (error) {
|
||||
console.error('登出接口调用失败:', error);
|
||||
} finally {
|
||||
// 清除认证信息
|
||||
commit('CLEAR_AUTH');
|
||||
|
||||
// 重置路由
|
||||
resetRouter();
|
||||
|
||||
// 跳转到登录页
|
||||
router.push('/login');
|
||||
}
|
||||
},
|
||||
|
||||
// 生成动态路由
|
||||
async generateRoutes({ state, commit }) {
|
||||
try {
|
||||
if (!state.menus || state.menus.length === 0) {
|
||||
console.warn('用户菜单为空,无法生成路由');
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据菜单生成路由
|
||||
const { generateRoutes } = await import('@/utils/route-generator');
|
||||
const routes = generateRoutes(state.menus);
|
||||
|
||||
// 添加路由到router
|
||||
routes.forEach((route: any) => {
|
||||
router.addRoute(route);
|
||||
});
|
||||
|
||||
// 标记路由已加载
|
||||
commit('SET_ROUTES_LOADED', true);
|
||||
|
||||
console.log('动态路由生成完成', routes);
|
||||
} catch (error) {
|
||||
console.error('生成动态路由失败:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
// 刷新Token
|
||||
async refreshToken({ commit }) {
|
||||
try {
|
||||
const newToken = await authApi.refreshToken();
|
||||
commit('SET_TOKEN', newToken);
|
||||
return Promise.resolve(newToken);
|
||||
} catch (error) {
|
||||
// 刷新失败,清除认证信息
|
||||
commit('CLEAR_AUTH');
|
||||
router.push('/login');
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 构建菜单树结构
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置路由
|
||||
*/
|
||||
function resetRouter() {
|
||||
// 这里需要根据实际路由配置来重置
|
||||
// 由于Vue Router 4没有直接的重置方法,我们需要重新创建router实例
|
||||
// 或者记录动态添加的路由并逐个移除
|
||||
location.reload(); // 临时方案,后续可以优化
|
||||
}
|
||||
|
||||
export default authModule;
|
||||
Reference in New Issue
Block a user