Files
zlqy/templates/login.html

137 lines
8.7 KiB
HTML

{% extends "base.html" %}
{% block title %}登录 - 智联青云{% endblock %}
{% block navbar %}{% endblock %}
{% block content %}
<div class="min-h-screen bg-slate-50 flex flex-col justify-center py-12 sm:px-6 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-md">
<h2 class="mt-6 text-center text-3xl font-extrabold text-slate-900">登录您的账户</h2>
<p class="mt-2 text-center text-sm text-slate-600">
或者 <a href="/register" class="font-medium text-primary hover:text-blue-500">注册新账户</a>
</p>
</div>
<div class="mt-8 sm:mx-auto sm:w-full sm:max-w-md">
<div class="bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10">
<div class="flex border-b border-slate-200 mb-6">
<button id="tab-phone" onclick="switchTab('phone')" class="flex-1 pb-4 text-sm font-medium text-center text-primary border-b-2 border-primary">手机验证码登录</button>
<button id="tab-email" onclick="switchTab('email')" class="flex-1 pb-4 text-sm font-medium text-center text-slate-500 hover:text-slate-700">邮箱密码登录</button>
</div>
<!-- 手机登录表单 -->
<form id="form-phone" class="space-y-6" onsubmit="handlePhoneLogin(event)">
<div>
<label class="block text-sm font-medium text-slate-700">手机号码</label>
<div class="mt-1 relative rounded-md shadow-sm">
<input id="phone" type="tel" required class="focus:ring-primary focus:border-primary block w-full pl-3 sm:text-sm border-slate-300 rounded-md py-2 border" placeholder="请输入11位手机号">
</div>
</div>
<div>
<label class="block text-sm font-medium text-slate-700">图形验证码</label>
<div class="mt-1 flex items-center space-x-2">
<input id="captcha-text-phone" type="text" class="focus:ring-primary focus:border-primary block flex-1 sm:text-sm border-slate-300 rounded-md py-2 border px-3" placeholder="请输入图形验证码">
<img id="captcha-img-phone" class="cursor-pointer h-10" onclick="fetchCaptcha('phone')" alt="验证码">
<button type="button" onclick="fetchCaptcha('phone')" class="p-2 text-slate-400 hover:text-slate-600" title="刷新验证码">
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/></svg>
</button>
</div>
</div>
<div>
<label class="block text-sm font-medium text-slate-700">短信验证码</label>
<div class="mt-1 flex rounded-md shadow-sm">
<input id="sms-code" type="text" required class="focus:ring-primary focus:border-primary block w-full rounded-none rounded-l-md sm:text-sm border-slate-300 py-2 border px-3" placeholder="请输入短信验证码">
<button type="button" id="send-sms-btn" onclick="handleSendSms()" class="relative inline-flex items-center px-4 py-2 border border-slate-300 text-sm font-medium rounded-r-md text-slate-700 bg-slate-50 hover:bg-slate-100">获取验证码</button>
</div>
</div>
<button type="submit" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-primary hover:bg-blue-700">登录</button>
</form>
<!-- 邮箱登录表单 -->
<form id="form-email" class="space-y-6 hidden" onsubmit="handleEmailLogin(event)">
<div>
<label class="block text-sm font-medium text-slate-700">邮箱地址</label>
<input id="login-email" type="email" required class="mt-1 focus:ring-primary focus:border-primary block w-full pl-3 sm:text-sm border-slate-300 rounded-md py-2 border" placeholder="请输入邮箱">
</div>
<div>
<label class="block text-sm font-medium text-slate-700">密码</label>
<input id="login-password" type="password" required class="mt-1 focus:ring-primary focus:border-primary block w-full pl-3 sm:text-sm border-slate-300 rounded-md py-2 border" placeholder="请输入密码">
</div>
<button type="submit" class="w-full flex justify-center py-2 px-4 border border-transparent rounded-md shadow-sm text-sm font-medium text-white bg-primary hover:bg-blue-700">登录</button>
</form>
<div class="mt-6 relative">
<div class="absolute inset-0 flex items-center"><div class="w-full border-t border-slate-300"></div></div>
<div class="relative flex justify-center text-sm">
<span id="login-hint" class="px-2 bg-white text-slate-500">提示:手机号登录默认为学生权限</span>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
let captchaId = '';
let countdown = 0;
let countdownTimer = null;
function switchTab(tab) {
document.getElementById('form-phone').classList.toggle('hidden', tab !== 'phone');
document.getElementById('form-email').classList.toggle('hidden', tab !== 'email');
document.getElementById('tab-phone').className = 'flex-1 pb-4 text-sm font-medium text-center ' + (tab === 'phone' ? 'text-primary border-b-2 border-primary' : 'text-slate-500 hover:text-slate-700');
document.getElementById('tab-email').className = 'flex-1 pb-4 text-sm font-medium text-center ' + (tab === 'email' ? 'text-primary border-b-2 border-primary' : 'text-slate-500 hover:text-slate-700');
document.getElementById('login-hint').textContent = tab === 'phone' ? '提示:手机号登录默认为学生权限' : '提示:管理员请使用管理员账号登录';
}
async function fetchCaptcha(suffix) {
try {
const res = await fetch('/api/captcha');
const data = await res.json();
captchaId = data.captchaId;
document.getElementById('captcha-img-' + suffix).src = 'data:image/png;base64,' + data.img;
const input = document.getElementById('captcha-text-' + suffix);
if (input) input.value = '';
} catch(e) { console.error('获取验证码失败', e); }
}
async function handleSendSms() {
const phone = document.getElementById('phone').value;
const captchaText = document.getElementById('captcha-text-phone').value;
if (!/^1[3-9]\d{9}$/.test(phone)) { alert('请输入有效的中国手机号码'); return; }
if (!captchaText) { alert('请输入图形验证码'); return; }
const btn = document.getElementById('send-sms-btn');
btn.disabled = true;
try {
const res = await fetch('/api/send-sms', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({phone, captchaId, captchaText}) });
const data = await res.json();
if (data.success) {
countdown = 60;
countdownTimer = setInterval(() => { countdown--; btn.textContent = countdown > 0 ? countdown+'s后重发' : '获取验证码'; if(countdown<=0){clearInterval(countdownTimer);btn.disabled=false;} }, 1000);
alert('验证码已发送');
} else { alert(data.message); btn.disabled = false; if(data.refreshCaptcha) fetchCaptcha('phone'); }
} catch(e) { alert('发送失败,请确保后端已启动'); btn.disabled = false; }
fetchCaptcha('phone');
}
async function handlePhoneLogin(e) {
e.preventDefault();
const phone = document.getElementById('phone').value;
const code = document.getElementById('sms-code').value;
try {
const res = await fetch('/api/verify-code', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({phone, code}) });
const data = await res.json();
if (data.success) { window.location.href = '/'; }
else alert(data.message);
} catch(e) { alert('验证失败'); }
}
async function handleEmailLogin(e) {
e.preventDefault();
const email = document.getElementById('login-email').value;
const password = document.getElementById('login-password').value;
try {
const res = await fetch('/api/login', { method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({email, password}) });
const data = await res.json();
if (data.success) { window.location.href = '/'; }
else alert(data.message);
} catch(e) { alert('登录失败'); }
}
fetchCaptcha('phone');
</script>
{% endblock %}