Files
ClassHelper/docs/app/classes.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

99 lines
5.4 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: 班级账号、学生名单、班主任与各科任课老师,以及"谁能看什么、谁能改什么"。
---
# 班级、学生与教师
## 班级账号:ClassHelper 班级端的身份
学生**没有个人账号**。一台教室机器用一个**班级账号**登录:
```
班级码(例如 G203) + 班级密码 → 这台机器代表"高二(3)班"
```
登录之后,这台机器上的「已读 / 完成 / 未交」都是**代全班**操作的;它看到的是本班的数据。
班级码是管理员在「班级管理」里设的(新建时自动生成,可以改成好记的)。
校验时会统一按大写比对(码存大写)。
> 班级密码在新建班级时由 `.env` 的 `DEFAULT_CLASS_PASSWORD` 决定初始值,
> 之后由管理员在「班级管理 → 修改班级账号」维护。
>
> **客户端没有改密码入口**,这是刻意移除的:教室机器上误改班级密码会让别的机器登录不了。
> 教师 / 管理员本人改密码在 Web 端顶栏头像菜单里。
## 学生
**学生管理**(仅管理员)→ 新建 / 导入名单。
学生记录**只是名单**:成绩、未交名单、叫人、已读记录都按名单记录,所以名单不全这几项就不准。
| 项目 | 说明 |
| -------- | ------------------------------------------------------------------------------------ |
| 用户名 | `^[A-Za-z0-9_.-]{3,32}$`;单个新建时自动生成 |
| 密码 | **没有密码概念**。学生的 `passwordHash` 是空串占位,不能登录,也没有任何重置密码接口 |
| 所属班级 | 一个学生属于一个主班级 |
> 学生**不是账号**(`Student` 表里没有密码、没有角色),拿学号去登录只会得到 401 ——
> 否则"密码错(401)"和"密码对但学生账号已停用(403)"的差异会把学生账号密码变成可离线验证的预言机。
## 教师
| 能力 | 在哪 | 谁能做 |
| -------------------- | ------------------------------------------------ | ------------- |
| 新建 / 编辑 / 删除 | 「教师管理」 | **仅管理员** |
| 导入名单(xlsx/csv) | 「教师管理 → 导入名单」 | **仅管理员** |
| 重置密码 | 「教师管理」(可指定新密码,留空用默认初始密码) | **仅管理员** |
| 加进某个班 | 班级详情 → 任课老师(班级 + 科目 + 教师) | 管理员 |
| 换班主任 | 班级详情顶部「更换班主任」 | **仅管理员** |
> **教师录入只有管理员能做**:`/api/teachers` 整组接口都是 `requireRole('ADMIN')`,教师调用返回 403。
> 前端也只在管理员登录时显示这个菜单项。
### 删除教师有护栏
下面四种情况一律拒绝(409),因为删账号会级联删掉他在各班发过的内容:
1. 他还是某个班的**班主任**;
2. 名下有**课程**;
3. 有**任课关系**(`Course.teacherId === 他`);
4. **发布过作业或通知**。
(后两项曾经漏检,会静默删掉该教师发过的作业与通知。)
## 角色与可见范围
班级内的角色由「账号角色 + 与该班级的关系」共同决定:
| 角色 | 怎么判定 | 可见范围 |
| ------------------ | ------------------------------ | -------------------------- |
| `ADMIN` 管理员 | `User.role = ADMIN` | 全部班级 |
| 班主任 `HEAD` | `Class.teacherId === 当前用户` | 本班 |
| 科任老师 `SUBJECT` | 该班 `Course.teacherId` 有当前用户 | 被任课的班级 |
| 学生 `STUDENT` | `User.classId` / 班级账号 | 自己的班级(只读业务数据) |
### 权限矩阵(摘要)
| 操作 | 管理员 | 班主任 | 科任老师 |
| ------------------------------------ | :----: | :----------: | :------: |
| 班级创建 / 修改 / 删除 | ✅ | ❌ | ❌ |
| 分配班主任与科任老师 | ✅ | ❌ | ❌ |
| 学生名单管理(增删 / 导入) | ✅ | ❌ | ❌ |
| 教师录入(新建 / 导入 / 改密码) | ✅ | ❌ | ❌ |
| 数据库管理(备份 / 导入导出 / 切换) | ✅ | ❌ | ❌ |
| 课表管理(增删改 / 导入) | ✅ | ✅(仅本班) | ❌ |
| 布置作业 | ✅ | ✅ | ✅ |
| 叫人 | ✅ | ✅ | ✅ |
| 发布通知 | ✅ | ✅ | ✅ |
| 成绩录入 / 修改 / 导入(仅本班) | ✅ | ✅(仅本班) | ❌ |
| 维护班级密码 | ✅ | ❌ | ❌ |
完整矩阵与实现见[角色与权限](../dev/permissions.md)。
## 学期周数
每个班有自己的学期周数(`Class.termWeeks`,默认 20,上限 30),**只有管理员**能改。
它决定"现在是第几教学周",见[课表](schedules.md)。