自动排课:保留手工安排,按教师、行政班、周次、节次、容量和场地约束补排。

课程约束:可限定校区、教学楼、指定教室、允许上课日、最早/最晚节次。
无教室课程:教室可为空,但仍校验教师和班级冲突。
作息维护:按学期维护节次、上下课时间和启用状态。
发布保护:发布前重新检查全部约束,并阻止学时未排满的课表发布。
工作台升级:增加“排课规则与作息”“自动排课”入口,自动生成后仍支持手工微调。
同时兼容 SQLite 和 MySQL,已生成正式迁移。
This commit is contained in:
2026-07-24 19:19:18 +08:00 Unverified
parent d7cf3f9e76
commit 6538b6080a
19 changed files with 4344 additions and 37 deletions
@@ -29,6 +29,11 @@ public sealed class AppDbContext(DbContextOptions<AppDbContext> options)
public DbSet<TeachingTaskClass> TeachingTaskClasses => Set<TeachingTaskClass>();
public DbSet<SchedulePlan> SchedulePlans => Set<SchedulePlan>();
public DbSet<ScheduleEntry> ScheduleEntries => Set<ScheduleEntry>();
public DbSet<ScheduleTimeSlot> ScheduleTimeSlots => Set<ScheduleTimeSlot>();
public DbSet<TeachingTaskScheduleConstraint> TeachingTaskScheduleConstraints =>
Set<TeachingTaskScheduleConstraint>();
public DbSet<TeachingTaskAllowedClassroom> TeachingTaskAllowedClassrooms =>
Set<TeachingTaskAllowedClassroom>();
public DbSet<CourseSelectionRound> CourseSelectionRounds =>
Set<CourseSelectionRound>();
public DbSet<CourseSelectionOffering> CourseSelectionOfferings =>
@@ -293,6 +298,51 @@ public sealed class AppDbContext(DbContextOptions<AppDbContext> options)
.WithMany()
.HasForeignKey(x => x.TeachingTaskId)
.OnDelete(DeleteBehavior.Restrict);
entity.HasOne(x => x.Classroom)
.WithMany()
.HasForeignKey(x => x.ClassroomId)
.OnDelete(DeleteBehavior.SetNull);
});
builder.Entity<ScheduleTimeSlot>(entity =>
{
entity.Property(x => x.Name).HasMaxLength(40);
entity.HasIndex(x => new { x.AcademicTermId, x.PeriodNumber }).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);
entity.HasIndex(x => x.TeachingTaskId).IsUnique();
entity.HasOne(x => x.TeachingTask)
.WithMany()
.HasForeignKey(x => x.TeachingTaskId)
.OnDelete(DeleteBehavior.Cascade);
entity.HasOne(x => x.RequiredCampus)
.WithMany()
.HasForeignKey(x => x.RequiredCampusId)
.OnDelete(DeleteBehavior.Restrict);
entity.HasOne(x => x.RequiredBuilding)
.WithMany()
.HasForeignKey(x => x.RequiredBuildingId)
.OnDelete(DeleteBehavior.Restrict);
});
builder.Entity<TeachingTaskAllowedClassroom>(entity =>
{
entity.HasKey(x => new
{
x.TeachingTaskScheduleConstraintId,
x.ClassroomId
});
entity.HasOne(x => x.TeachingTaskScheduleConstraint)
.WithMany(x => x.AllowedClassrooms)
.HasForeignKey(x => x.TeachingTaskScheduleConstraintId)
.OnDelete(DeleteBehavior.Cascade);
entity.HasOne(x => x.Classroom)
.WithMany()
.HasForeignKey(x => x.ClassroomId)