接入前端登录权限底座
This commit is contained in:
146
client/src/stores/authStore.ts
Normal file
146
client/src/stores/authStore.ts
Normal file
@@ -0,0 +1,146 @@
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
import { fetchCurrentAuth, loginAuth, logoutAuth } from '@/services/authService'
|
||||
import { clearStoredAccessToken, getStoredAccessToken, setStoredAccessToken } from '@/services/authSession'
|
||||
import type {
|
||||
AuthHotelResult,
|
||||
AuthLoginRequest,
|
||||
AuthLoginResult,
|
||||
AuthMeResult,
|
||||
AuthMenuResult,
|
||||
AuthPermissionCode,
|
||||
AuthUserResult,
|
||||
} from '@/types/auth'
|
||||
|
||||
interface AuthState {
|
||||
accessToken: string | null
|
||||
user: AuthUserResult | null
|
||||
defaultHotelId: string | null
|
||||
hotels: AuthHotelResult[]
|
||||
permissions: AuthPermissionCode[]
|
||||
menus: AuthMenuResult[]
|
||||
selectedHotelId: string | null
|
||||
restoreAttempted: boolean
|
||||
restoring: boolean
|
||||
}
|
||||
|
||||
export const useAuthStore = defineStore('auth', {
|
||||
state: (): AuthState => ({
|
||||
accessToken: getStoredAccessToken(),
|
||||
user: null,
|
||||
defaultHotelId: null,
|
||||
hotels: [],
|
||||
permissions: [],
|
||||
menus: [],
|
||||
selectedHotelId: null,
|
||||
restoreAttempted: false,
|
||||
restoring: false,
|
||||
}),
|
||||
getters: {
|
||||
isAuthenticated: (state) => Boolean(state.accessToken && state.user),
|
||||
selectedHotel: (state) =>
|
||||
state.hotels.find((hotel) => hotel.hotel_id === state.selectedHotelId) ?? state.hotels[0] ?? null,
|
||||
visibleMenus: (state) =>
|
||||
[...state.menus]
|
||||
.filter((menu) => Boolean(menu.route_path))
|
||||
.sort((left, right) => (left.sort_order ?? 0) - (right.sort_order ?? 0)),
|
||||
firstMenuPath(): string | null {
|
||||
return this.visibleMenus[0]?.route_path ?? null
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
hasPermission(permission: AuthPermissionCode): boolean {
|
||||
return this.permissions.includes(permission)
|
||||
},
|
||||
hasStoredToken(): boolean {
|
||||
return Boolean(getStoredAccessToken())
|
||||
},
|
||||
async login(request: AuthLoginRequest): Promise<AuthLoginResult> {
|
||||
const result = await loginAuth(request)
|
||||
this.applyLoginResult(result)
|
||||
return result
|
||||
},
|
||||
async restoreFromSession(): Promise<boolean> {
|
||||
if (this.restoreAttempted && this.isAuthenticated) {
|
||||
return true
|
||||
}
|
||||
const token = getStoredAccessToken()
|
||||
if (!token) {
|
||||
this.clearAuth()
|
||||
this.restoreAttempted = true
|
||||
return false
|
||||
}
|
||||
|
||||
this.accessToken = token
|
||||
this.restoring = true
|
||||
try {
|
||||
const result = await fetchCurrentAuth()
|
||||
this.applyAuthContext(result)
|
||||
this.restoreAttempted = true
|
||||
return true
|
||||
} catch {
|
||||
this.clearAuth()
|
||||
this.restoreAttempted = true
|
||||
return false
|
||||
} finally {
|
||||
this.restoring = false
|
||||
}
|
||||
},
|
||||
async logout(): Promise<void> {
|
||||
try {
|
||||
if (this.accessToken) {
|
||||
await logoutAuth()
|
||||
}
|
||||
} catch {
|
||||
// 本地退出必须完成;后端登出失败时不保留过期 token 或用户上下文。
|
||||
} finally {
|
||||
this.clearAuth()
|
||||
this.restoreAttempted = true
|
||||
}
|
||||
},
|
||||
applyLoginResult(result: AuthLoginResult): void {
|
||||
this.accessToken = result.access_token
|
||||
setStoredAccessToken(result.access_token)
|
||||
this.applyAuthContext(result)
|
||||
this.restoreAttempted = true
|
||||
},
|
||||
applyAuthContext(result: AuthMeResult): void {
|
||||
this.user = result.user
|
||||
this.defaultHotelId = result.default_hotel_id
|
||||
this.hotels = result.hotels
|
||||
this.permissions = result.permissions
|
||||
this.menus = result.menus
|
||||
this.selectedHotelId = resolveSelectedHotelId(result.hotels, result.default_hotel_id, this.selectedHotelId)
|
||||
},
|
||||
setSelectedHotelId(hotelId: string): void {
|
||||
if (this.hotels.some((hotel) => hotel.hotel_id === hotelId)) {
|
||||
this.selectedHotelId = hotelId
|
||||
}
|
||||
},
|
||||
clearAuth(): void {
|
||||
clearStoredAccessToken()
|
||||
this.accessToken = null
|
||||
this.user = null
|
||||
this.defaultHotelId = null
|
||||
this.hotels = []
|
||||
this.permissions = []
|
||||
this.menus = []
|
||||
this.selectedHotelId = null
|
||||
this.restoring = false
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
function resolveSelectedHotelId(
|
||||
hotels: AuthHotelResult[],
|
||||
defaultHotelId: string | null,
|
||||
currentHotelId: string | null,
|
||||
): string | null {
|
||||
if (currentHotelId && hotels.some((hotel) => hotel.hotel_id === currentHotelId)) {
|
||||
return currentHotelId
|
||||
}
|
||||
if (defaultHotelId && hotels.some((hotel) => hotel.hotel_id === defaultHotelId)) {
|
||||
return defaultHotelId
|
||||
}
|
||||
return hotels.find((hotel) => hotel.default_hotel)?.hotel_id ?? hotels[0]?.hotel_id ?? null
|
||||
}
|
||||
Reference in New Issue
Block a user