选择题训练系统 v2.0 服务器与代码维护说明(第2版)

面向 hofor881.cn 当前部署环境,用于后续理解、维护和逐步扩展系统。

第2版维护补充

一、当前服务器与系统信息

项目当前值
云服务商腾讯云
实例名称hofor
系统Ubuntu Server 24.04 LTS 64bit
公网 IP124.223.201.198
SSH 用户ubuntu
域名https://hofor881.cn
www 域名https://www.hofor881.cn
项目目录/var/www/quiz
Node 监听127.0.0.1:3000
公网访问Nginx 通过 443 HTTPS 反向代理到 Node
数据库PostgreSQL,数据库名 quiz
Node 守护PM2,应用名 quiz

二、整体架构

当前系统采用经典的单机部署结构:

用户浏览器
   |
   | HTTPS 443
   v
Nginx
   |
   | 反向代理到 127.0.0.1:3000
   v
Node.js / Express
   |
   | SQL
   v
PostgreSQL

外部用户只访问:

Node 程序只监听本机:

当前部署方式不需要开放公网 3000 端口。所有浏览器访问都通过 HTTPS 443 进入。

三、主要页面入口

页面地址用途
教师登录 /login.html 教师输入账号密码登录。
教师端 /teacher.html 发布任务、复制学生链接、查看提交记录。
学生端 /student.html?id=任务ID 学生填写班级、姓名、学号并答题。
使用说明 /help.html 给教师和学生看的操作说明。
维护说明 /admin-guide.html 服务器和代码维护说明。

四、项目目录结构

项目主目录:

cd /var/www/quiz

主要文件和目录:

路径作用
server.jsNode / Express 主程序,提供 API、静态页面访问、登录、发布、提交等功能。
.env环境变量配置文件,包含数据库连接、教师账号、JWT 密钥等。
public/login.html教师登录页。
public/teacher.html教师端页面。
public/student.html学生答题页面。
public/help.html普通使用说明。
public/admin-guide.html本维护说明文档。
db/init.sql数据库初始化 SQL。
db/pool.jsPostgreSQL 连接池配置。
utils/projectParser.js解析 v1.3.3 教师工程 JSON。
utils/grading.js判分相关工具函数。
package.jsonNode 依赖和项目脚本说明。

五、环境变量 .env

查看环境变量配置:

cd /var/www/quiz
cat .env

常见配置项:

变量名用途
PORTNode 服务端口,当前通常为 3000。
HOSTNode 监听地址,建议为 127.0.0.1。
DATABASE_URLPostgreSQL 数据库连接字符串。
TEACHER_USERNAME教师用户名。
TEACHER_PASSWORD教师密码。
JWT_SECRETJWT 登录令牌密钥。
.env 中包含密码和密钥。维护时可以在服务器上查看,不建议截图公开发送。

六、PM2 管理 Node 服务

1. 查看运行状态

pm2 status

正常情况下可以看到:

quiz    online

2. 重启服务

cd /var/www/quiz
pm2 restart quiz --update-env

3. 查看日志

pm2 logs quiz --nostream --lines 50

4. 保存 PM2 进程列表

pm2 save

5. 开机自启状态

systemctl status pm2-ubuntu
日常修改 server.js 或 .env 后,通常执行 pm2 restart quiz --update-env 即可。

七、Nginx 与 HTTPS

1. 当前 Nginx 站点配置文件

/etc/nginx/sites-available/hofor881.cn

2. 查看站点启用情况

ls -l /etc/nginx/sites-enabled

3. 查看当前 Nginx 配置摘要

sudo nginx -T | grep -nE "server_name|listen 443|listen 80|proxy_pass|ssl_certificate"

4. 测试 Nginx 配置

sudo nginx -t

5. 重载 Nginx

sudo systemctl reload nginx

6. 当前核心反向代理逻辑

location / {
    proxy_pass http://127.0.0.1:3000;
}
Nginx 对外提供 HTTPS 服务,Node 不直接暴露到公网。

八、PostgreSQL 数据库

1. 数据库信息

项目
数据库名quiz
业务用户quiz_user
主要业务表assignmentssubmissions

2. 进入数据库

sudo -u postgres psql -d quiz

3. 查看表列表

\dt

4. 查看 assignments 表结构

\d assignments

4-1. 旧库补充学生自删除字段

