Files
nxxmdata/backend/models/OperationLog.js

304 lines
8.0 KiB
JavaScript
Raw Normal View History

2025-09-12 20:08:42 +08:00
/**
* 操作日志模型
* @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;