grok2api / app /template /login.html
JXJBing's picture
Upload 45 files
1a9e2c2 verified
<!DOCTYPE html>
<html lang="zh-CN" class="h-full">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录 - Grok2API</title>
<link rel="icon" type="image/png" href="/static/favicon.png">
<script src="https://cdn.tailwindcss.com"></script>
<script>
tailwind.config = { theme: { extend: { colors: { border: "hsl(0 0% 89%)", input: "hsl(0 0% 89%)", ring: "hsl(0 0% 3.9%)", background: "hsl(0 0% 100%)", foreground: "hsl(0 0% 3.9%)", primary: { DEFAULT: "hsl(0 0% 9%)", foreground: "hsl(0 0% 98%)" }, secondary: { DEFAULT: "hsl(0 0% 96.1%)", foreground: "hsl(0 0% 9%)" }, muted: { DEFAULT: "hsl(0 0% 96.1%)", foreground: "hsl(0 0% 45.1%)" }, destructive: { DEFAULT: "hsl(0 84.2% 60.2%)", foreground: "hsl(0 0% 98%)" } } } } }
</script>
<style>
@keyframes slide-up {
from {
transform: translateY(100%);
opacity: 0
}
to {
transform: translateY(0);
opacity: 1
}
}
.animate-slide-up {
animation: slide-up .3s ease-out
}
</style>
</head>
<body class="h-full bg-background text-foreground antialiased">
<div class="flex min-h-full flex-col justify-center py-12 px-4 sm:px-6 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-md">
<div class="text-center">
<h1 class="text-4xl font-bold">Grok2API</h1>
<p class="mt-2 text-sm text-muted-foreground">管理员控制台</p>
</div>
</div>
<div class="sm:mx-auto sm:w-full sm:max-w-md">
<div class="bg-background py-8 px-4 sm:px-10 rounded-lg">
<form id="loginForm" class="space-y-6">
<div class="space-y-2">
<label for="username" class="text-sm font-medium">账户</label>
<input type="text" id="username" name="username" required
class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50"
placeholder="请输入账户">
</div>
<div class="space-y-2">
<label for="password" class="text-sm font-medium">密码</label>
<input type="password" id="password" name="password" required
class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-50"
placeholder="请输入密码">
</div>
<button type="submit" id="loginButton"
class="inline-flex items-center justify-center rounded-md font-medium transition-colors bg-primary text-primary-foreground hover:bg-primary/90 h-10 w-full disabled:opacity-50">登录</button>
</form>
<div class="mt-6 text-center text-xs text-muted-foreground space-y-1">
<p>Created By Chenyme © 2025</p>
<p>Fork 维护: @Tomiya233</p>
</div>
</div>
</div>
</div>
<script>
const form = document.getElementById('loginForm'), btn = document.getElementById('loginButton');
form.addEventListener('submit', async (e) => { e.preventDefault(); btn.disabled = true; btn.textContent = '登录中...'; try { const fd = new FormData(form), r = await fetch('/api/login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: fd.get('username'), password: fd.get('password') }) }); const d = await r.json(); d.success ? (localStorage.setItem('adminToken', d.token), location.href = '/manage') : showToast(d.message || '登录失败', 'error') } catch (e) { showToast('网络错误,请稍后重试', 'error') } finally { btn.disabled = false; btn.textContent = '登录' } });
function showToast(m, t = 'error') { const d = document.createElement('div'), bc = { success: 'bg-green-600', error: 'bg-destructive', info: 'bg-primary' }; d.className = `fixed bottom-4 right-4 ${bc[t] || bc.error} text-white px-4 py-2.5 rounded-lg shadow-lg text-sm font-medium z-50 animate-slide-up`; d.textContent = m; document.body.appendChild(d); setTimeout(() => { d.style.opacity = '0'; d.style.transition = 'opacity .3s'; setTimeout(() => d.parentNode && document.body.removeChild(d), 300) }, 2000) }
window.addEventListener('DOMContentLoaded', () => { const t = localStorage.getItem('adminToken'); t && fetch('/api/stats', { headers: { Authorization: `Bearer ${t}` } }).then(r => { if (r.ok) location.href = '/manage' }) });
</script>
</body>
</html>