如果是从旧版本升级,需确认 assignments 表已有学生自删除字段:

ALTER TABLE assignments ADD COLUMN IF NOT EXISTS allow_student_delete boolean DEFAULT false;

5. 查看 submissions 表结构

\d submissions

6. 查看任务列表

sudo -u postgres psql -d quiz -c "SELECT id,title,mode,access_code,created_at FROM assignments ORDER BY id DESC;"

7. 查看提交记录

sudo -u postgres psql -d quiz -c "SELECT id,assignment_id,class_name,name,student_id,score,created_at FROM submissions ORDER BY id DESC LIMIT 20;"

九、核心数据表说明

1. assignments:任务表

每发布一次任务,就会在 assignments 表中生成一条记录。

字段说明
id任务 ID,学生链接中使用。
title任务标题或试卷名称。
mode任务模式,practice 为练习,test 为测试。
access_code访问码,可用于扩展短链接或二维码。
settings_json任务设置,包含随机题目/选项、分数段 score_ranges 等设置。
questions_json题目数据。
project_json原始教师工程 JSON;分数段也会同步写入 project_json.settings.score_ranges,便于导出和迁移。
is_active任务是否启用。
allow_repeat_submit是否允许重复提交。
max_submit_count最多提交次数;为空表示不限次数。
allow_student_delete是否允许学生删除本人提交记录。
created_at创建时间。

2. submissions:提交表

学生每提交一次答案,就会在 submissions 表中生成一条记录。

字段说明
assignment_id对应任务 ID。
class_name学生填写的班级。
name学生填写的姓名。
student_id学生填写的学号。
answers_json学生答案。
score得分。
result_json判分详情。
created_at提交时间。

十、主要 API 流程

1. 教师登录

POST /api/login

教师输入用户名和密码,后端验证后返回登录结果和 token。

2. 教师发布任务

POST /api/assignments

教师上传 v1.3.3 教师工程 JSON,后端解析并写入 assignments 表。发布参数包括任务模式、随机设置、是否允许重复提交、最多提交次数和答题码名单。

3. 教师获取任务列表

GET /api/assignments

教师端显示已经发布的任务。

4. 学生获取任务详情

GET /api/assignments/:id

学生打开链接后,根据任务 ID 加载题目。

5. 学生提交答案

POST /api/assignments/:id/submissions
POST /api/submissions
POST /api/student/submit

学生提交班级、姓名、学号和答案,后端先按答题码或“班级+姓名+学号”检查提交次数上限,再判分并写入 submissions 表。

6. 教师查看提交记录

GET /api/assignments/:id/submissions

教师端点击“记录”,显示该任务的学生提交情况,并可查看单个学生作答详情。

6-1. 教师设置分数段

教师端支持三种分数段设置入口:发布任务时设置、任务列表单个任务“分数段”按钮、任务列表右上角“批量分数段”按钮。

7. 教师切换学生自删除权限

PATCH /api/assignments/:id/student-delete

教师端任务列表中的“可自删 / 禁自删”按钮会调用此接口,写入 assignments.allow_student_delete

8. 学生查看和删除本人记录

GET /api/assignments/:id/my-submissions
DELETE /api/assignments/:id/my-submissions/:submissionId

学生输入班级、姓名、学号后,只能查看和删除本人在当前任务下的提交记录;删除接口还会检查教师是否已允许自删除。

十一、主要代码文件说明

1. server.js

系统后端主文件,包含:

2. public/login.html

教师登录页。登录成功后保存 token,并跳转到教师端。

3. public/teacher.html

教师管理页。主要功能:

4. public/student.html

学生答题页。主要功能:

5. utils/projectParser.js

用于解析 v1.3.3 教师工程 JSON,把原始工程数据转换为系统发布任务所需的数据。

6. utils/grading.js

用于答案比对和计算成绩。

十二、日常维护常用命令

1. 进入项目目录

cd /var/www/quiz

2. 查看 Node 服务

pm2 status

3. 重启 Node 服务

pm2 restart quiz --update-env

4. 查看最近日志

pm2 logs quiz --nostream --lines 50

5. 查看 3000 监听

ss -lntp | grep 3000

6. 查看健康接口

curl -s https://hofor881.cn/api/health

7. 查看页面状态

curl -I https://hofor881.cn/login.html
curl -I https://hofor881.cn/teacher.html
curl -I https://hofor881.cn/student.html
curl -I https://hofor881.cn/help.html

