feat: 实现用户认证与权限管理系统

- 添加用户、角色、权限等数据模型
- 实现JWT认证中间件和密码加密
- 添加用户注册、登录、个人信息管理接口
- 实现前端认证上下文和受保护路由
- 添加登录历史记录和操作日志功能
- 提供管理员初始化脚本和修复工具
- 实现完整的登录页面和用户管理界面
This commit is contained in:
zhang1106
2025-12-25 10:48:35 +08:00
parent 568f9c7db8
commit a911d02999
29 changed files with 4309 additions and 154 deletions
+341
View File
@@ -0,0 +1,341 @@
const express = require('express');
const bcrypt = require('bcryptjs');
const User = require('../models/User');
const Role = require('../models/Role');
const UserRole = require('../models/UserRole');
const { generateToken, authMiddleware } = require('../middleware/auth');
const router = express.Router();
const SALT_ROUNDS = 10;
const generateId = () => {
return 'user_' + Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
};
router.post('/register', async (req, res) => {
try {
const { username, password, email, phone, realName } = req.body;
if (!username || !password) {
return res.status(400).json({
success: false,
message: '用户名和密码不能为空'
});
}
if (username.length < 3 || username.length > 20) {
return res.status(400).json({
success: false,
message: '用户名长度必须在3-20个字符之间'
});
}
if (password.length < 6) {
return res.status(400).json({
success: false,
message: '密码长度不能少于6个字符'
});
}
const existingUser = await User.findOne({ where: { username } });
if (existingUser) {
return res.status(400).json({
success: false,
message: '用户名已存在'
});
}
const hashedPassword = await bcrypt.hash(password, SALT_ROUNDS);
const userCount = await User.count();
const isFirstUser = userCount === 0;
const user = await User.create({
userId: generateId(),
username,
password: hashedPassword,
email,
phone,
realName: realName || username,
status: 'active'
});
if (isFirstUser) {
let adminRole = await Role.findOne({ where: { roleCode: 'admin' } });
if (!adminRole) {
adminRole = await Role.create({
roleId: 'role_admin',
roleName: '管理员',
roleCode: 'admin',
description: '系统管理员,拥有所有权限',
status: 'active',
permissions: []
});
}
await UserRole.create({
UserId: user.userId,
RoleId: adminRole.roleId
});
} else {
const defaultRole = await Role.findOne({ where: { roleCode: 'viewer' } });
if (defaultRole) {
await UserRole.create({
UserId: user.userId,
RoleId: defaultRole.roleId
});
}
}
const token = generateToken(user);
res.status(201).json({
success: true,
message: isFirstUser ? '注册成功,已为您分配管理员权限' : '注册成功',
data: {
user: {
userId: user.userId,
username: user.username,
email: user.email,
realName: user.realName
},
token
}
});
} catch (error) {
console.error('注册错误:', error);
res.status(500).json({
success: false,
message: '注册失败',
error: error.message
});
}
});
router.post('/login', async (req, res) => {
try {
const { username, password } = req.body;
if (!username || !password) {
return res.status(400).json({
success: false,
message: '用户名和密码不能为空'
});
}
const user = await User.findOne({ where: { username } });
if (!user) {
return res.status(401).json({
success: false,
message: '用户名或密码错误'
});
}
if (user.status === 'locked') {
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);
if (!isPasswordValid) {
user.loginCount = (user.loginCount || 0) + 1;
if (user.loginCount >= 5) {
user.status = 'locked';
}
await user.save();
return res.status(401).json({
success: false,
message: '用户名或密码错误'
});
}
const token = generateToken(user);
user.lastLoginTime = new Date();
user.lastLoginIp = req.ip || req.connection.remoteAddress;
user.loginCount = 0;
await user.save();
res.json({
success: true,
message: '登录成功',
data: {
user: {
userId: user.userId,
username: user.username,
email: user.email,
realName: user.realName,
avatar: user.avatar
},
token
}
});
} catch (error) {
console.error('登录错误:', error);
res.status(500).json({
success: false,
message: '登录失败',
error: error.message
});
}
});
router.get('/profile', authMiddleware, async (req, res) => {
try {
const user = await User.findByPk(req.user.userId, {
attributes: { exclude: ['password'] }
});
if (!user) {
return res.status(404).json({
success: false,
message: '用户不存在'
});
}
const roles = await Role.findAll({
include: [{
model: User,
where: { userId: req.user.userId },
attributes: []
}]
});
res.json({
success: true,
data: {
user,
roles: roles.map(r => ({
roleId: r.roleId,
roleName: r.roleName,
roleCode: r.roleCode
}))
}
});
} catch (error) {
console.error('获取profile错误:', error);
res.status(500).json({
success: false,
message: '获取用户信息失败'
});
}
});
router.put('/profile', authMiddleware, async (req, res) => {
try {
const { email, phone, realName, avatar } = req.body;
const user = await User.findByPk(req.user.userId);
if (!user) {
return res.status(404).json({
success: false,
message: '用户不存在'
});
}
if (email !== undefined) user.email = email;
if (phone !== undefined) user.phone = phone;
if (realName !== undefined) user.realName = realName;
if (avatar !== undefined) user.avatar = avatar;
await user.save();
res.json({
success: true,
message: '更新成功',
data: {
userId: user.userId,
username: user.username,
email: user.email,
phone: user.phone,
realName: user.realName,
avatar: user.avatar
}
});
} catch (error) {
console.error('更新profile错误:', error);
res.status(500).json({
success: false,
message: '更新失败'
});
}
});
router.put('/password', authMiddleware, async (req, res) => {
try {
const { oldPassword, newPassword } = req.body;
if (!oldPassword || !newPassword) {
return res.status(400).json({
success: false,
message: '旧密码和新密码都不能为空'
});
}
if (newPassword.length < 6) {
return res.status(400).json({
success: false,
message: '新密码长度不能少于6个字符'
});
}
const user = await User.findByPk(req.user.userId);
const isPasswordValid = await bcrypt.compare(oldPassword, user.password);
if (!isPasswordValid) {
return res.status(401).json({
success: false,
message: '旧密码错误'
});
}
user.password = await bcrypt.hash(newPassword, SALT_ROUNDS);
await user.save();
res.json({
success: true,
message: '密码修改成功'
});
} catch (error) {
console.error('修改密码错误:', error);
res.status(500).json({
success: false,
message: '密码修改失败'
});
}
});
router.post('/check-admin', async (req, res) => {
try {
const userCount = await User.count();
res.json({
success: true,
data: {
hasAdmin: userCount > 0,
userCount
}
});
} catch (error) {
console.error('检查管理员错误:', error);
res.status(500).json({
success: false,
message: '检查失败'
});
}
});
module.exports = router;
+120
View File
@@ -0,0 +1,120 @@
const express = require('express');
const LoginHistory = require('../models/LoginHistory');
const User = require('../models/User');
const { authMiddleware } = require('../middleware/auth');
const router = express.Router();
router.get('/', authMiddleware, async (req, res) => {
try {
const { page = 1, pageSize = 10, userId, loginType, startDate, endDate } = req.query;
const offset = (parseInt(page) - 1) * parseInt(pageSize);
const limit = parseInt(pageSize);
const where = {};
if (userId) where.userId = userId;
if (loginType) where.loginType = loginType;
if (startDate || endDate) {
where.loginTime = {};
if (startDate) where.loginTime[Op.gte] = new Date(startDate);
if (endDate) where.loginTime[Op.lte] = new Date(endDate);
}
const { count, rows } = await LoginHistory.findAndCountAll({
where,
limit,
offset,
order: [['loginTime', 'DESC']]
});
res.json({
success: true,
data: {
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize),
histories: rows.map(h => ({
id: h.id,
userId: h.userId,
username: h.username,
realName: h.realName,
loginTime: h.loginTime,
loginIp: h.loginIp,
userAgent: h.userAgent,
loginType: h.loginType,
failReason: h.failReason
}))
}
});
} catch (error) {
console.error('获取登录历史错误:', error);
res.status(500).json({
success: false,
message: '获取登录历史失败'
});
}
});
router.get('/user/:userId', authMiddleware, async (req, res) => {
try {
const { page = 1, pageSize = 10 } = req.query;
const offset = (parseInt(page) - 1) * parseInt(pageSize);
const limit = parseInt(pageSize);
const { count, rows } = await LoginHistory.findAndCountAll({
where: { userId: req.params.userId },
limit,
offset,
order: [['loginTime', 'DESC']]
});
res.json({
success: true,
data: {
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize),
histories: rows
}
});
} catch (error) {
console.error('获取用户登录历史错误:', error);
res.status(500).json({
success: false,
message: '获取登录历史失败'
});
}
});
router.delete('/:id', authMiddleware, async (req, res) => {
try {
await LoginHistory.destroy({ where: { id: req.params.id } });
res.json({ success: true, message: '删除成功' });
} catch (error) {
console.error('删除登录历史错误:', error);
res.status(500).json({ success: false, message: '删除失败' });
}
});
router.delete('/', authMiddleware, async (req, res) => {
try {
const { days } = req.body;
const where = { loginType: 'success' };
if (days) {
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - days);
where.loginTime = { [Op.lt]: cutoffDate };
}
await LoginHistory.destroy({ where });
res.json({ success: true, message: '清理成功' });
} catch (error) {
console.error('清理登录历史错误:', error);
res.status(500).json({ success: false, message: '清理失败' });
}
});
const { Op } = require('sequelize');
module.exports = router;
+162
View File
@@ -0,0 +1,162 @@
const express = require('express');
const OperationLog = require('../models/OperationLog');
const { authMiddleware } = require('../middleware/auth');
const router = express.Router();
const ACTION_TYPES = {
USER_CREATE: '创建用户',
USER_UPDATE: '修改用户',
USER_DELETE: '删除用户',
USER_LOGIN: '用户登录',
USER_LOGOUT: '用户登出',
ROLE_CREATE: '创建角色',
ROLE_UPDATE: '修改角色',
ROLE_DELETE: '删除角色',
ROLE_ASSIGN: '分配角色',
DEVICE_CREATE: '创建设备',
DEVICE_UPDATE: '修改设备',
DEVICE_DELETE: '删除设备',
CONSUMABLE_IN: '耗材入库',
CONSUMABLE_OUT: '耗材出库',
CONSUMABLE_RECORD: '耗材记录',
SYSTEM_CONFIG: '系统配置'
};
router.get('/', authMiddleware, async (req, res) => {
try {
const { page = 1, pageSize = 20, userId, action, module, startDate, endDate } = req.query;
const offset = (parseInt(page) - 1) * parseInt(pageSize);
const limit = parseInt(pageSize);
const where = {};
if (userId) where.userId = userId;
if (action) where.action = action;
if (module) where.module = module;
if (startDate || endDate) {
where.operateTime = {};
if (startDate) where.operateTime[Op.gte] = new Date(startDate);
if (endDate) where.operateTime[Op.lte] = new Date(endDate);
}
const { count, rows } = await OperationLog.findAndCountAll({
where,
limit,
offset,
order: [['operateTime', 'DESC']]
});
res.json({
success: true,
data: {
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize),
logs: rows.map(l => ({
id: l.id,
userId: l.userId,
username: l.username,
realName: l.realName,
action: l.action,
module: l.module,
description: l.description,
targetId: l.targetId,
targetName: l.targetName,
oldValue: l.oldValue,
newValue: l.newValue,
ip: l.ip,
status: l.status,
errorMessage: l.errorMessage,
operateTime: l.operateTime
}))
}
});
} catch (error) {
console.error('获取操作日志错误:', error);
res.status(500).json({
success: false,
message: '获取操作日志失败'
});
}
});
router.get('/actions', authMiddleware, (req, res) => {
res.json({
success: true,
data: Object.entries(ACTION_TYPES).map(([key, value]) => ({
key,
value,
label: value
}))
});
});
router.get('/modules', authMiddleware, (req, res) => {
res.json({
success: true,
data: [
{ key: 'user', value: 'user', label: '用户管理' },
{ key: 'role', value: 'role', label: '角色管理' },
{ key: 'device', value: 'device', label: '设备管理' },
{ key: 'consumable', value: 'consumable', label: '耗材管理' },
{ key: 'system', value: 'system', label: '系统设置' }
]
});
});
router.delete('/:id', authMiddleware, async (req, res) => {
try {
await OperationLog.destroy({ where: { id: req.params.id } });
res.json({ success: true, message: '删除成功' });
} catch (error) {
console.error('删除操作日志错误:', error);
res.status(500).json({ success: false, message: '删除失败' });
}
});
router.delete('/', authMiddleware, async (req, res) => {
try {
const { days } = req.body;
const where = {};
if (days) {
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - days);
where.operateTime = { [Op.lt]: cutoffDate };
}
await OperationLog.destroy({ where });
res.json({ success: true, message: '清理成功' });
} catch (error) {
console.error('清理操作日志错误:', error);
res.status(500).json({ success: false, message: '清理失败' });
}
});
const logOperation = async (req, action, module, description, targetId, targetName, oldValue, newValue, status = 'success', errorMessage = null) => {
try {
await OperationLog.create({
userId: req.user?.userId,
username: req.user?.username,
realName: req.userModel?.realName,
action,
module,
description,
targetId,
targetName,
oldValue: oldValue ? JSON.stringify(oldValue) : null,
newValue: newValue ? JSON.stringify(newValue) : null,
ip: req.ip,
status,
errorMessage
});
} catch (error) {
console.error('记录操作日志错误:', error);
}
};
module.exports = router;
module.exports.ACTION_TYPES = ACTION_TYPES;
module.exports.logOperation = logOperation;
const { Op } = require('sequelize');
+275
View File
@@ -0,0 +1,275 @@
const express = require('express');
const Role = require('../models/Role');
const Permission = require('../models/Permission');
const UserRole = require('../models/UserRole');
const User = require('../models/User');
const { authMiddleware } = require('../middleware/auth');
const router = express.Router();
const generateId = () => {
return 'role_' + Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
};
const { Op } = require('sequelize');
router.get('/', authMiddleware, async (req, res) => {
try {
const { page = 1, pageSize = 10, roleName, status } = req.query;
const offset = (parseInt(page) - 1) * parseInt(pageSize);
const limit = parseInt(pageSize);
const where = {};
if (roleName) {
where.roleName = { [Op.like]: `%${roleName}%` };
}
if (status) {
where.status = status;
}
const { count, rows: roles } = await Role.findAndCountAll({
where,
limit,
offset,
order: [['sort', 'ASC'], ['createdAt', 'DESC']]
});
res.json({
success: true,
data: {
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize),
roles
}
});
} catch (error) {
console.error('获取角色列表错误:', error);
res.status(500).json({
success: false,
message: '获取角色列表失败'
});
}
});
router.get('/all', authMiddleware, async (req, res) => {
try {
const roles = await Role.findAll({
where: { status: 'active' },
order: [['sort', 'ASC']]
});
res.json({
success: true,
data: roles
});
} catch (error) {
console.error('获取所有角色错误:', error);
res.status(500).json({
success: false,
message: '获取角色列表失败'
});
}
});
router.get('/:roleId', authMiddleware, async (req, res) => {
try {
const role = await Role.findByPk(req.params.roleId);
if (!role) {
return res.status(404).json({
success: false,
message: '角色不存在'
});
}
const permissions = await Permission.findAll({
where: { status: 'active' },
order: [['sort', 'ASC']]
});
res.json({
success: true,
data: {
role,
permissions,
rolePermissions: role.permissions || []
}
});
} catch (error) {
console.error('获取角色详情错误:', error);
res.status(500).json({
success: false,
message: '获取角色详情失败'
});
}
});
router.post('/', authMiddleware, async (req, res) => {
try {
const { roleName, roleCode, description, permissions, status, sort } = req.body;
if (!roleName || !roleCode) {
return res.status(400).json({
success: false,
message: '角色名称和角色编码不能为空'
});
}
const existingRole = await Role.findOne({ where: { roleCode } });
if (existingRole) {
return res.status(400).json({
success: false,
message: '角色编码已存在'
});
}
const role = await Role.create({
roleId: generateId(),
roleName,
roleCode,
description,
permissions: permissions || [],
status: status || 'active',
sort: sort || 0
});
res.status(201).json({
success: true,
message: '创建成功',
data: role
});
} catch (error) {
console.error('创建角色错误:', error);
res.status(500).json({
success: false,
message: '创建角色失败'
});
}
});
router.put('/:roleId', authMiddleware, async (req, res) => {
try {
const { roleName, description, permissions, status, sort } = req.body;
const role = await Role.findByPk(req.params.roleId);
if (!role) {
return res.status(404).json({
success: false,
message: '角色不存在'
});
}
if (roleName !== undefined) role.roleName = roleName;
if (description !== undefined) role.description = description;
if (permissions !== undefined) role.permissions = permissions;
if (status !== undefined) role.status = status;
if (sort !== undefined) role.sort = sort;
await role.save();
res.json({
success: true,
message: '更新成功',
data: role
});
} catch (error) {
console.error('更新角色错误:', error);
res.status(500).json({
success: false,
message: '更新角色失败'
});
}
});
router.delete('/:roleId', authMiddleware, async (req, res) => {
try {
const role = await Role.findByPk(req.params.roleId);
if (!role) {
return res.status(404).json({
success: false,
message: '角色不存在'
});
}
if (role.roleCode === 'admin') {
return res.status(400).json({
success: false,
message: '不能删除管理员角色'
});
}
const userCount = await UserRole.count({ where: { RoleId: role.roleId } });
if (userCount > 0) {
return res.status(400).json({
success: false,
message: '该角色下有用户,不能删除'
});
}
await role.destroy();
res.json({
success: true,
message: '删除成功'
});
} catch (error) {
console.error('删除角色错误:', error);
res.status(500).json({
success: false,
message: '删除角色失败'
});
}
});
router.post('/init-roles', async (req, res) => {
try {
const defaultRoles = [
{
roleId: 'role_admin',
roleName: '管理员',
roleCode: 'admin',
description: '系统管理员,拥有所有权限',
permissions: ['*'],
status: 'active',
sort: 1
},
{
roleId: 'role_operator',
roleName: '运维人员',
roleCode: 'operator',
description: '负责日常运维操作',
permissions: ['devices:read', 'devices:write', 'racks:read', 'rooms:read', 'consumables:read', 'consumables:write'],
status: 'active',
sort: 2
},
{
roleId: 'role_viewer',
roleName: '只读用户',
roleCode: 'viewer',
description: '仅能查看数据',
permissions: ['devices:read', 'racks:read', 'rooms:read', 'consumables:read'],
status: 'active',
sort: 3
}
];
for (const roleData of defaultRoles) {
await Role.upsert(roleData);
}
res.json({
success: true,
message: '初始化角色成功'
});
} catch (error) {
console.error('初始化角色错误:', error);
res.status(500).json({
success: false,
message: '初始化角色失败'
});
}
});
module.exports = router;
+450
View File
@@ -0,0 +1,450 @@
const express = require('express');
const bcrypt = require('bcryptjs');
const path = require('path');
const fs = require('fs');
const User = require('../models/User');
const Role = require('../models/Role');
const UserRole = require('../models/UserRole');
const { authMiddleware } = require('../middleware/auth');
const router = express.Router();
const SALT_ROUNDS = 10;
const generateId = () => {
return 'user_' + Date.now().toString(36) + Math.random().toString(36).substr(2, 9);
};
const getWhereClause = (query) => {
const where = {};
if (query.username) {
where.username = { [Op.like]: `%${query.username}%` };
}
if (query.status) {
where.status = query.status;
}
if (query.realName) {
where.realName = { [Op.like]: `%${query.realName}%` };
}
return where;
};
const { Op } = require('sequelize');
router.get('/', authMiddleware, async (req, res) => {
try {
const { page = 1, pageSize = 10, username, status, realName } = req.query;
const offset = (parseInt(page) - 1) * parseInt(pageSize);
const limit = parseInt(pageSize);
const where = getWhereClause({ username, status, realName });
const { count, rows: users } = await User.findAndCountAll({
where,
attributes: { exclude: ['password'] },
limit,
offset,
order: [['createdAt', 'DESC']]
});
for (const user of users) {
const userRoles = await UserRole.findAll({
include: [{
model: Role,
where: { status: 'active' }
}],
where: { UserId: user.userId }
});
user.dataValues.roles = userRoles.map(ur => ({
roleId: ur.Role.roleId,
roleName: ur.Role.roleName,
roleCode: ur.Role.roleCode
}));
}
res.json({
success: true,
data: {
total: count,
page: parseInt(page),
pageSize: parseInt(pageSize),
users
}
});
} catch (error) {
console.error('获取用户列表错误:', error);
res.status(500).json({
success: false,
message: '获取用户列表失败'
});
}
});
router.get('/all', authMiddleware, async (req, res) => {
try {
const users = await User.findAll({
where: { status: 'active' },
attributes: ['userId', 'username', 'realName', 'email'],
order: [['realName', 'ASC']]
});
res.json({
success: true,
data: users
});
} catch (error) {
console.error('获取所有用户错误:', error);
res.status(500).json({
success: false,
message: '获取用户列表失败'
});
}
});
router.get('/:userId', authMiddleware, async (req, res) => {
try {
const user = await User.findByPk(req.params.userId, {
attributes: { exclude: ['password'] }
});
if (!user) {
return res.status(404).json({
success: false,
message: '用户不存在'
});
}
const userRoles = await UserRole.findAll({
include: [{
model: Role,
where: { status: 'active' }
}],
where: { UserId: user.userId }
});
user.dataValues.roles = userRoles.map(ur => ({
roleId: ur.Role.roleId,
roleName: ur.Role.roleName,
roleCode: ur.Role.roleCode
}));
res.json({
success: true,
data: user
});
} catch (error) {
console.error('获取用户详情错误:', error);
res.status(500).json({
success: false,
message: '获取用户详情失败'
});
}
});
router.post('/', authMiddleware, async (req, res) => {
try {
const { username, password, email, phone, realName, roleIds, status, remark } = req.body;
if (!username || !password) {
return res.status(400).json({
success: false,
message: '用户名和密码不能为空'
});
}
const existingUser = await User.findOne({ where: { username } });
if (existingUser) {
return res.status(400).json({
success: false,
message: '用户名已存在'
});
}
const hashedPassword = await bcrypt.hash(password, SALT_ROUNDS);
const user = await User.create({
userId: generateId(),
username,
password: hashedPassword,
email,
phone,
realName: realName || username,
status: status || 'active',
remark
});
if (roleIds && roleIds.length > 0) {
for (const roleId of roleIds) {
await UserRole.create({
UserId: user.userId,
RoleId: roleId
});
}
}
res.status(201).json({
success: true,
message: '创建成功',
data: {
userId: user.userId,
username: user.username,
email: user.email,
realName: user.realName,
status: user.status
}
});
} catch (error) {
console.error('创建用户错误:', error);
res.status(500).json({
success: false,
message: '创建用户失败'
});
}
});
router.put('/:userId', authMiddleware, async (req, res) => {
try {
const { username, email, phone, realName, roleIds, status, remark, newPassword } = req.body;
const user = await User.findByPk(req.params.userId);
if (!user) {
return res.status(404).json({
success: false,
message: '用户不存在'
});
}
if (username !== undefined && username !== user.username) {
const existingUser = await User.findOne({
where: { username, userId: { [Op.ne]: user.userId } }
});
if (existingUser) {
return res.status(400).json({
success: false,
message: '用户名已存在'
});
}
user.username = username;
}
if (email !== undefined) user.email = email;
if (phone !== undefined) user.phone = phone;
if (realName !== undefined) user.realName = realName;
if (status !== undefined) user.status = status;
if (remark !== undefined) user.remark = remark;
if (newPassword && newPassword.length >= 6) {
user.password = await bcrypt.hash(newPassword, SALT_ROUNDS);
}
await user.save();
if (roleIds !== undefined) {
await UserRole.destroy({ where: { UserId: user.userId } });
for (const roleId of roleIds) {
await UserRole.create({
UserId: user.userId,
RoleId: roleId
});
}
}
const updatedUser = await User.findByPk(req.params.userId, {
attributes: { exclude: ['password'] }
});
res.json({
success: true,
message: '更新成功',
data: updatedUser
});
} catch (error) {
console.error('更新用户错误:', error);
res.status(500).json({
success: false,
message: '更新用户失败'
});
}
});
router.put('/:userId/password', authMiddleware, async (req, res) => {
try {
const { newPassword } = req.body;
const user = await User.findByPk(req.params.userId);
if (!user) {
return res.status(404).json({
success: false,
message: '用户不存在'
});
}
if (!newPassword || newPassword.length < 6) {
return res.status(400).json({
success: false,
message: '密码长度不能少于6个字符'
});
}
user.password = await bcrypt.hash(newPassword, SALT_ROUNDS);
await user.save();
res.json({
success: true,
message: '密码重置成功'
});
} catch (error) {
console.error('重置密码错误:', error);
res.status(500).json({
success: false,
message: '重置密码失败'
});
}
});
router.delete('/:userId', authMiddleware, async (req, res) => {
try {
const user = await User.findByPk(req.params.userId);
if (!user) {
return res.status(404).json({
success: false,
message: '用户不存在'
});
}
if (user.userId === req.user.userId) {
return res.status(400).json({
success: false,
message: '不能删除当前登录用户'
});
}
await UserRole.destroy({ where: { UserId: user.userId } });
await user.destroy();
res.json({
success: true,
message: '删除成功'
});
} catch (error) {
console.error('删除用户错误:', error);
res.status(500).json({
success: false,
message: '删除用户失败'
});
}
});
router.post('/:userId/avatar', authMiddleware, async (req, res) => {
try {
const user = await User.findByPk(req.params.userId);
if (!user) {
return res.status(404).json({
success: false,
message: '用户不存在'
});
}
if (!req.files || !req.files.avatar) {
return res.status(400).json({
success: false,
message: '请选择要上传的头像文件'
});
}
const avatarFile = req.files.avatar;
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
if (!allowedTypes.includes(avatarFile.mimetype)) {
return res.status(400).json({
success: false,
message: '只支持 JPG、PNG、GIF 和 WebP 格式的图片'
});
}
if (avatarFile.size > 5 * 1024 * 1024) {
return res.status(400).json({
success: false,
message: '图片大小不能超过 5MB'
});
}
const uploadDir = path.join(__dirname, '..', 'uploads', 'avatars');
if (!fs.existsSync(uploadDir)) {
fs.mkdirSync(uploadDir, { recursive: true });
}
const ext = path.extname(avatarFile.name) || '.jpg';
const filename = `avatar_${user.userId}_${Date.now()}${ext}`;
const filepath = path.join(uploadDir, filename);
await avatarFile.mv(filepath);
if (user.avatar && user.avatar.startsWith('/uploads/avatars/')) {
const oldFile = path.join(__dirname, '..', user.avatar);
if (fs.existsSync(oldFile)) {
fs.unlinkSync(oldFile);
}
}
const avatarUrl = `/uploads/avatars/${filename}`;
user.avatar = avatarUrl;
await user.save();
res.json({
success: true,
message: '头像上传成功',
data: { avatar: avatarUrl }
});
} catch (error) {
console.error('上传头像错误:', error);
res.status(500).json({
success: false,
message: '上传头像失败'
});
}
});
router.delete('/:userId/avatar', authMiddleware, async (req, res) => {
try {
const user = await User.findByPk(req.params.userId);
if (!user) {
return res.status(404).json({
success: false,
message: '用户不存在'
});
}
if (user.avatar && user.avatar.startsWith('/uploads/avatars/')) {
const oldFile = path.join(__dirname, '..', user.avatar);
if (fs.existsSync(oldFile)) {
fs.unlinkSync(oldFile);
}
}
user.avatar = null;
await user.save();
res.json({
success: true,
message: '头像删除成功'
});
} catch (error) {
console.error('删除头像错误:', error);
res.status(500).json({
success: false,
message: '删除头像失败'
});
}
});
module.exports = router;