add
@@ -0,0 +1,334 @@
|
||||
# 管理操作指南
|
||||
|
||||
本页面向超级管理员、校级管理员、班级管理员和招生学校账号。系统会同时在前端和服务端执行权限检查,管理员不能通过手工拼接 URL 越过数据范围。
|
||||
|
||||
## 1. 角色与权限边界
|
||||
|
||||
| 功能域 | 超级管理员 | 校级管理员 | 班级管理员 | 招生学校 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 全局运行总览 | 全部 | 本校 | 本班 | 本校招生业务 |
|
||||
| 学校与班级 | 管理全部学校 | 管理本校组织 | 只读本班相关信息 | 不适用 |
|
||||
| 管理员账号 | 管理各级管理员 | 按业务入口管理本校班级相关事项 | 不适用 | 不适用 |
|
||||
| 批量申领报名号 | 审批、监督 | 发起并接收结果 | 不直接发起 | 不适用 |
|
||||
| 考生资料 | 全部并可监督 | 本校 | 本班 | 投档后必要资料 |
|
||||
| 报名与缴费 | 全部 | 本校 | 本班 | 不适用 |
|
||||
| 考试与科目 | 创建、修改、归档 | 查看相关考试 | 查看相关考试 | 查看招生关联考试 |
|
||||
| 成绩录入与发布 | 可操作 | 范围内查看、导出、参与流程 | 范围内查看、参与复议 | 仅投档材料中的必要成绩 |
|
||||
| 考点考场 | 全局维护、审批 | 本校档案变更申请 | 查看相关安排 | 不适用 |
|
||||
| 审批流 | 设计、监督、退回 | 处理本校步骤、转交 | 处理本班步骤、转交 | 招生业务指定动作 |
|
||||
| 招生录取 | 全局设置与投档签发 | 确认本校指标资格 | 不可代确认指标资格 | 计划、投档、报到、模板 |
|
||||
| 通知公告 | 创建、发布、撤回 | 查看 | 查看 | 查看相关公示 |
|
||||
|
||||
同一级可以配置多个管理员。待办会按当前待办数和历史分配量在同一业务范围内自动均分,当前处理人还可把流程转交给同范围同级管理员。
|
||||
|
||||
## 2. 超级管理员首次配置
|
||||
|
||||
建议按以下顺序完成初始化:
|
||||
|
||||
1. 登录后立即修改初始密码。
|
||||
2. 在“账户安全”绑定 TOTP 并离线保存恢复码。
|
||||
3. 在“学校管理”建立学校,填写稳定且唯一的学校代码。
|
||||
4. 根据学校职责标记生源校、招生校,或同时具备两类职责。
|
||||
5. 建立校级、班级管理员,明确学校和班级数据范围。
|
||||
6. 在“报名号规则”配置年份、学校代码、性别、固定值和流水号等号码段。
|
||||
7. 在“流程设计”配置各业务的审批步骤。
|
||||
8. 在“考试与科目”建立考试和科目。
|
||||
9. 需要自主注册时才临时开启,并在结束后关闭。
|
||||
|
||||
生产系统完成初始化后,不要继续使用模板初始密码。
|
||||
|
||||
## 3. 组织、账号和报名号
|
||||
|
||||
### 学校与班级
|
||||
|
||||
学校代码会参与报名号、录取通知书编号和考务数据识别,应在投入使用前确定。系统保存学校和班级的数据范围关联,不能把权限控制仅理解为页面筛选。
|
||||
|
||||
### 管理员账号
|
||||
|
||||
- 超级管理员可建立多个同级账号,避免共享一个管理员账户。
|
||||
- 校级和班级管理员必须绑定正确的学校、班级范围。
|
||||
- 停用账号后,其有效登录状态会失效。
|
||||
- 密码重置产生的是新凭据,管理员不能读取旧密码。
|
||||
- 交接人员时,应创建或启用个人账号,不建议多人长期共用。
|
||||
|
||||
### 报名号规则
|
||||
|
||||
规则可组合:
|
||||
|
||||
- 年份;
|
||||
- 学校代码;
|
||||
- 性别;
|
||||
- 固定文本;
|
||||
- 流水号。
|
||||
|
||||
超级管理员只维护规则,不直接替代学校的批量申领流程。报名号在考生账户创建时原子生成一次,后续参加不同考试仍复用同一号码。
|
||||
|
||||
### 批量建号
|
||||
|
||||
校级管理员:
|
||||
|
||||
1. 选择一个或多个班级;
|
||||
2. 为每班填写申请人数;
|
||||
3. 提交批次审批;
|
||||
4. 等待最终批准;
|
||||
5. 下载按班级返回的报名号和初始密码 Excel;
|
||||
6. 通过安全渠道分别下发。
|
||||
|
||||
即使只申请一名考生,也按一人批次进入审批。最终批准时系统一次性生成报名号、随机初始密码和待补录账户,避免部分成功造成数量不一致。
|
||||
|
||||
## 4. 审批流程
|
||||
|
||||
可配置审批的主要业务包括:
|
||||
|
||||
- 考生资料修改;
|
||||
- 考试报名;
|
||||
- 成绩复议;
|
||||
- 批量报名号申领;
|
||||
- 考点和考场档案变更。
|
||||
|
||||
处理原则:
|
||||
|
||||
1. 先核对完整业务上下文和申请快照。
|
||||
2. 通过时确认下游步骤和最终生效条件。
|
||||
3. 退回时填写可执行的修改意见。
|
||||
4. 需要更换处理人时使用“转交”,不要让其他管理员共享账号操作。
|
||||
5. 超级管理员监督处理时保留原因,避免无说明改写流程历史。
|
||||
|
||||
班级和校级步骤会自动限制到考生所属班级和学校。审批实例、责任人、转交和监督动作均留痕。
|
||||
|
||||
## 5. 考生资料、报名与缴费
|
||||
|
||||
### 考生资料
|
||||
|
||||
各级管理员在自身范围内查看考生资料、审核状态和流程历史。Excel 导入会逐行校验并返回具体行号;批量修改资料仍需经过配置的审批流程,不因使用 Excel 而绕过审批。
|
||||
|
||||
### 报名审核
|
||||
|
||||
核对:
|
||||
|
||||
- 考试和科目;
|
||||
- 考生资料状态;
|
||||
- 报名时间;
|
||||
- 费用;
|
||||
- 当前审批步骤;
|
||||
- 历史处理意见。
|
||||
|
||||
### 缴费管理
|
||||
|
||||
报名终审与缴费确认彼此独立。超级、校级和班级管理员均可在各自数据范围内维护缴费状态,确认时系统记录办理人和时间。
|
||||
|
||||
缴费台账应通过页面筛选后导出。系统不接入支付 SDK,因此“已缴费”表示管理员已登记确认,不代表平台完成了在线支付交易。
|
||||
|
||||
## 6. 考试与科目
|
||||
|
||||
超级管理员可配置:
|
||||
|
||||
- 考试代码、名称和状态;
|
||||
- 报名、考试、准考证、成绩等时间;
|
||||
- 科目日期、开始结束时间;
|
||||
- 科目费用和满分;
|
||||
- 固定单科线、排名前百分比或不设单科线;
|
||||
- 固定总分线、总排名前百分比、单科均达线或不判定整场合格。
|
||||
|
||||
默认成绩等级按同场同科排名百分位计算:
|
||||
|
||||
| 区间 | 等级 |
|
||||
| --- | --- |
|
||||
| 前 10% | A+ |
|
||||
| 前 25% | A |
|
||||
| 前 50% | B+ |
|
||||
| 前 70% | B |
|
||||
| 前 90% | C |
|
||||
| 其余 | D |
|
||||
|
||||
同分共享名次。
|
||||
|
||||
### 考试归档
|
||||
|
||||
归档是整场考试的不可逆业务动作。归档后锁定:
|
||||
|
||||
- 手工成绩录入;
|
||||
- 成绩 Excel 导入;
|
||||
- 复议改分;
|
||||
- 考试配置修改。
|
||||
|
||||
归档前应确认报名、编排、成绩、复议、发布和必要导出均已完成。历史报名、准考证与成绩在页面中默认折叠展示。
|
||||
|
||||
## 7. 考点、考场与准考证编排
|
||||
|
||||
考点档案包括:
|
||||
|
||||
- 代码、名称和状态;
|
||||
- 负责人、应急电话;
|
||||
- 开放时间、交通说明;
|
||||
- 楼栋、楼层;
|
||||
- 考场容量、类型;
|
||||
- 座位编排说明。
|
||||
|
||||
考点新增以及考点、考场修改会先形成申请快照,审批通过后再整体更新正式档案。
|
||||
|
||||
### 批量编排
|
||||
|
||||
超级管理员选择整场考试后:
|
||||
|
||||
1. 选择混编范围:班内、校内、县区内、市内或省内。
|
||||
2. 选择准考证号码规则。
|
||||
3. 设置是否保留备用考场和稳定随机种子。
|
||||
4. 先执行预检。
|
||||
5. 处理所有阻断问题。
|
||||
6. 再确认正式编排。
|
||||
|
||||
预检检查:
|
||||
|
||||
- 科目时间冲突;
|
||||
- 考点与考场容量;
|
||||
- 档案完整性;
|
||||
- 准考证号码唯一性;
|
||||
- 多科考生的考点一致性。
|
||||
|
||||
预置号码规则包括:
|
||||
|
||||
- 县区编号 + 考场号 + 座位号;
|
||||
- 县区号 + 考场号 + 流水号;
|
||||
- 考点学校代码 + 考场号 + 座位号;
|
||||
- 考生学校代码 + 考场号 + 座位号。
|
||||
|
||||
预检只用于验证,不应写入正式编排结果;正式应用后再开放准考证下载。
|
||||
|
||||
## 8. 成绩管理
|
||||
|
||||
成绩管理中心按考试切换,提供:
|
||||
|
||||
- 录入和发布进度;
|
||||
- 成绩出齐人数;
|
||||
- 整场合格率;
|
||||
- 缺失科次;
|
||||
- 复议数量;
|
||||
- 可筛选成绩台账;
|
||||
- Excel 导入导出;
|
||||
- 缓存刷新。
|
||||
|
||||
### Excel 导入
|
||||
|
||||
成绩导入采用两阶段流程:
|
||||
|
||||
1. 上传并逐行校验;
|
||||
2. 页面暂存预览;
|
||||
3. 管理员核对错误、人数和变更内容;
|
||||
4. 明确确认;
|
||||
5. 在事务内原子批量写库。
|
||||
|
||||
预览不会修改数据库。不要把“解析成功”误认为“导入完成”。
|
||||
|
||||
### 成绩复议
|
||||
|
||||
终审时查看考试、科目、原分、当前分、当前排名和达线规则。批准改分后系统更新成绩并重新计算受影响结论。考试归档后不能批准会造成改分的操作。
|
||||
|
||||
### 发布与缓存
|
||||
|
||||
成绩录入不等于发布。发布、批量导入、归档和复议改分会自动使相关结果缓存失效;超级管理员也可在成绩管理中心手动刷新全部成绩缓存。
|
||||
|
||||
## 9. 通知与系统公示
|
||||
|
||||
超级管理员可:
|
||||
|
||||
- 新建草稿;
|
||||
- 编辑内容;
|
||||
- 发布;
|
||||
- 撤回;
|
||||
- 设置首页置顶;
|
||||
- 管理系统生成的招生公示可见性。
|
||||
|
||||
系统公示和人工公告来源不同。撤回、隐藏或重新公开后,应以公开首页实际显示结果为准。
|
||||
|
||||
招生流程会按阶段生成:
|
||||
|
||||
- 招生计划公示;
|
||||
- 指标资格公示;
|
||||
- 录取与补录公示;
|
||||
- 报到情况公示;
|
||||
- 脱敏录取名单;
|
||||
- 按学校、类别统计的录取分数线。
|
||||
|
||||
## 10. 招生录取全流程
|
||||
|
||||
### 录取设置
|
||||
|
||||
超级管理员按考试配置:
|
||||
|
||||
- 是否启用志愿;
|
||||
- 填报起止时间;
|
||||
- 普通志愿数量;
|
||||
- 最多提交次数;
|
||||
- 当前阶段。
|
||||
|
||||
### 招生账户和计划
|
||||
|
||||
超级管理员为招生学校建立专用账号。招生学校以结构化表单提交普通生、特长生和生源校指标计划;超级管理员审核后生效,也可代为上传并直接审核。
|
||||
|
||||
### 指标资格
|
||||
|
||||
生源校校级管理员按考试逐人确认本校考生指标资格。必须完成本校全部资料已完善在册考生的确认后,系统才公开资格结果。超级管理员和班级管理员不能代替校级管理员完成此确认。
|
||||
|
||||
### 志愿和投档
|
||||
|
||||
填报结束后,超级管理员执行投档。系统按总成绩降序逐人检索志愿,区分指标与普通计划池。
|
||||
|
||||
投档材料只发送给对应招生学校,包含必要个人资料和当次成绩,不包含其他志愿。
|
||||
|
||||
### 招生学校审核
|
||||
|
||||
招生学校可:
|
||||
|
||||
- 接收投档;
|
||||
- 填写特殊理由申请退档;
|
||||
- 查看本校计划录取率;
|
||||
- 维护录取通知书标题、正文、落款和配色。
|
||||
|
||||
退档由超级管理员统一审批。
|
||||
|
||||
### 正式录取
|
||||
|
||||
超级管理员签发正式录取后,系统按“招生学校代码 + 考试代码 + 校内独立流水号”生成稳定通知书编号,并开启招生学校报到工作台。
|
||||
|
||||
### 报到与补录
|
||||
|
||||
招生学校可以:
|
||||
|
||||
- 逐人暂存 `Y`、`N`、`P` 报到状态;
|
||||
- 导出带下拉校验的 Excel;
|
||||
- 修改后导入;
|
||||
- 扫描通知书二维码预检;
|
||||
- 确认扫描后登记;
|
||||
- 提交完整报到情况;
|
||||
- 选择不补录或申请补录。
|
||||
|
||||
扫描预览只做核验,不写入报到状态;正式扫描确认才产生业务变更。学校提交前的草稿不会进入超级管理员审批。
|
||||
|
||||
超级管理员审批各学校决定后,按缺额进入下一轮补录或结束录取。每轮结果都应独立保留和发布,不能只保留最终总状态。
|
||||
|
||||
## 11. Excel 操作建议
|
||||
|
||||
系统为班级、管理员、报名号、考生、缴费、考点考场、成绩、志愿、录取和报到等业务提供模板、导入与导出。
|
||||
|
||||
操作前:
|
||||
|
||||
1. 从当前页面下载最新模板,不复用旧版本模板。
|
||||
2. 保留隐藏标识列和表头。
|
||||
3. 不随意修改单元格数据验证。
|
||||
4. 使用页面提供的当前范围导出作为修改基础。
|
||||
5. 导入后逐条检查错误行和预览摘要。
|
||||
6. 只有确认目标范围正确后才提交写入。
|
||||
|
||||
只读角色可能仍保留导出能力,但不能通过修改请求完成写操作。
|
||||
|
||||
## 12. 审计与操作规范
|
||||
|
||||
- 每名管理员使用自己的账号。
|
||||
- 重要审批意见说明事实和原因。
|
||||
- 批量操作前先筛选并核对选中范围。
|
||||
- 不通过数据库直接修改业务状态。
|
||||
- 数据导出按敏感文件管理,使用后及时清理。
|
||||
- 归档、正式录取、批量导入、重建数据库等高影响操作执行前保留备份或导出。
|
||||
- 发现登录过期时重新登录,不要求使用者靠刷新页面恢复会话。
|
||||
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
# 系统架构
|
||||
|
||||
衡准考试信息管理系统采用 ASP.NET Core 10 模块化单体架构。生产环境部署一个 `Eis.Web` 进程,前端静态资源和 API 由同一宿主提供;数据库维护工具 `Eis.Tools` 独立发布。
|
||||
|
||||
## 1. 总体结构
|
||||
|
||||
```text
|
||||
浏览器
|
||||
├─ Vue 3 单页应用
|
||||
├─ 公开页面 / 考生中心 / 管理后台 / 招生学校端
|
||||
└─ PDF 文书生成模块
|
||||
│ HTTPS / JSON / Cookie
|
||||
▼
|
||||
Eis.Web(ASP.NET Core)
|
||||
├─ 静态资源与 SPA History 回退
|
||||
├─ Minimal API 端点
|
||||
├─ 身份识别、角色与数据范围校验
|
||||
└─ 健康检查
|
||||
│
|
||||
▼
|
||||
Eis.Application
|
||||
└─ 应用服务契约
|
||||
│
|
||||
▼
|
||||
Eis.Infrastructure
|
||||
├─ 业务服务与仓储
|
||||
├─ SQLite / MySQL
|
||||
├─ Redis / 本机缓存
|
||||
├─ Redis / 内存认证状态
|
||||
├─ ClosedXML
|
||||
└─ 安全与防伪服务
|
||||
```
|
||||
|
||||
## 2. 项目依赖
|
||||
|
||||
### Eis.Domain
|
||||
|
||||
领域层保存稳定业务概念和值,不包含 Web、数据库或前端细节。
|
||||
|
||||
### Eis.Application
|
||||
|
||||
应用层以接口描述用例,包括:
|
||||
|
||||
- 认证;
|
||||
- 考生服务;
|
||||
- 公开查询;
|
||||
- 管理中心;
|
||||
- 组织、账号、配置;
|
||||
- 考试、编排、成绩;
|
||||
- 审批、招生和录取。
|
||||
|
||||
端点依赖这些契约,而不是直接依赖数据库实现。
|
||||
|
||||
### Eis.Infrastructure
|
||||
|
||||
基础设施层实现:
|
||||
|
||||
- 关系数据库连接和初始化;
|
||||
- 管理员、考生、招生业务仓储;
|
||||
- 缓存和会话状态;
|
||||
- 密码、TOTP 和文书防伪;
|
||||
- Excel 读写;
|
||||
- 准考证、成绩单和录取通知书数据;
|
||||
- 审批流、统计和投档业务。
|
||||
|
||||
部分大型业务通过同名 partial 类拆分文件,例如考生服务和招生服务,以保持单个文件可维护。
|
||||
|
||||
### Eis.Web
|
||||
|
||||
Web 层负责:
|
||||
|
||||
- 加载 `.env` 和运行环境;
|
||||
- 组合依赖注入;
|
||||
- 初始化数据库;
|
||||
- HTTP 输入输出;
|
||||
- 获取当前身份;
|
||||
- 注册安全响应头;
|
||||
- 健康检查;
|
||||
- 静态资源;
|
||||
- SPA 路由回退。
|
||||
|
||||
复杂业务规则应留在 Infrastructure 的应用实现中,而不是放在端点委托。
|
||||
|
||||
### Eis.Tools
|
||||
|
||||
数据库工具复用 Infrastructure 的数据库选项、初始化和维护服务,提供:
|
||||
|
||||
- `database init`
|
||||
- `database reset`
|
||||
- `database seed`
|
||||
|
||||
工具可以和 Web 一起发布,但执行时不要求 Web 正在运行。SQLite 数据维护时反而应先停止 Web,避免并发写入。
|
||||
|
||||
## 3. HTTP 与前端
|
||||
|
||||
### API 域
|
||||
|
||||
| 前缀 | 面向对象 |
|
||||
| --- | --- |
|
||||
| `/api/public` | 未登录访客 |
|
||||
| `/api/auth` | 注册、登录、密码、TOTP、退出 |
|
||||
| `/api/candidate` | 当前考生 |
|
||||
| `/api/admin` | 超级、校级、班级管理员 |
|
||||
| `/api/admission` | 当前招生学校 |
|
||||
|
||||
未注册的 `/api/*` 由统一兜底端点返回 JSON 404,不会回退成 HTML,也不会转发到旧 Node.js 服务。
|
||||
|
||||
### SPA 路由
|
||||
|
||||
前端使用 Vue Router History 模式:
|
||||
|
||||
- `/candidate/...`
|
||||
- `/admin/...`
|
||||
- `/admission/...`
|
||||
|
||||
开发时由 Vite 提供页面并代理 API;生产时 ASP.NET Core 提供 `wwwroot/vue-app`,对非 API 语义 URL 返回前端入口。
|
||||
|
||||
### 会话初始化
|
||||
|
||||
前端进入路由前加载当前会话:
|
||||
|
||||
1. 未登录访问受保护页面:跳转登录页并携带返回地址。
|
||||
2. 已登录但角色不匹配:返回该角色首页。
|
||||
3. 考生必须改初始密码或资料未完成:跳转首次登录流程。
|
||||
4. 会话失效:重新登录,而不是假定刷新可恢复。
|
||||
|
||||
## 4. 认证与授权
|
||||
|
||||
### 凭据
|
||||
|
||||
- 密码使用 PBKDF2 加盐哈希。
|
||||
- TOTP 密钥使用 `TOTP_ENCRYPTION_KEY` 派生的材料,以 AES-256-GCM 加密保存。
|
||||
- 恢复码只保存带服务端密钥的哈希。
|
||||
- 登录状态通过 HttpOnly、SameSite Cookie 标识。
|
||||
|
||||
### 状态存储
|
||||
|
||||
未配置 Redis时:
|
||||
|
||||
- 登录 Session:进程内内存;
|
||||
- TOTP 登录挑战:进程内内存;
|
||||
- TOTP 绑定临时状态:进程内内存;
|
||||
- 进程重启后需要重新登录。
|
||||
|
||||
配置 Redis 时:
|
||||
|
||||
- 普通缓存通常使用 DB 0;
|
||||
- 认证状态默认自动使用 DB 1;
|
||||
- 也可用 `REDIS_SESSION_URL` 指向独立 Redis;
|
||||
- 系统拒绝让普通缓存和认证状态使用同一端点的同一逻辑 DB。
|
||||
|
||||
明确配置的认证 Redis 连接失败会阻止服务启动,避免多实例部署时静默退回本机内存。
|
||||
|
||||
### 数据范围
|
||||
|
||||
授权是多维度的:
|
||||
|
||||
```text
|
||||
角色
|
||||
└─ 管理级别
|
||||
└─ 学校
|
||||
└─ 班级
|
||||
└─ 具体业务状态
|
||||
```
|
||||
|
||||
招生学校角色另按自己的学校 ID 限制计划、投档和报到数据。投档材料不会包含考生的其他志愿。
|
||||
|
||||
## 5. 数据持久化
|
||||
|
||||
### 双数据库适配
|
||||
|
||||
- SQLite:本地开发、自动化测试、单机和默认 Docker 部署。
|
||||
- MySQL 8.4:生产、多实例或独立数据库部署。
|
||||
|
||||
两种数据库共享同一业务服务,并分别使用内嵌 schema SQL。数据库结构版本记录在 `schema_metadata`,当前为 v20。
|
||||
|
||||
### 总表与专属分表
|
||||
|
||||
系统采用“总表索引 + 独立物理分表”:
|
||||
|
||||
- 创建考试时建立:
|
||||
- `exam_<partition>_candidates`
|
||||
- `exam_<partition>_admissions`
|
||||
- `exam_<partition>_results`
|
||||
- `exam_<partition>_centers`
|
||||
- 创建学校时建立:
|
||||
- `school_<partition>_students`
|
||||
|
||||
分区键由业务 ID 的 SHA-256 摘要生成,不直接拼接用户输入。总表继续承担跨考试、跨学校查询和外键完整性,专属表支持按业务对象组织数据。
|
||||
|
||||
### 事务与审计
|
||||
|
||||
以下操作强调原子性:
|
||||
|
||||
- 报名号批量生成;
|
||||
- 批量成绩确认写入;
|
||||
- 成绩复议改分和相关结论;
|
||||
- 招生投档与正式录取;
|
||||
- 业务写入和审计日志。
|
||||
|
||||
批量操作失败时应整体回滚,避免半批状态。预览类操作不得开启正式写入。
|
||||
|
||||
## 6. 数据库状态快照
|
||||
|
||||
关系表读取会在进程内复用只读快照,避免每个请求重复扫描和转换全部业务数据。
|
||||
|
||||
- 应用自身写入:立即使快照失效。
|
||||
- SQLite:通过 `PRAGMA data_version` 识别其他连接的提交。
|
||||
- MySQL 外部直写:默认最多延迟 `DATABASE_STATE_CACHE_TTL_MS` 后可见。
|
||||
|
||||
因此不建议绕过应用直接写数据库。除审计缺失外,外部直写还可能造成短时间读到旧快照。
|
||||
|
||||
## 7. 应用缓存
|
||||
|
||||
缓存命名空间:
|
||||
|
||||
- `public`:首页和已发布公告;
|
||||
- `results`:考生已发布成绩。
|
||||
|
||||
特性:
|
||||
|
||||
- Redis 可选;
|
||||
- Redis 不可用时回退到有界本机缓存;
|
||||
- 热点请求合并,避免同一 key 并发回源;
|
||||
- 通过命名空间版本做批量失效;
|
||||
- 写入后主动失效。
|
||||
|
||||
公开缓存默认 60 秒,成绩缓存默认 24 小时。本机缓存默认最多 200 条。
|
||||
|
||||
## 8. Excel 和 PDF
|
||||
|
||||
### Excel
|
||||
|
||||
ClosedXML 在服务端生成和解析工作簿。导入一般遵循:
|
||||
|
||||
```text
|
||||
下载模板
|
||||
→ 填写
|
||||
→ 上传
|
||||
→ 逐行校验
|
||||
→ 页面预览
|
||||
→ 明确确认
|
||||
→ 事务写入
|
||||
```
|
||||
|
||||
这保证文件解析错误不会产生部分业务写入。
|
||||
|
||||
### PDF 文书
|
||||
|
||||
成绩单和录取通知书在浏览器端下载 PDF,数据由服务端按当前身份和发布状态提供。文书包含:
|
||||
|
||||
- 防伪查询码;
|
||||
- 二维码;
|
||||
- 公开验真地址;
|
||||
- HMAC 签名。
|
||||
|
||||
验真服务只返回允许公开核对的信息。
|
||||
|
||||
## 9. 健康检查
|
||||
|
||||
### `/health/live`
|
||||
|
||||
用于容器和进程存活检查,返回服务名和框架。
|
||||
|
||||
### `/health/migration`
|
||||
|
||||
用于诊断:
|
||||
|
||||
- 旧 API 已移除;
|
||||
- 原生认证、考生和管理模块状态;
|
||||
- 缓存 `ready`、`disabled` 或 `unavailable`;
|
||||
- 认证状态使用 `redis` 或 `memory`;
|
||||
- 当前启用的原生能力。
|
||||
|
||||
该路径名保留了迁移阶段语义,但当前系统已经完全运行于 ASP.NET Core。
|
||||
|
||||
## 10. 部署模型
|
||||
|
||||
### 单机
|
||||
|
||||
```text
|
||||
Eis.Web + SQLite + 内存会话/缓存
|
||||
```
|
||||
|
||||
适合开发、演示和低并发单实例。
|
||||
|
||||
### 生产
|
||||
|
||||
```text
|
||||
一个或多个 Eis.Web
|
||||
├─ MySQL 8.4
|
||||
├─ Redis 缓存 DB
|
||||
└─ Redis 认证状态 DB/实例
|
||||
```
|
||||
|
||||
多实例必须共享认证状态。静态资源包含在每个 Web 发布物中,不需要独立 Node.js 服务。
|
||||
|
||||
+228
@@ -0,0 +1,228 @@
|
||||
# 配置参考
|
||||
|
||||
应用从进程环境变量和仓库根目录 `.env` 读取配置。进程环境变量优先:如果同名变量已经由操作系统、容器或部署平台注入,`.env` 不会覆盖它。
|
||||
|
||||
## 1. 配置文件
|
||||
|
||||
本地开发:
|
||||
|
||||
```powershell
|
||||
Copy-Item -LiteralPath .\.env.example -Destination .\.env
|
||||
```
|
||||
|
||||
Docker Compose:
|
||||
|
||||
```powershell
|
||||
Copy-Item -LiteralPath .\.env.docker.example -Destination .\.env.docker
|
||||
```
|
||||
|
||||
`.env` 支持:
|
||||
|
||||
- 空行;
|
||||
- `#` 注释;
|
||||
- `KEY=value`;
|
||||
- 可选 `export KEY=value`;
|
||||
- 单引号或双引号包裹的完整值。
|
||||
|
||||
修改 `.env` 后需要重启应用。
|
||||
|
||||
## 2. 基础运行配置
|
||||
|
||||
| 变量 | 默认/示例 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `ASPNETCORE_ENVIRONMENT` | 本地 `Development` | `Production` 会启用生产密钥和数据库要求 |
|
||||
| `ASPNETCORE_URLS` | `http://127.0.0.1:4173` | Kestrel 监听地址 |
|
||||
| `DATABASE_CLIENT` | 开发 `sqlite`,生产 `mysql` | 仅支持 `sqlite`、`mysql` |
|
||||
|
||||
如果直接设置 `ASPNETCORE_ENVIRONMENT=Production` 而没有配置 MySQL 和两个生产密钥,应用会拒绝启动,这是预期的安全行为。
|
||||
|
||||
## 3. SQLite
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `SQLITE_PATH` | `./data/exam.sqlite` | 相对路径按应用根目录解析,也可使用绝对路径 |
|
||||
|
||||
示例:
|
||||
|
||||
```powershell
|
||||
$env:DATABASE_CLIENT = 'sqlite'
|
||||
$env:SQLITE_PATH = './data/exam.sqlite'
|
||||
dotnet run --project .\src\Eis.Web\Eis.Web.csproj
|
||||
```
|
||||
|
||||
## 4. MySQL 8.4
|
||||
|
||||
可以使用分项变量:
|
||||
|
||||
| 变量 | 必填 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `MYSQL_HOST` | 是 | 无 | MySQL 主机 |
|
||||
| `MYSQL_PORT` | 否 | `3306` | 端口 |
|
||||
| `MYSQL_USER` | 是 | 无 | 应用账号 |
|
||||
| `MYSQL_PASSWORD` | 视账号而定 | 空 | 密码 |
|
||||
| `MYSQL_DATABASE` | 是 | 无 | 数据库名 |
|
||||
| `MYSQL_CONNECTION_LIMIT` | 否 | `10` | 连接池最大连接数 |
|
||||
|
||||
也可以只设置:
|
||||
|
||||
| 变量 | 示例 |
|
||||
| --- | --- |
|
||||
| `DATABASE_URL` | `mysql://exam_app:password@127.0.0.1:3306/exam_information` |
|
||||
|
||||
`DATABASE_URL` 优先于全部 `MYSQL_*` 连接项。用户名和密码含特殊字符时必须按 URL 规则编码。
|
||||
|
||||
连接默认:
|
||||
|
||||
- 字符集 `utf8mb4`;
|
||||
- 连接超时 10 秒;
|
||||
- 命令超时 30 秒;
|
||||
- 启用连接池和连接重置。
|
||||
|
||||
## 5. 初始管理员
|
||||
|
||||
这些变量只在创建空数据库的初始管理员时使用:
|
||||
|
||||
| 变量 | 本地模板 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `INITIAL_ADMIN_USERNAME` | `admin` | 初始超级管理员账号 |
|
||||
| `INITIAL_ADMIN_PASSWORD` | `Admin123!` | 初始密码,生产必须更换 |
|
||||
| `INITIAL_ADMIN_DISPLAY_NAME` | `系统管理员` | 显示名 |
|
||||
|
||||
修改这些变量不会自动修改已经存在的管理员。已有账号应通过系统的密码修改或管理员重置功能维护。
|
||||
|
||||
## 6. TOTP 与文书防伪
|
||||
|
||||
| 变量 | 生产要求 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `TOTP_ENCRYPTION_KEY` | 至少 32 个字符 | 加密 TOTP 密钥并保护恢复码哈希 |
|
||||
| `DOCUMENT_VERIFICATION_SECRET` | 至少 32 个字符 | 对成绩单和录取通知书防伪载荷签名 |
|
||||
|
||||
要求:
|
||||
|
||||
- 两个值相互独立;
|
||||
- 不与数据库密码、Cookie 或其他系统密钥共用;
|
||||
- 由秘密管理平台或部署平台注入;
|
||||
- 部署后稳定保存;
|
||||
- 不提交到 Git。
|
||||
|
||||
影响:
|
||||
|
||||
- 更换 `TOTP_ENCRYPTION_KEY`:已绑定 TOTP 可能无法解密。
|
||||
- 更换 `DOCUMENT_VERIFICATION_SECRET`:历史文书查询码会失效。
|
||||
|
||||
开发环境未配置时使用仅供开发的稳定派生值。`DOCUMENT_VERIFICATION_SECRET` 未设置时还兼容读取 `SESSION_SECRET`,但新部署应使用独立变量,不依赖兼容路径。
|
||||
|
||||
## 7. Redis 普通缓存
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `REDIS_URL` | 未配置 | `redis://` 或 `rediss://` 地址,可在路径指定逻辑 DB |
|
||||
| `REDIS_CACHE_PREFIX` | `exam-information` | 缓存 key 前缀 |
|
||||
| `REDIS_CACHE_TTL_SECONDS` | `60` | 公开数据缓存秒数,最大 86400 |
|
||||
| `REDIS_RESULTS_CACHE_TTL_SECONDS` | `86400` | 已发布成绩缓存秒数 |
|
||||
| `REDIS_CONNECT_TIMEOUT_MS` | `1500` | Redis 连接超时,最大 30000 |
|
||||
| `LOCAL_CACHE_MAX_ENTRIES` | `200` | 本机回退缓存上限,最大 5000 |
|
||||
|
||||
普通缓存 Redis 暂时不可用时,应用回退到本机缓存,并保持写后失效语义。
|
||||
|
||||
## 8. Redis 认证状态
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `REDIS_SESSION_URL` | 复用 `REDIS_URL` 端点 | 可指定独立 Redis |
|
||||
| `REDIS_SESSION_DB` | 缓存 DB 为 0 时自动选 1,否则选 0 | 认证状态逻辑 DB |
|
||||
| `REDIS_SESSION_PREFIX` | `exam-information:auth` | Session 和临时状态 key 前缀 |
|
||||
| `AUTH_SESSION_TTL_SECONDS` | `28800` | 登录 Session,默认 8 小时,最大 30 天 |
|
||||
| `AUTH_LOGIN_CHALLENGE_TTL_SECONDS` | `300` | TOTP 登录挑战,最大 1 小时 |
|
||||
| `AUTH_TOTP_SETUP_TTL_SECONDS` | `600` | TOTP 绑定临时状态,最大 1 小时 |
|
||||
|
||||
普通缓存和认证状态不得使用同一 Redis 端点的同一逻辑 DB。错误配置时应用拒绝启动。
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
REDIS_URL=redis://127.0.0.1:6379/0
|
||||
REDIS_SESSION_DB=1
|
||||
```
|
||||
|
||||
独立实例:
|
||||
|
||||
```text
|
||||
REDIS_URL=rediss://cache.example.com:6379/0
|
||||
REDIS_SESSION_URL=rediss://session.example.com:6379/0
|
||||
```
|
||||
|
||||
Redis Cluster 通常不支持非 0 逻辑 DB,此时应使用 `REDIS_SESSION_URL` 指向独立端点或实例。
|
||||
|
||||
## 9. 数据状态快照
|
||||
|
||||
| 变量 | 默认值 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `DATABASE_STATE_CACHE_TTL_MS` | `30000` | MySQL 外部直写后,全量只读快照最长复用毫秒数 |
|
||||
|
||||
应用内写入会立即失效;SQLite 还会通过 `PRAGMA data_version` 识别外部连接提交。
|
||||
|
||||
## 10. 公开站点信息
|
||||
|
||||
| 变量 | 用途 |
|
||||
| --- | --- |
|
||||
| `PUBLIC_SITE_NAME` | 机构名称 |
|
||||
| `PUBLIC_SITE_CODE` | 机构代码 |
|
||||
| `PUBLIC_SITE_PHONE` | 联系电话 |
|
||||
| `PUBLIC_SITE_ADDRESS` | 地址 |
|
||||
| `PUBLIC_SITE_EMAIL` | 邮箱 |
|
||||
| `PUBLIC_SITE_HERO_EYEBROW` | 首页英文眉题 |
|
||||
| `PUBLIC_SITE_HERO_TITLE` | 首页主标题前半段 |
|
||||
| `PUBLIC_SITE_HERO_HIGHLIGHT` | 首页主标题强调段 |
|
||||
| `PUBLIC_SITE_HERO_DESCRIPTION` | 首页说明 |
|
||||
| `PUBLIC_SITE_FOOTER_NOTICE` | 页脚提示 |
|
||||
|
||||
这些变量会覆盖数据库中的演示机构展示信息,只通过公开首页接口返回非敏感字段。
|
||||
|
||||
## 11. 兼容迁移开关
|
||||
|
||||
源码仍可读取 `AUTH_NATIVE_ENABLED`、`CANDIDATE_NATIVE_ENABLED` 和若干 `ADMIN_NATIVE_*` 变量,但当前 `appsettings.json` 已默认启用全部 ASP.NET Core 原生域,旧 Node.js API 已移除。
|
||||
|
||||
正常部署不需要设置这些变量。除非正在调试迁移兼容行为,不应把它们加入新环境模板。
|
||||
|
||||
## 12. 生产配置示例
|
||||
|
||||
以下只展示结构,密钥和密码必须替换:
|
||||
|
||||
```text
|
||||
ASPNETCORE_ENVIRONMENT=Production
|
||||
ASPNETCORE_URLS=http://0.0.0.0:4173
|
||||
|
||||
DATABASE_CLIENT=mysql
|
||||
MYSQL_HOST=mysql.internal
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_USER=exam_app
|
||||
MYSQL_PASSWORD=replace-me
|
||||
MYSQL_DATABASE=exam_information
|
||||
MYSQL_CONNECTION_LIMIT=20
|
||||
|
||||
REDIS_URL=rediss://cache.internal:6379/0
|
||||
REDIS_SESSION_URL=rediss://session.internal:6379/0
|
||||
REDIS_CACHE_PREFIX=exam-information
|
||||
REDIS_SESSION_PREFIX=exam-information:auth
|
||||
|
||||
TOTP_ENCRYPTION_KEY=replace-with-a-unique-secret-at-least-32-characters
|
||||
DOCUMENT_VERIFICATION_SECRET=replace-with-another-unique-secret-at-least-32-characters
|
||||
|
||||
INITIAL_ADMIN_USERNAME=admin
|
||||
INITIAL_ADMIN_PASSWORD=replace-with-a-strong-initial-password
|
||||
INITIAL_ADMIN_DISPLAY_NAME=系统管理员
|
||||
```
|
||||
|
||||
## 13. 上线检查
|
||||
|
||||
- `ASPNETCORE_ENVIRONMENT=Production`。
|
||||
- 数据库目标明确,不是测试库或旧 SQLite 文件。
|
||||
- 两项 32 字符以上的独立密钥已由秘密管理注入。
|
||||
- 初始管理员密码已更换。
|
||||
- Redis 缓存与认证状态未使用同一逻辑 DB。
|
||||
- 多实例已使用共享认证 Redis。
|
||||
- `.env`、`.env.docker` 未提交到版本库。
|
||||
- 公开机构信息已改成真实信息。
|
||||
- `/health/live` 和 `/health/migration` 可由运维系统检查。
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
# 数据库与数据工具
|
||||
|
||||
本页包含会修改数据的命令。执行前先确认目标数据库、停止应用并完成备份。示例命令不会在阅读 Wiki 时自动执行。
|
||||
|
||||
## 1. 支持的数据库
|
||||
|
||||
| 数据库 | 推荐场景 | 特点 |
|
||||
| --- | --- | --- |
|
||||
| SQLite | 本地开发、测试、演示、单机部署 | 单文件、零外部依赖 |
|
||||
| MySQL 8.4 | 生产、多实例、集中运维 | 独立服务、连接池、并发能力更强 |
|
||||
|
||||
应用启动时会初始化空库结构和基础配置,但不会自动导入学校、考生、考试或报名等演示业务数据。
|
||||
|
||||
当前结构版本是 v20。已有数据库版本低于 v20 时,应用会拒绝直接运行并要求先备份和执行明确的升级流程。
|
||||
|
||||
## 2. 数据库目标识别
|
||||
|
||||
应用根目录通常是包含 `Eis.slnx` 或 `.env` 的目录。
|
||||
|
||||
SQLite:
|
||||
|
||||
- 默认:`<应用根目录>/data/exam.sqlite`
|
||||
- `SQLITE_PATH` 相对路径:按应用根目录解析
|
||||
- `--path`:数据库工具命令的显式 SQLite 目标
|
||||
|
||||
MySQL:
|
||||
|
||||
- `DATABASE_URL` 优先;
|
||||
- 否则读取 `MYSQL_HOST`、`MYSQL_PORT`、`MYSQL_USER`、`MYSQL_PASSWORD`、`MYSQL_DATABASE`;
|
||||
- 数据库工具确认目标时使用数据库名,不是主机名。
|
||||
|
||||
执行任何写操作前,先记录工具输出中的“目标”一行。
|
||||
|
||||
## 3. 建立 MySQL 数据库和账号
|
||||
|
||||
示例:
|
||||
|
||||
```sql
|
||||
CREATE DATABASE exam_information
|
||||
CHARACTER SET utf8mb4
|
||||
COLLATE utf8mb4_0900_ai_ci;
|
||||
|
||||
CREATE USER 'exam_app'@'%'
|
||||
IDENTIFIED BY 'replace-with-a-strong-password';
|
||||
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER
|
||||
ON exam_information.*
|
||||
TO 'exam_app'@'%';
|
||||
```
|
||||
|
||||
应用需要创建和演进表结构,因此账号除了数据读写外还需要 `CREATE` 和 `ALTER`。不要授予 MySQL 全局管理员权限。
|
||||
|
||||
配置方式见[配置参考](Configuration)。
|
||||
|
||||
## 4. 数据库结构
|
||||
|
||||
主要关系表包括:
|
||||
|
||||
- 组织:`organization`、`schools`、`school_classes`
|
||||
- 用户:`users`、`candidate_profiles`
|
||||
- 考试:`exams`、`exam_subjects`
|
||||
- 报名:`registrations`、`registration_subjects`
|
||||
- 编排:`test_centers`、`test_rooms`、`exam_arrangement_plans`、`admit_cards`、`admit_card_subjects`
|
||||
- 成绩:`results`
|
||||
- 流程:`workflow_definitions`、`workflow_steps`、`workflow_instances`、`workflow_actions`
|
||||
- 报名号:`number_rules`、`number_rule_segments`、`candidate_account_batches`、`candidate_account_batch_items`
|
||||
- 招生:招生计划、志愿、投档、录取、报到及相关记录
|
||||
- 公告与审计:`notices`、`audit_logs`
|
||||
- 分表登记:`exam_data_partitions`、`school_student_partitions`
|
||||
- 版本:`schema_metadata`
|
||||
|
||||
系统还为每场考试和每所学校维护专属物理分表。不要只备份总表或只复制少数业务表。
|
||||
|
||||
## 5. 获取数据库工具
|
||||
|
||||
统一发布:
|
||||
|
||||
```powershell
|
||||
pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\scripts\publish.ps1
|
||||
```
|
||||
|
||||
工具位于:
|
||||
|
||||
```text
|
||||
artifacts/publish/tools/Eis.Tools.dll
|
||||
```
|
||||
|
||||
查看帮助:
|
||||
|
||||
```powershell
|
||||
dotnet .\artifacts\publish\tools\Eis.Tools.dll --help
|
||||
```
|
||||
|
||||
源码开发时也可以:
|
||||
|
||||
```powershell
|
||||
dotnet run --project .\src\Eis.Tools\Eis.Tools.csproj -- --help
|
||||
```
|
||||
|
||||
## 6. 命令概览
|
||||
|
||||
```text
|
||||
database init 非破坏性建表和基础配置初始化
|
||||
database reset 重建为空业务库
|
||||
database seed 导入内置 1200 名考生演示数据
|
||||
```
|
||||
|
||||
通用参数:
|
||||
|
||||
| 参数 | 说明 |
|
||||
| --- | --- |
|
||||
| `--sqlite` | 明确使用 SQLite |
|
||||
| `--mysql` | 明确使用 MySQL |
|
||||
| `--path <文件>` | SQLite 文件路径,只能与 `--sqlite` 一起使用 |
|
||||
| `--confirm-target <目标>` | 对破坏性命令确认最终目标 |
|
||||
| `--force` | 仅 MySQL;允许覆盖无法识别为内置演示数据的业务数据 |
|
||||
| `--dry-run` | 只预检,不写入 |
|
||||
| `--root <目录>` | 指定 `.env` 和相对 SQLite 路径的应用根目录 |
|
||||
|
||||
`--sqlite` 与 `--mysql` 不能同时使用。`database init` 不接受 `--force`。
|
||||
|
||||
## 7. 初始化空库
|
||||
|
||||
### SQLite
|
||||
|
||||
```powershell
|
||||
dotnet .\artifacts\publish\tools\Eis.Tools.dll database init `
|
||||
--sqlite `
|
||||
--path .\data\exam.sqlite
|
||||
```
|
||||
|
||||
### MySQL
|
||||
|
||||
先配置 `.env` 或进程环境变量,然后:
|
||||
|
||||
```powershell
|
||||
dotnet .\artifacts\publish\tools\Eis.Tools.dll database init --mysql
|
||||
```
|
||||
|
||||
`init` 是非破坏性操作,用于建表和基础配置。它不会导入演示学校、考生或考试。
|
||||
|
||||
## 8. 导入演示数据
|
||||
|
||||
演示数据内置于 `Eis.Infrastructure.dll`,生产服务器不需要 Node.js。
|
||||
|
||||
### SQLite 安全流程
|
||||
|
||||
第一步,只预检:
|
||||
|
||||
```powershell
|
||||
dotnet .\artifacts\publish\tools\Eis.Tools.dll database seed `
|
||||
--sqlite `
|
||||
--path .\data\demo.sqlite `
|
||||
--dry-run
|
||||
```
|
||||
|
||||
第二步,核对工具显示的绝对目标路径。
|
||||
|
||||
第三步,明确确认同一目标:
|
||||
|
||||
```powershell
|
||||
dotnet .\artifacts\publish\tools\Eis.Tools.dll database seed `
|
||||
--sqlite `
|
||||
--path .\data\demo.sqlite `
|
||||
--confirm-target .\data\demo.sqlite
|
||||
```
|
||||
|
||||
如果目标文件已存在,工具先复制为:
|
||||
|
||||
```text
|
||||
<数据库文件>.backup-<UTC时间戳>
|
||||
```
|
||||
|
||||
### MySQL 测试库安全流程
|
||||
|
||||
第一步:
|
||||
|
||||
```powershell
|
||||
dotnet .\artifacts\publish\tools\Eis.Tools.dll database seed --mysql --dry-run
|
||||
```
|
||||
|
||||
确认输出的数据库名确实是测试库,例如 `exam_test`。
|
||||
|
||||
第二步:
|
||||
|
||||
```powershell
|
||||
dotnet .\artifacts\publish\tools\Eis.Tools.dll database seed `
|
||||
--mysql `
|
||||
--confirm-target exam_test
|
||||
```
|
||||
|
||||
如果工具发现无法识别为内置演示数据的业务记录,会拒绝覆盖。只有在已经备份且确认这个测试库可以完全覆盖时才使用:
|
||||
|
||||
```powershell
|
||||
dotnet .\artifacts\publish\tools\Eis.Tools.dll database seed `
|
||||
--mysql `
|
||||
--confirm-target exam_test `
|
||||
--force
|
||||
```
|
||||
|
||||
`--force` 不会删除数据库本身,但会改写其中的应用数据。不得对生产业务库使用。
|
||||
|
||||
## 9. 演示账号
|
||||
|
||||
演示数据中的预置账号密码统一为 `12345678`:
|
||||
|
||||
| 角色 | 账号 |
|
||||
| --- | --- |
|
||||
| 超级管理员 | `admin` |
|
||||
| 超级管理员(监督演示) | `supervisor` |
|
||||
| 校级管理员 | `school_admin` |
|
||||
| 同校校级管理员 | `school_admin_2` |
|
||||
| 班级管理员 | `class_admin` |
|
||||
| 同班班级管理员 | `class_admin_2` |
|
||||
| 考生 | `2026-HZ01-F-0001` |
|
||||
|
||||
这些账号只存在于演示数据。正常启动空库时不会创建校级、班级或考生样例账号。
|
||||
|
||||
## 10. 测试结束后重建空系统
|
||||
|
||||
### SQLite
|
||||
|
||||
先停止应用:
|
||||
|
||||
```powershell
|
||||
dotnet .\artifacts\publish\tools\Eis.Tools.dll database reset `
|
||||
--sqlite `
|
||||
--path .\data\exam.sqlite `
|
||||
--confirm-target .\data\exam.sqlite
|
||||
```
|
||||
|
||||
工具自动备份原 SQLite 文件,然后建立 v20 空业务系统和初始超级管理员。
|
||||
|
||||
### MySQL
|
||||
|
||||
先预检:
|
||||
|
||||
```powershell
|
||||
dotnet .\artifacts\publish\tools\Eis.Tools.dll database reset --mysql --dry-run
|
||||
```
|
||||
|
||||
再确认测试数据库名:
|
||||
|
||||
```powershell
|
||||
dotnet .\artifacts\publish\tools\Eis.Tools.dll database reset `
|
||||
--mysql `
|
||||
--confirm-target exam_test
|
||||
```
|
||||
|
||||
目标包含非演示业务数据时会拒绝。即使使用 `--force`,也应先完成 MySQL 原生备份。
|
||||
|
||||
## 11. Docker 中维护 SQLite
|
||||
|
||||
Compose 默认数据库路径是 `/app/data/exam.sqlite`,保存在命名卷 `exam-information-data`。
|
||||
|
||||
先停止 Web:
|
||||
|
||||
```powershell
|
||||
docker compose stop app
|
||||
```
|
||||
|
||||
再运行工具,目标和确认路径必须完全一致:
|
||||
|
||||
```powershell
|
||||
docker compose run --rm --entrypoint dotnet app `
|
||||
/app/tools/Eis.Tools.dll database seed `
|
||||
--sqlite `
|
||||
--path /app/data/exam.sqlite `
|
||||
--confirm-target /app/data/exam.sqlite
|
||||
```
|
||||
|
||||
完成后启动:
|
||||
|
||||
```powershell
|
||||
docker compose up --detach app
|
||||
```
|
||||
|
||||
不要对容器内另一个临时路径执行 seed 后误以为已经修改命名卷数据库。
|
||||
|
||||
## 12. 备份与恢复建议
|
||||
|
||||
### SQLite
|
||||
|
||||
维护前:
|
||||
|
||||
1. 停止所有使用该文件的 Web 和工具进程。
|
||||
2. 记录数据库绝对路径。
|
||||
3. 复制数据库文件到独立备份目录。
|
||||
4. 保留工具自动生成的时间戳备份。
|
||||
5. 恢复时先停止应用,再用备份文件替换目标。
|
||||
|
||||
不要只复制 `-wal` 或 `-shm` 文件。应用运行时直接复制数据库可能得到不一致备份,应优先停机。
|
||||
|
||||
### MySQL
|
||||
|
||||
使用组织既有的 MySQL 备份方案,例如逻辑备份、快照或托管服务备份。至少验证:
|
||||
|
||||
- 备份包含全部表和结构;
|
||||
- 恢复到隔离测试库成功;
|
||||
- 字符集为 `utf8mb4`;
|
||||
- 应用账号权限仍正确;
|
||||
- 恢复库结构版本是 v20。
|
||||
|
||||
## 13. 安全保护
|
||||
|
||||
数据库工具会:
|
||||
|
||||
- 要求破坏性命令明确 `--confirm-target`;
|
||||
- SQLite 比较最终绝对路径;
|
||||
- MySQL 比较数据库名;
|
||||
- 拒绝 `mysql`、`information_schema`、`performance_schema`、`sys` 等系统库;
|
||||
- 校验演示数据和数据库结构版本;
|
||||
- 默认拒绝覆盖未知 MySQL 业务数据;
|
||||
- 为已有 SQLite 文件自动建立时间戳备份。
|
||||
|
||||
这些保护不能代替人工确认和外部备份。
|
||||
|
||||
## 14. 常见错误
|
||||
|
||||
### “这是破坏性操作”
|
||||
|
||||
缺少 `--confirm-target`,或确认值和最终目标不一致。重新查看工具输出,不要盲目复制旧命令。
|
||||
|
||||
### “数据库结构版本低于要求”
|
||||
|
||||
当前应用要求 v20。停止上线,保留完整备份,并执行针对旧版本的升级流程;不要用 `reset` 假装完成生产迁移。
|
||||
|
||||
### “MySQL 配置不完整”
|
||||
|
||||
设置完整 `DATABASE_URL`,或至少设置 `MYSQL_HOST`、`MYSQL_USER`、`MYSQL_DATABASE`。
|
||||
|
||||
### “拒绝覆盖非演示业务数据”
|
||||
|
||||
目标中存在工具无法确认可覆盖的数据。先核对是否选错库。只有确认是可完全覆盖的测试库并已备份时才考虑 `--force`。
|
||||
|
||||
### SQLite 文件没有变化
|
||||
|
||||
检查:
|
||||
|
||||
- `--path` 是否指向预期文件;
|
||||
- 相对路径按哪个 `--root` 解析;
|
||||
- 容器中是否使用 `/app/data/exam.sqlite`;
|
||||
- Web 是否仍在运行并占用或继续写另一个数据库。
|
||||
|
||||
@@ -0,0 +1,383 @@
|
||||
# 部署与发布
|
||||
|
||||
项目支持框架依赖发布、自包含跨平台程序包和 Docker 镜像。生产部署前先完成[配置参考](Configuration)中的上线检查。
|
||||
|
||||
## 1. 部署前准备
|
||||
|
||||
至少准备:
|
||||
|
||||
- 生产 MySQL 8.4 数据库及最小权限账号;
|
||||
- 两项相互独立且至少 32 字符的密钥;
|
||||
- 强初始管理员密码;
|
||||
- HTTPS 入口或反向代理;
|
||||
- 持久化日志收集方式;
|
||||
- 数据库备份和恢复方案;
|
||||
- 多实例部署所需 Redis;
|
||||
- 端口、防火墙和健康检查策略。
|
||||
|
||||
生产环境不需要 Node.js 运行服务。Node.js 只在构建 Vue 前端时使用。
|
||||
|
||||
## 2. 本机统一发布
|
||||
|
||||
在仓库根目录运行:
|
||||
|
||||
```powershell
|
||||
pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\scripts\publish.ps1
|
||||
```
|
||||
|
||||
脚本会:
|
||||
|
||||
1. 在 `ClientApp` 执行 `npm ci`;
|
||||
2. 构建 Vue 生产资源;
|
||||
3. 发布 `Eis.Web`;
|
||||
4. 发布 `Eis.Tools`。
|
||||
|
||||
输出:
|
||||
|
||||
```text
|
||||
artifacts/publish/web
|
||||
artifacts/publish/tools
|
||||
```
|
||||
|
||||
启动 Web:
|
||||
|
||||
```powershell
|
||||
dotnet .\artifacts\publish\web\Eis.Web.dll
|
||||
```
|
||||
|
||||
查看数据库工具:
|
||||
|
||||
```powershell
|
||||
dotnet .\artifacts\publish\tools\Eis.Tools.dll --help
|
||||
```
|
||||
|
||||
这种发布方式需要服务器预装兼容的 .NET 10 Runtime。
|
||||
|
||||
## 3. 发布物目录建议
|
||||
|
||||
生产服务器可采用:
|
||||
|
||||
```text
|
||||
eis/
|
||||
├─ current/ 当前 Web 发布物
|
||||
├─ tools/ 与当前版本匹配的数据库工具
|
||||
├─ config/ 由平台管理,不纳入发布压缩包
|
||||
├─ data/ 仅 SQLite 部署使用
|
||||
├─ logs/ 若采用文件日志
|
||||
└─ releases/
|
||||
├─ 1.2.2/
|
||||
└─ 1.2.3/
|
||||
```
|
||||
|
||||
配置和持久化数据不要放进每次覆盖的应用发布目录。升级前保留上一版发布物,以便代码回滚;数据库发生不兼容升级时,还必须配套数据库恢复方案。
|
||||
|
||||
## 4. 自包含跨平台程序包
|
||||
|
||||
Gitea Actions 默认构建:
|
||||
|
||||
- `win-x64`:`.zip`
|
||||
- `linux-x64`:`.tar.gz`
|
||||
- `linux-arm64`:`.tar.gz`
|
||||
|
||||
手动选择扩展平台后增加:
|
||||
|
||||
- `win-arm64`
|
||||
- `osx-x64`
|
||||
- `osx-arm64`
|
||||
|
||||
每个包包含:
|
||||
|
||||
```text
|
||||
eis-<版本>-<RID>/
|
||||
├─ app/ Web 与数据库工具,共享运行时和依赖
|
||||
├─ README.md
|
||||
├─ LICENSE
|
||||
└─ .env.example
|
||||
```
|
||||
|
||||
还会生成 `SHA256SUMS`。
|
||||
|
||||
Windows 启动:
|
||||
|
||||
```powershell
|
||||
.\app\Eis.Web.exe
|
||||
```
|
||||
|
||||
Windows 数据库工具:
|
||||
|
||||
```powershell
|
||||
.\app\Eis.Tools.exe --help
|
||||
```
|
||||
|
||||
Linux/macOS:
|
||||
|
||||
```text
|
||||
./app/Eis.Web
|
||||
./app/Eis.Tools --help
|
||||
```
|
||||
|
||||
自包含包不要求目标机预装 .NET Runtime。
|
||||
|
||||
## 5. Docker 镜像
|
||||
|
||||
本地构建:
|
||||
|
||||
```powershell
|
||||
docker build --tag hengzhun-exam-system:local .
|
||||
```
|
||||
|
||||
镜像:
|
||||
|
||||
- 基于 ASP.NET Core 10 Runtime;
|
||||
- 包含 Web 和 `/app/tools/Eis.Tools.dll`;
|
||||
- 默认监听 `0.0.0.0:4173`;
|
||||
- 使用非 root 用户;
|
||||
- 数据目录 `/app/data`;
|
||||
- 通过 `/health/live` 健康检查。
|
||||
|
||||
### Docker Compose
|
||||
|
||||
创建配置:
|
||||
|
||||
```powershell
|
||||
Copy-Item -LiteralPath .\.env.docker.example -Destination .\.env.docker
|
||||
```
|
||||
|
||||
替换密钥和管理员密码后:
|
||||
|
||||
```powershell
|
||||
docker compose up --build --detach
|
||||
docker compose ps
|
||||
docker compose logs --follow app
|
||||
```
|
||||
|
||||
默认使用 SQLite,数据库位于命名卷:
|
||||
|
||||
```text
|
||||
exam-information-data:/app/data
|
||||
```
|
||||
|
||||
停止并保留数据:
|
||||
|
||||
```powershell
|
||||
docker compose down
|
||||
```
|
||||
|
||||
删除容器和全部命名卷数据:
|
||||
|
||||
```powershell
|
||||
docker compose down --volumes
|
||||
```
|
||||
|
||||
最后一个命令具有破坏性,只在明确清空 SQLite 数据时使用。
|
||||
|
||||
## 6. MySQL 和 Redis 容器部署
|
||||
|
||||
使用外部 MySQL 时,以环境变量覆盖 Compose 中的默认 SQLite 配置:
|
||||
|
||||
```text
|
||||
DATABASE_CLIENT=mysql
|
||||
DATABASE_URL=mysql://...
|
||||
```
|
||||
|
||||
然后可以移除 SQLite 数据卷挂载,但应先确认没有需要迁移的现有 SQLite 数据。
|
||||
|
||||
使用 Redis:
|
||||
|
||||
```text
|
||||
REDIS_URL=redis://redis-host:6379/0
|
||||
REDIS_SESSION_DB=1
|
||||
```
|
||||
|
||||
容器中的 `127.0.0.1` 指向容器自身。MySQL 或 Redis 在其他容器或主机上时,应使用 Compose 服务名、内网 DNS 或实际主机地址。
|
||||
|
||||
## 7. 生产启动顺序
|
||||
|
||||
推荐:
|
||||
|
||||
1. 完成数据库备份。
|
||||
2. 部署新版本到独立目录或拉取新镜像。
|
||||
3. 使用与新版本匹配的工具执行非破坏性数据库预检或初始化。
|
||||
4. 注入生产环境变量。
|
||||
5. 单实例启动新版本。
|
||||
6. 检查 `/health/live` 和 `/health/migration`。
|
||||
7. 检查首页、登录、静态资源和数据库连接。
|
||||
8. 多实例部署时再逐步替换其余实例。
|
||||
9. 完成关键业务烟测。
|
||||
10. 保留上一版本和回滚记录。
|
||||
|
||||
若结构版本不匹配,不要继续滚动启动所有实例。
|
||||
|
||||
## 8. 健康检查与监控
|
||||
|
||||
### 存活
|
||||
|
||||
```text
|
||||
GET /health/live
|
||||
```
|
||||
|
||||
正常响应包含:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "healthy",
|
||||
"service": "Eis.Web",
|
||||
"framework": ".NET 10"
|
||||
}
|
||||
```
|
||||
|
||||
### 组件状态
|
||||
|
||||
```text
|
||||
GET /health/migration
|
||||
```
|
||||
|
||||
重点检查:
|
||||
|
||||
- `legacyApiRemoved: true`
|
||||
- `cache.status`
|
||||
- `authentication.stateBackend`
|
||||
- 原生模块启用状态
|
||||
|
||||
`cache.status=unavailable` 表示普通 Redis 不可用且正在使用本机回退;认证 Redis 如果明确配置却连接失败,应用通常无法完成启动。
|
||||
|
||||
监控还应包含:
|
||||
|
||||
- HTTP 5xx;
|
||||
- 登录失败率;
|
||||
- 数据库连接和慢查询;
|
||||
- Redis 连接;
|
||||
- 容器重启次数;
|
||||
- 磁盘或 SQLite 卷容量;
|
||||
- 关键批量任务和审批错误。
|
||||
|
||||
## 9. HTTPS 与代理
|
||||
|
||||
建议在受管入口、反向代理或负载均衡器终止 TLS,只对外提供 HTTPS。代理配置需要:
|
||||
|
||||
- 转发到应用 `4173`;
|
||||
- 保留必要的 Host 和转发协议头;
|
||||
- 允许 Excel/PDF 所需响应大小;
|
||||
- 对 Vue History 路由使用应用自己的回退,不把 `/api/*` 错误改写成首页;
|
||||
- 对登录 Cookie 保持同站点访问模型。
|
||||
|
||||
代理和应用的公开域名变化后,检查文书二维码中的验真链接是否指向正确外部地址。
|
||||
|
||||
## 10. Gitea Actions 发布
|
||||
|
||||
工作流:
|
||||
|
||||
```text
|
||||
.gitea/workflows/publish.yml
|
||||
```
|
||||
|
||||
触发方式:
|
||||
|
||||
- 推送 `v*` 标签;
|
||||
- Actions 页面手动运行;
|
||||
- 普通分支推送不会触发耗时发布。
|
||||
|
||||
流水线:
|
||||
|
||||
1. 构建 Vue;
|
||||
2. 运行 Release 配置的 .NET 测试;
|
||||
3. 构建自包含平台包;
|
||||
4. 上传工作流制品;
|
||||
5. 构建 `linux/amd64`、`linux/arm64` Docker 镜像;
|
||||
6. 推送 Docker Hub 和 Gitea Registry;
|
||||
7. 标签构建创建正式 Release 或 Pre-release。
|
||||
|
||||
### 必要配置
|
||||
|
||||
Actions Variables:
|
||||
|
||||
- `DOCKERHUB_IMAGE`
|
||||
- `REGISTRY_USERNAME`
|
||||
|
||||
Actions Secrets:
|
||||
|
||||
- `DOCKERHUB_USERNAME`
|
||||
- `DOCKERHUB_TOKEN`
|
||||
- `REGISTRY_TOKEN`
|
||||
|
||||
Release 使用内置 `GITEA_TOKEN`,仓库或组织的任务令牌最大权限需要允许 Releases Write。
|
||||
|
||||
Gitea 镜像当前固定发布到:
|
||||
|
||||
```text
|
||||
git.biss.click/biss/eis-dotnet
|
||||
```
|
||||
|
||||
Docker Hub 镜像名由 `DOCKERHUB_IMAGE` 变量决定。
|
||||
|
||||
Runner 需要访问:
|
||||
|
||||
- Docker daemon;
|
||||
- GitHub Actions 源;
|
||||
- Docker Hub;
|
||||
- `git.biss.click`;
|
||||
- QEMU 注册能力。
|
||||
|
||||
## 11. 版本标签
|
||||
|
||||
稳定版本:
|
||||
|
||||
```powershell
|
||||
git tag v1.2.3
|
||||
git push origin v1.2.3
|
||||
```
|
||||
|
||||
会生成语义化镜像标签和 `latest`。
|
||||
|
||||
预发布:
|
||||
|
||||
```powershell
|
||||
git tag v1.3.0-rc.1
|
||||
git push origin v1.3.0-rc.1
|
||||
```
|
||||
|
||||
带连字符的版本会创建 Gitea Pre-release,不覆盖稳定版 `latest` 或主次版本标签。
|
||||
|
||||
发布标签前应确认标签所指提交已经通过本地检查,标签推送后不应移动同名标签来替换已发布制品。
|
||||
|
||||
## 12. 升级与回滚
|
||||
|
||||
### 升级
|
||||
|
||||
- 阅读版本变更;
|
||||
- 备份数据库;
|
||||
- 保存旧配置和密钥;
|
||||
- 验证新版本所需环境变量;
|
||||
- 用隔离数据库或测试环境演练;
|
||||
- 部署并检查健康状态;
|
||||
- 执行核心业务烟测。
|
||||
|
||||
### 代码回滚
|
||||
|
||||
若数据库结构仍兼容:
|
||||
|
||||
1. 停止新版本;
|
||||
2. 恢复上一发布目录或镜像标签;
|
||||
3. 使用原有配置启动;
|
||||
4. 检查健康状态和关键业务。
|
||||
|
||||
### 数据回滚
|
||||
|
||||
如果新版本已执行不兼容数据库变更,不能只回滚二进制。必须按事先验证的数据库恢复方案恢复匹配版本的数据。
|
||||
|
||||
不要通过 `database reset` 实现生产回滚。
|
||||
|
||||
## 13. 部署后验收
|
||||
|
||||
- 首页和公告正常;
|
||||
- 公开验真页可访问;
|
||||
- 管理员可登录和退出;
|
||||
- TOTP 登录可完成;
|
||||
- 各角色只能看见自己的数据范围;
|
||||
- Vue 语义 URL 直接刷新正常;
|
||||
- Excel 模板可下载;
|
||||
- PDF 文书可生成并验真;
|
||||
- 数据写入后公开和成绩缓存及时失效;
|
||||
- 数据库备份任务正常;
|
||||
- 监控能发现进程、数据库和 Redis 故障。
|
||||
|
||||
+308
@@ -0,0 +1,308 @@
|
||||
# 开发指南
|
||||
|
||||
本页说明本地开发、代码结构、前后端联调、验证和变更约定。首次启动请先完成[快速开始](Quick-Start)。
|
||||
|
||||
## 1. 技术栈与版本
|
||||
|
||||
| 领域 | 技术 |
|
||||
| --- | --- |
|
||||
| 运行时 | .NET 10 |
|
||||
| Web | ASP.NET Core Minimal API |
|
||||
| 前端 | Vue 3.5、Vue Router 5、Vite 8 |
|
||||
| 数据访问 | Microsoft.Data.Sqlite、MySqlConnector |
|
||||
| 缓存与认证状态 | StackExchange.Redis |
|
||||
| Excel | ClosedXML |
|
||||
| HTML 清理 | AngleSharp |
|
||||
| 二维码 | QRCoder |
|
||||
| 测试 | xUnit |
|
||||
|
||||
`Directory.Build.props` 全局启用:
|
||||
|
||||
- Nullable;
|
||||
- Implicit Usings;
|
||||
- 最新 C# 语言版本;
|
||||
- 最新分析级别;
|
||||
- 警告视为错误。
|
||||
|
||||
依赖版本集中在 `Directory.Packages.props` 管理。
|
||||
|
||||
## 2. 解决方案结构
|
||||
|
||||
```text
|
||||
Eis.slnx
|
||||
├─ src/Eis.Domain
|
||||
├─ src/Eis.Application
|
||||
├─ src/Eis.Infrastructure
|
||||
├─ src/Eis.Tools
|
||||
├─ src/Eis.Web
|
||||
│ ├─ ClientApp
|
||||
│ └─ wwwroot
|
||||
└─ tests/Eis.Infrastructure.Tests
|
||||
```
|
||||
|
||||
职责:
|
||||
|
||||
- `Eis.Domain`:领域值、跨层通用业务概念。
|
||||
- `Eis.Application`:服务接口和应用层契约,不依赖 Web 页面。
|
||||
- `Eis.Infrastructure`:SQLite/MySQL、认证、缓存、Excel、PDF 数据、仓储和业务实现。
|
||||
- `Eis.Tools`:数据库初始化、重建和演示数据命令行工具。
|
||||
- `Eis.Web`:进程入口、依赖注入、HTTP 端点、健康检查和静态资源托管。
|
||||
- `ClientApp`:Vue 源码。
|
||||
- `tests`:基础设施和核心业务自动化测试。
|
||||
|
||||
详细依赖关系见[系统架构](Architecture)。
|
||||
|
||||
## 3. 日常开发启动
|
||||
|
||||
终端一,启动 ASP.NET Core:
|
||||
|
||||
```powershell
|
||||
dotnet run --project .\src\Eis.Web\Eis.Web.csproj
|
||||
```
|
||||
|
||||
终端二,启动 Vite:
|
||||
|
||||
```powershell
|
||||
Set-Location .\src\Eis.Web\ClientApp
|
||||
npm run dev
|
||||
```
|
||||
|
||||
访问 <http://127.0.0.1:5173>。Vite 将 API、健康检查和旧的浏览器 PDF 模块代理到 `4173`。
|
||||
|
||||
仅修改后端且已经有前端生产构建时,可只访问 <http://127.0.0.1:4173>。
|
||||
|
||||
## 4. 前端开发
|
||||
|
||||
### 主要入口
|
||||
|
||||
| 路径 | 用途 |
|
||||
| --- | --- |
|
||||
| `src/main.js` | Vue 应用入口 |
|
||||
| `src/router/index.js` | 公开、考生、管理和招生路由 |
|
||||
| `src/stores/session.js` | 会话和用户上下文 |
|
||||
| `src/lib/api.js` | API 请求与错误处理 |
|
||||
| `src/lib/navigation.js` | 按角色和级别生成菜单 |
|
||||
| `src/views` | 页面级视图 |
|
||||
| `src/components` | 可复用业务组件 |
|
||||
| `src/styles` | 全局和首页样式 |
|
||||
|
||||
### 路由约定
|
||||
|
||||
- 公开:`/`、`/announcements`、`/verify/:code`、`/auth/...`
|
||||
- 考生:`/candidate/:page`
|
||||
- 管理员:`/admin/:page`
|
||||
- 招生学校:`/admission/:page`
|
||||
|
||||
新增受保护页面时,应同时考虑:
|
||||
|
||||
1. 路由的 `meta.roles`;
|
||||
2. 菜单是否对正确管理级别显示;
|
||||
3. 会话过期后的重新登录路径;
|
||||
4. 服务端端点的角色和范围校验;
|
||||
5. History 模式下刷新是否能由宿主正确回退。
|
||||
|
||||
前端隐藏按钮不是权限控制。所有敏感操作必须由服务端再次拒绝越权请求。
|
||||
|
||||
### API 调用
|
||||
|
||||
统一使用 `src/lib/api.js`,不要在组件中重复实现 Cookie、JSON 解析和错误状态处理。401 表示会话失效时,应引导重新登录,不应仅提示用户刷新页面。
|
||||
|
||||
### 构建产物
|
||||
|
||||
```powershell
|
||||
Set-Location .\src\Eis.Web\ClientApp
|
||||
npm run build
|
||||
```
|
||||
|
||||
Vite 固定输出:
|
||||
|
||||
- `wwwroot/vue-app/app.js`
|
||||
- `wwwroot/vue-app/app.css`
|
||||
- 必要的 chunks 和 assets
|
||||
|
||||
不要直接修改构建产物;源码变更后重新运行构建。
|
||||
|
||||
## 5. 后端开发
|
||||
|
||||
### 进程启动
|
||||
|
||||
`src/Eis.Web/Program.cs` 的主要顺序:
|
||||
|
||||
1. 查找应用根目录并加载 `.env`;
|
||||
2. 建立配置和依赖注入;
|
||||
3. 初始化数据库;
|
||||
4. 检查认证后端;
|
||||
5. 注册异常处理和安全响应头;
|
||||
6. 注册健康检查;
|
||||
7. 注册公开、认证、考生、管理端点;
|
||||
8. 为未知 `/api/*` 返回原生 JSON 404;
|
||||
9. 映射前端静态资源和 SPA 回退。
|
||||
|
||||
### 新增业务
|
||||
|
||||
推荐顺序:
|
||||
|
||||
1. 在 `Eis.Application` 定义清晰的服务契约。
|
||||
2. 在 `Eis.Infrastructure` 实现业务和持久化。
|
||||
3. SQLite 与 MySQL 走相同业务规则,并分别验证 SQL 差异。
|
||||
4. 在 `Eis.Web` 只处理 HTTP 输入、身份上下文和响应映射。
|
||||
5. 添加服务层或基础设施测试。
|
||||
6. 再接入 Vue 页面。
|
||||
|
||||
不要把复杂审批、录取或成绩规则直接写在端点委托或 Vue 组件中。
|
||||
|
||||
### 端点约定
|
||||
|
||||
- `/api/public/...`:公开读取。
|
||||
- `/api/auth/...`:登录、注册、密码、TOTP 和退出。
|
||||
- `/api/candidate/...`:考生本人业务。
|
||||
- `/api/admin/...`:管理员业务。
|
||||
- `/api/admission/...`:招生学校业务。
|
||||
|
||||
未知 API 会返回:
|
||||
|
||||
```json
|
||||
{
|
||||
"ok": false,
|
||||
"message": "API 接口不存在"
|
||||
}
|
||||
```
|
||||
|
||||
新增端点时要避免与兜底路由冲突,并保持错误响应对前端可理解。
|
||||
|
||||
## 6. 数据库开发
|
||||
|
||||
系统同时支持 SQLite 与 MySQL 8.4。数据库变更必须考虑:
|
||||
|
||||
- 两份 schema 资源;
|
||||
- 外键、唯一约束和索引;
|
||||
- v20 结构版本;
|
||||
- 初始化空库;
|
||||
- 已有数据库的版本检查;
|
||||
- 数据库工具的 seed/reset 行为;
|
||||
- 考试和学校专属物理分表;
|
||||
- 对现有测试的影响。
|
||||
|
||||
应用只会在空库自动创建当前结构。检测到低版本数据库时会要求先备份并执行明确升级流程,不应静默猜测迁移。
|
||||
|
||||
业务写入与审计日志应在同一事务内提交。预览、扫描预检、Excel 解析等明确标注为 preview 的操作不得修改数据库。
|
||||
|
||||
涉及真实数据前先阅读[数据库与数据工具](Database-Operations)。
|
||||
|
||||
## 7. 认证、权限和敏感信息
|
||||
|
||||
- 密码通过 PBKDF2 加盐哈希保存。
|
||||
- TOTP 密钥使用 AES-256-GCM 加密。
|
||||
- 恢复码只保存带服务端密钥的哈希。
|
||||
- 登录使用 HttpOnly、SameSite Cookie。
|
||||
- 每个端点按角色和业务数据范围授权。
|
||||
- 多实例部署时必须使用 Redis 共享认证状态。
|
||||
|
||||
实现管理功能时,至少验证:
|
||||
|
||||
1. 角色是否允许;
|
||||
2. 管理级别是否允许;
|
||||
3. 学校或班级范围是否匹配;
|
||||
4. 目标业务状态是否允许写入;
|
||||
5. 是否需要审批或审计;
|
||||
6. 归档状态是否应锁定操作。
|
||||
|
||||
日志、异常和 API 响应中不要输出密码、TOTP 密钥、恢复码、数据库连接密码或完整敏感身份信息。
|
||||
|
||||
## 8. 缓存开发
|
||||
|
||||
缓存命名空间当前包括 `public` 和 `results`。写操作完成后要使受影响命名空间失效。
|
||||
|
||||
Redis 不可用时,公开/结果缓存可回退到有界本机缓存;认证状态不同:一旦明确配置认证 Redis,连接失败会阻止启动,避免多实例随机掉线。
|
||||
|
||||
新增缓存时需要考虑:
|
||||
|
||||
- key 是否包含完整业务范围;
|
||||
- TTL;
|
||||
- 并发热点请求合并;
|
||||
- 写后失效;
|
||||
- Redis 和本机回退的一致性;
|
||||
- 敏感数据是否适合缓存。
|
||||
|
||||
## 9. Excel 与文书
|
||||
|
||||
Excel 导入遵守:
|
||||
|
||||
- 限制文件大小;
|
||||
- 逐行验证;
|
||||
- 返回明确行号;
|
||||
- 预览与确认分离;
|
||||
- 确认阶段原子写入;
|
||||
- 不绕过审批和数据范围。
|
||||
|
||||
成绩单和录取通知书包含 HMAC 防伪查询码。任何影响文书载荷或验真算法的变更,都要补充 `DocumentVerificationCodeServiceTests` 并检查历史兼容性。
|
||||
|
||||
## 10. 自动化测试
|
||||
|
||||
运行全部测试:
|
||||
|
||||
```powershell
|
||||
dotnet test .\Eis.slnx
|
||||
```
|
||||
|
||||
运行指定测试项目:
|
||||
|
||||
```powershell
|
||||
dotnet test .\tests\Eis.Infrastructure.Tests\Eis.Infrastructure.Tests.csproj
|
||||
```
|
||||
|
||||
按测试名称筛选:
|
||||
|
||||
```powershell
|
||||
dotnet test .\Eis.slnx --filter FullyQualifiedName~DatabaseInitializerTests
|
||||
```
|
||||
|
||||
前端生产构建:
|
||||
|
||||
```powershell
|
||||
Set-Location .\src\Eis.Web\ClientApp
|
||||
npm ci
|
||||
npm run build
|
||||
```
|
||||
|
||||
纯 .NET 发布产物烟测:
|
||||
|
||||
```powershell
|
||||
pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\scripts\smoke-dotnet-native.ps1
|
||||
```
|
||||
|
||||
测试使用临时 SQLite 数据库,不应连接生产数据库。
|
||||
|
||||
## 11. 发布前本地检查
|
||||
|
||||
推荐顺序:
|
||||
|
||||
```powershell
|
||||
dotnet test .\Eis.slnx
|
||||
pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\scripts\publish.ps1
|
||||
pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\scripts\smoke-dotnet-native.ps1
|
||||
git diff --check
|
||||
git status --short
|
||||
```
|
||||
|
||||
再人工检查:
|
||||
|
||||
- 首页和登录;
|
||||
- 不同角色菜单;
|
||||
- 关键列表筛选和分页;
|
||||
- 401 后重新登录;
|
||||
- Excel 预览不写库;
|
||||
- 归档后的写入锁定;
|
||||
- 公开缓存写后失效;
|
||||
- 直接刷新语义化 URL。
|
||||
|
||||
## 12. 变更注意事项
|
||||
|
||||
- 保留已有业务工作流,不用“最终状态”替代每轮即时结果。
|
||||
- 敏感规则同时修改前端交互和服务端校验。
|
||||
- 管理台账应提供搜索、有效筛选、结果范围选择、批量操作、分页和清楚状态文案。
|
||||
- 审批详情应展示完整上下文。
|
||||
- 数据脚本要可重复、可指定目标、支持 dry-run 和备份。
|
||||
- 不把测试库结果当作生产库现状。
|
||||
- 更新配置或脚本后,明确是否需要修改 npm/.NET 命令和部署文档。
|
||||
|
||||
+80
-1
@@ -1 +1,80 @@
|
||||
欢迎来到百科。
|
||||
# 衡准 · 考试信息管理系统 Wiki
|
||||
|
||||
衡准考试信息管理系统(EIS)是一套面向考试机构、学校、班级、考生和招生学校的完整考试业务平台。系统覆盖账号申领、考生建档、考试报名、缴费确认、审批流、考点考场、准考证编排、成绩与复议、中考志愿、投档录取、报到补录、通知公告和文书验真。
|
||||
|
||||
本 Wiki 同时面向系统使用人员、部署运维人员和开发人员。第一次接触项目时,建议先阅读[快速开始](Quick-Start);准备参与开发时,从[开发指南](Development-Guide)和[系统架构](Architecture)开始。
|
||||
|
||||
## 项目概览
|
||||
|
||||
| 项目 | 当前实现 |
|
||||
| --- | --- |
|
||||
| 后端 | ASP.NET Core 10 / C#,单进程模块化单体 |
|
||||
| 前端 | Vue 3、Vue Router、Vite |
|
||||
| 数据库 | SQLite(开发与单机部署)、MySQL 8.4(生产) |
|
||||
| 缓存与会话 | 可选 Redis;未配置时使用进程内实现 |
|
||||
| 文件能力 | ClosedXML 导入导出 Excel,浏览器端生成 PDF 文书 |
|
||||
| 认证安全 | PBKDF2、HttpOnly Cookie、可选 TOTP、恢复码 |
|
||||
| 当前数据库结构 | v20 |
|
||||
| 默认服务地址 | `http://127.0.0.1:4173` |
|
||||
|
||||
## 按身份阅读
|
||||
|
||||
### 系统使用人员
|
||||
|
||||
- [用户使用指南](User-Guide):公开服务、考生注册登录、首次登录、报名、准考证、成绩、志愿与录取。
|
||||
- [管理操作指南](Administration-Guide):超级管理员、校级管理员、班级管理员和招生学校的功能边界及推荐操作顺序。
|
||||
- [常见问题与故障排查](Testing-and-Troubleshooting):登录、页面、数据、导入、缓存和部署常见问题。
|
||||
|
||||
### 开发人员
|
||||
|
||||
- [快速开始](Quick-Start):安装依赖、创建配置、构建前端、启动后端和联调。
|
||||
- [开发指南](Development-Guide):项目结构、开发工作流、前后端约定、测试和提交前检查。
|
||||
- [系统架构](Architecture):分层、请求流程、权限、数据库、缓存和前端结构。
|
||||
- [配置参考](Configuration):全部常用环境变量、默认值和生产要求。
|
||||
|
||||
### 部署与运维人员
|
||||
|
||||
- [数据库与数据工具](Database-Operations):SQLite、MySQL、初始化、演示数据、重建和安全边界。
|
||||
- [部署与发布](Deployment-and-Release):本机发布、自包含程序包、Docker、Gitea Actions 和上线检查。
|
||||
- [常见问题与故障排查](Testing-and-Troubleshooting):健康检查、日志定位、版本不匹配和 Redis 故障。
|
||||
|
||||
## 业务角色
|
||||
|
||||
| 角色 | 主要职责 | 数据范围 |
|
||||
| --- | --- | --- |
|
||||
| 考生 | 完善资料、报名、查看准考证与成绩、申请复议、填报志愿、查看录取 | 仅本人 |
|
||||
| 班级管理员 | 管理本班考生、报名审批、缴费状态、复议流程 | 指定班级 |
|
||||
| 校级管理员 | 管理本校组织、批量申领报名号、审核本校业务、维护考点申请 | 指定学校 |
|
||||
| 超级管理员 | 全局配置、考试与成绩、流程监督、录取管理、通知发布 | 全部数据 |
|
||||
| 招生学校 | 提交招生计划、审核投档、登记报到、设计通知书 | 本招生学校 |
|
||||
| 公开访客 | 阅读公告、查看公开考试信息、验证成绩单和录取通知书 | 已公开数据 |
|
||||
|
||||
权限不只由前端菜单控制,服务端还会按角色、管理级别、学校、班级和招生学校范围再次校验。
|
||||
|
||||
## 核心业务主线
|
||||
|
||||
1. 超级管理员维护组织、管理员、报名号规则和审批流程。
|
||||
2. 校级管理员按班级申请考生账号,审批完成后安全下发报名号和初始密码。
|
||||
3. 考生首次登录修改密码、完善资料,随后选择考试和科目报名。
|
||||
4. 各级管理员完成资料、报名、缴费和相关审批。
|
||||
5. 超级管理员配置考试、考点考场并执行准考证预检与编排。
|
||||
6. 超级管理员录入并发布成绩;考生可查看结果并发起成绩复议。
|
||||
7. 启用招生录取后,系统继续处理指标资格、招生计划、志愿、投档、退档、正式录取、报到与补录。
|
||||
8. 系统按阶段发布公告和脱敏公示,并为成绩单及录取通知书提供防伪验真。
|
||||
|
||||
## 重要安全提示
|
||||
|
||||
> 生产环境必须分别设置至少 32 个字符的 `TOTP_ENCRYPTION_KEY` 和 `DOCUMENT_VERIFICATION_SECRET`。两者必须相互独立并长期保存。更换前者会导致已绑定 TOTP 无法解密,更换后者会导致历史文书验真码失效。
|
||||
|
||||
> `database reset` 和 `database seed` 会改写业务数据。执行前必须停止应用、确认数据库目标并完成备份。MySQL 生产业务库不要导入演示数据。
|
||||
|
||||
> `docker compose down` 会保留 SQLite 数据卷;`docker compose down --volumes` 会删除命名卷中的数据库,仅应在明确需要清空全部容器数据时使用。
|
||||
|
||||
## 文档维护约定
|
||||
|
||||
- 功能行为以当前源码和自动化测试为准。
|
||||
- 环境变量新增或默认值变化时,同步更新[配置参考](Configuration)和 `.env.example`。
|
||||
- 数据库工具参数变化时,同步更新[数据库与数据工具](Database-Operations)。
|
||||
- 发布平台或镜像名称变化时,同步更新[部署与发布](Deployment-and-Release)。
|
||||
- `src/Eis.Web/wwwroot/vue-app` 是 Vite 构建产物,不应手工修改。
|
||||
|
||||
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
# 快速开始
|
||||
|
||||
本页用于在 Windows PowerShell 环境中快速启动完整开发环境。项目根目录以下均以仓库根目录为当前目录。
|
||||
|
||||
## 1. 准备开发环境
|
||||
|
||||
需要安装:
|
||||
|
||||
- .NET 10 SDK。仓库 `global.json` 指定 `10.0.302`,允许使用同一特性带中的更高补丁版本。
|
||||
- Node.js 20.19 或更高版本,推荐 Node.js 24。
|
||||
- npm。
|
||||
- Git。
|
||||
- 可选:Docker Desktop,用于容器方式运行。
|
||||
- 可选:MySQL 8.4 和 Redis,用于验证生产拓扑。
|
||||
|
||||
检查版本:
|
||||
|
||||
```powershell
|
||||
dotnet --version
|
||||
node --version
|
||||
npm --version
|
||||
git --version
|
||||
```
|
||||
|
||||
## 2. 创建本地配置
|
||||
|
||||
复制环境变量模板:
|
||||
|
||||
```powershell
|
||||
Copy-Item -LiteralPath .\.env.example -Destination .\.env
|
||||
```
|
||||
|
||||
默认模板使用:
|
||||
|
||||
- `Development` 环境;
|
||||
- `http://127.0.0.1:4173`;
|
||||
- SQLite;
|
||||
- `./data/exam.sqlite`;
|
||||
- 初始超级管理员 `admin`。
|
||||
|
||||
首次本地启动可直接使用模板。若数据库是空库,应用会自动创建 v20 结构、系统基础配置、默认审批流程和一个初始超级管理员。
|
||||
|
||||
开发环境默认账号取自 `.env`:
|
||||
|
||||
```text
|
||||
账号:INITIAL_ADMIN_USERNAME
|
||||
密码:INITIAL_ADMIN_PASSWORD
|
||||
```
|
||||
|
||||
模板中的密码只适合本地开发,部署前必须更换。
|
||||
|
||||
## 3. 安装前端依赖并构建
|
||||
|
||||
```powershell
|
||||
Set-Location .\src\Eis.Web\ClientApp
|
||||
npm ci
|
||||
npm run build
|
||||
Set-Location ..\..\..
|
||||
```
|
||||
|
||||
构建产物写入 `src/Eis.Web/wwwroot/vue-app`。该目录由 Vite 管理,不要直接编辑其中的 `app.js` 或 `app.css`。
|
||||
|
||||
## 4. 恢复并启动后端
|
||||
|
||||
```powershell
|
||||
dotnet restore .\Eis.slnx
|
||||
dotnet run --project .\src\Eis.Web\Eis.Web.csproj
|
||||
```
|
||||
|
||||
打开:
|
||||
|
||||
- 系统首页:<http://127.0.0.1:4173>
|
||||
- 登录页:<http://127.0.0.1:4173/auth/login>
|
||||
- 存活检查:<http://127.0.0.1:4173/health/live>
|
||||
- 组件状态:<http://127.0.0.1:4173/health/migration>
|
||||
|
||||
`/health/live` 返回宿主是否存活;`/health/migration` 会展示原生模块、认证状态后端和缓存状态。
|
||||
|
||||
## 5. 前后端联调模式
|
||||
|
||||
后端继续运行在 `4173`。另开一个 PowerShell 终端:
|
||||
|
||||
```powershell
|
||||
Set-Location .\src\Eis.Web\ClientApp
|
||||
npm run dev
|
||||
```
|
||||
|
||||
访问 <http://127.0.0.1:5173>。Vite 会把以下路径代理到 ASP.NET Core:
|
||||
|
||||
- `/api`
|
||||
- `/health`
|
||||
- `/js`
|
||||
|
||||
前端使用 Vue Router History 模式。直接刷新 `/candidate/...`、`/admin/...` 或 `/admission/...` 时,由 ASP.NET Core 的前端资源回退逻辑返回 SPA 入口。
|
||||
|
||||
## 6. 首次登录后的基础配置
|
||||
|
||||
推荐按以下顺序建立可用业务环境:
|
||||
|
||||
1. 使用初始超级管理员登录。
|
||||
2. 在“账户安全”中修改管理员密码;需要时绑定 TOTP。
|
||||
3. 在“学校管理”中建立学校并标记生源校或招生校职责。
|
||||
4. 建立校级和班级管理员。
|
||||
5. 在“报名号规则”中确认号码段组合。
|
||||
6. 在“流程设计”中确认资料、报名、复议和档案变更审批步骤。
|
||||
7. 建立考试、科目、时间、费用和合格规则。
|
||||
8. 由校级管理员批量申领考生账号,或由超级管理员临时开启自主注册。
|
||||
|
||||
如果只需要查看完整样例流程,可使用数据库工具导入内置演示数据。该操作会改写目标数据库,请先阅读[数据库与数据工具](Database-Operations),不要未经确认直接对现有数据库执行。
|
||||
|
||||
## 7. Docker 快速启动
|
||||
|
||||
创建容器配置:
|
||||
|
||||
```powershell
|
||||
Copy-Item -LiteralPath .\.env.docker.example -Destination .\.env.docker
|
||||
```
|
||||
|
||||
打开 `.env.docker`,至少替换:
|
||||
|
||||
- `TOTP_ENCRYPTION_KEY`
|
||||
- `DOCUMENT_VERIFICATION_SECRET`
|
||||
- `INITIAL_ADMIN_PASSWORD`
|
||||
|
||||
三者应使用不同的安全随机值。随后运行:
|
||||
|
||||
```powershell
|
||||
docker compose up --build --detach
|
||||
docker compose ps
|
||||
docker compose logs --follow app
|
||||
```
|
||||
|
||||
打开 <http://127.0.0.1:4173>。
|
||||
|
||||
停止但保留 SQLite 数据:
|
||||
|
||||
```powershell
|
||||
docker compose down
|
||||
```
|
||||
|
||||
## 8. 最小验证
|
||||
|
||||
启动成功后至少完成:
|
||||
|
||||
```powershell
|
||||
dotnet test .\Eis.slnx
|
||||
```
|
||||
|
||||
并在浏览器检查:
|
||||
|
||||
1. 首页可加载;
|
||||
2. `/health/live` 返回 `healthy`;
|
||||
3. 初始管理员可登录;
|
||||
4. `/admin/dashboard` 可进入;
|
||||
5. 页面刷新不会出现 404;
|
||||
6. `data/exam.sqlite` 已生成。
|
||||
|
||||
更完整的检查方式见[测试与故障排查](Testing-and-Troubleshooting)。
|
||||
|
||||
@@ -0,0 +1,374 @@
|
||||
# 测试与故障排查
|
||||
|
||||
本页用于开发验证和运行故障定位。先确定当前使用的服务地址、运行环境和数据库目标,再执行检查。
|
||||
|
||||
## 1. 自动化测试
|
||||
|
||||
全部测试:
|
||||
|
||||
```powershell
|
||||
dotnet test .\Eis.slnx
|
||||
```
|
||||
|
||||
Release 配置:
|
||||
|
||||
```powershell
|
||||
dotnet test .\Eis.slnx --configuration Release
|
||||
```
|
||||
|
||||
指定项目:
|
||||
|
||||
```powershell
|
||||
dotnet test .\tests\Eis.Infrastructure.Tests\Eis.Infrastructure.Tests.csproj
|
||||
```
|
||||
|
||||
筛选:
|
||||
|
||||
```powershell
|
||||
dotnet test .\Eis.slnx --filter FullyQualifiedName~DatabaseInitializerTests
|
||||
```
|
||||
|
||||
测试覆盖:
|
||||
|
||||
- 空库 v20 初始化;
|
||||
- 数据库维护安全;
|
||||
- 认证状态后端;
|
||||
- 密码和 TOTP 历史兼容;
|
||||
- 文书防伪;
|
||||
- 缓存;
|
||||
- 公告内容处理;
|
||||
- Excel;
|
||||
- 地区数据;
|
||||
- 成绩统计;
|
||||
- 招生公示和迁移能力。
|
||||
|
||||
xUnit 使用独立临时 SQLite 数据库,不应连接或修改生产库。
|
||||
|
||||
## 2. 前端验证
|
||||
|
||||
生产构建:
|
||||
|
||||
```powershell
|
||||
Set-Location .\src\Eis.Web\ClientApp
|
||||
npm ci
|
||||
npm run build
|
||||
```
|
||||
|
||||
开发服务器:
|
||||
|
||||
```powershell
|
||||
npm run dev
|
||||
```
|
||||
|
||||
检查:
|
||||
|
||||
- 控制台无模块加载错误;
|
||||
- `/api` 请求代理到 `4173`;
|
||||
- 直接打开和刷新 Vue 子路由正常;
|
||||
- 401 后进入登录流程;
|
||||
- 不同角色菜单正确;
|
||||
- 移动端布局可操作;
|
||||
- `wwwroot/vue-app` 由构建生成。
|
||||
|
||||
项目当前没有单独的前端单元测试脚本,因此前端变更至少要通过 `npm run build` 和相关页面人工验证。
|
||||
|
||||
## 3. 发布烟测
|
||||
|
||||
```powershell
|
||||
pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\scripts\smoke-dotnet-native.ps1
|
||||
```
|
||||
|
||||
脚本会:
|
||||
|
||||
- 发布 `Eis.Web`;
|
||||
- 在系统临时目录创建一次性 SQLite 数据库;
|
||||
- 使用随机本机端口启动发布物;
|
||||
- 检查健康状态、首页和必要静态资源;
|
||||
- 使用临时超级管理员登录;
|
||||
- 确认未知 API 返回 404;
|
||||
- 停止进程并清理临时数据。
|
||||
|
||||
烟测不会使用仓库 `data/exam.sqlite`。
|
||||
|
||||
## 4. 手工烟测清单
|
||||
|
||||
### 公开页面
|
||||
|
||||
- 首页返回 200;
|
||||
- 公告列表和详情可用;
|
||||
- 未发布内容不可见;
|
||||
- 验真码成功和失败状态清楚;
|
||||
- 无效 `/api/...` 返回 JSON 404。
|
||||
|
||||
### 认证
|
||||
|
||||
- 正确密码登录;
|
||||
- 错误密码被拒绝;
|
||||
- Cookie 为 HttpOnly;
|
||||
- 登出后受保护接口不可用;
|
||||
- TOTP 动态码和恢复码可用;
|
||||
- 恢复码只能使用一次;
|
||||
- 会话过期后重新登录。
|
||||
|
||||
### 数据范围
|
||||
|
||||
- 班级管理员看不到其他班;
|
||||
- 校级管理员看不到其他学校;
|
||||
- 招生学校看不到其他学校投档;
|
||||
- 考生只能查看本人数据;
|
||||
- 手工调用隐藏端点仍被服务端拒绝。
|
||||
|
||||
### 关键流程
|
||||
|
||||
- 批量申领报名号;
|
||||
- 首次登录;
|
||||
- 资料和报名审批;
|
||||
- 缴费确认;
|
||||
- 编排预检和正式应用;
|
||||
- 成绩导入预览和确认;
|
||||
- 成绩发布和复议;
|
||||
- 志愿、投档、正式录取;
|
||||
- 报到扫描预览和确认;
|
||||
- 每轮补录与公开公示。
|
||||
|
||||
## 5. 健康检查解释
|
||||
|
||||
### `/health/live` 无法访问
|
||||
|
||||
可能原因:
|
||||
|
||||
- 进程未启动;
|
||||
- `ASPNETCORE_URLS` 不是预期地址;
|
||||
- 端口被占用;
|
||||
- 容器端口未映射;
|
||||
- 应用在初始化数据库或认证 Redis 时已经退出。
|
||||
|
||||
先查看应用标准输出、容器日志或服务管理器日志。
|
||||
|
||||
### `/health/migration` 中缓存为 `disabled`
|
||||
|
||||
没有配置 `REDIS_URL`,应用使用本机缓存。这在单实例开发环境正常。
|
||||
|
||||
### 缓存为 `unavailable`
|
||||
|
||||
普通 Redis 配置存在但暂时连接失败,应用回退到本机缓存。检查:
|
||||
|
||||
- URL 和 TLS scheme;
|
||||
- DNS、端口和防火墙;
|
||||
- 容器是否错误使用 `127.0.0.1`;
|
||||
- Redis 认证;
|
||||
- `REDIS_CONNECT_TIMEOUT_MS`。
|
||||
|
||||
### 认证后端为 `memory`
|
||||
|
||||
未配置 Redis 认证状态。单实例可用,但重启会要求重新登录;多实例部署不应使用。
|
||||
|
||||
## 6. 应用启动失败
|
||||
|
||||
### 生产环境缺少 TOTP 密钥
|
||||
|
||||
错误含义:原生认证已启用,`TOTP_ENCRYPTION_KEY` 少于 32 字符。
|
||||
|
||||
处理:通过秘密管理注入新的稳定密钥,不要把密钥写进仓库。
|
||||
|
||||
### 生产环境缺少文书密钥
|
||||
|
||||
`DOCUMENT_VERIFICATION_SECRET` 必须至少 32 字符,并与 TOTP 密钥不同。
|
||||
|
||||
### 默认尝试连接 MySQL
|
||||
|
||||
在 `Production` 下未设置 `DATABASE_CLIENT` 时默认使用 MySQL。若这是单机 SQLite 部署,显式设置:
|
||||
|
||||
```text
|
||||
DATABASE_CLIENT=sqlite
|
||||
SQLITE_PATH=/明确的持久化路径/exam.sqlite
|
||||
```
|
||||
|
||||
### MySQL 配置不完整
|
||||
|
||||
设置 `DATABASE_URL`,或完整设置主机、用户和数据库名。检查 `.env` 是否位于应用根目录,以及部署平台是否注入了空或错误同名变量。
|
||||
|
||||
### Redis 认证状态与缓存使用同一 DB
|
||||
|
||||
设置不同的 `REDIS_SESSION_DB`,或使用独立 `REDIS_SESSION_URL`。
|
||||
|
||||
### 数据库结构版本过低
|
||||
|
||||
当前要求 v20。停止应用,备份完整数据库并执行明确升级流程。不要直接 seed/reset 生产库。
|
||||
|
||||
## 7. 前端页面问题
|
||||
|
||||
### `4173` 页面显示旧版本
|
||||
|
||||
后端托管的是上次 Vite 构建产物。重新运行:
|
||||
|
||||
```powershell
|
||||
Set-Location .\src\Eis.Web\ClientApp
|
||||
npm run build
|
||||
```
|
||||
|
||||
不要手工修改 `wwwroot/vue-app`。
|
||||
|
||||
### `5173` API 请求失败
|
||||
|
||||
确认:
|
||||
|
||||
- ASP.NET Core 正在 `127.0.0.1:4173` 运行;
|
||||
- Vite 使用仓库中的 `vite.config.js`;
|
||||
- 请求路径以 `/api`、`/health` 或 `/js` 开头;
|
||||
- 没有另一个服务占用 `4173`。
|
||||
|
||||
### 刷新子页面 404
|
||||
|
||||
开发时应访问 Vite 的 `5173` 或 ASP.NET Core 的 `4173`。生产反向代理不要自行把 `/api/*` 改写为 SPA 首页;其他前端路由应转发给 ASP.NET Core 的资源回退逻辑。
|
||||
|
||||
### 登录后回到首页
|
||||
|
||||
可能是:
|
||||
|
||||
- 会话请求失败;
|
||||
- 用户角色与目标路由不匹配;
|
||||
- 考生仍需修改初始密码或完善资料;
|
||||
- Cookie 未随请求发送;
|
||||
- 多实例未共享 Redis Session。
|
||||
|
||||
打开浏览器网络面板检查 `/api/auth/me`,不要只反复刷新。
|
||||
|
||||
## 8. 数据库问题
|
||||
|
||||
### SQLite 数据“丢失”
|
||||
|
||||
先确认实际绝对路径:
|
||||
|
||||
- 仓库启动:通常是 `data/exam.sqlite`;
|
||||
- 发布目录:相对路径可能按应用根目录解析;
|
||||
- Docker:`/app/data/exam.sqlite`;
|
||||
- 测试:系统临时目录中的一次性文件。
|
||||
|
||||
最常见原因是启动时使用了另一个工作目录或环境变量,创建了新的空 SQLite 文件。
|
||||
|
||||
### Docker 重建后数据不见
|
||||
|
||||
检查是否执行过:
|
||||
|
||||
```powershell
|
||||
docker compose down --volumes
|
||||
```
|
||||
|
||||
以及 Compose 是否仍挂载 `exam-information-data:/app/data`。
|
||||
|
||||
### MySQL 外部修改暂时看不到
|
||||
|
||||
应用会复用只读快照,外部直写默认最长 30 秒后可见。应用自身写入会立即失效。不要把直接改数据库作为正常业务操作。
|
||||
|
||||
### 工具拒绝操作
|
||||
|
||||
这是安全边界。按[数据库与数据工具](Database-Operations)确认目标、dry-run、备份和 `--confirm-target`,不要先使用 `--force` 试错。
|
||||
|
||||
## 9. Redis 和缓存问题
|
||||
|
||||
### 写入后公开页面仍旧
|
||||
|
||||
确认写操作是否触发正确命名空间失效。公开公告、招生公示和可见性变更应失效 `public`;成绩录入、发布、导入、归档和复议应失效 `results`。
|
||||
|
||||
### 多实例随机掉登录
|
||||
|
||||
各实例可能使用本机内存会话或连接不同 Redis。确认:
|
||||
|
||||
- 所有实例 `REDIS_SESSION_URL`/DB 相同;
|
||||
- `REDIS_SESSION_PREFIX` 相同;
|
||||
- TOTP 加密密钥相同且稳定;
|
||||
- 实例没有因配置缺失退回内存。
|
||||
|
||||
### Redis Cluster 报逻辑 DB 错误
|
||||
|
||||
Cluster 常只支持 DB 0。让普通缓存和认证状态使用两个独立 Redis 端点,不要依赖 DB 0/1 分隔。
|
||||
|
||||
## 10. Excel 导入问题
|
||||
|
||||
### 返回具体行错误
|
||||
|
||||
按行修复后重新上传。常见原因:
|
||||
|
||||
- 必填列空;
|
||||
- 标识 ID 被改动;
|
||||
- 日期或数字格式不合法;
|
||||
- 目标学校、班级、考试不存在;
|
||||
- 重复唯一值;
|
||||
- 数据超出当前管理员范围;
|
||||
- 使用了旧版本模板。
|
||||
|
||||
### 预览成功但数据库没变化
|
||||
|
||||
预览阶段本来就不写数据库。需要在页面核对摘要后执行明确确认。
|
||||
|
||||
### 部分数据成功、部分失败
|
||||
|
||||
关键批量写入设计为原子事务。若页面显示部分变化,先确认是否查看了旧缓存、多个批次或之前已有的数据,再检查服务日志和审计记录。
|
||||
|
||||
## 11. 成绩与录取问题
|
||||
|
||||
### 管理员已录入但考生看不到
|
||||
|
||||
录入和发布是不同状态。确认整场或对应成绩是否正式发布。
|
||||
|
||||
### 无法修改成绩
|
||||
|
||||
检查:
|
||||
|
||||
- 考试是否归档;
|
||||
- 当前账号是否超级管理员;
|
||||
- 是否处于导入预览阶段;
|
||||
- 复议流程是否允许当前动作。
|
||||
|
||||
### 考生无法填志愿
|
||||
|
||||
检查:
|
||||
|
||||
- 考试是否启用招生;
|
||||
- 成绩是否全部发布;
|
||||
- 是否在填报阶段;
|
||||
- 是否达到提交上限;
|
||||
- 指标资格和计划是否已经生效。
|
||||
|
||||
### 无法补录
|
||||
|
||||
检查上一轮报到是否已由所有相关学校提交并完成审批,缺额是否存在,以及当前录取阶段是否允许启动下一轮。
|
||||
|
||||
## 12. 日志与问题报告
|
||||
|
||||
报告问题时提供:
|
||||
|
||||
- 应用版本或 Git 提交;
|
||||
- 操作系统和部署方式;
|
||||
- .NET、Node、浏览器版本;
|
||||
- `ASPNETCORE_ENVIRONMENT`;
|
||||
- 数据库类型和结构版本,不提供密码;
|
||||
- Redis 是否配置及状态,不提供完整凭据;
|
||||
- 复现步骤;
|
||||
- 预期与实际结果;
|
||||
- 浏览器控制台和网络状态;
|
||||
- 服务端异常前后日志;
|
||||
- 是否能在临时测试库复现。
|
||||
|
||||
不要在问题报告中粘贴:
|
||||
|
||||
- `.env` 全文;
|
||||
- 数据库密码;
|
||||
- TOTP 密钥;
|
||||
- 恢复码;
|
||||
- Session Cookie;
|
||||
- 完整证件号、手机号或未脱敏考生数据。
|
||||
|
||||
## 13. 提交前最终检查
|
||||
|
||||
```powershell
|
||||
dotnet test .\Eis.slnx
|
||||
pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\scripts\publish.ps1
|
||||
pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\scripts\smoke-dotnet-native.ps1
|
||||
git diff --check
|
||||
git status --short
|
||||
```
|
||||
|
||||
如果改动只涉及 Wiki,至少检查 Markdown 链接、命令路径和当前源码配置是否一致。
|
||||
|
||||
+210
@@ -0,0 +1,210 @@
|
||||
# 用户使用指南
|
||||
|
||||
本页面向公开访客和考生。管理员和招生学校请阅读[管理操作指南](Administration-Guide)。
|
||||
|
||||
## 1. 公开服务
|
||||
|
||||
无需登录即可使用:
|
||||
|
||||
- 首页:查看机构信息、主标语、已发布考试、报名时间、考试时间和科目。
|
||||
- 通知公告:查看已公开公告、录取与报到公示。
|
||||
- 文书验真:输入成绩单或录取通知书上的防伪查询码,或直接扫描二维码。
|
||||
- 登录:考生和管理员共用登录入口,系统按账号角色进入对应工作台。
|
||||
- 考生注册:仅在超级管理员开启自主注册后显示并可用。
|
||||
|
||||
公开页面只展示已经发布或明确允许公开的数据。录取公示中的证件号、手机号等敏感信息会脱敏。
|
||||
|
||||
## 2. 考生账号来源
|
||||
|
||||
考生账号有两种来源:
|
||||
|
||||
### 学校统一申领
|
||||
|
||||
学校管理员按一个或多个班级提交人数,审批通过后系统生成:
|
||||
|
||||
- 固定报名号;
|
||||
- 随机初始密码;
|
||||
- 待补录的考生账户。
|
||||
|
||||
报名号创建后不会因参加新的考试而改变。同一考生后续报名、准考证、成绩和录取均复用这个号码。
|
||||
|
||||
### 自主注册
|
||||
|
||||
超级管理员可随时开启或关闭自主注册。开启后,考生按页面要求注册,系统依据当前报名号规则生成固定报名号。
|
||||
|
||||
请勿重复注册。已经由学校领取报名号的考生应使用学校下发的账号。
|
||||
|
||||
## 3. 登录与首次设置
|
||||
|
||||
访问 `/auth/login`,输入报名号和密码。
|
||||
|
||||
学校下发的新账号首次登录后必须完成:
|
||||
|
||||
1. 修改初始密码;
|
||||
2. 填写个人资料;
|
||||
3. 提交资料审核。
|
||||
|
||||
在上述步骤完成前,系统会把考生引导到“首次登录”页面,不能直接办理其他考试事项。
|
||||
|
||||
建议新密码:
|
||||
|
||||
- 至少 8 位;
|
||||
- 不与报名号、姓名或初始密码相同;
|
||||
- 不与其他网站共用;
|
||||
- 由本人保存,不交给班级管理员代管。
|
||||
|
||||
## 4. 个人资料
|
||||
|
||||
“个人资料”用于维护:
|
||||
|
||||
- 姓名、性别、证件号码;
|
||||
- 出生日期、籍贯、民族;
|
||||
- 省、市、县区;
|
||||
- 学校、班级;
|
||||
- 手机、邮箱、家庭地址、邮编;
|
||||
- 监护人、紧急联系人及联系电话;
|
||||
- 体育或艺术特长资格及证明;
|
||||
- 政策资格信息。
|
||||
|
||||
提交后可查看审核状态和管理员意见。被退回时,根据意见修改并重新提交。资料变更可能进入配置好的多步骤审批流程,页面显示成功不等于正式档案已经立即生效。
|
||||
|
||||
## 5. 考试报名
|
||||
|
||||
进入“考试报名”:
|
||||
|
||||
1. 查看当前开放的考试。
|
||||
2. 阅读报名时间、考试时间、科目、费用和相关说明。
|
||||
3. 选择一个或多个科目。
|
||||
4. 提交报名。
|
||||
|
||||
提交后在“我的报名”中查看:
|
||||
|
||||
- 所报考试与科目;
|
||||
- 报名审核状态;
|
||||
- 应缴金额;
|
||||
- 缴费状态;
|
||||
- 缴费确认办理人和时间;
|
||||
- 班级负责人确认记录。
|
||||
|
||||
报名终审和缴费确认是两套独立状态。报名审核通过不表示已经缴费,缴费已确认也不替代报名审批。
|
||||
|
||||
系统不接入支付 SDK。实际收费方式以考试机构通知为准,管理员只在系统中登记缴费状态。
|
||||
|
||||
## 6. 准考证
|
||||
|
||||
进入“准考证”查看:
|
||||
|
||||
- 是否已经编排;
|
||||
- 是否到达开放下载时间;
|
||||
- 考点、考场、座位;
|
||||
- 各科考试时间;
|
||||
- 准考证下载入口。
|
||||
|
||||
多科目考生会固定在同一考点,但不同科目可能安排在不同考场和座位。未到开放时间、报名未满足条件或尚未完成编排时,系统不会提供正式下载。
|
||||
|
||||
## 7. 成绩与复议
|
||||
|
||||
进入“成绩查询”:
|
||||
|
||||
- 只显示已经发布的成绩;
|
||||
- 按考试查看各科成绩、名次、等级和达线结果;
|
||||
- 查看整场总分及合格结论;
|
||||
- 下载带防伪查询码和二维码的 PDF 成绩单。
|
||||
|
||||
如需复议:
|
||||
|
||||
1. 找到对应科目;
|
||||
2. 填写具体复议理由;
|
||||
3. 提交后查看审批进度;
|
||||
4. 等待最终结论。
|
||||
|
||||
复议批准并发生改分后,系统会在同一事务中更新成绩,并重新计算该考生受影响的排名区间结论。已经归档的考试不能再通过复议改分。
|
||||
|
||||
## 8. 志愿填报与录取
|
||||
|
||||
只有考试启用了招生录取且到达相应阶段时,才会显示可操作入口。
|
||||
|
||||
### 填报前提
|
||||
|
||||
- 当次考试成绩已经全部发布;
|
||||
- 处于允许填报的时间和阶段;
|
||||
- 未超过最多提交次数;
|
||||
- 志愿尚未因提交次数用尽而锁定。
|
||||
|
||||
### 志愿类型
|
||||
|
||||
- 指标志愿:仅对学校管理员已经确认有指标资格,且招生学校对生源校分配了相应指标的考生可选。
|
||||
- 普通志愿:从审核生效的普通招生计划中选择。
|
||||
- 特长类别:页面只显示与本人体育或艺术资格相匹配的类别。
|
||||
|
||||
志愿只能由考生本人保存或修改。班级和校级管理员不能查看考生志愿;超级管理员仅能在业务需要下只读查看。
|
||||
|
||||
系统按“分数优先、遵循志愿”处理投档,并严格区分指标计划池与普通计划池。
|
||||
|
||||
### 录取阶段
|
||||
|
||||
考生可查看:
|
||||
|
||||
- 投档学校和当前状态;
|
||||
- 退档处理结果;
|
||||
- 正式录取学校;
|
||||
- 录取通知书编号;
|
||||
- 招生学校自定义样式的 PDF 录取通知书;
|
||||
- 报到和补录相关公开通知。
|
||||
|
||||
正式签发后,录取通知书编号稳定生成,不应因普通页面刷新而变化。
|
||||
|
||||
## 9. 通知公告
|
||||
|
||||
考生中心的“通知公告”用于查看与考试相关的最新通知。首页只展示公开可见内容;草稿、已撤回通知和未到公开阶段的系统公示不会显示。
|
||||
|
||||
请特别关注:
|
||||
|
||||
- 报名开放与截止时间;
|
||||
- 缴费和资料补正要求;
|
||||
- 准考证开放时间;
|
||||
- 成绩发布时间与复议截止时间;
|
||||
- 志愿填报、录取、报到和补录安排。
|
||||
|
||||
## 10. 账户安全
|
||||
|
||||
“账户安全”支持:
|
||||
|
||||
- 修改密码;
|
||||
- 绑定 TOTP 验证器;
|
||||
- 重新生成一次性恢复码;
|
||||
- 关闭二次验证。
|
||||
|
||||
启用 TOTP 时:
|
||||
|
||||
1. 输入当前密码开始绑定;
|
||||
2. 使用验证器应用扫描二维码;
|
||||
3. 输入 6 位动态码完成启用;
|
||||
4. 立即保存恢复码。
|
||||
|
||||
每个恢复码只能使用一次。恢复码关闭页面后不会再次显示同一组明文;重新生成后,旧恢复码失效。
|
||||
|
||||
## 11. 常见状态理解
|
||||
|
||||
| 状态 | 含义 |
|
||||
| --- | --- |
|
||||
| 待补录 | 账号已创建,但考生资料尚未完整建立 |
|
||||
| 待审核 | 已提交,等待当前流程责任人处理 |
|
||||
| 已退回 | 需要根据意见修改后重新提交 |
|
||||
| 已通过 | 当前审批流程完成 |
|
||||
| 未缴费 | 系统尚未记录缴费确认 |
|
||||
| 已缴费 | 管理员已经记录办理人和确认时间 |
|
||||
| 未发布 | 数据可能已录入,但考生端不可见 |
|
||||
| 已发布 | 考生可以正式查询 |
|
||||
| 已归档 | 考试进入只读历史状态,关键写操作被锁定 |
|
||||
|
||||
## 12. 使用问题处理
|
||||
|
||||
- 登录过期:返回登录页重新登录,不要反复刷新原页面。
|
||||
- 忘记密码:联系有权限的管理员重置;管理员不能查看原密码。
|
||||
- 看不到考试:确认报名时间、考试发布状态和个人资料是否满足要求。
|
||||
- 看不到成绩:成绩可能尚未发布,不以管理员已录入为准。
|
||||
- 无法填志愿:检查成绩是否全部发布、填报阶段、提交次数和指标资格。
|
||||
- PDF 无法下载:确认浏览器允许下载,并检查是否到达开放时间。
|
||||
- 验真失败:确认查询码完整;若系统密钥被更换,历史文书查询码可能失效。
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
## 衡准考试系统
|
||||
|
||||
- [Wiki 首页](Home)
|
||||
- [快速开始](Quick-Start)
|
||||
- [用户使用指南](User-Guide)
|
||||
- [管理操作指南](Administration-Guide)
|
||||
- [开发指南](Development-Guide)
|
||||
- [系统架构](Architecture)
|
||||
- [配置参考](Configuration)
|
||||
- [数据库与数据工具](Database-Operations)
|
||||
- [部署与发布](Deployment-and-Release)
|
||||
- [测试与故障排查](Testing-and-Troubleshooting)
|
||||
|
||||
Reference in New Issue
Block a user