Files
blog/write-server/nginx/login.html
T
2026-06-21 23:58:29 +08:00

115 lines
3.8 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>写作后台 - 登录</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{min-height:100vh;display:flex;align-items:center;justify-content:center;background:#fcfaf5;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}
.login-card{background:#fff;border-radius:16px;box-shadow:0 4px 24px rgba(34,61,102,.08);padding:48px 40px;width:100%;max-width:380px}
h1{font-size:20px;color:#1d3d6c;margin-bottom:4px;font-weight:700}
.sub{font-size:13px;color:#999;margin-bottom:32px}
.field{margin-bottom:20px}
.field label{display:block;font-size:13px;color:#223d66;margin-bottom:6px;font-weight:500}
.field input{width:100%;padding:10px 14px;border:1.5px solid #e4dfd2;border-radius:8px;font-size:14px;color:#223d66;background:#fcfaf5;outline:none;transition:border .2s}
.field input:focus{border-color:#1d3d6c}
.btn{width:100%;padding:12px;background:#1d3d6c;color:#fff;border:none;border-radius:8px;font-size:15px;font-weight:600;cursor:pointer;transition:opacity .2s;margin-top:4px}
.btn:hover{opacity:.85}
.btn:active{opacity:.7}
.btn:disabled{opacity:.5;cursor:not-allowed}
.error{background:#fef2f2;color:#dc2626;font-size:13px;padding:10px 14px;border-radius:8px;margin-bottom:16px;display:none}
</style>
</head>
<body>
<div class="login-card">
<h1>写作后台</h1>
<p class="sub">优世界 · Blog Admin</p>
<div class="error" id="err">用户名或密码错误</div>
<form id="form">
<div class="field">
<label>用户名</label>
<input type="text" id="user" autocomplete="username" autofocus required>
</div>
<div class="field">
<label>密码</label>
<input type="password" id="pass" autocomplete="current-password" required>
</div>
<button class="btn" type="submit" id="btn">登 录</button>
</form>
</div>
<script>
document.getElementById('form').addEventListener('submit', async function(e) {
e.preventDefault();
var btn = document.getElementById('btn');
var err = document.getElementById('err');
btn.disabled = true;
btn.textContent = '登录中...';
err.style.display = 'none';
var u = document.getElementById('user').value;
var p = document.getElementById('pass').value;
var tok = btoa(u + ':' + p);
try {
// 验证凭据
var res = await fetch('/auth/check', {
headers: { 'Authorization': 'Basic ' + tok }
});
if (!res.ok) {
throw new Error('auth failed');
}
// 存储凭据
localStorage.setItem('wauth', tok);
// 注册 Service Worker
if ('serviceWorker' in navigator) {
var reg = await navigator.serviceWorker.register('/sw.js');
// 等待 SW 激活
if (reg.installing) {
await new Promise(function(resolve) {
reg.installing.addEventListener('statechange', function() {
if (this.state === 'activated') resolve();
});
});
}
// 发送 token 给 SW
var sw = reg.active || reg.waiting || reg.installing;
if (sw) {
sw.postMessage({ type: 'SET_TOKEN', token: tok });
}
// 确保 SW 控制当前页面
if (navigator.serviceWorker.controller) {
navigator.serviceWorker.controller.postMessage({ type: 'SET_TOKEN', token: tok });
}
}
// 跳转到主页
location.href = '/';
} catch (err2) {
err.style.display = 'block';
btn.disabled = false;
btn.textContent = '登 录';
}
});
// 已登录则验证后跳转
(function(){
var tok = localStorage.getItem('wauth');
if (!tok) return;
fetch('/auth/check', { headers: { 'Authorization': 'Basic ' + tok } }).then(function(r) {
if (r.ok) {
location.href = '/';
} else {
localStorage.removeItem('wauth');
}
}).catch(function() {
localStorage.removeItem('wauth');
});
})();
</script>
</body>
</html>