feat: 完成多多畅职就业服务平台核心功能开发

主要更新:
-  完成主题配色从暗色到亮蓝白配色的全面转换
-  实现高薪岗位页面及后端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>
This commit is contained in:
KQL
2025-12-22 15:40:55 +08:00
parent 97e79e0f8c
commit 61698639ef
55 changed files with 13178 additions and 1298 deletions

220
js/utils/auth-helper.js Normal file
View File

@@ -0,0 +1,220 @@
/**
* 认证工具模块
* 用于其他页面检查登录状态、获取用户信息、退出登录等
*/
const AuthHelper = {
// 配置常量
TOKEN_KEY: 'duoduo_auth_token',
USER_INFO_KEY: 'duoduo_user_info',
API_BASE_URL: 'http://192.168.1.17:8080/api',
/**
* 获取存储的token
* @returns {string|null} token字符串或null
*/
getToken() {
return localStorage.getItem(this.TOKEN_KEY);
},
/**
* 获取存储的用户信息
* @returns {Object|null} 用户信息对象或null
*/
getUserInfo() {
const userInfo = localStorage.getItem(this.USER_INFO_KEY);
return userInfo ? JSON.parse(userInfo) : null;
},
/**
* 检查是否已登录
* @returns {boolean} 是否已登录
*/
isLoggedIn() {
return !!this.getToken();
},
/**
* 退出登录
* 清除所有认证信息并跳转到登录页
*/
logout() {
localStorage.removeItem(this.TOKEN_KEY);
localStorage.removeItem(this.USER_INFO_KEY);
window.location.href = 'auth.html';
},
/**
* 验证token是否有效
* 调用后端API验证token如果无效则清除登录状态
* @returns {Promise<boolean>} token是否有效
*/
async validateToken() {
const token = this.getToken();
if (!token) {
return false;
}
try {
const response = await fetch(`${this.API_BASE_URL}/auth/me`, {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
});
if (response.ok) {
const data = await response.json();
if (data.success) {
// 更新用户信息
localStorage.setItem(this.USER_INFO_KEY, JSON.stringify(data.data));
return true;
}
}
// Token无效清除登录状态
this.logout();
return false;
} catch (error) {
console.error('Token验证失败:', error);
return false;
}
},
/**
* 路由守卫:保护需要登录的页面
* 如果未登录则跳转到登录页
* @param {string} redirectUrl 跳转的登录页URL默认为auth.html
* @returns {boolean} 是否已登录
*/
requireAuth(redirectUrl = 'auth.html') {
if (!this.isLoggedIn()) {
window.location.href = redirectUrl;
return false;
}
return true;
},
/**
* 获取带认证头的fetch配置
* @param {Object} options fetch的配置对象
* @returns {Object} 包含Authorization头的配置对象
*/
getAuthHeaders(options = {}) {
const token = this.getToken();
return {
...options,
headers: {
...options.headers,
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
};
},
/**
* 发送认证请求的封装方法
* @param {string} url 请求URL
* @param {Object} options fetch配置
* @returns {Promise<Object>} 响应数据
*/
async fetchWithAuth(url, options = {}) {
const response = await fetch(url, this.getAuthHeaders(options));
// 如果返回401未授权清除登录状态并跳转
if (response.status === 401) {
this.logout();
return null;
}
return response.json();
},
/**
* 获取当前用户信息(从服务器获取最新)
* @returns {Promise<Object|null>} 用户信息或null
*/
async getCurrentUser() {
try {
const data = await this.fetchWithAuth(`${this.API_BASE_URL}/auth/me`);
if (data && data.success) {
// 更新本地存储的用户信息
localStorage.setItem(this.USER_INFO_KEY, JSON.stringify(data.data));
return data.data;
}
return null;
} catch (error) {
console.error('获取用户信息失败:', error);
return null;
}
},
/**
* 更新用户资料
* @param {Object} profileData 要更新的资料数据
* @returns {Promise<boolean>} 是否更新成功
*/
async updateProfile(profileData) {
try {
const data = await this.fetchWithAuth(`${this.API_BASE_URL}/auth/profile`, {
method: 'PUT',
body: JSON.stringify(profileData)
});
if (data && data.success) {
// 更新成功后刷新用户信息
await this.getCurrentUser();
return true;
}
return false;
} catch (error) {
console.error('更新资料失败:', error);
return false;
}
},
/**
* 在页面中显示用户名
* @param {string} elementId 要显示用户名的元素ID
*/
displayUsername(elementId) {
const userInfo = this.getUserInfo();
if (userInfo && userInfo.username) {
const element = document.getElementById(elementId);
if (element) {
element.textContent = userInfo.username;
}
}
},
/**
* 在页面中显示用户完整信息
* @param {Object} elementIds 元素ID映射对象 {username: 'username-el', email: 'email-el', ...}
*/
displayUserInfo(elementIds) {
const userInfo = this.getUserInfo();
if (!userInfo) return;
for (const [field, elementId] of Object.entries(elementIds)) {
const element = document.getElementById(elementId);
if (element && userInfo[field]) {
element.textContent = userInfo[field];
}
}
}
};
// 如果在浏览器环境中,暴露到全局
if (typeof window !== 'undefined') {
window.AuthHelper = AuthHelper;
}
// 支持ES6模块导出
if (typeof module !== 'undefined' && module.exports) {
module.exports = AuthHelper;
}