using MediatR; using TakeoutSaaS.Application.App.Tenants.Dto; using TakeoutSaaS.Application.App.Tenants.Queries; using TakeoutSaaS.Application.App.Tenants.Targeting; using TakeoutSaaS.Application.Identity.Abstractions; using TakeoutSaaS.Domain.Tenants.Repositories; using TakeoutSaaS.Shared.Abstractions.Security; using TakeoutSaaS.Shared.Abstractions.Tenancy; namespace TakeoutSaaS.Application.App.Tenants.Handlers; /// /// 公告详情查询处理器。 /// public sealed class GetAnnouncementByIdQueryHandler( ITenantAnnouncementRepository announcementRepository, ITenantAnnouncementReadRepository readRepository, ITenantProvider tenantProvider, ICurrentUserAccessor? currentUserAccessor = null, IAdminAuthService? adminAuthService = null, IMiniAuthService? miniAuthService = null) : IRequestHandler { /// /// 查询公告详情。 /// /// 查询请求。 /// 取消标记。 /// 公告 DTO 或 null。 public async Task Handle(GetAnnouncementByIdQuery request, CancellationToken cancellationToken) { var tenantId = tenantProvider.GetCurrentTenantId(); // 1. 查询公告主体(含平台公告) var announcement = await announcementRepository.FindByIdInScopeAsync(tenantId, request.AnnouncementId, cancellationToken); if (announcement == null) { return null; } // 2. 目标受众过滤 var targetContext = await AnnouncementTargetContextFactory.BuildAsync( tenantProvider, currentUserAccessor, adminAuthService, miniAuthService, cancellationToken); if (!TargetTypeFilter.IsMatch(announcement, targetContext)) { return null; } // 3. 优先查用户级已读 var userId = targetContext.UserId; var reads = await readRepository.GetByAnnouncementAsync( tenantId, new[] { announcement.Id }, userId == 0 ? null : userId, cancellationToken); if (reads.Count == 0) { var tenantReads = await readRepository.GetByAnnouncementAsync(tenantId, new[] { announcement.Id }, null, cancellationToken); reads = tenantReads; } var readRecord = reads.FirstOrDefault(); return announcement.ToDto(readRecord != null, readRecord?.ReadAt); } }