All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 21s
- 后端: Auth(登录/登出/me + session 中间件)、Users、Tokens 路由与 Service, scrypt 哈希+timingSafeEqual 校验、requireAdmin 保护、admin 用户自动初始化 - 前端: login.html(登录页, 无账号密码提示)、admin.html(用户+Token 管理, 令牌明文显隐/复制/吊销/重置密码)、标题栏用户信息+系统管理入口 - 持久化: jsonAdapter 支持 users/api-tokens,运行时数据忽略入库 - 文档: 需求.md/原型设计.md 同步
96 lines
3.8 KiB
HTML
96 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>登录 - Registry 配置管理中心</title>
|
|
<link rel="stylesheet" href="/css/style.css">
|
|
<style>
|
|
body.login-page {
|
|
background: linear-gradient(135deg, #003a70 0%, #0a4a86 48%, #0b63a8 100%);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
height: 100vh;
|
|
}
|
|
.login-wrap { width: 400px; max-width: calc(100vw - 32px); }
|
|
.login-card { background: #fff; border-radius: 8px; box-shadow: 0 18px 50px rgba(0,0,0,0.35); overflow: hidden; }
|
|
.login-card-header { background: linear-gradient(to bottom, #0a4a86, #003a70); color: #fff; padding: 28px 24px 22px; text-align: center; }
|
|
.login-logo { font-size: 36px; line-height: 1; }
|
|
.login-card-header h1 { font-size: 18px; font-weight: 600; margin-top: 10px; }
|
|
.login-card-header p { font-size: 12px; color: #cfe3f7; margin-top: 4px; }
|
|
.login-card-body { padding: 24px; }
|
|
.login-card-body .form-group { margin-bottom: 16px; }
|
|
.login-card-body .form-group input { height: 36px; }
|
|
.login-error { display: none; margin-bottom: 14px; padding: 8px 12px; border: 1px solid #f2b8b5; background: #fdecea; color: #c62828; border-radius: 3px; font-size: 12px; }
|
|
.login-error.show { display: block; }
|
|
.login-btn { width: 100%; height: 38px; font-size: 14px; font-weight: 600; }
|
|
.login-footer { margin-top: 16px; text-align: center; font-size: 11px; color: rgba(255,255,255,0.65); }
|
|
</style>
|
|
</head>
|
|
<body class="login-page">
|
|
<div class="login-wrap">
|
|
<div class="login-card">
|
|
<div class="login-card-header">
|
|
<div class="login-logo">📋</div>
|
|
<h1>Registry 配置管理中心</h1>
|
|
<p>微服务配置集中化 · 可视化 · 规范化管理</p>
|
|
</div>
|
|
<div class="login-card-body">
|
|
<div class="login-error" id="login-error"></div>
|
|
<form id="login-form" autocomplete="off">
|
|
<div class="form-group">
|
|
<label>用户名 <span class="required">*</span></label>
|
|
<input type="text" id="username" placeholder="请输入用户名" autofocus>
|
|
</div>
|
|
<div class="form-group">
|
|
<label>密码 <span class="required">*</span></label>
|
|
<input type="password" id="password" placeholder="请输入密码">
|
|
</div>
|
|
<button type="submit" class="btn btn-primary login-btn" id="btn-login">登 录</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<div class="login-footer">Registry Config Center</div>
|
|
</div>
|
|
<script>
|
|
// 已登录则直接跳转
|
|
if (localStorage.getItem("registry_token")) {
|
|
window.location.href = "/projects.html";
|
|
}
|
|
|
|
document.getElementById("login-form").addEventListener("submit", async function (e) {
|
|
e.preventDefault();
|
|
var error = document.getElementById("login-error");
|
|
var btn = document.getElementById("btn-login");
|
|
var username = document.getElementById("username").value.trim();
|
|
var password = document.getElementById("password").value;
|
|
|
|
error.classList.remove("show");
|
|
|
|
if (!username || !password) {
|
|
error.textContent = "请输入用户名和密码";
|
|
error.classList.add("show");
|
|
return;
|
|
}
|
|
|
|
btn.disabled = true;
|
|
btn.textContent = "登录中...";
|
|
|
|
try {
|
|
var data = await API.login(username, password);
|
|
localStorage.setItem("registry_token", data.token);
|
|
localStorage.setItem("registry_user", JSON.stringify(data.user));
|
|
window.location.href = "/projects.html";
|
|
} catch (err) {
|
|
error.textContent = err.message || "登录失败";
|
|
error.classList.add("show");
|
|
btn.disabled = false;
|
|
btn.textContent = "登 录";
|
|
}
|
|
});
|
|
</script>
|
|
<script src="/js/api.js"></script>
|
|
</body>
|
|
</html>
|