sec commit

This commit is contained in:
2026-04-02 00:59:42 +08:00
parent ab7dabc6a8
commit 881cca3fe6
1835 changed files with 207016 additions and 0 deletions

View File

@@ -0,0 +1,224 @@
<!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; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f0f2f5; display: flex; align-items: center; justify-content: center; min-height: 100vh; }
.container { background: #fff; border-radius: 12px; box-shadow: 0 2px 12px rgba(0,0,0,0.1); padding: 40px 36px; width: 400px; }
.logo { text-align: center; margin-bottom: 28px; }
.logo h1 { font-size: 24px; color: #1a1a2e; font-weight: 600; }
.logo p { font-size: 13px; color: #888; margin-top: 4px; }
.form-group { margin-bottom: 16px; }
label { display: block; font-size: 14px; color: #333; margin-bottom: 6px; font-weight: 500; }
input { width: 100%; height: 44px; padding: 0 14px; border: 1px solid #ddd; border-radius: 8px; font-size: 15px; outline: none; transition: border-color 0.2s; }
input:focus { border-color: #4f46e5; }
.captcha-row { display: flex; gap: 10px; }
.captcha-row input { flex: 1; }
.captcha-canvas { height: 44px; border-radius: 8px; cursor: pointer; border: 1px solid #ddd; background: #f9fafb; }
.sms-row { display: flex; gap: 10px; }
.sms-row input { flex: 1; }
.btn-sms { height: 44px; padding: 0 16px; background: #e8e7ff; color: #4f46e5; border: none; border-radius: 8px; font-size: 14px; font-weight: 600; cursor: pointer; white-space: nowrap; flex-shrink: 0; }
.btn-sms:hover { background: #dddbf0; }
.btn-sms:disabled { background: #f0f0f0; color: #aaa; cursor: not-allowed; }
.btn { width: 100%; height: 46px; background: #4f46e5; color: #fff; border: none; border-radius: 8px; font-size: 16px; font-weight: 600; cursor: pointer; transition: background 0.2s; margin-top: 10px; }
.btn:hover { background: #4338ca; }
.btn:disabled { background: #a5a6f6; cursor: not-allowed; }
.links { text-align: center; margin-top: 16px; font-size: 13px; }
.links a { color: #4f46e5; text-decoration: none; }
.links a:hover { text-decoration: underline; }
.msg { padding: 10px 14px; border-radius: 8px; font-size: 13px; margin-bottom: 16px; display: none; }
.msg.error { background: #fef2f2; color: #dc2626; border: 1px solid #fca5a5; display: block; }
.msg.success { background: #f0fdf4; color: #16a34a; border: 1px solid #86efac; display: block; }
.loading { display: none; text-align: center; margin-top: 10px; font-size: 13px; color: #888; }
.tip { font-size: 12px; color: #888; margin-top: 4px; }
</style>
</head>
<body>
<div class="container">
<div class="logo">
<h1>创建账号</h1>
<p>3分钟完成注册</p>
</div>
<div id="msg" class="msg"></div>
<form id="regForm">
<div class="form-group">
<label for="phone">手机号</label>
<input type="tel" id="phone" placeholder="请输入手机号" maxlength="11" required autocomplete="tel">
</div>
<div class="form-group">
<label for="captchaCode">图形验证码</label>
<div class="captcha-row">
<input type="text" id="captchaCode" placeholder="请输入图形验证码" maxlength="4" required style="flex:1">
<canvas id="captchaCanvas" class="captcha-canvas" width="100" height="44" title="点击刷新"></canvas>
</div>
<p class="tip">点击图片刷新验证码</p>
</div>
<div class="form-group">
<label for="smsCode">短信验证码</label>
<div class="sms-row">
<input type="text" id="smsCode" placeholder="请输入短信验证码" maxlength="6" required>
<button type="button" class="btn-sms" id="sendBtn">发送验证码</button>
</div>
</div>
<div class="form-group">
<label for="password">设置密码</label>
<input type="password" id="password" placeholder="6位及以上密码" minlength="6" required>
<p class="tip">密码至少6位建议混合字母和数字</p>
</div>
<button type="submit" class="btn" id="submitBtn">注册</button>
</form>
<div class="links">
<a href="login.html">已有账号?立即登录</a>
</div>
<div id="loading" class="loading">注册中...</div>
</div>
<script>
const API = 'http://localhost:3000/api/auth';
let captchaKey = '';
let smsCountdown = 0;
let smsTimer = null;
const form = document.getElementById('regForm');
const msg = document.getElementById('msg');
const sendBtn = document.getElementById('sendBtn');
const submitBtn = document.getElementById('submitBtn');
const canvas = document.getElementById('captchaCanvas');
const ctx = canvas.getContext('2d');
// Generate a simple random captcha
function generateCaptcha() {
captchaKey = Math.random().toString(36).slice(2, 10);
const code = Math.random().toString(36).slice(2, 6).toUpperCase();
localStorage.setItem('captcha_' + captchaKey, code);
drawCaptcha(code);
}
function drawCaptcha(code) {
ctx.clearRect(0, 0, 100, 44);
ctx.fillStyle = '#f9fafb';
ctx.fillRect(0, 0, 100, 44);
ctx.font = 'bold 22px monospace';
ctx.fillStyle = '#1a1a2e';
// slight rotation effect
ctx.save();
ctx.translate(10, 30);
ctx.rotate(-0.1);
ctx.fillText(code.slice(0, 2), 0, 0);
ctx.restore();
ctx.save();
ctx.translate(55, 30);
ctx.rotate(0.1);
ctx.fillText(code.slice(2), 0, 0);
ctx.restore();
//干扰线
ctx.strokeStyle = '#ddd';
for (let i = 0; i < 3; i++) {
ctx.beginPath();
ctx.moveTo(Math.random() * 100, Math.random() * 44);
ctx.lineTo(Math.random() * 100, Math.random() * 44);
ctx.stroke();
}
}
canvas.addEventListener('click', generateCaptcha);
generateCaptcha();
function showMsg(text, type) {
msg.textContent = text;
msg.className = 'msg ' + type;
msg.style.display = 'block';
}
function hideMsg() { msg.style.display = 'none'; }
sendBtn.addEventListener('click', async () => {
if (smsCountdown > 0) return;
const phone = document.getElementById('phone').value.trim();
const captchaInput = document.getElementById('captchaCode').value.trim().toUpperCase();
if (!/^1[3-9]\d{9}$/.test(phone)) { showMsg('请输入正确的手机号', 'error'); return; }
if (captchaInput.length !== 4) { showMsg('请输入4位图形验证码', 'error'); return; }
const stored = localStorage.getItem('captcha_' + captchaKey);
if (!stored || stored.toUpperCase() !== captchaInput) {
showMsg('图形验证码错误', 'error');
generateCaptcha();
return;
}
sendBtn.disabled = true;
sendBtn.textContent = '发送中...';
try {
const res = await fetch(API + '/send-code', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ phone, captchaKey, captchaCode: captchaInput })
});
const data = await res.json();
if (data.code === 0) {
showMsg('验证码已发送,请注意查收', 'success');
smsCountdown = 60;
smsTimer = setInterval(() => {
smsCountdown--;
if (smsCountdown <= 0) {
clearInterval(smsTimer);
sendBtn.textContent = '发送验证码';
sendBtn.disabled = false;
} else {
sendBtn.textContent = smsCountdown + '秒后重试';
}
}, 1000);
} else {
showMsg(data.message || '发送失败', 'error');
sendBtn.textContent = '发送验证码';
sendBtn.disabled = false;
}
} catch {
showMsg('网络错误,请检查服务器', 'error');
sendBtn.textContent = '发送验证码';
sendBtn.disabled = false;
}
});
form.addEventListener('submit', async (e) => {
e.preventDefault();
hideMsg();
const phone = document.getElementById('phone').value.trim();
const smsCode = document.getElementById('smsCode').value.trim();
const password = document.getElementById('password').value;
if (!/^1[3-9]\d{9}$/.test(phone)) { showMsg('请输入正确的手机号', 'error'); return; }
if (!/^\d{4,6}$/.test(smsCode)) { showMsg('请输入4-6位短信验证码', 'error'); return; }
if (password.length < 6) { showMsg('密码至少6位', 'error'); return; }
submitBtn.disabled = true;
submitBtn.textContent = '注册中...';
try {
const res = await fetch(API + '/register', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ phone, code: smsCode, password })
});
const data = await res.json();
if (data.code === 0) {
localStorage.setItem('auth_token', data.token);
localStorage.setItem('auth_user', JSON.stringify(data.user));
showMsg('注册成功!正在跳转...', 'success');
setTimeout(() => { window.location.href = 'devices.html'; }, 800);
} else {
showMsg(data.message || '注册失败', 'error');
}
} catch {
showMsg('网络错误,请检查服务器是否启动', 'error');
} finally {
submitBtn.disabled = false;
submitBtn.textContent = '注册';
}
});
</script>
</body>
</html>