Files
ClassHelper/docs/faq.md
T
LoveChengke 9d5ac7adf9 feat(shared,server,web,client,plugin)!: 角色与权限重构 + 学期周次 + 课表方向反转(1.2.0)
学生、任课关系、周次口径三处长期靠约定维持的事情,改为由数据模型保证。

学生不是账号
- 拆出独立 Student 表,没有 passwordHash / role / 任何登录字段
- 「学生不能登录」由表结构保证,不再靠「登录前判 role 再 403」的代码分支
- 三张个人数据表外键 userId → studentId;删掉 Enrollment 与 ClassTeacher
- 学生一律称「学号」、教师一律称「工号」,「学生账号」这个概念消失

任课关系唯一来源 = Course(班级 + 科目 + 教师)
- 班主任 = Class.teacherId,科任 = Course.teacherId,同一人两处指向同一账号、不重复建号
- 作业与成绩按科目再收一道:挂科目只由该科任课老师改,没挂科目归班主任 / 管理员
- 新增「任课教师分配」与「班级教师批量导入」(带「使用工号匹配」开关)

成绩与名单
- 成绩等级:百分制 / 等级制 A·B·C·D / 自定义,支持单个与批量改等级
- 按学号查成绩明细(教师端 + 班级端 + 设备令牌),受按班开关控制
- 调班 / 转出(单个与批量)+ 可查历史;学号不变、历史作业成绩留原归属
- 毕业归档页(按年度记录毕业班级 / 毕业生 / 转出学生 / 该届通知与作业)
- 学年升级(未毕业不归档、数据沿用);班级称呼改为「2026级1班」

ClassHelper 班级端在线状态
- Web 端显示 班级 / 设备名 / 设备号 / 在线离线 / 最后在线 / 最后心跳
- lastHeartbeatAt 驱动 60 秒在线窗口,与只表示「带状态上报」的 lastSeenAt 分开

学期周次
- 新增 TermWeek(classId 空串 = 全校默认),管理员可用日期范围选择器逐周配置
- 一键按开学日期生成整学期;联网拉取调休建议(只给建议、不改数据,无外网失败属正常)
- 改周次后随课表下发给教室的 ClassHelper 班级端

课表方向反转
- 主方向改为「服务端 → 教室」自动下发;教室不再自动回传
- 取教室课表改为手动动作(点击前弹警告),插件按待办标记在下一次心跳补报

改名
- 班级小助手 → ClassHelper:界面、窗口标题、托盘、灵动岛、EXE、安装包、
  安装目录、systemd 描述、插件清单与设置页、官网、文档站、README

BREAKING CHANGE: 产品名与 EXE 名变更(班级小助手.exe → ClassHelper.exe),
安装目录随之改变,不支持覆盖安装,需先卸载旧版。
服务端首次启动会自动应用 6 个数据库迁移(学生行按 id 原样搬迁,历史数据不丢),
升级前请先备份。
2026-10-06 19:41:18 +08:00

