修改管理后台
This commit is contained in:
303
backend/models/OperationLog.js
Normal file
303
backend/models/OperationLog.js
Normal file
@@ -0,0 +1,303 @@
|
||||
/**
|
||||
* 操作日志模型
|
||||
* @file OperationLog.js
|
||||
* @description 记录系统用户的操作日志,包括新增、编辑、删除操作
|
||||
*/
|
||||
const { DataTypes } = require('sequelize');
|
||||
const BaseModel = require('./BaseModel');
|
||||
|
||||
class OperationLog extends BaseModel {
|
||||
static init(sequelize) {
|
||||
return super.init({
|
||||
id: {
|
||||
type: DataTypes.INTEGER,
|
||||
primaryKey: true,
|
||||
autoIncrement: true,
|
||||
comment: '主键ID'
|
||||
},
|
||||
user_id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: false,
|
||||
comment: '操作用户ID'
|
||||
},
|
||||
username: {
|
||||
type: DataTypes.STRING(50),
|
||||
allowNull: false,
|
||||
comment: '操作用户名'
|
||||
},
|
||||
user_role: {
|
||||
type: DataTypes.STRING(50),
|
||||
allowNull: false,
|
||||
comment: '操作用户角色'
|
||||
},
|
||||
operation_type: {
|
||||
type: DataTypes.ENUM('CREATE', 'UPDATE', 'DELETE', 'READ', 'LOGIN', 'LOGOUT', 'EXPORT', 'IMPORT', 'BATCH_DELETE', 'BATCH_UPDATE'),
|
||||
allowNull: false,
|
||||
comment: '操作类型:CREATE-新增,UPDATE-编辑,DELETE-删除,READ-查看,LOGIN-登录,LOGOUT-登出,EXPORT-导出,IMPORT-导入,BATCH_DELETE-批量删除,BATCH_UPDATE-批量更新'
|
||||
},
|
||||
module_name: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: false,
|
||||
comment: '操作模块名称'
|
||||
},
|
||||
table_name: {
|
||||
type: DataTypes.STRING(100),
|
||||
allowNull: false,
|
||||
comment: '操作的数据表名'
|
||||
},
|
||||
record_id: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '操作的记录ID'
|
||||
},
|
||||
operation_desc: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: false,
|
||||
comment: '操作描述'
|
||||
},
|
||||
old_data: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: true,
|
||||
comment: '操作前的数据(编辑和删除时记录)'
|
||||
},
|
||||
new_data: {
|
||||
type: DataTypes.JSON,
|
||||
allowNull: true,
|
||||
comment: '操作后的数据(新增和编辑时记录)'
|
||||
},
|
||||
ip_address: {
|
||||
type: DataTypes.STRING(45),
|
||||
allowNull: true,
|
||||
comment: '操作IP地址'
|
||||
},
|
||||
user_agent: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '用户代理信息'
|
||||
},
|
||||
request_url: {
|
||||
type: DataTypes.STRING(500),
|
||||
allowNull: true,
|
||||
comment: '请求URL'
|
||||
},
|
||||
request_method: {
|
||||
type: DataTypes.STRING(10),
|
||||
allowNull: true,
|
||||
comment: '请求方法'
|
||||
},
|
||||
response_status: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '响应状态码'
|
||||
},
|
||||
execution_time: {
|
||||
type: DataTypes.INTEGER,
|
||||
allowNull: true,
|
||||
comment: '执行时间(毫秒)'
|
||||
},
|
||||
error_message: {
|
||||
type: DataTypes.TEXT,
|
||||
allowNull: true,
|
||||
comment: '错误信息(如果有)'
|
||||
},
|
||||
created_at: {
|
||||
type: DataTypes.DATE,
|
||||
allowNull: false,
|
||||
defaultValue: DataTypes.NOW,
|
||||
comment: '创建时间'
|
||||
}
|
||||
}, {
|
||||
sequelize,
|
||||
tableName: 'operation_logs',
|
||||
comment: '操作日志表',
|
||||
indexes: [
|
||||
{
|
||||
name: 'idx_user_id',
|
||||
fields: ['user_id']
|
||||
},
|
||||
{
|
||||
name: 'idx_operation_type',
|
||||
fields: ['operation_type']
|
||||
},
|
||||
{
|
||||
name: 'idx_module_name',
|
||||
fields: ['module_name']
|
||||
},
|
||||
{
|
||||
name: 'idx_table_name',
|
||||
fields: ['table_name']
|
||||
},
|
||||
{
|
||||
name: 'idx_created_at',
|
||||
fields: ['created_at']
|
||||
},
|
||||
{
|
||||
name: 'idx_user_operation',
|
||||
fields: ['user_id', 'operation_type']
|
||||
},
|
||||
{
|
||||
name: 'idx_module_operation',
|
||||
fields: ['module_name', 'operation_type']
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录操作日志
|
||||
* @param {Object} logData 日志数据
|
||||
* @returns {Promise<OperationLog>} 创建的日志记录
|
||||
*/
|
||||
static async recordOperation(logData) {
|
||||
try {
|
||||
const {
|
||||
userId,
|
||||
username,
|
||||
userRole,
|
||||
operationType,
|
||||
moduleName,
|
||||
tableName,
|
||||
recordId,
|
||||
operationDesc,
|
||||
oldData,
|
||||
newData,
|
||||
ipAddress,
|
||||
userAgent,
|
||||
requestUrl,
|
||||
requestMethod,
|
||||
responseStatus,
|
||||
executionTime,
|
||||
errorMessage
|
||||
} = logData;
|
||||
|
||||
return await this.create({
|
||||
user_id: userId,
|
||||
username: username,
|
||||
user_role: userRole,
|
||||
operation_type: operationType,
|
||||
module_name: moduleName,
|
||||
table_name: tableName,
|
||||
record_id: recordId,
|
||||
operation_desc: operationDesc,
|
||||
old_data: oldData,
|
||||
new_data: newData,
|
||||
ip_address: ipAddress,
|
||||
user_agent: userAgent,
|
||||
request_url: requestUrl,
|
||||
request_method: requestMethod,
|
||||
response_status: responseStatus,
|
||||
execution_time: executionTime,
|
||||
error_message: errorMessage
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('记录操作日志失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户操作统计
|
||||
* @param {number} userId 用户ID
|
||||
* @param {string} startDate 开始日期
|
||||
* @param {string} endDate 结束日期
|
||||
* @returns {Promise<Object>} 统计结果
|
||||
*/
|
||||
static async getUserOperationStats(userId, startDate, endDate) {
|
||||
try {
|
||||
const whereClause = {
|
||||
user_id: userId
|
||||
};
|
||||
|
||||
if (startDate && endDate) {
|
||||
whereClause.created_at = {
|
||||
[this.sequelize.Sequelize.Op.between]: [startDate, endDate]
|
||||
};
|
||||
}
|
||||
|
||||
const stats = await this.findAll({
|
||||
where: whereClause,
|
||||
attributes: [
|
||||
'operation_type',
|
||||
[this.sequelize.fn('COUNT', this.sequelize.col('id')), 'count']
|
||||
],
|
||||
group: ['operation_type'],
|
||||
raw: true
|
||||
});
|
||||
|
||||
return stats.reduce((acc, stat) => {
|
||||
acc[stat.operation_type] = parseInt(stat.count);
|
||||
return acc;
|
||||
}, {});
|
||||
} catch (error) {
|
||||
console.error('获取用户操作统计失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模块操作统计
|
||||
* @param {string} moduleName 模块名称
|
||||
* @param {string} startDate 开始日期
|
||||
* @param {string} endDate 结束日期
|
||||
* @returns {Promise<Object>} 统计结果
|
||||
*/
|
||||
static async getModuleOperationStats(moduleName, startDate, endDate) {
|
||||
try {
|
||||
const whereClause = {
|
||||
module_name: moduleName
|
||||
};
|
||||
|
||||
if (startDate && endDate) {
|
||||
whereClause.created_at = {
|
||||
[this.sequelize.Sequelize.Op.between]: [startDate, endDate]
|
||||
};
|
||||
}
|
||||
|
||||
const stats = await this.findAll({
|
||||
where: whereClause,
|
||||
attributes: [
|
||||
'operation_type',
|
||||
[this.sequelize.fn('COUNT', this.sequelize.col('id')), 'count']
|
||||
],
|
||||
group: ['operation_type'],
|
||||
raw: true
|
||||
});
|
||||
|
||||
return stats.reduce((acc, stat) => {
|
||||
acc[stat.operation_type] = parseInt(stat.count);
|
||||
return acc;
|
||||
}, {});
|
||||
} catch (error) {
|
||||
console.error('获取模块操作统计失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理过期日志
|
||||
* @param {number} daysToKeep 保留天数
|
||||
* @returns {Promise<number>} 删除的记录数
|
||||
*/
|
||||
static async cleanExpiredLogs(daysToKeep = 90) {
|
||||
try {
|
||||
const cutoffDate = new Date();
|
||||
cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);
|
||||
|
||||
const deletedCount = await this.destroy({
|
||||
where: {
|
||||
created_at: {
|
||||
[this.sequelize.Sequelize.Op.lt]: cutoffDate
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log(`清理了 ${deletedCount} 条过期操作日志`);
|
||||
return deletedCount;
|
||||
} catch (error) {
|
||||
console.error('清理过期日志失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = OperationLog;
|
||||
Reference in New Issue
Block a user