refactor: 移除登录历史和操作日志功能及相关代码

移除后端登录历史和操作日志的模型、路由及前端相关页面和路由配置
清理创建和删除索引脚本中的相关代码
调整系统管理菜单结构
This commit is contained in:
zhang1106
2026-01-20 16:54:26 +08:00
parent 61dc0eefbe
commit 2af47ee162
10 changed files with 18 additions and 1020 deletions
+1 -21
View File
@@ -45,23 +45,6 @@ const createIndexes = async () => {
await queryInterface.addIndex('consumable_logs', ['consumableId', 'createdAt']);
console.log(' ✓ consumable_logs 表索引创建完成');
// OperationLog 表索引
console.log('创建 operation_logs 表索引...');
await queryInterface.addIndex('operation_logs', ['userId']);
await queryInterface.addIndex('operation_logs', ['action']);
await queryInterface.addIndex('operation_logs', ['module']);
await queryInterface.addIndex('operation_logs', ['createdAt']);
await queryInterface.addIndex('operation_logs', ['userId', 'createdAt']);
console.log(' ✓ operation_logs 表索引创建完成');
// LoginHistory 表索引
console.log('创建 login_histories 表索引...');
await queryInterface.addIndex('login_histories', ['userId']);
await queryInterface.addIndex('login_histories', ['loginTime']);
await queryInterface.addIndex('login_histories', ['loginType']);
await queryInterface.addIndex('login_histories', ['userId', 'loginTime']);
console.log(' ✓ login_histories 表索引创建完成');
// Rack 表索引
console.log('创建 racks 表索引...');
await queryInterface.addIndex('racks', ['roomId']);
@@ -87,8 +70,7 @@ const checkIndexes = async () => {
const queryInterface = sequelize.getQueryInterface();
const tables = [
'devices', 'users', 'consumables', 'consumable_records',
'consumable_logs', 'operation_logs', 'login_histories',
'racks', 'rooms'
'consumable_logs', 'racks', 'rooms'
];
console.log('\n检查现有索引...');
@@ -117,8 +99,6 @@ const dropIndexes = async () => {
{ table: 'consumables', indexes: ['category', 'status', 'category_status'] },
{ table: 'consumable_records', indexes: ['consumableId', 'type', 'createdAt'] },
{ table: 'consumable_logs', indexes: ['consumableId', 'operationType', 'createdAt', 'consumableId_createdAt'] },
{ table: 'operation_logs', indexes: ['userId', 'action', 'module', 'createdAt', 'userId_createdAt'] },
{ table: 'login_histories', indexes: ['userId', 'loginTime', 'loginType', 'userId_loginTime'] },
{ table: 'racks', indexes: ['roomId', 'status', 'roomId_status'] },
{ table: 'rooms', indexes: ['status', 'name'] }
];
-1
View File
@@ -1,6 +1,5 @@
const jwt = require('jsonwebtoken');
const User = require('../models/User');
const LoginHistory = require('../models/LoginHistory');
const JWT_SECRET = process.env.JWT_SECRET || 'idc-management-secret-key-2024';
const TOKEN_EXPIRY = process.env.TOKEN_EXPIRY || '24h';
-63
View File
@@ -1,63 +0,0 @@
const { DataTypes } = require('sequelize');
const { sequelize } = require('../db');
const LoginHistory = sequelize.define('LoginHistory', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
userId: {
type: DataTypes.STRING,
allowNull: false,
comment: '用户ID'
},
username: {
type: DataTypes.STRING,
allowNull: false,
comment: '用户名'
},
realName: {
type: DataTypes.STRING,
allowNull: true,
comment: '真实姓名'
},
loginTime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW,
comment: '登录时间'
},
loginIp: {
type: DataTypes.STRING,
allowNull: true,
comment: '登录IP'
},
userAgent: {
type: DataTypes.TEXT,
allowNull: true,
comment: '浏览器UA'
},
loginType: {
type: DataTypes.ENUM('success', 'failed'),
defaultValue: 'success',
comment: '登录结果'
},
failReason: {
type: DataTypes.STRING,
allowNull: true,
comment: '失败原因'
}
}, {
tableName: 'login_histories',
timestamps: true,
createdAt: 'loginTime',
updatedAt: false,
indexes: [
{ fields: ['userId'] },
{ fields: ['loginTime'] },
{ fields: ['loginType'] },
{ fields: ['userId', 'loginTime'] }
]
});
module.exports = LoginHistory;
-89
View File
@@ -1,89 +0,0 @@
const { DataTypes } = require('sequelize');
const { sequelize } = require('../db');
const OperationLog = sequelize.define('OperationLog', {
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
userId: {
type: DataTypes.STRING,
allowNull: false,
comment: '操作人ID'
},
username: {
type: DataTypes.STRING,
allowNull: false,
comment: '操作人用户名'
},
realName: {
type: DataTypes.STRING,
allowNull: true,
comment: '操作人真实姓名'
},
action: {
type: DataTypes.STRING,
allowNull: false,
comment: '操作类型'
},
module: {
type: DataTypes.STRING,
allowNull: true,
comment: '操作模块'
},
description: {
type: DataTypes.TEXT,
allowNull: true,
comment: '操作描述'
},
targetId: {
type: DataTypes.STRING,
allowNull: true,
comment: '目标对象ID'
},
targetName: {
type: DataTypes.STRING,
allowNull: true,
comment: '目标对象名称'
},
oldValue: {
type: DataTypes.TEXT,
allowNull: true,
comment: '旧值'
},
newValue: {
type: DataTypes.TEXT,
allowNull: true,
comment: '新值'
},
ip: {
type: DataTypes.STRING,
allowNull: true,
comment: '操作IP'
},
status: {
type: DataTypes.ENUM('success', 'failed'),
defaultValue: 'success',
comment: '操作状态'
},
errorMessage: {
type: DataTypes.TEXT,
allowNull: true,
comment: '错误信息'
}
}, {
tableName: 'operation_logs',
timestamps: true,
createdAt: 'operateTime',
updatedAt: false,
indexes: [
{ fields: ['userId'] },
{ fields: ['action'] },
{ fields: ['module'] },
{ fields: ['operateTime'] },
{ fields: ['userId', 'operateTime'] }
]
});
module.exports = OperationLog;
-120
View File
@@ -1,120 +0,0 @@
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
@@ -1,162 +0,0 @@
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');
-4
View File
@@ -58,8 +58,6 @@ const consumableCategoryRoutes = require('./routes/consumableCategories');
const authRoutes = require('./routes/auth');
const usersRoutes = require('./routes/users');
const rolesRoutes = require('./routes/roles');
const loginHistoryRoutes = require('./routes/loginHistory');
const operationLogsRoutes = require('./routes/operationLogs');
const ticketRoutes = require('./routes/tickets');
const ticketCategoryRoutes = require('./routes/ticketCategories');
const ticketFieldRoutes = require('./routes/ticketFields');
@@ -77,8 +75,6 @@ app.use('/api/consumable-categories', consumableCategoryRoutes);
app.use('/api/auth', authRoutes);
app.use('/api/users', usersRoutes);
app.use('/api/roles', rolesRoutes);
app.use('/api/login-history', loginHistoryRoutes);
app.use('/api/operation-logs', operationLogsRoutes);
app.use('/api/tickets', ticketRoutes);
app.use('/api/ticket-categories', ticketCategoryRoutes);
app.use('/api/ticket-fields', ticketFieldRoutes);