const OperationLog = require('../models/OperationLog'); const LoginLog = require('../models/LoginLog'); /** * 记录操作日志 * @param {Object} options 日志选项 * @param {number} options.userId 用户ID * @param {string} options.username 用户名 * @param {string} options.module 操作模块 * @param {string} options.action 操作类型 * @param {string} options.description 操作描述 * @param {string} options.method 请求方法 * @param {string} options.url 请求URL * @param {string} options.ip IP地址 * @param {Object} options.params 请求参数 * @param {Object} options.result 操作结果 * @param {string} options.status 操作状态 success/fail * @param {number} options.duration 执行时长(毫秒) */ async function logOperation(options) { try { await OperationLog.create({ userId: options.userId, username: options.username, module: options.module, action: options.action, description: options.description, method: options.method, url: options.url, ip: options.ip, params: options.params ? JSON.stringify(options.params) : null, result: options.result ? JSON.stringify(options.result) : null, status: options.status || 'success', duration: options.duration }); } catch (error) { console.error('记录操作日志失败:', error); } } /** * 记录登录日志 * @param {Object} options 日志选项 * @param {number} options.userId 用户ID * @param {string} options.username 用户名 * @param {string} options.loginType 登录类型 login/logout * @param {string} options.ip IP地址 * @param {string} options.userAgent 浏览器信息 * @param {string} options.status 登录状态 success/fail * @param {string} options.message 登录信息/失败原因 */ async function logLogin(options) { try { await LoginLog.create({ userId: options.userId, username: options.username, loginType: options.loginType, ip: options.ip, userAgent: options.userAgent, status: options.status || 'success', message: options.message }); } catch (error) { console.error('记录登录日志失败:', error); } } /** * 获取客户端IP地址 * @param {Object} req Express请求对象 * @returns {string} IP地址 */ function getClientIp(req) { return req.headers['x-forwarded-for'] || req.headers['x-real-ip'] || req.connection.remoteAddress || req.socket.remoteAddress || 'unknown'; } /** * 操作日志中间件 * 自动记录API请求日志 */ function operationLogMiddleware(options = {}) { const { module = '系统', excludePaths = ['/api/auth/login'] } = options; return async (req, res, next) => { // 排除指定路径 if (excludePaths.some(path => req.path.includes(path))) { return next(); } const startTime = Date.now(); const originalSend = res.send; // 捕获响应数据 res.send = function(data) { res.responseData = data; return originalSend.call(this, data); }; res.on('finish', async () => { const duration = Date.now() - startTime; const user = req.user || {}; try { await OperationLog.create({ userId: user.id, username: user.username, module: module, action: getActionFromMethod(req.method), description: `${req.method} ${req.path}`, method: req.method, url: req.originalUrl, ip: getClientIp(req), params: JSON.stringify({ body: req.body, query: req.query, params: req.params }), result: res.responseData ? res.responseData.substring(0, 2000) : null, status: res.statusCode >= 200 && res.statusCode < 300 ? 'success' : 'fail', duration: duration }); } catch (error) { console.error('记录操作日志失败:', error); } }); next(); }; } /** * 根据HTTP方法获取操作类型 * @param {string} method HTTP方法 * @returns {string} 操作类型 */ function getActionFromMethod(method) { const actionMap = { 'GET': '查询', 'POST': '新增', 'PUT': '修改', 'PATCH': '修改', 'DELETE': '删除' }; return actionMap[method] || '其他'; } module.exports = { logOperation, logLogin, getClientIp, operationLogMiddleware, getActionFromMethod };