156 lines
6.8 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.
---
title: 常见问题
description: 装不上、连不上、改了不生效——最常被问到的那些问题。
---
# 常见问题
## 安装与启动
### 客户端装不上 / 便捷版双击没反应 / 应用一闪就没了
**现象**:安装程序报「拒绝访问」,便捷版双击毫无反应,装上了也启动即退且不写日志
(退出码 `0x80000003`)。
**原因**:交付物被打了 **Low 完整性标签**。带 Low 标签的 exe 会被 Windows 降级运行:
写不进 `%LOCALAPPDATA%` / `%TEMP%`;即使装上,Chromium 的子进程(完整性更低)也读不到这些文件而秒崩。
**处置**:从 [Releases](https://github.com/LoveChengke/classhelper/releases) 下载的官方包不受影响
(打包脚本收尾会自动修正标签)。自己构建时如果碰到,用:
```cmd
icacls <产物目录> /setintegritylevel Medium /T /C
```
判据是 `icacls <exe> | findstr Mandatory` 里出现 `Low`。
另外**别把安装测试装进仓库目录里** —— 在那里又会继承 Low。
### 双击客户端"点了没反应"
**关窗只是隐藏到托盘,进程还在。** 再双击 EXE 会被单实例锁秒退(看起来像没反应),
安装包也会因为"应用正在运行"装不上。先**从托盘右键退出**。
### 安装包装不上,说应用正在运行
同上。托盘 → 退出 ClassHelper。
## 连接与登录
### 后端明明在跑,`Invoke-WebRequest` 却返回别人的 404
**系统代理拦住了 `127.0.0.1`**。自测请加 `-NoProxy`(`curl.exe` 用 `--noproxy '*'`)。
项目内的 Node 脚本直连,不受影响。
### 客户端连不上服务器
1. 服务器地址要填**局域网 IP**(`http://192.168.1.10:4000`),不要写 `localhost`(那是客户端自己);
2. 服务器防火墙放行 **4000**;
3. 服务器上如果开了系统代理,内网地址可能被代理接管 —— 浏览器与客户端**不会**自动绕过
(只有 ClassIsland 插件对本地 / 内网做了强制直连);
4. 在服务器本机 `curl.exe --noproxy '*' http://127.0.0.1:4000/healthz` 是不是 200?
### 页面能打开,但接口全 401
令牌过期,或者 `.env` 里的 `JWT_SECRET` 被换过(换过之后所有人的令牌都失效)。重新登录即可。
### 提示「无法连接 GitHub」/ 检查更新查不到
**这是设计内的结果**,不是错误。机房与教室机器常常只有内网,请求会超时;
界面按"暂时查不到更新"呈现。失败结果同样进缓存,不会每点一次都白等一个超时。
### 反向代理后面所有请求都被限流
反向代理没设 `TRUST_PROXY=1`,导致所有请求都被算作代理那一个 IP。
## 功能行为
### 上课时段发的通知学生看不到
**这是设计行为。** 上课时段普通通知只进队列、不打断课堂,**下课自动补弹**。
紧急通知与叫人则立刻弹。规则见[通知与提醒](app/notifications.md)。
### 老师说发了通知,教室机器上什么都没弹
按顺序排查:
1. 客户端顶栏的实时通道是不是"已连接"?
2. 现在是上课时段吗?(同上,是设计行为)
3. 教室客户端的「设置 → 提醒」是不是设成了"只在 ClassIsland 上弹"?那样客户端只进通知中心。
4. 反向代理放行 `/socket.io/` 的 WebSocket 升级了吗?
### 屏幕上出现了第二个灵动岛,点它反应不对
那是**自动化验证实例**的岛 —— `pnpm verify:desktop` / `verify:packaged` 会真的在屏幕上放一个,
而且它归脚本控制,会自己展开 / 收起 / 消失。验证实例的岛是**洋红主题色**,一眼可辨。
### 灵动岛上的文字往右跳一下再缩回
那是早期的布局问题(胶囊内容跟着卡片重排),已经修掉了。如果你的版本还有,
说明用的是旧产物 —— 参考[更新与升级](management/upgrade.md)。
### 灵动岛调"左右边距"没反应
**左右边距只在「左 / 右停靠」时生效。** 默认是「顶部居中」,水平锚点就是屏幕中线,
这时调它不会有任何变化 —— 设置页会把那个滑块置灰并写明原因。
### 触摸屏上点不开灵动岛
触摸屏(希沃白板等)会自动走「触摸模式」,正常情况不用手动开。
如果确实点不开,到「设置 → 关于」看一眼诊断信息,并把客户端版本反馈出来。
### 教室机器上刚录的作业又要弹一次?
**本机录入的作业不会上岛**(自己通知自己没意义)。如果弹了,说明这条不是这台机器录的。
### 学生登录不了
**学生没有个人账号。** ClassHelper 班级端统一用**班级码 + 班级密码**登录(见[装 ClassHelper 班级端](get-started/client.md))。
用学生用户名去登录一定会失败,这是设计。
### 客户端里找不到"修改密码"
**是刻意移除的。** 防止教室机器上误改班级密码后,别的教室机器被锁在门外。
班级密码由管理员在 Web 端「班级管理」维护;教师 / 管理员本人密码在 Web 端顶栏头像菜单里改。
## 开发与运维
### `pnpm db:seed` 报 `Cannot find module '.../@classhelper/shared/dist/index.js'`
`packages/shared` 还没构建(它产出 `dist`,三端与 seed 都依赖)。先 `pnpm build:shared`。
### 根目录跑 `pnpm db:deploy` 说不存在
根 `package.json` 没有这个脚本。正确写法:
```bash
pnpm --filter @classhelper/server db:deploy
```
### 后端改了代码不生效
`tsx src/index.ts` **不热载**。用 `pnpm dev:server`(watch),或重启服务端。
**切换数据库之后必须重启**才会连上新库。
### 上传表格报「服务器内部错误:request entity too large」
表格导入的文件上限是 **8MB**(请求体 12MB),超限应返回 **413 `IMPORT_TOO_LARGE`** 与中文提示。
如果你看到的是英文兜底错误,说明这个异常没被映射 —— 那是 bug,不是你的文件太大。
### 切了 MySQL 之后重启又连回旧库
服务端安装形态里,安装目录的 `.env` **必须是指向 `/etc/classhelper/config.env` 的软链**。
两处不是同一个文件时,一键切换会"看起来成功、重启后又连回旧库"。
Linux 上跑 `sudo classhelper doctor` 有专门一条断言盯着这个软链。
### SQLite 报 `database is locked`
同一个数据库文件只允许一个服务实例。确认没有重复启动;需要并发就换 MySQL。
## 还没解决?
- 开发环境的坑(命令、代理与 TLS、完整性标签、ClassIsland 路径与日志编码……)
都记在仓库的 [`AGENTS.md`](https://github.com/LoveChengke/classhelper/blob/master/AGENTS.md) 里;
- 功能行为的权威说明在[完整参考](reference.md);
- 都不是的话,去 [Issues](https://github.com/LoveChengke/classhelper/issues) 提一个,
附上版本号(Web 端顶栏 / 客户端「设置 → 关于」里都有)和日志。