成绩+点名

This commit is contained in:
2026-07-25 14:08:50 +08:00 Unverified
parent 7800951aee
commit 36049af692
16 changed files with 1809 additions and 98 deletions
@@ -14,6 +14,7 @@ public sealed class DevelopmentSqliteMigrator(
private const string CourseSelectionMigration = "20260724_06_course_selection";
private const string GradesMigration = "20260724_07_grades";
private const string ExamsMigration = "20260724_08_exams";
private const string AttendanceMigration = "20260724_08b_attendance";
private const string StudentStatusChangesMigration = "20260724_09_student_status_changes";
private const string GraduationAuditsMigration = "20260724_10_graduation_audits";
private const string DegreeAwardsMigration = "20260724_11_degree_awards";
@@ -29,6 +30,8 @@ public sealed class DevelopmentSqliteMigrator(
"20260725_17_teaching_task_scheduling_modes";
private const string SchedulePublishJobsMigration =
"20260725_18_schedule_publish_jobs";
private const string FlexibleGradesMigration =
"20260725_19_flexible_grades";
public async Task MigrateAsync(CancellationToken cancellationToken = default)
{
@@ -177,6 +180,34 @@ public sealed class DevelopmentSqliteMigrator(
SchedulePublishJobsMigration,
schedulePublishJobsExist ? [] : SchedulePublishJobStatements,
cancellationToken);
var midtermWeightExists = await db.Database
.SqlQueryRaw<int>(
"""
SELECT COUNT(*) AS "Value"
FROM pragma_table_info('GradeSheets')
WHERE name = 'MidtermWeight'
""")
.AnyAsync(value => value > 0, cancellationToken);
await ApplyMigrationAsync(
FlexibleGradesMigration,
midtermWeightExists
? FlexibleGradesUpgradeStatements
: FlexibleGradesNewStatements,
cancellationToken);
var attendanceSheetsExist = await db.Database
.SqlQueryRaw<int>(
"""
SELECT COUNT(*) AS "Value"
FROM sqlite_master
WHERE type = 'table' AND name = 'AttendanceSheets'
""")
.AnyAsync(value => value > 0, cancellationToken);
await ApplyMigrationAsync(
AttendanceMigration,
attendanceSheetsExist ? [] : AttendanceStatements,
cancellationToken);
}
private async Task ApplyMigrationAsync(
@@ -629,7 +660,6 @@ public sealed class DevelopmentSqliteMigrator(
"Id" TEXT NOT NULL CONSTRAINT "PK_GradeSheets" PRIMARY KEY,
"TeachingTaskId" TEXT NOT NULL,
"RegularWeight" TEXT NOT NULL,
"MidtermWeight" TEXT NOT NULL,
"FinalWeight" TEXT NOT NULL,
"Status" INTEGER NOT NULL,
"ReviewComment" TEXT NULL,
@@ -656,7 +686,6 @@ public sealed class DevelopmentSqliteMigrator(
"GradeSheetId" TEXT NOT NULL,
"StudentId" TEXT NOT NULL,
"RegularScore" TEXT NULL,
"MidtermScore" TEXT NULL,
"FinalScore" TEXT NULL,
"TotalScore" TEXT NULL,
"GradePoint" TEXT NULL,
@@ -723,6 +752,182 @@ public sealed class DevelopmentSqliteMigrator(
"""CREATE INDEX IF NOT EXISTS "IX_ExamSessionInvigilators_TeacherId" ON "ExamSessionInvigilators" ("TeacherId");"""
];
private static readonly string[] FlexibleGradesNewStatements =
[
"""
CREATE TABLE IF NOT EXISTS "GradeItems" (
"Id" TEXT NOT NULL CONSTRAINT "PK_GradeItems" PRIMARY KEY,
"GradeSheetId" TEXT NOT NULL,
"Name" TEXT NOT NULL,
"Weight" TEXT NOT NULL,
"SortOrder" INTEGER NOT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
CONSTRAINT "FK_GradeItems_GradeSheets_GradeSheetId"
FOREIGN KEY ("GradeSheetId") REFERENCES "GradeSheets" ("Id") ON DELETE CASCADE
);
""",
"""
CREATE INDEX IF NOT EXISTS "IX_GradeItems_GradeSheetId_SortOrder"
ON "GradeItems" ("GradeSheetId", "SortOrder");
""",
"""
CREATE TABLE IF NOT EXISTS "GradeItemScores" (
"GradeRecordId" TEXT NOT NULL,
"GradeItemId" TEXT NOT NULL,
"Score" TEXT NULL,
CONSTRAINT "PK_GradeItemScores" PRIMARY KEY ("GradeRecordId", "GradeItemId"),
CONSTRAINT "FK_GradeItemScores_GradeRecords_GradeRecordId"
FOREIGN KEY ("GradeRecordId") REFERENCES "GradeRecords" ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_GradeItemScores_GradeItems_GradeItemId"
FOREIGN KEY ("GradeItemId") REFERENCES "GradeItems" ("Id") ON DELETE RESTRICT
);
"""
];
private static readonly string[] FlexibleGradesUpgradeStatements =
[
"""
CREATE TABLE "GradeSheets_v2" (
"Id" TEXT NOT NULL CONSTRAINT "PK_GradeSheets" PRIMARY KEY,
"TeachingTaskId" TEXT NOT NULL,
"RegularWeight" TEXT NOT NULL,
"FinalWeight" TEXT NOT NULL,
"Status" INTEGER NOT NULL,
"ReviewComment" TEXT NULL,
"SubmittedAt" TEXT NULL,
"ReviewedAt" TEXT NULL,
"PublishedAt" TEXT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
CONSTRAINT "FK_GradeSheets_TeachingTasks_TeachingTaskId"
FOREIGN KEY ("TeachingTaskId") REFERENCES "TeachingTasks" ("Id") ON DELETE RESTRICT
);
""",
"""
INSERT INTO "GradeSheets_v2" ("Id","TeachingTaskId","RegularWeight","FinalWeight",
"Status","ReviewComment","SubmittedAt","ReviewedAt","PublishedAt","CreatedAt","UpdatedAt")
SELECT "Id","TeachingTaskId","RegularWeight","FinalWeight",
"Status","ReviewComment","SubmittedAt","ReviewedAt","PublishedAt","CreatedAt","UpdatedAt"
FROM "GradeSheets";
""",
"DROP TABLE \"GradeSheets\";",
"ALTER TABLE \"GradeSheets_v2\" RENAME TO \"GradeSheets\";",
"""
CREATE UNIQUE INDEX IF NOT EXISTS "IX_GradeSheets_TeachingTaskId"
ON "GradeSheets" ("TeachingTaskId");
""",
"""
CREATE INDEX IF NOT EXISTS "IX_GradeSheets_Status"
ON "GradeSheets" ("Status");
""",
"""
CREATE TABLE "GradeRecords_v2" (
"Id" TEXT NOT NULL CONSTRAINT "PK_GradeRecords" PRIMARY KEY,
"GradeSheetId" TEXT NOT NULL,
"StudentId" TEXT NOT NULL,
"RegularScore" TEXT NULL,
"FinalScore" TEXT NULL,
"TotalScore" TEXT NULL,
"GradePoint" TEXT NULL,
"ExamStatus" INTEGER NOT NULL,
"Notes" TEXT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
CONSTRAINT "FK_GradeRecords_GradeSheets_GradeSheetId"
FOREIGN KEY ("GradeSheetId") REFERENCES "GradeSheets" ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_GradeRecords_Students_StudentId"
FOREIGN KEY ("StudentId") REFERENCES "Students" ("Id") ON DELETE RESTRICT
);
""",
"""
INSERT INTO "GradeRecords_v2" ("Id","GradeSheetId","StudentId","RegularScore","FinalScore",
"TotalScore","GradePoint","ExamStatus","Notes","CreatedAt","UpdatedAt")
SELECT "Id","GradeSheetId","StudentId","RegularScore","FinalScore",
"TotalScore","GradePoint","ExamStatus","Notes","CreatedAt","UpdatedAt"
FROM "GradeRecords";
""",
"DROP TABLE \"GradeRecords\";",
"ALTER TABLE \"GradeRecords_v2\" RENAME TO \"GradeRecords\";",
"""
CREATE UNIQUE INDEX IF NOT EXISTS "IX_GradeRecords_GradeSheetId_StudentId"
ON "GradeRecords" ("GradeSheetId", "StudentId");
""",
"""
CREATE INDEX IF NOT EXISTS "IX_GradeRecords_StudentId_TotalScore"
ON "GradeRecords" ("StudentId", "TotalScore");
""",
"""
CREATE TABLE IF NOT EXISTS "GradeItems" (
"Id" TEXT NOT NULL CONSTRAINT "PK_GradeItems" PRIMARY KEY,
"GradeSheetId" TEXT NOT NULL,
"Name" TEXT NOT NULL,
"Weight" TEXT NOT NULL,
"SortOrder" INTEGER NOT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
CONSTRAINT "FK_GradeItems_GradeSheets_GradeSheetId"
FOREIGN KEY ("GradeSheetId") REFERENCES "GradeSheets" ("Id") ON DELETE CASCADE
);
""",
"""
CREATE INDEX IF NOT EXISTS "IX_GradeItems_GradeSheetId_SortOrder"
ON "GradeItems" ("GradeSheetId", "SortOrder");
""",
"""
CREATE TABLE IF NOT EXISTS "GradeItemScores" (
"GradeRecordId" TEXT NOT NULL,
"GradeItemId" TEXT NOT NULL,
"Score" TEXT NULL,
CONSTRAINT "PK_GradeItemScores" PRIMARY KEY ("GradeRecordId", "GradeItemId"),
CONSTRAINT "FK_GradeItemScores_GradeRecords_GradeRecordId"
FOREIGN KEY ("GradeRecordId") REFERENCES "GradeRecords" ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_GradeItemScores_GradeItems_GradeItemId"
FOREIGN KEY ("GradeItemId") REFERENCES "GradeItems" ("Id") ON DELETE RESTRICT
);
"""
];
private static readonly string[] AttendanceStatements =
[
"""
CREATE TABLE IF NOT EXISTS "AttendanceSheets" (
"Id" TEXT NOT NULL CONSTRAINT "PK_AttendanceSheets" PRIMARY KEY,
"TeachingTaskId" TEXT NOT NULL,
"Name" TEXT NOT NULL,
"AttendanceDate" TEXT NOT NULL,
"Status" INTEGER NOT NULL,
"Notes" TEXT NULL,
"SubmittedAt" TEXT NULL,
"CreatedAt" TEXT NOT NULL,
"UpdatedAt" TEXT NOT NULL,
CONSTRAINT "FK_AttendanceSheets_TeachingTasks_TeachingTaskId"
FOREIGN KEY ("TeachingTaskId") REFERENCES "TeachingTasks" ("Id") ON DELETE RESTRICT
);
""",
"""
CREATE INDEX IF NOT EXISTS "IX_AttendanceSheets_TeachingTaskId_AttendanceDate"
ON "AttendanceSheets" ("TeachingTaskId", "AttendanceDate");
""",
"""
CREATE TABLE IF NOT EXISTS "AttendanceRecords" (
"AttendanceSheetId" TEXT NOT NULL,
"StudentId" TEXT NOT NULL,
"Status" INTEGER NOT NULL,
"Notes" TEXT NULL,
CONSTRAINT "PK_AttendanceRecords" PRIMARY KEY ("AttendanceSheetId", "StudentId"),
CONSTRAINT "FK_AttendanceRecords_AttendanceSheets_AttendanceSheetId"
FOREIGN KEY ("AttendanceSheetId") REFERENCES "AttendanceSheets" ("Id") ON DELETE CASCADE,
CONSTRAINT "FK_AttendanceRecords_Students_StudentId"
FOREIGN KEY ("StudentId") REFERENCES "Students" ("Id") ON DELETE RESTRICT
);
""",
"""
CREATE INDEX IF NOT EXISTS "IX_AttendanceRecords_AttendanceSheetId_StudentId"
ON "AttendanceRecords" ("AttendanceSheetId", "StudentId");
"""
];
private static readonly string[] StudentStatusChangesStatements =
[
"""