Files
all-in-one-sys/api/controllers/authController.js
KQL 61698639ef 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>
2025-12-22 15:40:55 +08:00

338 lines
10 KiB
JavaScript

/**
* 用户认证控制器
*/
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const db = require('../../config/database');
const JWT_SECRET = process.env.JWT_SECRET || 'duoduo-career-jwt-secret-key-2024';
const JWT_EXPIRE = process.env.JWT_EXPIRE || '7d';
/**
* 用户注册
*/
exports.register = async (req, res) => {
try {
const { username, password, email, phone, professional_category_code, professional_category } = req.body;
// 验证必填字段
if (!username || !password) {
return res.status(400).json({
success: false,
message: '真实姓名和密码不能为空'
});
}
// 验证真实姓名长度
if (username.length < 2 || username.length > 10) {
return res.status(400).json({
success: false,
message: '姓名长度必须在2-10个字符之间'
});
}
// 验证密码长度
if (password.length < 6) {
return res.status(400).json({
success: false,
message: '密码长度至少为6个字符'
});
}
// 验证手机号必填
if (!phone) {
return res.status(400).json({
success: false,
message: '手机号码不能为空'
});
}
// 检查手机号是否已被使用(手机号不允许重复)
const [existingPhones] = await db.query(
'SELECT id FROM users WHERE phone = ?',
[phone]
);
if (existingPhones.length > 0) {
return res.status(400).json({
success: false,
message: '该手机号已被注册'
});
}
// 如果提供了邮箱,检查是否已被使用
if (email) {
const [existingEmails] = await db.query(
'SELECT id FROM users WHERE email = ?',
[email]
);
if (existingEmails.length > 0) {
return res.status(400).json({
success: false,
message: '邮箱已被使用'
});
}
}
// 加密密码
const passwordHash = await bcrypt.hash(password, 10);
// 插入用户
const [result] = await db.query(
'INSERT INTO users (username, password_hash, email, phone, role, status) VALUES (?, ?, ?, ?, ?, ?)',
[username, passwordHash, email || null, phone || null, 'user', 'active']
);
// 创建用户资料记录
await db.query(
`INSERT INTO user_profiles (
user_id,
professional_category_code,
professional_category
) VALUES (?, ?, ?)`,
[
result.insertId,
professional_category_code || null,
professional_category || null
]
);
res.status(201).json({
success: true,
message: '注册成功',
data: {
id: result.insertId,
username
}
});
} catch (error) {
console.error('注册错误:', error);
res.status(500).json({
success: false,
message: '服务器错误,请稍后重试'
});
}
};
/**
* 用户登录
*/
exports.login = async (req, res) => {
try {
const { username, password } = req.body;
// 验证必填字段
if (!username || !password) {
return res.status(400).json({
success: false,
message: '用户名和密码不能为空'
});
}
// 查询用户
const [users] = await db.query(`
SELECT
u.id, u.username, u.password_hash, u.email, u.phone, u.role, u.status,
p.professional_category_code,
p.professional_category
FROM users u
LEFT JOIN user_profiles p ON u.id = p.user_id
WHERE u.username = ?
`, [username]);
if (users.length === 0) {
return res.status(401).json({
success: false,
message: '用户名或密码错误'
});
}
const user = users[0];
// 检查账号状态
if (user.status === 'banned') {
return res.status(403).json({
success: false,
message: '账号已被封禁'
});
}
if (user.status === 'inactive') {
return res.status(403).json({
success: false,
message: '账号未激活'
});
}
// 验证密码
const isPasswordValid = await bcrypt.compare(password, user.password_hash);
if (!isPasswordValid) {
return res.status(401).json({
success: false,
message: '用户名或密码错误'
});
}
// 尝试更新最后登录时间(非阻塞)
try {
await db.query(
'UPDATE users SET last_login = NOW() WHERE id = ?',
[user.id]
);
} catch (updateError) {
// 如果更新失败(如数据库锁定),记录错误但不影响登录
console.warn('更新登录时间失败:', updateError.message);
}
// 生成JWT
const token = jwt.sign(
{
id: user.id,
username: user.username,
role: user.role
},
JWT_SECRET,
{ expiresIn: JWT_EXPIRE }
);
res.json({
success: true,
message: '登录成功',
data: {
token,
user: {
id: user.id,
username: user.username,
email: user.email,
phone: user.phone,
role: user.role,
professional_category_code: user.professional_category_code,
professional_category: user.professional_category
}
}
});
} catch (error) {
console.error('登录错误:', error);
res.status(500).json({
success: false,
message: '服务器错误,请稍后重试'
});
}
};
/**
* 获取当前用户信息
*/
exports.getCurrentUser = async (req, res) => {
try {
const userId = req.user.id;
// 查询用户基本信息和资料
const [users] = await db.query(`
SELECT
u.id, u.username, u.email, u.phone, u.role, u.status, u.created_at, u.last_login,
p.real_name, p.gender, p.birth_date, p.education, p.major, p.school,
p.graduation_year, p.city, p.avatar_url, p.self_intro, p.skills,
p.professional_category_code,
p.professional_category
FROM users u
LEFT JOIN user_profiles p ON u.id = p.user_id
WHERE u.id = ?
`, [userId]);
if (users.length === 0) {
return res.status(404).json({
success: false,
message: '用户不存在'
});
}
const user = users[0];
// 解析JSON字段
if (user.skills) {
try {
user.skills = JSON.parse(user.skills);
} catch (e) {
user.skills = [];
}
}
res.json({
success: true,
data: user
});
} catch (error) {
console.error('获取用户信息错误:', error);
res.status(500).json({
success: false,
message: '服务器错误'
});
}
};
/**
* 更新用户资料
*/
exports.updateProfile = async (req, res) => {
try {
const userId = req.user.id;
const {
real_name, gender, birth_date, education, major, school,
graduation_year, city, address, avatar_url, self_intro, skills,
professional_category_code,
professional_category
} = req.body;
// 构建更新字段
const updates = {};
if (real_name !== undefined) updates.real_name = real_name;
if (gender !== undefined) updates.gender = gender;
if (birth_date !== undefined) updates.birth_date = birth_date;
if (education !== undefined) updates.education = education;
if (major !== undefined) updates.major = major;
if (school !== undefined) updates.school = school;
if (graduation_year !== undefined) updates.graduation_year = graduation_year;
if (city !== undefined) updates.city = city;
if (address !== undefined) updates.address = address;
if (avatar_url !== undefined) updates.avatar_url = avatar_url;
if (self_intro !== undefined) updates.self_intro = self_intro;
if (skills !== undefined) updates.skills = JSON.stringify(skills);
if (professional_category_code !== undefined) updates.professional_category_code = professional_category_code;
if (professional_category !== undefined) updates.professional_category = professional_category;
if (Object.keys(updates).length === 0) {
return res.status(400).json({
success: false,
message: '没有要更新的字段'
});
}
// 构建SQL
const fields = Object.keys(updates).map(key => `${key} = ?`).join(', ');
const values = Object.values(updates);
values.push(userId);
await db.query(
`UPDATE user_profiles SET ${fields}, updated_at = NOW() WHERE user_id = ?`,
values
);
res.json({
success: true,
message: '资料更新成功'
});
} catch (error) {
console.error('更新资料错误:', error);
res.status(500).json({
success: false,
message: '服务器错误'
});
}
};