first commit
This commit is contained in:
commit
40a78f0032
77 files changed
+102842
No files matched your search
@@ -0,0 +1,570 @@
|
||||
<!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 rel="icon" type="image/png" href="/static/favicon.png">
|
||||
<link rel="stylesheet" href="/static/lib/bootstrap/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="/static/lib/bootstrap-icons/bootstrap-icons.css">
|
||||
<style>
|
||||
body {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 10px;
|
||||
}
|
||||
.register-container {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
|
||||
overflow: hidden;
|
||||
max-width: 420px;
|
||||
width: 100%;
|
||||
max-height: 95vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.register-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 1.2rem;
|
||||
text-align: center;
|
||||
}
|
||||
.register-header h2 {
|
||||
margin-bottom: 0.3rem;
|
||||
font-size: 1.4rem;
|
||||
}
|
||||
.register-header p {
|
||||
margin-bottom: 0;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.register-body {
|
||||
padding: 1.2rem;
|
||||
}
|
||||
.form-control {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e9ecef;
|
||||
padding: 8px 12px;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.form-control:focus {
|
||||
border-color: #667eea;
|
||||
box-shadow: 0 0 0 0.15rem rgba(102, 126, 234, 0.2);
|
||||
}
|
||||
.btn-register {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 10px;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.btn-register:hover {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
.btn-code {
|
||||
border-radius: 8px;
|
||||
border: 1px solid #667eea;
|
||||
color: #667eea;
|
||||
font-weight: 600;
|
||||
transition: all 0.3s ease;
|
||||
padding: 8px 12px;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.btn-code:hover {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
}
|
||||
.btn-code:disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.login-link {
|
||||
text-align: center;
|
||||
margin-top: 0.8rem;
|
||||
}
|
||||
.login-link a {
|
||||
color: #667eea;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.login-link a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.alert {
|
||||
border-radius: 8px;
|
||||
border: none;
|
||||
padding: 0.6rem 1rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.input-group {
|
||||
margin-bottom: 0.8rem;
|
||||
}
|
||||
.countdown {
|
||||
color: #6c757d;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.mb-3 {
|
||||
margin-bottom: 0.8rem !important;
|
||||
}
|
||||
.form-label {
|
||||
margin-bottom: 0.3rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.85rem;
|
||||
color: #495057;
|
||||
}
|
||||
.form-text {
|
||||
margin-top: 0.2rem;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
.captcha-container img {
|
||||
height: 32px !important;
|
||||
}
|
||||
|
||||
/* 响应式优化 */
|
||||
@media (max-height: 700px) {
|
||||
.register-header {
|
||||
padding: 1rem;
|
||||
}
|
||||
.register-header h2 {
|
||||
font-size: 1.2rem;
|
||||
margin-bottom: 0.2rem;
|
||||
}
|
||||
.register-header p {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.register-body {
|
||||
padding: 1rem;
|
||||
}
|
||||
.mb-3 {
|
||||
margin-bottom: 0.6rem !important;
|
||||
}
|
||||
.form-control {
|
||||
padding: 6px 10px;
|
||||
}
|
||||
.btn-code {
|
||||
padding: 6px 10px;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.register-container {
|
||||
margin: 5px;
|
||||
max-width: none;
|
||||
}
|
||||
.row.g-2 > * {
|
||||
padding-left: 0.25rem;
|
||||
padding-right: 0.25rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="register-container">
|
||||
<div class="register-header">
|
||||
<h2 class="mb-0">
|
||||
<i class="bi bi-person-plus-fill me-2"></i>
|
||||
用户注册
|
||||
</h2>
|
||||
<p class="mb-0 mt-2 opacity-75">注册后即可使用闲鱼管理系统</p>
|
||||
</div>
|
||||
|
||||
<div class="register-body">
|
||||
<div id="alertContainer"></div>
|
||||
|
||||
<form id="registerForm">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">
|
||||
<i class="bi bi-person me-1"></i>用户名
|
||||
</label>
|
||||
<input type="text" class="form-control" id="username" name="username"
|
||||
placeholder="3-20个字符,支持字母、数字、下划线" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label">
|
||||
<i class="bi bi-envelope me-1"></i>邮箱地址
|
||||
</label>
|
||||
<input type="email" class="form-control" id="email" name="email"
|
||||
placeholder="用于接收验证码和重要通知" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="captchaCode" class="form-label">
|
||||
<i class="bi bi-shield-lock me-1"></i>图形验证码
|
||||
</label>
|
||||
<div class="row g-2">
|
||||
<div class="col-7">
|
||||
<input type="text" class="form-control" id="captchaCode" name="captchaCode"
|
||||
placeholder="输入4位验证码" maxlength="4" required>
|
||||
</div>
|
||||
<div class="col-5">
|
||||
<div class="captcha-container" style="position: relative;">
|
||||
<img id="captchaImage" src="" alt="图形验证码"
|
||||
style="width: 100%; height: 32px; border: 1px solid #ddd; border-radius: 5px; cursor: pointer;"
|
||||
onclick="refreshCaptcha()">
|
||||
<div id="captchaLoading" class="text-center" style="display: none; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);">
|
||||
<div class="spinner-border spinner-border-sm" role="status"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-text">
|
||||
<span id="captchaStatus">请输入图形验证码,点击图片可刷新</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="verificationCode" class="form-label">
|
||||
<i class="bi bi-shield-check me-1"></i>邮箱验证码
|
||||
</label>
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" id="verificationCode" name="verificationCode"
|
||||
placeholder="输入6位验证码" maxlength="6" required>
|
||||
<button type="button" class="btn btn-code" id="sendCodeBtn" onclick="sendVerificationCode()" disabled>
|
||||
发送验证码
|
||||
</button>
|
||||
</div>
|
||||
<div class="form-text">
|
||||
<span id="codeStatus">请先验证图形验证码</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">
|
||||
<i class="bi bi-lock me-1"></i>设置密码
|
||||
</label>
|
||||
<input type="password" class="form-control" id="password" name="password"
|
||||
placeholder="至少6个字符" required>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<label for="confirmPassword" class="form-label">
|
||||
<i class="bi bi-lock-fill me-1"></i>确认密码
|
||||
</label>
|
||||
<input type="password" class="form-control" id="confirmPassword" name="confirmPassword"
|
||||
placeholder="再次输入密码" required>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-register btn-primary w-100 mt-2">
|
||||
<i class="bi bi-person-plus me-1"></i>立即注册
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="login-link">
|
||||
<span class="text-muted">已有账号?</span>
|
||||
<a href="/login.html">立即登录</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/static/lib/bootstrap/bootstrap.bundle.min.js"></script>
|
||||
<script>
|
||||
let countdownTimer = null;
|
||||
let countdownSeconds = 0;
|
||||
let sessionId = generateSessionId();
|
||||
let captchaVerified = false;
|
||||
|
||||
function generateSessionId() {
|
||||
return 'session_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
|
||||
}
|
||||
|
||||
function showAlert(message, type = 'danger') {
|
||||
const alertContainer = document.getElementById('alertContainer');
|
||||
const alertHtml = `
|
||||
<div class="alert alert-${type} alert-dismissible fade show" role="alert">
|
||||
<i class="bi bi-${type === 'success' ? 'check-circle' : 'exclamation-triangle'}-fill me-2"></i>
|
||||
${message}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
||||
</div>
|
||||
`;
|
||||
alertContainer.innerHTML = alertHtml;
|
||||
}
|
||||
|
||||
function validateEmail(email) {
|
||||
const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return re.test(email);
|
||||
}
|
||||
|
||||
async function loadCaptcha() {
|
||||
const captchaImage = document.getElementById('captchaImage');
|
||||
const captchaLoading = document.getElementById('captchaLoading');
|
||||
const captchaStatus = document.getElementById('captchaStatus');
|
||||
|
||||
try {
|
||||
captchaLoading.style.display = 'block';
|
||||
captchaImage.style.display = 'none';
|
||||
|
||||
const response = await fetch('/generate-captcha', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ session_id: sessionId })
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
captchaImage.src = result.captcha_image;
|
||||
captchaStatus.textContent = '请输入图形验证码,点击图片可刷新';
|
||||
captchaVerified = false;
|
||||
updateSendCodeButton();
|
||||
} else {
|
||||
captchaStatus.textContent = '图形验证码加载失败,请刷新页面重试';
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载图形验证码失败:', error);
|
||||
captchaStatus.textContent = '图形验证码加载失败,请检查网络连接';
|
||||
} finally {
|
||||
captchaLoading.style.display = 'none';
|
||||
captchaImage.style.display = 'block';
|
||||
}
|
||||
}
|
||||
|
||||
function refreshCaptcha() {
|
||||
sessionId = generateSessionId(); // 生成新的session ID
|
||||
loadCaptcha();
|
||||
// 不再自动清空验证码输入框,让用户自己决定是否清空
|
||||
}
|
||||
|
||||
async function verifyCaptcha() {
|
||||
const captchaCode = document.getElementById('captchaCode').value.trim();
|
||||
const captchaStatus = document.getElementById('captchaStatus');
|
||||
|
||||
if (!captchaCode) {
|
||||
captchaStatus.textContent = '请输入图形验证码';
|
||||
captchaVerified = false;
|
||||
updateSendCodeButton();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/verify-captcha', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
session_id: sessionId,
|
||||
captcha_code: captchaCode
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
captchaStatus.innerHTML = '<span style="color: green;">✓ 图形验证码验证成功</span>';
|
||||
captchaVerified = true;
|
||||
} else {
|
||||
captchaStatus.innerHTML = '<span style="color: red;">✗ 图形验证码错误,请重新输入</span>';
|
||||
captchaVerified = false;
|
||||
refreshCaptcha(); // 自动刷新验证码
|
||||
}
|
||||
|
||||
updateSendCodeButton();
|
||||
|
||||
} catch (error) {
|
||||
console.error('验证图形验证码失败:', error);
|
||||
captchaStatus.innerHTML = '<span style="color: red;">验证失败,请检查网络连接</span>';
|
||||
captchaVerified = false;
|
||||
updateSendCodeButton();
|
||||
}
|
||||
}
|
||||
|
||||
function updateSendCodeButton() {
|
||||
const sendCodeBtn = document.getElementById('sendCodeBtn');
|
||||
const email = document.getElementById('email').value.trim();
|
||||
const codeStatus = document.getElementById('codeStatus');
|
||||
|
||||
if (captchaVerified && email && validateEmail(email)) {
|
||||
sendCodeBtn.disabled = false;
|
||||
codeStatus.textContent = '图形验证码已验证,可以发送邮箱验证码';
|
||||
} else {
|
||||
sendCodeBtn.disabled = true;
|
||||
if (!captchaVerified) {
|
||||
codeStatus.textContent = '请先验证图形验证码';
|
||||
} else if (!email) {
|
||||
codeStatus.textContent = '请先输入邮箱地址';
|
||||
} else if (!validateEmail(email)) {
|
||||
codeStatus.textContent = '请输入有效的邮箱地址';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function startCountdown() {
|
||||
countdownSeconds = 60;
|
||||
const sendCodeBtn = document.getElementById('sendCodeBtn');
|
||||
const codeStatus = document.getElementById('codeStatus');
|
||||
|
||||
sendCodeBtn.disabled = true;
|
||||
|
||||
countdownTimer = setInterval(() => {
|
||||
countdownSeconds--;
|
||||
sendCodeBtn.textContent = `重新发送 (${countdownSeconds}s)`;
|
||||
codeStatus.innerHTML = `<span class="countdown">验证码已发送,${countdownSeconds}秒后可重新发送</span>`;
|
||||
|
||||
if (countdownSeconds <= 0) {
|
||||
clearInterval(countdownTimer);
|
||||
sendCodeBtn.disabled = false;
|
||||
sendCodeBtn.textContent = '发送验证码';
|
||||
codeStatus.textContent = '可以重新发送验证码';
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
async function sendVerificationCode() {
|
||||
const email = document.getElementById('email').value.trim();
|
||||
|
||||
if (!captchaVerified) {
|
||||
showAlert('请先验证图形验证码');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!email) {
|
||||
showAlert('请先输入邮箱地址');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateEmail(email)) {
|
||||
showAlert('请输入有效的邮箱地址');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/send-verification-code', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
email: email,
|
||||
session_id: sessionId
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showAlert(result.message, 'success');
|
||||
startCountdown();
|
||||
} else {
|
||||
showAlert(result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('发送验证码失败:', error);
|
||||
showAlert('发送验证码失败,请检查网络连接');
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('registerForm').addEventListener('submit', async function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData(this);
|
||||
const username = formData.get('username').trim();
|
||||
const email = formData.get('email').trim();
|
||||
const captchaCode = formData.get('captchaCode').trim();
|
||||
const verificationCode = formData.get('verificationCode').trim();
|
||||
const password = formData.get('password');
|
||||
const confirmPassword = formData.get('confirmPassword');
|
||||
|
||||
// 前端验证
|
||||
if (!captchaVerified) {
|
||||
showAlert('请先验证图形验证码');
|
||||
return;
|
||||
}
|
||||
if (username.length < 3 || username.length > 20) {
|
||||
showAlert('用户名长度必须在3-20个字符之间');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!/^[a-zA-Z0-9_]+$/.test(username)) {
|
||||
showAlert('用户名只能包含字母、数字和下划线');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!validateEmail(email)) {
|
||||
showAlert('请输入有效的邮箱地址');
|
||||
return;
|
||||
}
|
||||
|
||||
if (verificationCode.length !== 6) {
|
||||
showAlert('请输入6位验证码');
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.length < 6) {
|
||||
showAlert('密码长度至少6个字符');
|
||||
return;
|
||||
}
|
||||
|
||||
if (password !== confirmPassword) {
|
||||
showAlert('两次输入的密码不一致');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/register', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: username,
|
||||
email: email,
|
||||
verification_code: verificationCode,
|
||||
password: password
|
||||
})
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
showAlert(result.message, 'success');
|
||||
setTimeout(() => {
|
||||
window.location.href = '/login.html';
|
||||
}, 2000);
|
||||
} else {
|
||||
showAlert(result.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('注册失败:', error);
|
||||
showAlert('注册失败,请检查网络连接');
|
||||
}
|
||||
});
|
||||
|
||||
// 页面加载完成后初始化
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
loadCaptcha();
|
||||
});
|
||||
|
||||
// 图形验证码输入框事件
|
||||
document.getElementById('captchaCode').addEventListener('input', function() {
|
||||
if (this.value.length === 4) {
|
||||
verifyCaptcha();
|
||||
} else {
|
||||
captchaVerified = false;
|
||||
updateSendCodeButton();
|
||||
document.getElementById('captchaStatus').textContent = '请输入4位图形验证码';
|
||||
}
|
||||
});
|
||||
|
||||
// 邮箱输入框事件
|
||||
document.getElementById('email').addEventListener('input', function() {
|
||||
updateSendCodeButton();
|
||||
});
|
||||
|
||||
document.getElementById('email').addEventListener('blur', function() {
|
||||
const email = this.value.trim();
|
||||
updateSendCodeButton();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user