feat(web): management console frontend
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>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
d0e31b198f
commit
489a79564c
@@ -0,0 +1,86 @@
|
||||
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,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user