541 lines
15 KiB
JavaScript
541 lines
15 KiB
JavaScript
|
|
/**
|
|||
|
|
* 操作日志路由
|
|||
|
|
* @file operationLogs.js
|
|||
|
|
* @description 定义操作日志相关的API路由
|
|||
|
|
*/
|
|||
|
|
const express = require('express');
|
|||
|
|
const router = express.Router();
|
|||
|
|
const { body, query, param } = require('express-validator');
|
|||
|
|
const operationLogController = require('../controllers/operationLogController');
|
|||
|
|
const auth = require('../middleware/auth');
|
|||
|
|
const { hasPermission } = require('../config/permissions');
|
|||
|
|
|
|||
|
|
// 验证中间件
|
|||
|
|
const validateRequest = (req, res, next) => {
|
|||
|
|
const errors = validationResult(req);
|
|||
|
|
if (!errors.isEmpty()) {
|
|||
|
|
return res.status(400).json({
|
|||
|
|
success: false,
|
|||
|
|
message: '请求参数验证失败',
|
|||
|
|
errors: errors.array()
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
next();
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @swagger
|
|||
|
|
* components:
|
|||
|
|
* schemas:
|
|||
|
|
* OperationLog:
|
|||
|
|
* type: object
|
|||
|
|
* properties:
|
|||
|
|
* id:
|
|||
|
|
* type: integer
|
|||
|
|
* description: 主键ID
|
|||
|
|
* user_id:
|
|||
|
|
* type: integer
|
|||
|
|
* description: 操作用户ID
|
|||
|
|
* username:
|
|||
|
|
* type: string
|
|||
|
|
* description: 操作用户名
|
|||
|
|
* user_role:
|
|||
|
|
* type: string
|
|||
|
|
* description: 操作用户角色
|
|||
|
|
* operation_type:
|
|||
|
|
* type: string
|
|||
|
|
* enum: [CREATE, UPDATE, DELETE]
|
|||
|
|
* description: 操作类型
|
|||
|
|
* module_name:
|
|||
|
|
* type: string
|
|||
|
|
* description: 操作模块名称
|
|||
|
|
* table_name:
|
|||
|
|
* type: string
|
|||
|
|
* description: 操作的数据表名
|
|||
|
|
* record_id:
|
|||
|
|
* type: integer
|
|||
|
|
* description: 操作的记录ID
|
|||
|
|
* operation_desc:
|
|||
|
|
* type: string
|
|||
|
|
* description: 操作描述
|
|||
|
|
* old_data:
|
|||
|
|
* type: object
|
|||
|
|
* description: 操作前的数据
|
|||
|
|
* new_data:
|
|||
|
|
* type: object
|
|||
|
|
* description: 操作后的数据
|
|||
|
|
* ip_address:
|
|||
|
|
* type: string
|
|||
|
|
* description: 操作IP地址
|
|||
|
|
* user_agent:
|
|||
|
|
* type: string
|
|||
|
|
* description: 用户代理信息
|
|||
|
|
* request_url:
|
|||
|
|
* type: string
|
|||
|
|
* description: 请求URL
|
|||
|
|
* request_method:
|
|||
|
|
* type: string
|
|||
|
|
* description: 请求方法
|
|||
|
|
* response_status:
|
|||
|
|
* type: integer
|
|||
|
|
* description: 响应状态码
|
|||
|
|
* execution_time:
|
|||
|
|
* type: integer
|
|||
|
|
* description: 执行时间(毫秒)
|
|||
|
|
* error_message:
|
|||
|
|
* type: string
|
|||
|
|
* description: 错误信息
|
|||
|
|
* created_at:
|
|||
|
|
* type: string
|
|||
|
|
* format: date-time
|
|||
|
|
* description: 创建时间
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @swagger
|
|||
|
|
* /api/operation-logs:
|
|||
|
|
* get:
|
|||
|
|
* summary: 获取操作日志列表
|
|||
|
|
* tags: [OperationLogs]
|
|||
|
|
* security:
|
|||
|
|
* - bearerAuth: []
|
|||
|
|
* parameters:
|
|||
|
|
* - in: query
|
|||
|
|
* name: page
|
|||
|
|
* schema:
|
|||
|
|
* type: integer
|
|||
|
|
* default: 1
|
|||
|
|
* description: 页码
|
|||
|
|
* - in: query
|
|||
|
|
* name: pageSize
|
|||
|
|
* schema:
|
|||
|
|
* type: integer
|
|||
|
|
* default: 20
|
|||
|
|
* description: 每页记录数
|
|||
|
|
* - in: query
|
|||
|
|
* name: userId
|
|||
|
|
* schema:
|
|||
|
|
* type: integer
|
|||
|
|
* description: 用户ID
|
|||
|
|
* - in: query
|
|||
|
|
* name: username
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* description: 用户名
|
|||
|
|
* - in: query
|
|||
|
|
* name: operationType
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* enum: [CREATE, UPDATE, DELETE]
|
|||
|
|
* description: 操作类型
|
|||
|
|
* - in: query
|
|||
|
|
* name: moduleName
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* description: 模块名称
|
|||
|
|
* - in: query
|
|||
|
|
* name: tableName
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* description: 数据表名
|
|||
|
|
* - in: query
|
|||
|
|
* name: startDate
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* format: date
|
|||
|
|
* description: 开始日期
|
|||
|
|
* - in: query
|
|||
|
|
* name: endDate
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* format: date
|
|||
|
|
* description: 结束日期
|
|||
|
|
* - in: query
|
|||
|
|
* name: sortBy
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* default: created_at
|
|||
|
|
* description: 排序字段
|
|||
|
|
* - in: query
|
|||
|
|
* name: sortOrder
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* enum: [ASC, DESC]
|
|||
|
|
* default: DESC
|
|||
|
|
* description: 排序方向
|
|||
|
|
* responses:
|
|||
|
|
* 200:
|
|||
|
|
* description: 获取操作日志列表成功
|
|||
|
|
* content:
|
|||
|
|
* application/json:
|
|||
|
|
* schema:
|
|||
|
|
* type: object
|
|||
|
|
* properties:
|
|||
|
|
* success:
|
|||
|
|
* type: boolean
|
|||
|
|
* data:
|
|||
|
|
* type: array
|
|||
|
|
* items:
|
|||
|
|
* $ref: '#/components/schemas/OperationLog'
|
|||
|
|
* pagination:
|
|||
|
|
* type: object
|
|||
|
|
* properties:
|
|||
|
|
* total:
|
|||
|
|
* type: integer
|
|||
|
|
* page:
|
|||
|
|
* type: integer
|
|||
|
|
* pageSize:
|
|||
|
|
* type: integer
|
|||
|
|
* totalPages:
|
|||
|
|
* type: integer
|
|||
|
|
* hasMore:
|
|||
|
|
* type: boolean
|
|||
|
|
* message:
|
|||
|
|
* type: string
|
|||
|
|
* 500:
|
|||
|
|
* description: 服务器内部错误
|
|||
|
|
*/
|
|||
|
|
router.get('/',
|
|||
|
|
auth,
|
|||
|
|
(req, res, next) => {
|
|||
|
|
if (!hasPermission(req.user.permissions, 'operation_log:view')) {
|
|||
|
|
return res.status(403).json({
|
|||
|
|
success: false,
|
|||
|
|
message: '权限不足,无法访问操作日志'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
next();
|
|||
|
|
},
|
|||
|
|
operationLogController.getOperationLogs
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @swagger
|
|||
|
|
* /api/operation-logs/{id}:
|
|||
|
|
* get:
|
|||
|
|
* summary: 获取操作日志详情
|
|||
|
|
* tags: [OperationLogs]
|
|||
|
|
* security:
|
|||
|
|
* - bearerAuth: []
|
|||
|
|
* parameters:
|
|||
|
|
* - in: path
|
|||
|
|
* name: id
|
|||
|
|
* required: true
|
|||
|
|
* schema:
|
|||
|
|
* type: integer
|
|||
|
|
* description: 操作日志ID
|
|||
|
|
* responses:
|
|||
|
|
* 200:
|
|||
|
|
* description: 获取操作日志详情成功
|
|||
|
|
* content:
|
|||
|
|
* application/json:
|
|||
|
|
* schema:
|
|||
|
|
* type: object
|
|||
|
|
* properties:
|
|||
|
|
* success:
|
|||
|
|
* type: boolean
|
|||
|
|
* data:
|
|||
|
|
* $ref: '#/components/schemas/OperationLog'
|
|||
|
|
* message:
|
|||
|
|
* type: string
|
|||
|
|
* 404:
|
|||
|
|
* description: 操作日志不存在
|
|||
|
|
* 500:
|
|||
|
|
* description: 服务器内部错误
|
|||
|
|
*/
|
|||
|
|
router.get('/:id',
|
|||
|
|
auth,
|
|||
|
|
(req, res, next) => {
|
|||
|
|
if (!hasPermission(req.user.permissions, 'operation_log:view')) {
|
|||
|
|
return res.status(403).json({
|
|||
|
|
success: false,
|
|||
|
|
message: '权限不足,无法访问操作日志'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
next();
|
|||
|
|
},
|
|||
|
|
operationLogController.getOperationLogById
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @swagger
|
|||
|
|
* /api/operation-logs/stats/overview:
|
|||
|
|
* get:
|
|||
|
|
* summary: 获取操作统计
|
|||
|
|
* tags: [OperationLogs]
|
|||
|
|
* security:
|
|||
|
|
* - bearerAuth: []
|
|||
|
|
* parameters:
|
|||
|
|
* - in: query
|
|||
|
|
* name: type
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* enum: [user, module, overall]
|
|||
|
|
* default: overall
|
|||
|
|
* description: 统计类型
|
|||
|
|
* - in: query
|
|||
|
|
* name: userId
|
|||
|
|
* schema:
|
|||
|
|
* type: integer
|
|||
|
|
* description: 用户ID(type为user时必填)
|
|||
|
|
* - in: query
|
|||
|
|
* name: moduleName
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* description: 模块名称(type为module时必填)
|
|||
|
|
* - in: query
|
|||
|
|
* name: startDate
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* format: date
|
|||
|
|
* description: 开始日期
|
|||
|
|
* - in: query
|
|||
|
|
* name: endDate
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* format: date
|
|||
|
|
* description: 结束日期
|
|||
|
|
* responses:
|
|||
|
|
* 200:
|
|||
|
|
* description: 获取操作统计成功
|
|||
|
|
* content:
|
|||
|
|
* application/json:
|
|||
|
|
* schema:
|
|||
|
|
* type: object
|
|||
|
|
* properties:
|
|||
|
|
* success:
|
|||
|
|
* type: boolean
|
|||
|
|
* data:
|
|||
|
|
* type: object
|
|||
|
|
* properties:
|
|||
|
|
* CREATE:
|
|||
|
|
* type: integer
|
|||
|
|
* UPDATE:
|
|||
|
|
* type: integer
|
|||
|
|
* DELETE:
|
|||
|
|
* type: integer
|
|||
|
|
* message:
|
|||
|
|
* type: string
|
|||
|
|
* 500:
|
|||
|
|
* description: 服务器内部错误
|
|||
|
|
*/
|
|||
|
|
router.get('/stats/overview',
|
|||
|
|
auth,
|
|||
|
|
(req, res, next) => {
|
|||
|
|
if (!hasPermission(req.user.permissions, 'operation_log:view')) {
|
|||
|
|
return res.status(403).json({
|
|||
|
|
success: false,
|
|||
|
|
message: '权限不足,无法访问操作统计'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
next();
|
|||
|
|
},
|
|||
|
|
operationLogController.getOperationStats
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @swagger
|
|||
|
|
* /api/operation-logs/stats/chart:
|
|||
|
|
* get:
|
|||
|
|
* summary: 获取操作日志图表数据
|
|||
|
|
* tags: [OperationLogs]
|
|||
|
|
* security:
|
|||
|
|
* - bearerAuth: []
|
|||
|
|
* parameters:
|
|||
|
|
* - in: query
|
|||
|
|
* name: type
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* enum: [hourly, daily, monthly]
|
|||
|
|
* default: daily
|
|||
|
|
* description: 图表类型
|
|||
|
|
* - in: query
|
|||
|
|
* name: startDate
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* format: date
|
|||
|
|
* description: 开始日期
|
|||
|
|
* - in: query
|
|||
|
|
* name: endDate
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* format: date
|
|||
|
|
* description: 结束日期
|
|||
|
|
* responses:
|
|||
|
|
* 200:
|
|||
|
|
* description: 获取操作日志图表数据成功
|
|||
|
|
* content:
|
|||
|
|
* application/json:
|
|||
|
|
* schema:
|
|||
|
|
* type: object
|
|||
|
|
* properties:
|
|||
|
|
* success:
|
|||
|
|
* type: boolean
|
|||
|
|
* data:
|
|||
|
|
* type: object
|
|||
|
|
* properties:
|
|||
|
|
* dates:
|
|||
|
|
* type: array
|
|||
|
|
* items:
|
|||
|
|
* type: string
|
|||
|
|
* series:
|
|||
|
|
* type: object
|
|||
|
|
* properties:
|
|||
|
|
* CREATE:
|
|||
|
|
* type: array
|
|||
|
|
* items:
|
|||
|
|
* type: integer
|
|||
|
|
* UPDATE:
|
|||
|
|
* type: array
|
|||
|
|
* items:
|
|||
|
|
* type: integer
|
|||
|
|
* DELETE:
|
|||
|
|
* type: array
|
|||
|
|
* items:
|
|||
|
|
* type: integer
|
|||
|
|
* message:
|
|||
|
|
* type: string
|
|||
|
|
* 500:
|
|||
|
|
* description: 服务器内部错误
|
|||
|
|
*/
|
|||
|
|
router.get('/stats/chart',
|
|||
|
|
auth,
|
|||
|
|
(req, res, next) => {
|
|||
|
|
if (!hasPermission(req.user.permissions, 'operation_log:view')) {
|
|||
|
|
return res.status(403).json({
|
|||
|
|
success: false,
|
|||
|
|
message: '权限不足,无法访问操作统计'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
next();
|
|||
|
|
},
|
|||
|
|
operationLogController.getOperationChartData
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @swagger
|
|||
|
|
* /api/operation-logs/clean:
|
|||
|
|
* post:
|
|||
|
|
* summary: 清理过期日志
|
|||
|
|
* tags: [OperationLogs]
|
|||
|
|
* security:
|
|||
|
|
* - bearerAuth: []
|
|||
|
|
* requestBody:
|
|||
|
|
* required: false
|
|||
|
|
* content:
|
|||
|
|
* application/json:
|
|||
|
|
* schema:
|
|||
|
|
* type: object
|
|||
|
|
* properties:
|
|||
|
|
* daysToKeep:
|
|||
|
|
* type: integer
|
|||
|
|
* default: 90
|
|||
|
|
* description: 保留天数
|
|||
|
|
* responses:
|
|||
|
|
* 200:
|
|||
|
|
* description: 清理过期日志成功
|
|||
|
|
* content:
|
|||
|
|
* application/json:
|
|||
|
|
* schema:
|
|||
|
|
* type: object
|
|||
|
|
* properties:
|
|||
|
|
* success:
|
|||
|
|
* type: boolean
|
|||
|
|
* data:
|
|||
|
|
* type: object
|
|||
|
|
* properties:
|
|||
|
|
* deletedCount:
|
|||
|
|
* type: integer
|
|||
|
|
* message:
|
|||
|
|
* type: string
|
|||
|
|
* 500:
|
|||
|
|
* description: 服务器内部错误
|
|||
|
|
*/
|
|||
|
|
router.post('/clean',
|
|||
|
|
auth,
|
|||
|
|
(req, res, next) => {
|
|||
|
|
if (!hasPermission(req.user.permissions, 'operation_log:view')) {
|
|||
|
|
return res.status(403).json({
|
|||
|
|
success: false,
|
|||
|
|
message: '权限不足,无法清理操作日志'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
next();
|
|||
|
|
},
|
|||
|
|
operationLogController.cleanExpiredLogs
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @swagger
|
|||
|
|
* /api/operation-logs/export:
|
|||
|
|
* get:
|
|||
|
|
* summary: 导出操作日志
|
|||
|
|
* tags: [OperationLogs]
|
|||
|
|
* security:
|
|||
|
|
* - bearerAuth: []
|
|||
|
|
* parameters:
|
|||
|
|
* - in: query
|
|||
|
|
* name: userId
|
|||
|
|
* schema:
|
|||
|
|
* type: integer
|
|||
|
|
* description: 用户ID
|
|||
|
|
* - in: query
|
|||
|
|
* name: username
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* description: 用户名
|
|||
|
|
* - in: query
|
|||
|
|
* name: operationType
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* enum: [CREATE, UPDATE, DELETE]
|
|||
|
|
* description: 操作类型
|
|||
|
|
* - in: query
|
|||
|
|
* name: moduleName
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* description: 模块名称
|
|||
|
|
* - in: query
|
|||
|
|
* name: tableName
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* description: 数据表名
|
|||
|
|
* - in: query
|
|||
|
|
* name: startDate
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* format: date
|
|||
|
|
* description: 开始日期
|
|||
|
|
* - in: query
|
|||
|
|
* name: endDate
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* format: date
|
|||
|
|
* description: 结束日期
|
|||
|
|
* responses:
|
|||
|
|
* 200:
|
|||
|
|
* description: 导出操作日志成功
|
|||
|
|
* content:
|
|||
|
|
* text/csv:
|
|||
|
|
* schema:
|
|||
|
|
* type: string
|
|||
|
|
* format: binary
|
|||
|
|
* 500:
|
|||
|
|
* description: 服务器内部错误
|
|||
|
|
*/
|
|||
|
|
router.get('/export',
|
|||
|
|
auth,
|
|||
|
|
(req, res, next) => {
|
|||
|
|
if (!hasPermission(req.user.permissions, 'operation_log:view')) {
|
|||
|
|
return res.status(403).json({
|
|||
|
|
success: false,
|
|||
|
|
message: '权限不足,无法导出操作日志'
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
next();
|
|||
|
|
},
|
|||
|
|
operationLogController.exportOperationLogs
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
module.exports = router;
|