commit d6106baf3f43b07f2267a096dadacad4d2f7fa91 Author: nxxy335 Date: Tue Sep 8 12:28:22 2026 +0800 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..8d8fe9e --- /dev/null +++ b/README.md @@ -0,0 +1,116 @@ +# NY 问卷考试系统数据平台 + +基于 **PHP 8 + 卷王问卷系统(SurveyKing)社区版开放 API** 的实时数据统计平台。 +选择某个问卷 / 考试后,自动拉取答卷 → 用「姓名」关联学号名单 → 按 +**学号、姓名、成绩、提交时间、考试时长** 依次排列展示,并支持定时自动刷新。 + +## 功能 + +| 功能 | 说明 | +| --- | --- | +| 问卷/考试切换 | 下拉选择,实时显示该问卷的答卷数据 | +| 学号自动匹配 | 用答卷中的「姓名」题在学号名单中查找对应学号(自动识别姓名题,也可手动指定) | +| 实时刷新 | 5 秒 / 10 秒 / 15 秒 / 30 秒 / 60 秒 / 2 分钟可选,数据变化的行会高亮闪烁;**每次刷新后新增的提交以绿色底纹标出** | +| 统计卡片 | 名单总人数、已提交、缺考、提交率、平均分、**合格率**(≥60% 满分)、最高分、最低分、平均用时;**选择班级后,全部卡片只统计该班级** | +| 最高/最低分获得者 | 最高分、最低分卡片下方显示是谁(👑 / 🔻 + 姓名);可在「设置」中关闭 | +| 缺考名单 | 名单中有、但未提交的人 | +| 未匹配答卷 | 提交了但姓名不在名单中的答卷,方便排查 | +| 名单导入 | 上传 `.xlsx` / `.csv`,自动识别「学号」「姓名」「班级」列(班级可选);支持覆盖 / 追加、手动增删改 | +| 导出 | 成绩明细 CSV(学号/姓名/班级/成绩/提交时间/考试时长)、缺考名单 CSV(学号/姓名/班级) | +| 排序 / 班级 | 点击表头排序,**成绩明细默认按提交时间降序**;支持学号/姓名/班级/成绩/提交时间/时长排序;按班级下拉筛选 | +| 全屏 / 自适应 | 右上角「全屏」按钮进入全屏(布局自动铺满、表格更高);页面适配手机 / 平板 / 桌面三端 | + +## 环境要求 + +- PHP ≥ 8.0(需启用 `curl`、`json`、`mbstring`、`openssl`(可选,用于 RSA 加密密码);`zip` 可选,无 zip 扩展时会用内置解析器读 xlsx) +- 无需数据库、无需 Composer 依赖,数据以 JSON 存放在 `data/` + +## 部署 + +### 方式一:PHP 内置服务器(最快体验) + +在本目录执行: + +```bash +php -S 0.0.0.0:8080 +``` + +浏览器打开 。 + +Windows 也可双击 `启动平台.bat`。 + +### 方式二:放到 PHP 站点目录 + +把整个 `ny-exam-platform` 目录复制到 Apache / Nginx + PHP-FPM 的站点目录下, +确保进程对 `data/` 目录有写权限即可。 + +## 首次配置 + +打开页面 → 右上角 **设置**: + +| 配置项 | 示例 | 说明 | +| --- | --- | --- | +| 卷王系统地址 | `http://192.168.1.10:1991` | 卷王后台地址,结尾不要带 `/` | +| 接口前缀 | `/api` | 社区版默认 `/api`;企业版可填 `/admin-api` | +| 登录账号 | `admin` | 卷王后台管理员账号 | +| 登录密码 | `123456` | 卷王后台密码 | +| 姓名题关键词 | `姓名,名字,学生姓名` | 用于自动识别哪道题填的是姓名 | +| 默认刷新间隔 | `15` | 秒 | + +填完点 **测试连接**,显示「连接成功」后点 **保存**。 + +> 登录流程(社区版 v1.13):`GET /api/system` 取 RSA 公钥 → 公钥加密密码 → +> `POST /api/public/login` 换取 JWT。 +> **注意**:v1.13 服务端的 `JwtTokenFilter` 只从 Cookie `sk-token` 读取令牌(**不读 `Authorization` 头**), +> 所以登录后程序会把 `Set-Cookie` 里的 `sk-token` 原样带在后续每个请求的 `Cookie` 头里(同时也带 `Authorization` 头以兼容旧版)。 +> 程序已内置该流程与令牌缓存,并向下兼容 `/system/auth/login`、`/admin-api/oauth2/token` 两种登录方式。 + +**关于 401 "Full authentication is required to access this resource"** +若你用自己写的客户端对接卷王社区版 v1.13,即使登录成功、拿到了 JWT,调用 `/project/list` 等接口仍可能返回 401。 +原因是 v1.13 服务端只认 Cookie 里的 `sk-token`,不认 `Authorization` 头。务必在登录响应里取 `Set-Cookie: sk-token=...`, +并在后续每个请求带上 `Cookie: sk-token=`。本平台已处理此细节。 + +## 学号名单 + +- **平台启动时不预设任何名单**,请通过右上角 **名单管理** 上传你自己的名单(`.xlsx` / `.csv`)。 +- 名单文件可包含「学号」「姓名」两列,**「班级」为可选列**;含班级时,成绩明细会显示班级列并支持按班级筛选(一份考试涉及多个班级时很实用)。 +- 上传方式:名单管理 → 点击或拖拽文件 → 选择覆盖 / 追加 → **保存名单**;也可手动增 / 删 / 改。 +- 名单数据保存在 `data/roster.json`。 + +## 目录结构 + +``` +ny-exam-platform/ +├─ index.php 主页面 +├─ api.php 后端接口(代理卷王 API) +├─ bootstrap.php 配置 / 公共函数 / 自动加载 +├─ lib/ +│ ├─ SurveyKingClient.php 卷王 API 客户端(登录、令牌缓存、项目、答卷) +│ ├─ DataService.php 数据组装(姓名→学号匹配、统计、排序) +│ ├─ Roster.php 学号名单管理(xlsx/csv 导入与持久化) +│ └─ XlsxReader.php 零依赖 XLSX 读取器 +├─ assets/ 前端样式与脚本 +├─ data/ 配置、名单、令牌缓存(需可写) +└─ tools/ 开发辅助(PHP 语法校验脚本) +``` + +## 常见问题 + +**1. 页面提示"无法连接卷王系统"** +检查:地址端口是否正确、服务器防火墙是否放行、接口前缀是否为 `/api`、账号密码是否正确。 +可直接在服务器本机执行 `curl http://127.0.0.1:1991/api/system` 验证。 + +**2. 读到了答卷但学号为空** +说明答卷里的姓名与名单不一致。处理: +- 在「姓名字段」下拉里手动指定正确的题目; +- 或到「设置」里补充姓名题关键词; +- 未匹配的答卷会显示在「未匹配答卷」面板,可据此核对姓名是否写错(如多了空格)。 + +**3. 成绩列全是 `-`** +说明该问卷不是考试模式或没有开启自动评分,卷王未返回 `examScore`。 + +**4. 考试时长显示 `-`** +答卷的 `metaInfo.answerInfo` 中没有开始/结束时间(例如是后台手动录入的答卷)。 + +**5. 想让同一学号只保留最新提交** +设置里勾选「同一学号只保留最新一份答卷」(默认开启);取消勾选则保留全部提交记录。