feat: 新增操作日志功能并优化定时任务配置

1.  新增OperationLogAttribute与OperationLogActionFilter,实现自动化操作日志记录
2.  新增OperationLogRecordInput输入模型,重构IOperationLogService日志接口
3.  为所有业务控制器接口添加操作日志注解
4.  调整期刊AI批改任务的执行周期与方法适配异步调用
5.  优化Hangfire定时任务注册逻辑,支持异步任务
6.  补充完善操作日志类型与目标类型枚举
This commit is contained in:
glz
2026-07-09 18:01:37 +08:00
parent 4bb03aa0df
commit 766be485d0
25 changed files with 1001 additions and 92 deletions

View File

@ -98,11 +98,16 @@ public class CompensationManageService(
UserId = task.UserId
});
await operationLogService.LogAsync(
operatorId, operatorName,
OperationLogActionType.CompensationRetry,
OperationLogTargetType.CompensationTask,
taskId, null, detail, ipAddress);
await operationLogService.LogAsync(new OperationLogRecordInput
{
OperatorId = operatorId,
OperatorName = operatorName,
ActionType = OperationLogActionType.CompensationRetry,
TargetType = OperationLogTargetType.CompensationTask,
TargetId = taskId,
Detail = detail,
IpAddress = ipAddress
});
logger.LogInformation("补偿任务手动重试成功TaskId: {TaskId}", taskId);
}
@ -140,11 +145,16 @@ public class CompensationManageService(
UserId = task.UserId
});
await operationLogService.LogAsync(
operatorId, operatorName,
OperationLogActionType.CompensationResolve,
OperationLogTargetType.CompensationTask,
taskId, null, detail, ipAddress);
await operationLogService.LogAsync(new OperationLogRecordInput
{
OperatorId = operatorId,
OperatorName = operatorName,
ActionType = OperationLogActionType.CompensationResolve,
TargetType = OperationLogTargetType.CompensationTask,
TargetId = taskId,
Detail = detail,
IpAddress = ipAddress
});
logger.LogInformation("补偿任务标记已解决成功TaskId: {TaskId}", taskId);
}

View File

@ -24,23 +24,41 @@ public class OperationLogService(
/// 记录操作日志
/// </summary>
public async Task LogAsync(long operatorId, string operatorName, string actionType, string targetType, long targetId, string? targetName = null, string? detail = null, string? ipAddress = null)
{
await LogAsync(new OperationLogRecordInput
{
OperatorId = operatorId,
OperatorName = operatorName,
ActionType = actionType,
TargetType = targetType,
TargetId = targetId,
TargetName = targetName,
Detail = detail,
IpAddress = ipAddress
});
}
/// <summary>
/// 记录操作日志
/// </summary>
public async Task LogAsync(OperationLogRecordInput input)
{
try
{
var log = new OperationLog
{
OperatorId = operatorId,
OperatorName = operatorName,
ActionType = actionType,
TargetType = targetType,
TargetId = targetId,
TargetName = targetName,
Detail = detail,
IpAddress = ipAddress,
OperatorId = input.OperatorId,
OperatorName = input.OperatorName,
ActionType = input.ActionType,
TargetType = input.TargetType,
TargetId = input.TargetId,
TargetName = input.TargetName,
Detail = input.Detail,
IpAddress = input.IpAddress,
IsDeleted = false,
CreatedBy = operatorName,
CreatedBy = input.OperatorName,
CreatedAt = DateTime.Now,
UpdatedBy = operatorName,
UpdatedBy = input.OperatorName,
UpdatedAt = DateTime.Now
};
@ -48,12 +66,12 @@ public class OperationLogService(
logger.LogInformation(
"记录操作日志Operator: {Operator}, Action: {Action}, Target: {TargetType}/{TargetId}",
operatorName, actionType, targetType, targetId);
input.OperatorName, input.ActionType, input.TargetType, input.TargetId);
}
catch (Exception ex)
{
// 日志记录不应影响主业务流程
logger.LogError(ex, "记录操作日志失败Operator: {Operator}, Action: {Action}", operatorName, actionType);
logger.LogError(ex, "记录操作日志失败Operator: {Operator}, Action: {Action}", input.OperatorName, input.ActionType);
}
}

View File

@ -252,11 +252,17 @@ public class UsersService(
RecordId = result.RecordId
});
await operationLogService.LogAsync(
operatorId, operatorName,
OperationLogActionType.ManualAddPoints,
OperationLogTargetType.User,
userId, user.Name, detail, ipAddress);
await operationLogService.LogAsync(new OperationLogRecordInput
{
OperatorId = operatorId,
OperatorName = operatorName,
ActionType = OperationLogActionType.ManualAddPoints,
TargetType = OperationLogTargetType.User,
TargetId = userId,
TargetName = user.Name,
Detail = detail,
IpAddress = ipAddress
});
return new ManualPointsOutput
{
@ -302,11 +308,17 @@ public class UsersService(
RecordId = result.RecordId
});
await operationLogService.LogAsync(
operatorId, operatorName,
OperationLogActionType.ManualDeductPoints,
OperationLogTargetType.User,
userId, user.Name, detail, ipAddress);
await operationLogService.LogAsync(new OperationLogRecordInput
{
OperatorId = operatorId,
OperatorName = operatorName,
ActionType = OperationLogActionType.ManualDeductPoints,
TargetType = OperationLogTargetType.User,
TargetId = userId,
TargetName = user.Name,
Detail = detail,
IpAddress = ipAddress
});
return new ManualPointsOutput
{