成绩+点名
This commit is contained in:
@@ -4,6 +4,7 @@ using Jiaowu.Api.Domain.Academic;
|
||||
using Jiaowu.Api.Domain.Identity;
|
||||
using Jiaowu.Api.Infrastructure.Auth;
|
||||
using Jiaowu.Api.Infrastructure.CourseSelection;
|
||||
using Jiaowu.Api.Infrastructure.Excel;
|
||||
using Jiaowu.Api.Infrastructure.Persistence;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
@@ -868,6 +869,100 @@ public sealed class CourseSelectionsController(
|
||||
return await SaveAsync(id, false, cancellationToken);
|
||||
}
|
||||
|
||||
[HttpGet("my-offerings")]
|
||||
[Authorize(Roles = SystemRoles.Teacher)]
|
||||
public async Task<ActionResult> GetMyOfferings(
|
||||
Guid? academicTermId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var userId = currentUserDataScope.Current.UserId;
|
||||
var offeringsQuery = db.CourseSelectionOfferings.AsNoTracking()
|
||||
.Where(x =>
|
||||
x.TeachingTask!.Teachers.Any(t =>
|
||||
t.Teacher!.UserId == userId) &&
|
||||
x.CourseSelectionRound!.Status != CourseSelectionRoundStatus.Draft);
|
||||
if (academicTermId.HasValue)
|
||||
offeringsQuery = offeringsQuery.Where(x =>
|
||||
x.CourseSelectionRound!.AcademicTermId == academicTermId);
|
||||
var offerings = await offeringsQuery
|
||||
.OrderByDescending(x => x.CourseSelectionRound!.AcademicTerm!.StartDate)
|
||||
.ThenBy(x => x.TeachingTask!.Course!.Code)
|
||||
.Select(x => new
|
||||
{
|
||||
x.Id,
|
||||
x.TeachingTaskId,
|
||||
x.TeachingTask!.TaskNumber,
|
||||
TaskName = x.TeachingTask.Name,
|
||||
x.TeachingTask.AcademicTermId,
|
||||
TermName = x.TeachingTask.AcademicTerm!.Name,
|
||||
CourseCode = x.TeachingTask.Course!.Code,
|
||||
CourseName = x.TeachingTask.Course.Name,
|
||||
RoundName = x.CourseSelectionRound!.Name,
|
||||
x.Capacity,
|
||||
EnrolledCount = x.Enrollments.Count(e =>
|
||||
e.Status == CourseEnrollmentStatus.Enrolled),
|
||||
RoundStatus = x.CourseSelectionRound.Status
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
return Ok(offerings);
|
||||
}
|
||||
|
||||
[HttpGet("offerings/{id:guid}/roster/export.xlsx")]
|
||||
[Authorize(Roles = RosterReaders)]
|
||||
public async Task<ActionResult> ExportRoster(
|
||||
Guid id,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var offering = await db.CourseSelectionOfferings.AsNoTracking()
|
||||
.Where(x => x.Id == id)
|
||||
.Select(x => new
|
||||
{
|
||||
x.Id,
|
||||
x.TeachingTask!.TaskNumber,
|
||||
CourseCode = x.TeachingTask.Course!.Code,
|
||||
CourseName = x.TeachingTask.Course.Name,
|
||||
RoundName = x.CourseSelectionRound!.Name,
|
||||
CollegeId = x.TeachingTask.Course.CollegeId,
|
||||
TeacherUserIds = x.TeachingTask.Teachers
|
||||
.Select(item => item.Teacher!.UserId)
|
||||
})
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
if (offering is null) return NotFound();
|
||||
|
||||
var scope = currentUserDataScope.Current;
|
||||
var isAssignedTeacher =
|
||||
scope.IsInRole(SystemRoles.Teacher) &&
|
||||
offering.TeacherUserIds.Contains(scope.UserId);
|
||||
if (!isAssignedTeacher && !scope.CanAccessCollege(offering.CollegeId))
|
||||
return Forbid();
|
||||
|
||||
var students = await db.CourseEnrollments.AsNoTracking()
|
||||
.Where(x =>
|
||||
x.CourseSelectionOfferingId == id &&
|
||||
x.Status == CourseEnrollmentStatus.Enrolled)
|
||||
.OrderBy(x => x.Student!.StudentNumber)
|
||||
.Select(x => new
|
||||
{
|
||||
x.Student!.StudentNumber,
|
||||
x.Student.Name,
|
||||
ClassName = x.Student.AdministrativeClass!.Name,
|
||||
MajorName = x.Student.AdministrativeClass.Major!.Name,
|
||||
x.EnrolledAt
|
||||
})
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var bytes = ExcelWorkbookHelper.Create(
|
||||
"选课名单",
|
||||
["学号", "姓名", "班级", "专业", "选课时间"],
|
||||
students.Select(s => new List<object?>
|
||||
{
|
||||
s.StudentNumber, s.Name, s.ClassName, s.MajorName,
|
||||
s.EnrolledAt.ToString("yyyy-MM-dd HH:mm")
|
||||
}).ToList<IReadOnlyList<object?>>());
|
||||
return File(bytes, ExcelWorkbookHelper.ContentType,
|
||||
$"选课名单-{offering.TaskNumber}.xlsx");
|
||||
}
|
||||
|
||||
private IQueryable<CourseSelectionOffering> ScopedOfferings()
|
||||
{
|
||||
var source = db.CourseSelectionOfferings.AsQueryable();
|
||||
|
||||
Reference in New Issue
Block a user