using Microsoft.EntityFrameworkCore; using TakeoutSaaS.Domain.Tenants.Entities; using TakeoutSaaS.Domain.Tenants.Enums; using TakeoutSaaS.Domain.Tenants.Repositories; using TakeoutSaaS.Infrastructure.App.Persistence; namespace TakeoutSaaS.Infrastructure.App.Repositories; /// /// EF 租户公告仓储。 /// public sealed class EfTenantAnnouncementRepository(TakeoutAppDbContext context) : ITenantAnnouncementRepository { /// public async Task> SearchAsync( long tenantId, string? keyword, AnnouncementStatus? status, TenantAnnouncementType? type, bool? isActive, DateTime? effectiveFrom, DateTime? effectiveTo, DateTime? effectiveAt, bool orderByPriority = false, int? limit = null, CancellationToken cancellationToken = default) { var tenantIds = new[] { tenantId, 0L }; var query = context.TenantAnnouncements.AsNoTracking() .IgnoreQueryFilters() .Where(x => tenantIds.Contains(x.TenantId)); if (!string.IsNullOrWhiteSpace(keyword)) { var normalized = keyword.Trim(); query = query.Where(x => EF.Functions.ILike(x.Title, $"%{normalized}%") || EF.Functions.ILike(x.Content, $"%{normalized}%")); } if (status.HasValue) { query = query.Where(x => x.Status == status.Value); } if (type.HasValue) { query = query.Where(x => x.AnnouncementType == type.Value); } if (isActive.HasValue) { query = isActive.Value ? query.Where(x => x.Status == AnnouncementStatus.Published) : query.Where(x => x.Status != AnnouncementStatus.Published); } if (effectiveFrom.HasValue) { query = query.Where(x => x.EffectiveFrom >= effectiveFrom.Value); } if (effectiveTo.HasValue) { query = query.Where(x => x.EffectiveTo == null || x.EffectiveTo <= effectiveTo.Value); } if (effectiveAt.HasValue) { var at = effectiveAt.Value; query = query.Where(x => x.EffectiveFrom <= at && (x.EffectiveTo == null || x.EffectiveTo >= at)); } // 应用排序(如果启用) if (orderByPriority) { query = query.OrderByDescending(x => x.Priority).ThenByDescending(x => x.EffectiveFrom); } // 应用限制(如果指定) if (limit.HasValue && limit.Value > 0) { query = query.Take(limit.Value); } return await query.ToListAsync(cancellationToken); } /// public Task FindByIdInScopeAsync(long tenantId, long announcementId, CancellationToken cancellationToken = default) { var tenantIds = new[] { tenantId, 0L }; return context.TenantAnnouncements.AsNoTracking() .IgnoreQueryFilters() .FirstOrDefaultAsync(x => tenantIds.Contains(x.TenantId) && x.Id == announcementId, cancellationToken); } /// public async Task> SearchUnreadAsync( long tenantId, long? userId, AnnouncementStatus? status, bool? isActive, DateTime? effectiveAt, CancellationToken cancellationToken = default) { var tenantIds = new[] { tenantId, 0L }; var announcementQuery = context.TenantAnnouncements.AsNoTracking() .IgnoreQueryFilters() .Where(x => tenantIds.Contains(x.TenantId)); if (status.HasValue) { announcementQuery = announcementQuery.Where(x => x.Status == status.Value); } if (isActive.HasValue) { announcementQuery = isActive.Value ? announcementQuery.Where(x => x.Status == AnnouncementStatus.Published) : announcementQuery.Where(x => x.Status != AnnouncementStatus.Published); } if (effectiveAt.HasValue) { var at = effectiveAt.Value; announcementQuery = announcementQuery.Where(x => x.EffectiveFrom <= at && (x.EffectiveTo == null || x.EffectiveTo >= at)); } var readQuery = context.TenantAnnouncementReads.AsNoTracking() .IgnoreQueryFilters() .Where(x => x.TenantId == tenantId); readQuery = userId.HasValue ? readQuery.Where(x => x.UserId == null || x.UserId == userId.Value) : readQuery.Where(x => x.UserId == null); var query = from announcement in announcementQuery join read in readQuery on announcement.Id equals read.AnnouncementId into readGroup where !readGroup.Any() select announcement; return await query.ToListAsync(cancellationToken); } /// public Task FindByIdAsync(long tenantId, long announcementId, CancellationToken cancellationToken = default) { return context.TenantAnnouncements.AsNoTracking() .FirstOrDefaultAsync(x => x.TenantId == tenantId && x.Id == announcementId, cancellationToken); } /// public Task AddAsync(TenantAnnouncement announcement, CancellationToken cancellationToken = default) { return context.TenantAnnouncements.AddAsync(announcement, cancellationToken).AsTask(); } /// public Task UpdateAsync(TenantAnnouncement announcement, CancellationToken cancellationToken = default) { context.TenantAnnouncements.Update(announcement); return Task.CompletedTask; } /// public async Task DeleteAsync(long tenantId, long announcementId, CancellationToken cancellationToken = default) { var entity = await context.TenantAnnouncements.FirstOrDefaultAsync(x => x.TenantId == tenantId && x.Id == announcementId, cancellationToken); if (entity != null) { context.TenantAnnouncements.Remove(entity); } } /// public Task SaveChangesAsync(CancellationToken cancellationToken = default) { return context.SaveChangesAsync(cancellationToken); } }