排课
Build and publish Jiaowu packages and container image / Test, package and publish (push) Successful in 32m28s
Build and publish Jiaowu packages and container image / Test, package and publish (push) Successful in 32m28s
This commit is contained in:
@@ -11,8 +11,14 @@ public sealed class ExamArrangementService(AppDbContext db)
|
||||
|
||||
public async Task<ExamArrangementResult> ArrangeAsync(
|
||||
Guid planId,
|
||||
IReadOnlyCollection<Guid>? requestedSessionIds,
|
||||
bool assignClassrooms,
|
||||
bool assignInvigilators,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (!assignClassrooms && !assignInvigilators)
|
||||
return ExamArrangementResult.Fail("请至少选择分配考场或分配监考教师。");
|
||||
|
||||
var plan = await db.ExamPlans
|
||||
.Include(x => x.AcademicTerm)
|
||||
.Include(x => x.Sessions)
|
||||
@@ -27,9 +33,23 @@ public sealed class ExamArrangementService(AppDbContext db)
|
||||
if (plan.Status != ExamPlanStatus.Draft)
|
||||
return ExamArrangementResult.Fail("只有草稿状态的考试计划可以自动编排。");
|
||||
|
||||
var sessions = plan.Sessions.ToList();
|
||||
var requestedIds = (requestedSessionIds ?? [])
|
||||
.Distinct()
|
||||
.ToHashSet();
|
||||
if (requestedIds.Count > 100)
|
||||
return ExamArrangementResult.Fail("一次最多处理100个考试场次。");
|
||||
if (requestedIds.Count > 0 &&
|
||||
plan.Sessions.Count(x => requestedIds.Contains(x.Id)) != requestedIds.Count)
|
||||
return ExamArrangementResult.Fail("所选场次不存在或不属于当前考试计划。");
|
||||
|
||||
var sessions = plan.Sessions
|
||||
.Where(x => requestedIds.Count == 0 || requestedIds.Contains(x.Id))
|
||||
.OrderBy(x => x.ExamDate)
|
||||
.ThenBy(x => x.StartPeriod)
|
||||
.ThenByDescending(x => x.RequiredInvigilatorCount)
|
||||
.ToList();
|
||||
if (sessions.Count == 0)
|
||||
return ExamArrangementResult.Fail("考试计划中没有场次。");
|
||||
return ExamArrangementResult.Fail("没有可处理的考试场次。");
|
||||
|
||||
var termId = plan.AcademicTermId;
|
||||
var timeSlots = await db.ScheduleTimeSlots.AsNoTracking()
|
||||
@@ -44,8 +64,8 @@ public sealed class ExamArrangementService(AppDbContext db)
|
||||
|
||||
int assignedRooms = 0;
|
||||
int assignedInvigilators = 0;
|
||||
int skippedRooms = 0;
|
||||
int skippedInvigilators = 0;
|
||||
int unavailableRooms = 0;
|
||||
int unavailableInvigilators = 0;
|
||||
var messages = new List<string>();
|
||||
|
||||
// Track occupied time slots to avoid conflicts
|
||||
@@ -69,7 +89,7 @@ public sealed class ExamArrangementService(AppDbContext db)
|
||||
cancellationToken);
|
||||
|
||||
// ── Auto-assign classroom ──
|
||||
if (!session.ClassroomId.HasValue)
|
||||
if (assignClassrooms && !session.ClassroomId.HasValue)
|
||||
{
|
||||
var room = await FindBestClassroomAsync(
|
||||
session, studentCount, occupiedRooms, cancellationToken);
|
||||
@@ -83,20 +103,15 @@ public sealed class ExamArrangementService(AppDbContext db)
|
||||
}
|
||||
else
|
||||
{
|
||||
skippedRooms++;
|
||||
unavailableRooms++;
|
||||
messages.Add(
|
||||
$"“{session.TeachingTask!.Course!.Name}”:无可用考场(需≥{studentCount}座)");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
skippedRooms++;
|
||||
}
|
||||
|
||||
// ── Auto-assign invigilators ──
|
||||
var currentInvigilatorCount = session.Invigilators.Count;
|
||||
var needed = session.RequiredInvigilatorCount - currentInvigilatorCount;
|
||||
if (needed > 0)
|
||||
if (assignInvigilators && needed > 0)
|
||||
{
|
||||
var courseTeacherIds = session.TeachingTask!.Teachers
|
||||
.Select(x => x.TeacherId).ToHashSet();
|
||||
@@ -116,12 +131,11 @@ public sealed class ExamArrangementService(AppDbContext db)
|
||||
}
|
||||
|
||||
if (newlyAssigned.Count < needed)
|
||||
{
|
||||
unavailableInvigilators += needed - newlyAssigned.Count;
|
||||
messages.Add(
|
||||
$"“{session.TeachingTask!.Course!.Name}”:仅找到{newlyAssigned.Count}/{needed}名监考教师");
|
||||
}
|
||||
else
|
||||
{
|
||||
skippedInvigilators++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,8 +143,9 @@ public sealed class ExamArrangementService(AppDbContext db)
|
||||
|
||||
return new ExamArrangementResult(
|
||||
true,
|
||||
$"{assignedRooms}个考场、{assignedInvigilators}名监考已分配。" +
|
||||
(skippedRooms > 0 ? $" {skippedRooms}个场次无可用考场。" : "") +
|
||||
$"{sessions.Count}个场次处理完成,分配{assignedRooms}个考场、{assignedInvigilators}名监考教师。" +
|
||||
(unavailableRooms > 0 ? $" {unavailableRooms}个场次暂无可用考场。" : "") +
|
||||
(unavailableInvigilators > 0 ? $" 仍缺{unavailableInvigilators}名监考教师。" : "") +
|
||||
(messages.Count > 0 ? $" 详情:{string.Join(";", messages.Take(10))}" : ""));
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,14 @@ public sealed class MakeupExamArrangementService(AppDbContext db)
|
||||
|
||||
public async Task<ExamArrangementResult> ArrangeAsync(
|
||||
Guid planId,
|
||||
IReadOnlyCollection<Guid>? requestedSessionIds,
|
||||
bool assignClassrooms,
|
||||
bool assignInvigilators,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (!assignClassrooms && !assignInvigilators)
|
||||
return ExamArrangementResult.Fail("请至少选择分配考场或分配监考教师。");
|
||||
|
||||
var plan = await db.MakeupExamPlans
|
||||
.Include(x => x.AcademicTerm)
|
||||
.Include(x => x.Sessions)
|
||||
@@ -27,9 +33,23 @@ public sealed class MakeupExamArrangementService(AppDbContext db)
|
||||
if (plan.Status != MakeupExamPlanStatus.Draft)
|
||||
return ExamArrangementResult.Fail("只有草稿状态的补考计划可以自动编排。");
|
||||
|
||||
var sessions = plan.Sessions.ToList();
|
||||
var requestedIds = (requestedSessionIds ?? [])
|
||||
.Distinct()
|
||||
.ToHashSet();
|
||||
if (requestedIds.Count > 100)
|
||||
return ExamArrangementResult.Fail("一次最多处理100个补考场次。");
|
||||
if (requestedIds.Count > 0 &&
|
||||
plan.Sessions.Count(x => requestedIds.Contains(x.Id)) != requestedIds.Count)
|
||||
return ExamArrangementResult.Fail("所选场次不存在或不属于当前补考计划。");
|
||||
|
||||
var sessions = plan.Sessions
|
||||
.Where(x => requestedIds.Count == 0 || requestedIds.Contains(x.Id))
|
||||
.OrderBy(x => x.ExamDate)
|
||||
.ThenBy(x => x.StartPeriod)
|
||||
.ThenByDescending(x => x.RequiredInvigilatorCount)
|
||||
.ToList();
|
||||
if (sessions.Count == 0)
|
||||
return ExamArrangementResult.Fail("补考计划中没有场次。");
|
||||
return ExamArrangementResult.Fail("没有可处理的补考场次。");
|
||||
|
||||
var termId = plan.AcademicTermId;
|
||||
var timeSlots = await db.ScheduleTimeSlots.AsNoTracking()
|
||||
@@ -44,8 +64,8 @@ public sealed class MakeupExamArrangementService(AppDbContext db)
|
||||
|
||||
int assignedRooms = 0;
|
||||
int assignedInvigilators = 0;
|
||||
int skippedRooms = 0;
|
||||
int skippedInvigilators = 0;
|
||||
int unavailableRooms = 0;
|
||||
int unavailableInvigilators = 0;
|
||||
var messages = new List<string>();
|
||||
|
||||
var occupiedRooms = sessions
|
||||
@@ -66,7 +86,7 @@ public sealed class MakeupExamArrangementService(AppDbContext db)
|
||||
.CountAsync(x => x.MakeupExamSessionId == session.Id, cancellationToken);
|
||||
|
||||
// Auto-assign classroom
|
||||
if (!session.ClassroomId.HasValue)
|
||||
if (assignClassrooms && !session.ClassroomId.HasValue)
|
||||
{
|
||||
var room = await FindBestClassroomAsync(
|
||||
session, enrolledCount, occupiedRooms, cancellationToken);
|
||||
@@ -80,20 +100,15 @@ public sealed class MakeupExamArrangementService(AppDbContext db)
|
||||
}
|
||||
else
|
||||
{
|
||||
skippedRooms++;
|
||||
unavailableRooms++;
|
||||
messages.Add(
|
||||
$"\"{session.TeachingTask!.Course!.Name}\":无可用考场(需≥{enrolledCount}座)");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
skippedRooms++;
|
||||
}
|
||||
|
||||
// Auto-assign invigilators
|
||||
var currentInvigilatorCount = session.Invigilators.Count;
|
||||
var needed = session.RequiredInvigilatorCount - currentInvigilatorCount;
|
||||
if (needed > 0)
|
||||
if (assignInvigilators && needed > 0)
|
||||
{
|
||||
var courseTeacherIds = session.TeachingTask!.Teachers
|
||||
.Select(x => x.TeacherId).ToHashSet();
|
||||
@@ -113,12 +128,11 @@ public sealed class MakeupExamArrangementService(AppDbContext db)
|
||||
}
|
||||
|
||||
if (newlyAssigned.Count < needed)
|
||||
{
|
||||
unavailableInvigilators += needed - newlyAssigned.Count;
|
||||
messages.Add(
|
||||
$"\"{session.TeachingTask!.Course!.Name}\":仅找到{newlyAssigned.Count}/{needed}名监考教师");
|
||||
}
|
||||
else
|
||||
{
|
||||
skippedInvigilators++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,8 +140,9 @@ public sealed class MakeupExamArrangementService(AppDbContext db)
|
||||
|
||||
return new ExamArrangementResult(
|
||||
true,
|
||||
$"{assignedRooms}个考场、{assignedInvigilators}名监考已分配。" +
|
||||
(skippedRooms > 0 ? $" {skippedRooms}个场次无可用考场。" : "") +
|
||||
$"{sessions.Count}个场次处理完成,分配{assignedRooms}个考场、{assignedInvigilators}名监考教师。" +
|
||||
(unavailableRooms > 0 ? $" {unavailableRooms}个场次暂无可用考场。" : "") +
|
||||
(unavailableInvigilators > 0 ? $" 仍缺{unavailableInvigilators}名监考教师。" : "") +
|
||||
(messages.Count > 0 ? $" 详情:{string.Join(";", messages.Take(10))}" : ""));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user