# 会计经审在线考试系统

面向学校电脑教室的局域网在线考试系统：考生凭"姓名 + 准考证号"登录，管理员统一设置开考时间，交卷立即出成绩与用时，支持打印个人成绩单与总成绩排名，支持 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. **题库管理**：点击"导入试题"，选择文件导入（示例题库可通过管理页"下载示例题库（A卷 50 题）"按钮获取，或直接使用项目 `sample/` 目录下的 `会计经审A卷-示例题库50题.csv`——**这份就是正式 A 卷**，含单选15/多选20/判断15、共 100 分）；导入会逐行校验，错误行会给出具体行号。
2. **考生管理**：导入考生名单（姓名、准考证号）。随机房装机包一起发的 231 人正式名单，
   可以直接点【导入随包名单（231 人）】一键导入；也可以点【导入考生名单】上传
   《准考证导入模板1.xlsx》。一份名单可反复导入，重复的准考证号会被自动跳过。
3. **考试场次**：新建场次 —— 设置场次名、开考时间（服务器时间）、时长、抽题方式（全部或按题型抽 N 道）、题目/选项乱序、迟到规则。
4. 开考后可在**监考看板**实时查看进度、切屏告警，必要时"强制收卷"。
5. 试卷只有 单选 / 多选 / 判断 三种题型，交卷即出成绩。
6. **成绩排名**查看排名（总分降序、同分用时升序），可打印 A4 排名表或导出 CSV。

## 三、考生流程

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

## 四、功能与规则说明

| 功能 | 说明 |
|---|---|
| 统一开考 | 以**服务器时间**为准，开考前只能看到等待页；到点自动进入答题 |
| 自动收卷 | 倒计时结束服务器自动收卷并判分（即使学生关闭了页面） |
| 交卷即出分 | 试卷只有 单选 / 多选 / 判断，交卷即出成绩 |
| 判分规则 | 单选/判断全对得分；多选默认全对得分（可在设置中改为"漏选得一半分"） |
| 答案保存 | 每答一题立即保存到服务器，断电、刷新、断网重进可恢复进度 |
| 防作弊（轻量） | 切屏计数：默认 3 次警告、5 次自动交卷（可在设置中调整或关闭）；答题页禁右键/复制 |
| 迟到处理 | 默认允许迟到登录但统一按截止时间收卷；可改为迟到单独计时 |
| 迟到禁入 | 场次可配置"开考后 N 分钟内允许登录"，超时拒绝登录（0=不限） |
| 提前交卷限制 | 场次可配置"开考后 N 分钟内禁止交卷"（0=随时可交） |
| 考生须知 | 场次可配置考试说明文本，开考前显示并要求考生勾选确认（留空不显示）；确认只在前端把关，不做服务端拦截 |
| 答卷复核 | 成绩排名页可查看任意考生逐题答案与标准答案对照，用于成绩申诉复核 |
| 打印 | 考生端个人成绩单；教师端总成绩排名表，均为 A4 排版，浏览器打印（Ctrl+P） |
| 成绩表打印/导出选项 | "成绩排名"页可勾选 **不显示姓名（只按准考证号）**，并可切换 **按成绩排名 / 按准考证号排序**（两个选项会记住上次选择，同时作用于页面、打印、下载打印版、导出的 CSV） |
| 缺考口径 | 排名表只列**有成绩（已交卷）**的人；缺考人员用「导出缺考名单」核对（= 名单人数 − 有成绩人数）。合并其他机房时，**可以把各机房的"缺考名单 CSV"一起上传**，跨机房缺考口径才完整（合计里会显示"其中其他机房报来 J 人"） |
| 数据备份 | 管理端「系统设置 → 下载数据备份」：不停止服务也能导出与正式库完全一致的完整数据（生成时加锁并做完整性校验，同一时刻只允许一个） |
| 抗重启 | 会话已持久化：**服务器意外重启/崩溃后，考生的登录状态与答题进度都能继续**，不必重新登录；万一仍需重登，页面会明确提示"刷新后重新登录，答案不会丢" |
| 时钟保护 | 后台检测系统时间跳变（改时间/自动校时）并写入日志与告警；答题截止时间始终以服务器时间为准 |
| 答题保存 | 每题答案带服务端版本号，杜绝"两台设备/时钟不准导致答案被静默回退"；保存失败会在题目下方**红色高亮**提示，交卷前若仍有未保存的答案会先拦一次 |
| 试卷库/名单库 | 管理端"题库管理"页有**试卷库**（A–E 五套卷的 CSV＋原始 Excel，共 10 份）、"考生管理"页有**名单库**（组委会正式名单）：点一下即可下载。**仅管理端可见**，未登录访问一律 401，且这些文件绝不进公开下载区 |
| 补录考生 | 开考后发现名单漏人/临时增补：先在「考生管理」补录，再到「监考看板」点【补进本场次】即可（不用重建场次） |
| 场次唯一性 | 只保留一个"进行中"的正式场次；系统检测到多个进行中场次时会在场次页给出醒目告警 |
| 匿名测评模式 | 场次可选"匿名测评模式"：**隐藏分数与排名**，交卷后只显示"提交成功"；考生端看不到每题分值与逐题得分，管理端排名页/监考看板也不再显示分数。适合把系统当问卷、满意度调查、民主测评工具用（注意：仍是"姓名+准考证号"登录，属**记名收集**，不是匿名投票） |
| 答案保密 | 考生交卷后只看到自己的答案与得分，**看不到参考答案**（防止提前交卷者把答案传给同学）；教师端"答卷复核"仍可查看参考答案 |

