| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- import { defineStore } from 'pinia'
- import { ref, computed } from 'vue'
- import { getToken, setToken, removeToken, setUserInfo, removeUserInfo, getUserInfo } from '@/utils/storage'
- import { login as loginApi, logout as logoutApi, getUserInfoApi } from '@/api/auth'
- /**
- * 用户状态 Store
- * 管理登录状态、用户信息、Token、权限路由列表
- */
- export const useUserStore = defineStore('user', () => {
- // 状态
- const token = ref(getToken() || '')
- const userInfo = ref(getUserInfo() || {})
- // 计算属性
- const isLoggedIn = computed(() => !!token.value)
- const username = computed(() => userInfo.value?.username || '')
- const nickname = computed(() => userInfo.value?.nickname || userInfo.value?.username || '')
- const avatar = computed(() => userInfo.value?.avatar || '/default-avatar.png')
- /**
- * 管理员角色:1=超级管理员,2=设备管理员,3=圣手管理
- * 超级管理员拥有所有菜单权限
- */
- const adminRole = computed(() => userInfo.value?.adminRole || null)
- /**
- * 权限路由路径列表(JSON字符串解析后的数组)
- * 超级管理员(adminRole=1)此值为 null,前端视为拥有全部权限
- * 其他角色为可访问的路由路径数组,如 ['/dashboard', '/device']
- */
- const permissions = computed(() => {
- const raw = userInfo.value?.permissions
- if (raw === null || raw === undefined) return null // 超级管理员:全部权限
- if (typeof raw === 'string') {
- try {
- return JSON.parse(raw).map(normalizePermissionPath).filter(Boolean)
- } catch {
- return []
- }
- }
- if (Array.isArray(raw)) return raw.map(normalizePermissionPath).filter(Boolean)
- return []
- })
- /**
- * 判断是否有指定路由的权限
- * @param {string} path 路由 path
- */
- function hasPermission(path) {
- if (adminRole.value === 1) return true // 超级管理员全部通过
- if (permissions.value === null) return true // null 也视为全部权限
- return permissions.value.includes(normalizePermissionPath(path))
- }
- /**
- * 登录
- * @param {Object} loginData 登录参数 { username, password }
- */
- async function login(loginData) {
- const res = await loginApi(loginData)
- const { token: newToken, ...info } = res.data
- // 保存 Token 到内存和 localStorage
- token.value = newToken
- setToken(newToken)
- // 保存用户基本信息(含 adminRole 和 permissions)
- userInfo.value = info
- setUserInfo(info)
- return res
- }
- /**
- * 退出登录
- * 清除本地状态并调用后端退出接口
- */
- async function logout() {
- try {
- await logoutApi()
- } catch (e) {
- // 退出接口失败不影响本地清除
- }
- clearUser()
- }
- /**
- * 获取最新用户信息(从后端刷新,含权限路由)
- */
- async function fetchUserInfo() {
- const res = await getUserInfoApi()
- userInfo.value = res.data
- setUserInfo(res.data)
- return res.data
- }
- /**
- * 清除用户状态(退出登录时调用)
- */
- function clearUser() {
- token.value = ''
- userInfo.value = {}
- removeToken()
- removeUserInfo()
- }
- return {
- token,
- userInfo,
- isLoggedIn,
- username,
- nickname,
- avatar,
- adminRole,
- permissions,
- hasPermission,
- login,
- logout,
- fetchUserInfo,
- clearUser
- }
- })
- function normalizePermissionPath(path) {
- if (!path || typeof path !== 'string') return ''
- const cleanPath = path.split('?')[0].split('#')[0].trim()
- if (cleanPath === '/admin') return '/system/admin'
- if (cleanPath === '/log') return '/system/log'
- return cleanPath
- }
|