服务器端分页优化

This commit is contained in:
2026-08-11 11:46:26 +08:00 Unverified
parent 292d029459
commit 83103eebb8
7 changed files with 287 additions and 50 deletions
+66 -22
View File
@@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations;
using System.Security.Claims;
using Jiaowu.Api.Contracts;
using Jiaowu.Api.Domain.Academic;
using Jiaowu.Api.Domain.Identity;
using Jiaowu.Api.Infrastructure.Persistence;
@@ -19,10 +20,35 @@ public sealed class UsersController(
RoleManager<ApplicationRole> roleManager) : ControllerBase
{
[HttpGet]
public async Task<ActionResult<object>> GetUsers(CancellationToken cancellationToken)
public async Task<ActionResult<PagedResult<UserListItem>>> GetUsers(
int page = 1,
int pageSize = 20,
string? keyword = null,
CancellationToken cancellationToken = default)
{
var users = await userManager.Users.AsNoTracking()
if (page < 1 || pageSize is < 1 or > 100)
return ValidationProblem("页码必须大于 0,且每页条数应在 1 至 100 之间。");
var query = userManager.Users.AsNoTracking();
if (!string.IsNullOrWhiteSpace(keyword))
{
keyword = keyword.Trim();
query = query.Where(user =>
user.UserName!.Contains(keyword) ||
user.DisplayName.Contains(keyword) ||
(user.StaffNumber != null && user.StaffNumber.Contains(keyword)) ||
(from userRole in db.UserRoles
join role in db.Roles on userRole.RoleId equals role.Id
where userRole.UserId == user.Id && role.Name!.Contains(keyword)
select role.Id).Any());
}
var total = await query.CountAsync(cancellationToken);
var users = await query
.OrderBy(x => x.UserName)
.ThenBy(x => x.Id)
.Skip((page - 1) * pageSize)
.Take(pageSize)
.Select(x => new
{
x.Id,
@@ -36,26 +62,34 @@ public sealed class UsersController(
})
.ToListAsync(cancellationToken);
var result = new List<object>();
foreach (var user in users)
{
var identityUser = await userManager.FindByIdAsync(user.Id.ToString());
result.Add(new
{
user.Id,
user.UserName,
user.DisplayName,
user.StaffNumber,
user.CollegeId,
user.IsEnabled,
user.LastLoginAt,
user.CreatedAt,
Roles = identityUser is null
? []
: await userManager.GetRolesAsync(identityUser)
});
}
return Ok(result);
var userIds = users.Select(x => x.Id).ToArray();
var roleRows = await (
from userRole in db.UserRoles.AsNoTracking()
join role in db.Roles.AsNoTracking() on userRole.RoleId equals role.Id
where userIds.Contains(userRole.UserId)
select new { userRole.UserId, RoleName = role.Name! })
.ToListAsync(cancellationToken);
var rolesByUser = roleRows
.GroupBy(x => x.UserId)
.ToDictionary(
group => group.Key,
group => (IReadOnlyCollection<string>)group
.Select(x => x.RoleName)
.OrderBy(x => x)
.ToArray());
var items = users.Select(user => new UserListItem(
user.Id,
user.UserName ?? string.Empty,
user.DisplayName,
user.StaffNumber,
user.CollegeId,
user.IsEnabled,
user.LastLoginAt,
user.CreatedAt,
rolesByUser.GetValueOrDefault(user.Id, Array.Empty<string>())))
.ToArray();
return Ok(new PagedResult<UserListItem>(items, total, page, pageSize));
}
[HttpGet("roles")]
@@ -281,6 +315,16 @@ public sealed record CreateUserRequest(
[MinLength(1)] string[] Roles);
public sealed record SetUserStatusRequest(bool IsEnabled);
public sealed record UserListItem(
Guid Id,
string UserName,
string DisplayName,
string? StaffNumber,
Guid? CollegeId,
bool IsEnabled,
DateTime? LastLoginAt,
DateTime CreatedAt,
IReadOnlyCollection<string> Roles);
public sealed record SetRolesRequest(
[MaxLength(30)] string? StaffNumber,
Guid? CollegeId,