import { useState, useEffect } from 'react' import { useNavigate } from '@tanstack/react-router' import { Key, Lock, AlertCircle, Moon, Sun, HelpCircle, FileText, Terminal, Zap } from 'lucide-react' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog' import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from '@/components/ui/alert-dialog' import { WavesBackground } from '@/components/waves-background' import { useAnimation } from '@/hooks/use-animation' import { useTheme } from '@/components/use-theme' import { checkAuthStatus } from '@/lib/fetch-with-auth' import { cn } from '@/lib/utils' import { APP_FULL_NAME } from '@/lib/version' export function AuthPage() { const [token, setToken] = useState('') const [isValidating, setIsValidating] = useState(false) const [error, setError] = useState('') const [checkingAuth, setCheckingAuth] = useState(true) const navigate = useNavigate() const { enableWavesBackground, setEnableWavesBackground } = useAnimation() const { theme, setTheme } = useTheme() // 如果已经认证,直接跳转到首页 useEffect(() => { const verifyAuth = async () => { try { const isAuth = await checkAuthStatus() if (isAuth) { navigate({ to: '/' }) } } catch { // 忽略错误,保持在登录页 } finally { setCheckingAuth(false) } } verifyAuth() }, [navigate]) // 获取实际应用的主题(处理 system 情况) const getActualTheme = () => { if (theme === 'system') { return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' } return theme } const actualTheme = getActualTheme() // 主题切换(无动画) const toggleTheme = () => { const newTheme = actualTheme === 'dark' ? 'light' : 'dark' setTheme(newTheme) } const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() setError('') if (!token.trim()) { setError('请输入 Access Token') return } setIsValidating(true) console.log('开始验证 token...') try { // 向后端发送请求验证 token(后端会设置 HttpOnly Cookie) const response = await fetch('/api/webui/auth/verify', { method: 'POST', headers: { 'Content-Type': 'application/json', }, credentials: 'include', // 确保接收并存储 Cookie body: JSON.stringify({ token: token.trim() }), }) console.log('Token 验证响应状态:', response.status) const data = await response.json() console.log('Token 验证响应数据:', data) if (response.ok && data.valid) { console.log('Token 验证成功,准备跳转...') console.log('is_first_setup:', data.is_first_setup) // Token 验证成功,Cookie 已由后端设置 // 等待一小段时间确保 Cookie 已设置 await new Promise(resolve => setTimeout(resolve, 100)) // 再次检查认证状态 const authCheck = await checkAuthStatus() console.log('跳转前认证状态检查:', authCheck) // 直接使用验证响应中的 is_first_setup 字段,避免额外请求 if (data.is_first_setup) { console.log('跳转到首次配置页面') // 需要首次配置,跳转到配置向导 navigate({ to: '/setup' }) } else { console.log('跳转到首页') // 不需要配置或配置已完成,跳转到首页 navigate({ to: '/' }) } } else { console.error('Token 验证失败:', data.message) setError(data.message || 'Token 验证失败,请检查后重试') } } catch (err) { console.error('Token 验证错误:', err) setError('连接服务器失败,请检查网络连接') } finally { setIsValidating(false) } } // 正在检查认证状态时显示加载 if (checkingAuth) { return (
{enableWavesBackground && }
正在检查登录状态...
) } return (
{/* 波浪背景 - 独立控制 */} {enableWavesBackground && } {/* 认证卡片 - 磨砂玻璃效果 */} {/* 主题切换按钮 */} {/* Logo/Icon */}
欢迎使用 MaiBot 请输入您的 Access Token 以继续访问系统
{/* Token 输入框 */}
setToken(e.target.value)} className={cn('pl-10', error && 'border-red-500 focus-visible:ring-red-500')} disabled={isValidating} autoFocus autoComplete="off" />
{/* 错误提示 */} {error && (
{error}
)} {/* 提交按钮 */} {/* 帮助文本 */} 如何获取 Access Token Access Token 是访问 MaiBot WebUI 的唯一凭证,请按以下方式获取
{/* 方式一:查看控制台 */}

方式一:查看启动日志

在 MaiBot 启动时,控制台会显示 WebUI Access Token。

🔑 WebUI Access Token: abc123...

💡 请使用此 Token 登录 WebUI

{/* 方式二:查看配置文件 */}

方式二:查看配置文件

Token 保存在项目根目录的配置文件中:

data/webui.json

打开此文件,复制 access_token 字段的值

{/* 安全提示 */}

安全提示

  • 请妥善保管您的 Token,不要泄露给他人
  • 如需重置 Token,请在登录后前往系统设置
{/* 性能优化选项 */} 关闭背景动画 背景动画可能会在低性能设备上造成卡顿。关闭动画可以显著提升界面流畅度。

关闭动画后,背景将变为纯色,但不影响任何功能的使用。您可以随时在系统设置中重新开启动画。

取消 setEnableWavesBackground(false)} > 关闭动画
{/* 页脚信息 */}

{APP_FULL_NAME}

) }