# 会计经审在线考试系统

面向学校电脑教室的局域网在线考试系统：考生凭"姓名 + 准考证号"登录，管理员统一设置开考时间，交卷立即出成绩与用时，支持打印个人成绩单与总成绩排名，支持 Excel/CSV 批量导入试题。**全程离线运行，零第三方依赖，不访问互联网。**

## 一、快速开始

### 方式 A：直接运行（需要 Python 3.8+）

1. 确认电脑装有 Python 3（Windows 安装时勾选 "Add Python to PATH"）。
2. 把整个项目文件夹拷贝到教师机（服务器），双击：
   - Windows：`启动服务器.bat`（启动后会自动打开管理端和考生端页面）
   - macOS / Linux：`./启动服务器.sh`（或 `python3 server.py`）
3. 窗口显示启动成功后：
   - **考生端**：学生机浏览器访问 `http://教师机IP:8080/`（**学生机无需安装任何软件**）
   - **管理端**：教师机浏览器访问 `http://教师机IP:8080/admin`
   - 默认管理员口令：`admin`（首次登录会提示修改）

**让学生机全部打开考生端**：在教师机双击 `生成学生端快捷方式.bat`，输入教师机 IP，桌面上会生成一个快捷方式文件；通过 U 盘/共享文件夹/机房管理软件发到每台学生机，学生双击即打开考生端（也可直接把 `http://教师机IP:8080/` 写在黑板上让学生输入）。

### 让学生机打开考生端的简便办法（按推荐顺序）

1. **机房有电子教室软件（极域/红蜘蛛/凌波等）**：教师端"远程命令/批量执行"功能一条命令让全部学生机同时打开考生端，完全不用发文件。

   **以极域电子教室为例**：
   ① 教师端软件中选中全部学生机；
   ② 打开"远程命令"功能（多数版本在工具栏"远程管理 / 其他工具"里）；
   ③ 在命令框输入并发送（IP 换成教师机实际 IP）：
   ```
   start http://192.168.1.100:8080/
   ```
   ④ 全部学生机浏览器自动弹出考生端登录页。

   红蜘蛛、凌波等软件同样有"远程命令"功能，命令相同；用 `启动服务器-短地址.bat` 启动时命令改为 `start http://192.168.1.100/`。

   配套技巧：
   - 开考前后可用软件的"黑屏肃静"统一控制考场纪律；
   - 收卷后想统一关闭学生浏览器，可远程执行：
     ```
     taskkill /f /im chrome.exe /im msedge.exe
     ```
     （注意：会关闭学生机上所有浏览器窗口）
2. **把地址缩到最短**：双击 `启动服务器-短地址.bat`（用 80 端口启动），学生端地址变成 `http://192.168.1.100`，不用输端口号；或把教师机计算机名改成好记的名字（如 `kaoshi`），学生输入 `http://kaoshi` 即可。
3. **黑板上写一个地址**：学生浏览器第一次输入后会自动记住（下次只敲一个字母+回车就能补全），每台机器只需输入一次。
4. 兜底方案：`生成学生端快捷方式.bat` 生成的文件发给学生。

> 教师机 IP 查看方法：Windows 命令行执行 `ipconfig`，看"IPv4 地址"；
> 启动窗口里也会直接打印局域网访问地址。如 8080 端口被占用：
> `python server.py --port 9000`（学生端地址同步改端口）。

### 方式 B：单文件 exe（教室机器免装 Python）

在**任意一台 Windows 电脑**（教师机本机也行）双击项目里的 `打包exe.bat`，等待 1~3 分钟，`dist/会计经审考试系统.exe` 即生成完毕；把该 exe 拷到教师机双击运行即可，教师机无需安装 Python。详细说明见 `build_exe.md`。

## 二、教师操作流程