8. 查看 Nginx 状态

systemctl status nginx

9. 重载 Nginx

sudo nginx -t
sudo systemctl reload nginx

十三、修改代码的推荐流程

  1. 进入项目目录:
cd /var/www/quiz
  1. 修改前先备份目标文件:
cp server.js server.js.bak.$(date +%Y%m%d%H%M%S)
cp public/teacher.html public/teacher.html.bak.$(date +%Y%m%d%H%M%S)
cp public/student.html public/student.html.bak.$(date +%Y%m%d%H%M%S)
  1. 修改文件。
  2. 如果修改的是前端 HTML,一般刷新页面即可。
  3. 如果修改的是 server.js 或 .env,需要重启 PM2:
pm2 restart quiz --update-env
  1. 保存 PM2 状态:
pm2 save

十四、数据库备份与恢复

1. 创建备份目录

mkdir -p /var/www/quiz/backups

2. 备份数据库

sudo -u postgres pg_dump quiz > /var/www/quiz/backups/quiz_$(date +%Y%m%d_%H%M%S).sql

3. 查看备份文件

ls -lh /var/www/quiz/backups

4. 恢复数据库的基本形式

sudo -u postgres psql -d quiz < /var/www/quiz/backups/备份文件名.sql
做较大修改前,建议同时备份数据库和代码文件。

十五、代码备份建议

1. 备份整个项目目录

sudo tar -czf /var/www/quiz_backup_$(date +%Y%m%d_%H%M%S).tar.gz /var/www/quiz

2. 查看备份包

ls -lh /var/www | grep quiz_backup

3. 单文件修改前备份

cp public/student.html public/student.html.bak.$(date +%Y%m%d%H%M%S)

十六、一次完整业务流程对应的数据变化

1. 教师发布任务

教师上传 JSON 并点击发布后:

2. 学生打开链接

学生访问:

/student.html?id=任务ID

学生端调用:

GET /api/assignments/:id

3. 学生提交答案

学生点击提交后:

4. 教师查看记录

教师点击“记录”后:

GET /api/assignments/:id/submissions

教师端显示该任务所有提交记录。教师可查看单个学生作答详情,也可删除提交记录;学生自删除权限由任务列表中的“可自删 / 禁自删”按钮控制。

十七、练习模式与测试模式

模式mode 值学生提交后
练习模式practice显示成绩、答案、解析。
测试模式test只显示成绩。

模式是在教师发布任务时确定的,并保存在 assignments 表里。随机题目/选项来自 settings_json;重复提交策略由 allow_repeat_submit 与 max_submit_count 共同决定;学生是否可删除本人记录由 allow_student_delete 决定。

十八、后期改进设想

十九、更新教师账号密码

教师账号密码保存在:

/var/www/quiz/.env

修改方式:

cd /var/www/quiz
nano .env

修改类似以下两项:

TEACHER_USERNAME=新的用户名
TEACHER_PASSWORD=新的密码

修改后重启:

pm2 restart quiz --update-env
修改密码后,需要使用新密码登录教师端。

十九、系统扩展方向

1. 多教师账号

未来可以把教师账号从 .env 移到 teachers 表中,每个教师拥有自己的任务列表和提交记录。

2. 企业版部署

未来可以为不同学校或机构增加 tenant_id,实现多机构隔离。

3. 二维码页面

可以给每个任务增加二维码展示页面,方便课堂投屏扫码。

4. 成绩导出

可以在教师端增加导出 CSV 或 Excel 的按钮。

5. 任务管理

可以增加任务停用、删除、重命名、复制任务等功能。

二十一、备案信息添加与维护

当前网站已添加 ICP 备案和公安备案底部信息。为了便于维护,备案信息使用公共脚本统一生成。

1. 当前备案信息

2. 涉及文件

3. 关键注意事项

给 HTML 页面插入 <script src="/beian-footer.js"></script> 时,必须插入最后一个 </body> 前面,不要替换第一个 </body>

原因:教师端和学生端中存在 w.document.write(...</body></html>) 弹窗字符串,错误插入会破坏 JavaScript,导致页面报 Invalid or unexpected token

4. 检查命令

cd /var/www/quiz

ls -lh public/beian.png public/beian-footer.js
file public/beian.png

