Files
rxthinkcmf-wiki/RXThinkCMF_Laravel13_NaiveVue/zh/frontend/store.md
T
2026-10-08 17:50:29 +08:00

107 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)。)