175 lines
5.7 KiB
C#
175 lines
5.7 KiB
C#
using Fake.DependencyInjection;
|
|
using Fake.Rbac.Infrastructure;
|
|
using Fake.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Oms.Application.Dtos.Rbac;
|
|
|
|
namespace Oms.Application.Rbac;
|
|
|
|
public class InternalUserRepository(FakeRbacDbContext dbContext) : IScopedDependency
|
|
{
|
|
private static readonly string InternalUserFilter = $$"""
|
|
(
|
|
NOT EXISTS (SELECT 1 FROM `{{FakeTables.UserRole}}` ur0 WHERE ur0.`UserId` = u.`Id`)
|
|
OR EXISTS (
|
|
SELECT 1
|
|
FROM `{{FakeTables.UserRole}}` ur
|
|
INNER JOIN `{{FakeTables.Role}}` r ON r.`Id` = ur.`RoleId` AND r.`IsDeleted` = 0
|
|
WHERE ur.`UserId` = u.`Id`
|
|
AND r.`Code` <> 'Customer'
|
|
AND r.`Code` NOT LIKE 'CustomerSub\_%'
|
|
)
|
|
)
|
|
""";
|
|
public async Task<InternalUserListResultDto> GetInternalUsersAsync(
|
|
string? keyword,
|
|
Guid? organizationId,
|
|
int page,
|
|
int pageSize,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var where = $"WHERE u.`IsDeleted` = 0 AND {InternalUserFilter}";
|
|
var args = new List<object>();
|
|
|
|
if (!string.IsNullOrWhiteSpace(keyword))
|
|
{
|
|
var pattern = $"%{keyword.Trim()}%";
|
|
where += $" AND (u.`Name` LIKE {{{args.Count}}} OR u.`Account` LIKE {{{args.Count + 1}}})";
|
|
args.Add(pattern);
|
|
args.Add(pattern);
|
|
}
|
|
|
|
if (organizationId.HasValue && organizationId.Value != Guid.Empty)
|
|
{
|
|
where += $" AND u.`OrganizationId` = {{{args.Count}}}";
|
|
args.Add(organizationId.Value.ToString());
|
|
}
|
|
|
|
var countSql = $$"""
|
|
SELECT COUNT(*) AS `Value`
|
|
FROM `{{FakeTables.User}}` u
|
|
{where}
|
|
""";
|
|
var total = await dbContext.Database.SqlQueryRaw<long>(countSql, args.ToArray())
|
|
.FirstAsync(cancellationToken);
|
|
|
|
var offset = Math.Max(page - 1, 0) * pageSize;
|
|
var listSql = $$"""
|
|
SELECT
|
|
u.`Id` AS `Id`,
|
|
u.`Name` AS `Name`,
|
|
u.`Account` AS `Account`,
|
|
u.`Email` AS `Email`,
|
|
u.`Avatar` AS `Avatar`,
|
|
u.`Phone` AS `Phone`,
|
|
u.`EmployeeNo` AS `EmployeeNo`,
|
|
u.`WechatId` AS `WechatId`,
|
|
u.`OrganizationId` AS `OrganizationId`,
|
|
o.`Name` AS `OrganizationName`,
|
|
u.`CreateTime` AS `CreatedAt`
|
|
FROM `{{FakeTables.User}}` u
|
|
LEFT JOIN `{{FakeTables.Organization}}` o ON o.`Id` = u.`OrganizationId` AND o.`IsDeleted` = 0
|
|
{where}
|
|
ORDER BY u.`CreateTime` DESC
|
|
LIMIT {pageSize} OFFSET {offset}
|
|
""";
|
|
var rows = await dbContext.Database.SqlQueryRaw<InternalUserRow>(listSql, args.ToArray())
|
|
.ToListAsync(cancellationToken);
|
|
if (rows.Count == 0)
|
|
{
|
|
return new InternalUserListResultDto { Total = total, Items = [] };
|
|
}
|
|
|
|
var userIds = rows.Select(x => x.Id).Distinct().ToList();
|
|
var roleMap = await LoadRolesByUserIdsAsync(userIds, cancellationToken);
|
|
var items = rows.Select(row => new InternalUserListItemDto
|
|
{
|
|
Id = row.Id.ToString(),
|
|
Name = row.Name,
|
|
Account = row.Account,
|
|
Email = row.Email,
|
|
Avatar = row.Avatar,
|
|
Phone = row.Phone,
|
|
EmployeeNo = row.EmployeeNo,
|
|
WechatId = row.WechatId,
|
|
OrganizationId = row.OrganizationId?.ToString(),
|
|
OrganizationName = row.OrganizationName,
|
|
CreatedAt = row.CreatedAt,
|
|
Roles = roleMap.TryGetValue(row.Id, out var roles) ? roles : []
|
|
}).ToList();
|
|
|
|
return new InternalUserListResultDto { Total = total, Items = items };
|
|
}
|
|
|
|
private async Task<Dictionary<Guid, List<InternalUserRoleDto>>> LoadRolesByUserIdsAsync(
|
|
IReadOnlyList<Guid> userIds,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
if (userIds.Count == 0)
|
|
{
|
|
return [];
|
|
}
|
|
|
|
var inClause = string.Join(",", userIds.Select(x => $"'{x}'"));
|
|
var sql = $$"""
|
|
SELECT
|
|
ur.`UserId` AS `UserId`,
|
|
r.`Id` AS `RoleId`,
|
|
r.`Name` AS `RoleName`,
|
|
r.`Code` AS `RoleCode`
|
|
FROM `{{FakeTables.UserRole}}` ur
|
|
INNER JOIN `{{FakeTables.Role}}` r ON r.`Id` = ur.`RoleId` AND r.`IsDeleted` = 0
|
|
WHERE ur.`UserId` IN ({inClause})
|
|
ORDER BY r.`Name`
|
|
""";
|
|
|
|
var roleRows = await dbContext.Database.SqlQueryRaw<UserRoleRow>(sql).ToListAsync(cancellationToken);
|
|
return roleRows
|
|
.GroupBy(x => x.UserId)
|
|
.ToDictionary(
|
|
g => g.Key,
|
|
g => g.Select(x => new InternalUserRoleDto
|
|
{
|
|
Id = x.RoleId.ToString(),
|
|
Name = x.RoleName,
|
|
Code = x.RoleCode
|
|
}).ToList());
|
|
}
|
|
|
|
private sealed class InternalUserRow
|
|
{
|
|
public Guid Id { get; set; }
|
|
|
|
public string? Name { get; set; }
|
|
|
|
public string? Account { get; set; }
|
|
|
|
public string? Email { get; set; }
|
|
|
|
public string? Avatar { get; set; }
|
|
|
|
public string? Phone { get; set; }
|
|
|
|
public string? EmployeeNo { get; set; }
|
|
|
|
public string? WechatId { get; set; }
|
|
|
|
public Guid? OrganizationId { get; set; }
|
|
|
|
public string? OrganizationName { get; set; }
|
|
|
|
public DateTime? CreatedAt { get; set; }
|
|
}
|
|
|
|
private sealed class UserRoleRow
|
|
{
|
|
public Guid UserId { get; set; }
|
|
|
|
public Guid RoleId { get; set; }
|
|
|
|
public string? RoleName { get; set; }
|
|
|
|
public string? RoleCode { get; set; }
|
|
}
|
|
}
|