using MediatR; using TakeoutSaaS.Application.App.Tenants.Commands; using TakeoutSaaS.Application.App.Tenants.Dto; using TakeoutSaaS.Application.Identity.Abstractions; 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.Security; namespace TakeoutSaaS.Application.App.Tenants.Handlers; /// /// 领取租户入驻审核处理器。 /// public sealed class ClaimTenantReviewCommandHandler( ITenantRepository tenantRepository, ICurrentUserAccessor currentUserAccessor, IAdminAuthService adminAuthService) : IRequestHandler { /// public async Task Handle(ClaimTenantReviewCommand request, CancellationToken cancellationToken) { // 1. 校验租户存在 var tenant = await tenantRepository.FindByIdAsync(request.TenantId, cancellationToken) ?? throw new BusinessException(ErrorCodes.NotFound, "租户不存在"); // 2. 查询是否已领取 var existingClaim = await tenantRepository.GetActiveReviewClaimAsync(request.TenantId, cancellationToken); if (existingClaim != null) { if (existingClaim.ClaimedBy == currentUserAccessor.UserId) { return existingClaim.ToDto(); } throw new BusinessException(ErrorCodes.Conflict, $"该审核已被 {existingClaim.ClaimedByName} 领取"); } // 3. (空行后) 获取当前用户显示名(用于展示快照) var profile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken); var displayName = string.IsNullOrWhiteSpace(profile.DisplayName) ? $"user:{currentUserAccessor.UserId}" : profile.DisplayName; // 4. (空行后) 构造领取记录与审计日志 var now = DateTime.UtcNow; var claim = new TenantReviewClaim { TenantId = request.TenantId, ClaimedBy = currentUserAccessor.UserId, ClaimedByName = displayName, ClaimedAt = now, ReleasedAt = null }; var auditLog = new TenantAuditLog { TenantId = tenant.Id, Action = TenantAuditAction.ReviewClaimed, Title = "领取审核", Description = $"领取人:{displayName}", OperatorId = currentUserAccessor.UserId, OperatorName = displayName, PreviousStatus = tenant.Status, CurrentStatus = tenant.Status }; // 5. (空行后) 写入领取记录(处理并发领取冲突) var success = await tenantRepository.TryAddReviewClaimAsync(claim, auditLog, cancellationToken); if (!success) { var current = await tenantRepository.GetActiveReviewClaimAsync(request.TenantId, cancellationToken); if (current == null) { throw new BusinessException(ErrorCodes.Conflict, "审核领取失败,请刷新后重试"); } if (current.ClaimedBy == currentUserAccessor.UserId) { return current.ToDto(); } throw new BusinessException(ErrorCodes.Conflict, $"该审核已被 {current.ClaimedByName} 领取"); } // 6. (空行后) 返回领取结果 return claim.ToDto(); } }