管理端后端
This commit is contained in:
1 parent
eebc5518c5
commit
4ef6f6c90d
24 files changed
+1745
-10
No files matched your search
@@ -38,11 +38,12 @@
|
|||||||
|
|
||||||
## 第二阶段:组织、选民与候选人
|
## 第二阶段:组织、选民与候选人
|
||||||
|
|
||||||
- [ ] 组织架构:组织、部门、班级等层级与成员归属。
|
- [x] 行政区划目录:省、市、区县、镇街、村社区五级;省市区镇采用受控 AreaCity 数据版本,村社区采用本地确认目录。
|
||||||
- [ ] 用户和选民资料:导入、停用、有效状态、组织范围查询。
|
- [x] 地域角色与范围:省、市、区、镇、村管理员的下级覆盖;计票员、监督员与具体计票所分配。
|
||||||
|
- [x] 用户和选民资料:导入预校验/确认、停用、有效状态、地域范围查询。
|
||||||
- [ ] 选民资格规则:按组织、名单、身份属性或人工审核确定。
|
- [ ] 选民资格规则:按组织、名单、身份属性或人工审核确定。
|
||||||
- [ ] 候选人管理:提名、自荐、资格材料、审核、撤回、取消资格和公示。
|
- [x] 候选人管理:提名、自荐、服务端资格状态转换、撤回、取消资格和公示;资格材料文件待对象存储阶段接入。
|
||||||
- [ ] 提供 Excel 批量导入/导出,导入须预校验并返回逐行错误。
|
- [x] 提供 Excel 批量导入,导入预校验并返回逐行错误;导出将在管理端与授权下载审计接入时实施。
|
||||||
|
|
||||||
## 第三阶段:选举活动与在线投票
|
## 第三阶段:选举活动与在线投票
|
||||||
|
|
||||||
|
|||||||
@@ -23,3 +23,15 @@ CMS 使用独立的 `ElectionSystem.Cms` Orchard Core 主机及数据库;具
|
|||||||
## 当前数据库对象
|
## 当前数据库对象
|
||||||
|
|
||||||
初始迁移仅创建 `identity_users`、`organization_units` 和 `audit_entries`。审计元数据只记录受影响的字段名,不能用于保存线上匿名选票内容或关联信息。
|
初始迁移仅创建 `identity_users`、`organization_units` 和 `audit_entries`。审计元数据只记录受影响的字段名,不能用于保存线上匿名选票内容或关联信息。
|
||||||
|
|
||||||
|
## 第二阶段:地域、人员与候选人
|
||||||
|
|
||||||
|
`administrative_regions` 是行政区划目录,不承载单位、支部或选举组织。其层级固定为省、市、区县、镇街、村社区五级;省市区镇基础数据应由 AreaCity-JsSpider-StatsGov 的受控版本导入,村社区只能由本地确认目录预校验后导入,并保留 `Source` 与 `SourceVersion`。补齐节点保留 `IsSynthetic`,不可擅自扁平化。
|
||||||
|
|
||||||
|
`identity_user_regional_roles` 将用户角色与地域范围分开保存。省、市、区、镇、村管理员的范围自动覆盖全部下级地域;系统管理员没有地域限制。计票员和监督员还必须经 `identity_user_counting_stations` 分配到具体计票所,未来线下计票接口必须同时检查地域角色和计票所分配。
|
||||||
|
|
||||||
|
所有 `/api/admin/*` 路由要求 JWT Bearer 认证,并要求身份提供的本地用户 GUID(`nameidentifier` 或 `sub` claim)。部署时配置 `Authentication:Authority`、`Authentication:Audience`,并在 OpenIddict/Keycloak 的声明映射中提供该 GUID。未认证请求返回 401,不能触发地域范围查询或写入。
|
||||||
|
|
||||||
|
`voter_profiles` 是选民主数据,按地域、状态查询和写入均须先应用管理员范围。选民 Excel 采用“上传预校验—逐行错误—同一操作者确认”模式,预览在 30 分钟后失效,确认前重新检查范围和重复选民编号。它不保存投票内容,后续 `Voting` 模块只可从选民 ID 创建资格/已投状态。
|
||||||
|
|
||||||
|
`candidate_profiles` 维护候选人地域归属和提名、审核、撤回、取消资格、公示状态;状态转换必须在服务端验证,撤回和取消资格必须说明原因。候选人材料文件将在对象存储接入后作为独立、授权的附件实体实现。
|
||||||
@@ -8,12 +8,18 @@ public sealed class GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logge
|
|||||||
public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
|
public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var traceId = httpContext.TraceIdentifier;
|
var traceId = httpContext.TraceIdentifier;
|
||||||
logger.LogError(exception, "Unhandled request failure. TraceId: {TraceId}", traceId);
|
var status = exception switch
|
||||||
|
{
|
||||||
|
UnauthorizedAccessException => StatusCodes.Status403Forbidden,
|
||||||
|
InvalidOperationException => StatusCodes.Status409Conflict,
|
||||||
|
_ => StatusCodes.Status500InternalServerError
|
||||||
|
};
|
||||||
|
if (status >= 500) logger.LogError(exception, "Unhandled request failure. TraceId: {TraceId}", traceId);
|
||||||
var problem = new ProblemDetails
|
var problem = new ProblemDetails
|
||||||
{
|
{
|
||||||
Status = StatusCodes.Status500InternalServerError,
|
Status = status,
|
||||||
Title = "An unexpected error occurred.",
|
Title = status == StatusCodes.Status403Forbidden ? "The action is outside your authorized scope." : status == StatusCodes.Status409Conflict ? "The request conflicts with current data or workflow state." : "An unexpected error occurred.",
|
||||||
Type = "https://tools.ietf.org/html/rfc9110#section-15.6.1",
|
Type = status == StatusCodes.Status403Forbidden ? "https://tools.ietf.org/html/rfc9110#section-15.5.4" : "https://tools.ietf.org/html/rfc9110#section-15.6.1",
|
||||||
Instance = httpContext.Request.Path
|
Instance = httpContext.Request.Path
|
||||||
};
|
};
|
||||||
problem.Extensions["traceId"] = traceId;
|
problem.Extensions["traceId"] = traceId;
|
||||||
|
|||||||
Loaded 3 of 24 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user