You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
11 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 学校组织模式与可选行政班设计
## 背景与结论
产品需要同时服务两类学校:
- 标准学校:学生属于行政班,教师从行政班组建教学班;
- 珠江学校:不使用行政班,由教师直接维护教学班学生名单。
两类需求共用同一个产品、同一套代码库和同一套数据库。行政班不是系统的必备实体,而是某些学校启用的学生归属方式;教学班始终是实训、任务、成绩和学习进度的业务主体。
不建立长期客户分支,也不重建项目。短期交付若必须使用分支,分支中的差异必须回收为学校级配置或明确的扩展点。
## 目标与非目标
### 目标
1. 让每所学校独立选择是否启用行政班。
2. 珠江学校由教师创建教学班、添加和维护教学班学生。
3. 标准学校保持现有行政班和教学班逻辑,避免数据或操作回归。
4. 学生可以加入多个教学班;任务、成绩和进度只以教学班为准。
5. 复用现有 `school_class.class_type`、`created_by` 与 `teaching_class_student` 数据模型。
### 非目标
- 本期不拆分为两套部署或两套数据库结构。
- 本期不将学校管理员的全校学生管理能力开放给珠江学校。
- 本期不引入通用流程引擎或任意层级组织树。
- 本期不改变外部教务系统同步的既有语义;后续可将其作为第三种名单来源扩展。
## 方案选择
| 方案 | 结论 | 原因 |
| --- | --- | --- |
| 客户长期分支 | 不采用 | 版本升级、缺陷修复和安全补丁都需要反复合并,维护成本随客户数增长。 |
| 独立项目 | 不采用 | 当前差异集中在组织结构与名单维护,不足以证明业务核心已经分化。 |
| 学校级组织模式配置 | 采用 | 差异可被稳定规则表达,公共任务、成绩、实训等能力继续复用。 |
## 核心模型
```text
学校
├─ 学生身份(必属学校,以“学校 + 学号”去重)
├─ 行政班(可选,仅 ADMIN_CLASS_ENABLED 学校)
└─ 教学班(实训业务主体)
└─ 教学班学生成员(学生可加入多个教学班)
└─ 实训任务、提交、成绩、学习进度
```
### 学校组织配置
新增一张一对一配置表 `school_product_config`,避免以后不断向 `school` 表加入互不相关的定制字段。
| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `school_id` | VARCHAR(64), PK | 对应 `school.school_id` |
| `organization_mode` | VARCHAR(32) | `ADMIN_CLASS_ENABLED``TEACHING_CLASS_ONLY` |
| `student_roster_owner` | VARCHAR(32) | `SCHOOL_ADMIN`、`TEACHER`;预留 `EXTERNAL_SYNC` |
| `create_time` / `update_time` | DATETIME | 审计时间 |
配置必须由平台超管维护,学校管理员和教师只读取当前学校配置。创建新学校时必须创建配置记录,默认值为:
```text
organization_mode = ADMIN_CLASS_ENABLED
student_roster_owner = SCHOOL_ADMIN
```
珠江学校配置为:
```text
organization_mode = TEACHING_CLASS_ONLY
student_roster_owner = TEACHER
```
不允许在学校已存在行政班或学生数据时直接切换组织模式;应先完成数据核查/迁移,或新建学校租户。
### 珠江学校的数据规则
| 对象 | 规则 |
| --- | --- |
| 学生 `Userinfo` | `school_id` 必填;`school_class_id` 可为空;院系、专业在珠江模式下可为空。 |
| 行政班 `SchoolClass` | 不允许创建 `class_type=ADMIN`;行政班列表、导入入口和相关菜单不展示。 |
| 教学班 `SchoolClass` | 必须为 `class_type=TEACHING``created_by` 必填且等于创建教师。`school_major_id` 允许为空。 |
| 教学班成员 `TeachingClassStudent` | `teaching_class_id`、`student_user_id` 必填;`admin_class_id` 改为可为空。保留 `(teaching_class_id, student_user_id)` 唯一约束。 |
| 学生身份去重 | 导入及新增均以 `school_id + student_number`(现有学号/账号字段的业务含义需统一)查重,不能仅按姓名查重。 |
`school_class_id` 只能继续作为历史兼容字段或行政班归属,不能再作为“学生当前教学班”的唯一来源。所有实训上下文应通过 `teaching_class_student` 查询教学班成员关系。
## 业务流程
### 珠江:教师维护名单
1. 教师进入“我的教学班”,创建教学班;系统写入 `class_type=TEACHING`、`created_by=当前教师`。
2. 教师在教学班内选择“添加学生”:单个新增、批量导入,或搜索并加入本校已有学生。
3. 系统用学校和学号查找学生:
- 找到已有学生:仅新增当前教学班成员关系;
- 未找到学生:创建本校学生身份后新增成员关系;
- 已在当前教学班:返回重复明细,不创建重复记录。
4. 教师可编辑自己教学班成员的基本资料,并移出该教学班。
5. 移出教学班仅删除/失效成员关系,绝不删除 `Userinfo`、提交、成绩或其他教学班成员关系。
学生首次被任何教师导入后成为学校范围的学生身份。后续教师只能把已有学生加入自己的教学班;如允许编辑共享身份资料,必须记录操作者和修改时间,并以学号唯一性校验为准。
### 标准学校:保持既有逻辑
1. 学校管理员维护学生及行政班。
2. 教师可从一个或多个行政班生成教学班,或导入名单。
3. 导入教学班时保留现有“学生属于指定行政班/专业范围”的校验。
4. `TeachingClassStudent.admin_class_id` 记录学生行政班快照。
所有涉及“行政班存在”或“成员必须来自行政班”的规则,都以当前学校的 `organization_mode` 为前提。不得让珠江模式经过标准模式的行政班校验。
## 权限与界面
### 珠江学校
| 角色 | 可见模块 | 关键限制 |
| --- | --- | --- |
| 平台超管 | 学校与学校配置 | 可查看学校数据;配置变更须通过平台端。 |
| 学校管理员 | 学校基础信息、教师管理 | 不显示院系、专业、行政班和全校学生管理。 |
| 教师 | 我的教学班、教学班学生、任务和成绩 | 只可操作 `created_by=本人` 的教学班及其成员。 |
| 学生 | 已加入教学班的实训内容 | 仅访问自己有效教学班中的任务、进度和成绩。 |
### 前端行为
- 登录后返回或单独读取学校产品配置,并存入用户会话状态。
- 菜单、路由守卫、页面操作按钮均按角色和学校配置判断;隐藏菜单不是权限控制,后端必须执行相同校验。
- 珠江教师创建教学班页不展示“从行政班组建”,只提供“空教学班后添加学生”及“按学生名单创建教学班”。
- 珠江导入模板只包含学生必要身份字段,不包含院系、专业、行政班列。
- 标准学校继续使用现有模板与页面流程。
## 后端改造边界
现有代码已具备 `SchoolClass.classType`、`SchoolClass.createdBy`、`TeachingClassStudent` 和教师教学班成员导入入口。改造应优先在既有服务/控制器上补充配置判断,而不是复制一套珠江控制器。
### 配置读取
新增 `SchoolProductConfig`、Mapper 与 `SchoolProductConfigService`,对外提供:
```text
getRequiredConfig(schoolId)
requiresAdminClass(schoolId)
isTeacherRosterManaged(schoolId)
```
服务层必须获取登录用户所属学校后自行读取配置;不能信任前端传入的组织模式。
### 教师教学班接口
可沿用现有教学班与成员导入接口,但应收敛为以下语义:
```text
POST /api/.../teaching-classes
GET /api/.../teaching-classes/mine
GET /api/.../teaching-classes/{id}/students
POST /api/.../teaching-classes/{id}/students
POST /api/.../teaching-classes/{id}/students/import
PATCH /api/.../teaching-classes/{id}/students/{studentId}
DELETE /api/.../teaching-classes/{id}/students/{studentId}
```
每个教学班接口先验证:班级存在、`class_type=TEACHING`、归属学校等于操作者学校、`created_by` 等于操作者。名单接口在珠江模式下不得调用行政班、专业或院系的必填校验。
### 需要重点检查的现有逻辑
- 教学班成员导入与“按学生名单创建教学班”当前会调用行政班/专业范围校验;应按组织模式分支为标准校验与珠江校验。
- 教学班成员写入当前会传入学生的 `schoolClassId`;珠江模式传入 `NULL`
- 学生任务、成绩、AI 评价和学习进度的“当前教学班”解析必须优先使用 `TeachingClassStudent`;若学生可并行处于多个教学班,调用方必须显式传入 `teachingClassId` 或让学生选择上下文,禁止任取第一条成员记录。
- 删除学生的接口必须在教学班上下文中仅移除成员关系;任何全局删除学生账号的行为不应向教师开放。
## 数据迁移与上线
1. 新增 `school_product_config`,为所有已有学校写入标准学校默认配置。
2.`teaching_class_student.admin_class_id` 改为可空;保留已有数据。
3. 确认 `school_class.school_major_id`、学生的院系/专业字段在数据库层允许为空;若不允许,仅为珠江场景放宽为空。
4. 为珠江创建配置,发布后先由一名教师做小范围名单导入验收。
5. 不删除行政班、专业、院系或历史 `school_class_id` 数据,不对标准学校做批量数据重写。
6. 配置切换设置为受控操作:出现行政班、学生归属或任务数据时,后端拒绝直接切换并返回可操作的迁移提示。
## 审计与错误处理
记录教学班创建、学生身份创建、成员加入、成员移出和成员资料变更,至少包含学校、教学班、学生、操作者、时间、来源(手工/导入)。
典型错误:
- 教师操作非本人教学班403。
- 非珠江学校以珠江模板导入:返回“当前学校启用了行政班,请使用标准导入方式”。
- 珠江学校请求创建行政班:返回“当前学校未启用行政班”。
- 学号已存在但姓名冲突:返回冲突行,不自动覆盖既有学生身份。
- 学生已在当前教学班:返回重复明细,整批导入的处理策略统一为“重复行跳过并回显”;其他校验错误则整批拒绝。
## 验收标准
1. 珠江教师可创建教学班、导入新学生、将已有学生加入另一教学班,且成员 `admin_class_id` 为空。
2. 珠江教师不需要创建或选择行政班、院系、专业即可完成名单维护。
3. 珠江学校管理员看不到且无法调用行政班、院系、专业、全校学生管理功能。
4. 珠江教师不能操作其他教师教学班或其成员。
5. 标准学校仍需经行政班规则组建教学班,原有行政班成员导入与任务分配测试通过。
6. 学生在多个教学班时任务、成绩、AI 评价与学习进度都按明确的 `teachingClassId` 隔离。
7. 移出教学班不会删除学生身份、历史任务提交或其他教学班的成员资格。
8. 非法切换学校组织模式被后端拒绝;前端隐藏入口不能绕过后端授权。
## 实施顺序
1. 编写数据库迁移与配置实体/服务单元测试。
2. 完成学校创建、查询与平台配置管理接口。
3. 调整教学班创建、学生新增、名单导入、成员移出服务的配置分支。
4. 调整学生当前教学班解析,使多教学班上下文明确。
5. 修改前端会话配置、菜单与教学班名单页面/导入模板。
6. 覆盖珠江模式、标准模式、跨教师越权、多教学班和历史回归测试。