新增按学期配置的“自动排课优化”页签,可调教师/行政班同日集中、行政班空档与连堂、首末节、教室容量冗余等权重。
自动排课在所有硬约束满足后,对候选排法应用这些软约束评分;不会改动既有课程或已发布课表。
This commit is contained in:
1 parent
8074d59e82
commit
0513e251df
10 files changed
+7588
-2
No files matched your search
@@ -14,6 +14,46 @@ namespace Jiaowu.Api.Controllers;
|
||||
[Route("api/schedules")]
|
||||
public sealed class ScheduleSettingsController(AppDbContext db, IAppCache cache) : ControllerBase
|
||||
{
|
||||
[HttpGet("optimization-settings")]
|
||||
public async Task<ActionResult> GetOptimizationSettings(
|
||||
Guid academicTermId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var settings = await db.ScheduleOptimizationSettings.AsNoTracking()
|
||||
.FirstOrDefaultAsync(x => x.AcademicTermId == academicTermId, cancellationToken)
|
||||
?? ScheduleOptimizationSettings.CreateDefault(academicTermId);
|
||||
return Ok(ToOptimizationSettingsResponse(settings));
|
||||
}
|
||||
|
||||
[HttpPut("optimization-settings/{academicTermId:guid}")]
|
||||
public async Task<ActionResult> SaveOptimizationSettings(
|
||||
Guid academicTermId,
|
||||
ScheduleOptimizationSettingsRequest request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
if (!await db.AcademicTerms.AnyAsync(
|
||||
x => x.Id == academicTermId && x.IsEnabled,
|
||||
cancellationToken))
|
||||
return ValidationProblem("学期不存在或已停用。");
|
||||
|
||||
var settings = await db.ScheduleOptimizationSettings
|
||||
.FirstOrDefaultAsync(x => x.AcademicTermId == academicTermId, cancellationToken);
|
||||
if (settings is null)
|
||||
{
|
||||
settings = ScheduleOptimizationSettings.CreateDefault(academicTermId);
|
||||
db.ScheduleOptimizationSettings.Add(settings);
|
||||
}
|
||||
settings.TeacherSameDayWeight = request.TeacherSameDayWeight;
|
||||
settings.ClassSameDayWeight = request.ClassSameDayWeight;
|
||||
settings.ClassGapWeight = request.ClassGapWeight;
|
||||
settings.ConsecutiveClassWeight = request.ConsecutiveClassWeight;
|
||||
settings.EarlyPeriodPenalty = request.EarlyPeriodPenalty;
|
||||
settings.LatePeriodPenalty = request.LatePeriodPenalty;
|
||||
settings.RoomCapacityWasteWeight = request.RoomCapacityWasteWeight;
|
||||
await db.SaveChangesAsync(cancellationToken);
|
||||
return Ok(ToOptimizationSettingsResponse(settings));
|
||||
}
|
||||
|
||||
[HttpGet("time-slots")]
|
||||
public async Task<ActionResult> GetTimeSlots(
|
||||
Guid academicTermId,
|
||||
@@ -32,6 +72,17 @@ public sealed class ScheduleSettingsController(AppDbContext db, IAppCache cache)
|
||||
})
|
||||
.ToListAsync(cancellationToken));
|
||||
|
||||
private static object ToOptimizationSettingsResponse(ScheduleOptimizationSettings settings) => new
|
||||
{
|
||||
settings.TeacherSameDayWeight,
|
||||
settings.ClassSameDayWeight,
|
||||
settings.ClassGapWeight,
|
||||
settings.ConsecutiveClassWeight,
|
||||
settings.EarlyPeriodPenalty,
|
||||
settings.LatePeriodPenalty,
|
||||
settings.RoomCapacityWasteWeight
|
||||
};
|
||||
|
||||
[HttpPut("time-slots/{academicTermId:guid}")]
|
||||
public async Task<ActionResult> ReplaceTimeSlots(
|
||||
Guid academicTermId,
|
||||
@@ -544,6 +595,15 @@ public sealed record ScheduleTimeSlotRequest(
|
||||
TimeOnly EndsAt,
|
||||
bool IsEnabled);
|
||||
|
||||
public sealed record ScheduleOptimizationSettingsRequest(
|
||||
[Range(0, 10_000)] int TeacherSameDayWeight,
|
||||
[Range(0, 10_000)] int ClassSameDayWeight,
|
||||
[Range(0, 10_000)] int ClassGapWeight,
|
||||
[Range(0, 10_000)] int ConsecutiveClassWeight,
|
||||
[Range(0, 10_000)] int EarlyPeriodPenalty,
|
||||
[Range(0, 10_000)] int LatePeriodPenalty,
|
||||
[Range(0, 10_000)] int RoomCapacityWasteWeight);
|
||||
|
||||
public sealed record TeachingTaskScheduleConstraintRequest(
|
||||
TeachingTaskSchedulingMode SchedulingMode,
|
||||
bool RequiresClassroom,
|
||||
|
||||
@@ -43,6 +43,26 @@ public sealed class ScheduleTimeSlot : EntityBase
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 学期级自动排课的软约束权重。所有值为 0 时表示关闭对应偏好;
|
||||
/// 硬约束(冲突、容量和课程可用范围)始终优先于这些设置。
|
||||
/// </summary>
|
||||
public sealed class ScheduleOptimizationSettings : EntityBase
|
||||
{
|
||||
public Guid AcademicTermId { get; set; }
|
||||
public AcademicTerm? AcademicTerm { get; set; }
|
||||
public int TeacherSameDayWeight { get; set; } = 120;
|
||||
public int ClassSameDayWeight { get; set; } = 100;
|
||||
public int ClassGapWeight { get; set; } = 240;
|
||||
public int ConsecutiveClassWeight { get; set; } = 60;
|
||||
public int EarlyPeriodPenalty { get; set; } = 30;
|
||||
public int LatePeriodPenalty { get; set; } = 30;
|
||||
public int RoomCapacityWasteWeight { get; set; } = 1;
|
||||
|
||||
public static ScheduleOptimizationSettings CreateDefault(Guid academicTermId) =>
|
||||
new() { AcademicTermId = academicTermId };
|
||||
}
|
||||
|
||||
public sealed class TeachingTaskScheduleConstraint : EntityBase
|
||||
{
|
||||
public Guid TeachingTaskId { get; set; }
|
||||
|
||||
@@ -37,6 +37,8 @@ public sealed class AppDbContext(DbContextOptions<AppDbContext> options)
|
||||
public DbSet<ScheduleEntry> ScheduleEntries => Set<ScheduleEntry>();
|
||||
public DbSet<PublishedScheduleOccurrence> PublishedScheduleOccurrences => Set<PublishedScheduleOccurrence>();
|
||||
public DbSet<ScheduleTimeSlot> ScheduleTimeSlots => Set<ScheduleTimeSlot>();
|
||||
public DbSet<ScheduleOptimizationSettings> ScheduleOptimizationSettings =>
|
||||
Set<ScheduleOptimizationSettings>();
|
||||
public DbSet<TeachingTaskScheduleConstraint> TeachingTaskScheduleConstraints =>
|
||||
Set<TeachingTaskScheduleConstraint>();
|
||||
public DbSet<TeachingTaskAllowedClassroom> TeachingTaskAllowedClassrooms =>
|
||||
@@ -518,6 +520,15 @@ public sealed class AppDbContext(DbContextOptions<AppDbContext> options)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
builder.Entity<ScheduleOptimizationSettings>(entity =>
|
||||
{
|
||||
entity.HasIndex(x => x.AcademicTermId).IsUnique();
|
||||
entity.HasOne(x => x.AcademicTerm)
|
||||
.WithMany()
|
||||
.HasForeignKey(x => x.AcademicTermId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
builder.Entity<TeachingTaskScheduleConstraint>(entity =>
|
||||
{
|
||||
entity.Property(x => x.AllowedDayOfWeeks).HasMaxLength(20);
|
||||
|
||||
Loaded 3 of 10 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user