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);
}
}