已按“实验成绩独立管理”完成修改。
每个实验项目独立建成绩单,支持评分项、参与状态、补做次数、安全违规、报告地址和教师评语。 流程为:录入 → 学院审核 → 教务发布;学生只能查看已发布成绩。 自主预约实验支持同步有效预约名单,已评分记录不会被误删。 课程成绩可将已发布实验成绩汇总为快照导入指定分项;导入后锁定,不能手工篡改。 实验项目成绩不完整时,对应课程分项保持空白,不按 0 分处理。 一级“实验管理”菜单下增加“项目与场次”“实验成绩”;学生端增加“实验安排”“实验成绩”。 已生成 MySQL 正式迁移及 SQLite 开发迁移,尚未操作生产数据库。 界面采用“实验项目 → 独立评分 → 审核发布”工作台设计。
This commit is contained in:
@@ -72,6 +72,8 @@ public sealed class DevelopmentSqliteMigrator(
|
||||
"20260728_38_exam_publish_jobs";
|
||||
private const string ExperimentManagementMigration =
|
||||
"20260728_39_experiment_management";
|
||||
private const string ExperimentGradeManagementMigration =
|
||||
"20260728_40_experiment_grade_management";
|
||||
|
||||
public async Task MigrateAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
@@ -543,6 +545,32 @@ public sealed class DevelopmentSqliteMigrator(
|
||||
ExperimentManagementMigration,
|
||||
experimentProjectsExist ? [] : ExperimentManagementStatements,
|
||||
cancellationToken);
|
||||
|
||||
var gradeItemSourceExists = await db.Database
|
||||
.SqlQueryRaw<int>(
|
||||
"""
|
||||
SELECT COUNT(*) AS "Value"
|
||||
FROM pragma_table_info('GradeItems')
|
||||
WHERE name = 'SourceType'
|
||||
""")
|
||||
.AnyAsync(value => value > 0, cancellationToken);
|
||||
var experimentGradeSheetsExist = await db.Database
|
||||
.SqlQueryRaw<int>(
|
||||
"""
|
||||
SELECT COUNT(*) AS "Value"
|
||||
FROM sqlite_master
|
||||
WHERE type = 'table' AND name = 'ExperimentGradeSheets'
|
||||
""")
|
||||
.AnyAsync(value => value > 0, cancellationToken);
|
||||
await ApplyMigrationAsync(
|
||||
ExperimentGradeManagementMigration,
|
||||
(gradeItemSourceExists
|
||||
? []
|
||||
: ExperimentGradeItemSourceStatements)
|
||||
.Concat(experimentGradeSheetsExist
|
||||
? []
|
||||
: ExperimentGradeManagementStatements),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
private async Task ApplyMigrationAsync(
|
||||
@@ -2511,4 +2539,133 @@ public sealed class DevelopmentSqliteMigrator(
|
||||
);
|
||||
"""
|
||||
];
|
||||
|
||||
private static readonly string[] ExperimentGradeItemSourceStatements =
|
||||
[
|
||||
"""
|
||||
ALTER TABLE "GradeItems"
|
||||
ADD "SourceType" INTEGER NOT NULL DEFAULT 1;
|
||||
""",
|
||||
"""
|
||||
ALTER TABLE "GradeItems"
|
||||
ADD "SourceSnapshotAt" TEXT NULL;
|
||||
"""
|
||||
];
|
||||
|
||||
private static readonly string[] ExperimentGradeManagementStatements =
|
||||
[
|
||||
"""
|
||||
CREATE TABLE "ExperimentGradeSheets" (
|
||||
"Id" TEXT NOT NULL
|
||||
CONSTRAINT "PK_ExperimentGradeSheets" PRIMARY KEY,
|
||||
"ExperimentProjectId" TEXT NOT NULL,
|
||||
"ContributionWeight" TEXT NOT NULL,
|
||||
"PassScore" 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_ExperimentGradeSheets_ExperimentProjects_ExperimentProjectId"
|
||||
FOREIGN KEY ("ExperimentProjectId")
|
||||
REFERENCES "ExperimentProjects" ("Id")
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
""",
|
||||
"""
|
||||
CREATE UNIQUE INDEX "IX_ExperimentGradeSheets_ExperimentProjectId"
|
||||
ON "ExperimentGradeSheets" ("ExperimentProjectId");
|
||||
""",
|
||||
"""
|
||||
CREATE TABLE "ExperimentGradeItems" (
|
||||
"Id" TEXT NOT NULL
|
||||
CONSTRAINT "PK_ExperimentGradeItems" PRIMARY KEY,
|
||||
"ExperimentGradeSheetId" TEXT NOT NULL,
|
||||
"Name" TEXT NOT NULL,
|
||||
"Kind" INTEGER NOT NULL,
|
||||
"Weight" TEXT NOT NULL,
|
||||
"SortOrder" INTEGER NOT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
CONSTRAINT "FK_ExperimentGradeItems_ExperimentGradeSheets_ExperimentGradeSheetId"
|
||||
FOREIGN KEY ("ExperimentGradeSheetId")
|
||||
REFERENCES "ExperimentGradeSheets" ("Id")
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
""",
|
||||
"""
|
||||
CREATE INDEX "IX_ExperimentGradeItems_ExperimentGradeSheetId_SortOrder"
|
||||
ON "ExperimentGradeItems" ("ExperimentGradeSheetId", "SortOrder");
|
||||
""",
|
||||
"""
|
||||
CREATE TABLE "ExperimentGradeRecords" (
|
||||
"Id" TEXT NOT NULL
|
||||
CONSTRAINT "PK_ExperimentGradeRecords" PRIMARY KEY,
|
||||
"ExperimentGradeSheetId" TEXT NOT NULL,
|
||||
"StudentId" TEXT NOT NULL,
|
||||
"ExperimentSessionId" TEXT NULL,
|
||||
"ParticipationStatus" INTEGER NOT NULL,
|
||||
"TotalScore" TEXT NULL,
|
||||
"IsPassed" INTEGER NULL,
|
||||
"SafetyViolation" INTEGER NOT NULL,
|
||||
"AttemptNumber" INTEGER NOT NULL,
|
||||
"SubmissionReference" TEXT NULL,
|
||||
"SubmittedAt" TEXT NULL,
|
||||
"IsLate" INTEGER NOT NULL,
|
||||
"TeacherComment" TEXT NULL,
|
||||
"CreatedAt" TEXT NOT NULL,
|
||||
"UpdatedAt" TEXT NOT NULL,
|
||||
CONSTRAINT "FK_ExperimentGradeRecords_ExperimentGradeSheets_ExperimentGradeSheetId"
|
||||
FOREIGN KEY ("ExperimentGradeSheetId")
|
||||
REFERENCES "ExperimentGradeSheets" ("Id")
|
||||
ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ExperimentGradeRecords_Students_StudentId"
|
||||
FOREIGN KEY ("StudentId") REFERENCES "Students" ("Id")
|
||||
ON DELETE RESTRICT,
|
||||
CONSTRAINT "FK_ExperimentGradeRecords_ExperimentSessions_ExperimentSessionId"
|
||||
FOREIGN KEY ("ExperimentSessionId")
|
||||
REFERENCES "ExperimentSessions" ("Id")
|
||||
ON DELETE RESTRICT
|
||||
);
|
||||
""",
|
||||
"""
|
||||
CREATE UNIQUE INDEX "IX_ExperimentGradeRecords_ExperimentGradeSheetId_StudentId"
|
||||
ON "ExperimentGradeRecords" ("ExperimentGradeSheetId", "StudentId");
|
||||
""",
|
||||
"""
|
||||
CREATE INDEX "IX_ExperimentGradeRecords_StudentId"
|
||||
ON "ExperimentGradeRecords" ("StudentId");
|
||||
""",
|
||||
"""
|
||||
CREATE INDEX "IX_ExperimentGradeRecords_ExperimentSessionId"
|
||||
ON "ExperimentGradeRecords" ("ExperimentSessionId");
|
||||
""",
|
||||
"""
|
||||
CREATE TABLE "ExperimentGradeItemScores" (
|
||||
"ExperimentGradeRecordId" TEXT NOT NULL,
|
||||
"ExperimentGradeItemId" TEXT NOT NULL,
|
||||
"Score" TEXT NULL,
|
||||
"Comment" TEXT NULL,
|
||||
CONSTRAINT "PK_ExperimentGradeItemScores"
|
||||
PRIMARY KEY (
|
||||
"ExperimentGradeRecordId",
|
||||
"ExperimentGradeItemId"
|
||||
),
|
||||
CONSTRAINT "FK_ExperimentGradeItemScores_ExperimentGradeRecords_ExperimentGradeRecordId"
|
||||
FOREIGN KEY ("ExperimentGradeRecordId")
|
||||
REFERENCES "ExperimentGradeRecords" ("Id")
|
||||
ON DELETE CASCADE,
|
||||
CONSTRAINT "FK_ExperimentGradeItemScores_ExperimentGradeItems_ExperimentGradeItemId"
|
||||
FOREIGN KEY ("ExperimentGradeItemId")
|
||||
REFERENCES "ExperimentGradeItems" ("Id")
|
||||
ON DELETE CASCADE
|
||||
);
|
||||
""",
|
||||
"""
|
||||
CREATE INDEX "IX_ExperimentGradeItemScores_ExperimentGradeItemId"
|
||||
ON "ExperimentGradeItemScores" ("ExperimentGradeItemId");
|
||||
"""
|
||||
];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user