9c843b79ba
- 新增 users 和 user_settings 表,repositories/analyses/review_notes 添加 user_id 列 - 实现基于邮箱+密码的注册登录,密码使用 bcrypt 哈希 - 使用 gin-contrib/sessions cookie-based session 管理 - 所有仓库、分析记录、review notes 按用户隔离 - 用户设置(LLM 配置、review 参数、缓存配置)独立存储 - 新增登录/注册页面,导航栏显示用户邮箱和退出按钮 - 前端 fetch 请求统一添加 credentials: 'same-origin' - 支持 SESSION_SECRET 环境变量配置会话密钥
69 lines
3.0 KiB
HTML
69 lines
3.0 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN" class="h-full">
|
|
{{template "head" .}}
|
|
<body class="h-full bg-gray-50 text-gray-900">
|
|
<div class="min-h-full flex flex-col">
|
|
{{template "nav" .}}
|
|
<main class="flex-1 flex items-center justify-center">
|
|
<div class="w-full max-w-md px-4">
|
|
<div class="bg-white rounded-lg shadow-sm border border-gray-200 p-8">
|
|
<h1 class="text-2xl font-bold text-center mb-6">登录</h1>
|
|
<form id="login-form" class="space-y-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">邮箱</label>
|
|
<input type="email" name="email" required
|
|
class="w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
|
placeholder="your@email.com">
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700 mb-1">密码</label>
|
|
<input type="password" name="password" required
|
|
class="w-full rounded-md border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500"
|
|
placeholder="••••••">
|
|
</div>
|
|
<div id="login-error" class="text-sm text-red-600 hidden"></div>
|
|
<button type="submit"
|
|
class="w-full bg-indigo-600 text-white px-5 py-2 rounded-md text-sm font-medium hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2">
|
|
登录
|
|
</button>
|
|
</form>
|
|
<p class="mt-4 text-center text-sm text-gray-500">
|
|
还没有账号?<a href="/register" class="text-indigo-600 hover:text-indigo-700">注册</a>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
{{template "footer" .}}
|
|
</div>
|
|
<script>
|
|
document.getElementById('login-form').addEventListener('submit', async function(e) {
|
|
e.preventDefault();
|
|
const form = new FormData(this);
|
|
const errorEl = document.getElementById('login-error');
|
|
errorEl.classList.add('hidden');
|
|
try {
|
|
const resp = await fetch('/api/auth/login', {
|
|
method: 'POST',
|
|
headers: {'Content-Type': 'application/json'},
|
|
credentials: 'same-origin',
|
|
body: JSON.stringify({
|
|
email: form.get('email'),
|
|
password: form.get('password')
|
|
})
|
|
});
|
|
const data = await resp.json();
|
|
if (!resp.ok) {
|
|
errorEl.textContent = data.error || '登录失败';
|
|
errorEl.classList.remove('hidden');
|
|
return;
|
|
}
|
|
window.location.href = '/';
|
|
} catch (err) {
|
|
errorEl.textContent = '网络错误,请重试';
|
|
errorEl.classList.remove('hidden');
|
|
}
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|