feat: 租户账单公告通知接口

This commit is contained in:
2025-12-03 21:08:28 +08:00
parent 075906266a
commit 9fe7d9606d
47 changed files with 1522 additions and 4 deletions

View File

@@ -0,0 +1,45 @@
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Shared.Abstractions.Entities;
namespace TakeoutSaaS.Domain.Tenants.Entities;
/// <summary>
/// 租户公告。
/// </summary>
public sealed class TenantAnnouncement : MultiTenantEntityBase
{
/// <summary>
/// 公告标题。
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// 公告正文(可为 Markdown/HTML前端自行渲染
/// </summary>
public string Content { get; set; } = string.Empty;
/// <summary>
/// 公告类型。
/// </summary>
public TenantAnnouncementType AnnouncementType { get; set; } = TenantAnnouncementType.System;
/// <summary>
/// 展示优先级,数值越大越靠前。
/// </summary>
public int Priority { get; set; } = 0;
/// <summary>
/// 生效时间UTC
/// </summary>
public DateTime EffectiveFrom { get; set; } = DateTime.UtcNow;
/// <summary>
/// 失效时间UTC为空表示长期有效。
/// </summary>
public DateTime? EffectiveTo { get; set; }
/// <summary>
/// 是否启用。
/// </summary>
public bool IsActive { get; set; } = true;
}

View File

@@ -0,0 +1,24 @@
using TakeoutSaaS.Shared.Abstractions.Entities;
namespace TakeoutSaaS.Domain.Tenants.Entities;
/// <summary>
/// 租户公告已读记录。
/// </summary>
public sealed class TenantAnnouncementRead : MultiTenantEntityBase
{
/// <summary>
/// 公告 ID。
/// </summary>
public long AnnouncementId { get; set; }
/// <summary>
/// 已读用户 ID后台账号为空表示租户级已读。
/// </summary>
public long? UserId { get; set; }
/// <summary>
/// 已读时间。
/// </summary>
public DateTime ReadAt { get; set; } = DateTime.UtcNow;
}

View File

@@ -0,0 +1,22 @@
namespace TakeoutSaaS.Domain.Tenants.Enums;
/// <summary>
/// 租户公告类型。
/// </summary>
public enum TenantAnnouncementType
{
/// <summary>
/// 系统公告。
/// </summary>
System = 0,
/// <summary>
/// 账单/订阅相关提醒。
/// </summary>
Billing = 1,
/// <summary>
/// 运营通知。
/// </summary>
Operation = 2
}

View File

@@ -0,0 +1,20 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using TakeoutSaaS.Domain.Tenants.Entities;
namespace TakeoutSaaS.Domain.Tenants.Repositories;
/// <summary>
/// 公告已读仓储。
/// </summary>
public interface ITenantAnnouncementReadRepository
{
Task<IReadOnlyList<TenantAnnouncementRead>> GetByAnnouncementAsync(long tenantId, long announcementId, CancellationToken cancellationToken = default);
Task<TenantAnnouncementRead?> FindAsync(long tenantId, long announcementId, long? userId, CancellationToken cancellationToken = default);
Task AddAsync(TenantAnnouncementRead record, CancellationToken cancellationToken = default);
Task SaveChangesAsync(CancellationToken cancellationToken = default);
}

View File

@@ -0,0 +1,30 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
namespace TakeoutSaaS.Domain.Tenants.Repositories;
/// <summary>
/// 租户公告仓储。
/// </summary>
public interface ITenantAnnouncementRepository
{
Task<IReadOnlyList<TenantAnnouncement>> SearchAsync(
long tenantId,
TenantAnnouncementType? type,
bool? isActive,
DateTime? effectiveAt,
CancellationToken cancellationToken = default);
Task<TenantAnnouncement?> FindByIdAsync(long tenantId, long announcementId, CancellationToken cancellationToken = default);
Task AddAsync(TenantAnnouncement announcement, CancellationToken cancellationToken = default);
Task UpdateAsync(TenantAnnouncement announcement, CancellationToken cancellationToken = default);
Task DeleteAsync(long tenantId, long announcementId, CancellationToken cancellationToken = default);
Task SaveChangesAsync(CancellationToken cancellationToken = default);
}

View File

@@ -0,0 +1,30 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
namespace TakeoutSaaS.Domain.Tenants.Repositories;
/// <summary>
/// 租户账单仓储。
/// </summary>
public interface ITenantBillingRepository
{
Task<IReadOnlyList<TenantBillingStatement>> SearchAsync(
long tenantId,
TenantBillingStatus? status,
DateTime? from,
DateTime? to,
CancellationToken cancellationToken = default);
Task<TenantBillingStatement?> FindByIdAsync(long tenantId, long billingId, CancellationToken cancellationToken = default);
Task<TenantBillingStatement?> FindByStatementNoAsync(long tenantId, string statementNo, CancellationToken cancellationToken = default);
Task AddAsync(TenantBillingStatement bill, CancellationToken cancellationToken = default);
Task UpdateAsync(TenantBillingStatement bill, CancellationToken cancellationToken = default);
Task SaveChangesAsync(CancellationToken cancellationToken = default);
}

View File

@@ -0,0 +1,29 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
namespace TakeoutSaaS.Domain.Tenants.Repositories;
/// <summary>
/// 租户通知仓储。
/// </summary>
public interface ITenantNotificationRepository
{
Task<IReadOnlyList<TenantNotification>> SearchAsync(
long tenantId,
TenantNotificationSeverity? severity,
bool? unreadOnly,
DateTime? from,
DateTime? to,
CancellationToken cancellationToken = default);
Task<TenantNotification?> FindByIdAsync(long tenantId, long notificationId, CancellationToken cancellationToken = default);
Task AddAsync(TenantNotification notification, CancellationToken cancellationToken = default);
Task UpdateAsync(TenantNotification notification, CancellationToken cancellationToken = default);
Task SaveChangesAsync(CancellationToken cancellationToken = default);
}