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

@@ -6,6 +6,7 @@ using TakeoutSaaS.Application.Identity.Contracts;
using TakeoutSaaS.Application.Identity.Events;
using TakeoutSaaS.Application.Identity.Queries;
using TakeoutSaaS.Domain.Identity.Entities;
using TakeoutSaaS.Domain.Identity.Enums;
using TakeoutSaaS.Domain.Identity.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
@@ -43,9 +44,7 @@ public sealed class UpdateIdentityUserCommandHandler(
}
// 3. 获取用户实体
var user = isSuperAdmin
? await identityUserRepository.GetForUpdateIgnoringTenantAsync(request.UserId, cancellationToken)
: await identityUserRepository.GetForUpdateAsync(request.UserId, cancellationToken);
var user = await identityUserRepository.GetForUpdateAsync(request.UserId, cancellationToken);
if (user == null)
{
return null;
@@ -57,28 +56,37 @@ public sealed class UpdateIdentityUserCommandHandler(
}
// 4. 规范化输入并校验唯一性
var portal = user.Portal;
var tenantId = user.TenantId;
if (portal == PortalType.Tenant && (!tenantId.HasValue || tenantId.Value == 0))
{
throw new BusinessException(ErrorCodes.InternalServerError, "用户缺少有效的租户标识");
}
var displayName = request.DisplayName.Trim();
var phone = string.IsNullOrWhiteSpace(request.Phone) ? null : request.Phone.Trim();
var email = string.IsNullOrWhiteSpace(request.Email) ? null : request.Email.Trim();
var roleIds = request.RoleIds == null ? null : ParseIds(request.RoleIds, "角色");
if (!string.IsNullOrWhiteSpace(phone)
if (portal == PortalType.Tenant
&& !string.IsNullOrWhiteSpace(phone)
&& !string.Equals(phone, user.Phone, StringComparison.OrdinalIgnoreCase)
&& await identityUserRepository.ExistsByPhoneAsync(user.TenantId, phone, user.Id, cancellationToken))
&& await identityUserRepository.ExistsByPhoneAsync(tenantId!.Value, phone, user.Id, cancellationToken))
{
throw new BusinessException(ErrorCodes.Conflict, "手机号已存在");
}
if (!string.IsNullOrWhiteSpace(email)
if (portal == PortalType.Tenant
&& !string.IsNullOrWhiteSpace(email)
&& !string.Equals(email, user.Email, StringComparison.OrdinalIgnoreCase)
&& await identityUserRepository.ExistsByEmailAsync(user.TenantId, email, user.Id, cancellationToken))
&& await identityUserRepository.ExistsByEmailAsync(tenantId!.Value, email, user.Id, cancellationToken))
{
throw new BusinessException(ErrorCodes.Conflict, "邮箱已存在");
}
if (roleIds is { Length: > 0 })
{
var roles = await roleRepository.GetByIdsAsync(user.TenantId, roleIds, cancellationToken);
var roles = await roleRepository.GetByIdsAsync(portal, tenantId, roleIds, cancellationToken);
if (roles.Count != roleIds.Length)
{
throw new BusinessException(ErrorCodes.BadRequest, "角色列表包含无效项");
@@ -134,7 +142,7 @@ public sealed class UpdateIdentityUserCommandHandler(
// 8. 覆盖角色绑定(仅当显式传入时)
if (roleIds != null)
{
await userRoleRepository.ReplaceUserRolesAsync(user.TenantId, user.Id, roleIds, cancellationToken);
await userRoleRepository.ReplaceUserRolesAsync(portal, tenantId, user.Id, roleIds, cancellationToken);
}
// 9. 返回用户详情