新增每门课程的“优先上课日 / 偏好节次范围”,与硬性可排范围分离。

遗传算法在满足冲突、容量、场地等硬约束后,优先满足课程偏好;偏好无法满足时仍会安排可行课次。
管理员可通过“课程偏好权重”控制偏好的影响程度。
修复遗传适应度:教室容量冗余、同一任务分散、日负载和实验场地偏好现在都会实际参与种群评分
This commit is contained in:
biss committed 2026-08-17 11:10:49 +08:00
1 parent 94bc064697
commit c4649f9cdc
10 files changed
+7403 -11

No files matched your search

@@ -50,6 +50,7 @@ public sealed class ScheduleSettingsController(AppDbContext db, IAppCache cache)
settings.EarlyPeriodPenalty = request.EarlyPeriodPenalty;
settings.LatePeriodPenalty = request.LatePeriodPenalty;
settings.RoomCapacityWasteWeight = request.RoomCapacityWasteWeight;
settings.CoursePreferenceWeight = request.CoursePreferenceWeight;
await db.SaveChangesAsync(cancellationToken);
return Ok(ToOptimizationSettingsResponse(settings));
}
@@ -80,7 +81,8 @@ public sealed class ScheduleSettingsController(AppDbContext db, IAppCache cache)
settings.ConsecutiveClassWeight,
settings.EarlyPeriodPenalty,
settings.LatePeriodPenalty,
settings.RoomCapacityWasteWeight
settings.RoomCapacityWasteWeight,
settings.CoursePreferenceWeight
};
[HttpPut("time-slots/{academicTermId:guid}")]
@@ -189,6 +191,9 @@ public sealed class ScheduleSettingsController(AppDbContext db, IAppCache cache)
AllowedDayOfWeeks = ParseDays(constraint?.AllowedDayOfWeeks),
constraint?.EarliestPeriod,
constraint?.LatestPeriod,
PreferredDayOfWeeks = ParseDays(constraint?.PreferredDayOfWeeks),
constraint?.PreferredEarliestPeriod,
constraint?.PreferredLatestPeriod,
AllowedClassroomIds = constraint?.AllowedClassrooms
.Select(x => x.ClassroomId) ?? [],
AllowedExperimentClassroomIds = constraint?.AllowedExperimentClassrooms
@@ -210,6 +215,12 @@ public sealed class ScheduleSettingsController(AppDbContext db, IAppCache cache)
request.LatestPeriod.HasValue &&
request.EarliestPeriod > request.LatestPeriod)
return ValidationProblem("最早节次不能晚于最晚节次。");
if (request.PreferredDayOfWeeks?.Any(day => day is < 1 or > 7) == true)
return ValidationProblem("偏好上课日必须位于星期一至星期日。");
if (request.PreferredEarliestPeriod.HasValue &&
request.PreferredLatestPeriod.HasValue &&
request.PreferredEarliestPeriod > request.PreferredLatestPeriod)
return ValidationProblem("偏好最早节次不能晚于偏好最晚节次。");
if (!Enum.IsDefined(request.SchedulingMode))
return ValidationProblem("授课方式无效。");
var task = await db.TeachingTasks
@@ -322,6 +333,11 @@ public sealed class ScheduleSettingsController(AppDbContext db, IAppCache cache)
: string.Join(',', request.AllowedDayOfWeeks.Distinct().Order());
constraint.EarliestPeriod = request.EarliestPeriod;
constraint.LatestPeriod = request.LatestPeriod;
constraint.PreferredDayOfWeeks = request.PreferredDayOfWeeks?.Count > 0
? string.Join(',', request.PreferredDayOfWeeks.Distinct().Order())
: null;
constraint.PreferredEarliestPeriod = request.PreferredEarliestPeriod;
constraint.PreferredLatestPeriod = request.PreferredLatestPeriod;
constraint.AllowedExperimentVenueNatures = request.AllowedExperimentVenueNatures;
db.TeachingTaskAllowedClassrooms.RemoveRange(constraint.AllowedClassrooms);
db.TeachingTaskAllowedExperimentClassrooms.RemoveRange(constraint.AllowedExperimentClassrooms);
@@ -566,6 +582,9 @@ public sealed class ScheduleSettingsController(AppDbContext db, IAppCache cache)
constraint.AllowedDayOfWeeks = null;
constraint.EarliestPeriod = null;
constraint.LatestPeriod = null;
constraint.PreferredDayOfWeeks = null;
constraint.PreferredEarliestPeriod = null;
constraint.PreferredLatestPeriod = null;
db.TeachingTaskAllowedClassrooms.RemoveRange(constraint.AllowedClassrooms);
db.TeachingTaskAllowedExperimentClassrooms.RemoveRange(constraint.AllowedExperimentClassrooms);
constraint.AllowedClassrooms = [];
@@ -602,7 +621,8 @@ public sealed record ScheduleOptimizationSettingsRequest(
[Range(0, 10_000)] int ConsecutiveClassWeight,
[Range(0, 10_000)] int EarlyPeriodPenalty,
[Range(0, 10_000)] int LatePeriodPenalty,
[Range(0, 10_000)] int RoomCapacityWasteWeight);
[Range(0, 10_000)] int RoomCapacityWasteWeight,
[Range(0, 10_000)] int CoursePreferenceWeight = 180);
public sealed record TeachingTaskScheduleConstraintRequest(
TeachingTaskSchedulingMode SchedulingMode,
@@ -616,7 +636,10 @@ public sealed record TeachingTaskScheduleConstraintRequest(
TeachingVenueNature AllowedExperimentVenueNatures = 0,
IReadOnlyList<Guid>? AllowedExperimentClassroomIds = null,
Guid? ExperimentRequiredCampusId = null,
Guid? ExperimentRequiredBuildingId = null);
Guid? ExperimentRequiredBuildingId = null,
IReadOnlyList<int>? PreferredDayOfWeeks = null,
[Range(1, 30)] int? PreferredEarliestPeriod = null,
[Range(1, 30)] int? PreferredLatestPeriod = null);
public sealed record TeachingTaskScheduleConstraintBatchRequest(
Guid AcademicTermId,
@@ -58,6 +58,7 @@ public sealed class ScheduleOptimizationSettings : EntityBase
public int EarlyPeriodPenalty { get; set; } = 30;
public int LatePeriodPenalty { get; set; } = 30;
public int RoomCapacityWasteWeight { get; set; } = 1;
public int CoursePreferenceWeight { get; set; } = 180;
public static ScheduleOptimizationSettings CreateDefault(Guid academicTermId) =>
new() { AcademicTermId = academicTermId };
@@ -79,6 +80,9 @@ public sealed class TeachingTaskScheduleConstraint : EntityBase
public string? AllowedDayOfWeeks { get; set; }
public int? EarliestPeriod { get; set; }
public int? LatestPeriod { get; set; }
public string? PreferredDayOfWeeks { get; set; }
public int? PreferredEarliestPeriod { get; set; }
public int? PreferredLatestPeriod { get; set; }
public TeachingVenueNature AllowedExperimentVenueNatures { get; set; }
public ICollection<TeachingTaskAllowedClassroom> AllowedClassrooms { get; set; } = [];
public ICollection<TeachingTaskAllowedExperimentClassroom> AllowedExperimentClassrooms { get; set; } = [];
@@ -532,6 +532,7 @@ public sealed class AppDbContext(DbContextOptions<AppDbContext> options)
builder.Entity<TeachingTaskScheduleConstraint>(entity =>
{
entity.Property(x => x.AllowedDayOfWeeks).HasMaxLength(20);
entity.Property(x => x.PreferredDayOfWeeks).HasMaxLength(20);
entity.HasIndex(x => x.TeachingTaskId).IsUnique();
entity.HasOne(x => x.TeachingTask)
.WithMany()
Loaded 3 of 10 files, more files were not shown because too many files have changed in this diff. Show more