using Microsoft.Extensions.Logging; using Newtonsoft.Json; using QYZH.InteractiveMagazine.IService; using QYZH.InteractiveMagazine.Models.Common; using QYZH.InteractiveMagazine.Models.Dto; using QYZH.InteractiveMagazine.Models.Dto.Compensation; using QYZH.InteractiveMagazine.Models.Entity; using QYZH.InteractiveMagazine.Models.Enum; using QYZH.InteractiveMagazine.Repository; using SqlSugar; namespace QYZH.InteractiveMagazine.Service; /// /// 补偿任务管理服务实现 /// public class CompensationManageService( BaseRepository compensationTaskRepository, IOperationLogService operationLogService, ILogger logger) : BaseRepository, ICompensationManageService { /// /// 分页查询补偿任务(含用户昵称) /// public async Task> GetListAsync(CompensationTaskQueryInput input) { if (input.PageIndex <= 0) input.PageIndex = 1; if (input.PageSize <= 0 || input.PageSize > 100) input.PageSize = 10; RefAsync totalNumber = 0; var pageResult = await compensationTaskRepository.Queryable() .LeftJoin((t, u) => t.UserId == u.Id) .WhereIF(input.UserId.HasValue, (t, u) => t.UserId == input.UserId.Value) .WhereIF(input.TaskType.HasValue, (t, u) => t.TaskType == (int)input.TaskType.Value) .WhereIF(input.Status.HasValue, (t, u) => t.Status == (int)input.Status) .WhereIF(!string.IsNullOrWhiteSpace(input.BusinessSource), (t, u) => t.BusinessSource == input.BusinessSource) .OrderByDescending((t, u) => t.CreatedAt) .Select((t, u) => new CompensationManageOutput { Id = t.Id, TaskType = (CompensationTaskTypeEnum)t.TaskType, BusinessSource = t.BusinessSource, BusinessId = t.BusinessId, UserId = t.UserId, UserName = u.Name, Payload = t.Payload, ErrorMessage = t.ErrorMessage, ErrorSource = t.ErrorSource, RetryCount = t.RetryCount, MaxRetries = t.MaxRetries, Status = (CompensationTaskStatusEnum)t.Status, ProcessedAt = t.ProcessedAt, ScheduledAt = t.ScheduledAt, ResultMessage = t.ResultMessage, CreatedAt = t.CreatedAt }) .ToPageListAsync(input.PageIndex, input.PageSize, totalNumber); return new PageListModel(pageResult, input.PageIndex, input.PageSize, totalNumber); } /// /// 手动重试补偿任务 /// public async Task RetryAsync(long taskId, long operatorId, string operatorName, CompensationRetryInput input, string? ipAddress = null) { logger.LogInformation("手动重试补偿任务,TaskId: {TaskId}, Operator: {Operator}", taskId, operatorName); var task = await compensationTaskRepository.GetByIdAsync(taskId); if (task == null) throw new BusinessException("补偿任务不存在", 404); if (task.Status != (int)CompensationTaskStatusEnum.Failed && task.Status != (int)CompensationTaskStatusEnum.Cancelled) throw new BusinessException($"只有失败或已取消的任务才能重试,当前状态: {task.Status}", 400); // 重置任务状态为 Pending,清零重试次数,设置立即执行 await compensationTaskRepository.Context.Updateable() .SetColumns(t => t.Status == (int)CompensationTaskStatusEnum.Pending) .SetColumns(t => t.RetryCount == 0) .SetColumns(t => t.ScheduledAt == DateTime.Now) .SetColumns(t => t.ResultMessage == $"管理员手动重试: {input.Reason}") .SetColumns(t => t.UpdatedBy == operatorName) .SetColumns(t => t.UpdatedAt == DateTime.Now) .Where(t => t.Id == taskId && !t.IsDeleted) .ExecuteCommandAsync(); // 记录操作日志 var detail = JsonConvert.SerializeObject(new { OriginalStatus = task.Status, Reason = input.Reason, TaskType = task.TaskType, UserId = task.UserId }); await operationLogService.LogAsync( operatorId, operatorName, OperationLogActionType.CompensationRetry, OperationLogTargetType.CompensationTask, taskId, null, detail, ipAddress); logger.LogInformation("补偿任务手动重试成功,TaskId: {TaskId}", taskId); } /// /// 标记补偿任务为已解决 /// public async Task ResolveAsync(long taskId, long operatorId, string operatorName, CompensationResolveInput input, string? ipAddress = null) { logger.LogInformation("标记补偿任务已解决,TaskId: {TaskId}, Operator: {Operator}", taskId, operatorName); var task = await compensationTaskRepository.GetByIdAsync(taskId); if (task == null) throw new BusinessException("补偿任务不存在", 404); if (task.Status == (int)CompensationTaskStatusEnum.Success) throw new BusinessException("该任务已经是成功状态,无需标记", 400); // 标记为 Success await compensationTaskRepository.Context.Updateable() .SetColumns(t => t.Status == (int)CompensationTaskStatusEnum.Success) .SetColumns(t => t.ResultMessage == $"管理员手动标记已解决: {input.ResolveNote}") .SetColumns(t => t.ProcessedAt == DateTime.Now) .SetColumns(t => t.UpdatedBy == operatorName) .SetColumns(t => t.UpdatedAt == DateTime.Now) .Where(t => t.Id == taskId && !t.IsDeleted) .ExecuteCommandAsync(); // 记录操作日志 var detail = JsonConvert.SerializeObject(new { OriginalStatus = task.Status, ResolveNote = input.ResolveNote, TaskType = task.TaskType, UserId = task.UserId }); await operationLogService.LogAsync( operatorId, operatorName, OperationLogActionType.CompensationResolve, OperationLogTargetType.CompensationTask, taskId, null, detail, ipAddress); logger.LogInformation("补偿任务标记已解决成功,TaskId: {TaskId}", taskId); } /// /// 获取补偿任务详情 /// public async Task GetDetailAsync(long taskId) { logger.LogInformation("获取补偿任务详情,TaskId: {TaskId}", taskId); var result = await compensationTaskRepository.Queryable() .LeftJoin((t, u) => t.UserId == u.Id) .Where((t, u) => t.Id == taskId && !t.IsDeleted) .Select((t, u) => new CompensationManageDetailOutput { Id = t.Id, TaskType = (CompensationTaskTypeEnum)t.TaskType, BusinessSource = t.BusinessSource, BusinessId = t.BusinessId, UserId = t.UserId, UserName = u.Name, Payload = t.Payload, ErrorMessage = t.ErrorMessage, ErrorSource = t.ErrorSource, RetryCount = t.RetryCount, MaxRetries = t.MaxRetries, Status = (CompensationTaskStatusEnum)t.Status, ProcessedAt = t.ProcessedAt, ScheduledAt = t.ScheduledAt, ResultMessage = t.ResultMessage, CreatedAt = t.CreatedAt, CreatedBy = t.CreatedBy, UpdatedBy = t.UpdatedBy, UpdatedAt = t.UpdatedAt }) .FirstAsync(); if (result == null) throw new BusinessException("补偿任务不存在", 404); return result; } }