# Vuex 用户状态完整性优化说明 ## 问题背景 在之前的首页 userId 获取问题中,发现 Vuex 的 user 模块只存储了部分用户信息(name、avatar、roles、permissions),导致页面中无法直接从 `state.user` 获取 userId 和 deptId 等关键信息。 ## 问题分析 ### 后端接口返回的数据 [`/getInfo`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\ruoyi-admin\src\main\java\com\ruoyi\web\controller\system\SysLoginController.java#L63-L82) 接口返回的完整数据结构: ```json { "code": 200, "msg": "操作成功", "user": { "userId": 1, "deptId": 103, "userName": "admin", "nickName": "管理员", "email": "admin@163.com", "phonenumber": "15888888888", "sex": "1", "avatar": "", "status": "0", "delFlag": "0", "loginIp": "127.0.0.1", "loginDate": "2023-05-15 10:00:00", "dept": { "deptId": 103, "parentId": 101, "deptName": "研发部门" } }, "roles": ["admin"], "permissions": ["*:*:*"] } ``` ### 原 Vuex State 结构 **修改前:** ```javascript state: { token: getToken(), name: storage.get(constant.name), // ✅ 存储 avatar: storage.get(constant.avatar), // ✅ 存储 roles: storage.get(constant.roles), // ✅ 存储 permissions: storage.get(constant.permissions) // ✅ 存储 // ❌ 缺少 userId // ❌ 缺少 deptId } ``` ### 导致的问题 1. **无法直接获取 userId** ```javascript // ❌ 错误:currentUser.userId 为 undefined computed: { ...mapState({ currentUser: state => state.user }) } // 使用时 this.currentUser.userId // undefined ``` 2. **无法直接获取 deptId** ```javascript // ❌ 错误:currentUser.deptId 为 undefined const deptId = this.currentUser.deptId // undefined ``` 3. **依赖问题** - 需要额外调用 API 获取用户信息 - 增加了不必要的网络请求 - 代码复杂度增加 ## 解决方案 ### 1. 修改 Vuex State 结构 **文件:** [`app/store/modules/user.js`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\app\store\modules\user.js) **修改前:** ```javascript state: { token: getToken(), name: storage.get(constant.name), avatar: storage.get(constant.avatar), roles: storage.get(constant.roles), permissions: storage.get(constant.permissions) } ``` **修改后:** ```javascript state: { token: getToken(), userId: storage.get(constant.userId), // ✅ 新增 name: storage.get(constant.name), avatar: storage.get(constant.avatar), roles: storage.get(constant.roles), permissions: storage.get(constant.permissions), deptId: storage.get(constant.deptId) // ✅ 新增 } ``` ### 2. 添加新的 Mutations **修改前:** ```javascript mutations: { SET_TOKEN: (state, token) => { state.token = token }, SET_NAME: (state, name) => { state.name = name storage.set(constant.name, name) }, SET_AVATAR: (state, avatar) => { state.avatar = avatar storage.set(constant.avatar, avatar) }, SET_ROLES: (state, roles) => { state.roles = roles storage.set(constant.roles, roles) }, SET_PERMISSIONS: (state, permissions) => { state.permissions = permissions storage.set(constant.permissions, permissions) } } ``` **修改后:** ```javascript mutations: { SET_TOKEN: (state, token) => { state.token = token }, SET_USER_ID: (state, userId) => { // ✅ 新增 state.userId = userId storage.set(constant.userId, userId) }, SET_NAME: (state, name) => { state.name = name storage.set(constant.name, name) }, SET_AVATAR: (state, avatar) => { state.avatar = avatar storage.set(constant.avatar, avatar) }, SET_ROLES: (state, roles) => { state.roles = roles storage.set(constant.roles, roles) }, SET_PERMISSIONS: (state, permissions) => { state.permissions = permissions storage.set(constant.permissions, permissions) }, SET_DEPT_ID: (state, deptId) => { // ✅ 新增 state.deptId = deptId storage.set(constant.deptId, deptId) } } ``` ### 3. 更新 GetInfo Action **修改前:** ```javascript GetInfo({ commit, state }) { return new Promise((resolve, reject) => { getInfo().then(res => { const user = res.user const avatar = (user == null || user.avatar == "" || user.avatar == null) ? require("@/static/images/profile.jpg") : baseUrl + user.avatar const username = (user == null || user.userName == "" || user.userName == null) ? "" : user.userName if (res.roles && res.roles.length > 0) { commit('SET_ROLES', res.roles) commit('SET_PERMISSIONS', res.permissions) } else { commit('SET_ROLES', ['ROLE_DEFAULT']) } commit('SET_NAME', username) commit('SET_AVATAR', avatar) resolve(res) }).catch(error => { reject(error) }) }) } ``` **修改后:** ```javascript GetInfo({ commit, state }) { return new Promise((resolve, reject) => { getInfo().then(res => { const user = res.user const avatar = (user == null || user.avatar == "" || user.avatar == null) ? require("@/static/images/profile.jpg") : baseUrl + user.avatar const username = (user == null || user.userName == "" || user.userName == null) ? "" : user.userName const userId = (user == null || user.userId == null) ? null : user.userId // ✅ 新增 const deptId = (user == null || user.deptId == null) ? null : user.deptId // ✅ 新增 if (res.roles && res.roles.length > 0) { commit('SET_ROLES', res.roles) commit('SET_PERMISSIONS', res.permissions) } else { commit('SET_ROLES', ['ROLE_DEFAULT']) } commit('SET_USER_ID', userId) // ✅ 新增 commit('SET_NAME', username) commit('SET_AVATAR', avatar) commit('SET_DEPT_ID', deptId) // ✅ 新增 resolve(res) }).catch(error => { reject(error) }) }) } ``` ### 4. 更新 Constant 常量 **文件:** [`app/utils/constant.js`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\app\utils\constant.js) **修改前:** ```javascript const constant = { avatar: 'vuex_avatar', name: 'vuex_name', roles: 'vuex_roles', permissions: 'vuex_permissions' } ``` **修改后:** ```javascript const constant = { userId: 'vuex_userId', // ✅ 新增 avatar: 'vuex_avatar', name: 'vuex_name', roles: 'vuex_roles', permissions: 'vuex_permissions', deptId: 'vuex_deptId' // ✅ 新增 } ``` ## 优化效果 ### 1. 页面使用更简洁 **修改前:** ```javascript // ❌ 需要额外调用 API 获取用户信息 methods: { loadData() { getUserProfile().then(response => { const userId = response.data.userId // 使用 userId... }) } } ``` **修改后:** ```javascript // ✅ 直接从 Vuex 获取 computed: { ...mapState({ currentUser: state => state.user }) }, methods: { loadData() { const userId = this.currentUser.userId const deptId = this.currentUser.deptId // 直接使用 userId 和 deptId... } } ``` ### 2. 减少网络请求 - ✅ 无需额外调用 API 获取用户信息 - ✅ 减少服务器压力 - ✅ 提高页面响应速度 ### 3. 数据持久化 ```javascript // ✅ 数据会自动存储到本地存储 storage.set(constant.userId, userId) storage.set(constant.deptId, deptId) // ✅ 页面刷新后可以从本地存储恢复 state: { userId: storage.get(constant.userId), deptId: storage.get(constant.deptId) } ``` ## 使用示例 ### 示例1:首页获取用户信息 **文件:** [`app/pages/index.vue`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\app\pages\index.vue) ```javascript export default { computed: { ...mapState({ userName: state => state.user.name, currentUser: state => state.user }) }, methods: { loadRunningTasks() { const userId = this.currentUser.userId // ✅ 直接获取 if (!userId) { console.error('用户未登录') return } const queryParams = { assigneeId: userId, // ... } // 加载任务列表... } } } ``` ### 示例2:绑定车辆页面 **文件:** [`app/pages/bind-vehicle.vue`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\app\pages\bind-vehicle.vue) ```javascript export default { computed: { ...mapState({ currentUser: state => state.user }) }, methods: { loadVehicleList() { const deptId = this.currentUser.deptId // ✅ 直接获取部门ID listAvailableVehicles(deptId, 'GENERAL').then(response => { // 处理车辆列表... }) }, bindVehicle() { const userId = this.currentUser.userId // ✅ 直接获取用户ID bindVehicleToUser(userId, this.selectedVehicleId).then(response => { // 处理绑定结果... }) } } } ``` ### 示例3:个人中心 **文件:** [`app/pages/mine/index.vue`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\app\pages\mine\index.vue) ```javascript export default { computed: { ...mapState({ currentUser: state => state.user }) }, methods: { loadUserInfo() { const userId = this.currentUser.userId // ✅ 直接获取 getUserBoundVehicle(userId).then(response => { // 处理用户绑定车辆信息... }) } } } ``` ## 数据流图 ```mermaid graph TD A[用户登录] --> B[调用 /login 接口] B --> C[获取 token] C --> D[调用 GetInfo Action] D --> E[请求 /getInfo 接口] E --> F[返回完整用户信息] F --> G[提取 userId, deptId 等] G --> H[存储到 Vuex State] H --> I[持久化到 LocalStorage] I --> J[页面可直接使用] K[页面刷新] --> L[从 LocalStorage 恢复] L --> J ``` ## State 数据结构 ### 完整的 state.user 结构 ```javascript { token: "eyJhbGciOiJIUzUxMiJ9...", userId: 1, // ✅ 用户ID name: "admin", // 用户名 avatar: "/profile/avatar.jpg", // 头像 roles: ["admin"], // 角色列表 permissions: ["*:*:*"], // 权限列表 deptId: 103 // ✅ 部门ID } ``` ### LocalStorage 存储 ```javascript { "vuex_token": "eyJhbGciOiJIUzUxMiJ9...", "vuex_userId": 1, // ✅ 持久化 "vuex_name": "admin", "vuex_avatar": "/profile/avatar.jpg", "vuex_roles": ["admin"], "vuex_permissions": ["*:*:*"], "vuex_deptId": 103 // ✅ 持久化 } ``` ## 注意事项 ### 1. 登录状态检查 在使用 userId 和 deptId 之前,务必检查是否存在: ```javascript const userId = this.currentUser.userId if (!userId) { console.error('用户未登录') return } ``` ### 2. 数据同步 - ✅ 登录后会自动同步 - ✅ 退出登录会自动清除 - ✅ 页面刷新会从本地存储恢复 ### 3. 退出登录清理 LogOut Action 中的 `storage.clean()` 会清除所有存储的用户信息。 ## 兼容性 ### 向后兼容 - ✅ 原有的 [name](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\ruoyi-ui\vue.config.js#L9-L9)、[avatar](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\ruoyi-common\src\main\java\com\ruoyi\common\core\domain\entity\SysUser.java#L52-L52)、[roles](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\app\plugins\auth.js#L16-L16)、[permissions](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\app\plugins\auth.js#L4-L4) 使用方式不变 - ✅ 新增的 userId 和 deptId 不影响现有功能 - ✅ 所有页面无需修改即可继续使用 ### 渐进式升级 可以逐步将各页面中重复的用户信息获取逻辑替换为从 Vuex 获取。 ## 测试验证 ### 功能测试 1. **登录功能** - ✅ 登录成功后 userId 和 deptId 正确存储 - ✅ 数据持久化到 LocalStorage 2. **页面刷新** - ✅ 刷新后 userId 和 deptId 从 LocalStorage 恢复 - ✅ 页面可以正常使用用户信息 3. **退出登录** - ✅ 退出后清除所有用户信息 - ✅ LocalStorage 中的数据被清空 4. **各页面使用** - ✅ 首页可以获取 userId 加载任务 - ✅ 绑定车辆页面可以获取 userId 和 deptId - ✅ 个人中心可以获取 userId ## 相关文件 ### 修改的文件 1. [`app/store/modules/user.js`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\app\store\modules\user.js) - Vuex 用户模块 2. [`app/utils/constant.js`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\app\utils\constant.js) - 常量定义 ### 受益的页面 1. [`app/pages/index.vue`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\app\pages\index.vue) - 首页 2. [`app/pages/bind-vehicle.vue`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\app\pages\bind-vehicle.vue) - 绑定车辆 3. [`app/pages/mine/index.vue`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\app\pages\mine\index.vue) - 个人中心 4. [`app/pages/task/create.vue`](file://d:\project\急救转运\code\Api\RuoYi-Vue-master\app\pages\task\create.vue) - 创建任务 ### 相关文档 - [首页用户ID获取问题修复.md](./首页用户ID获取问题修复.md) - [车辆绑定解绑功能说明.md](./车辆绑定解绑功能说明.md) ## 总结 通过本次优化,Vuex 用户状态管理更加完整,主要改进: 1. ✅ **完整性**:存储了 userId 和 deptId 等关键信息 2. ✅ **持久化**:数据会自动保存到 LocalStorage 3. ✅ **便捷性**:页面可以直接从 Vuex 获取用户信息,无需额外 API 调用 4. ✅ **一致性**:所有页面使用统一的方式获取用户信息 5. ✅ **性能**:减少了不必要的网络请求 6. ✅ **兼容性**:向后兼容,不影响现有功能 **核心价值**: - 简化了代码逻辑 - 提高了开发效率 - 减少了维护成本 - 提升了用户体验 ## 版本历史 | 版本 | 日期 | 修改内容 | 修改人 | |------|------|---------|--------| | 1.0 | 2025-10-15 | Vuex 用户状态完整性优化 | - |