1. **题库管理**：点击"导入试题"，选择文件导入（示例题库可通过管理页"下载示例题库（50题）"按钮获取，或直接使用项目 `sample/` 目录下的 `会计经审示例题库50题.csv`）；导入会逐行校验，错误行会给出具体行号。
2. **考生管理**：导入考生名单（姓名、准考证号）。
3. **考试场次**：新建场次 —— 设置场次名、开考时间（服务器时间）、时长、抽题方式（全部或按题型抽 N 道）、题目/选项乱序、迟到规则。
4. 开考后可在**监考看板**实时查看进度、切屏告警，必要时"强制收卷"。
5. 试卷只有 单选 / 多选 / 判断 三种题型，交卷即出成绩。
6. **成绩排名**查看排名（总分降序、同分用时升序），可打印 A4 排名表或导出 CSV。

## 三、考生流程

登录（姓名 + 准考证号）→ 等待页倒计时 → 到点自动进入答题 → 答题（每题即时保存，刷新/断线可恢复）→ 交卷 → 立即显示成绩、用时、交卷时间与逐题得分（不含参考答案）→ 打印成绩单。

## 四、功能与规则说明

| 功能 | 说明 |
|---|---|
| 统一开考 | 以**服务器时间**为准，开考前只能看到等待页；到点自动进入答题 |
| 自动收卷 | 倒计时结束服务器自动收卷并判分（即使学生关闭了页面） |
| 交卷即出分 | 试卷只有 单选 / 多选 / 判断，交卷即出成绩 |
| 判分规则 | 单选/判断全对得分；多选默认全对得分（可在设置中改为"漏选得一半分"） |
| 答案保存 | 每答一题立即保存到服务器，断电、刷新、断网重进可恢复进度 |
| 防作弊（轻量） | 切屏计数：默认 3 次警告、5 次自动交卷（可在设置中调整或关闭）；答题页禁右键/复制 |
| 迟到处理 | 默认允许迟到登录但统一按截止时间收卷；可改为迟到单独计时 |
| 迟到禁入 | 场次可配置"开考后 N 分钟内允许登录"，超时拒绝登录（0=不限） |
| 提前交卷限制 | 场次可配置"开考后 N 分钟内禁止交卷"（0=随时可交） |
| 考生须知 | 场次可配置考试说明文本，开考前显示并要求考生勾选确认（留空不显示） |
| 答卷复核 | 成绩排名页可查看任意考生逐题答案与标准答案对照，用于成绩申诉复核 |
| 打印 | 考生端个人成绩单；教师端总成绩排名表，均为 A4 排版，浏览器打印（Ctrl+P） |
| 缺考口径 | 排名表只列**有成绩（已交卷）**的人；缺考人员用「导出缺考名单」核对（= 名单人数 − 有成绩人数） |
| 数据备份 | 管理端「系统设置 → 下载数据备份」：不停止服务也能导出与正式库完全一致的完整数据 |
| 补录考生 | 开考后发现名单漏人/临时增补：先在「考生管理」补录，再到「监考看板」点【补进本场次】即可（不用重建场次） |
| 场次唯一性 | 只保留一个"进行中"的正式场次；系统检测到多个进行中场次时会在场次页给出醒目告警 |
| 答案保密 | 考生交卷后只看到自己的答案与得分，**看不到参考答案**（防止提前交卷者把答案传给同学）；教师端"答卷复核"仍可查看参考答案 |

## 五、导入文件格式

### ⚠ 导入正式试卷前必读（避免示例题/旧题混进正式卷）

- **导入是"追加"不是"覆盖"**：题库里已有题时再导入，会变成"旧题 + 新题"。
  正式竞赛要求 50 题（单选15/多选20/判断15、100 分），如果混进示例题就会变成 100 题。
- 正确顺序：**先清空题库 → 再导入正式试卷 → 核对统计 → 最后建场次**
  （题目在建场次那一刻被锁定；顺序反了要删场次重来）
