优化服务器端分页
This commit is contained in:
1 parent
83103eebb8
commit
5d7322507b
6 files changed
+225
-50
No files matched your search
@@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Jiaowu.Api.Contracts;
|
||||||
using Jiaowu.Api.Domain.Academic;
|
using Jiaowu.Api.Domain.Academic;
|
||||||
using Jiaowu.Api.Domain.Identity;
|
using Jiaowu.Api.Domain.Identity;
|
||||||
using Jiaowu.Api.Infrastructure.Auth;
|
using Jiaowu.Api.Infrastructure.Auth;
|
||||||
@@ -176,8 +177,13 @@ public sealed class CourseAdjustmentsController(
|
|||||||
public async Task<ActionResult> GetMine(
|
public async Task<ActionResult> GetMine(
|
||||||
Guid? academicTermId,
|
Guid? academicTermId,
|
||||||
CourseAdjustmentStatus? status,
|
CourseAdjustmentStatus? status,
|
||||||
CancellationToken cancellationToken)
|
int page = 1,
|
||||||
|
int pageSize = 20,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
if (page < 1 || pageSize is < 1 or > 100)
|
||||||
|
return ValidationProblem("页码必须大于 0,且每页条数应在 1 至 100 之间。");
|
||||||
|
|
||||||
var userId = currentUserDataScope.Current.UserId;
|
var userId = currentUserDataScope.Current.UserId;
|
||||||
var source = db.CourseAdjustments.AsNoTracking()
|
var source = db.CourseAdjustments.AsNoTracking()
|
||||||
.Where(x => x.ApplicantUserId == userId);
|
.Where(x => x.ApplicantUserId == userId);
|
||||||
@@ -187,10 +193,15 @@ public sealed class CourseAdjustmentsController(
|
|||||||
if (status.HasValue)
|
if (status.HasValue)
|
||||||
source = source.Where(x => x.Status == status);
|
source = source.Where(x => x.Status == status);
|
||||||
|
|
||||||
return Ok(await source
|
var total = await source.CountAsync(cancellationToken);
|
||||||
|
var items = await source
|
||||||
.OrderByDescending(x => x.CreatedAt)
|
.OrderByDescending(x => x.CreatedAt)
|
||||||
|
.ThenByDescending(x => x.Id)
|
||||||
|
.Skip((page - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
.Select(AdjustmentProjection())
|
.Select(AdjustmentProjection())
|
||||||
.ToListAsync(cancellationToken));
|
.ToListAsync(cancellationToken);
|
||||||
|
return Ok(new PagedResult<object>(items, total, page, pageSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ═══════════════ Pending reviews ═══════════════
|
// ═══════════════ Pending reviews ═══════════════
|
||||||
@@ -199,8 +210,13 @@ public sealed class CourseAdjustmentsController(
|
|||||||
[Authorize(Roles = Reviewers)]
|
[Authorize(Roles = Reviewers)]
|
||||||
public async Task<ActionResult> GetPendingReviews(
|
public async Task<ActionResult> GetPendingReviews(
|
||||||
Guid? academicTermId,
|
Guid? academicTermId,
|
||||||
CancellationToken cancellationToken)
|
int page = 1,
|
||||||
|
int pageSize = 20,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
if (page < 1 || pageSize is < 1 or > 100)
|
||||||
|
return ValidationProblem("页码必须大于 0,且每页条数应在 1 至 100 之间。");
|
||||||
|
|
||||||
var scope = currentUserDataScope.Current;
|
var scope = currentUserDataScope.Current;
|
||||||
var source = db.CourseAdjustments.AsNoTracking()
|
var source = db.CourseAdjustments.AsNoTracking()
|
||||||
.Where(x => x.Status == CourseAdjustmentStatus.Submitted);
|
.Where(x => x.Status == CourseAdjustmentStatus.Submitted);
|
||||||
@@ -211,10 +227,15 @@ public sealed class CourseAdjustmentsController(
|
|||||||
source = source.Where(x =>
|
source = source.Where(x =>
|
||||||
x.TeachingTask!.AcademicTermId == academicTermId);
|
x.TeachingTask!.AcademicTermId == academicTermId);
|
||||||
|
|
||||||
return Ok(await source
|
var total = await source.CountAsync(cancellationToken);
|
||||||
|
var items = await source
|
||||||
.OrderByDescending(x => x.SubmittedAt)
|
.OrderByDescending(x => x.SubmittedAt)
|
||||||
|
.ThenByDescending(x => x.Id)
|
||||||
|
.Skip((page - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
.Select(AdjustmentProjection())
|
.Select(AdjustmentProjection())
|
||||||
.ToListAsync(cancellationToken));
|
.ToListAsync(cancellationToken);
|
||||||
|
return Ok(new PagedResult<object>(items, total, page, pageSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ═══════════════ Detail ═══════════════
|
// ═══════════════ Detail ═══════════════
|
||||||
|
|||||||
@@ -17,17 +17,53 @@ public sealed class StudentStatusChangesController(
|
|||||||
ICurrentUserDataScope currentUserDataScope) : ControllerBase
|
ICurrentUserDataScope currentUserDataScope) : ControllerBase
|
||||||
{
|
{
|
||||||
[HttpGet]
|
[HttpGet]
|
||||||
public async Task<ActionResult> Get(CancellationToken token)
|
public async Task<ActionResult<StudentStatusChangePage>> Get(
|
||||||
|
int page = 1,
|
||||||
|
int pageSize = 20,
|
||||||
|
CancellationToken token = default)
|
||||||
{
|
{
|
||||||
|
if (page < 1 || pageSize is < 1 or > 100)
|
||||||
|
return ValidationProblem("页码必须大于 0,且每页条数应在 1 至 100 之间。");
|
||||||
|
|
||||||
var source = ScopedChanges().AsNoTracking();
|
var source = ScopedChanges().AsNoTracking();
|
||||||
return Ok(await source.OrderByDescending(x => x.SubmittedAt).Select(x => new
|
var userScope = currentUserDataScope.Current;
|
||||||
{
|
var total = await source.CountAsync(token);
|
||||||
x.Id, x.StudentId, x.Student!.StudentNumber, x.Student.Name,
|
var actionableTotal = await source.CountAsync(change =>
|
||||||
ClassName = x.Student.AdministrativeClass!.Name,
|
(change.State == StudentStatusChangeState.Submitted &&
|
||||||
CollegeName = x.Student.AdministrativeClass.Major!.College!.Name,
|
userScope.IsInRole(SystemRoles.Counselor)) ||
|
||||||
x.Type, x.OriginalStatus, x.TargetStatus, x.Reason, x.State,
|
(change.State == StudentStatusChangeState.CounselorApproved &&
|
||||||
x.ReviewComment, x.SubmittedAt, x.ReviewedAt, x.ApprovedAt
|
userScope.IsInRole(SystemRoles.CollegeAdmin)) ||
|
||||||
}).ToListAsync(token));
|
(change.State == StudentStatusChangeState.CollegeApproved &&
|
||||||
|
(userScope.IsInRole(SystemRoles.AcademicAdmin) ||
|
||||||
|
userScope.IsInRole(SystemRoles.SuperAdmin))), token);
|
||||||
|
var finishedTotal = await source.CountAsync(change =>
|
||||||
|
change.State == StudentStatusChangeState.Approved ||
|
||||||
|
change.State == StudentStatusChangeState.Rejected ||
|
||||||
|
change.State == StudentStatusChangeState.Cancelled, token);
|
||||||
|
var items = await source
|
||||||
|
.OrderByDescending(x => x.SubmittedAt)
|
||||||
|
.ThenByDescending(x => x.Id)
|
||||||
|
.Skip((page - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
|
.Select(x => new StudentStatusChangeListItem(
|
||||||
|
x.Id,
|
||||||
|
x.StudentId,
|
||||||
|
x.Student!.StudentNumber,
|
||||||
|
x.Student.Name,
|
||||||
|
x.Student.AdministrativeClass!.Name,
|
||||||
|
x.Student.AdministrativeClass.Major!.College!.Name,
|
||||||
|
x.Type,
|
||||||
|
x.OriginalStatus,
|
||||||
|
x.TargetStatus,
|
||||||
|
x.Reason,
|
||||||
|
x.State,
|
||||||
|
x.ReviewComment,
|
||||||
|
x.SubmittedAt,
|
||||||
|
x.ReviewedAt,
|
||||||
|
x.ApprovedAt))
|
||||||
|
.ToListAsync(token);
|
||||||
|
return Ok(new StudentStatusChangePage(
|
||||||
|
items, total, page, pageSize, actionableTotal, finishedTotal));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("options")]
|
[HttpGet("options")]
|
||||||
@@ -199,6 +235,31 @@ public sealed class StudentStatusChangesController(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public sealed record StudentStatusChangePage(
|
||||||
|
IReadOnlyCollection<StudentStatusChangeListItem> Items,
|
||||||
|
int Total,
|
||||||
|
int Page,
|
||||||
|
int PageSize,
|
||||||
|
int ActionableTotal,
|
||||||
|
int FinishedTotal);
|
||||||
|
|
||||||
|
public sealed record StudentStatusChangeListItem(
|
||||||
|
Guid Id,
|
||||||
|
Guid StudentId,
|
||||||
|
string StudentNumber,
|
||||||
|
string Name,
|
||||||
|
string ClassName,
|
||||||
|
string CollegeName,
|
||||||
|
StudentStatusChangeType Type,
|
||||||
|
StudentStatus OriginalStatus,
|
||||||
|
StudentStatus TargetStatus,
|
||||||
|
string Reason,
|
||||||
|
StudentStatusChangeState State,
|
||||||
|
string? ReviewComment,
|
||||||
|
DateTime SubmittedAt,
|
||||||
|
DateTime? ReviewedAt,
|
||||||
|
DateTime? ApprovedAt);
|
||||||
|
|
||||||
public sealed record StudentStatusChangeRequest(
|
public sealed record StudentStatusChangeRequest(
|
||||||
StudentStatusChangeType Type,
|
StudentStatusChangeType Type,
|
||||||
[Required, MinLength(10), MaxLength(1000)] string Reason);
|
[Required, MinLength(10), MaxLength(1000)] string Reason);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using Jiaowu.Api.Contracts;
|
||||||
using Jiaowu.Api.Domain.Academic;
|
using Jiaowu.Api.Domain.Academic;
|
||||||
using Jiaowu.Api.Domain.Identity;
|
using Jiaowu.Api.Domain.Identity;
|
||||||
using Jiaowu.Api.Infrastructure.Auth;
|
using Jiaowu.Api.Infrastructure.Auth;
|
||||||
@@ -46,17 +47,26 @@ public sealed class TeacherCourseApplicationsController(
|
|||||||
[Authorize(Roles = SystemRoles.Teacher)]
|
[Authorize(Roles = SystemRoles.Teacher)]
|
||||||
public async Task<ActionResult> GetMine(
|
public async Task<ActionResult> GetMine(
|
||||||
Guid? academicTermId,
|
Guid? academicTermId,
|
||||||
CancellationToken cancellationToken)
|
int page = 1,
|
||||||
|
int pageSize = 20,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
if (page < 1 || pageSize is < 1 or > 100)
|
||||||
|
return ValidationProblem("页码必须大于 0,且每页条数应在 1 至 100 之间。");
|
||||||
|
|
||||||
var teacher = await CurrentTeacherAsync(cancellationToken);
|
var teacher = await CurrentTeacherAsync(cancellationToken);
|
||||||
if (teacher is null) return ConflictProblem("当前账号尚未关联在职教师档案。");
|
if (teacher is null) return ConflictProblem("当前账号尚未关联在职教师档案。");
|
||||||
var source = db.TeacherCourseApplications.AsNoTracking()
|
var source = db.TeacherCourseApplications.AsNoTracking()
|
||||||
.Where(x => x.TeacherId == teacher.Id);
|
.Where(x => x.TeacherId == teacher.Id);
|
||||||
if (academicTermId.HasValue)
|
if (academicTermId.HasValue)
|
||||||
source = source.Where(x => x.AcademicTermId == academicTermId);
|
source = source.Where(x => x.AcademicTermId == academicTermId);
|
||||||
return Ok(await source
|
var total = await source.CountAsync(cancellationToken);
|
||||||
|
var items = await source
|
||||||
.OrderByDescending(x => x.AcademicTerm!.StartDate)
|
.OrderByDescending(x => x.AcademicTerm!.StartDate)
|
||||||
.ThenBy(x => x.Course!.Code)
|
.ThenBy(x => x.Course!.Code)
|
||||||
|
.ThenBy(x => x.Id)
|
||||||
|
.Skip((page - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
.Select(x => new
|
.Select(x => new
|
||||||
{
|
{
|
||||||
x.Id,
|
x.Id,
|
||||||
@@ -72,7 +82,8 @@ public sealed class TeacherCourseApplicationsController(
|
|||||||
x.SubmittedAt,
|
x.SubmittedAt,
|
||||||
x.ReviewedAt
|
x.ReviewedAt
|
||||||
})
|
})
|
||||||
.ToListAsync(cancellationToken));
|
.ToListAsync(cancellationToken);
|
||||||
|
return Ok(new PagedResult<object>(items, total, page, pageSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("mine")]
|
[HttpPost("mine")]
|
||||||
@@ -144,15 +155,24 @@ public sealed class TeacherCourseApplicationsController(
|
|||||||
public async Task<ActionResult> GetReviews(
|
public async Task<ActionResult> GetReviews(
|
||||||
Guid? academicTermId,
|
Guid? academicTermId,
|
||||||
TeacherCourseApplicationStatus? status,
|
TeacherCourseApplicationStatus? status,
|
||||||
CancellationToken cancellationToken)
|
int page = 1,
|
||||||
|
int pageSize = 20,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
|
if (page < 1 || pageSize is < 1 or > 100)
|
||||||
|
return ValidationProblem("页码必须大于 0,且每页条数应在 1 至 100 之间。");
|
||||||
|
|
||||||
var source = ScopedApplications().AsNoTracking();
|
var source = ScopedApplications().AsNoTracking();
|
||||||
if (academicTermId.HasValue)
|
if (academicTermId.HasValue)
|
||||||
source = source.Where(x => x.AcademicTermId == academicTermId);
|
source = source.Where(x => x.AcademicTermId == academicTermId);
|
||||||
if (status.HasValue) source = source.Where(x => x.Status == status);
|
if (status.HasValue) source = source.Where(x => x.Status == status);
|
||||||
return Ok(await source
|
var total = await source.CountAsync(cancellationToken);
|
||||||
|
var items = await source
|
||||||
.OrderBy(x => x.Status)
|
.OrderBy(x => x.Status)
|
||||||
.ThenByDescending(x => x.SubmittedAt)
|
.ThenByDescending(x => x.SubmittedAt)
|
||||||
|
.ThenBy(x => x.Id)
|
||||||
|
.Skip((page - 1) * pageSize)
|
||||||
|
.Take(pageSize)
|
||||||
.Select(x => new
|
.Select(x => new
|
||||||
{
|
{
|
||||||
x.Id,
|
x.Id,
|
||||||
@@ -172,7 +192,8 @@ public sealed class TeacherCourseApplicationsController(
|
|||||||
x.SubmittedAt,
|
x.SubmittedAt,
|
||||||
x.ReviewedAt
|
x.ReviewedAt
|
||||||
})
|
})
|
||||||
.ToListAsync(cancellationToken));
|
.ToListAsync(cancellationToken);
|
||||||
|
return Ok(new PagedResult<object>(items, total, page, pageSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("assignment-options")]
|
[HttpGet("assignment-options")]
|
||||||
|
|||||||
Loaded 3 of 6 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user