/** * 操作日志模型 * @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} 创建的日志记录 */ 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} 统计结果 */ 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} 统计结果 */ 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} 删除的记录数 */ 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;