Files
Exam-Information-System/README.md
T

207 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 衡准 · 考试信息管理系统
一个完整可运行的分级权限考试信息管理系统,使用 Node.js 后端;本地开发采用 SQLite,生产环境支持 MySQL 8.4。
## 已实现功能
### 公开服务首页
- 通知公告首页展示与详情阅读
- 已发布考试、报名时间、考试时间和科目展示
- 考试服务办理流程说明
- 考生注册与双角色登录入口
### 考生中心
- 报名号即考生账户,同一考生参加不同考试始终使用同一个号码
- 学校管理员按一个或多个班级填写人数并提交批量申领(单人也按 1 人批次走审批)
- 首次登录强制修改初始密码,完成后才能补全个人信息
- 完整维护姓名、性别、证件号码、籍贯、出生日期、民族、家庭住址、手机号、邮箱、学校、班级、监护人和紧急联系人
- 自主注册可由超级管理员随时开启或关闭;开启后系统直接生成固定报名号
- 资料审核状态与管理员审核意见
- 查看开放考试并自主选择多个报考科目
- 查看报名审核、应缴金额、缴费状态及班级负责人确认记录
- 准考证生成状态、开放时间与下载
- 已发布成绩查询,并可按科目提交成绩复议、查看审批进度与结论
- 通知公告中心
### 管理后台
- 超级、校级、班级三级管理员,同一级支持多个账号
- 超级管理员管理全局事务,并可监督、修改、退回全部审批流程
- 校级管理员管理本校班级、班级管理员、考生和报名流程,按班级批量申领报名号,并提交本校考点、考场档案变更
- 班级管理员可查看并审批本班考生、报名与成绩复议流程,并在线下收款后确认考生已缴费;成绩录入仍仅限超级管理员
- 报名终审与缴费确认相互独立,系统不接入支付 SDK;仅考生所属班级负责人可确认缴费,并记录确认人和时间
- 超级、校级、班级管理员均可按各自数据范围查看及导出 Excel 缴费名单
- 考生信息修改、考试报名、成绩复议、批量报名号申领、考点考场变更使用可配置的多步骤审批流程
- 班级和校级审批自动限定到考生所属班级、学校;同范围多名管理员按当前待办与历史分配量自动均分
- 当前处理人可将流程转交给同范围的同级管理员
- 自定义报名号生成规则,可组合年份、学校代码、性别、固定值和流水号
- 报名号在创建考生账户时只生成一次,后续考试报名自动复用
- 超级管理员只维护号码规则;校级批量申请最终批准后,系统原子生成固定报名号、随机初始密码和待补录账户
- 批次结果按班级返回校级管理员,并可导出 Excel 安全下发
- 结构化考点与考场档案,包含代码、负责人、应急电话、开放时间、交通、楼栋、楼层、容量、座位编排说明、类型和状态
- 考点新增及考点/考场修改先形成申请快照,审批通过后才整体更新正式档案
- 班级、班级管理员、报名号班级配额、考生资料、考点考场和成绩均提供 Excel 模板、导入与当前数据导出;只读角色保留对应导出能力
- Excel 导入逐行校验并返回具体行号;考生资料和考点考场的批量修改仍必须经过配置好的审批流程
- 考务指标与审计日志
- 考生资料审核、通过或退回修改
- 考试报名及科目审核
- 创建考试并结构化配置科目日期、时间、费用和满分;每科可独立选择固定分、排名前百分比或不设单科线,并汇总总分
- 支持固定总分线、总成绩排名前百分比、单科均达线及不判定四类整场合格策略
- 通知发布、草稿、撤回及首页置顶
- 按整场考试预检并批量编排准考证,支持班内、校内、县区内、市内和省内五级混编
- 预置“县区编号+考场号+座位号”“县区号+考场号+流水号”“考点学校代码+考场号+座位号”“考生学校代码+考场号+座位号”四种号码规则
- 多科目考生固定在同一考点,各科独立分配考场和座位;同科目组合优先相邻编排
- 编排前校验科目时间冲突、考点容量、档案完整性和号码唯一性,默认保留备用考场并支持稳定种子复现
- 每科可独立设置固定及格分、排名前百分比或不设单科线;成绩等级按同场同科排名百分位自动计算
- 默认排名等级区间为前 10% A+、前 25% A、前 50% B+、前 70% B、前 90% C、其余 D;同分共享名次
- 成绩管理中心按多场考试切换,展示录入/发布进度、成绩出齐人数、整场合格率、缺失科次与复议数量,并提供可筛选成绩台账
- 成绩复议终审表单展示考试、科目、原分、当前排名和达线规则;批准后在同一事务内更新成绩并只重算该考生的排名区间结论
- 成绩 Excel 采用“上传解析与逐行校验—页面暂存预览—确认后原子批量写库”的两阶段流程,预览不会修改数据库
- 超级管理员可将整场考试不可逆归档;归档后手工录入、Excel 导入、复议改分和考试配置全部锁定,历史报名、准考证与成绩默认折叠展示
- 管理员与考生接口权限隔离
### 系统能力
- PBKDF2 加盐密码哈希
- HttpOnly、SameSite 登录 Cookie
- 服务端角色权限校验
- SQLite / MySQL 8.4 双数据库持久化
- 规范关系模型、外键、唯一约束和业务索引
- 业务写入与审计日志使用原子事务提交
- 关键管理操作审计日志
- 组织、学校、班级三级数据范围在服务端强制过滤
- 审批实例、当前责任人、转交和监督操作全程留痕
- 桌面端与移动端响应式布局
- Excel 文件使用 `exceljs` 生成和解析,并限制上传文件大小
## 运行
需要 Node.js 22.5 或更高版本(SQLite 使用 Node.js 内置驱动)。
```powershell
npm install
npm start
```
打开 <http://127.0.0.1:4173>。
本地开发无需额外配置,首次运行会自动创建 `data/exam.sqlite` 和完整关系型数据库结构,但不会导入学校、考生、考试或报名测试数据。首次建库只写入系统基础配置和一个超级管理员;账号、密码和显示名可通过 `INITIAL_ADMIN_USERNAME``INITIAL_ADMIN_PASSWORD``INITIAL_ADMIN_DISPLAY_NAME` 设置。当前数据库结构版本为 v15;低于 v15 的开发库会提示重建,不执行兼容迁移。
需要清空并重建空业务库时运行 `npm run reset-db`。需要测试数据时再手动运行 `npm run seed-test-data`;该命令会覆盖本地 SQLite 数据库,生成 4 所学校、360 名批量考生及 360 条不同状态的报名数据,并明确不生成考场编排计划和准考证。省市区县下拉数据位于 `src/data/china-regions.mjs`,当前版本为国家地名信息库截至 2025-12-31 的三级快照,并补入和康县(653228)与和安县(653229);从新版 CSV 更新时可运行 `node scripts/build-regions.mjs <CSV路径> src/data/china-regions.mjs`
## 数据库配置
应用启动时会自动读取项目根目录的 `.env`,可先运行 `Copy-Item .env.example .env` 创建配置文件。命令行或部署平台已经注入的进程环境变量优先于 `.env`。应用根据 `DATABASE_CLIENT` 使用不同数据库;未设置时,开发/测试环境默认 `sqlite``NODE_ENV=production` 默认 `mysql`
### 本地 SQLite
```powershell
$env:DATABASE_CLIENT = 'sqlite'
$env:SQLITE_PATH = './data/exam.sqlite'
npm start
```
`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`
- `exams``exam_subjects`
- `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`
所有关联均有外键约束,账号、证件号、考试代码、报名关系、准考证号和单科成绩均有对应唯一约束。
```powershell
$env:NODE_ENV = '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:HOST = '0.0.0.0'
npm start
```
也可以只设置标准连接地址 `DATABASE_URL=mysql://user:password@host:3306/database`。完整模板见 `.env.example`;将模板复制为 `.env` 后取消 MySQL 配置项的注释并填写实际连接信息即可。生产部署仍建议由部署平台注入环境变量,避免在服务器文件中保存密码。
## 手动测试数据账号
测试数据脚本会提供以下账号;其中初始超级管理员也可能由正常首次建库创建,并可通过环境变量改名、改密,其余校级、班级和考生账号不会在正常启动时创建:
| 角色 | 账号 | 密码 |
| --- | --- | --- |
| 超级管理员 | `admin` | `Admin123!` |
| 超级管理员(监督演示) | `supervisor` | `Admin123!` |
| 校级管理员 | `school_admin` | `School123!` |
| 同校校级管理员(转交演示) | `school_admin_2` | `School123!` |
| 班级管理员 | `class_admin` | `Class123!` |
| 同班班级管理员(均分演示) | `class_admin_2` | `Class123!` |
| 考生(首次登录需改密) | `2026-HZ01-F-0001` | `Candidate123!` |
## 自动化测试
```powershell
npm test
```
测试使用独立临时 SQLite 数据库,覆盖固定报名号跨考试复用、首次登录强制改密、完整资料补录、自主注册开关、三级管理员数据范围、本校班级与班级管理员管理、多级审批、同级转交、校级按班级批量申领与终审原子建号、班级负责人缴费确认、三级缴费名单导出、结构化考点考场及变更审批、多资源 Excel 导入导出、多科目报名、独立科目及格规则、成绩 Excel 预览后原子提交、五级准考证混编、四种号码规则、多科目同考点、成绩复议、校班严格匹配和多人均分。
## 项目结构
项目采用模块化单体架构:仍由一个 Node.js 进程部署,但 HTTP、权限、业务路由、数据库适配和前端页面按职责分开。
```text
index.html 页面入口
styles.css 公共首页、考生端、管理端响应式样式
app.js 前端路由、事件与表单控制器
server.mjs HTTP 服务启动、模块装配与静态文件服务
database.mjs 数据仓储与数据库模块装配
excel.mjs Excel 模板、导入解析与导出工作簿
src/data/base.mjs 空业务库与系统基础配置
src/data/seed.mjs 手动测试数据生成器
scripts/import-test-data.mjs 独立测试数据导入脚本
src/http/responses.mjs JSON、文件与请求体处理
src/security/session.mjs Cookie 会话与当前用户
src/security/authorization.mjs 管理层级、权限和数据范围
src/routes/public.routes.mjs 公开 API
src/routes/auth.routes.mjs 登录、注册与改密 API
src/routes/candidate.routes.mjs 考生业务 API
src/routes/admin.routes.mjs 管理业务 API
src/database/schema.mjs SQLite / MySQL 关系模型
src/database/sqlite-adapter.mjs SQLite 初始化、迁移与事务适配
src/database/mysql-adapter.mjs MySQL 初始化、迁移与事务适配
src/client/state.mjs 前端共享状态
src/client/api.mjs 浏览器 API 请求封装
src/client/ui.mjs 格式化、图标与通用 UI 工具
src/client/public-views.mjs 公共首页与登录注册视图
src/client/candidate-views.mjs 考生中心视图
src/client/admin-views.mjs 管理后台视图
tests/system.test.mjs 端到端系统测试
data/exam.sqlite 本地运行后生成的 SQLite 数据库
.env.example 开发与生产环境变量模板
```