Files
KCGL/inventory-web/src/stores/user.ts
dxc c86e67b793 feat: refresh user permissions on page reload
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
2026-02-26 16:21:35 +08:00

132 lines
4.6 KiB
TypeScript
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.

import { defineStore } from 'pinia'
import { login } from '@/api/auth'
import { getRolePermissions } from '@/api/system/permission'
import { ref } from 'vue'
export const useUserStore = defineStore('user', () => {
// 1. State: 初始化时优先从 localStorage 获取,防止刷新丢失
const token = ref(localStorage.getItem('token') || '')
const role = ref(localStorage.getItem('role') || '')
const username = ref(localStorage.getItem('username') || '')
const permissions = ref<string[]>(JSON.parse(localStorage.getItem('permissions') || '[]'))
// 2. Actions
// 登录逻辑
const handleLogin = async (loginForm: any) => {
const res = await login(loginForm)
// [调试日志] 查看实际返回的数据结构
console.log('Login API Response:', res)
// ============================================================
// [关键修复] 兼容 Axios 拦截器的不同处理方式
// 如果拦截器已经返回了 response.data那么 res 本身就是数据对象
// ============================================================
const data = res.data || res
// 安全检查:确保 data 存在且包含 access_token
if (!data || !data.access_token) {
console.error('Login Error: 响应数据中缺少 access_token', data)
throw new Error('登录失败: 响应数据异常')
}
// 更新 Pinia 状态 (内存)
token.value = data.access_token
// 处理用户信息 (确保后端返回结构中有 user 字段)
if (data.user) {
role.value = data.user.role || 'user' // 默认给个 user 角色防止空
username.value = data.user.username || '用户'
// 持久化存储用户信息
localStorage.setItem('role', role.value)
localStorage.setItem('username', username.value)
}
// 持久化存储 Token
localStorage.setItem('token', data.access_token)
// 登录成功后,根据角色获取权限
if (role.value) {
try {
const permRes = await getRolePermissions(role.value)
const permData = permRes.data || permRes
// 合并 menus 和 elements 两个数组
const allPerms = [
...(permData.menus || []),
...(permData.elements || [])
]
permissions.value = allPerms
localStorage.setItem('permissions', JSON.stringify(allPerms))
} catch (error) {
console.error('获取权限失败:', error)
permissions.value = []
localStorage.setItem('permissions', '[]')
}
}
return true // 返回 true 表示登录成功
}
// 退出逻辑
const logout = () => {
// 1. 清空 Pinia 状态 (内存)
token.value = ''
role.value = ''
username.value = ''
permissions.value = []
// 2. 清空 LocalStorage (硬盘)
localStorage.removeItem('token')
localStorage.removeItem('role')
localStorage.removeItem('username')
localStorage.removeItem('permissions')
}
// 刷新用户权限(不重新登录)
const refreshUserPermissions = async () => {
if (!token.value || !role.value) {
console.warn('无法刷新权限:用户未登录')
return
}
try {
const permRes = await getRolePermissions(role.value)
const permData = permRes.data || permRes
// 合并 menus 和 elements 两个数组
const allPerms = [
...(permData.menus || []),
...(permData.elements || [])
]
permissions.value = allPerms
localStorage.setItem('permissions', JSON.stringify(allPerms))
console.log('用户权限已刷新')
} catch (error) {
console.error('刷新权限失败:', error)
// 可选:保留原有权限
}
}
// 3. Getters / Helpers
// 判断当前用户是否拥有某些角色
const hasRole = (roles: string[]) => {
return roles.includes(role.value)
}
// 判断当前用户是否拥有某个权限(菜单或元素)
const hasPermission = (code: string) => {
return permissions.value.includes(code)
}
return {
token,
role,
username,
permissions,
handleLogin,
logout,
refreshUserPermissions,
hasRole,
hasPermission
}
})