- 系统已加防呆：① 题库非空时导入会先弹确认；② 导入结果会显示"题库现有 N 题"并与
  正式竞赛规格比对（不一致会 ⚠ 提示）；③ 题干与已有题目重复时会提示"可能是重复导入"；
  ④ 题库管理页顶部常驻"✅/⚠ 与正式竞赛是否一致"的核对条。
- 出厂状态：部署包与完整包里的题库都是**空的**；示例题库只作为 `sample/` 里的文件提供，
  需要试用时再手动导入。

### 试题（CSV 用 UTF-8 编码保存，xlsx 直接支持）

表头：`题型,题干,选项A,选项B,选项C,选项D,选项E,选项F,答案,分值`（解析列已不再使用）

- 题型：只能是 `单选` / `多选` / `判断` 三种
- 单选答案填单个字母（B）；多选填字母串（ABD）；判断答案填 对/错（或 A/B，A=对 B=错）
- 判断题选项固定"对/错"；分值必填正数
- 管理端可下载标准模板与示例题库（`sample/会计经审示例题库50题.csv`，仅管理端可下载，学生端不可访问）

### 考生名单

列：`姓名,准考证号,单位`（**单位可选**，填了就会显示在考生成绩单与总排名表上，便于按单位统计）。
> 机位号（座位号）由现场抽签决定，**系统不参与、名单里也不用填**；抽签与座位安排请用
> 《考场情况记录表》，考生按抽签机位就座即可，登录仍用"姓名 + 准考证号"。
- **准考证号建议先把该列设为"文本"再填**，否则 Excel 会把 `0012` 变成 `12`（系统无法还原）；
  系统本身原样保留前导零，实测导入 `0012` 后库里就是 `0012`、登录也必须用 `0012`。
- 表头写"姓名"或"名字"都能识别；缺姓名/准考证号、准考证号重复（文件内或与已有名单重复）、
  姓名/证号超过 50 字符、含不可见控制字符 → 都会按行号报错，**好行照常导入**（部分导入）。
- "考生管理"页可【导出名单 CSV】核对，也可【下载名单模板】。
- 四个机房必须导入**同一份完整名单**（约 200 人），不要只导本考场。

表头：`姓名,准考证号`

## 六、多机房考试与成绩合并（200 人场景）

**情况一：各机房网络互通（同一局域网可达）**
一台服务器即可承载全部考生（**200 人满员实测**：全员同时登录→答题→同时交卷，总耗时 35～45 秒、11,605 次请求、0 失败；到点 200 份答卷同时判分，最慢 3.8 秒全部完成；200～400 人单服务器可安全承载，更多人数建议分机房部署+成绩合并）：教师机放任一机房，其他机房学生机直接访问 `http://教师机IP:8080/`。部署前请网络管理员确认各机房之间互通。

**情况二：机房之间网络隔离（推荐，互不影响）**
每个机房部署一台服务器（部署包拷多份），考试流程：
1. 各机房导入**同一套题库**，并且每个机房都导入**同一份完整名单**（200 人全名单，不是只导本考场的）；
   ★ 为什么导全名单：合并时才能用"名单人数 − 有成绩人数"算出缺考人数；只导部分名单会导致缺考统计不准。
2. 各机房创建场次，**开考时间、时长设置成完全一致**（各机房教师机先联网对时）；
3. 各机房独立考试、独立收卷；
4. 考试结束后，在任一机房（作为汇总机）：
   - 各机房管理端"成绩排名"→"导出本机房 CSV"，把 CSV 文件拷到汇总机；
   - 汇总机管理端"成绩排名"→"**合并其他机房成绩**"→ 逐个选择其他机房的 CSV（**逐个上传会自动累计合并**，传完为止）；
   - 系统自动按"总分降序、同分用时升序"重新计算**全体总排名**，可打印总排名表、导出合并 CSV。

注意：同分按用时排名要求各机房教师机时钟一致，考前务必联网对时。

