auth.ts 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  1. import { computed, ref } from 'vue'
  2. export type UserRole = 'admin' | 'user'
  3. export type UserStatus = 'active' | 'disabled'
  4. export interface AuthUser {
  5. id: number
  6. username: string
  7. display_name: string
  8. role: UserRole
  9. status: UserStatus
  10. last_login_at: string | null
  11. created_at: string | null
  12. updated_at: string | null
  13. }
  14. export const currentUser = ref<AuthUser | null>(null)
  15. export const authResolved = ref(false)
  16. export const isAdmin = computed(() => currentUser.value?.role === 'admin')
  17. let pendingLoad: Promise<AuthUser | null> | null = null
  18. export function defaultRouteFor(user: AuthUser): string {
  19. return user.role === 'admin' ? '/' : '/demand-map'
  20. }
  21. export async function loadCurrentUser(force = false): Promise<AuthUser | null> {
  22. if (authResolved.value && !force) return currentUser.value
  23. if (pendingLoad && !force) return pendingLoad
  24. pendingLoad = (async () => {
  25. try {
  26. const response = await fetch('/api/auth/me')
  27. if (!response.ok) {
  28. currentUser.value = null
  29. return null
  30. }
  31. const payload = await response.json() as { user: AuthUser }
  32. currentUser.value = payload.user
  33. return payload.user
  34. } catch {
  35. currentUser.value = null
  36. return null
  37. } finally {
  38. authResolved.value = true
  39. pendingLoad = null
  40. }
  41. })()
  42. return pendingLoad
  43. }
  44. export async function login(username: string, password: string): Promise<AuthUser> {
  45. const response = await fetch('/api/auth/login', {
  46. method: 'POST',
  47. headers: { 'Content-Type': 'application/json' },
  48. body: JSON.stringify({ username, password }),
  49. })
  50. if (!response.ok) {
  51. const payload = await response.json().catch(() => null) as { detail?: string } | null
  52. throw new Error(payload?.detail || '登录失败,请稍后重试')
  53. }
  54. const payload = await response.json() as { user: AuthUser }
  55. currentUser.value = payload.user
  56. authResolved.value = true
  57. return payload.user
  58. }
  59. export async function logout(): Promise<void> {
  60. try {
  61. await fetch('/api/auth/logout', { method: 'POST' })
  62. } finally {
  63. currentUser.value = null
  64. authResolved.value = true
  65. }
  66. }