feat: 实现租户管理及套餐流程

This commit is contained in:
2025-12-03 16:37:50 +08:00
parent 151f64d41a
commit a536a554c2
34 changed files with 1732 additions and 2 deletions

View File

@@ -0,0 +1,50 @@
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Shared.Abstractions.Entities;
namespace TakeoutSaaS.Domain.Tenants.Entities;
/// <summary>
/// 租户运营审核日志。
/// </summary>
public sealed class TenantAuditLog : AuditableEntityBase
{
/// <summary>
/// 关联的租户标识。
/// </summary>
public long TenantId { get; set; }
/// <summary>
/// 操作类型。
/// </summary>
public TenantAuditAction Action { get; set; }
/// <summary>
/// 日志标题。
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// 详细描述。
/// </summary>
public string? Description { get; set; }
/// <summary>
/// 操作人 ID。
/// </summary>
public long? OperatorId { get; set; }
/// <summary>
/// 操作人名称。
/// </summary>
public string? OperatorName { get; set; }
/// <summary>
/// 原状态。
/// </summary>
public TenantStatus? PreviousStatus { get; set; }
/// <summary>
/// 新状态。
/// </summary>
public TenantStatus? CurrentStatus { get; set; }
}

View File

@@ -0,0 +1,60 @@
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Shared.Abstractions.Entities;
namespace TakeoutSaaS.Domain.Tenants.Entities;
/// <summary>
/// 租户套餐订阅变更记录。
/// </summary>
public sealed class TenantSubscriptionHistory : AuditableEntityBase
{
/// <summary>
/// 租户标识。
/// </summary>
public long TenantId { get; set; }
/// <summary>
/// 对应的订阅 ID。
/// </summary>
public long TenantSubscriptionId { get; set; }
/// <summary>
/// 原套餐 ID。
/// </summary>
public long FromPackageId { get; set; }
/// <summary>
/// 新套餐 ID。
/// </summary>
public long ToPackageId { get; set; }
/// <summary>
/// 变更类型。
/// </summary>
public SubscriptionChangeType ChangeType { get; set; }
/// <summary>
/// 生效时间。
/// </summary>
public DateTime EffectiveFrom { get; set; }
/// <summary>
/// 到期时间。
/// </summary>
public DateTime EffectiveTo { get; set; }
/// <summary>
/// 相关费用。
/// </summary>
public decimal? Amount { get; set; }
/// <summary>
/// 币种。
/// </summary>
public string? Currency { get; set; }
/// <summary>
/// 备注。
/// </summary>
public string? Notes { get; set; }
}

View File

@@ -0,0 +1,95 @@
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Shared.Abstractions.Entities;
namespace TakeoutSaaS.Domain.Tenants.Entities;
/// <summary>
/// 租户实名认证资料。
/// </summary>
public sealed class TenantVerificationProfile : AuditableEntityBase
{
/// <summary>
/// 对应的租户标识。
/// </summary>
public long TenantId { get; set; }
/// <summary>
/// 实名状态。
/// </summary>
public TenantVerificationStatus Status { get; set; } = TenantVerificationStatus.Draft;
/// <summary>
/// 营业执照编号。
/// </summary>
public string? BusinessLicenseNumber { get; set; }
/// <summary>
/// 营业执照文件地址。
/// </summary>
public string? BusinessLicenseUrl { get; set; }
/// <summary>
/// 法人姓名。
/// </summary>
public string? LegalPersonName { get; set; }
/// <summary>
/// 法人身份证号。
/// </summary>
public string? LegalPersonIdNumber { get; set; }
/// <summary>
/// 法人身份证正面。
/// </summary>
public string? LegalPersonIdFrontUrl { get; set; }
/// <summary>
/// 法人身份证反面。
/// </summary>
public string? LegalPersonIdBackUrl { get; set; }
/// <summary>
/// 开户名。
/// </summary>
public string? BankAccountName { get; set; }
/// <summary>
/// 银行账号。
/// </summary>
public string? BankAccountNumber { get; set; }
/// <summary>
/// 银行名称。
/// </summary>
public string? BankName { get; set; }
/// <summary>
/// 附加资料JSON
/// </summary>
public string? AdditionalDataJson { get; set; }
/// <summary>
/// 提交时间。
/// </summary>
public DateTime? SubmittedAt { get; set; }
/// <summary>
/// 审核时间。
/// </summary>
public DateTime? ReviewedAt { get; set; }
/// <summary>
/// 审核人 ID。
/// </summary>
public long? ReviewedBy { get; set; }
/// <summary>
/// 审核人姓名。
/// </summary>
public string? ReviewedByName { get; set; }
/// <summary>
/// 审核备注。
/// </summary>
public string? ReviewRemarks { get; set; }
}

View File

