refactor: 管理端去租户过滤并Portal化RBAC菜单

This commit is contained in:
2026-01-29 10:46:49 +00:00
parent ea9c20d8a9
commit b3639ff34b
115 changed files with 1106 additions and 1092 deletions

View File

@@ -4,10 +4,20 @@ using TakeoutSaaS.Shared.Abstractions.Entities;
namespace TakeoutSaaS.Domain.Identity.Entities;
/// <summary>
/// 管理后台账户实体(平台管理员租户管理员或商户员工)。
/// 后台账户实体(按 Portal 区分平台管理员租户后台账号)。
/// </summary>
public sealed class IdentityUser : MultiTenantEntityBase
public sealed class IdentityUser : AuditableEntityBase
{
/// <summary>
/// 账号所属 Portal。
/// </summary>
public PortalType Portal { get; set; }
/// <summary>
/// 所属租户 IDPortal=Tenant 时必填Portal=Admin 时必须为空)。
/// </summary>
public long? TenantId { get; set; }
/// <summary>
/// 登录账号。
/// </summary>

View File

@@ -1,12 +1,18 @@
using TakeoutSaaS.Domain.Identity.Enums;
using TakeoutSaaS.Shared.Abstractions.Entities;
namespace TakeoutSaaS.Domain.Identity.Entities;
/// <summary>
/// 管理端菜单定义。
/// 后台菜单定义(按 Portal 区分 Admin/Tenant 两套菜单树)
/// </summary>
public sealed class MenuDefinition : MultiTenantEntityBase
public sealed class MenuDefinition : AuditableEntityBase
{
/// <summary>
/// 菜单所属 Portal。
/// </summary>
public PortalType Portal { get; set; }
/// <summary>
/// 父级菜单 ID根节点为 0。
/// </summary>

View File

@@ -1,3 +1,4 @@
using TakeoutSaaS.Domain.Identity.Enums;
using TakeoutSaaS.Shared.Abstractions.Entities;
namespace TakeoutSaaS.Domain.Identity.Entities;
@@ -5,8 +6,13 @@ namespace TakeoutSaaS.Domain.Identity.Entities;
/// <summary>
/// 权限定义。
/// </summary>
public sealed class Permission : MultiTenantEntityBase
public sealed class Permission : AuditableEntityBase
{
/// <summary>
/// 权限所属 Portal。
/// </summary>
public PortalType Portal { get; set; }
/// <summary>
/// 父级权限 ID根节点为 0。
/// </summary>

View File

@@ -1,3 +1,4 @@
using TakeoutSaaS.Domain.Identity.Enums;
using TakeoutSaaS.Shared.Abstractions.Entities;
namespace TakeoutSaaS.Domain.Identity.Entities;
@@ -5,8 +6,18 @@ namespace TakeoutSaaS.Domain.Identity.Entities;
/// <summary>
/// 角色定义。
/// </summary>
public sealed class Role : MultiTenantEntityBase
public sealed class Role : AuditableEntityBase
{
/// <summary>
/// 角色所属 Portal。
/// </summary>
public PortalType Portal { get; set; }
/// <summary>
/// 所属租户 IDPortal=Tenant 时必填Portal=Admin 时必须为空)。
/// </summary>
public long? TenantId { get; set; }
/// <summary>
/// 角色名称。
/// </summary>

View File

@@ -1,3 +1,4 @@
using TakeoutSaaS.Domain.Identity.Enums;
using TakeoutSaaS.Shared.Abstractions.Entities;
namespace TakeoutSaaS.Domain.Identity.Entities;
@@ -5,8 +6,18 @@ namespace TakeoutSaaS.Domain.Identity.Entities;
/// <summary>
/// 角色-权限关系。
/// </summary>
public sealed class RolePermission : MultiTenantEntityBase
public sealed class RolePermission : AuditableEntityBase
{
/// <summary>
/// 关系所属 Portal。
/// </summary>
public PortalType Portal { get; set; }
/// <summary>
/// 所属租户 IDPortal=Tenant 时必填Portal=Admin 时必须为空)。
/// </summary>
public long? TenantId { get; set; }
/// <summary>
/// 角色 ID。
/// </summary>

View File

@@ -1,3 +1,4 @@
using TakeoutSaaS.Domain.Identity.Enums;
using TakeoutSaaS.Shared.Abstractions.Entities;
namespace TakeoutSaaS.Domain.Identity.Entities;
@@ -5,8 +6,18 @@ namespace TakeoutSaaS.Domain.Identity.Entities;
/// <summary>
/// 用户-角色关系。
/// </summary>
public sealed class UserRole : MultiTenantEntityBase
public sealed class UserRole : AuditableEntityBase
{
/// <summary>
/// 关系所属 Portal。
/// </summary>
public PortalType Portal { get; set; }
/// <summary>
/// 所属租户 IDPortal=Tenant 时必填Portal=Admin 时必须为空)。
/// </summary>
public long? TenantId { get; set; }
/// <summary>
/// 用户 ID。
/// </summary>

View File

@@ -0,0 +1,18 @@
namespace TakeoutSaaS.Domain.Identity.Enums;
/// <summary>
/// 后台端类型(用于区分平台管理端与租户管理端)。
/// </summary>
public enum PortalType
{
/// <summary>
/// 平台管理端Admin
/// </summary>
Admin = 0,
/// <summary>
/// 租户管理端Tenant
/// </summary>
Tenant = 1
}

View File

@@ -74,14 +74,6 @@ public interface IIdentityUserRepository
/// <returns>后台用户或 null。</returns>
Task<IdentityUser?> FindByIdAsync(long userId, CancellationToken cancellationToken = default);
/// <summary>
/// 根据 ID 获取后台用户(忽略租户过滤器,仅用于只读查询)。
/// </summary>
/// <param name="userId">用户 ID。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>后台用户或 null。</returns>
Task<IdentityUser?> FindByIdIgnoringTenantAsync(long userId, CancellationToken cancellationToken = default);
/// <summary>
/// 根据 ID 获取后台用户(用于更新,返回可跟踪实体)。
/// </summary>
@@ -90,28 +82,13 @@ public interface IIdentityUserRepository
/// <returns>后台用户或 null。</returns>
Task<IdentityUser?> GetForUpdateAsync(long userId, CancellationToken cancellationToken = default);
/// <summary>
/// 根据 ID 获取后台用户(用于更新,忽略租户过滤器)。
/// </summary>
/// <remarks>用于跨租户场景(如平台生成的重置密码链接)。</remarks>
/// <param name="userId">用户 ID。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>后台用户或 null。</returns>
Task<IdentityUser?> GetForUpdateIgnoringTenantAsync(long userId, CancellationToken cancellationToken = default);
/// <summary>
/// 根据 ID 获取后台用户(用于更新,包含已删除数据)。
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="userId">用户 ID。</param>
/// <param name="ignoreTenantFilter">是否忽略租户过滤。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>后台用户或 null。</returns>
Task<IdentityUser?> GetForUpdateIncludingDeletedAsync(
long tenantId,
long userId,
bool ignoreTenantFilter = false,
CancellationToken cancellationToken = default);
Task<IdentityUser?> GetForUpdateIncludingDeletedAsync(long userId, CancellationToken cancellationToken = default);
/// <summary>
/// 按租户与关键字查询后台用户列表(仅读)。
@@ -126,12 +103,10 @@ public interface IIdentityUserRepository
/// 分页查询后台用户列表。
/// </summary>
/// <param name="filter">查询过滤条件。</param>
/// <param name="ignoreTenantFilter">是否忽略租户过滤器。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>分页结果。</returns>
Task<(IReadOnlyList<IdentityUser> Items, int Total)> SearchPagedAsync(
IdentityUserSearchFilter filter,
bool ignoreTenantFilter = false,
CancellationToken cancellationToken = default);
/// <summary>
@@ -149,14 +124,12 @@ public interface IIdentityUserRepository
/// <param name="tenantId">租户 ID。</param>
/// <param name="userIds">用户 ID 集合。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
/// <param name="ignoreTenantFilter">是否忽略租户过滤器。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>后台用户列表。</returns>
Task<IReadOnlyList<IdentityUser>> GetForUpdateByIdsAsync(
long tenantId,
IEnumerable<long> userIds,
bool includeDeleted,
bool ignoreTenantFilter = false,
CancellationToken cancellationToken = default);
/// <summary>

View File

@@ -1,4 +1,5 @@
using TakeoutSaaS.Domain.Identity.Entities;
using TakeoutSaaS.Domain.Identity.Enums;
namespace TakeoutSaaS.Domain.Identity.Repositories;
@@ -8,14 +9,19 @@ namespace TakeoutSaaS.Domain.Identity.Repositories;
public interface IMenuRepository
{
/// <summary>
/// 按租户获取菜单列表。
/// 按 Portal 获取菜单列表。
/// </summary>
Task<IReadOnlyList<MenuDefinition>> GetByTenantAsync(long tenantId, CancellationToken cancellationToken = default);
/// <param name="portal">Portal 类型。</param>
/// <param name="cancellationToken">取消标记。</param>
Task<IReadOnlyList<MenuDefinition>> GetByPortalAsync(PortalType portal, CancellationToken cancellationToken = default);
/// <summary>
/// 根据 ID 查询菜单。
/// </summary>
Task<MenuDefinition?> FindByIdAsync(long id, long tenantId, CancellationToken cancellationToken = default);
/// <param name="id">菜单 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="cancellationToken">取消标记。</param>
Task<MenuDefinition?> FindByIdAsync(long id, PortalType portal, CancellationToken cancellationToken = default);
/// <summary>
/// 新增菜单。
@@ -30,7 +36,10 @@ public interface IMenuRepository
/// <summary>
/// 删除菜单。
/// </summary>
Task DeleteAsync(long id, long tenantId, CancellationToken cancellationToken = default);
/// <param name="id">菜单 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="cancellationToken">取消标记。</param>
Task DeleteAsync(long id, PortalType portal, CancellationToken cancellationToken = default);
/// <summary>
/// 持久化变更。

View File

@@ -1,9 +1,10 @@
using TakeoutSaaS.Domain.Identity.Enums;
using TakeoutSaaS.Domain.Identity.Entities;
namespace TakeoutSaaS.Domain.Identity.Repositories;
/// <summary>
/// 权限仓储。
/// 权限仓储(全局权限定义,按 Portal 区分)
/// </summary>
public interface IPermissionRepository
{
@@ -11,46 +12,42 @@ public interface IPermissionRepository
/// 根据 ID 查询权限。
/// </summary>
/// <param name="permissionId">权限 ID。</param>
/// <param name="tenantId">租户 ID。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>权限实体或 null。</returns>
Task<Permission?> FindByIdAsync(long permissionId, long tenantId, CancellationToken cancellationToken = default);
Task<Permission?> FindByIdAsync(long permissionId, CancellationToken cancellationToken = default);
/// <summary>
/// 根据编码查询权限。
/// </summary>
/// <param name="code">权限编码。</param>
/// <param name="tenantId">租户 ID。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>权限实体或 null。</returns>
Task<Permission?> FindByCodeAsync(string code, long tenantId, CancellationToken cancellationToken = default);
Task<Permission?> FindByCodeAsync(string code, CancellationToken cancellationToken = default);
/// <summary>
/// 根据编码集合查询权限列表。
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="codes">权限编码集合。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>权限集合。</returns>
Task<IReadOnlyList<Permission>> GetByCodesAsync(long tenantId, IEnumerable<string> codes, CancellationToken cancellationToken = default);
Task<IReadOnlyList<Permission>> GetByCodesAsync(IEnumerable<string> codes, CancellationToken cancellationToken = default);
/// <summary>
/// 根据 ID 集合查询权限列表。
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="permissionIds">权限 ID 集合。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>权限集合。</returns>
Task<IReadOnlyList<Permission>> GetByIdsAsync(long tenantId, IEnumerable<long> permissionIds, CancellationToken cancellationToken = default);
Task<IReadOnlyList<Permission>> GetByIdsAsync(IEnumerable<long> permissionIds, CancellationToken cancellationToken = default);
/// <summary>
/// 按关键字搜索权限。
/// 按 Portal 与关键字搜索权限。
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="keyword">关键字。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>权限集合。</returns>
Task<IReadOnlyList<Permission>> SearchAsync(long tenantId, string? keyword, CancellationToken cancellationToken = default);
Task<IReadOnlyList<Permission>> SearchAsync(PortalType portal, string? keyword, CancellationToken cancellationToken = default);
/// <summary>
/// 新增权限。
@@ -72,10 +69,9 @@ public interface IPermissionRepository
/// 删除权限。
/// </summary>
/// <param name="permissionId">权限 ID。</param>
/// <param name="tenantId">租户 ID。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>异步操作任务。</returns>
Task DeleteAsync(long permissionId, long tenantId, CancellationToken cancellationToken = default);
Task DeleteAsync(long permissionId, CancellationToken cancellationToken = default);
/// <summary>
/// 保存仓储变更。

View File

@@ -1,4 +1,5 @@
using TakeoutSaaS.Domain.Identity.Entities;
using TakeoutSaaS.Domain.Identity.Enums;
namespace TakeoutSaaS.Domain.Identity.Repositories;
@@ -10,11 +11,16 @@ public interface IRolePermissionRepository
/// <summary>
/// 根据角色 ID 集合获取角色权限关系。
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="tenantId">租户 IDPortal=Tenant 必填Portal=Admin 必须为空)。</param>
/// <param name="roleIds">角色 ID 集合。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>角色权限关系列表。</returns>
Task<IReadOnlyList<RolePermission>> GetByRoleIdsAsync(long tenantId, IEnumerable<long> roleIds, CancellationToken cancellationToken = default);
Task<IReadOnlyList<RolePermission>> GetByRoleIdsAsync(
PortalType portal,
long? tenantId,
IEnumerable<long> roleIds,
CancellationToken cancellationToken = default);
/// <summary>
/// 批量新增角色权限关系。
@@ -27,12 +33,18 @@ public interface IRolePermissionRepository
/// <summary>
/// 替换角色的权限集合。
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="tenantId">租户 IDPortal=Tenant 必填Portal=Admin 必须为空)。</param>
/// <param name="roleId">角色 ID。</param>
/// <param name="permissionIds">权限 ID 集合。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>异步操作任务。</returns>
Task ReplaceRolePermissionsAsync(long tenantId, long roleId, IEnumerable<long> permissionIds, CancellationToken cancellationToken = default);
Task ReplaceRolePermissionsAsync(
PortalType portal,
long? tenantId,
long roleId,
IEnumerable<long> permissionIds,
CancellationToken cancellationToken = default);
/// <summary>
/// 提交持久化变更。

View File

@@ -1,4 +1,5 @@
using TakeoutSaaS.Domain.Identity.Entities;
using TakeoutSaaS.Domain.Identity.Enums;
namespace TakeoutSaaS.Domain.Identity.Repositories;
@@ -11,37 +12,45 @@ public interface IRoleRepository
/// 根据 ID 查询角色。
/// </summary>
/// <param name="roleId">角色 ID。</param>
/// <param name="tenantId">租户 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="tenantId">租户 IDPortal=Tenant 必填Portal=Admin 必须为空)。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>角色实体或 null。</returns>
Task<Role?> FindByIdAsync(long roleId, long tenantId, CancellationToken cancellationToken = default);
Task<Role?> FindByIdAsync(PortalType portal, long? tenantId, long roleId, CancellationToken cancellationToken = default);
/// <summary>
/// 根据编码查询角色。
/// </summary>
/// <param name="code">角色编码。</param>
/// <param name="tenantId">租户 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="tenantId">租户 IDPortal=Tenant 必填Portal=Admin 必须为空)。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>角色实体或 null。</returns>
Task<Role?> FindByCodeAsync(string code, long tenantId, CancellationToken cancellationToken = default);
Task<Role?> FindByCodeAsync(PortalType portal, long? tenantId, string code, CancellationToken cancellationToken = default);
/// <summary>
/// 批量获取角色列表。
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="tenantId">租户 IDPortal=Tenant 必填Portal=Admin 必须为空)。</param>
/// <param name="roleIds">角色 ID 集合。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>角色集合。</returns>
Task<IReadOnlyList<Role>> GetByIdsAsync(long tenantId, IEnumerable<long> roleIds, CancellationToken cancellationToken = default);
Task<IReadOnlyList<Role>> GetByIdsAsync(
PortalType portal,
long? tenantId,
IEnumerable<long> roleIds,
CancellationToken cancellationToken = default);
/// <summary>
/// 按关键字搜索角色。
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="tenantId">租户 IDPortal=Tenant 必填Portal=Admin 必须为空)。</param>
/// <param name="keyword">关键字。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>角色集合。</returns>
Task<IReadOnlyList<Role>> SearchAsync(long tenantId, string? keyword, CancellationToken cancellationToken = default);
Task<IReadOnlyList<Role>> SearchAsync(PortalType portal, long? tenantId, string? keyword, CancellationToken cancellationToken = default);
/// <summary>
/// 新增角色。
@@ -63,10 +72,11 @@ public interface IRoleRepository
/// 删除角色。
/// </summary>
/// <param name="roleId">角色 ID。</param>
/// <param name="tenantId">租户 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="tenantId">租户 IDPortal=Tenant 必填Portal=Admin 必须为空)。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>异步操作任务。</returns>
Task DeleteAsync(long roleId, long tenantId, CancellationToken cancellationToken = default);
Task DeleteAsync(PortalType portal, long? tenantId, long roleId, CancellationToken cancellationToken = default);
/// <summary>
/// 保存仓储变更。

View File

@@ -1,4 +1,5 @@
using TakeoutSaaS.Domain.Identity.Entities;
using TakeoutSaaS.Domain.Identity.Enums;
namespace TakeoutSaaS.Domain.Identity.Repositories;
@@ -10,39 +11,56 @@ public interface IUserRoleRepository
/// <summary>
/// 批量获取指定用户的角色关系。
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="tenantId">租户 IDPortal=Tenant 必填Portal=Admin 必须为空)。</param>
/// <param name="userIds">用户 ID 集合。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>用户角色关系集合。</returns>
Task<IReadOnlyList<UserRole>> GetByUserIdsAsync(long tenantId, IEnumerable<long> userIds, CancellationToken cancellationToken = default);
Task<IReadOnlyList<UserRole>> GetByUserIdsAsync(
PortalType portal,
long? tenantId,
IEnumerable<long> userIds,
CancellationToken cancellationToken = default);
/// <summary>
/// 获取单个用户的角色关系。
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="tenantId">租户 IDPortal=Tenant 必填Portal=Admin 必须为空)。</param>
/// <param name="userId">用户 ID。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>指定用户的角色关系列表。</returns>
Task<IReadOnlyList<UserRole>> GetByUserIdAsync(long tenantId, long userId, CancellationToken cancellationToken = default);
Task<IReadOnlyList<UserRole>> GetByUserIdAsync(
PortalType portal,
long? tenantId,
long userId,
CancellationToken cancellationToken = default);
/// <summary>
/// 替换用户的角色列表。
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="tenantId">租户 IDPortal=Tenant 必填Portal=Admin 必须为空)。</param>
/// <param name="userId">用户 ID。</param>
/// <param name="roleIds">角色 ID 集合。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>异步操作任务。</returns>
Task ReplaceUserRolesAsync(long tenantId, long userId, IEnumerable<long> roleIds, CancellationToken cancellationToken = default);
Task ReplaceUserRolesAsync(
PortalType portal,
long? tenantId,
long userId,
IEnumerable<long> roleIds,
CancellationToken cancellationToken = default);
/// <summary>
/// 统计指定角色下的用户数量。
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="portal">Portal 类型。</param>
/// <param name="tenantId">租户 IDPortal=Tenant 必填Portal=Admin 必须为空)。</param>
/// <param name="roleId">角色 ID。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>用户数量。</returns>
Task<int> CountUsersByRoleAsync(long tenantId, long roleId, CancellationToken cancellationToken = default);
Task<int> CountUsersByRoleAsync(PortalType portal, long? tenantId, long roleId, CancellationToken cancellationToken = default);
/// <summary>
/// 提交持久化变更。

View File

@@ -11,7 +11,11 @@ public interface IStoreRepository
/// <summary>
/// 依据标识获取门店。
/// </summary>
Task<Store?> FindByIdAsync(long storeId, long tenantId, CancellationToken cancellationToken = default);
/// <param name="storeId">门店 ID。</param>
/// <param name="tenantId">租户 ID为空则不做租户过滤。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
Task<Store?> FindByIdAsync(long storeId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false);
/// <summary>
/// 获取指定商户的门店列表。
@@ -22,14 +26,14 @@ public interface IStoreRepository
/// 按租户筛选门店列表。
/// </summary>
Task<IReadOnlyList<Store>> SearchAsync(
long tenantId,
long? tenantId,
long? merchantId,
StoreStatus? status,
StoreAuditStatus? auditStatus,
StoreBusinessStatus? businessStatus,
StoreOwnershipType? ownershipType,
string? keyword,
bool ignoreTenantFilter = false,
bool includeDeleted = false,
CancellationToken cancellationToken = default);
/// <summary>
@@ -51,12 +55,20 @@ public interface IStoreRepository
/// <summary>
/// 获取门店营业时段。
/// </summary>
Task<IReadOnlyList<StoreBusinessHour>> GetBusinessHoursAsync(long storeId, long tenantId, CancellationToken cancellationToken = default);
/// <param name="storeId">门店 ID。</param>
/// <param name="tenantId">租户 ID为空则不做租户过滤。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
Task<IReadOnlyList<StoreBusinessHour>> GetBusinessHoursAsync(long storeId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false);
/// <summary>
/// 获取门店费用配置。
/// </summary>
Task<StoreFee?> GetStoreFeeAsync(long storeId, long tenantId, CancellationToken cancellationToken = default);
/// <param name="storeId">门店 ID。</param>
/// <param name="tenantId">租户 ID为空则不做租户过滤。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
Task<StoreFee?> GetStoreFeeAsync(long storeId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false);
/// <summary>
/// 新增门店费用配置。
@@ -71,7 +83,11 @@ public interface IStoreRepository
/// <summary>
/// 获取门店资质列表。
/// </summary>
Task<IReadOnlyList<StoreQualification>> GetQualificationsAsync(long storeId, long tenantId, CancellationToken cancellationToken = default);
/// <param name="storeId">门店 ID。</param>
/// <param name="tenantId">租户 ID为空则不做租户过滤。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
Task<IReadOnlyList<StoreQualification>> GetQualificationsAsync(long storeId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false);
/// <summary>
/// 依据标识获取门店资质。
@@ -111,22 +127,38 @@ public interface IStoreRepository
/// <summary>
/// 获取门店配送区域配置。
/// </summary>
Task<IReadOnlyList<StoreDeliveryZone>> GetDeliveryZonesAsync(long storeId, long tenantId, CancellationToken cancellationToken = default);
/// <param name="storeId">门店 ID。</param>
/// <param name="tenantId">租户 ID为空则不做租户过滤。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
Task<IReadOnlyList<StoreDeliveryZone>> GetDeliveryZonesAsync(long storeId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false);
/// <summary>
/// 依据标识获取配送区域。
/// </summary>
Task<StoreDeliveryZone?> FindDeliveryZoneByIdAsync(long deliveryZoneId, long tenantId, CancellationToken cancellationToken = default);
/// <param name="deliveryZoneId">配送区域 ID。</param>
/// <param name="tenantId">租户 ID为空则不做租户过滤。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
Task<StoreDeliveryZone?> FindDeliveryZoneByIdAsync(long deliveryZoneId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false);
/// <summary>
/// 获取门店节假日配置。
/// </summary>
Task<IReadOnlyList<StoreHoliday>> GetHolidaysAsync(long storeId, long tenantId, CancellationToken cancellationToken = default);
/// <param name="storeId">门店 ID。</param>
/// <param name="tenantId">租户 ID为空则不做租户过滤。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
Task<IReadOnlyList<StoreHoliday>> GetHolidaysAsync(long storeId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false);
/// <summary>
/// 依据标识获取节假日配置。
/// </summary>
Task<StoreHoliday?> FindHolidayByIdAsync(long holidayId, long tenantId, CancellationToken cancellationToken = default);
/// <param name="holidayId">节假日配置 ID。</param>
/// <param name="tenantId">租户 ID为空则不做租户过滤。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
Task<StoreHoliday?> FindHolidayByIdAsync(long holidayId, long? tenantId, CancellationToken cancellationToken = default, bool includeDeleted = false);
/// <summary>
/// 获取门店桌台区域。
@@ -276,12 +308,18 @@ public interface IStoreRepository
/// <summary>
/// 删除配送区域。
/// </summary>
Task DeleteDeliveryZoneAsync(long deliveryZoneId, long tenantId, CancellationToken cancellationToken = default);
/// <param name="deliveryZoneId">配送区域 ID。</param>
/// <param name="tenantId">租户 ID为空则不做租户过滤。</param>
/// <param name="cancellationToken">取消标记。</param>
Task DeleteDeliveryZoneAsync(long deliveryZoneId, long? tenantId, CancellationToken cancellationToken = default);
/// <summary>
/// 删除节假日。
/// </summary>
Task DeleteHolidayAsync(long holidayId, long tenantId, CancellationToken cancellationToken = default);
/// <param name="holidayId">节假日配置 ID。</param>
/// <param name="tenantId">租户 ID为空则不做租户过滤。</param>
/// <param name="cancellationToken">取消标记。</param>
Task DeleteHolidayAsync(long holidayId, long? tenantId, CancellationToken cancellationToken = default);
/// <summary>
/// 删除桌台区域。

View File

@@ -15,60 +15,60 @@ public interface ISubscriptionRepository
/// </summary>
/// <param name="subscriptionId">订阅 ID。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="ignoreTenantFilter">是否忽略租户过滤(用于平台级查询/任务)。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
/// <returns>订阅实体,未找到返回 null。</returns>
Task<TenantSubscription?> FindByIdAsync(
long subscriptionId,
CancellationToken cancellationToken = default,
bool ignoreTenantFilter = false);
bool includeDeleted = false);
/// <summary>
/// 按 ID 列表批量查询订阅。
/// </summary>
/// <param name="subscriptionIds">订阅 ID 列表。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="ignoreTenantFilter">是否忽略租户过滤(用于平台级查询/任务)。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
/// <returns>订阅实体列表。</returns>
Task<IReadOnlyList<TenantSubscription>> FindByIdsAsync(
IEnumerable<long> subscriptionIds,
CancellationToken cancellationToken = default,
bool ignoreTenantFilter = false);
bool includeDeleted = false);
/// <summary>
/// 分页查询订阅列表(含关联信息)。
/// </summary>
/// <param name="filter">查询过滤条件。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="ignoreTenantFilter">是否忽略租户过滤(用于平台级查询/任务)。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
/// <returns>分页结果。</returns>
Task<(IReadOnlyList<SubscriptionWithRelations> Items, int Total)> SearchPagedAsync(
SubscriptionSearchFilter filter,
CancellationToken cancellationToken = default,
bool ignoreTenantFilter = false);
bool includeDeleted = false);
/// <summary>
/// 获取订阅详情(含关联信息)。
/// </summary>
/// <param name="subscriptionId">订阅 ID。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="ignoreTenantFilter">是否忽略租户过滤(用于平台级查询/任务)。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
/// <returns>订阅详情信息。</returns>
Task<SubscriptionDetailInfo?> GetDetailAsync(
long subscriptionId,
CancellationToken cancellationToken = default,
bool ignoreTenantFilter = false);
bool includeDeleted = false);
/// <summary>
/// 按 ID 列表批量查询订阅(含租户信息)。
/// </summary>
/// <param name="subscriptionIds">订阅 ID 列表。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="ignoreTenantFilter">是否忽略租户过滤(用于平台级查询/任务)。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
/// <returns>订阅与租户信息列表。</returns>
Task<IReadOnlyList<SubscriptionWithTenant>> FindByIdsWithTenantAsync(
IEnumerable<long> subscriptionIds,
CancellationToken cancellationToken = default,
bool ignoreTenantFilter = false);
bool includeDeleted = false);
/// <summary>
/// 查询自动续费候选订阅(活跃 + 开启自动续费 + 即将到期)。
@@ -76,13 +76,13 @@ public interface ISubscriptionRepository
/// <param name="now">当前时间UTC。</param>
/// <param name="renewalThreshold">续费阈值时间UTC到期时间小于等于该时间视为候选。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="ignoreTenantFilter">是否忽略租户过滤(用于平台级查询/任务)。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
/// <returns>候选订阅集合(含套餐信息)。</returns>
Task<IReadOnlyList<AutoRenewalCandidate>> FindAutoRenewalCandidatesAsync(
DateTime now,
DateTime renewalThreshold,
CancellationToken cancellationToken = default,
bool ignoreTenantFilter = false);
bool includeDeleted = false);
/// <summary>
/// 查询续费提醒候选订阅(活跃 + 未开启自动续费 + 到期时间落在指定日期范围)。
@@ -90,25 +90,25 @@ public interface ISubscriptionRepository
/// <param name="startOfDay">筛选开始时间UTC。</param>
/// <param name="endOfDay">筛选结束时间UTC不含。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="ignoreTenantFilter">是否忽略租户过滤(用于平台级查询/任务)。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
/// <returns>候选订阅集合(含租户与套餐信息)。</returns>
Task<IReadOnlyList<RenewalReminderCandidate>> FindRenewalReminderCandidatesAsync(
DateTime startOfDay,
DateTime endOfDay,
CancellationToken cancellationToken = default,
bool ignoreTenantFilter = false);
bool includeDeleted = false);
/// <summary>
/// 查询已到期仍处于 Active 的订阅(用于进入宽限期)。
/// </summary>
/// <param name="now">当前时间UTC。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="ignoreTenantFilter">是否忽略租户过滤(用于平台级查询/任务)。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
/// <returns>到期订阅集合。</returns>
Task<IReadOnlyList<TenantSubscription>> FindExpiredActiveSubscriptionsAsync(
DateTime now,
CancellationToken cancellationToken = default,
bool ignoreTenantFilter = false);
bool includeDeleted = false);
/// <summary>
/// 查询宽限期已结束的订阅(用于自动暂停)。
@@ -116,13 +116,13 @@ public interface ISubscriptionRepository
/// <param name="now">当前时间UTC。</param>
/// <param name="gracePeriodDays">宽限期天数。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="ignoreTenantFilter">是否忽略租户过滤(用于平台级查询/任务)。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
/// <returns>宽限期到期订阅集合。</returns>
Task<IReadOnlyList<TenantSubscription>> FindGracePeriodExpiredSubscriptionsAsync(
DateTime now,
int gracePeriodDays,
CancellationToken cancellationToken = default,
bool ignoreTenantFilter = false);
bool includeDeleted = false);
#endregion
@@ -177,12 +177,12 @@ public interface ISubscriptionRepository
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <param name="ignoreTenantFilter">是否忽略租户过滤(用于平台级查询/任务)。</param>
/// <param name="includeDeleted">是否包含已删除数据。</param>
/// <returns>配额使用列表。</returns>
Task<IReadOnlyList<TenantQuotaUsage>> GetQuotaUsagesAsync(
long tenantId,
CancellationToken cancellationToken = default,
bool ignoreTenantFilter = false);
bool includeDeleted = false);
#endregion