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

教师批量录入平时、期中、期末成绩。
自动计算总评、绩点和及格状态。
支持缺考、缓考、免修。
教师提交 → 学院审核/退回 → 校级发布。
学生只能查看正式发布成绩。
自动统计平均分、完成度、及格率和加权 GPA。
SQLite 本地增量升级和 MySQL 正式迁移均已完成。
分级权限在前后端同时校验。
This commit is contained in:
biss committed 2026-07-24 15:33:47 +08:00
1 parent 151a22554f
commit af52e27a3a
18 files changed
+3686 -22

No files matched your search

+1 -1
View File
@@ -2,7 +2,7 @@
面向普通高校的教务管理系统。后端使用 ASP.NET Core 10、EF Core 10,前端使用 Vue 3、TypeScript 和 Element Plus。 面向普通高校的教务管理系统。后端使用 ASP.NET Core 10、EF Core 10,前端使用 Vue 3、TypeScript 和 Element Plus。
当前已实现系统登录与角色权限、基础数据、用户管理、教师档案、学生档案、课程库、培养方案、教学任务、排课课表、学生选课和首页统计。人员及课程列表支持组合筛选、服务端分页和完整增删改查;培养方案支持课程模块、专业年级版本、复制新版本、发布锁定和旧版本归档;教学任务支持学期课程开设、多教师、合班、容量校验、发布与结课;排课支持单双周、周次节次、教室容量、教师/行政班/教室冲突校验和版本化发布;选课支持批次时间窗、投放范围、容量与学分上限、重复课程与课表冲突校验、退课截止时间和实时教学班名单。 当前已实现系统登录与角色权限、基础数据、用户管理、教师档案、学生档案、课程库、培养方案、教学任务、排课课表、学生选课、成绩管理和首页统计。人员及课程列表支持组合筛选、服务端分页和完整增删改查;培养方案支持课程模块、专业年级版本、复制新版本、发布锁定和旧版本归档;教学任务支持学期课程开设、多教师、合班、容量校验、发布与结课;排课支持单双周、周次节次、教室容量、教师/行政班/教室冲突校验和版本化发布;选课支持批次时间窗、投放范围、容量与学分上限、重复课程与课表冲突校验、退课截止时间和实时教学班名单;成绩管理支持分项比例、批量录入、特殊考试状态、自动总评与绩点、教师提交、学院审核、校级发布和学生成绩单。
权限采用后端强制校验的角色与数据范围模型。多角色账号按 `All > College > Class > Self` 取最高数据范围:校级角色可访问全校数据,院系管理员限定本学院,辅导员通过稳定的账号 ID 绑定所带行政班,教师和学生限定本人及当前教学关系;前端菜单和路由限制仅作为交互辅助,不替代 API 授权。 权限采用后端强制校验的角色与数据范围模型。多角色账号按 `All > College > Class > Self` 取最高数据范围:校级角色可访问全校数据,院系管理员限定本学院,辅导员通过稳定的账号 ID 绑定所带行政班,教师和学生限定本人及当前教学关系;前端菜单和路由限制仅作为交互辅助,不替代 API 授权。
+91
View File
@@ -222,6 +222,94 @@ try {
throw 'Course-selection roster did not include the selected student.' throw 'Course-selection roster did not include the selected student.'
} }
$gradeTasks = Invoke-RestMethod `
-Uri 'http://localhost:5255/api/grades/sheets' `
-Headers $headers
$gradeTask = @($gradeTasks) |
Where-Object { $null -ne $_.sheet } |
Select-Object -First 1
if ($null -eq $gradeTask) {
throw 'Development grade sheet was not seeded.'
}
$gradeDetail = Invoke-RestMethod `
-Uri "http://localhost:5255/api/grades/sheets/$($gradeTask.sheet.id)" `
-Headers $headers
if (@($gradeDetail.sheet.records).Count -lt 1) {
throw 'Development grade sheet has no student records.'
}
$teacherLoginBody = @{
userName = 'teacher'
password = 'Teacher@123456'
} | ConvertTo-Json
$teacherLogin = Invoke-RestMethod `
-Method Post `
-Uri 'http://localhost:5255/api/auth/login' `
-ContentType 'application/json' `
-Body $teacherLoginBody
$teacherHeaders = @{ Authorization = "Bearer $($teacherLogin.token)" }
$teacherGradeTasks = Invoke-RestMethod `
-Uri 'http://localhost:5255/api/grades/sheets' `
-Headers $teacherHeaders
$teacherGradeTask = @($teacherGradeTasks) |
Where-Object { $_.id -eq $gradeTask.id } |
Select-Object -First 1
if ($null -eq $teacherGradeTask) {
throw 'Assigned teacher cannot access the grade sheet.'
}
if ($teacherGradeTask.sheet.status -eq 'Draft' -or
$teacherGradeTask.sheet.status -eq 'Returned') {
Invoke-RestMethod `
-Method Post `
-Uri "http://localhost:5255/api/grades/sheets/$($teacherGradeTask.sheet.id)/submit" `
-Headers $teacherHeaders |
Out-Null
}
$collegeLoginBody = @{
userName = 'college'
password = 'College@123456'
} | ConvertTo-Json
$collegeLogin = Invoke-RestMethod `
-Method Post `
-Uri 'http://localhost:5255/api/auth/login' `
-ContentType 'application/json' `
-Body $collegeLoginBody
$collegeHeaders = @{ Authorization = "Bearer $($collegeLogin.token)" }
$collegeGradeTasks = Invoke-RestMethod `
-Uri 'http://localhost:5255/api/grades/sheets' `
-Headers $collegeHeaders
$collegeGradeTask = @($collegeGradeTasks) |
Where-Object { $_.id -eq $gradeTask.id } |
Select-Object -First 1
if ($collegeGradeTask.sheet.status -eq 'Submitted') {
Invoke-RestMethod `
-Method Post `
-Uri "http://localhost:5255/api/grades/sheets/$($collegeGradeTask.sheet.id)/approve" `
-Headers $collegeHeaders |
Out-Null
}
$adminGradeTasks = Invoke-RestMethod `
-Uri 'http://localhost:5255/api/grades/sheets' `
-Headers $headers
$adminGradeTask = @($adminGradeTasks) |
Where-Object { $_.id -eq $gradeTask.id } |
Select-Object -First 1
if ($adminGradeTask.sheet.status -eq 'Approved') {
Invoke-RestMethod `
-Method Post `
-Uri "http://localhost:5255/api/grades/sheets/$($adminGradeTask.sheet.id)/publish" `
-Headers $headers |
Out-Null
}
$studentTranscript = Invoke-RestMethod `
-Uri 'http://localhost:5255/api/grades/student/transcript' `
-Headers $studentHeaders
if (@($studentTranscript.records).Count -lt 1) {
throw 'Published grade is not visible in the student transcript.'
}
$frontend = Invoke-WebRequest -Uri 'http://localhost:5255/' -TimeoutSec 5 $frontend = Invoke-WebRequest -Uri 'http://localhost:5255/' -TimeoutSec 5
$spaFallback = Invoke-WebRequest -Uri 'http://localhost:5255/base-data' -TimeoutSec 5 $spaFallback = Invoke-WebRequest -Uri 'http://localhost:5255/base-data' -TimeoutSec 5
$unknownApiParameters = @{ $unknownApiParameters = @{
@@ -250,6 +338,9 @@ try {
SelectionOfferings = @($selectionOfferings).Count SelectionOfferings = @($selectionOfferings).Count
StudentEnrollments = $activeEnrollments.Count StudentEnrollments = $activeEnrollments.Count
RosterStudents = $selectionRoster.enrolledCount RosterStudents = $selectionRoster.enrolledCount
GradeSheets = @($gradeTasks).Count
GradeRecords = @($gradeDetail.sheet.records).Count
TranscriptRecords = @($studentTranscript.records).Count
AccessUpdate = $true AccessUpdate = $true
ScopeChecks = $scopeChecks -join ', ' ScopeChecks = $scopeChecks -join ', '
StaticIndex = $frontend.Content.Contains('明序教务管理系统') StaticIndex = $frontend.Content.Contains('明序教务管理系统')
@@ -44,6 +44,11 @@ public sealed class DashboardController(AppDbContext db) : ControllerBase
.CountAsync( .CountAsync(
x => x.Status == CourseEnrollmentStatus.Enrolled, x => x.Status == CourseEnrollmentStatus.Enrolled,
cancellationToken), cancellationToken),
GradeSheets = await db.GradeSheets.CountAsync(cancellationToken),
PublishedGradeSheets = await db.GradeSheets.CountAsync(
x => x.Status == GradeSheetStatus.Published,
cancellationToken),
GradeRecords = await db.GradeRecords.CountAsync(cancellationToken),
Users = await db.Users.CountAsync(cancellationToken) Users = await db.Users.CountAsync(cancellationToken)
} }
}; };
Loaded 3 of 18 files, more files were not shown because too many files have changed in this diff. Show more