182 lines
6.2 KiB
C#
182 lines
6.2 KiB
C#
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;
|
|
|
|
/// <summary>
|
|
/// EF 租户公告仓储。
|
|
/// </summary>
|
|
public sealed class EfTenantAnnouncementRepository(TakeoutAppDbContext context) : ITenantAnnouncementRepository
|
|
{
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<TenantAnnouncement>> 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);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<TenantAnnouncement?> 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);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public async Task<IReadOnlyList<TenantAnnouncement>> 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);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task<TenantAnnouncement?> FindByIdAsync(long tenantId, long announcementId, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.TenantAnnouncements.AsNoTracking()
|
|
.FirstOrDefaultAsync(x => x.TenantId == tenantId && x.Id == announcementId, cancellationToken);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task AddAsync(TenantAnnouncement announcement, CancellationToken cancellationToken = default)
|
|
{
|
|
return context.TenantAnnouncements.AddAsync(announcement, cancellationToken).AsTask();
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task UpdateAsync(TenantAnnouncement announcement, CancellationToken cancellationToken = default)
|
|
{
|
|
context.TenantAnnouncements.Update(announcement);
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
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);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
|
{
|
|
return context.SaveChangesAsync(cancellationToken);
|
|
}
|
|
}
|