# 衡准 · 考试信息管理系统 一个完整可运行的分级权限考试信息管理系统,前端使用 Vue 3 + Vite,后端使用 ASP.NET Core 10;本地开发采用 SQLite,生产环境支持 MySQL 8.4。 ## 已实现功能 ### 公开服务首页 - 通知公告首页展示与详情阅读 - 已发布考试、报名时间、考试时间和科目展示 - 考试服务办理流程说明 - 考生注册与双角色登录入口 ### 考生中心 - 报名号即考生账户,同一考生参加不同考试始终使用同一个号码 - 学校管理员按一个或多个班级填写人数并提交批量申领(单人也按 1 人批次走审批) - 首次登录强制修改初始密码,完成后才能补全个人信息 - 完整维护姓名、性别、证件号码、籍贯、出生日期、民族、家庭住址、手机号、邮箱、学校、班级、监护人和紧急联系人 - 自主注册可由超级管理员随时开启或关闭;开启后系统直接生成固定报名号 - 资料审核状态与管理员审核意见 - 查看开放考试并自主选择多个报考科目 - 查看报名审核、应缴金额、缴费状态及班级负责人确认记录 - 准考证生成状态、开放时间与下载 - 已发布成绩查询,并可按科目提交成绩复议、查看审批进度与结论 - 下载带 HMAC 防伪查询码和二维码的 PDF 成绩单 - 查看正式录取结果、录取通知书编号,并下载招生学校自定义样式的 PDF 录取通知书 - 通知公告中心 ### 管理后台 - 超级、校级、班级三级管理员,同一级支持多个账号 - 超级管理员管理全局事务,并可监督、修改、退回全部审批流程 - 校级管理员管理本校班级、班级管理员、考生和报名流程,按班级批量申领报名号,并提交本校考点、考场档案变更 - 班级管理员可查看并审批本班考生、报名与成绩复议流程,并维护本班考生缴费状态;成绩录入仍仅限超级管理员 - 报名终审与缴费确认相互独立,系统不接入支付 SDK;超级、校级、班级管理员均可在各自数据范围内修改缴费状态,确认缴费时记录办理人和时间 - 超级、校级、班级管理员均可按各自数据范围筛选、查看及导出 Excel 缴费名单 - 考生信息修改、考试报名、成绩复议、批量报名号申领、考点考场变更使用可配置的多步骤审批流程 - 班级和校级审批自动限定到考生所属班级、学校;同范围多名管理员按当前待办与历史分配量自动均分 - 当前处理人可将流程转交给同范围的同级管理员 - 自定义报名号生成规则,可组合年份、学校代码、性别、固定值和流水号 - 报名号在创建考生账户时只生成一次,后续考试报名自动复用 - 超级管理员只维护号码规则;校级批量申请最终批准后,系统原子生成固定报名号、随机初始密码和待补录账户 - 批次结果按班级返回校级管理员,并可导出 Excel 安全下发 - 结构化考点与考场档案,包含代码、负责人、应急电话、开放时间、交通、楼栋、楼层、容量、座位编排说明、类型和状态 - 考点新增及考点/考场修改先形成申请快照,审批通过后才整体更新正式档案 - 班级、班级管理员、报名号班级配额、考生资料、考点考场和成绩均提供 Excel 模板、导入与当前数据导出;只读角色保留对应导出能力 - Excel 导入逐行校验并返回具体行号;考生资料和考点考场的批量修改仍必须经过配置好的审批流程 - 考务指标与审计日志 - 考生资料审核、通过或退回修改 - 考试报名及科目审核 - 创建考试并结构化配置科目日期、时间、费用和满分;每科可独立选择固定分、排名前百分比或不设单科线,并汇总总分 - 支持固定总分线、总成绩排名前百分比、单科均达线及不判定四类整场合格策略 - 通知发布、草稿、撤回及首页置顶 - 按整场考试预检并批量编排准考证,支持班内、校内、县区内、市内和省内五级混编 - 预置“县区编号+考场号+座位号”“县区号+考场号+流水号”“考点学校代码+考场号+座位号”“考生学校代码+考场号+座位号”四种号码规则 - 多科目考生固定在同一考点,各科独立分配考场和座位;同科目组合优先相邻编排 - 编排前校验科目时间冲突、考点容量、档案完整性和号码唯一性,默认保留备用考场并支持稳定种子复现 - 每科可独立设置固定及格分、排名前百分比或不设单科线;成绩等级按同场同科排名百分位自动计算 - 默认排名等级区间为前 10% A+、前 25% A、前 50% B+、前 70% B、前 90% C、其余 D;同分共享名次 - 成绩管理中心按多场考试切换,展示录入/发布进度、成绩出齐人数、整场合格率、缺失科次与复议数量,并提供可筛选成绩台账 - 成绩复议终审表单展示考试、科目、原分、当前排名和达线规则;批准后在同一事务内更新成绩并只重算该考生的排名区间结论 - 成绩 Excel 采用“上传解析与逐行校验—页面暂存预览—确认后原子批量写库”的两阶段流程,预览不会修改数据库 - 超级管理员可将整场考试不可逆归档;归档后手工录入、Excel 导入、复议改分和考试配置全部锁定,历史报名、准考证与成绩默认折叠展示 - 管理员与考生接口权限隔离 ### 系统能力 - PBKDF2 加盐密码哈希 - 可选 TOTP 二次验证,支持验证器扫码绑定、一次性恢复码与登录防重放 - TOTP 密钥使用 AES-256-GCM 加密存储,恢复码仅保存带服务端密钥的哈希 - HttpOnly、SameSite 登录 Cookie - 服务端角色权限校验 - SQLite / MySQL 8.4 双数据库持久化 - 可选 Redis 公开接口缓存,支持写后版本失效、热点请求合并和故障回源 - Redis 登录状态存储,和普通接口缓存使用不同逻辑数据库,支持多实例共享会话 - 规范关系模型、外键、唯一约束和业务索引 - 业务写入与审计日志使用原子事务提交 - 关键管理操作审计日志 - 组织、学校、班级三级数据范围在服务端强制过滤 - 审批实例、当前责任人、转交和监督操作全程留痕 - 桌面端与移动端响应式布局 - Excel 文件使用 ClosedXML 生成和解析,并限制上传文件大小 - 成绩单与录取通知书以 PDF 下载,使用服务端 HMAC 防伪码支持公开验真 ## 运行 需要 .NET 10 SDK、Node.js 20.19+(推荐 Node.js 24)和 npm。 ```powershell Set-Location .\src\Eis.Web\ClientApp npm ci npm run build Set-Location ..\..\.. dotnet restore .\Eis.slnx dotnet run --project .\src\Eis.Web\Eis.Web.csproj ``` 打开 。 日常开发前端时,可以让 ASP.NET Core 继续监听 `4173`,另开一个终端启动 Vite: ```powershell Set-Location .\src\Eis.Web\ClientApp npm run dev ``` 然后打开 。Vite 会把 API 和 PDF 文书生成模块代理到 ASP.NET Core。前端已整体迁移为 Vue 3 单页应用,使用 Vue Router History 模式;公开服务、考生中心、管理后台和招生学校端均使用独立的语义化 URL。生产构建输出到 `src/Eis.Web/wwwroot/vue-app`,不得手工修改该目录中的文件。 账户可在“账户安全”中启用 TOTP 二次验证。生产环境必须设置至少 32 个字符的 `TOTP_ENCRYPTION_KEY`;该值用于加密 TOTP 密钥并保护恢复码哈希,部署后必须稳定保存,不能随意更换。本地开发未设置时会使用仅适合开发的稳定派生值。 生产环境还必须单独设置至少 32 个字符的 `DOCUMENT_VERIFICATION_SECRET`。系统用它为成绩单和录取通知书生成 HMAC 防伪查询码;更换该值会使此前下载文书的查询码失效,因此应独立生成、稳定保存且不得与 TOTP 密钥共用。 本地开发无需额外配置,首次运行会自动创建 `data/exam.sqlite` 和完整关系型数据库结构,但不会导入学校、考生、考试或报名测试数据。首次建库会写入系统基础配置、默认审批流程和一个超级管理员;账号、密码和显示名可通过 `INITIAL_ADMIN_USERNAME`、`INITIAL_ADMIN_PASSWORD`、`INITIAL_ADMIN_DISPLAY_NAME` 设置。当前数据库结构版本为 v20。 统一发布 Web 和数据库工具: ```powershell pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\scripts\publish.ps1 ``` 发布结果分别位于 `artifacts/publish/web` 和 `artifacts/publish/tools`。服务器启动 Web: ```powershell dotnet .\artifacts\publish\web\Eis.Web.dll ``` 数据库工具使用编译后的 `Eis.Tools.dll`,不需要源代码或 `dotnet run`: ```powershell dotnet .\artifacts\publish\tools\Eis.Tools.dll database init --sqlite --path .\data\exam.sqlite dotnet .\artifacts\publish\tools\Eis.Tools.dll database seed --sqlite --path .\data\demo.sqlite --dry-run ``` ### Docker 项目根目录包含生产镜像和 Docker Compose 配置。默认使用 SQLite,数据库保存在命名卷 `exam-information-data` 中,因此重建容器不会丢失数据。 先创建容器环境文件,并将其中的 TOTP 主密钥、文书防伪签名密钥和初始管理员密码替换为相互独立的安全随机值: ```powershell Copy-Item .env.docker.example .env.docker ``` 然后构建并启动: ```powershell docker compose up --build --detach ``` 启动完成后访问 。查看状态和日志可运行: ```powershell docker compose ps docker compose logs --follow app ``` 停止服务使用 `docker compose down`;该命令会保留数据库卷。只有明确需要删除全部 SQLite 数据时才使用 `docker compose down --volumes`。 也可以只构建镜像: ```powershell docker build --tag hengzhun-exam-system:local . ``` 镜像包含 ASP.NET Core 10 Web 宿主和编译后的 `/app/tools/Eis.Tools.dll`,默认监听 `0.0.0.0:4173`,以非 root 用户运行,并通过 `/health/live` 执行健康检查。需要连接 MySQL 或 Redis 时,用运行环境变量覆盖 `DATABASE_CLIENT`、`DATABASE_URL`/`MYSQL_*`、`REDIS_URL`;认证状态默认使用同一 Redis 服务的独立 DB 1,也可以通过 `REDIS_SESSION_DB` 或 `REDIS_SESSION_URL` 单独配置。此时 SQLite 数据卷可以移除。 容器内执行数据库工具前应先停止 Web,SQLite 目标必须与命名卷路径完全一致: ```powershell docker compose stop app 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 docker compose up --detach app ``` #### Gitea Actions 自动发布跨平台程序包与 Docker 镜像 工作流位于 `.gitea/workflows/publish.yml`。它会构建 Vue 前端、使用 .NET 10 运行测试,然后默认生成以下无需预装 .NET 运行时的自包含程序包: - Windows:`win-x64`(`.zip`) - Linux:`linux-x64`、`linux-arm64`(`.tar.gz`) 每个程序包都把 Web 与数据库工具放在同一个 `app` 目录中,使二者共享 .NET 运行时和公共依赖;根目录还包含 `README.md`、`LICENSE` 和环境变量示例,构建结果同时附带 `SHA256SUMS`。标签构建会把这些文件上传到同名 Gitea Release;手动构建可在 Actions 运行记录中下载归档。普通代码推送不会触发这套耗时的发布构建。 解压后,Windows 使用 `.\app\Eis.Web.exe` 启动服务,Linux/macOS 使用 `./app/Eis.Web`;数据库工具分别为 `.\app\Eis.Tools.exe` 和 `./app/Eis.Tools`。 如需 Windows ARM64、macOS Intel 或 Apple Silicon 包,从 Gitea Actions 页面手动运行工作流并勾选“同时构建 Windows ARM64 和 macOS x64/ARM64”。扩展构建会在默认三种平台之外增加 `win-arm64`、`osx-x64` 和 `osx-arm64`。 同一工作流还会构建 `linux/amd64`、`linux/arm64` 双架构 Docker 镜像,并同时推送到 Docker Hub 与 `git.biss.click/biss/exam-information-system`。 使用前需要完成以下配置: 1. 在 Docker Hub 创建目标仓库,并创建具有该仓库 Read & Write 权限的访问令牌。 2. 在 Gitea 仓库的 Actions Variables 中添加 `DOCKERHUB_IMAGE`,值为不带 registry 和 tag 的完整镜像名,例如 `yourname/exam-information-system`。 3. 在 Gitea 仓库的 Actions Secrets 中添加 `DOCKERHUB_USERNAME` 和 `DOCKERHUB_TOKEN`。前者填写 Docker Hub 用户名,后者填写访问令牌,不要填写账户密码。 4. 使用对 `biss` 组织拥有软件包写权限的 Gitea 账号,在“设置 → 应用 → 生成新令牌”中创建具有 Package Read & Write 权限的个人访问令牌。在仓库 Actions Variables 中添加 `REGISTRY_USERNAME`,值为该令牌所属的用户名;在 Actions Secrets 中添加 `REGISTRY_TOKEN`,值为个人访问令牌。自定义 Secret 不能使用 Gitea 保留的 `GITEA_` 前缀,也不能用工作流内置的 `GITEA_TOKEN` 代替该软件包令牌。 5. 确保 Gitea Actions 与仓库的软件包注册表已启用,并且 `ubuntu-latest` Runner 能访问 Docker daemon、GitHub、Docker Hub 和 `git.biss.click`。双架构构建还需要 Runner 允许 QEMU 注册步骤运行。 推送形如 `v1.2.3` 的 Git 标签后,会自动构建跨平台程序包,发布镜像标签 `1.2.3`、`1.2`、`latest` 和对应的提交标签,并在构建成功后创建带下载附件的同名正式 Gitea Release。例如: ```powershell git tag v1.2.3 git push origin v1.2.3 ``` 带连字符预发布后缀的语义化版本标签会自动创建 Gitea Pre-release,例如: ```powershell git tag v1.3.0-rc.1 git push origin v1.3.0-rc.1 ``` 该版本的镜像标签为 `1.3.0-rc.1`,不会覆盖稳定版的 `1.3` 或 `latest` 标签。除版本标签外,也可以从 Gitea Actions 页面手动运行工作流;普通分支推送不会触发发布。 构建缓存保存为同一 Docker Hub 仓库中的 `buildcache` 标签,以加快后续构建。Release 使用工作流内置的 `GITEA_TOKEN` 创建,无需添加额外 Secret;仓库或组织“Actions → General”中的任务令牌最大权限必须允许 Releases Write。 首次成功推送后,容器镜像会出现在 `biss` 所有者的软件包列表。Gitea 的软件包归属于用户或组织,不会天然归属于某个仓库;打开该软件包的设置页面,将它关联到 `Exam-Information-System`,即可让它显示在此仓库的“软件包”页。之后可使用 `docker pull git.biss.click/biss/exam-information-system:latest` 拉取。 应用会在空库上自动创建结构和基础配置。测试数据导入和空库重建均由编译后的 `Eis.Tools.dll` 完成;旧 Node 导入入口已移除。演示数据包内置于 `Eis.Infrastructure.dll`,生产服务器不需要 Node.js。 ## 数据库配置 应用启动时会自动读取项目根目录的 `.env`,可先运行 `Copy-Item .env.example .env` 创建配置文件。命令行或部署平台已经注入的进程环境变量优先于 `.env`。应用根据 `DATABASE_CLIENT` 使用不同数据库;未设置时,开发/测试环境默认 `sqlite`,ASP.NET Core 生产环境默认 `mysql`。 公开首页的机构名称、机构代码、电话、地址、邮箱、主标语和页脚提示分别由 `PUBLIC_SITE_NAME`、`PUBLIC_SITE_CODE`、`PUBLIC_SITE_PHONE`、`PUBLIC_SITE_ADDRESS`、`PUBLIC_SITE_EMAIL`、`PUBLIC_SITE_HERO_*`、`PUBLIC_SITE_FOOTER_NOTICE` 配置。修改 `.env` 后需要重启应用;这些配置会覆盖数据库中的演示机构信息,且只通过公开首页接口返回非敏感展示字段。 ### 本地 SQLite ```powershell $env:DATABASE_CLIENT = 'sqlite' $env:SQLITE_PATH = './data/exam.sqlite' dotnet run --project .\src\Eis.Web\Eis.Web.csproj ``` `SQLITE_PATH` 可省略,默认路径就是 `./data/exam.sqlite`。 ### 生产 MySQL 8.4 先在 MySQL 8.4 中创建数据库和最小权限账号: ```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'@'%'; ``` 启动应用时设置连接信息,应用会自动创建以下关系表和系统基础配置,但不会自动写入测试业务数据: - `schools`、`school_classes`、`users`、`candidate_profiles` - `school_student_partitions`(学校学生专属表登记) - `exams`、`exam_subjects` - `exam_data_partitions`(考试专属表登记) - `registrations`、`registration_subjects` - `admission_number_rules`、`exam_arrangement_plans`、`admit_cards`、`admit_card_subjects` - `results`、`notices`、`audit_logs` - `test_centers`、`test_rooms`、`center_change_requests`、`center_change_rooms` - `number_rules`、`number_rule_segments` - `candidate_account_batches`、`candidate_account_batch_items` - `workflow_definitions`、`workflow_steps`、`workflow_instances`、`workflow_actions` - `organization`、`schema_metadata` 所有关联均有外键约束,账号、证件号、考试代码、报名关系、准考证号和单科成绩均有对应唯一约束。 系统采用“总表索引 + 独立物理分表”存储:创建每场考试时,会立即创建该场考试专用的 `exam_<分区键>_candidates`、`exam_<分区键>_admissions`、`exam_<分区键>_results`、 `exam_<分区键>_centers` 四张表;创建每所学校时,会创建 `school_<分区键>_students` 学生专属表。分区键由业务 ID 的 SHA-256 摘要生成,不直接拼接用户输入。报名、缴费、准考证编排、 成绩和学生资料发生变化后,专属表会自动同步;总表继续承担跨考试、跨学校查询和外键完整性约束。 ```powershell $env:ASPNETCORE_ENVIRONMENT = 'Production' $env:DATABASE_CLIENT = 'mysql' $env:MYSQL_HOST = '127.0.0.1' $env:MYSQL_PORT = '3306' $env:MYSQL_USER = 'exam_app' $env:MYSQL_PASSWORD = 'replace-with-a-strong-password' $env:MYSQL_DATABASE = 'exam_information' $env:ASPNETCORE_URLS = 'http://0.0.0.0:4173' dotnet run --project .\src\Eis.Web\Eis.Web.csproj ``` 也可以只设置标准连接地址 `DATABASE_URL=mysql://user:password@host:3306/database`。完整模板见 `.env.example`;将模板复制为 `.env` 后取消 MySQL 配置项的注释并填写实际连接信息即可。生产部署仍建议由部署平台注入环境变量,避免在服务器文件中保存密码。 ### Redis 缓存(可选) 配置 `REDIS_URL` 后,应用会缓存公开首页、已发布公告详情和每名考生的已发布成绩查询。公开数据默认 TTL 为 60 秒,成绩默认 TTL 为 24 小时;成绩录入/发布、批量导入、考试归档和成绩复议会自动使成绩缓存失效,超级管理员也可以在成绩管理中心手动刷新全部成绩缓存。Redis 未配置或暂时不可用时,应用会自动切换到有界本机缓存(默认最多 200 条),避免热点接口反复回源;写入后的失效语义保持不变。 同一个 `REDIS_URL` 还会启用 Redis 认证状态存储:登录 Session、TOTP 登录挑战和 TOTP 绑定临时状态全部写入 Redis。普通接口缓存按 `REDIS_URL` 使用 DB 0 时,认证状态默认自动选择独立 DB 1;可通过 `REDIS_SESSION_DB` 修改逻辑 DB,或通过 `REDIS_SESSION_URL` 指向另一台 Redis。应用会拒绝让认证状态与普通缓存使用同一 Redis 端点的同一逻辑 DB。认证 Redis 配置后连接失败会阻止服务启动,避免多实例之间悄悄退回本机状态而出现随机掉线。完全未配置 Redis 时,认证状态仍使用本机内存,服务重启会要求重新登录。 数据库关系表会按写入版本复用进程内只读快照,避免每个请求重复扫描并转换全部业务表。应用自身写入会立即使快照失效;SQLite 还通过 `PRAGMA data_version` 检测其他连接的提交,MySQL 外部直写默认最多延迟 30 秒可见。可通过 `DATABASE_STATE_CACHE_TTL_MS` 调整 MySQL 快照时间,通过 `LOCAL_CACHE_MAX_ENTRIES` 控制本机接口缓存上限。 ```powershell $env:REDIS_URL = 'redis://127.0.0.1:6379/0' $env:REDIS_CACHE_PREFIX = 'exam-information' $env:REDIS_CACHE_TTL_SECONDS = '60' $env:REDIS_RESULTS_CACHE_TTL_SECONDS = '86400' $env:REDIS_SESSION_DB = '1' $env:AUTH_SESSION_TTL_SECONDS = '28800' dotnet run --project .\src\Eis.Web\Eis.Web.csproj ``` 生产环境可使用 `redis://` 或启用 TLS 的 `rediss://` 连接地址,并通过 `REDIS_CONNECT_TIMEOUT_MS` 调整启动连接超时。若 Redis Cluster 不支持非 0 逻辑 DB,请用 `REDIS_SESSION_URL` 为认证状态配置独立 Redis 实例。 ### 导入服务器 MySQL 测试数据 先停止正在运行的应用进程,确认服务器 `.env` 中已经设置 `DATABASE_CLIENT=mysql` 及完整 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 ``` 工具会读取 `.env`,拒绝 MySQL 系统数据库,校验 v20 结构和已有数据,并在同一事务内清理、导入。若检测到无法识别为内置演示数据的业务记录,默认拒绝覆盖。仅在确认目标确实是可完全覆盖的测试库时追加: ```powershell dotnet .\artifacts\publish\tools\Eis.Tools.dll database seed --mysql --confirm-target exam_test --force ``` 强制模式会删除该 MySQL 数据库内现有应用数据并在同一事务中写入样例数据,但不会删除数据库本身。MySQL 操作前应另行完成数据库备份;不要对生产业务库执行该命令。 ## 中考志愿填报与招生录取 系统可按考试单独启用志愿填报,未启用的考试不会出现志愿入口。完整流程如下: 1. 超级管理员设置填报时间、普通志愿数、最多提交次数和当前阶段;考生只有在当次成绩全部发布后才能填报,达到提交上限后自动锁定。 2. 招生学校账号以结构化表单上传本校普通生、特长生与生源校指标分配计划,超级管理员审核后生效;超级管理员也可代上传并直接审核。 3. 生源校学校管理员按考试逐人确认指标分配资格;本校资料已完善的在册考生全部确认后,系统自动公开有无资格及对应特长类型。超级管理员和班级管理员均不能代确认。 4. 每名考生有一个专用指标分配志愿栏,只有确认有资格且招生校对本校分配了对应指标时可选;其余均为普通志愿。志愿只能由考生本人保存或修改,班级、校级管理员无权查看,超级管理员只读可见。 5. 超级管理员结束填报并执行投档。系统按总成绩降序逐个检索志愿,严格区分指标计划池与普通计划池,并遵循“分数优先、遵循志愿”。 6. 投档材料只发送到对应招生学校,包含必要考生资料与当次成绩,不包含考生其余志愿。学校可接收或填写特殊理由申请退档,退档由超级管理员统一审核。 7. 超级管理员签发正式录取后,系统按“招生学校代码 + 考试代码 + 校内独立流水号”生成稳定的录取通知书编号,并开启招生学校报到工作台。 8. 招生学校可逐人暂存 Y/N/P 报到状态,也可导出带下拉校验的 Excel、修改后导入,或扫描录取通知书二维码核验并登记;完整报到情况提交前不会进入审批。 9. 学校提交报到情况后可选择不补录或申请补录。超级管理员审批所有学校决定后,系统按缺额进入下一轮补录或结束录取;计划录取率和实际报到率在双方工作台实时显示。 10. 审批通过的报到情况会自动进入公开通知,包含计划数、正式录取数、已报到数、缺额和学校说明;无补录时标题不会出现“补录”。录取结束后继续自动发布脱敏录取名单及按学校、类别统计的录取分数线。 公开公示固定包含报名号、姓名、考生总成绩和录取学校;证件号、手机号等重要身份信息只提供脱敏值。考生档案中的特长资格按“体育 / 艺术”大类与对应小类登记,志愿页面先按学校代码选择招生校,再仅显示符合本人资格的该校类别。 学校统一在“学校管理”中维护,并可分别标记为生源校、招生校或同时具备两类职责。每场考试报名都包含独立于科目的 `feature_score`(特征分),默认 0,由超级管理员登记;招生学校可设计本校录取通知书的标题、正文、落款和配色,通知书不再添加“录取专用章”。管理后台以一级业务域分组,并把招生录取拆为录取设置、招生账户、招生计划、报到与补录、投档监督等二级菜单。 数据结构版本为 v20,`admission_records` 关系表新增指标资格、资格公示和分数线公告记录,并支持 SQLite / MySQL 自动迁移。新角色值为 `admission_school`。 ## 手动测试数据账号 测试数据脚本会提供以下账号;其中初始超级管理员也可能由正常首次建库创建,并可通过环境变量改名、改密,其余校级、班级和考生账号不会在正常启动时创建: 为了便于临时联调,所有预置样例账号统一使用密码 `12345678`,且预置考生不会在首次登录时被要求改密。通过系统业务流程后续新建的账号仍按正式规则生成随机初始密码。 | 角色 | 账号 | 密码 | | --- | --- | --- | | 超级管理员 | `admin` | `12345678` | | 超级管理员(监督演示) | `supervisor` | `12345678` | | 校级管理员 | `school_admin` | `12345678` | | 同校校级管理员(转交演示) | `school_admin_2` | `12345678` | | 班级管理员 | `class_admin` | `12345678` | | 同班班级管理员(均分演示) | `class_admin_2` | `12345678` | | 考生 | `2026-HZ01-F-0001` | `12345678` | ## 测试结束后初始化系统 先停止应用。SQLite 重建会自动生成带时间戳的原库备份,然后恢复系统基础配置和一个初始超级管理员: ```powershell dotnet .\artifacts\publish\tools\Eis.Tools.dll database reset --sqlite --path .\data\exam.sqlite --confirm-target .\data\exam.sqlite ``` MySQL 应先执行 `--dry-run` 确认目标,再明确填写数据库名: ```powershell dotnet .\artifacts\publish\tools\Eis.Tools.dll database reset --mysql --dry-run dotnet .\artifacts\publish\tools\Eis.Tools.dll database reset --mysql --confirm-target exam_test ``` MySQL 模式会自动识别由本项目生成的批量演示数据;目标包含非演示业务记录时仍会拒绝,只有确认可覆盖时才能追加 `--force`。初始化管理员由 `.env` 中的 `INITIAL_ADMIN_USERNAME`、`INITIAL_ADMIN_PASSWORD`、`INITIAL_ADMIN_DISPLAY_NAME` 决定。 ## 自动化测试 ```powershell dotnet test .\Eis.slnx pwsh.exe -NoLogo -NoProfile -NonInteractive -File .\scripts\smoke-dotnet-native.ps1 ``` xUnit 测试使用独立临时 SQLite 数据库,覆盖认证与历史数据兼容性、端点启用约束、文书防伪码、文件处理、缓存以及空库 v20 初始化;测试不会连接或修改生产数据库。 ## 项目结构 项目采用 ASP.NET Core 10 模块化单体架构,由一个 `Eis.Web` 进程部署;HTTP、权限、业务服务、数据库适配和前端页面按职责分层。 ```text Eis.slnx .NET 10 解决方案 src/Eis.Domain 领域模型与业务值 src/Eis.Application 应用服务契约 src/Eis.Infrastructure SQLite/MySQL、认证、缓存、Excel 与业务实现 src/Eis.Tools 可独立发布的数据库初始化、重建和演示数据工具 src/Eis.Web ASP.NET Core 宿主、端点和静态资源 src/Eis.Web/ClientApp Vue 3 单文件组件、Vite 配置与前端源码 src/Eis.Web/wwwroot/vue-app Vue 生产构建产物 src/Eis.Web/wwwroot/js 渐进迁移期间保留的业务模块 src/Eis.Web/wwwroot 浏览器入口、基础样式及 CKEditor tests/Eis.Infrastructure.Tests xUnit 自动化测试 scripts/publish.ps1 Web 与数据库工具统一发布脚本 scripts/publish-platform-packages.sh CI 跨平台自包含程序包构建脚本 scripts/smoke-dotnet-native.ps1 纯 .NET 发布产物烟测 data/exam.sqlite 本地运行后生成的 SQLite 数据库 .env.example 开发与生产环境变量模板 ```