Vue 3 + TS + Vite + Tailwind with self-built UI components. Landing, auth, user dashboard (keys/usage/settings), and admin console (overview/models/channels/users/usage/config). Theme system (light/dark/system) with pre-paint boot script, theme-aware ECharts, and a channel editor with multi-format (Anthropic/OpenAI) selection. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
87 lines
1.8 KiB
TypeScript
87 lines
1.8 KiB
TypeScript
import { reactive, computed } from 'vue'
|
|
import { authApi } from '@/api'
|
|
import { setToken, getToken, tryRefresh } from '@/api/client'
|
|
import type { LoginResult, User } from '@/types'
|
|
|
|
const state = reactive<{
|
|
user: User | null
|
|
ready: boolean
|
|
loading: boolean
|
|
}>({
|
|
user: null,
|
|
ready: false,
|
|
loading: false,
|
|
})
|
|
|
|
async function restore(): Promise<void> {
|
|
if (state.user) return
|
|
if (!getToken()) {
|
|
// No access token in storage: try the refresh cookie to recover a session.
|
|
const fresh = await tryRefresh()
|
|
if (!fresh) {
|
|
state.ready = true
|
|
return
|
|
}
|
|
setToken(fresh)
|
|
}
|
|
try {
|
|
state.user = await authApi.me()
|
|
} catch {
|
|
state.user = null
|
|
} finally {
|
|
state.ready = true
|
|
}
|
|
}
|
|
|
|
async function apply(result: LoginResult): Promise<void> {
|
|
setToken(result.token.accessToken)
|
|
state.user = result.user
|
|
}
|
|
|
|
async function login(account: string, password: string): Promise<void> {
|
|
state.loading = true
|
|
try {
|
|
await apply(await authApi.login(account, password))
|
|
} finally {
|
|
state.loading = false
|
|
}
|
|
}
|
|
|
|
async function register(data: { username: string; email: string; password: string; inviteCode?: string }): Promise<void> {
|
|
state.loading = true
|
|
try {
|
|
await apply(await authApi.register(data))
|
|
} finally {
|
|
state.loading = false
|
|
}
|
|
}
|
|
|
|
async function logout(): Promise<void> {
|
|
try {
|
|
await authApi.logout()
|
|
} catch {
|
|
// ignore network errors on logout
|
|
}
|
|
setToken('')
|
|
state.user = null
|
|
}
|
|
|
|
async function refreshProfile(): Promise<void> {
|
|
if (!getToken()) return
|
|
state.user = await authApi.me()
|
|
}
|
|
|
|
export function useAuth() {
|
|
return {
|
|
state,
|
|
user: computed(() => state.user),
|
|
isAdmin: computed(() => state.user?.role === 'admin'),
|
|
isAuthed: computed(() => !!state.user),
|
|
restore,
|
|
login,
|
|
register,
|
|
logout,
|
|
refreshProfile,
|
|
}
|
|
}
|