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