已完成“成绩管理与学业档案”模块:

教师批量录入平时、期中、期末成绩。
自动计算总评、绩点和及格状态。
支持缺考、缓考、免修。
教师提交 → 学院审核/退回 → 校级发布。
学生只能查看正式发布成绩。
自动统计平均分、完成度、及格率和加权 GPA。
SQLite 本地增量升级和 MySQL 正式迁移均已完成。
分级权限在前后端同时校验。
This commit is contained in:
2026-07-24 15:33:47 +08:00 Unverified
parent 151a22554f
commit af52e27a3a
18 changed files with 3686 additions and 22 deletions
@@ -422,37 +422,84 @@ public sealed class DatabaseInitializer(
await SeedDevelopmentUsersAsync(computerCollege.Id);
await SeedDevelopmentCourseSelectionAsync();
await SeedDevelopmentGradesAsync();
}
private async Task SeedDevelopmentCourseSelectionAsync()
{
if (await db.CourseSelectionRounds.AnyAsync())
if (!await db.CourseSelectionRounds.AnyAsync())
{
return;
var term = await db.AcademicTerms.SingleAsync(x => x.IsCurrent);
var task = await db.TeachingTasks.SingleAsync(
x => x.TaskNumber == "2026-1-CS101-01");
var now = DateTime.UtcNow;
db.CourseSelectionRounds.Add(new CourseSelectionRound
{
AcademicTermId = term.Id,
Name = "2026—2027 学年第一学期第一轮选课",
StartsAt = now.AddDays(-2),
EndsAt = now.AddDays(14),
WithdrawalEndsAt = now.AddDays(21),
MaxCredits = 30,
Status = CourseSelectionRoundStatus.Open,
Notes = "本地开发演示轮次,可用于验证选课、退课和教学班名单。",
Offerings =
[
new CourseSelectionOffering
{
TeachingTaskId = task.Id,
Capacity = 60,
IsOpenToAll = false,
Notes = "面向计科 2026-1 班开放。"
}
]
});
await db.SaveChangesAsync();
}
var term = await db.AcademicTerms.SingleAsync(x => x.IsCurrent);
var seededTask = await db.TeachingTasks.SingleAsync(
x => x.TaskNumber == "2026-1-CS101-01");
var offering = await db.CourseSelectionOfferings.FirstOrDefaultAsync(
x => x.TeachingTaskId == seededTask.Id);
var student = await db.Students.SingleAsync(x =>
x.StudentNumber == "202601001");
if (offering is not null &&
!await db.CourseEnrollments.AnyAsync(x =>
x.CourseSelectionOfferingId == offering.Id &&
x.StudentId == student.Id))
{
db.CourseEnrollments.Add(new CourseEnrollment
{
CourseSelectionOfferingId = offering.Id,
StudentId = student.Id
});
await db.SaveChangesAsync();
}
}
private async Task SeedDevelopmentGradesAsync()
{
if (await db.GradeSheets.AnyAsync()) return;
var task = await db.TeachingTasks.SingleAsync(
x => x.TaskNumber == "2026-1-CS101-01");
var now = DateTime.UtcNow;
db.CourseSelectionRounds.Add(new CourseSelectionRound
var student = await db.Students.SingleAsync(
x => x.StudentNumber == "202601001");
db.GradeSheets.Add(new GradeSheet
{
AcademicTermId = term.Id,
Name = "2026—2027 学年第一学期第一轮选课",
StartsAt = now.AddDays(-2),
EndsAt = now.AddDays(14),
WithdrawalEndsAt = now.AddDays(21),
MaxCredits = 30,
Status = CourseSelectionRoundStatus.Open,
Notes = "本地开发演示轮次,可用于验证选课、退课和教学班名单。",
Offerings =
TeachingTaskId = task.Id,
RegularWeight = 30,
MidtermWeight = 0,
FinalWeight = 70,
Status = GradeSheetStatus.Draft,
Records =
[
new CourseSelectionOffering
new GradeRecord
{
TeachingTaskId = task.Id,
Capacity = 60,
IsOpenToAll = false,
Notes = "面向计科 2026-1 班开放。"
StudentId = student.Id,
RegularScore = 88,
FinalScore = 92,
TotalScore = 90.8m,
GradePoint = 4.0m
}
]
});