主要更新: - ✅ 完成主题配色从暗色到亮蓝白配色的全面转换 - ✅ 实现高薪岗位页面及后端API集成 - ✅ 完成登录注册页面及认证系统 - ✅ 实现预招录确认功能 - ✅ 添加数据库管理和维护工具脚本 - ✅ 优化错误处理和用户体验 核心功能: 1. 首页 (index.html) - 3D地球、专业分类、过渡岗位 2. 高薪岗位页面 (high.html) - 岗位详情、预招录确认、成功案例 3. 登录注册 (auth.html) - 用户认证、专业分类选择 4. 后端API - RESTful接口,JWT认证,MySQL数据库 技术栈: - 前端:Three.js, GSAP, 原生JavaScript - 后端:Node.js, Express, MySQL - 认证:JWT, bcrypt - 样式:自定义CSS,响应式设计 数据库工具: - kill-by-ids.js - 批量终止MySQL进程 - unlock-all-tables.js - 解锁数据库表 - init-db.js - 初始化数据库 - 其他管理脚本 🤖 Generated with Claude Code Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
351 lines
11 KiB
JavaScript
351 lines
11 KiB
JavaScript
/**
|
||
* 用户认证逻辑
|
||
* 处理登录、注册表单的提交和验证
|
||
*/
|
||
|
||
// API配置
|
||
const API_BASE_URL = 'http://192.168.1.17:8080/api';
|
||
const AUTH_TOKEN_KEY = 'duoduo_auth_token';
|
||
const USER_INFO_KEY = 'duoduo_user_info';
|
||
|
||
// 专业大类数据
|
||
let professionalCategories = [];
|
||
|
||
/**
|
||
* 加载专业大类数据
|
||
*/
|
||
async function loadProfessionalCategories() {
|
||
try {
|
||
const response = await fetch('/专业大类.json');
|
||
professionalCategories = await response.json();
|
||
|
||
// 填充注册表单的下拉选择框
|
||
const selectElement = document.getElementById('register-professional-category');
|
||
if (selectElement) {
|
||
professionalCategories.forEach(category => {
|
||
const option = document.createElement('option');
|
||
option.value = category.大类代码;
|
||
option.textContent = category.大类名称;
|
||
selectElement.appendChild(option);
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('加载专业大类失败:', error);
|
||
}
|
||
}
|
||
|
||
// ==================== 工具函数 ====================
|
||
|
||
/**
|
||
* 显示错误信息
|
||
*/
|
||
function showError(elementId, message) {
|
||
const errorElement = document.getElementById(elementId);
|
||
errorElement.textContent = message;
|
||
errorElement.style.display = 'block';
|
||
}
|
||
|
||
/**
|
||
* 显示成功信息
|
||
*/
|
||
function showSuccess(elementId, message) {
|
||
const successElement = document.getElementById(elementId);
|
||
successElement.textContent = message;
|
||
successElement.style.display = 'block';
|
||
}
|
||
|
||
/**
|
||
* 隐藏消息
|
||
*/
|
||
function hideMessage(elementId) {
|
||
const element = document.getElementById(elementId);
|
||
element.textContent = '';
|
||
element.style.display = 'none';
|
||
}
|
||
|
||
/**
|
||
* 隐藏所有消息
|
||
*/
|
||
function hideAllMessages() {
|
||
hideMessage('login-error-msg');
|
||
hideMessage('register-error-msg');
|
||
hideMessage('register-success-msg');
|
||
}
|
||
|
||
// ==================== 表单验证 ====================
|
||
|
||
/**
|
||
* 验证登录表单
|
||
*/
|
||
function validateLoginForm(username, password) {
|
||
if (!username || !password) {
|
||
return '用户名和密码不能为空';
|
||
}
|
||
return null;
|
||
}
|
||
|
||
/**
|
||
* 验证注册表单
|
||
*/
|
||
function validateRegisterForm(username, password, confirmPassword, email, phone) {
|
||
// 真实姓名验证
|
||
if (!username) {
|
||
return '真实姓名不能为空';
|
||
}
|
||
if (username.length < 2 || username.length > 10) {
|
||
return '姓名长度必须在2-10个字符之间';
|
||
}
|
||
|
||
// 密码验证
|
||
if (!password) {
|
||
return '密码不能为空';
|
||
}
|
||
if (password.length < 6) {
|
||
return '密码长度至少为6个字符';
|
||
}
|
||
|
||
// 确认密码验证
|
||
if (password !== confirmPassword) {
|
||
return '两次输入的密码不一致';
|
||
}
|
||
|
||
// 邮箱验证(如果填写)
|
||
if (email && email.trim() !== '') {
|
||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||
if (!emailRegex.test(email)) {
|
||
return '邮箱格式不正确';
|
||
}
|
||
}
|
||
|
||
// 手机号验证(必填)
|
||
if (!phone || phone.trim() === '') {
|
||
return '手机号码不能为空';
|
||
}
|
||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||
if (!phoneRegex.test(phone)) {
|
||
return '手机号格式不正确';
|
||
}
|
||
|
||
return null;
|
||
}
|
||
|
||
// ==================== 登录功能 ====================
|
||
|
||
/**
|
||
* 处理用户登录
|
||
*/
|
||
async function handleLogin() {
|
||
// 隐藏之前的错误信息
|
||
hideAllMessages();
|
||
|
||
// 获取表单数据
|
||
const username = document.getElementById('login-username').value.trim();
|
||
const password = document.getElementById('login-password').value;
|
||
|
||
// 前端验证
|
||
const validationError = validateLoginForm(username, password);
|
||
if (validationError) {
|
||
showError('login-error-msg', validationError);
|
||
return;
|
||
}
|
||
|
||
// 禁用提交按钮,显示加载状态
|
||
const submitBtn = document.getElementById('login-submit-btn');
|
||
const originalText = submitBtn.textContent;
|
||
submitBtn.disabled = true;
|
||
submitBtn.textContent = '登录中...';
|
||
submitBtn.style.opacity = '0.7';
|
||
|
||
try {
|
||
// 调用登录API
|
||
const response = await fetch(`${API_BASE_URL}/auth/login`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({ username, password })
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
// 保存token和用户信息到localStorage
|
||
localStorage.setItem(AUTH_TOKEN_KEY, data.data.token);
|
||
localStorage.setItem(USER_INFO_KEY, JSON.stringify(data.data.user));
|
||
|
||
// 登录成功,跳转到首页
|
||
window.location.href = 'index.html';
|
||
} else {
|
||
// 显示后端返回的错误信息
|
||
showError('login-error-msg', data.message || '登录失败,请重试');
|
||
}
|
||
} catch (error) {
|
||
console.error('登录错误:', error);
|
||
showError('login-error-msg', '网络错误,请检查服务器是否运行');
|
||
} finally {
|
||
// 恢复按钮状态
|
||
submitBtn.disabled = false;
|
||
submitBtn.textContent = originalText;
|
||
submitBtn.style.opacity = '1';
|
||
}
|
||
}
|
||
|
||
// ==================== 注册功能 ====================
|
||
|
||
/**
|
||
* 处理用户注册
|
||
*/
|
||
async function handleRegister() {
|
||
// 隐藏之前的消息
|
||
hideAllMessages();
|
||
|
||
// 获取表单数据
|
||
const username = document.getElementById('register-username').value.trim();
|
||
const password = document.getElementById('register-password').value;
|
||
const confirmPassword = document.getElementById('register-password-confirm').value;
|
||
const email = document.getElementById('register-email').value.trim();
|
||
const phone = document.getElementById('register-phone').value.trim();
|
||
const professionalCategoryCode = document.getElementById('register-professional-category').value;
|
||
|
||
// 前端验证
|
||
const validationError = validateRegisterForm(username, password, confirmPassword, email, phone);
|
||
if (validationError) {
|
||
showError('register-error-msg', validationError);
|
||
return;
|
||
}
|
||
|
||
// 禁用提交按钮,显示加载状态
|
||
const submitBtn = document.getElementById('register-submit-btn');
|
||
const originalText = submitBtn.textContent;
|
||
submitBtn.disabled = true;
|
||
submitBtn.textContent = '注册中...';
|
||
submitBtn.style.opacity = '0.7';
|
||
|
||
try {
|
||
// 调用注册API
|
||
const requestBody = { username, password };
|
||
if (email) requestBody.email = email;
|
||
if (phone) requestBody.phone = phone;
|
||
// 如果选择了专业大类,添加到请求体
|
||
if (professionalCategoryCode) {
|
||
requestBody.professional_category_code = professionalCategoryCode;
|
||
const category = professionalCategories.find(c => c.大类代码 === professionalCategoryCode);
|
||
if (category) {
|
||
requestBody.professional_category = category.大类名称;
|
||
}
|
||
}
|
||
|
||
const response = await fetch(`${API_BASE_URL}/auth/register`, {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(requestBody)
|
||
});
|
||
|
||
const data = await response.json();
|
||
|
||
if (data.success) {
|
||
// 显示成功提示
|
||
showSuccess('register-success-msg', '注册成功!正在跳转到登录...');
|
||
|
||
// 2秒后切换到登录表单并预填充用户名
|
||
setTimeout(() => {
|
||
// 切换到登录表单
|
||
switchToLogin();
|
||
|
||
// 预填充用户名
|
||
document.getElementById('login-username').value = username;
|
||
|
||
// 清空注册表单
|
||
document.getElementById('register-username').value = '';
|
||
document.getElementById('register-password').value = '';
|
||
document.getElementById('register-password-confirm').value = '';
|
||
document.getElementById('register-email').value = '';
|
||
document.getElementById('register-phone').value = '';
|
||
|
||
hideAllMessages();
|
||
}, 2000);
|
||
} else {
|
||
// 显示后端返回的错误信息
|
||
showError('register-error-msg', data.message || '注册失败,请重试');
|
||
}
|
||
} catch (error) {
|
||
console.error('注册错误:', error);
|
||
showError('register-error-msg', '网络错误,请检查服务器是否运行');
|
||
} finally {
|
||
// 恢复按钮状态
|
||
submitBtn.disabled = false;
|
||
submitBtn.textContent = originalText;
|
||
submitBtn.style.opacity = '1';
|
||
}
|
||
}
|
||
|
||
// ==================== 表单切换功能 ====================
|
||
|
||
/**
|
||
* 切换到注册表单
|
||
*/
|
||
function switchToRegister() {
|
||
hideAllMessages();
|
||
|
||
const loginContainer = document.getElementById('login-form-container');
|
||
const registerContainer = document.getElementById('register-form-container');
|
||
|
||
// 隐藏登录
|
||
loginContainer.style.opacity = '0';
|
||
setTimeout(() => {
|
||
loginContainer.classList.add('hidden');
|
||
// 显示注册
|
||
registerContainer.classList.remove('hidden');
|
||
registerContainer.classList.add('fade-in');
|
||
registerContainer.style.opacity = '1';
|
||
}, 300);
|
||
}
|
||
|
||
/**
|
||
* 切换到登录表单
|
||
*/
|
||
function switchToLogin() {
|
||
hideAllMessages();
|
||
|
||
const loginContainer = document.getElementById('login-form-container');
|
||
const registerContainer = document.getElementById('register-form-container');
|
||
|
||
// 隐藏注册
|
||
registerContainer.classList.remove('fade-in');
|
||
registerContainer.style.opacity = '0';
|
||
|
||
setTimeout(() => {
|
||
registerContainer.classList.add('hidden');
|
||
registerContainer.style.opacity = '1';
|
||
|
||
// 显示登录
|
||
loginContainer.classList.remove('hidden');
|
||
loginContainer.style.opacity = '1';
|
||
loginContainer.classList.add('fade-in');
|
||
}, 300);
|
||
}
|
||
|
||
// ==================== 页面初始化 ====================
|
||
|
||
document.addEventListener('DOMContentLoaded', () => {
|
||
// 加载专业大类数据
|
||
loadProfessionalCategories();
|
||
|
||
// 检查是否已登录
|
||
const token = localStorage.getItem(AUTH_TOKEN_KEY);
|
||
if (token) {
|
||
// 已登录,直接跳转到首页
|
||
window.location.href = 'index.html';
|
||
return;
|
||
}
|
||
|
||
// 绑定切换按钮事件
|
||
document.getElementById('switch-to-register').addEventListener('click', switchToRegister);
|
||
document.getElementById('switch-to-login').addEventListener('click', switchToLogin);
|
||
|
||
// 绑定表单提交事件(通过form的onsubmit已经绑定,这里只是确保)
|
||
// 表单已通过内联 onsubmit 绑定
|
||
});
|