feat: 添加操作日志、危险操作确认和业务关联功能
1. 新增操作日志记录功能,记录关键操作 2. 实现危险操作确认对话框,防止误删 3. 添加业务和库房管理模块 4. 支持设备标记为空闲状态 5. 完善API文档和健康检查 6. 优化前端删除操作的确认流程 7. 添加Swagger API文档支持 8. 实现设备与业务的关联功能 9. 改进设备模型,添加空闲相关字段 10. 优化用户、角色管理操作日志
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { logDangerousOperation, getDangerousOperationsLogs, cleanOldLogs, DANGEROUS_OPERATION_TYPES, RISK_LEVELS, calculateRiskLevel } = require('../utils/dangerousOperationLogger');
|
||||
|
||||
router.post('/log', async (req, res) => {
|
||||
try {
|
||||
const {
|
||||
operationType,
|
||||
operationName,
|
||||
targetType,
|
||||
targetId,
|
||||
targetName,
|
||||
beforeState,
|
||||
metadata = {},
|
||||
success = true,
|
||||
errorMessage = null,
|
||||
} = req.body;
|
||||
|
||||
if (!operationType || !operationName) {
|
||||
return res.status(400).json({ error: '缺少必需参数 operationType 或 operationName' });
|
||||
}
|
||||
|
||||
const riskLevel = metadata.riskLevel || calculateRiskLevel(operationType, metadata.itemCount || 1, {
|
||||
hasRelatedData: metadata.relatedDataCount > 0,
|
||||
isSystemLevel: metadata.isSystemLevel,
|
||||
});
|
||||
|
||||
await logDangerousOperation(req, {
|
||||
operationType,
|
||||
operationName,
|
||||
targetType,
|
||||
targetId,
|
||||
targetName,
|
||||
beforeState,
|
||||
metadata: {
|
||||
...metadata,
|
||||
riskLevel,
|
||||
},
|
||||
success,
|
||||
errorMessage,
|
||||
});
|
||||
|
||||
res.json({ success: true, riskLevel });
|
||||
} catch (error) {
|
||||
console.error('Failed to log dangerous operation:', error);
|
||||
res.status(500).json({ error: '日志记录失败' });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/logs', async (req, res) => {
|
||||
try {
|
||||
const { operationType, targetType, success, startDate, endDate, username, riskLevel, page = 1, pageSize = 50 } = req.query;
|
||||
|
||||
const filters = {
|
||||
operationType,
|
||||
targetType,
|
||||
success: success !== undefined ? success === 'true' : undefined,
|
||||
startDate,
|
||||
endDate,
|
||||
username,
|
||||
riskLevel,
|
||||
};
|
||||
|
||||
const allLogs = getDangerousOperationsLogs(filters);
|
||||
const total = allLogs.length;
|
||||
const startIndex = (parseInt(page) - 1) * parseInt(pageSize);
|
||||
const endIndex = startIndex + parseInt(pageSize);
|
||||
const logs = allLogs.slice(startIndex, endIndex);
|
||||
|
||||
res.json({
|
||||
logs,
|
||||
total,
|
||||
page: parseInt(page),
|
||||
pageSize: parseInt(pageSize),
|
||||
totalPages: Math.ceil(total / parseInt(pageSize)),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to get dangerous operations logs:', error);
|
||||
res.status(500).json({ error: '获取日志失败' });
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/logs/clean', async (req, res) => {
|
||||
try {
|
||||
const { daysToKeep = 90 } = req.query;
|
||||
|
||||
if (!req.user || req.user.role !== 'admin') {
|
||||
return res.status(403).json({ error: '只有管理员才能清理日志' });
|
||||
}
|
||||
|
||||
const result = await cleanOldLogs(parseInt(daysToKeep));
|
||||
|
||||
await logDangerousOperation(req, {
|
||||
operationType: DANGEROUS_OPERATION_TYPES.PURGE,
|
||||
operationName: '清理危险操作日志',
|
||||
targetType: 'operation_logs',
|
||||
targetId: null,
|
||||
targetName: `清理 ${daysToKeep} 天前的日志`,
|
||||
metadata: {
|
||||
riskLevel: RISK_LEVELS.MEDIUM,
|
||||
deletedCount: result.deletedCount,
|
||||
remainingCount: result.remainingCount,
|
||||
daysToKeep: parseInt(daysToKeep),
|
||||
},
|
||||
success: true,
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: `已清理 ${result.deletedCount} 条过期日志,保留 ${result.remainingCount} 条日志`,
|
||||
deletedCount: result.deletedCount,
|
||||
remainingCount: result.remainingCount,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to clean logs:', error);
|
||||
res.status(500).json({ error: '清理日志失败' });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/risk-assessment', async (req, res) => {
|
||||
try {
|
||||
const { operationType, itemCount, hasRelatedData, isSystemLevel } = req.query;
|
||||
|
||||
const riskLevel = calculateRiskLevel(
|
||||
operationType,
|
||||
parseInt(itemCount) || 1,
|
||||
{
|
||||
hasRelatedData: hasRelatedData === 'true',
|
||||
isSystemLevel: isSystemLevel === 'true',
|
||||
}
|
||||
);
|
||||
|
||||
const riskDescriptions = {
|
||||
[RISK_LEVELS.EXTREME]: '极高风险操作,需要输入确认关键词才能执行',
|
||||
[RISK_LEVELS.HIGH]: '高风险操作,需要详细确认信息',
|
||||
[RISK_LEVELS.MEDIUM]: '中等风险操作,需要明确确认',
|
||||
[RISK_LEVELS.LOW]: '低风险操作,使用标准确认即可',
|
||||
};
|
||||
|
||||
res.json({
|
||||
riskLevel,
|
||||
description: riskDescriptions[riskLevel],
|
||||
requiresKeyword: riskLevel === RISK_LEVELS.EXTREME,
|
||||
confirmationLevel: riskLevel === RISK_LEVELS.EXTREME ? 'KEYWORD' : riskLevel === RISK_LEVELS.HIGH ? 'ENHANCED' : 'STANDARD',
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to assess risk:', error);
|
||||
res.status(500).json({ error: '风险评估失败' });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user