2026-06-18 15:40:53 +08:00
<!DOCTYPE html>
< html lang = "zh-CN" >
< head >
< meta charset = "UTF-8" >
2026-06-18 18:28:08 +08:00
< meta name = "viewport" content = "width=device-width,initial-scale=1.0" >
< title > 光湖 · 注册< / title >
2026-06-18 15:40:53 +08:00
< style >
*{margin:0;padding:0;box-sizing:border-box}
2026-06-18 18:28:08 +08:00
:root{
--bg:#060a14;--card:rgba(14,20,48,0.8);
--blue:#60a5fa;--cyan:#22d3ee;--text:#eaf0ff;--dim:#94a7d0;
--border:rgba(96,165,250,0.15);--ok:#34d399;--err:#f87171;
}
body{font-family:-apple-system,BlinkMacSystemFont,'PingFang SC','Microsoft YaHei',sans-serif;background:var(--bg);color:var(--text);min-height:100vh;display:flex;align-items:center;justify-content:center;overflow:hidden}
.bg{position:fixed;inset:0;background:radial-gradient(ellipse at 30% 20%,rgba(40,80,160,0.3),transparent 60%),radial-gradient(ellipse at 70% 80%,rgba(30,60,130,0.25),transparent 60%),#060a14;z-index:0}
.card{position:relative;z-index:1;width:100%;max-width:400px;padding:40px 32px;background:var(--card);border:1px solid var(--border);border-radius:16px;backdrop-filter:blur(20px)}
.logo{text-align:center;font-size:32px;margin-bottom:8px}
.title{text-align:center;font-size:22px;font-weight:500;color:var(--text);margin-bottom:4px}
.sub{text-align:center;font-size:13px;color:var(--dim);margin-bottom:28px}
.step{display:none}
.step.active{display:block}
label{display:block;font-size:13px;color:var(--dim);margin-bottom:6px}
input{width:100%;padding:12px;border-radius:10px;border:1px solid var(--border);background:rgba(12,20,40,0.6);color:var(--text);font-size:15px;outline:none;transition:border .3s;margin-bottom:16px}
input:focus{border-color:var(--blue)}
.btn{width:100%;padding:12px;border-radius:10px;border:none;background:linear-gradient(135deg,var(--blue),var(--cyan));color:#fff;font-size:15px;font-weight:500;cursor:pointer;transition:opacity .3s}
.btn:hover{opacity:.85}
2026-06-18 15:40:53 +08:00
.btn:disabled{opacity:.5;cursor:not-allowed}
2026-06-18 18:28:08 +08:00
.msg{text-align:center;font-size:13px;margin-top:12px;min-height:20px}
.msg.ok{color:var(--ok)}
.msg.err{color:var(--err)}
.back{display:block;text-align:center;margin-top:16px;font-size:13px;color:var(--dim);text-decoration:none}
.back:hover{color:var(--blue)}
.countdown{color:var(--dim)}
2026-06-18 15:40:53 +08:00
< / style >
< / head >
< body >
2026-06-18 18:28:08 +08:00
< div class = "bg" > < / div >
2026-06-18 15:40:53 +08:00
< div class = "card" >
2026-06-18 18:28:08 +08:00
< div class = "logo" > 🌊< / div >
< div class = "title" > 注册光湖协作中心< / div >
< div class = "sub" > 用邮箱注册,立即开始协作< / div >
< div id = "step1" class = "step active" >
< label > 邮箱地址< / label >
2026-06-18 15:40:53 +08:00
< input type = "email" id = "email" placeholder = "your@email.com" autocomplete = "email" >
2026-06-18 18:28:08 +08:00
< button class = "btn" id = "sendBtn" onclick = "sendCode()" > 发送验证码< / button >
< div class = "msg" id = "msg1" > < / div >
2026-06-18 15:40:53 +08:00
< / div >
2026-06-18 18:28:08 +08:00
< div id = "step2" class = "step" >
< label > 验证码(已发送至 < span id = "emailDisplay" > < / span > ) < / label >
< input type = "text" id = "code" placeholder = "6位验证码" maxlength = "6" autocomplete = "one-time-code" >
< label > 设置密码< / label >
< input type = "password" id = "password" placeholder = "至少6位" >
< button class = "btn" id = "verifyBtn" onclick = "verifyCode()" > 完成注册< / button >
< div class = "msg" id = "msg2" > < / div >
< a href = "#" class = "back" onclick = "backToStep1()" > ← 换一个邮箱< / a >
2026-06-18 15:40:53 +08:00
< / div >
2026-06-18 18:28:08 +08:00
< div class = "msg" id = "msg3" style = "margin-top:16px" > < / div >
< a href = "/outline/" class = "back" style = "margin-top:8px" > 已有账号?去登录 →< / a >
2026-06-18 15:40:53 +08:00
< / div >
< script >
2026-06-18 18:28:08 +08:00
let countdownTimer = null;
async function sendCode() {
2026-06-18 15:40:53 +08:00
const email = document.getElementById('email').value.trim();
2026-06-18 18:28:08 +08:00
const msg = document.getElementById('msg1');
const btn = document.getElementById('sendBtn');
2026-06-18 15:40:53 +08:00
2026-06-18 18:28:08 +08:00
if (!email || !email.includes('@')) {
msg.className = 'msg err'; msg.textContent = '请输入有效邮箱';
return;
}
2026-06-18 15:40:53 +08:00
2026-06-18 18:28:08 +08:00
btn.disabled = true; btn.textContent = '发送中...';
msg.className = 'msg'; msg.textContent = '';
2026-06-18 15:40:53 +08:00
2026-06-18 18:28:08 +08:00
try {
const res = await fetch('/register-api/send-code', {
method: 'POST', headers: {'Content-Type':'application/json'},
body: JSON.stringify({email})
});
const data = await res.json();
if (data.ok) {
document.getElementById('emailDisplay').textContent = email;
document.getElementById('step1').classList.remove('active');
document.getElementById('step2').classList.add('active');
startCountdown(60);
} else {
msg.className = 'msg err'; msg.textContent = data.error;
btn.disabled = false; btn.textContent = '发送验证码';
}
} catch(e) {
msg.className = 'msg err'; msg.textContent = '网络错误,请重试';
btn.disabled = false; btn.textContent = '发送验证码';
}
}
function startCountdown(sec) {
if (countdownTimer) clearInterval(countdownTimer);
const btn = document.getElementById('sendBtn');
2026-06-18 15:40:53 +08:00
btn.disabled = true;
2026-06-18 18:28:08 +08:00
countdownTimer = setInterval(() => {
sec--;
if (sec < = 0) {
clearInterval(countdownTimer);
btn.disabled = false;
btn.textContent = '重新发送';
} else {
btn.textContent = `${sec}秒后重发`;
}
}, 1000);
}
async function verifyCode() {
const email = document.getElementById('email').value.trim();
const code = document.getElementById('code').value.trim();
const password = document.getElementById('password').value;
const msg = document.getElementById('msg2');
const btn = document.getElementById('verifyBtn');
if (!code || code.length !== 6) {
msg.className = 'msg err'; msg.textContent = '请输入6位验证码';
return;
}
if (!password || password.length < 6 ) {
msg.className = 'msg err'; msg.textContent = '密码至少6位';
return;
}
btn.disabled = true; btn.textContent = '注册中...';
2026-06-18 15:40:53 +08:00
try {
2026-06-18 18:28:08 +08:00
const res = await fetch('/register-api/verify', {
method: 'POST', headers: {'Content-Type':'application/json'},
body: JSON.stringify({email, code, password})
2026-06-18 15:40:53 +08:00
});
const data = await res.json();
if (data.ok) {
2026-06-18 18:28:08 +08:00
msg.className = 'msg ok'; msg.textContent = '注册成功! 3秒后跳转登录...';
setTimeout(() => { window.location.href = '/outline/'; }, 3000);
2026-06-18 15:40:53 +08:00
} else {
2026-06-18 18:28:08 +08:00
msg.className = 'msg err'; msg.textContent = data.error;
btn.disabled = false; btn.textContent = '完成注册';
2026-06-18 15:40:53 +08:00
}
} catch(e) {
2026-06-18 18:28:08 +08:00
msg.className = 'msg err'; msg.textContent = '网络错误,请重试';
btn.disabled = false; btn.textContent = '完成注册';
2026-06-18 15:40:53 +08:00
}
}
2026-06-18 18:28:08 +08:00
function backToStep1() {
document.getElementById('step2').classList.remove('active');
document.getElementById('step1').classList.add('active');
if (countdownTimer) clearInterval(countdownTimer);
const btn = document.getElementById('sendBtn');
btn.disabled = false; btn.textContent = '发送验证码';
2026-06-18 15:40:53 +08:00
}
< / script >
< / body >
< / html >