# Store 状态管理 :::tip 说明 前端使用 Pinia 进行状态管理,核心模块包括 `user`(用户信息与权限)、`asyncRoute`(动态路由与菜单)、`projectSetting`(项目配置)、`designSetting`(主题设计)等。 ::: ## Pinia 配置 ```typescript // src/store/index.ts import { createPinia } from 'pinia'; const pinia = createPinia(); export default pinia; ``` Store 模块位于 `src/store/modules/` 目录: ``` src/store/modules/ ├── user.ts # 用户登录状态、Token、用户信息、权限列表 ├── asyncRoute.ts # 动态路由生成、菜单管理、组件缓存 ├── projectSetting.ts # 项目配置(权限模式、水印、动画等) ├── designSetting.ts # 主题色、深色模式 ├── lockscreen.ts # 锁屏状态 ├── tabsView.ts # 标签页管理 └── ossConfig.ts # OSS 配置 ``` ## User Store 管理用户登录状态、Token、用户信息和权限列表,是核心 Store: ```typescript // src/store/modules/user.ts import { defineStore } from 'pinia'; import { createStorage } from '@/utils/Storage'; import { ACCESS_TOKEN, CURRENT_USER } from '@/store/mutation-types'; import { getUserInfo, login, logout } from '@/api/common/user'; const Storage = createStorage({ storage: localStorage }); export interface IUserState { token: string; username: string; welcome: string; avatar: string; permissions: any[]; info: any; } export const useUserStore = defineStore({ id: 'app-user', state: (): IUserState => ({ token: Storage.get(ACCESS_TOKEN, ''), // 从 localStorage 恢复 token username: '', welcome: '', avatar: '', permissions: [], info: Storage.get(CURRENT_USER, {}), // 从 localStorage 恢复用户信息 }), getters: { getToken(): string { return this.token; }, getPermissions(): [any][] { return this.permissions; }, getUserInfo(): object { return this.info; }, }, actions: { // 登录 async login(userInfo) { const response = await login(userInfo); const { code, data } = response; if (code === ResultEnum.SUCCESS) { const ex = 7 * 24 * 60 * 60 * 1000; // 7 天过期 storage.set(ACCESS_TOKEN, data.access_token, ex); this.setToken(data.access_token); } return Promise.resolve(response); }, // 获取用户信息 GetInfo() { return new Promise((resolve, reject) => { getUserInfo().then((res) => { if (res.permissions && res.permissions.length) { this.setPermissions(res.permissions); } this.setUserInfo(res); this.setAvatar(res.avatar); resolve(res); }).catch(reject); }); }, // 登出 async logout() { return new Promise((resolve, reject) => { logout().then(() => { this.setPermissions([]); this.setUserInfo(''); storage.remove(ACCESS_TOKEN); storage.remove(CURRENT_USER); storage.clear(); resolve(''); }).catch(reject); }); }, }, }); ``` ### Token 存储机制 Token 通过 `Storage` 工具类存储在 `localStorage` 中,键名为 `ACCESS-TOKEN`,自动大写转换,支持 7 天过期时间: ```typescript // src/utils/Storage.ts export const createStorage = ({ prefixKey = '', storage = localStorage } = {}) => { const Storage = class { set(key: string, value: any, expire: number | null = DEFAULT_CACHE_TIME) { const stringData = JSON.stringify({ value, expire: expire !== null ? Date.now() + expire : null, }); this.storage.setItem(this.getKey(key), stringData); } get(key: string, def: any = null) { const item = this.storage.getItem(this.getKey(key)); if (item) { const data = JSON.parse(item); const { value, expire } = data; if (expire === null || expire >= Date.now()) return value; this.remove(key); // 过期则删除 } return def; } }; return new Storage(); }; export const storage = createStorage(); ``` ## AsyncRoute Store 管理动态路由和菜单,是路由系统的核心: ```typescript // src/store/modules/asyncRoute.ts export const useAsyncRouteStore = defineStore({ id: 'app-async-route', state: (): IAsyncRouteState => ({ menus: [], // 菜单列表 routers: constantRouter, // 静态路由 addRouters: [], // 动态路由 keepAliveComponents: [], // 需要缓存的组件名 isDynamicAddedRoute: false, // 路由是否已添加 }), actions: { async generateRoutes(data) { const { getPermissionMode } = useProjectSetting(); const permissionMode = unref(getPermissionMode); let accessedRouters; if (permissionMode === 'BACK') { // 后端控制模式:从后端获取菜单生成路由 accessedRouters = await generatorDynamicRouter(); } else { // 前端控制模式:根据权限过滤静态路由表 accessedRouters = filter(asyncRoutes, routeFilter); } this.setRouters(accessedRouters); this.setMenus(accessedRouters); return toRaw(accessedRouters); }, setRouters(routers) { this.addRouters = routers; this.routers = constantRouter.concat(routers); }, setMenus(menus) { this.menus = menus; }, setDynamicAddedRoute(added: boolean) { this.isDynamicAddedRoute = added; }, }, }); ``` ## Store 间协作 登录流程中 Store 协作: ```typescript // 路由守卫中的调用(router-guards.ts) const userStore = useUserStoreWidthOut(); const asyncRouteStore = useAsyncRouteStoreWidthOut(); // 1. 获取用户信息(设置 permissions) const userInfo = await userStore.GetInfo(); // 2. 根据用户信息生成动态路由 const routes = await asyncRouteStore.generateRoutes(userInfo); // 3. 动态添加路由 routes.forEach((item) => router.addRoute(item)); ``` ## 使用方式 在组件中使用 store: ```vue ``` 在 setup 外使用 store(需要传入 pinia 实例): ```typescript import { store } from '@/store'; import { useUserStore } from '@/store/modules/user'; export function useUserStoreWidthOut() { return useUserStore(store); } ``` :::tip 温馨提示 Token 通过 `Storage` 工具类管理,支持自动过期(默认 7 天)。退出登录时 `storage.clear()` 会清除所有 localStorage 数据。权限列表 `permissions` 在 `GetInfo` 时从后端获取,存储在 user store 中供 `v-perm` 指令使用。 ::: ## 总结 Pinia 状态管理包含 user(登录与权限)、asyncRoute(动态路由与菜单)、projectSetting(项目配置)等核心模块。user store 管理 Token 和权限列表,asyncRoute store 管理动态路由生成和组件缓存。Store 之间通过路由守卫协调工作,完成登录 → 获取信息 → 生成路由 → 挂载应用的完整流程。