**合并时的四条铁律（已用"4 个机房、62 人名单"实测通过，见 docs 第 16 节）：**
0. 系统已会自动收卷，**但建议考完在每个机房点一次「强制收卷」**，让成绩立刻定稿（不等 5 分钟宽限）。
1. 各机房必须用**系统导出的原始 CSV**上传，**不要用 Excel 打开后另存**——Excel 会把准考证号的
   前导零吃掉（`0012` 变成 `12`），导致同一人算成两个人；系统已能识别这种文件并弹出 ⚠ 警告。
2. 合并后核对页面提示：`累计 N 名外部考生 … 当前总排名共 X 人（名单 M 人，缺考 K 人）`；
   **X 应等于"实际参加考试人数"，且不应超过名单 M 人**。
3. 合并结果只存在于当前网页：**刷新或关闭页面后需要重新上传各机房 CSV**，
   所以合并完请立刻"打印排名表"或"下载打印版文件 / 导出合并 CSV"留存。
4. 同一个机房的文件重复上传、或把"合并结果 CSV"再传一次，都不会重复计人（按准考证号去重，
   本机房优先、先上传的机房优先）。

## 六之二、考前压力自检（建议每个机房都跑一次）

**最简单的办法：双击系统文件夹里的「考前自检.bat」**（按提示填本机房人数、选 1 或 2 即可）。

也可以在命令行手动运行（会用**独立端口和临时数据库**模拟整场考试，**不影响 `data/exam.db`，正式服务可照常开着**）：

```
python load_test.py                  # 默认 200 人，跑三种极限场景（约 5 分钟）
python load_test.py --students 50    # 只按本机房实际人数测（约 15 秒）
python load_test.py --mode full      # 只测：整场同时考试（登录→答题→同时交卷）
python load_test.py --mode storm     # 只测：到点自动收卷（全部答卷同时判分）
python load_test.py --mode race      # 只测：时间到了还在答题（验证不丢答案）
```

输出会给出各接口的中位/P95/最慢响应时间、失败次数、内存峰值，并自动核对数据库
（答卷份数、答案条数、排名表序号是否连续）。**判定标准：异常记录 0 条、排名表行数＝考生数。**
若某台机器明显比其它机房慢（例如中位超过 1 秒），考前换一台机器或关闭杀毒软件实时扫描。

## 常见问题

- **学生打不开页面**：检查学生机与教师机在同一局域网；Windows 防火墙弹出提示时选择"允许访问"；确认用教师机 IP 而不是 127.0.0.1。
- **考生关掉浏览器/电脑断电**：服务器到点会自动收卷（默认到点后 5 分钟内归档，留出临时顺延的救急窗口），
  考生不会因为没点"交卷"而丢成绩；管理端"监考看板"里仍会显示他是"答题中"直到归档完成。
- **考试中途断电**：答案每题即时保存到教师机数据库，学生机断电重启后重新登录即可断点续考，已答题目与剩余时间自动恢复（时间以教师机为准，断电期间计时不暂停）。教师机断电：重新开机后双击启动脚本即可，数据不丢失；如需补偿断电耽误的时间，管理端 → 监考看板 → **顺延时长**（一键全考场顺延，考生页面几秒内更新倒计时）。建议教师机使用笔记本电脑或接 UPS。
- **改了本机时间想提前开考**：无效，系统一律以服务器时间为准。
- **服务器意外重启**：数据保存在 `data/exam.db`，重启后成绩、答案都在；考生重新登录即可继续（已交卷的会直接看到成绩）。
- **备份数据**：先退出程序，再拷贝整个 `data/` 文件夹（含 exam.db 及其 wal/shm 伴生文件）；不停机备份请用 sqlite3 的 `.backup` 或 `VACUUM INTO` 命令。
- **出现"服务器内部错误"**：管理端 → 系统设置 → **查看服务器日志**（或"导出日志文件"）即可看到原因和出错位置，把内容发给技术负责人就能定位；日志同时保存在 `data/server.log`，重启不丢。
- **管理员口令忘记了**：双击 `重置系统数据.bat` 选择"备份后重置"，会备份原数据并恢复默认口令 `admin`（注意：题库/考生名单/成绩会被清空，重置前请确认已有备份）。
- **导出/备份题库**：题库管理页"导出题库 CSV"。

