主要更新: - ✅ 完成主题配色从暗色到亮蓝白配色的全面转换 - ✅ 实现高薪岗位页面及后端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>
221 lines
6.0 KiB
JavaScript
221 lines
6.0 KiB
JavaScript
/**
|
||
* 认证工具模块
|
||
* 用于其他页面检查登录状态、获取用户信息、退出登录等
|
||
*/
|
||
|
||
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;
|
||
}
|