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.CheckIn; using QYZH.InteractiveMagazine.Models.Dto.Compensation; using QYZH.InteractiveMagazine.Models.Dto.Points; using QYZH.InteractiveMagazine.Models.Entity; using QYZH.InteractiveMagazine.Models.Enum; using QYZH.InteractiveMagazine.Repository; using SqlSugar; namespace QYZH.InteractiveMagazine.Service; public class UsersService( BaseRepository usersRepository, ILogger _logger, IPointsService pointsService, ICheckInService checkInService, ICompensationTaskService compensationTaskService, IUserJournalService userJournalService, IOperationLogService operationLogService) : BaseRepository, IUsersService { /// /// 分页查询用户列表 /// public async Task>> GetListAsync(UsersQueryInput input) { var page = Queryable() .WhereIF(!string.IsNullOrEmpty(input.WxUserId), u => u.OpenId == input.WxUserId) .OrderBy(u => u.Id, OrderByType.Desc) .ToPage(input); return BaseResponse>.Success(page); } /// /// 获取用户详情(包含积分记录、签到记录、补偿任务、期刊列表) /// public async Task> GetDetailAsync(long id) { var user = await GetByIdAsync(u => u.Id == id); if (user == null) { return BaseResponse.Fail("用户不存在"); } // 并行查询关联数据 var pointsTask = GetPointsRecordsAsync(id); var checkInTask = GetCheckInRecordsAsync(id); var compensationTask = GetFailedCompensationTasksAsync(id); var journalsTask = GetUserJournalsWithDetailAsync(id); await Task.WhenAll(pointsTask, checkInTask, compensationTask, journalsTask); return BaseResponse.Success(new UserDetailOutput { BasicInfo = user, PointsRecords = await pointsTask, CheckInRecords = await checkInTask, FailedCompensationTasks = await compensationTask, Journals = await journalsTask }); } /// /// 获取用户积分记录(最近20条) /// private async Task> GetPointsRecordsAsync(long userId) { try { var result = await pointsService.GetPointsRecordsAsync(new PointsRecordQueryInput { UserId = userId, PageIndex = 1, PageSize = 20 }); return result.Result ?? []; } catch (Exception ex) { _logger.LogWarning(ex, "获取用户积分记录失败,UserId: {UserId}", userId); return []; } } /// /// 获取用户签到记录 /// private async Task> GetCheckInRecordsAsync(long userId) { try { var info = await checkInService.GetCheckInInfoAsync(userId); return info.RecentRecords ?? []; } catch (Exception ex) { _logger.LogWarning(ex, "获取用户签到记录失败,UserId: {UserId}", userId); return []; } } /// /// 获取用户失败的补偿任务(需要手动处理) /// private async Task> GetFailedCompensationTasksAsync(long userId) { try { var tasks = await compensationTaskService.GetTasksAsync(new GetCompensationTasksInput { Status = CompensationTaskStatusEnum.Failed, Limit = 50 }); return tasks.Where(t => t.UserId == userId).ToList(); } catch (Exception ex) { _logger.LogWarning(ex, "获取用户失败补偿任务失败,UserId: {UserId}", userId); return []; } } /// /// 获取用户拥有的期刊列表(含期刊详情) /// private async Task> GetUserJournalsWithDetailAsync(long userId) { try { var userJournals = await Context.Queryable() .Where(uj => uj.UserId == userId && !uj.IsDeleted) .OrderByDescending(uj => uj.CreatedAt) .ToListAsync(); var result = new List(); foreach (var uj in userJournals) { var journal = await Context.Queryable() .Where(j => j.Id == uj.JournalId && !j.IsDeleted) .FirstAsync(); if (journal != null) { result.Add(new UserJournalItemOutput { BindId = uj.Id, JournalId = uj.JournalId, JournalTitle = journal.Title, CoverImageUrl = journal.CoverImageUrl, Type = uj.Type.ToString(), Status = uj.Status.ToString(), CreatedAt = uj.CreatedAt }); } } return result; } catch (Exception ex) { _logger.LogWarning(ex, "获取用户期刊列表失败,UserId: {UserId}", userId); return []; } } /// /// 更新用户状态 /// public async Task UpdateStatusAsync(long id, UpdateUserStatusInput input) { var exists = await Queryable().AnyAsync(u => u.Id == id); if (!exists) { return BaseResponse.Fail("用户不存在"); } var statusValue = input.Status == 1 ? UserStatusEnum.Active : UserStatusEnum.Disabled; var result = await UpdateAsync( u => new Users { Status = statusValue }, u => u.Id == id ); return result ? BaseResponse.Success() : BaseResponse.Fail("更新失败"); } /// /// 手动增加用户积分 /// public async Task ManualAddPointsAsync(long userId, ManualAddPointsInput input, long operatorId, string operatorName, string? ipAddress = null) { _logger.LogInformation("管理员手动增加积分,UserId: {UserId}, Amount: {Amount}, Operator: {Operator}", userId, input.Amount, operatorName); // 校验用户是否存在 var user = await Queryable().Where(u => u.Id == userId && !u.IsDeleted).FirstAsync(); if (user == null) throw new BusinessException("用户不存在", 404); // 调用积分服务增加积分 var result = await pointsService.AddPointsAsync(new AddPointsInput { UserId = userId, Amount = input.Amount, ChangeType = PointsChangeTypeEnum.ManualAdjust, Description = $"管理员手动增加: {input.Reason}", OperatorName = operatorName }); // 记录操作日志 var detail = JsonConvert.SerializeObject(new { Amount = input.Amount, Reason = input.Reason, PreviousBalance = result.PreviousBalance, NewBalance = result.NewBalance, RecordId = result.RecordId }); await operationLogService.LogAsync( operatorId, operatorName, OperationLogActionType.ManualAddPoints, OperationLogTargetType.User, userId, user.Name, detail, ipAddress); return new ManualPointsOutput { RecordId = result.RecordId, PreviousBalance = result.PreviousBalance, NewBalance = result.NewBalance, ChangeAmount = input.Amount, OperatorName = operatorName, OperatedAt = DateTime.Now }; } /// /// 手动扣除用户积分 /// public async Task ManualDeductPointsAsync(long userId, ManualDeductPointsInput input, long operatorId, string operatorName, string? ipAddress = null) { _logger.LogInformation("管理员手动扣除积分,UserId: {UserId}, Amount: {Amount}, Operator: {Operator}", userId, input.Amount, operatorName); // 校验用户是否存在 var user = await Queryable().Where(u => u.Id == userId && !u.IsDeleted).FirstAsync(); if (user == null) throw new BusinessException("用户不存在", 404); // 调用积分服务扣除积分 var result = await pointsService.DeductPointsAsync(new DeductPointsInput { UserId = userId, Amount = input.Amount, ChangeType = PointsChangeTypeEnum.ManualAdjust, Description = $"管理员手动扣除: {input.Reason}", OperatorName = operatorName }); // 记录操作日志 var detail = JsonConvert.SerializeObject(new { Amount = input.Amount, Reason = input.Reason, PreviousBalance = result.PreviousBalance, NewBalance = result.NewBalance, RecordId = result.RecordId }); await operationLogService.LogAsync( operatorId, operatorName, OperationLogActionType.ManualDeductPoints, OperationLogTargetType.User, userId, user.Name, detail, ipAddress); return new ManualPointsOutput { RecordId = result.RecordId, PreviousBalance = result.PreviousBalance, NewBalance = result.NewBalance, ChangeAmount = -input.Amount, OperatorName = operatorName, OperatedAt = DateTime.Now }; } }