编辑 | blame | 历史 | 原始文档

Vuex 用户状态完整性优化说明

问题背景

在之前的首页 userId 获取问题中,发现 Vuex 的 user 模块只存储了部分用户信息(name、avatar、roles、permissions),导致页面中无法直接从 state.user 获取 userId 和 deptId 等关键信息。

问题分析

后端接口返回的数据

/getInfo 接口返回的完整数据结构:

{
  "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
```

  1. 无法直接获取 deptId
    javascript // ❌ 错误:currentUser.deptId 为 undefined const deptId = this.currentUser.deptId // undefined

  2. 依赖问题

  • 需要额外调用 API 获取用户信息
  • 增加了不必要的网络请求
  • 代码复杂度增加

解决方案

1. 修改 Vuex State 结构

文件: 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

修改前:
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. 数据持久化

// ✅ 数据会自动存储到本地存储
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

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

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

export default {
  computed: {
    ...mapState({
      currentUser: state => state.user
    })
  },
  
  methods: {
    loadUserInfo() {
      const userId = this.currentUser.userId  // ✅ 直接获取
      getUserBoundVehicle(userId).then(response => {
        // 处理用户绑定车辆信息...
      })
    }
  }
}

数据流图

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 结构

{
  token: "eyJhbGciOiJIUzUxMiJ9...",
  userId: 1,                    // ✅ 用户ID
  name: "admin",                // 用户名
  avatar: "/profile/avatar.jpg", // 头像
  roles: ["admin"],             // 角色列表
  permissions: ["*:*:*"],       // 权限列表
  deptId: 103                   // ✅ 部门ID
}

LocalStorage 存储

{
  "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 之前,务必检查是否存在:

const userId = this.currentUser.userId
if (!userId) {
  console.error('用户未登录')
  return
}

2. 数据同步

  • ✅ 登录后会自动同步
  • ✅ 退出登录会自动清除
  • ✅ 页面刷新会从本地存储恢复

3. 退出登录清理

LogOut Action 中的 storage.clean() 会清除所有存储的用户信息。

兼容性

向后兼容

  • ✅ 原有的 nameavatarrolespermissions 使用方式不变
  • ✅ 新增的 userId 和 deptId 不影响现有功能
  • ✅ 所有页面无需修改即可继续使用

渐进式升级

可以逐步将各页面中重复的用户信息获取逻辑替换为从 Vuex 获取。

测试验证

功能测试

  1. 登录功能
  • ✅ 登录成功后 userId 和 deptId 正确存储
  • ✅ 数据持久化到 LocalStorage
  1. 页面刷新
  • ✅ 刷新后 userId 和 deptId 从 LocalStorage 恢复
  • ✅ 页面可以正常使用用户信息
  1. 退出登录
  • ✅ 退出后清除所有用户信息
  • ✅ LocalStorage 中的数据被清空
  1. 各页面使用
  • ✅ 首页可以获取 userId 加载任务
  • ✅ 绑定车辆页面可以获取 userId 和 deptId
  • ✅ 个人中心可以获取 userId

相关文件

修改的文件

  1. app/store/modules/user.js - Vuex 用户模块
  2. app/utils/constant.js - 常量定义

受益的页面

  1. app/pages/index.vue - 首页
  2. app/pages/bind-vehicle.vue - 绑定车辆
  3. app/pages/mine/index.vue - 个人中心
  4. app/pages/task/create.vue - 创建任务

相关文档

总结

通过本次优化,Vuex 用户状态管理更加完整,主要改进:

  1. 完整性:存储了 userId 和 deptId 等关键信息
  2. 持久化:数据会自动保存到 LocalStorage
  3. 便捷性:页面可以直接从 Vuex 获取用户信息,无需额外 API 调用
  4. 一致性:所有页面使用统一的方式获取用户信息
  5. 性能:减少了不必要的网络请求
  6. 兼容性:向后兼容,不影响现有功能

核心价值
- 简化了代码逻辑
- 提高了开发效率
- 减少了维护成本
- 提升了用户体验

版本历史

版本 日期 修改内容 修改人

| 1.0 | 2025-10-15 | Vuex 用户状态完整性优化 | - |