## 六之三、公网辅助站（题目上传下载 / 资料分发）

已部署一台公网辅助站，用于**集中管理题目**与**分发资料**（正式考试仍在机房内网各自搭服务器）：

| 用途 | 网址 |
|---|---|
| 资料下载（公开，无需登录） | https://ks.llixz.cn/download |
| 管理端（导入/导出题库、建场次） | https://ks.llixz.cn/admin |
| 考生端 | https://ks.llixz.cn/ |

- 题库上传：管理端 →「题库管理」→ 导入试题（xlsx / CSV），逐行校验并报错误行号；
  下载：同一页「导出题库 CSV」，可备份或分发给各机房。
- 下载中心：把要公开分发的文件（部署包、导入模板、操作说明）放进服务器的 `downloads/`
  目录即可自动出现在 `/download` 页面（也可用环境变量 `EXAM_DOWNLOAD_DIR` 指定别的目录）；
  **正式试卷、答案、成绩不要放进该目录**。
- 服务器运维（技术负责人）：`systemctl restart ks-exam` 重启，日志 `/var/log/ks-exam.log`，
  数据在 `/opt/ks-exam/data`，健康检查 `https://ks.llixz.cn/api/health`。

## 七、目录结构

```
server.py            服务端入口（Python 标准库，零第三方依赖）
db.py                数据库访问层（SQLite）
logic.py             业务逻辑（抽题、判分、交卷、排名）
importer.py          试题/名单导入与校验
xlsx_read.py         极简 xlsx 读取器
static/              前端页面（原生 HTML/CSS/JS，无 CDN）
templates/           导入模板（仅管理端可下载）
sample/              示例题库（含答案，仅管理端可下载）
data/                运行数据（exam.db，自动生成）
启动服务器.bat/.sh   一键启动脚本
考前自检.bat         考前压力自检（双击即用，选人数即可，不碰正式数据）
test_e2e.py          端到端自测脚本（开发用）
load_test.py         考场压力测试/考前自检脚本（200 人同时考试模拟，不碰正式数据）
docs/                需求与设计方案文档
```

## 八、浏览器要求

请统一使用 **Chrome 73+ / Edge 79+ / Firefox 63+ / Safari 12.1+**（任意新版 Chrome/Edge 均可）。不支持 Internet Explorer 与旧版 Edge（EdgeHTML）。

## 九、安全说明

本系统面向**局域网教室环境**设计：管理员口令使用 PBKDF2（60 万次迭代）加密存储；默认口令为 admin（**可直接登录使用**；如需安全加固，可在"系统设置"勾选"强制修改默认口令"，开启后未改密无法使用管理功能，新口令要求 ≥6 位且不能为 admin；开启后需先按提示改密才能再关闭该开关）；管理员与学生登录均有限速；会话 12 小时有效并自动清理；试题模板与含答案的示例题库仅管理端可下载；超时后服务器强制收卷、不能再保存答案。

仍需知悉的局限：

- **传输明文**：全程 HTTP 明文，同网段技术高手可通过抓包窃取口令/会话，请勿暴露到公网；如条件允许可加自签 TLS 或改用独立交换机端口隔离。
- **防作弊为轻量级**：切屏计数、禁右键/复制均为前端手段，不承诺对抗刻意作弊。
- **冒名登录**：仅凭"姓名+准考证号"登录，知道他人考号即可冒名；重要考试建议现场核对证件。
- **多端登录**：同一账号可在多台电脑同时登录答题（后保存的覆盖先保存的），监考时留意异常。
