feat(admin-frontend): 初始化管理端登录功能

This commit is contained in:
yinjianm
2026-04-21 03:28:04 +08:00
parent 994819e8a0
commit 4cfda0fbf1
38 changed files with 4296 additions and 9 deletions
+43
View File
@@ -0,0 +1,43 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { getSecurePath, getApiBaseUrl, getAppTitle, getLogo, getVersion } from '@/utils/runtime'
export const useAppStore = defineStore('app', () => {
const securePath = ref('')
const apiBaseUrl = ref('')
const title = ref('Xboard Admin')
const logo = ref('')
const version = ref('')
const sidebarCollapsed = ref(false)
const isDark = ref(false)
function initConfig() {
securePath.value = getSecurePath()
apiBaseUrl.value = getApiBaseUrl()
title.value = getAppTitle()
logo.value = getLogo()
version.value = getVersion()
const saved = localStorage.getItem('xboard_theme_dark')
if (saved !== null) {
isDark.value = saved === 'true'
}
applyTheme()
}
function toggleSidebar() {
sidebarCollapsed.value = !sidebarCollapsed.value
}
function toggleTheme() {
isDark.value = !isDark.value
localStorage.setItem('xboard_theme_dark', String(isDark.value))
applyTheme()
}
function applyTheme() {
document.documentElement.classList.toggle('dark', isDark.value)
}
return { securePath, apiBaseUrl, title, logo, version, sidebarCollapsed, isDark, initConfig, toggleSidebar, toggleTheme }
})
+81
View File
@@ -0,0 +1,81 @@
import { defineStore } from 'pinia'
import { ref } from 'vue'
import { login as apiLogin } from '@/api/passport'
import { getSystemStatus } from '@/api/admin'
import { getToken, setToken, removeToken, hasToken } from '@/utils/token'
import axios from 'axios'
export const useAuthStore = defineStore('auth', () => {
const authHeader = ref<string | null>(getToken())
const isAdmin = ref(false)
const isLoading = ref(false)
const validated = ref(false)
async function login(email: string, password: string, remember: boolean = false) {
isLoading.value = true
try {
const res = await apiLogin({ email, password })
if (!res.data.is_admin) {
throw new Error('该账号无管理员权限')
}
authHeader.value = res.data.auth_data
isAdmin.value = res.data.is_admin
setToken(res.data.auth_data, remember)
const probeOk = await validateAdmin()
if (!probeOk) {
validated.value = true
isAdmin.value = true
}
return true
} catch (err) {
authHeader.value = null
isAdmin.value = false
removeToken()
throw err
} finally {
isLoading.value = false
}
}
async function validateAdmin(): Promise<boolean> {
if (!hasToken()) {
return false
}
try {
await getSystemStatus()
validated.value = true
isAdmin.value = true
return true
} catch (err) {
if (axios.isAxiosError(err)) {
const status = err.response?.status
if (status === 401 || status === 403) {
logout()
return false
}
}
console.warn('[Xboard] Admin probe failed, proceeding with login token')
return false
}
}
function logout() {
authHeader.value = null
isAdmin.value = false
validated.value = false
removeToken()
}
function initFromStorage() {
const token = getToken()
if (token) {
authHeader.value = token
}
}
return { authHeader, isAdmin, isLoading, validated, login, logout, validateAdmin, initFromStorage }
})