user.ts 2.67 KB
import { defineStore } from 'pinia'
import { AuthApi } from '@/api/login'
import { clearToken, setToken } from '@/utils/auth'
import { usePermissionStore } from './permission'
import type { LoginReqVO, UserInfoVO } from '@/types'

/**
 * 用户 store:token / 用户信息 / 角色 / 权限标识
 *
 * 说明:菜单与路由不在本 store 里,统一由 permission store 负责(二者职责分离)。
 */
export const useUserStore = defineStore('user', () => {
  const userInfo = ref<UserInfoVO | null>(null)
  const roles = ref<string[]>([])
  const permissions = ref<string[]>([])
  /** 是否已拉取过用户信息 */
  const isUserInfoLoaded = ref(false)

  const isSuperAdmin = computed(() => roles.value.includes('super_admin'))

  /** 登录:只负责拿 token */
  async function login(reqVO: LoginReqVO) {
    const data = await AuthApi.login(reqVO)
    setToken(data.accessToken, data.refreshToken, data.expiresTime)
    return data
  }

  /**
   * 获取用户信息 + 角色 + 权限 + 菜单(一次请求)
   * 并把菜单交给 permission store 生成路由
   */
  async function getInfo() {
    const data = await AuthApi.getPermissionInfo()
    userInfo.value = data.user
    roles.value = data.roles || []
    permissions.value = data.permissions || []
    isUserInfoLoaded.value = true
    usePermissionStore().generateRoutes(data.menus || [])
    return data
  }

  /** 登出:调后端注销 token,本地状态无论如何都要清干净 */
  async function logout() {
    try {
      await AuthApi.logout()
    } catch (e) {
      // 后端不可用也要允许前端登出
    } finally {
      resetState()
    }
  }

  function resetState() {
    clearToken()
    userInfo.value = null
    roles.value = []
    permissions.value = []
    isUserInfoLoaded.value = false
    usePermissionStore().reset()
  }

  /** 是否拥有某个权限标识(如 'park:park-lot:create');超管恒为 true */
  function hasPermission(permission: string | string[]): boolean {
    if (isSuperAdmin.value) return true
    if (!permission || (Array.isArray(permission) && permission.length === 0)) return true
    const required = Array.isArray(permission) ? permission : [permission]
    return required.some((p) => permissions.value.includes(p))
  }

  /** 是否拥有某个角色;超管恒为 true */
  function hasRole(role: string | string[]): boolean {
    if (isSuperAdmin.value) return true
    const required = Array.isArray(role) ? role : [role]
    return required.some((r) => roles.value.includes(r))
  }

  return {
    userInfo,
    roles,
    permissions,
    isUserInfoLoaded,
    isSuperAdmin,
    login,
    getInfo,
    logout,
    resetState,
    hasPermission,
    hasRole
  }
})