已完成“成绩管理与学业档案”模块:
教师批量录入平时、期中、期末成绩。 自动计算总评、绩点和及格状态。 支持缺考、缓考、免修。 教师提交 → 学院审核/退回 → 校级发布。 学生只能查看正式发布成绩。 自动统计平均分、完成度、及格率和加权 GPA。 SQLite 本地增量升级和 MySQL 正式迁移均已完成。 分级权限在前后端同时校验。
This commit is contained in:
1 parent
151a22554f
commit
af52e27a3a
18 files changed
+3686
-22
No files matched your search
@@ -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 授权。
|
||||||
|
|
||||||
|
|||||||
@@ -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
Reference in new issue
Block a user