feat: 用户管理后端与日志库迁移

This commit is contained in:
2025-12-27 06:23:03 +08:00
parent 0ff2794667
commit b2a90cf8af
57 changed files with 4117 additions and 33 deletions

View File

@@ -0,0 +1,104 @@
using MediatR;
using TakeoutSaaS.Application.Identity.Abstractions;
using TakeoutSaaS.Application.Identity.Contracts;
using TakeoutSaaS.Application.Identity.Queries;
using TakeoutSaaS.Domain.Identity.Entities;
using TakeoutSaaS.Domain.Identity.Enums;
using TakeoutSaaS.Domain.Identity.Repositories;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
namespace TakeoutSaaS.Application.Identity.Handlers;
/// <summary>
/// 获取用户详情处理器。
/// </summary>
public sealed class GetIdentityUserDetailQueryHandler(
IIdentityUserRepository identityUserRepository,
IUserRoleRepository userRoleRepository,
IRoleRepository roleRepository,
IRolePermissionRepository rolePermissionRepository,
IPermissionRepository permissionRepository,
ITenantProvider tenantProvider,
ICurrentUserAccessor currentUserAccessor,
IAdminAuthService adminAuthService)
: IRequestHandler<GetIdentityUserDetailQuery, UserDetailDto?>
{
/// <inheritdoc />
public async Task<UserDetailDto?> Handle(GetIdentityUserDetailQuery request, CancellationToken cancellationToken)
{
// 1. 获取操作者档案并判断权限
var currentTenantId = tenantProvider.GetCurrentTenantId();
var operatorProfile = await adminAuthService.GetProfileAsync(currentUserAccessor.UserId, cancellationToken);
var isSuperAdmin = IdentityUserAccess.IsSuperAdmin(operatorProfile);
// 2. (空行后) 查询用户实体
IdentityUser? user;
if (request.IncludeDeleted)
{
user = await identityUserRepository.GetForUpdateIncludingDeletedAsync(currentTenantId, request.UserId, isSuperAdmin, cancellationToken);
}
else
{
user = isSuperAdmin
? await identityUserRepository.GetForUpdateIgnoringTenantAsync(request.UserId, cancellationToken)
: await identityUserRepository.GetForUpdateAsync(request.UserId, cancellationToken);
}
if (user == null)
{
return null;
}
if (!isSuperAdmin && user.TenantId != currentTenantId)
{
return null;
}
// 3. (空行后) 加载角色与权限
var roleRelations = await userRoleRepository.GetByUserIdAsync(user.TenantId, user.Id, cancellationToken);
var roleIds = roleRelations.Select(x => x.RoleId).Distinct().ToArray();
var roles = roleIds.Length == 0
? Array.Empty<Role>()
: await roleRepository.GetByIdsAsync(user.TenantId, roleIds, cancellationToken);
var roleCodes = roles.Select(x => x.Code)
.Where(code => !string.IsNullOrWhiteSpace(code))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
var permissionIds = roleIds.Length == 0
? Array.Empty<long>()
: (await rolePermissionRepository.GetByRoleIdsAsync(user.TenantId, roleIds, cancellationToken))
.Select(x => x.PermissionId)
.Distinct()
.ToArray();
var permissions = permissionIds.Length == 0
? Array.Empty<string>()
: (await permissionRepository.GetByIdsAsync(user.TenantId, permissionIds, cancellationToken))
.Select(x => x.Code)
.Where(code => !string.IsNullOrWhiteSpace(code))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToArray();
// 4. (空行后) 组装详情 DTO
var now = DateTime.UtcNow;
return new UserDetailDto
{
UserId = user.Id,
TenantId = user.TenantId,
MerchantId = user.MerchantId,
Account = user.Account,
DisplayName = user.DisplayName,
Phone = user.Phone,
Email = user.Email,
Status = user.Status,
IsLocked = user.Status == IdentityUserStatus.Locked || (user.LockedUntil.HasValue && user.LockedUntil.Value > now),
Roles = roleCodes,
RoleIds = roleIds.Select(id => id.ToString()).ToArray(),
Permissions = permissions,
CreatedAt = user.CreatedAt,
LastLoginAt = user.LastLoginAt,
Avatar = user.Avatar,
RowVersion = user.RowVersion
};
}
}