247 lines
10 KiB
HTML
247 lines
10 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>
|
||
<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;
|
||
--violet:#8b5cf6; --magenta:#c77dff; --cyan:#4cc9f0; --gold:#e7b85c;
|
||
--text:#e9edf6; --text-dim:#9aa6c4;
|
||
--card:rgba(255,255,255,.05); --card-bd:rgba(255,255,255,.12);
|
||
--glow:0 0 22px rgba(139,92,246,.30);
|
||
}
|
||
*{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);
|
||
background:#000;
|
||
display:flex;align-items:center;justify-content:center;min-height:100vh;overflow:hidden;position:relative;
|
||
}
|
||
/* 隐藏原来的光斑动画,改用背景图 */
|
||
body::before,body::after{display:none;}
|
||
|
||
.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 .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;}
|
||
|
||
.card{background:var(--card);border:1px solid var(--card-bd);border-radius:18px;padding:26px 26px 30px;backdrop-filter:blur(10px);box-shadow:var(--glow);}
|
||
.tabs{display:flex;gap:6px;margin-bottom:20px;background:rgba(8,12,26,.5);border-radius:12px;padding:5px;}
|
||
.tabs button{flex:1;font-family:inherit;font-size:14px;font-weight:500;color:var(--text-dim);background:transparent;border:none;padding:9px;border-radius:9px;cursor:pointer;transition:.2s;}
|
||
.tabs button.active{color:#fff;background:rgba(139,92,246,.28);box-shadow:var(--glow);}
|
||
|
||
.field{margin-bottom:14px;}
|
||
.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);}
|
||
|
||
.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);}
|
||
.submit:disabled{opacity:.6;cursor:default;}
|
||
|
||
.msg{margin-top:14px;font-size:13px;text-align:center;min-height:18px;}
|
||
.msg.err{color:#ff8a8a;}
|
||
.msg.ok{color:#8be39a;}
|
||
|
||
.back{text-align:center;margin-top:18px;font-size:13px;color:var(--text-dim);}
|
||
.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;}
|
||
|
||
/* 登录页背景轮播(竖向滑动) */
|
||
.bg-slides{position:fixed;inset:0;z-index:0;overflow:hidden;}
|
||
.bg-track{position:absolute;inset:0;display:flex;flex-direction:column;transition:transform 1.25s cubic-bezier(0.4,0,0.2,1);will-change:transform;}
|
||
.bg-slide{flex:0 0 100%;width:100%;height:100%;background-size:cover;background-position:center;position:relative;}
|
||
.bg-overlay{position:fixed;inset:0;z-index:1;pointer-events:none;
|
||
background:linear-gradient(120deg, rgba(8,12,26,.78), rgba(8,12,26,.48) 55%, rgba(8,12,26,.76)),
|
||
radial-gradient(900px 600px at 50% 40%, transparent, rgba(8,12,26,.55));}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="bg-slides" id="bgSlides"></div>
|
||
<div class="bg-overlay"></div>
|
||
<div class="wrap">
|
||
<div class="brand">
|
||
<div class="cn">宇森</div>
|
||
<div class="en">YUSEN · GARDEN OF CIVILIZATION</div>
|
||
<div class="tag">你不是玩家,你是园丁。</div>
|
||
</div>
|
||
|
||
<div class="card">
|
||
<div class="hint hidden" id="hint">登录后即可进入游戏</div>
|
||
<div class="tabs">
|
||
<button id="tabLogin" class="active">登录</button>
|
||
<button id="tabReg">注册</button>
|
||
</div>
|
||
|
||
<!-- 登录 -->
|
||
<form id="loginForm" autocomplete="off">
|
||
<div class="field">
|
||
<label>账号</label>
|
||
<input id="lLogin" type="text" placeholder="Odoo 用户名 / 邮箱" />
|
||
</div>
|
||
<div class="field">
|
||
<label>密码</label>
|
||
<input id="lPwd" type="password" placeholder="密码" />
|
||
</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="登录用账号" />
|
||
</div>
|
||
<div class="field">
|
||
<label>邮箱</label>
|
||
<input id="rEmail" type="email" placeholder="邮箱(可空)" />
|
||
</div>
|
||
<div class="field">
|
||
<label>密码</label>
|
||
<input id="rPwd" type="password" placeholder="至少 6 位" />
|
||
</div>
|
||
<button class="submit" type="submit">创建园丁账号</button>
|
||
</form>
|
||
|
||
<div class="msg" id="msg"></div>
|
||
</div>
|
||
|
||
<div class="back"><a href="index.html">← 返回官网</a></div>
|
||
</div>
|
||
|
||
<script src="assets/game-api.js"></script>
|
||
<script>
|
||
const tabLogin = document.getElementById('tabLogin');
|
||
const tabReg = document.getElementById('tabReg');
|
||
const loginForm = document.getElementById('loginForm');
|
||
const regForm = document.getElementById('regForm');
|
||
const msg = document.getElementById('msg');
|
||
|
||
// 回跳目标(进入游戏流程带 ?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) {}
|
||
})();
|
||
|
||
function showMsg(text, kind){ msg.textContent = text || ''; msg.className = 'msg' + (kind ? ' ' + kind : ''); }
|
||
function switchTab(which){
|
||
if (which === 'login'){
|
||
tabLogin.classList.add('active'); tabReg.classList.remove('active');
|
||
loginForm.classList.remove('hidden'); regForm.classList.add('hidden');
|
||
} else {
|
||
tabReg.classList.add('active'); tabLogin.classList.remove('active');
|
||
regForm.classList.remove('hidden'); loginForm.classList.add('hidden');
|
||
}
|
||
showMsg('');
|
||
}
|
||
tabLogin.onclick = () => switchTab('login');
|
||
tabReg.onclick = () => switchTab('reg');
|
||
|
||
loginForm.addEventListener('submit', async (e) => {
|
||
e.preventDefault();
|
||
showMsg('');
|
||
const login = document.getElementById('lLogin').value.trim();
|
||
const password = document.getElementById('lPwd').value;
|
||
if (!login || !password){ showMsg('请填写账号和密码', 'err'); return; }
|
||
const btn = loginForm.querySelector('.submit'); btn.disabled = true; btn.textContent = '登录中…';
|
||
try {
|
||
const r = await API.login(login, password);
|
||
if (r.ok){ location.href = nextUrl; }
|
||
else { showMsg(r.error || '登录失败', 'err'); }
|
||
} catch (err) {
|
||
showMsg('网络错误,请稍后重试', 'err');
|
||
} finally {
|
||
btn.disabled = false; btn.textContent = '进入世界';
|
||
}
|
||
});
|
||
|
||
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 btn = regForm.querySelector('.submit'); btn.disabled = true; btn.textContent = '注册中…';
|
||
try {
|
||
const r = await API.register(payload);
|
||
if (r.ok){ location.href = nextUrl; }
|
||
else { showMsg(r.error || '注册失败', 'err'); }
|
||
} catch (err) {
|
||
showMsg('网络错误,请稍后重试', 'err');
|
||
} finally {
|
||
btn.disabled = false; btn.textContent = '创建园丁账号';
|
||
}
|
||
});
|
||
</script>
|
||
<script>
|
||
// 登录页背景轮播(竖向滑动 + 滚轮控制)
|
||
(function(){
|
||
const imgs=[
|
||
'../assets/slides/login_bg.png',
|
||
'../assets/slides/01_starry_sky.png',
|
||
'../assets/slides/02_sky.png',
|
||
'../assets/slides/03_earth.png',
|
||
'../assets/slides/04_underground.png',
|
||
'../assets/slides/05_core.png'
|
||
];
|
||
const box=document.getElementById('bgSlides');
|
||
if(!box) return;
|
||
let cur=0, t=null;
|
||
const track=document.createElement('div');
|
||
track.className='bg-track';
|
||
box.appendChild(track);
|
||
imgs.forEach((s,i)=>{
|
||
const d=document.createElement('div');
|
||
d.className='bg-slide'+(i===0?' active':'');
|
||
d.style.backgroundImage="url('"+s+"')";
|
||
track.appendChild(d);
|
||
});
|
||
const all=track.querySelectorAll('.bg-slide');
|
||
function go(n){
|
||
if(n<0)n=imgs.length-1;if(n>=imgs.length)n=0;
|
||
if(n===cur)return;
|
||
all[cur].classList.remove('active');cur=n;
|
||
track.style.transform='translateY('+(-cur*100)+'%)';
|
||
all[cur].classList.add('active');resetTimer();
|
||
}
|
||
function next(){go(cur+1);}
|
||
function prev(){go(cur-1);}
|
||
function resetTimer(){clearInterval(t);t=setInterval(next,6000);}
|
||
// 鼠标滚轮
|
||
let lock=false,wheeling=0;
|
||
document.addEventListener('wheel',function(e){
|
||
wheeling+=e.deltaY;
|
||
if(lock)return;
|
||
if(Math.abs(wheeling)>50){
|
||
lock=true;
|
||
if(wheeling>0)next();else prev();
|
||
wheeling=0;
|
||
setTimeout(function(){lock=false;},1250);
|
||
}
|
||
},{passive:true});
|
||
resetTimer();
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|