121 lines
5.5 KiB
HTML
121 lines
5.5 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="zh-CN">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>登录 - RainWeb</title>
|
|
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
|
|
<link rel="stylesheet" href="/css/style.css">
|
|
<style>
|
|
.password-wrapper { position: relative; }
|
|
.password-wrapper input { width: 100%; padding-right: 44px; }
|
|
.password-wrapper .toggle-pw { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); background: none; border: none; color: var(--md-ref-on-surface-variant); cursor: pointer; padding: 4px; border-radius: 50%; display: flex; align-items: center; justify-content: center; }
|
|
.password-wrapper .toggle-pw:hover { background: var(--md-ref-surface-variant); }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="login-page">
|
|
<div class="card login-card">
|
|
<h1>登录</h1>
|
|
<p class="subtitle">欢迎回到 RainWeb</p>
|
|
<div class="form-group"><label>用户名</label><input type="text" id="username" placeholder="输入用户名" autocomplete="username" autofocus></div>
|
|
<div class="form-group"><label>密码</label>
|
|
<div class="password-wrapper"><input type="password" id="password" placeholder="输入密码" autocomplete="current-password">
|
|
<button class="toggle-pw" type="button" onclick="togglePw(this)" tabindex="-1"><span class="material-icons" style="font-size:20px">visibility_off</span></button></div>
|
|
</div>
|
|
<div id="loginError" style="color:var(--md-ref-error);font-size:14px;margin-bottom:12px;display:none"></div>
|
|
<button class="btn w-full" id="capBtn" onclick="doCaptcha()" style="display:none;margin-bottom:8px;background:#fff;color:#333;border:1px solid #333;justify-content:center;height:44px">
|
|
<span class="material-icons" id="capBtnIcon" style="font-size:20px">verified_user</span>
|
|
<span id="capBtnText">点击进行人机验证</span>
|
|
</button>
|
|
<button class="btn btn-filled w-full" onclick="handleLogin()" id="loginBtn">登录</button>
|
|
<div style="text-align:center;margin-top:16px">
|
|
<span class="text-muted">没有账户?</span>
|
|
<a href="/register.html" class="btn-text btn" style="font-size:14px">注册</a>
|
|
</div>
|
|
<div style="text-align:center;margin-top:8px">
|
|
<a href="/" class="btn-text btn" style="font-size:14px">← 返回主页</a>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="snackbar" class="snackbar"></div>
|
|
<script src="/js/theme.js"></script>
|
|
<script src="/js/api.js"></script>
|
|
<script src="/js/nav.js"></script>
|
|
<script src="/js/captcha.js"></script>
|
|
<script>
|
|
const token = localStorage.getItem('token');
|
|
if (token) window.location.href = '/';
|
|
|
|
let captchaNeeded = false;
|
|
let settingsLoaded = false;
|
|
|
|
// First load settings, then check captcha
|
|
API.getPublicSettings().then(s => {
|
|
window._recaptchaSiteKey = s.recaptcha_site_key || '';
|
|
window._turnstileSiteKey = s.turnstile_site_key || '';
|
|
settingsLoaded = true;
|
|
// Now check captcha
|
|
CAPTCHA.checkRequired('login').then(r => {
|
|
if (r.required) {
|
|
captchaNeeded = true;
|
|
document.getElementById('capBtn').style.display = 'inline-flex';
|
|
}
|
|
});
|
|
});
|
|
|
|
function togglePw(btn) {
|
|
const input = btn.parentElement.querySelector('input');
|
|
const icon = btn.querySelector('.material-icons');
|
|
if (input.type === 'password') { input.type = 'text'; icon.textContent = 'visibility'; }
|
|
else { input.type = 'password'; icon.textContent = 'visibility_off'; }
|
|
}
|
|
|
|
async function doCaptcha() {
|
|
const ok = await CAPTCHA.showModal('login');
|
|
if (ok) {
|
|
document.getElementById('capBtn').style.background = '#e8f5e9';
|
|
document.getElementById('capBtn').style.borderColor = '#4caf50';
|
|
document.getElementById('capBtn').style.color = '#2e7d32';
|
|
document.getElementById('capBtnIcon').textContent = 'check_circle';
|
|
document.getElementById('capBtnText').textContent = '验证通过';
|
|
document.getElementById('capBtn').disabled = true;
|
|
}
|
|
}
|
|
|
|
async function handleLogin() {
|
|
const username = document.getElementById('username').value.trim();
|
|
const password = document.getElementById('password').value;
|
|
const errEl = document.getElementById('loginError');
|
|
const btn = document.getElementById('loginBtn');
|
|
if (!username || !password) { errEl.textContent = '请输入用户名和密码'; errEl.style.display = 'block'; return; }
|
|
|
|
if (captchaNeeded && !CAPTCHA.verified) {
|
|
errEl.textContent = '请先点击验证按钮完成验证';
|
|
errEl.style.display = 'block'; return;
|
|
}
|
|
|
|
errEl.style.display = 'none';
|
|
btn.disabled = true;
|
|
btn.textContent = '登录中...';
|
|
try {
|
|
const data = await API.login(username, password, 'verified');
|
|
localStorage.setItem('token', data.token);
|
|
localStorage.setItem('username', data.username);
|
|
localStorage.setItem('role', data.role);
|
|
window.location.href = '/';
|
|
} catch (e) {
|
|
errEl.textContent = e.message;
|
|
errEl.style.display = 'block';
|
|
btn.disabled = false;
|
|
btn.textContent = '登录';
|
|
}
|
|
}
|
|
|
|
document.getElementById('username').addEventListener('keydown', e => { if (e.key === 'Enter') document.getElementById('password').focus(); });
|
|
document.getElementById('password').addEventListener('keydown', e => { if (e.key === 'Enter') handleLogin(); });
|
|
</script>
|
|
</body>
|
|
</html>
|