/** * 用户认证控制器 */ 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: '服务器错误' }); } };