# 9.6 状态管理(Pinia) :::tip 概述 前端使用 Pinia 进行全局状态管理,核心 Store 包含用户信息、动态路由、项目配置等。 ::: ## Store 清单 | Store | 文件 | 说明 | |-------|------|------| | userStore | `store/modules/user.ts` | Token / 用户信息 / 权限列表 / 登录登出 | | asyncRouteStore | `store/modules/asyncRoute.ts` | 动态路由 / keep-alive 缓存 | | projectSettingStore | `store/modules/projectSetting.ts` | 项目配置 | | ossConfigStore | `store/modules/ossConfig.ts` | 云存储配置 | | designSettingStore | `store/modules/designSetting.ts` | 主题设计 | | lockscreenStore | `store/modules/lockscreen.ts` | 锁屏 | | tabsViewStore | `store/modules/tabsView.ts` | 标签页 | ## userStore 核心代码 ```typescript // ui/src/store/modules/user.ts import { ACCESS_TOKEN, CURRENT_USER, IS_LOCKSCREEN } from '@/store/mutation-types'; import { ResultEnum } from '@/enums/httpEnum'; export const useUserStore = defineStore({ id: 'app-user', state: (): IUserState => ({ token: Storage.get(ACCESS_TOKEN, ''), username: '', avatar: '', permissions: [], info: Storage.get(CURRENT_USER, {}), }), actions: { // 登录(key/code 为验证码参数;响应字段为 snake_case 的 access_token,见 8.6) async login(userInfo) { const response = await login(userInfo); const { code, data } = response; if (code === ResultEnum.SUCCESS) { const ex = 7 * 24 * 60 * 60 * 1000; storage.set(ACCESS_TOKEN, data.access_token, ex); // 仅存 access_token storage.set(IS_LOCKSCREEN, false); this.setToken(data.access_token); } return response; }, // 获取用户信息(含 roles / permissions / city) async GetInfo() { const res = await getUserInfo(); // GET /api/index/getUser this.setPermissions(res.permissions); this.setUserInfo(res); this.setAvatar(res.avatar); return res; }, // 登出(后端同时吊销 refresh_token) async logout() { await logout(); this.setPermissions([]); this.setUserInfo(''); storage.remove(ACCESS_TOKEN); storage.remove(CURRENT_USER); storage.clear(); }, }, }); ``` :::tip 权限与后端一致 `GetInfo` 拿到的 `permissions` 与 `Authenticate` 中间件鉴权用的是同一份数据(复用 `JwtService::getUserPermissions` 的 Redis 缓存)——超管为 `['*:*:*']`,普通用户为角色关联的 `menu.permission` 列表。 ::: ## 在组件中使用 :::tip Store 使用方式 - 在 `setup` 中:`const userStore = useUserStore()` - 在 `setup` 外:`const userStore = useUserStoreWidthOut()` ::: ```typescript import { useUserStore } from '@/store/modules/user'; const userStore = useUserStore(); // 获取用户信息 const username = userStore.username; const permissions = userStore.permissions; // 登录 await userStore.login({ username: 'admin', password: '123456', key, code }); // 登出 await userStore.logout(); ``` ## asyncRouteStore(动态路由) | 状态/方法 | 说明 | |------|------| | `getIsDynamicAddedRoute` | 动态路由是否已加载(守卫据此跳过重复生成) | | `generateRoutes(userInfo)` | 调用 `/api/index/getMenus` 生成路由表 | | `keepAliveComponents` | 页面级缓存组件名列表(标签页切换保留状态) | (生成细节见 [9.5 路由与动态菜单](/zh/frontend/router.html)。)