## 五、导入文件格式

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

- **导入是"追加"不是"覆盖"**：题库里已有题时再导入，会变成"旧题 + 新题"。
  正式竞赛要求 50 题（单选15/多选20/判断15、100 分），如果混进示例题就会变成 100 题。
- 正确顺序：**先清空题库 → 再导入正式试卷 → 核对统计 → 最后建场次**
  （题目在建场次那一刻被锁定；顺序反了要删场次重来）
- ⚠ **已经建好场次后不要再点【清空题库】**：场次在创建时就锁定了题目快照，
  清空题库会让该场次变成 0 题（考生拿到空卷、交 0 分并进排名）。
  系统已禁止这种操作：被任何场次（含尚未开考的场次）引用的题目都不能删改，
  清空题库会返回"请先删除该场次"。要换卷请**先删场次 → 清空题库 → 重新导入 → 重建场次**。
- 系统已加防呆：① 题库非空时导入会先弹确认；② 导入结果会显示"题库现有 N 题"并与
  正式竞赛规格比对（不一致会 ⚠ 提示）；③ 题干与已有题目重复时会提示"可能是重复导入"；
  ④ 题库管理页顶部常驻"✅/⚠ 与正式竞赛是否一致"的核对条。
- 出厂状态：部署包与完整包里的题库都是**空的**；`sample/会计经审A卷-示例题库50题.csv`
  只是**文件形式**留档（即正式 A 卷），需要时在管理页点"下载示例题库（A卷 50 题）"或手动导入。
- ⚠ **公网下载区（`downloads/`，任何人无需登录即可下载）绝不能放入 `试卷/`、`sample/`、`名单/` 里的任何文件**——试卷含全部答案，名单是考生个人信息。
  公网下载区只放程序部署包、导入模板、操作说明。
- 原「绝不能放入这份 A 卷示例题库」说明：
  它含全部答案，等同于公布正式试卷；`名单/` 里是考生姓名与准考证号，同样不能放公网。
  公网下载区只放程序部署包、导入模板、操作说明。
- 三种交付包（`打包交付包.py` 自动生成并自检）：**机房装机包（含 A 卷 + 231 人名单）** 只走内网；
  **部署包** 不含试卷、答案与名单，可放公网；**完整包** 含空库与全部文档，仅本地留档。

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

**列名/写法不用改也能导**（出题人给的 Excel 往往不按模板写，系统会自动识别）：

| 模板写法 | 也认这些写法 |
|---|---|
| `题型` | 类型、题目类型、试题类型；取值可写 `单选/单选题/单项选择`、`多选/多选题/多项选择`、`判断/判断题/是非题`、`填空/填空题/填充题` |
| `题干` | 题目、试题、问题、题目内容 |
| `选项A`（B~F 同理） | `选项 A`（中间空格）、小写 `选项a`、`A`、`选项1`、全角字母 |
| `答案` | **正确答案**、参考答案、标准答案、正确选项 |
| `分值` | 分数、每题分值、本题分值 |
| `解析` | 答案解析、试题解析（可选，不导也不影响） |

