按 examId 延迟加载成绩工作区,未选择考试时不执行排名计算

单条及批量成绩草稿、发布
特长分单条及批量维护
成绩复议多级审批、终审改分、归档锁定
排名、等级、单科达线和考试汇总
成绩台账 Excel 导出
管理范围、超级管理员写权限及事务审计
独立开关 ADMIN_NATIVE_RESULTS_ENABLED
This commit is contained in:
2026-07-23 12:16:01 +08:00 Unverified
parent 8f83adbc1e
commit d47c614b53
15 changed files with 1523 additions and 15 deletions
+120
View File
@@ -484,6 +484,7 @@ try {
ADMIN_NATIVE_WORKFLOW_OPERATIONS_ENABLED = 'true'
ADMIN_NATIVE_EXAM_MANAGEMENT_ENABLED = 'true'
ADMIN_NATIVE_ARRANGEMENTS_ENABLED = 'true'
ADMIN_NATIVE_RESULTS_ENABLED = 'true'
ADMIN_NATIVE_ALLOW_MEMORY = 'true'
LegacyNode__Enabled = 'true'
LegacyNode__BaseUrl = $legacyBaseUrl
@@ -576,6 +577,9 @@ try {
$legacyAdmissionsAfterWrite = Invoke-WebRequest -Uri "$legacyBaseUrl/api/candidate/admissions" -WebSession $candidateSession
$nativeAdmissionsAfterWrite = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/candidate/admissions" -WebSession $nativeCandidateSession
Assert-CandidateAdmissionsEquivalent -Expected $legacyAdmissionsAfterWrite.Content -Actual $nativeAdmissionsAfterWrite.Content
$appealResultId = $null
$appealExamId = $null
$appealOriginalScore = $null
$appealableResult = @($nativeCandidateResults.results | Where-Object { $null -eq $_.appeal } | Select-Object -First 1)[0]
if ($null -ne $appealableResult) {
$shortAppeal = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/candidate/results/$($appealableResult.id)/appeals" -Method Post -ContentType 'application/json' -Body '{"reason":"短"}' -WebSession $nativeCandidateSession -SkipHttpErrorCheck
@@ -588,6 +592,9 @@ try {
if ($appealResponse.StatusCode -ne 201 -or $appealResponse.Headers['X-EIS-Implementation'] -ne 'aspnet-core' -or $appeal.workflow.status -ne 'pending') {
throw 'Native score appeal did not persist a pending workflow'
}
$appealResultId = $appealableResult.id
$appealExamId = $appealableResult.examId
$appealOriginalScore = $appealableResult.score
}
$admitProcess = Start-TestProcess -FileName $nodeExecutable -ArgumentList @(
'tests/helpers/prepare-candidate-admit-smoke.mjs', $smokeDatabasePath, '2026-HZ01-F-0001'
@@ -932,6 +939,118 @@ try {
throw 'Native center-material workbook export is invalid'
}
$legacyEmptyResults = Invoke-WebRequest -Uri "$legacyBaseUrl/api/admin/results" -WebSession $session
$nativeEmptyResults = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/results" -WebSession $nativeSession
if ($nativeEmptyResults.Headers['X-EIS-Implementation'] -ne 'aspnet-core') {
throw 'Native empty result workspace did not use ASP.NET Core'
}
Assert-JsonEquivalent -Expected $legacyEmptyResults.Content -Actual $nativeEmptyResults.Content -Label 'Empty result workspace'
$resultsUri = "/api/admin/results?examId=$($arrangementExam.id)"
$legacyResults = Invoke-WebRequest -Uri "$legacyBaseUrl$resultsUri" -WebSession $session
$nativeResults = Invoke-WebRequest -Uri "$nativeAuthBaseUrl$resultsUri" -WebSession $nativeSession
if ($nativeResults.Headers['X-EIS-Implementation'] -ne 'aspnet-core') {
throw 'Native result workspace did not use ASP.NET Core'
}
Assert-JsonEquivalent -Expected $legacyResults.Content -Actual $nativeResults.Content -Label 'Super-admin result workspace'
$nativeResultsState = $nativeResults.Content | ConvertFrom-Json
$resultRegistration = @($nativeResultsState.registrations | Where-Object { @($_.subjects).Count -gt 0 } | Select-Object -First 1)[0]
if ($null -eq $resultRegistration) {
throw 'Seed data did not provide an approved registration for native result writes'
}
$resultSubject = @($resultRegistration.subjects)[0]
$schoolResultWrite = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/results" -Method Post -ContentType 'application/json' -Body '{}' -WebSession $nativeSchoolSession -SkipHttpErrorCheck
if ($schoolResultWrite.StatusCode -ne 403 -or $schoolResultWrite.Headers['X-EIS-Implementation'] -ne 'aspnet-core') {
throw 'Native result writes did not preserve the super-admin boundary'
}
$invalidResultBody = @{
registrationId = $resultRegistration.id
subjectId = $resultSubject.id
score = [double] $resultSubject.fullScore + 1
published = $false
} | ConvertTo-Json -Compress
$invalidResult = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/results" -Method Post -ContentType 'application/json' -Body $invalidResultBody -WebSession $nativeSession -SkipHttpErrorCheck
if ($invalidResult.StatusCode -ne 400) {
throw 'Native result write accepted a score above the subject full score'
}
$score = [Math]::Min([double] $resultSubject.fullScore, 88.5)
$bulkDraftBody = @{
examId = $arrangementExam.id
subjectId = $resultSubject.id
published = $false
rows = @(@{ registrationId = $resultRegistration.id; score = $score })
} | ConvertTo-Json -Depth 5 -Compress
$bulkDraftResponse = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/results/bulk" -Method Post -ContentType 'application/json' -Body $bulkDraftBody -WebSession $nativeSession
$bulkDraft = $bulkDraftResponse.Content | ConvertFrom-Json
if ($bulkDraftResponse.Headers['X-EIS-Implementation'] -ne 'aspnet-core' -or $bulkDraft.count -ne 1 -or $bulkDraft.published -ne $false) {
throw 'Native result bulk draft did not save the requested score'
}
$bulkPublishBody = @{
examId = $arrangementExam.id
subjectId = $resultSubject.id
published = $true
rows = @(@{ registrationId = $resultRegistration.id; score = $score })
} | ConvertTo-Json -Depth 5 -Compress
$bulkPublish = Invoke-RestMethod -Uri "$nativeAuthBaseUrl/api/admin/results/bulk" -Method Post -ContentType 'application/json' -Body $bulkPublishBody -WebSession $nativeSession
if ($bulkPublish.count -ne 1 -or $bulkPublish.published -ne $true -or $bulkPublish.summary.publish -ne 1) {
throw 'Native result bulk publication did not publish the requested score'
}
$invalidFeatureBody = @{
examId = $arrangementExam.id
rows = @(@{ registrationId = $resultRegistration.id; featureScore = 1001 })
} | ConvertTo-Json -Depth 5 -Compress
$invalidFeature = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/feature-scores/bulk" -Method Post -ContentType 'application/json' -Body $invalidFeatureBody -WebSession $nativeSession -SkipHttpErrorCheck
if ($invalidFeature.StatusCode -ne 400) {
throw 'Native feature-score bulk write accepted a score above 1000'
}
$featureBody = @{ featureScore = 19.25 } | ConvertTo-Json -Compress
$featureResponse = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/registrations/$($resultRegistration.id)/feature-score" -Method Patch -ContentType 'application/json' -Body $featureBody -WebSession $nativeSession
$featureRegistration = ($featureResponse.Content | ConvertFrom-Json).registration
if ($featureResponse.Headers['X-EIS-Implementation'] -ne 'aspnet-core' -or $featureRegistration.featureScore -ne 19.25) {
throw 'Native feature-score write did not persist the rounded score'
}
$invalidAppeal = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/score-appeals/missing-result" -Method Patch -ContentType 'application/json' -Body '{"status":"invalid"}' -WebSession $nativeSession -SkipHttpErrorCheck
if ($invalidAppeal.StatusCode -ne 400 -or $invalidAppeal.Headers['X-EIS-Implementation'] -ne 'aspnet-core') {
throw 'Native score-appeal review accepted an invalid status'
}
if ($null -ne $appealResultId) {
$appealReviewIterations = 0
do {
$appealReviewIterations += 1
if ($appealReviewIterations -gt 10) {
throw 'Native score-appeal workflow did not reach a terminal state'
}
$appealReviewBody = @{
status = 'approved'
reviewedScore = $appealOriginalScore
reviewNote = "原生成绩复议第 $appealReviewIterations"
} | ConvertTo-Json -Compress
$appealReviewResponse = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/score-appeals/$appealResultId" -Method Patch -ContentType 'application/json' -Body $appealReviewBody -WebSession $nativeSession
$appealReview = $appealReviewResponse.Content | ConvertFrom-Json
if ($appealReviewResponse.Headers['X-EIS-Implementation'] -ne 'aspnet-core') {
throw 'Native score-appeal review did not use ASP.NET Core'
}
} while ($appealReview.workflow.status -eq 'pending')
if ($appealReview.workflow.status -ne 'approved' -or $appealReview.result.score -ne $appealOriginalScore) {
throw 'Native score-appeal review did not complete the workflow and preserve the reviewed score'
}
if ($appealExamId) {
$appealResultsUri = "/api/admin/results?examId=$appealExamId"
$legacyAppealResults = Invoke-WebRequest -Uri "$legacyBaseUrl$appealResultsUri" -WebSession $session
$nativeAppealResults = Invoke-WebRequest -Uri "$nativeAuthBaseUrl$appealResultsUri" -WebSession $nativeSession
Assert-JsonEquivalent -Expected $legacyAppealResults.Content -Actual $nativeAppealResults.Content -Label 'Score-appeal review follow-up'
}
}
$resultExport = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/excel/results?examId=$($arrangementExam.id)" -WebSession $nativeSession
if ($resultExport.Headers['X-EIS-Implementation'] -ne 'aspnet-core' -or
$resultExport.Headers['Content-Type'] -notmatch 'spreadsheetml' -or
$resultExport.RawContentLength -lt 1000) {
throw 'Native result workbook export is invalid'
}
$legacyResultsAfterWrites = Invoke-WebRequest -Uri "$legacyBaseUrl$resultsUri" -WebSession $session
$nativeResultsAfterWrites = Invoke-WebRequest -Uri "$nativeAuthBaseUrl$resultsUri" -WebSession $nativeSession
Assert-JsonEquivalent -Expected $legacyResultsAfterWrites.Content -Actual $nativeResultsAfterWrites.Content -Label 'Result writes follow-up'
$operationalSessions = @(
@{ Level = 'super'; Legacy = $session; Native = $nativeSession },
@{ Level = 'school'; Legacy = $legacySchoolSession; Native = $nativeSchoolSession },
@@ -1712,6 +1831,7 @@ try {
NativeAdminWorkflowOperations = 'passed'
NativeAdminExamManagement = 'passed'
NativeAdminArrangements = 'passed'
NativeAdminResults = 'passed'
} | Format-List
}
finally {