feat: 全新的Vue3管理后台(admin-spa)和路由重构

🎨 新增功能:
- 使用Vue3 + Vite构建的全新管理后台界面
- 支持Tab切换的API统计页面(统计查询/使用教程)
- 优雅的胶囊式Tab切换设计
- 同步了PR #106的会话窗口管理功能
- 完整的响应式设计和骨架屏加载状态

🔧 路由调整:
- 新版管理后台部署在 /admin-next/ 路径
- 将根路径 / 重定向到 /admin-next/api-stats
- 将 /web 页面路由重定向到新版,保留 /web/auth/* 认证路由
- 将 /apiStats 页面路由重定向到新版,保留API端点

🗑️ 清理工作:
- 删除旧版 web/admin/ 静态文件
- 删除旧版 web/apiStats/ 静态文件
- 清理相关的文件服务代码

🐛 修复问题:
- 修复重定向循环问题
- 修复环境变量配置
- 修复路由404错误
- 优化构建配置

🚀 生成方式:使用 Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
shaw
2025-07-29 12:40:51 +08:00
parent c98de2aca5
commit 414856f152
70 changed files with 18748 additions and 10314 deletions

View File

@@ -0,0 +1,130 @@
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
import router from '@/router'
import { apiClient } from '@/config/api'
export const useAuthStore = defineStore('auth', () => {
// 状态
const isLoggedIn = ref(false)
const authToken = ref(localStorage.getItem('authToken') || '')
const username = ref('')
const loginError = ref('')
const loginLoading = ref(false)
const oemSettings = ref({
siteName: 'Claude Relay Service',
siteIcon: '',
siteIconData: '',
faviconData: ''
})
const oemLoading = ref(true)
// 计算属性
const isAuthenticated = computed(() => !!authToken.value && isLoggedIn.value)
const token = computed(() => authToken.value)
const user = computed(() => ({ username: username.value }))
// 方法
async function login(credentials) {
loginLoading.value = true
loginError.value = ''
try {
const result = await apiClient.post('/web/auth/login', credentials)
if (result.success) {
authToken.value = result.token
username.value = credentials.username
isLoggedIn.value = true
localStorage.setItem('authToken', result.token)
await router.push('/dashboard')
} else {
loginError.value = result.message || '登录失败'
}
} catch (error) {
loginError.value = error.message || '登录失败,请检查用户名和密码'
} finally {
loginLoading.value = false
}
}
function logout() {
isLoggedIn.value = false
authToken.value = ''
username.value = ''
localStorage.removeItem('authToken')
router.push('/login')
}
function checkAuth() {
if (authToken.value) {
isLoggedIn.value = true
// 验证token有效性
verifyToken()
}
}
async function verifyToken() {
try {
// 使用 dashboard 端点来验证 token
// 如果 token 无效,会抛出错误
const result = await apiClient.get('/admin/dashboard')
if (!result.success) {
logout()
}
} catch (error) {
// token 无效,需要重新登录
logout()
}
}
async function loadOemSettings() {
oemLoading.value = true
try {
const result = await apiClient.get('/admin/oem-settings')
if (result.success && result.data) {
oemSettings.value = { ...oemSettings.value, ...result.data }
// 设置favicon
if (result.data.faviconData) {
const link = document.querySelector("link[rel*='icon']") || document.createElement('link')
link.type = 'image/x-icon'
link.rel = 'shortcut icon'
link.href = result.data.faviconData
document.getElementsByTagName('head')[0].appendChild(link)
}
// 设置页面标题
if (result.data.siteName) {
document.title = `${result.data.siteName} - 管理后台`
}
}
} catch (error) {
console.error('加载OEM设置失败:', error)
} finally {
oemLoading.value = false
}
}
return {
// 状态
isLoggedIn,
authToken,
username,
loginError,
loginLoading,
oemSettings,
oemLoading,
// 计算属性
isAuthenticated,
token,
user,
// 方法
login,
logout,
checkAuth,
loadOemSettings
}
})