login.html: 密码框增加显示/隐藏切换(眼睛按钮)

This commit is contained in:
李鹏宇 2026-07-23 18:02:04 +08:00
parent f3d252e146
commit 221eb42c3b

View File

@ -4,7 +4,6 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>宇森 · 登录</title>
<link href="https://fonts.googleapis.com/css2?family=ZCOOL+QingKe+HuangYou&family=Noto+Sans+SC:wght@300;400;500;700&display=swap" rel="stylesheet" />
<style>
:root{
--bg-0:#080c1a; --bg-1:#0e1730; --bg-2:#15213f;
@ -16,7 +15,7 @@
*{box-sizing:border-box;margin:0;padding:0;}
html,body{height:100%;}
body{
font-family:"Noto Sans SC",system-ui,sans-serif;color:var(--text);
font-family:"PingFang SC","Hiragino Sans GB","Microsoft YaHei","Noto Sans CJK SC",system-ui,-apple-system,sans-serif;color:var(--text);
background:
radial-gradient(1000px 620px at 82% -8%, rgba(139,92,246,.16), transparent 60%),
radial-gradient(820px 560px at 8% 112%, rgba(76,201,240,.12), transparent 55%),
@ -31,7 +30,7 @@
.wrap{position:relative;z-index:2;width:min(420px,92vw);}
.brand{text-align:center;margin-bottom:26px;}
.brand .cn{font-family:"ZCOOL QingKe HuangYou",sans-serif;font-size:38px;letter-spacing:6px;color:#fff;text-shadow:0 0 18px rgba(139,92,246,.6);}
.brand .cn{font-family:"PingFang SC","Microsoft YaHei",system-ui,sans-serif;font-weight:900;font-size:42px;letter-spacing:8px;color:#fff;text-shadow:0 0 18px rgba(139,92,246,.6);}
.brand .en{font-size:11px;color:var(--magenta);letter-spacing:3px;margin-top:6px;}
.brand .tag{font-size:13px;color:var(--text-dim);margin-top:10px;}
@ -44,6 +43,10 @@
.field label{display:block;font-size:12px;color:var(--text-dim);margin-bottom:6px;letter-spacing:1px;}
.field input{width:100%;background:rgba(8,12,26,.6);border:1px solid var(--card-bd);border-radius:10px;color:var(--text);padding:11px 13px;font-family:inherit;font-size:14px;outline:none;transition:.2s;}
.field input:focus{border-color:var(--violet);box-shadow:0 0 0 3px rgba(139,92,246,.18);}
.pw-wrap{position:relative;}
.pw-wrap input{padding-right:40px;}
.pw-toggle{position:absolute;right:8px;top:50%;transform:translateY(-50%);background:transparent;border:none;color:var(--text-dim);cursor:pointer;font-size:16px;line-height:1;padding:4px 6px;border-radius:6px;transition:.2s;}
.pw-toggle:hover{color:#fff;background:rgba(255,255,255,.08);}
.submit{width:100%;margin-top:6px;font-size:15px;font-weight:700;color:#0b1020;background:linear-gradient(120deg,var(--gold),#f0d49a);padding:12px;border-radius:11px;cursor:pointer;border:none;letter-spacing:2px;transition:.22s;box-shadow:0 0 18px rgba(231,184,92,.35);}
.submit:hover{filter:brightness(1.08);}
@ -57,8 +60,6 @@
.back a{color:var(--cyan);text-decoration:none;}
.back a:hover{text-decoration:underline;}
.hint{margin-bottom:16px;font-size:13px;color:var(--cyan);background:rgba(76,201,240,.10);border:1px solid rgba(76,201,240,.30);border-radius:10px;padding:9px 12px;text-align:center;}
.hidden{display:none;}
</style>
</head>
@ -71,7 +72,6 @@
</div>
<div class="card">
<div class="hint hidden" id="hint">登录后即可进入游戏</div>
<div class="tabs">
<button id="tabLogin" class="active">登录</button>
<button id="tabReg">注册</button>
@ -81,32 +81,41 @@
<form id="loginForm" autocomplete="off">
<div class="field">
<label>账号</label>
<input id="lLogin" type="text" placeholder="Odoo 用户名 / 邮箱" />
<input id="lLogin" type="text" placeholder="Odoo 用户名" />
</div>
<div class="field">
<label>密码</label>
<input id="lPwd" type="password" placeholder="密码" />
<div class="pw-wrap">
<input id="lPwd" type="password" placeholder="密码" />
<button type="button" class="pw-toggle" data-target="lPwd" aria-label="显示密码">👁</button>
</div>
</div>
<button class="submit" type="submit">进入世界</button>
</form>
<!-- 注册 -->
<form id="regForm" class="hidden" autocomplete="off">
<div class="field">
<label>昵称</label>
<input id="rName" type="text" placeholder="显示名称(可空)" />
</div>
<div class="field">
<label>账号</label>
<input id="rLogin" type="text" placeholder="登录用账号" />
<input id="rLogin" type="text" placeholder="登录用账号(字母/数字/._-" />
</div>
<div class="field">
<label>邮箱</label>
<input id="rEmail" type="email" placeholder="邮箱(可空)" />
<label>昵称</label>
<input id="rName" type="text" placeholder="默认与账号一致,可改" />
</div>
<div class="field">
<label>密码</label>
<input id="rPwd" type="password" placeholder="至少 6 位" />
<div class="pw-wrap">
<input id="rPwd" type="password" placeholder="至少 8 位,字母+数字" />
<button type="button" class="pw-toggle" data-target="rPwd" aria-label="显示密码">👁</button>
</div>
</div>
<div class="field">
<label>确认密码</label>
<div class="pw-wrap">
<input id="rPwd2" type="password" placeholder="再次输入密码" />
<button type="button" class="pw-toggle" data-target="rPwd2" aria-label="显示密码">👁</button>
</div>
</div>
<button class="submit" type="submit">创建园丁账号</button>
</form>
@ -128,8 +137,6 @@
// 回跳目标(进入游戏流程带 ?next=world.html
const params = new URLSearchParams(location.search);
const nextUrl = params.get('next') || 'world.html';
const hint = document.getElementById('hint');
if (params.get('next')) hint.classList.remove('hidden');
// 已登录则直接跳走
(async () => {
try { const me = await API.me(); if (me && me.uid) location.href = nextUrl; } catch (e) {}
@ -149,6 +156,34 @@
tabLogin.onclick = () => switchTab('login');
tabReg.onclick = () => switchTab('reg');
// 密码显示/隐藏切换(眼睛按钮)
document.querySelectorAll('.pw-toggle').forEach(btn => {
btn.addEventListener('click', () => {
const input = document.getElementById(btn.dataset.target);
if (!input) return;
if (input.type === 'password') {
input.type = 'text';
btn.textContent = '🙈';
btn.setAttribute('aria-label', '隐藏密码');
} else {
input.type = 'password';
btn.textContent = '👁';
btn.setAttribute('aria-label', '显示密码');
}
input.focus();
});
});
// 昵称默认 = 账号:账号变更时若昵称仍空/等于上次账号值,则同步;用户改过昵称则保留
const rLogin = document.getElementById('rLogin');
const rName = document.getElementById('rName');
let lastLoginVal = '';
rLogin.addEventListener('input', () => {
const v = rLogin.value.trim();
if (rName.value === '' || rName.value === lastLoginVal) rName.value = v;
lastLoginVal = v;
});
loginForm.addEventListener('submit', async (e) => {
e.preventDefault();
showMsg('');
@ -170,16 +205,19 @@
regForm.addEventListener('submit', async (e) => {
e.preventDefault();
showMsg('');
const payload = {
name: document.getElementById('rName').value.trim(),
login: document.getElementById('rLogin').value.trim(),
email: document.getElementById('rEmail').value.trim(),
password: document.getElementById('rPwd').value,
};
if (!payload.login || !payload.password){ showMsg('账号和密码必填', 'err'); return; }
const login = document.getElementById('rLogin').value.trim();
const name = document.getElementById('rName').value.trim();
const password = document.getElementById('rPwd').value;
const pwd2 = document.getElementById('rPwd2').value;
if (!login) { showMsg('请填写账号', 'err'); return; }
if (password.length < 8) { showMsg('密码至少 8 ', 'err'); return; }
if (!/[a-zA-Z]/.test(password) || !/\d/.test(password)) {
showMsg('密码必须同时包含字母和数字', 'err'); return;
}
if (password !== pwd2) { showMsg('两次密码输入不一致', 'err'); return; }
const btn = regForm.querySelector('.submit'); btn.disabled = true; btn.textContent = '注册中…';
try {
const r = await API.register(payload);
const r = await API.register({ name, login, password });
if (r.ok){ location.href = nextUrl; }
else { showMsg(r.error || '注册失败', 'err'); }
} catch (err) {