@@ -0,0 +1,27 @@
namespace TakeoutSaaS.Domain.Tenants.Enums;
/// <summary>
/// 套餐订阅的操作类型。
/// </summary>
public enum SubscriptionChangeType
{
/// <summary>
/// 新订阅。
/// </summary>
New = 0,
/// <summary>
/// 续费。
/// </summary>
Renew = 1,
/// <summary>
/// 升级套餐。
/// </summary>
Upgrade = 2,
/// <summary>
/// 降级套餐。
/// </summary>
Downgrade = 3
}

View File

@@ -0,0 +1,42 @@
namespace TakeoutSaaS.Domain.Tenants.Enums;
/// <summary>
/// 租户运营审核动作。
/// </summary>
public enum TenantAuditAction
{
/// <summary>
/// 注册信息提交。
/// </summary>
RegistrationSubmitted = 1,
/// <summary>
/// 实名资料提交或更新。
/// </summary>
VerificationSubmitted = 2,
/// <summary>
/// 实名审核通过。
/// </summary>
VerificationApproved = 3,
/// <summary>
/// 实名审核驳回。
/// </summary>
VerificationRejected = 4,
/// <summary>
/// 订阅创建或续费。
/// </summary>
SubscriptionUpdated = 5,
/// <summary>
/// 套餐升降配。
/// </summary>
SubscriptionPlanChanged = 6,
/// <summary>
/// 租户状态变更(启用/停用/到期等)。
/// </summary>
StatusChanged = 7
}

View File

@@ -0,0 +1,27 @@
namespace TakeoutSaaS.Domain.Tenants.Enums;
/// <summary>
/// 租户实名认证状态。
/// </summary>
public enum TenantVerificationStatus
{
/// <summary>
/// 草稿,未提交审核。
/// </summary>
Draft = 0,
/// <summary>
/// 已提交审核,等待运营处理。
/// </summary>
Pending = 1,
/// <summary>
/// 审核通过。
/// </summary>
Approved = 2,
/// <summary>
/// 审核驳回。
/// </summary>
Rejected = 3
}

View File

@@ -0,0 +1,95 @@
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 ITenantRepository
{
/// <summary>
/// 依据 ID 获取租户。
/// </summary>
Task<Tenant?> FindByIdAsync(long tenantId, CancellationToken cancellationToken = default);
/// <summary>
/// 按状态与关键词查询租户列表。
/// </summary>
Task<IReadOnlyList<Tenant>> SearchAsync(
TenantStatus? status,
string? keyword,
CancellationToken cancellationToken = default);
/// <summary>
/// 新增租户。
/// </summary>
Task AddTenantAsync(Tenant tenant, CancellationToken cancellationToken = default);
/// <summary>
/// 更新租户。
/// </summary>
Task UpdateTenantAsync(Tenant tenant, CancellationToken cancellationToken = default);
/// <summary>
/// 判断编码是否存在。
/// </summary>
Task<bool> ExistsByCodeAsync(string code, CancellationToken cancellationToken = default);
/// <summary>
/// 获取实名资料。
/// </summary>
Task<TenantVerificationProfile?> GetVerificationProfileAsync(long tenantId, CancellationToken cancellationToken = default);
/// <summary>
/// 新增或更新实名资料。
/// </summary>
Task UpsertVerificationProfileAsync(TenantVerificationProfile profile, CancellationToken cancellationToken = default);
/// <summary>
/// 获取当前订阅。
/// </summary>
Task<TenantSubscription?> GetActiveSubscriptionAsync(long tenantId, CancellationToken cancellationToken = default);
/// <summary>
/// 依据订阅 ID 查询。
/// </summary>
Task<TenantSubscription?> FindSubscriptionByIdAsync(long tenantId, long subscriptionId, CancellationToken cancellationToken = default);
/// <summary>
/// 新增订阅。
/// </summary>
Task AddSubscriptionAsync(TenantSubscription subscription, CancellationToken cancellationToken = default);
/// <summary>
/// 更新订阅。
/// </summary>
Task UpdateSubscriptionAsync(TenantSubscription subscription, CancellationToken cancellationToken = default);
/// <summary>
/// 记录订阅历史。
/// </summary>
Task AddSubscriptionHistoryAsync(TenantSubscriptionHistory history, CancellationToken cancellationToken = default);
/// <summary>
/// 获取订阅历史。
/// </summary>
Task<IReadOnlyList<TenantSubscriptionHistory>> GetSubscriptionHistoryAsync(long tenantId, CancellationToken cancellationToken = default);
/// <summary>
/// 新增审核日志。
/// </summary>
Task AddAuditLogAsync(TenantAuditLog log, CancellationToken cancellationToken = default);
/// <summary>
/// 查询审核日志。
/// </summary>
Task<IReadOnlyList<TenantAuditLog>> GetAuditLogsAsync(long tenantId, CancellationToken cancellationToken = default);
/// <summary>
/// 持久化。
/// </summary>
Task SaveChangesAsync(CancellationToken cancellationToken = default);
}