using MediatR; using Microsoft.Extensions.Logging; using TakeoutSaaS.Application.App.Tenants.Commands; using TakeoutSaaS.Application.App.Tenants.Contracts; using TakeoutSaaS.Domain.Identity.Repositories; using TakeoutSaaS.Domain.Tenants.Entities; using TakeoutSaaS.Domain.Tenants.Enums; using TakeoutSaaS.Domain.Tenants.Repositories; using TakeoutSaaS.Shared.Abstractions.Constants; using TakeoutSaaS.Shared.Abstractions.Exceptions; using TakeoutSaaS.Shared.Abstractions.Ids; using TakeoutSaaS.Shared.Abstractions.Security; namespace TakeoutSaaS.Application.App.Tenants.Handlers; /// /// 领取租户审核命令处理器。 /// public sealed class ClaimTenantReviewCommandHandler( ITenantRepository tenantRepository, IIdentityUserRepository identityUserRepository, ICurrentUserAccessor currentUserAccessor, IIdGenerator idGenerator, ILogger logger) : IRequestHandler { /// public async Task Handle(ClaimTenantReviewCommand request, CancellationToken cancellationToken) { // 1. 校验租户是否存在 var tenant = await tenantRepository.FindByIdAsync(request.TenantId, cancellationToken); if (tenant is null) { throw new BusinessException(ErrorCodes.NotFound, "租户不存在"); } // 2. 校验租户状态(只有待审核状态才能领取) if (tenant.Status != TenantStatus.PendingReview) { throw new BusinessException(ErrorCodes.BadRequest, "租户不在待审核状态,无法领取审核"); } // 3. 检查是否已被领取 var existingClaim = await tenantRepository.GetActiveReviewClaimAsync(request.TenantId, cancellationToken); if (existingClaim is not null) { // 4. 如果是自己领取的,直接返回 if (existingClaim.ClaimedBy == currentUserAccessor.UserId) { return ToDto(existingClaim); } // 5. 已被他人领取 throw new BusinessException(ErrorCodes.Conflict, $"该审核已被 {existingClaim.ClaimedByName} 领取"); } // 6. 创建新的领取记录 var now = DateTime.UtcNow; // 7. 查询当前用户的显示名称 var actorName = "system"; if (currentUserAccessor.IsAuthenticated && currentUserAccessor.UserId != 0) { var user = await identityUserRepository.FindByIdAsync(currentUserAccessor.UserId, cancellationToken); actorName = user?.DisplayName ?? $"用户{currentUserAccessor.UserId}"; } var claim = new TenantReviewClaim { Id = idGenerator.NextId(), TenantId = request.TenantId, ClaimedBy = currentUserAccessor.UserId, ClaimedByName = actorName, ClaimedAt = now }; // 8. 保存领取记录 await tenantRepository.AddReviewClaimAsync(claim, cancellationToken); // 9. 添加审核日志 await tenantRepository.AddAuditLogAsync(new TenantAuditLog { Id = idGenerator.NextId(), TenantId = request.TenantId, Action = TenantAuditAction.ReviewClaimed, Title = "领取审核", Description = $"领取人:{actorName}", OperatorId = currentUserAccessor.UserId, OperatorName = actorName, CurrentStatus = tenant.Status }, cancellationToken); // 10. 保存变更 await tenantRepository.SaveChangesAsync(cancellationToken); logger.LogInformation("租户 {TenantId} 审核已被 {UserId} 领取", request.TenantId, currentUserAccessor.UserId); return ToDto(claim); } private static TenantReviewClaimDto ToDto(TenantReviewClaim claim) => new() { Id = claim.Id, TenantId = claim.TenantId, ClaimedBy = claim.ClaimedBy, ClaimedByName = claim.ClaimedByName, ClaimedAt = claim.ClaimedAt }; }