grep -n "beian-footer.js" public/login.html public/teacher.html public/student.html public/help.html public/admin-guide.html
grep -n "闽ICP备2026023379号\|闽公网安备35012102550517号" public/beian-footer.js

curl -I http://127.0.0.1:3000/beian.png
curl -s "http://127.0.0.1:3000/teacher.html?v=beian-check" | tail -20
curl -s "http://127.0.0.1:3000/student.html?id=66&v=beian-check" | tail -20

5. 离线保留版

已生成独立离线说明文件:

二十二、查看导入后在线教师工程大小

在线版教师工程主要保存在 PostgreSQL 的 assignments.project_json 字段中。可用以下 SQL 查看在线压缩后的工程大小,并与本地离线版工程 JSON 比较。

1. 查看最近任务工程大小

cd /var/www/quiz

sudo -u postgres psql -d quiz -c "
SELECT
  id,
  title,
  created_at,
  pg_size_pretty(pg_column_size(project_json)::bigint) AS db_size,
  pg_size_pretty(octet_length(project_json::text)::bigint) AS text_size,
  ((length(project_json::text) - length(replace(project_json::text, 'data:image', ''))) / length('data:image')) AS image_count
FROM assignments
ORDER BY id DESC
LIMIT 30;
"

2. 按工程大小从大到小排序

sudo -u postgres psql -d quiz -c "
SELECT
  id,
  title,
  created_at,
  pg_size_pretty(pg_column_size(project_json)::bigint) AS db_size,
  pg_size_pretty(octet_length(project_json::text)::bigint) AS text_size
FROM assignments
ORDER BY pg_column_size(project_json) DESC
LIMIT 20;
"

3. 查看所有工程总大小

sudo -u postgres psql -d quiz -c "
SELECT
  COUNT(*) AS assignment_count,
  pg_size_pretty(SUM(pg_column_size(project_json))::bigint) AS total_project_json_db_size,
  pg_size_pretty(SUM(octet_length(project_json::text))::bigint) AS total_project_json_text_size,
  pg_size_pretty(SUM(pg_column_size(questions_json))::bigint) AS total_questions_json_db_size
FROM assignments;
"

4. 导出某个在线工程 JSON 与本地比较

sudo -u postgres psql -d quiz -Atc "SELECT project_json::text FROM assignments WHERE id=66;" > /tmp/assignment_66_project.json

ls -lh /tmp/assignment_66_project.json
wc -c /tmp/assignment_66_project.json

gzip -c /tmp/assignment_66_project.json > /tmp/assignment_66_project.json.gz
ls -lh /tmp/assignment_66_project.json /tmp/assignment_66_project.json.gz

5. 查看 API 实际返回大小

curl -s -o /tmp/assignment_66_api.json -w "download_size_bytes=%{size_download}\n" "http://127.0.0.1:3000/api/assignments/66"

ls -lh /tmp/assignment_66_api.json
wc -c /tmp/assignment_66_api.json

6. 离线保留版

已生成独立离线说明文件:

二十三、本轮教师端任务列表与弹窗模式维护记录

1. 本轮主要提交

a7a6dc9 feat: show submission records below assignment row
721896d feat: show answer code management below assignment row
d6d6326 feat: show QR code below assignment row
98a0714 feat: add row detail display mode option
3e546ea feat: support question stats in submission popup
cbc6473 feat: show submission records in popup mode
db2bc35 feat: show answer code management in popup mode
eadb4c6 fix: allow blank student id in answer code validation
39ccb0f feat: show assignment QR code in popup mode
2755728 feat: add teacher detail display mode toggle
22b533b feat: add assignment export options
3a165ac feat: show display sequence number in assignment list

2. 教师端任务列表显示编号

3. 任务导出功能

4. 详情显示模式

5. 弹窗模式维护注意事项

5-1. 任务下方模式维护注意事项

6. 答题码空学号规则

答题码名单现在支持学号为空的格式:

班级,姓名,学号,答题码
班级,姓名,,答题码

7. 分数段设置维护记录

8. 相关检查命令

cd /var/www/quiz

git log --oneline -10
git status --short
pm2 status

sudo -u postgres psql -d quiz -c "SELECT id, assignment_id, class_name, name, student_id, code, created_at FROM assignment_codes ORDER BY id DESC LIMIT 10;"

二十四、快速入口

教师登录 教师端 操作说明