判断题的选项列随便写（`正确/错误`、`√/×`、`T/F` 都行），系统统一按"对/错"显示；
多选答案写 `AC`（字母顺序不限）；分值必须是 0~1000 的数字。

### 试题（模板格式）

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

- 题型：`单选` / `多选` / `判断` / `填空` 四种

### 填空题怎么写（`填空`）

填空题没有选项，题干里用 **`|`** 表示空的位置，答案里每个空用 **`|`** 分隔，
同一个空如果有多种可接受的写法，用 **`/`** 分隔：

| 题型 | 题干 | 答案 | 分值 |
|---|---|---|---|
| 填空 | 我国的货币是`|`。 | `人民币/元` | 10 |
| 填空 | 首都是`|`，最大城市是`|`。 | `北京|上海` | 20 |

- **判分规则（按空给分）**：全部空正确得满分；答对一部分得「分值 × 正确空数 ÷ 总空数」
  （保留 2 位小数）；一个空都没对得 0 分。上表第 2 题只答对第一个空 → 得 10 分。
- **容错**：自动忽略首尾与中间空格、全角/半角差异、英文大小写
  （` 人民币 `、`ＲＭＢ`、`rmb` 都能与对应写法匹配；但不会把"3.14"和"314"当成同一个）。
- **校验**：题干里 `|` 的个数必须与答案的段数一致，否则导入时会报错并指出行号
  （避免"题干 2 个空、答案只写了 1 段"这种错位）；填空题不要填"选项"列。
- **考生端**：每个空一个输入框，答完自动保存；中途只填了一部分也可以，按已对的空给分。
- 与正式竞赛的关系：正式竞赛规格是 单选15/多选20/判断15（不含填空），
  所以题库里一旦有填空题，管理端的核对条会提示"与正式竞赛不一致"，属于正常现象。
- 导出/再导入：填空题导出时"选项"列留空，列数与其它题型一致，可以往返导入。
- 单选答案填单个字母（B）；多选填字母串（ABD）；判断答案填 对/错（或 A/B，A=对 B=错）
- 判断题选项固定"对/错"，答案写 对/错、正确/错误、√/×、T/F、A/B 都认；分值必填正数
- ★ 选项必须**从 A 开始连续填写**（尾部留空可以，中间不能空）：中间空一列会让答案字母错位，系统会直接拒绝该行并提示，不会静默导入
- 管理端可下载标准模板与示例题库（`sample/会计经审A卷-示例题库50题.csv`＝正式 A 卷，仅管理端可下载，学生端不可访问）

### 随包默认名单（考生管理 → 【导入随包名单】）

程序目录 `名单/` 下的第一个 xlsx/csv 即为"随包默认名单"（现为组委会 231 人正式名单）。
考生管理页会显示【导入随包名单（N 人）】按钮，一键导入；未附名单的部署包不显示该按钮，
强行调用接口会得到明确提示。更新名单：把新文件放进 `名单/` 覆盖即可（文件名随意）。

### 考生名单

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

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

## 六、多机房考试与成绩合并（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 |
| 国内实例 i-bp111juvyrlvyj2cbzgp | https://ks.slsfzy.com/download | https://ks.slsfzy.com/admin |

> 两个站点的管理员口令**各不相同**，且**不写在任何公开发布的文件里**——由技术负责人单独通知。
> （《公网辅助站使用说明.txt》只放在服务器程序目录，绝不能放进公网下载区。）
> 两站的考生端都已关闭（只用于题库管理与资料分发），正式考试仍在机房内网各自搭服务器。

- 题库上传：管理端 →「题库管理」→ 导入试题（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/              示例题库＝正式 A 卷 50 题（含答案，仅管理端可下载，禁止放公网）
名单/                随包默认考生名单（231 人，管理端可一键导入；含个人信息，禁止放公网）
试卷/                试卷库：A–E 五套正式卷（CSV + 原始 Excel，含答案，仅管理端可下载）
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 或改用独立交换机端口隔离。
- **防作弊为轻量级**：切屏计数、禁右键/复制均为前端手段，不承诺对抗刻意作弊。
- **冒名登录**：仅凭"姓名+准考证号"登录，知道他人考号即可冒名；重要考试建议现场核对证件。
- **多端登录**：同一账号可在多台电脑同时登录答题（后保存的覆盖先保存的），监考时留意异常。
