自动排课:保留手工安排,按教师、行政班、周次、节次、容量和场地约束补排。
课程约束:可限定校区、教学楼、指定教室、允许上课日、最早/最晚节次。 无教室课程:教室可为空,但仍校验教师和班级冲突。 作息维护:按学期维护节次、上下课时间和启用状态。 发布保护:发布前重新检查全部约束,并阻止学时未排满的课表发布。 工作台升级:增加“排课规则与作息”“自动排课”入口,自动生成后仍支持手工微调。 同时兼容 SQLite 和 MySQL,已生成正式迁移。
This commit is contained in:
@@ -19,6 +19,8 @@ public sealed class DevelopmentSqliteMigrator(
|
||||
private const string DegreeAwardsMigration = "20260724_11_degree_awards";
|
||||
private const string GraduationClearanceMigration = "20260724_12_graduation_clearance";
|
||||
private const string CourseCategoriesMigration = "20260724_13_course_categories";
|
||||
private const string SchedulingOptimizationMigration =
|
||||
"20260724_14_scheduling_optimization";
|
||||
|
||||
public async Task MigrateAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -107,6 +109,18 @@ public sealed class DevelopmentSqliteMigrator(
|
||||
"ALTER TABLE", StringComparison.OrdinalIgnoreCase))
|
||||
: CourseCategoriesStatements,
|
||||
cancellationToken);
|
||||
var schedulingOptimizationExists = await db.Database
|
||||
.SqlQueryRaw<int>(
|
||||
"""
|
||||
SELECT COUNT(*) AS "Value"
|
||||
FROM sqlite_master
|
||||
WHERE type = 'table' AND name = 'ScheduleTimeSlots'
|
||||
""")
|
||||
.AnyAsync(value => value > 0, cancellationToken);
|
||||
await ApplyMigrationAsync(
|
||||
SchedulingOptimizationMigration,
|
||||
schedulingOptimizationExists ? [] : SchedulingOptimizationStatements,
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
private async Task ApplyMigrationAsync(
|
||||
@@ -814,4 +828,129 @@ public sealed class DevelopmentSqliteMigrator(
|
||||
ON "Courses" ("CourseCategoryId");
|
||||
"""
|
||||
];
|
||||
|
||||
private static readonly string[] SchedulingOptimizationStatements =
|
||||
[
|
||||
"""
|
||||
CREATE TABLE "ScheduleEntries_New" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ScheduleEntries" PRIMARY KEY,
|
||||
"SchedulePlanId" TEXT NOT NULL,
|
||||
"TeachingTaskId" TEXT NOT NULL,
|
||||
"ClassroomId" TEXT NULL,
|
||||
"DayOfWeek" INTEGER NOT NULL,
|
||||
"StartPeriod" INTEGER NOT NULL,
|
||||
"PeriodCount" INTEGER NOT NULL,
|
||||
"StartWeek" INTEGER NOT NULL,
|
||||
"EndWeek" INTEGER NOT NULL,
|
||||
"WeekPattern" INTEGER NOT NULL,
|
||||
"Notes" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
CONSTRAINT "FK_ScheduleEntries_SchedulePlans_SchedulePlanId"
|
||||
FOREIGN KEY ("SchedulePlanId") REFERENCES "SchedulePlans" ("Id")
|
||||
ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ScheduleEntries_TeachingTasks_TeachingTaskId"
|
||||
FOREIGN KEY ("TeachingTaskId") REFERENCES "TeachingTasks" ("Id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT "FK_ScheduleEntries_Classrooms_ClassroomId"
|
||||
FOREIGN KEY ("ClassroomId") REFERENCES "Classrooms" ("Id")
|
||||
ON DELETE SET NULL
|
||||
);
|
||||
""",
|
||||
"""
|
||||
INSERT INTO "ScheduleEntries_New"
|
||||
SELECT "Id", "SchedulePlanId", "TeachingTaskId", "ClassroomId",
|
||||
"DayOfWeek", "StartPeriod", "PeriodCount", "StartWeek", "EndWeek",
|
||||
"WeekPattern", "Notes", "CreatedAt", "UpdatedAt"
|
||||
FROM "ScheduleEntries";
|
||||
""",
|
||||
"""DROP TABLE "ScheduleEntries";""",
|
||||
"""ALTER TABLE "ScheduleEntries_New" RENAME TO "ScheduleEntries";""",
|
||||
"""
|
||||
CREATE INDEX "IX_ScheduleEntries_SchedulePlanId_DayOfWeek_StartPeriod"
|
||||
ON "ScheduleEntries" ("SchedulePlanId", "DayOfWeek", "StartPeriod");
|
||||
""",
|
||||
"""
|
||||
CREATE INDEX "IX_ScheduleEntries_TeachingTaskId"
|
||||
ON "ScheduleEntries" ("TeachingTaskId");
|
||||
""",
|
||||
"""
|
||||
CREATE INDEX "IX_ScheduleEntries_ClassroomId"
|
||||
ON "ScheduleEntries" ("ClassroomId");
|
||||
""",
|
||||
"""
|
||||
CREATE TABLE "ScheduleTimeSlots" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_ScheduleTimeSlots" PRIMARY KEY,
|
||||
"AcademicTermId" TEXT NOT NULL,
|
||||
"PeriodNumber" INTEGER NOT NULL,
|
||||
"Name" TEXT NOT NULL,
|
||||
"StartsAt" TEXT NOT NULL,
|
||||
"EndsAt" TEXT NOT NULL,
|
||||
"IsEnabled" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
CONSTRAINT "FK_ScheduleTimeSlots_AcademicTerms_AcademicTermId"
|
||||
FOREIGN KEY ("AcademicTermId") REFERENCES "AcademicTerms" ("Id")
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
""",
|
||||
"""
|
||||
CREATE UNIQUE INDEX "IX_ScheduleTimeSlots_AcademicTermId_PeriodNumber"
|
||||
ON "ScheduleTimeSlots" ("AcademicTermId", "PeriodNumber");
|
||||
""",
|
||||
"""
|
||||
CREATE TABLE "TeachingTaskScheduleConstraints" (
|
||||
"Id" TEXT NOT NULL CONSTRAINT "PK_TeachingTaskScheduleConstraints" PRIMARY KEY,
|
||||
"TeachingTaskId" TEXT NOT NULL,
|
||||
"RequiresClassroom" INTEGER NOT NULL,
|
||||
"RequiredCampusId" TEXT NULL,
|
||||
"RequiredBuildingId" TEXT NULL,
|
||||
"AllowedDayOfWeeks" TEXT NULL,
|
||||
"EarliestPeriod" INTEGER NULL,
|
||||
"LatestPeriod" INTEGER NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
CONSTRAINT "FK_TeachingTaskScheduleConstraints_TeachingTasks_TeachingTaskId"
|
||||
FOREIGN KEY ("TeachingTaskId") REFERENCES "TeachingTasks" ("Id")
|
||||
ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_TeachingTaskScheduleConstraints_Campuses_RequiredCampusId"
|
||||
FOREIGN KEY ("RequiredCampusId") REFERENCES "Campuses" ("Id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT "FK_TeachingTaskScheduleConstraints_Buildings_RequiredBuildingId"
|
||||
FOREIGN KEY ("RequiredBuildingId") REFERENCES "Buildings" ("Id")
|
||||
ON DELETE RESTRICT
|
||||
);
|
||||
""",
|
||||
"""
|
||||
CREATE UNIQUE INDEX "IX_TeachingTaskScheduleConstraints_TeachingTaskId"
|
||||
ON "TeachingTaskScheduleConstraints" ("TeachingTaskId");
|
||||
""",
|
||||
"""
|
||||
CREATE INDEX "IX_TeachingTaskScheduleConstraints_RequiredCampusId"
|
||||
ON "TeachingTaskScheduleConstraints" ("RequiredCampusId");
|
||||
""",
|
||||
"""
|
||||
CREATE INDEX "IX_TeachingTaskScheduleConstraints_RequiredBuildingId"
|
||||
ON "TeachingTaskScheduleConstraints" ("RequiredBuildingId");
|
||||
""",
|
||||
"""
|
||||
CREATE TABLE "TeachingTaskAllowedClassrooms" (
|
||||
"TeachingTaskScheduleConstraintId" TEXT NOT NULL,
|
||||
"ClassroomId" TEXT NOT NULL,
|
||||
CONSTRAINT "PK_TeachingTaskAllowedClassrooms"
|
||||
PRIMARY KEY ("TeachingTaskScheduleConstraintId", "ClassroomId"),
|
||||
CONSTRAINT "FK_TeachingTaskAllowedClassrooms_Constraints"
|
||||
FOREIGN KEY ("TeachingTaskScheduleConstraintId")
|
||||
REFERENCES "TeachingTaskScheduleConstraints" ("Id")
|
||||
ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_TeachingTaskAllowedClassrooms_Classrooms_ClassroomId"
|
||||
FOREIGN KEY ("ClassroomId") REFERENCES "Classrooms" ("Id")
|
||||
ON DELETE RESTRICT
|
||||
);
|
||||
""",
|
||||
"""
|
||||
CREATE INDEX "IX_TeachingTaskAllowedClassrooms_ClassroomId"
|
||||
ON "TeachingTaskAllowedClassrooms" ("ClassroomId");
|
||||
"""
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user