冰朔 2bfc3c547b
Some checks failed
自动更新代码和重启 / update-and-restart (push) Has been cancelled
CI检查 + 自动部署 / check (push) Has been cancelled
CI检查 + 自动部署 / deploy (push) Has been cancelled
铸渊自检 / health-check (push) Has been cancelled
D135c: 铸渊执行记录 · guada部署·Outline修复·邮箱注册系统
完成:
- Nginx /api/ 路由修复(3998→3090)
- guada Agent引擎部署(BS-SG-001:8787)
- Outline文件写入权限修复
- Dex数据库持久化+权限修复
- 邮箱注册系统(register.html + register-api:3997)
- 注册服务改用Python写Dex BLOB(修复node-sqlite3格式问题)

待修复:
- 注册后退出再登录间歇性OAuth state丢失(考虑独立子域名)

记录: cc-d135c.hdlp
2026-06-18 18:28:08 +08:00

164 lines
6.5 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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}
: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}
.btn:disabled{opacity:.5;cursor:not-allowed}
.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)}
</style>
</head>
<body>
<div class="bg"></div>
<div class="card">
<div class="logo">🌊</div>
<div class="title">注册光湖协作中心</div>
<div class="sub">用邮箱注册,立即开始协作</div>
<div id="step1" class="step active">
<label>邮箱地址</label>
<input type="email" id="email" placeholder="your@email.com" autocomplete="email">
<button class="btn" id="sendBtn" onclick="sendCode()">发送验证码</button>
<div class="msg" id="msg1"></div>
</div>
<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>
</div>
<div class="msg" id="msg3" style="margin-top:16px"></div>
<a href="/outline/" class="back" style="margin-top:8px">已有账号?去登录 →</a>
</div>
<script>
let countdownTimer = null;
async function sendCode() {
const email = document.getElementById('email').value.trim();
const msg = document.getElementById('msg1');
const btn = document.getElementById('sendBtn');
if (!email || !email.includes('@')) {
msg.className = 'msg err'; msg.textContent = '请输入有效邮箱';
return;
}
btn.disabled = true; btn.textContent = '发送中...';
msg.className = 'msg'; msg.textContent = '';
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');
btn.disabled = true;
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 = '注册中...';
try {
const res = await fetch('/register-api/verify', {
method: 'POST', headers: {'Content-Type':'application/json'},
body: JSON.stringify({email, code, password})
});
const data = await res.json();
if (data.ok) {
msg.className = 'msg ok'; msg.textContent = '注册成功3秒后跳转登录...';
setTimeout(() => { window.location.href = '/outline/'; }, 3000);
} 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 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 = '发送验证码';
}
</script>
</body>
</html>