按 examId 延迟加载成绩工作区,未选择考试时不执行排名计算
单条及批量成绩草稿、发布 特长分单条及批量维护 成绩复议多级审批、终审改分、归档锁定 排名、等级、单科达线和考试汇总 成绩台账 Excel 导出 管理范围、超级管理员写权限及事务审计 独立开关 ADMIN_NATIVE_RESULTS_ENABLED
This commit is contained in:
1 parent
8f83adbc1e
commit
d47c614b53
15 files changed
+1523
-15
No files matched your search
@@ -0,0 +1,15 @@
|
||||
using System.Text.Json.Nodes;
|
||||
|
||||
namespace Eis.Application.Administration;
|
||||
|
||||
public interface IAdminResultService
|
||||
{
|
||||
Task<AdminEndpointResult> GetAsync(string sessionToken, string examId, CancellationToken cancellationToken);
|
||||
Task<AdminEndpointResult> SaveAsync(string sessionToken, JsonObject body, CancellationToken cancellationToken);
|
||||
Task<AdminEndpointResult> SaveBulkAsync(string sessionToken, JsonObject body, CancellationToken cancellationToken);
|
||||
Task<AdminEndpointResult> SaveFeatureBulkAsync(string sessionToken, JsonObject body, CancellationToken cancellationToken);
|
||||
Task<AdminEndpointResult> SaveFeatureAsync(string sessionToken, string registrationId, JsonObject body, CancellationToken cancellationToken);
|
||||
Task<AdminEndpointResult> ReviewAppealAsync(string sessionToken, string resultId, JsonObject body, CancellationToken cancellationToken);
|
||||
Task<AdminEndpointResult> RefreshCacheAsync(string sessionToken, CancellationToken cancellationToken);
|
||||
Task<AdminDocumentResult> ExportAsync(string sessionToken, string examId, CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -12,7 +12,8 @@ public sealed record AdminMigrationOptions(
|
||||
bool NativeRegistrationPaymentWritesEnabled = false,
|
||||
bool NativeWorkflowOperationsEnabled = false,
|
||||
bool NativeExamManagementEnabled = false,
|
||||
bool NativeArrangementsEnabled = false)
|
||||
bool NativeArrangementsEnabled = false,
|
||||
bool NativeResultsEnabled = false)
|
||||
{
|
||||
public static AdminMigrationOptions FromEnvironment(
|
||||
bool configuredNativeReadsEnabled,
|
||||
@@ -28,7 +29,8 @@ public sealed record AdminMigrationOptions(
|
||||
bool configuredNativeRegistrationPaymentWritesEnabled = false,
|
||||
bool configuredNativeWorkflowOperationsEnabled = false,
|
||||
bool configuredNativeExamManagementEnabled = false,
|
||||
bool configuredNativeArrangementsEnabled = false)
|
||||
bool configuredNativeArrangementsEnabled = false,
|
||||
bool configuredNativeResultsEnabled = false)
|
||||
{
|
||||
var readsEnabled = ParseBoolean(
|
||||
Environment.GetEnvironmentVariable("ADMIN_NATIVE_READS_ENABLED"),
|
||||
@@ -67,17 +69,20 @@ public sealed record AdminMigrationOptions(
|
||||
var arrangementsEnabled = ParseBoolean(
|
||||
Environment.GetEnvironmentVariable("ADMIN_NATIVE_ARRANGEMENTS_ENABLED"),
|
||||
configuredNativeArrangementsEnabled);
|
||||
if ((organizationWritesEnabled || accountBatchesEnabled || configurationEnabled || noticeManagementEnabled || centersEnabled || operationalReadsEnabled || candidateManagementEnabled || registrationPaymentWritesEnabled || workflowOperationsEnabled || examManagementEnabled || arrangementsEnabled) && !readsEnabled)
|
||||
var resultsEnabled = ParseBoolean(
|
||||
Environment.GetEnvironmentVariable("ADMIN_NATIVE_RESULTS_ENABLED"),
|
||||
configuredNativeResultsEnabled);
|
||||
if ((organizationWritesEnabled || accountBatchesEnabled || configurationEnabled || noticeManagementEnabled || centersEnabled || operationalReadsEnabled || candidateManagementEnabled || registrationPaymentWritesEnabled || workflowOperationsEnabled || examManagementEnabled || arrangementsEnabled || resultsEnabled) && !readsEnabled)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"启用原生组织维护接口前必须同时设置 ADMIN_NATIVE_READS_ENABLED=true");
|
||||
}
|
||||
if ((candidateManagementEnabled || registrationPaymentWritesEnabled) && !operationalReadsEnabled)
|
||||
if ((candidateManagementEnabled || registrationPaymentWritesEnabled || resultsEnabled) && !operationalReadsEnabled)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"启用原生考生、报名或缴费写接口前必须同时设置 ADMIN_NATIVE_OPERATIONAL_READS_ENABLED=true");
|
||||
}
|
||||
var anyNativeAdminEndpointEnabled = readsEnabled || organizationWritesEnabled || accountBatchesEnabled || configurationEnabled || noticeManagementEnabled || centersEnabled || operationalReadsEnabled || candidateManagementEnabled || registrationPaymentWritesEnabled || workflowOperationsEnabled || examManagementEnabled || arrangementsEnabled;
|
||||
var anyNativeAdminEndpointEnabled = readsEnabled || organizationWritesEnabled || accountBatchesEnabled || configurationEnabled || noticeManagementEnabled || centersEnabled || operationalReadsEnabled || candidateManagementEnabled || registrationPaymentWritesEnabled || workflowOperationsEnabled || examManagementEnabled || arrangementsEnabled || resultsEnabled;
|
||||
if (anyNativeAdminEndpointEnabled && !authenticationNativeEnabled)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
@@ -93,7 +98,7 @@ public sealed record AdminMigrationOptions(
|
||||
"管理端仍有接口需要转发给 Node;启用原生管理端接口必须配置共享 Redis 会话");
|
||||
}
|
||||
|
||||
return new AdminMigrationOptions(readsEnabled, organizationWritesEnabled, accountBatchesEnabled, configurationEnabled, noticeManagementEnabled, centersEnabled, operationalReadsEnabled, candidateManagementEnabled, registrationPaymentWritesEnabled, workflowOperationsEnabled, examManagementEnabled, arrangementsEnabled);
|
||||
return new AdminMigrationOptions(readsEnabled, organizationWritesEnabled, accountBatchesEnabled, configurationEnabled, noticeManagementEnabled, centersEnabled, operationalReadsEnabled, candidateManagementEnabled, registrationPaymentWritesEnabled, workflowOperationsEnabled, examManagementEnabled, arrangementsEnabled, resultsEnabled);
|
||||
}
|
||||
|
||||
private static bool ParseBoolean(string? value, bool fallback) => value?.Trim().ToLowerInvariant() switch
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
using ClosedXML.Excel;
|
||||
|
||||
namespace Eis.Infrastructure.Administration;
|
||||
|
||||
internal sealed record AdminResultExportRow(
|
||||
string CandidateNumber,
|
||||
string CardNumber,
|
||||
string CandidateName,
|
||||
string SchoolName,
|
||||
string ClassName,
|
||||
string ExamCode,
|
||||
string ExamName,
|
||||
string SubjectName,
|
||||
object FullScore,
|
||||
string PassRule,
|
||||
object PassScore,
|
||||
object Score,
|
||||
object Rank,
|
||||
object RankPercent,
|
||||
string Qualified,
|
||||
string Grade,
|
||||
string Published,
|
||||
string UpdatedAt);
|
||||
|
||||
internal static class AdminResultExporter
|
||||
{
|
||||
private static readonly string[] Headers =
|
||||
[
|
||||
"报名号*", "准考证号(只读参考)", "姓名(只读参考)", "学校(只读参考)", "班级(只读参考)",
|
||||
"考试代码*", "考试名称(只读参考)", "科目*", "科目满分(只读参考)", "单科及格规则(只读参考)",
|
||||
"实际及格分(只读参考)", "成绩*", "本科排名(导出计算)", "排名百分位(导出计算)",
|
||||
"单科达线(导出计算)", "排名等级(自动计算)", "发布状态*", "更新时间(只读参考)"
|
||||
];
|
||||
|
||||
public static byte[] Build(IReadOnlyList<AdminResultExportRow> rows)
|
||||
{
|
||||
using var workbook = new XLWorkbook();
|
||||
var sheet = workbook.Worksheets.Add("成绩");
|
||||
sheet.Cell(1, 1).Value = "考试成绩台账";
|
||||
sheet.Range(1, 1, 1, Headers.Length).Merge();
|
||||
sheet.Range(1, 1, 1, Headers.Length).Style
|
||||
.Font.SetBold().Font.SetFontSize(16).Font.SetFontColor(XLColor.White)
|
||||
.Fill.SetBackgroundColor(XLColor.FromHtml("#182552"));
|
||||
for (var index = 0; index < Headers.Length; index++)
|
||||
{
|
||||
sheet.Cell(2, index + 1).Value = Headers[index];
|
||||
}
|
||||
sheet.Range(2, 1, 2, Headers.Length).Style
|
||||
.Font.SetBold().Font.SetFontColor(XLColor.White)
|
||||
.Fill.SetBackgroundColor(XLColor.FromHtml("#245365"));
|
||||
for (var rowIndex = 0; rowIndex < rows.Count; rowIndex++)
|
||||
{
|
||||
var item = rows[rowIndex];
|
||||
object[] values =
|
||||
[
|
||||
item.CandidateNumber, item.CardNumber, item.CandidateName, item.SchoolName, item.ClassName,
|
||||
item.ExamCode, item.ExamName, item.SubjectName, item.FullScore, item.PassRule, item.PassScore,
|
||||
item.Score, item.Rank, item.RankPercent, item.Qualified, item.Grade, item.Published, item.UpdatedAt
|
||||
];
|
||||
for (var column = 0; column < values.Length; column++)
|
||||
{
|
||||
sheet.Cell(rowIndex + 3, column + 1).Value = XLCellValue.FromObject(values[column]);
|
||||
}
|
||||
}
|
||||
sheet.SheetView.FreezeRows(2);
|
||||
sheet.RangeUsed()?.SetAutoFilter();
|
||||
double[] widths =
|
||||
[
|
||||
24, 22, 14, 22, 16, 18, 26, 14, 16, 22, 18, 12, 16, 18, 16, 18, 14, 22
|
||||
];
|
||||
for (var index = 0; index < widths.Length; index++)
|
||||
{
|
||||
sheet.Column(index + 1).Width = widths[index];
|
||||
}
|
||||
sheet.Columns(9, 14).Style.NumberFormat.Format = "0.00";
|
||||
using var stream = new MemoryStream();
|
||||
workbook.SaveAs(stream);
|
||||
return stream.ToArray();
|
||||
}
|
||||
}
|
||||
Loaded 3 of 15 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user