import { Middleware, IMiddleware } from '@midwayjs/core'; import { Context, NextFunction } from '@midwayjs/koa'; import { Provide, Inject } from '@midwayjs/core'; import { InjectRepository } from '@midwayjs/sequelize'; import SysOperationLog from '../entity/sysOperationLog.entity'; @Provide() export class LogMiddleware implements IMiddleware { // 中间件匹配范围:全局生效,跳过日志查询、健康检查、登录(登录由内部记录)与文件上传(multipart 无记录价值) ignore = ['/api/logs/*', '/api/health', '/api/auth/login', '/api/upload/*']; @InjectRepository(SysOperationLog) logModel!: typeof SysOperationLog; resolve() { return async (ctx: Context, next: NextFunction) => { await next(); // 仅记录写操作,且要求登录用户存在 if (!['POST', 'PUT', 'DELETE'].includes(ctx.method)) { return; } if (!ctx.state.user) { return; } const logData = { userId: ctx.state.user.userId, module: this.getModuleFromUrl(ctx.url), action: this.getActionDescription(ctx), method: ctx.method, params: JSON.stringify(ctx.request.body || {}), ip: ctx.ip, }; this.saveLog(logData).catch(err => { console.error('保存操作日志失败:', err); }); }; } private getActionDescription(ctx: Context): string { const actionMap: Record> = { '/api/auth/login': { POST: '用户登录' }, '/api/auth/logout': { POST: '用户登出' }, '/api/users': { POST: '创建用户', PUT: '更新用户', DELETE: '删除用户', }, '/api/roles': { POST: '创建角色', PUT: '更新角色', DELETE: '删除角色', }, '/api/menus': { POST: '创建菜单', PUT: '更新菜单', DELETE: '删除菜单', }, '/api/dicts': { POST: '创建字典', PUT: '更新字典', DELETE: '删除字典', }, }; const basePath = ctx.url.split('?')[0]; if (actionMap[basePath]?.[ctx.method]) { return actionMap[basePath][ctx.method]; } for (const [path, actions] of Object.entries(actionMap)) { if (basePath.startsWith(path) && actions[ctx.method]) { return actions[ctx.method]; } } return `${ctx.method} ${basePath}`; } private getModuleFromUrl(url: string): string { const moduleMap: Record = { '/api/auth': '认证', '/api/users': '用户管理', '/api/roles': '角色管理', '/api/menus': '菜单管理', '/api/dicts': '数据字典', '/api/logs': '日志管理', '/api/dashboard': '仪表盘', }; for (const [path, module] of Object.entries(moduleMap)) { if (url.startsWith(path)) { return module; } } return '其他'; } private async saveLog(logData: any): Promise { try { await this.logModel.create(logData); } catch (error) { console.error('写入操作日志失败:', error); } } }