116 lines
4.1 KiB
HTML
116 lines
4.1 KiB
HTML
{% extends "auth.html" %}
|
|
|
|
{% block title %}登录{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="min-h-screen flex items-center justify-center bg-gradient-to-br from-blue-50 to-indigo-100">
|
|
|
|
<div class="w-full max-w-sm bg-white rounded-2xl shadow-xl p-8 relative">
|
|
|
|
<!-- Logo / 标题 -->
|
|
<div class="text-center mb-6">
|
|
<div
|
|
class="mx-auto w-14 h-14 flex items-center justify-center rounded-full bg-blue-600 text-white text-xl font-bold shadow">
|
|
北
|
|
</div>
|
|
<h2 class="text-2xl font-bold mt-4">小北学生系统</h2>
|
|
<p class="text-sm text-gray-500 mt-1">
|
|
校园签到 · 数据可视化 · 自动化
|
|
</p>
|
|
</div>
|
|
|
|
<!-- 表单 -->
|
|
<div class="space-y-4">
|
|
<!-- 用户名 -->
|
|
<div class="relative">
|
|
<span class="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400">
|
|
👤
|
|
</span>
|
|
<input id="username" type="text" placeholder="用户名"
|
|
class="w-full pl-10 pr-4 py-2 border rounded-lg focus:outline-none focus:ring focus:ring-blue-200" />
|
|
</div>
|
|
|
|
<!-- 密码 -->
|
|
<div class="relative">
|
|
<span class="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400">
|
|
🔒
|
|
</span>
|
|
<input id="password" type="password" placeholder="密码"
|
|
class="w-full pl-10 pr-4 py-2 border rounded-lg focus:outline-none focus:ring focus:ring-blue-200" />
|
|
</div>
|
|
|
|
<!-- 登录按钮 -->
|
|
<button id="login-btn"
|
|
class="w-full bg-blue-600 text-white py-2 rounded-lg hover:bg-blue-700 transition disabled:opacity-60 flex items-center justify-center gap-2">
|
|
<span id="btn-text">登录</span>
|
|
<svg id="loading" class="hidden w-5 h-5 animate-spin text-white" xmlns="http://www.w3.org/2000/svg"
|
|
fill="none" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" />
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- 错误提示 -->
|
|
<p id="error" class="text-red-500 text-sm mt-4 text-center hidden animate-pulse"></p>
|
|
|
|
<!-- 底部 -->
|
|
<div class="mt-6 text-center text-xs text-gray-400">
|
|
© {{ year }} 小北 · 学生服务系统
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<script>
|
|
const btn = document.getElementById("login-btn")
|
|
const btnText = document.getElementById("btn-text")
|
|
const loading = document.getElementById("loading")
|
|
const errorBox = document.getElementById("error")
|
|
|
|
async function login() {
|
|
const username = document.getElementById("username").value.trim()
|
|
const password = document.getElementById("password").value.trim()
|
|
|
|
if (!username || !password) {
|
|
showError("请输入用户名和密码")
|
|
return
|
|
}
|
|
|
|
btn.disabled = true
|
|
btnText.innerText = "登录中"
|
|
loading.classList.remove("hidden")
|
|
|
|
try {
|
|
const res = await fetch("/login", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ username, password }),
|
|
})
|
|
|
|
if (res.ok) {
|
|
window.location.href = "/home"
|
|
} else {
|
|
showError("用户名或密码错误")
|
|
}
|
|
} catch {
|
|
showError("网络异常,请稍后再试")
|
|
} finally {
|
|
btn.disabled = false
|
|
btnText.innerText = "登录"
|
|
loading.classList.add("hidden")
|
|
}
|
|
}
|
|
|
|
function showError(msg) {
|
|
errorBox.innerText = msg
|
|
errorBox.classList.remove("hidden")
|
|
}
|
|
|
|
// 事件绑定
|
|
btn.addEventListener("click", login)
|
|
document.addEventListener("keydown", e => {
|
|
if (e.key === "Enter") login()
|
|
})
|
|
</script>
|
|
{% endblock %} |