Appearance
云学院功能清单、执行优先级与系统接入设计
状态:历史功能盘点;账号和实施现状以上游组件与 edu_user 迁移设计及后续 P0–P3 文档为准 盘点日期:2026-10-26
范围:packages/web/(5404 端口的云学院演示站)接入 packages/server/,并复用 packages/manage/ 已有的系统基础能力。本文不把当前演示交互视作已交付的后端功能。
账号决策(2026-11-03 更新):平台管理员、学校管理员、老师、学生都是前台用户,统一存于 edu_user,user_type=web,由角色区分身份;sys_user 仅承载系统后台账号。不接学校单点登录。下文涉及旧 sys_user 云学院账号的描述仅保留为历史盘点。
已确认的课程决策:允许学校课程副本。平台课程分发给学校时创建独立副本;学校把副本分配给班级。学校编辑副本不会直接修改平台课程或其他学校副本。
已确认的学校删除决策:分为可恢复的“停用学校、禁用校内账号、软删除”和独立的“硬删除”两部分;硬删除不是普通列表的直接删除按钮。
已确认的考试决策:学生交卷后立即可查看分数、正确答案和解析;同一学生对同一试卷只有一次考试机会,暂不允许补考、重考或改分。
已确认的课堂准入决策:本校学生凭有效课堂码即可加入课堂,不限制其所在班级,也不要求其班级已分配该课程;跨校账号不能加入。
已确认的练习与 AI 范围:刷题不保存练习记录,也不建立跨轮次错题本;AI 问答与查看历史作为 Gap 保留在产品清单,本次暂不实现。
1. 现状与目标
云学院目前有 4 种身份、33 个 page.tsx 路由页面。站点能完成单浏览器内的演示流程,但业务数据由 packages/web/src/data/db.ts 生成,并通过 packages/web/src/store/useApp.ts 的 Zustand persist 存在浏览器 localStorage(键 ykt-app-v1)。站点没有 API route,也没有调用 weiran4j 的请求层。不同浏览器、设备或用户之间没有共享业务状态。
目标是保留已完成的页面和交互,把身份、资源归属、业务写入和统计口径迁到服务端,形成跨用户可用、可审计的教学业务系统。
已有系统能力与边界
weiran4j / web 已有能力 | 云学院可如何复用 | 仍需新增 |
|---|---|---|
| 登录、Cookie/JWT、当前用户、角色菜单、权限码、登录日志 | 作为统一身份和授权基础 | 学校租户归属;学校管理员、老师、学生角色和可见范围;面向 5404 站点的登录集成 |
| 用户管理、角色管理、密码重置、手机号登录 | 复用系统账号,不再存明文密码 | 学号、学校/班级关系、任教关系、批量开户规则;确认学生是否允许手机号登录 |
| 资源库上传、资源引用、文件预览/下载 | 存 PDF 课件、课程资料与封面 | 课程与附件关联、上传授权和发布流程;如需视频大文件或转码须另定方案 |
| 行政区划、字典、系统配置、操作日志、批处理 | 学校地区、基础选项、变更审计、批量导入 | 学校和教学业务的领域表与接口 |
weiran4j 当前 Controller 覆盖 system、platform、region 等基础模块,没有学校、课程、班级、学习、考试、竞赛或课堂业务 Controller。不能把现有 packages/manage/ 管理台的系统用户页直接当作云学院业务页。
2. 模块与功能清单
“当前状态”统一为前端演示;下表列出页面已表现出的能力,不代表有服务端保障。P0 为接入前提,P1 为首个教学闭环,P2 为教学活动闭环,P3 为增强能力。
| 模块 | 页面 / 角色 | 页面功能 | 接入后关键结果 | 优先级 |
|---|---|---|---|---|
| 身份与权限 | /login、所有角色布局 | 四身份登录、演示账号选择、顶部一键切换身份、退出 | 真实登录态、服务端权限和学校范围;演示身份切换只保留在显式演示环境 | P0 |
| 学校管理 | /admin/schools、/admin/schools/[id];平台管理员 | 学校搜索、新建/编辑/删除、状态和师生/课程概览 | 学校档案、唯一编码;停用/账号禁用/软删除与独立硬删除 | P0 |
| 师生账号 | /school/accounts、学校详情;学校管理员/平台管理员 | 老师和学生单个新增、粘贴名单批量导入、编辑、启停、重置密码、关联班级 | 系统用户与学校/班级关联、去重与导入结果、敏感字段不回显 | P0 |
| 班级与任教 | /school/classes、/teach/classes、/teach/classes/[id] | 建班/改班/删班、学生名单、老师任教、班级课程与进度查看 | 班级成员关系、任教关系、班级变更的一致性 | P0 / P1 |
| 平台课程库 | /admin/courses、/studio/[lessonId] | 分类、章节、课程树;新建、改名、删除、拖动排序;编辑介绍、PDF、资料、随堂题 | 课程结构持久化、排序版本、草稿/发布、资源引用 | P1 |
| 平台分发 | /admin/distribute | 选章节、选学校、允许编辑、确认分发;对学校生成副本 | 分发记录、来源版本、幂等重发及副本策略 | P1 |
| 校内课程分配 | /school/courses、/school/assign | 查看学校副本;班级×章节矩阵勾选/全选 | 班级课程授权、老师/学生即时可见范围 | P1 |
| 老师备课与授课 | /teach/courses、/studio/[lessonId]、/studio/[lessonId]/screen | 查看任教课程、改可编辑副本、资料发布、PDF/题目投屏与标注 | 课程编辑鉴权、资源持久化;跨设备投屏状态 | P1 / P2 |
| 学生课程学习 | /study/courses、/study/courses/[id] | 按班级看课程、阅读 PDF/资料、标记完成;页面含 AI/导图/闪卡演示工具 | 服务端可见范围、学习进度、实际文件访问;AI 另排 | P1 |
| 题库与练习 | /admin/exams、/teach/exams、/study/practice | 平台/校本题库、单选/多选/判断、知识点和难度筛选;学生顺序/随机刷题、即时解析 | 题目版本、答案保护、发布范围;仅本轮展示结果与错题,退出后不保存练习记录或错题本 | P2 |
| 考试与成绩 | /admin/exams/[id]、/teach/exams/[id]、/study/exams、/study/exam/[id] | 组卷、指定班级、发布/结束;答题卡和交卷;答卷查看、成绩分布、逐题正确率和学生解析 | 服务端计时/判分、一次提交、交卷即展示完整结果、试卷快照、真实成绩和权限 | P2 |
| 课堂与签到 | /studio/[lessonId]、/study/live | 老师生成 6 位课堂码、开始/结束、学生加入即签到、提问与已解答、出勤导出 | 跨用户课堂状态、课堂码并发/过期、签到去重、提问同步 | P2 |
| 答题竞赛 | /teach/arena、/study/arena、/study/arena/[id] | 二人、四人、挑战、大竞赛;指定参赛者/知识点,限时答题、排名、总榜与 Excel 导出 | 真正多用户成绩、统一计时、结算与排名,不再推演对手 | P3 |
| 数据大屏 | /school/screen、/teach/screen | 学校或任教班范围的活跃趋势、课程使用、教师、考试、排行、动态 | 真实事件与聚合口径、数据更新频率、范围授权 | P3 |
| AI 内容辅助 | 授课/学习页中的 AI 总结、思维导图、闪卡 | 当前依据演示数据生成摘要、导图、记忆卡 | 真实 PDF 提取与可追溯页码仍属后续能力 | 后续候选 |
| AI 问答与查看历史 Gap | 授课/学习页的问答入口;历史页待设计 | 当前问答只是本地演示,未持久化会话与历史 | 保留需求记录;本次不建问答/历史接口、不作为验收项 | 暂不实现 |
| 外部录课白板 | 老师侧栏 | 新窗口跳转 say.unistory.cn | 若需统一登录/回传录课结果,另行定义集成;当前仅外链 | 待定 |
演示实现中的关键差异
- 登录在浏览器中查找
db.users的明文密码;切换身份直接写currentUserId。页面级限制不能替代接口鉴权。 - PDF 和资料上传通过
URL.createObjectURL生成临时地址,刷新后文件不可用;种子内容还引用本地样例 PDF、外网视频/图片。 - 投屏状态靠
BroadcastChannel和localStorage,适合同一浏览器多窗口,不能服务不同设备。 - 竞赛中未答题对手的成绩由
simulateRivals推演,ContestEntry.source可为sim。这不是多人实战成绩。 - 大屏的学生数、课程数、考试记录等来自演示库;缺失的登录次数用固定基准日
2026-09-29和哈希生成。 - AI 的摘要、页码、问答、导图、闪卡由课程介绍和题库文本推演,没有真正读取 PDF 或调用模型。
- 考试交卷时“用时”是随机生成;成绩分析里的逐题正确率也有演示推演。批阅“复核完成”当前只弹提示,没有持久状态变化;“导出试卷”按钮也没有真实导出。
- 学生刷题仅在本轮会话显示成绩和错题;退出后不保存练习记录,也不建立跨轮次错题本。
3. 执行优先级与交付批次
| 批次 | 完成标准 | 前置关系 | 主要工作 |
|---|---|---|---|
| P0 身份与组织底座 | 两个浏览器以不同学校/角色登录时,只能读写各自授权数据;学校、班级和师生账号跨设备一致 | 无 | 统一登录、租户范围、学校、用户扩展、班级成员/任教、权限码、接口请求层 |
| P1 课程学习闭环 | 平台建课程并分发,学校配给班级,老师备课,学生能在另一设备看到并完成课程;文件刷新可用 | P0 | 课程树、学校副本、分发、班级分配、资源上传/引用、学习进度 |
| P2 考核与课堂闭环 | 老师发卷,学生交卷,老师查真实成绩;老师开课后其他设备学生可签到/提问 | P1(课堂依赖课程);题库可与 P1 后段并行准备 | 题库、试卷、答卷、判分、课堂、签到、提问、投屏同步 |
| P3 增强能力 | 竞赛全员成绩真实可核验;大屏只显示真实口径 | P2 的事件与成绩 | 竞赛、多用户同步、埋点/聚合;AI 内容辅助另排,问答与历史 Gap 暂不实施 |
先实现一条可验收的纵向路径:平台管理员建学校 → 学校管理员建班和开账号 → 平台管理员发章节 → 学校管理员配班 → 老师完善课程 → 学生登录学习 → 进度回到老师班级页。避免先把每个页面接成只读列表而无法完成业务。
4. 方案设计
4.1 架构与模块边界
mermaid
flowchart LR
S[web: 四角色业务页面] --> A[统一请求层]
W[web: 系统管理台] --> B[weiran4j system]
A --> B
A --> E[weiran4j 教学业务模块]
E --> B
E --> M[资源库]
E --> DB[(MySQL)]
E --> R[课堂/竞赛实时通道]
E --> Q[统计与聚合任务]system持有登录、用户、角色、菜单、文件与审计;教学模块持有学校、班级、课程、分发、学习、考试、课堂、竞赛。二者通过系统模块公开的服务接口协作,避免教学表复制密码与用户状态。packages/web/建立一个请求/查询层和领域 DTO;页面从服务端取得数据。Zustand 可保留弹窗、筛选、投屏工具等临时 UI 状态,不再持久化整份业务库。- 复用现有
/api-backend/...规范,并在packages/web/开发/部署环境代理到 Java 服务。当前云学院学校账号使用edu_user,通过专属角色和学校范围隔离;这些账号不能访问packages/manage/系统管理台。 - 所有列表、详情、写入和资源下载都由后端按当前用户重新计算可见范围,不依赖客户端传入的
schoolId或角色。
4.2 使用 backend 账号区分云学院身份
sys_user 只选择现有认证和账号存储通道,不表示用户是系统管理员。云学院身份由现有 sys_role / sys_user_role 的角色编码决定;学校归属与班级归属另存业务关系,不能塞进角色名。
| 角色编码(建议) | 云学院身份 | 业务范围 |
|---|---|---|
ykt_platform_admin | 平台管理员 | 全平台学校与默认课程库;不自动获得 super_admin 的全部系统权限 |
ykt_school_admin | 学校管理员 | ykt_school_user 关联的学校 |
ykt_teacher | 老师 | 所属学校与任教班级 |
ykt_student | 学生 | 平时按所在班级及课程分配查看课程;加入课堂仅校验同校身份和有效课堂码 |
建议增加 ykt_school_user(user_id, school_id, student_no?, status)、ykt_class_student(class_id, user_id) 和 ykt_class_teacher(class_id, user_id);学校成员关系对一名普通师生暂按“一人一校”约束,学号在校内唯一。sys_user 继续持有账号、加密密码、手机号和启停状态。sys_user_role 可容纳多个角色,但云学院四种身份对单个账号恰好生效一种;如用户还兼有其他系统角色,站点仅识别 ykt_* 角色,不按“角色数组第一个”猜身份。将来确需兼任多个云学院身份,再增加显式的当前身份选择与切换审计。
登录后先调用现有 getCurrentUser 获取 id/roles/permissions,再调用新增 ykt/me 返回 siteRole、schoolId、班级/任教范围和首页。packages/web/ 根据 siteRole 渲染四种导航。服务端每个业务接口同时校验角色权限码和学校/班级/资源归属;请求体中的 schoolId 不能自行扩大访问范围。学校管理员新增师生时走教学业务模块的开户接口,由该接口协调 UserService 建系统账号、绑定专属角色与学校,不能把 system:user:create 全局权限直接发给学校管理员。
必须补一层入口隔离:packages/manage/ 系统管理台只接受被明确授予系统管理角色的用户;云学院师生账号即使可通过 /api-backend/n/system/auth/login 登录,也不能因同属 backend 类型而访问系统管理页或无业务授权的系统接口。现有通用接口中未标注权限码的入口需要逐项审计;云学院专用角色只授予 ykt:* 权限。super_admin 的通配权限属于系统运维,应明确是否允许代管云学院数据并记录审计,不能当作日常平台管理员账号。
4.3 领域模型与关键约束
| 实体 | 关键字段/关系 | 必须保持的不变量 |
|---|---|---|
| School | id, code, name, stage, regionCode, status, deletedAt | 编码唯一;停用后拒绝该校业务登录/写入;软删除保留教学数据,硬删除按单独流程物理清理 |
| SchoolMember / ClassMember / ClassTeacher | userId, schoolId, role, classId | 学生在一个时间点至多有一个主班;老师可任教多个班;学校管理员仅可管理本校 |
| CoursePackage / Chapter / Lesson | 所属者、分类、排序、版本、发布状态、课件资源 ID | 平台库与学校副本归属明确;排序在同一作用域唯一;已发布内容修改需版本规则 |
| Distribution / ClassCourse | 来源章节、目标学校、稳定的学校副本 ID、当前来源版本、允许编辑、目标班级 | 同版本分发幂等;升级不换副本 ID、不清空班级分配;学校改动不能被静默覆盖 |
| LessonResource / FeedPost / Progress | 课件、资料、发布者、完成者、完成时间 | 资源存储引用可靠;课程完成按学生+课程唯一;删除课程应保留可审计的历史引用 |
| Question / Paper / PaperQuestion / PaperAssignment / Submission | 题目、选项、答案、分数、试卷快照、班级、作答 | 发布后冻结题目与分值;一人一卷只允许一次有效提交且提交幂等;答题中不得返回正确答案,交卷后立即返回分数/答案/解析;计时与判分在服务端 |
| LiveSession / CheckIn / LiveQuestion | 课堂码、教师、课程、状态、签到与提问 | 课堂码在有效期内唯一;同一课堂学生签到唯一;跨设备更新可见 |
| Contest / ContestPlayer / ContestAnswer / ContestResult | 赛制、冻结题序、参赛者、答题与排名 | 每人每题一次有效提交;排名在服务端统一结算;真实成绩不允许 sim |
| LearningEvent / DailyAggregate | 用户、事件、发生时间、统计维度 | 指标可追溯事件;学校/班级范围一致;展示数据注明统计周期和延迟 |
演示模型里 CoursePackage 在界面称“章节”,Chapter 是该章节下的分组,Lesson 才是界面称“课程”。设计接口和表名时需固定这份术语映射,避免前后端把“课程”理解成不同层级。
4.4 核心流程与接口草案
接口名称为设计草案;最终 URL、DTO、权限码以 Controller 生成的 OpenAPI 为准。
| 流程 | 建议接口组 | 写入规则 |
|---|---|---|
| 学校/组织 | school、class、member 的列表/详情/创建/更新/停用与班级成员调整;school/softDelete、school/restore、school/hardDeletePreview、school/hardDelete | 学校编码唯一;跨校拒绝;软删除可恢复;硬删除独立预检;批量导入返回逐行成功/失败 |
| 课程与资源 | coursePackage、chapter、lesson、lessonPost;复用 system/media 上传 | 服务端按版本校验编辑冲突;上传成功后再保存业务引用;资料发布与附件引用同事务 |
| 分发与分配 | distribution/preview、distribution/create、distribution/upgradePreview、distribution/upgrade、classCourse/replace | 首次分发与升级分开;预览显示校本改动和冲突;提交使用幂等键;班级分配做差量更新 |
| 学习 | myCourses、lesson/get、lessonProgress/complete | 列表按当前登录用户与班级计算;完成操作幂等并记录时间 |
| 题库与考试 | question、paper、paper/publish、exam/start、exam/submit、exam/result、exam/report | 发布时冻结试卷;一人一卷;交卷带提交令牌;判分和交卷时间均由服务端给出,结果立即可查 |
| 课堂 | live/start、live/join、live/ask、live/answer、live/end、live/attendance | 加入只检查学生身份、同校、有效课堂码和课堂进行中;不查班级/课程分配;签到唯一;课堂码过期;导出名单基于服务端记录 |
| 竞赛 | contest/create、contest/start、contest/answer、contest/result、contest/ranking | 冻结参赛人和题序;服务端判超时、结算与排名;结果导出只读真实记录 |
| 数据 | analytics/school、analytics/classes | 统计接口返回口径和时间窗;AI 问答/历史接口本次不建 |
实时通道首选服务端事件推送或 WebSocket,课堂的签到、提问、投屏状态和竞赛战况统一由服务端发布;具体传输方式可在 P2 技术验证后定。写操作通过现有操作日志记录操作者、资源和结果。
4.5 分发升级场景与处理逻辑
基本约定:采用已确认的学校副本模式,不能把分发简化为纯关联。平台课程只在“发布新版本”时形成不可变来源快照,例如 v1 → v2;平台日常编辑草稿不会触发学校升级。首次分发生成一份学校副本。此后同一“平台章节 × 学校”始终复用同一个学校副本 ID,班级分配始终引用这个 ID。学校副本分别记录 sourceVersion(跟到的平台版本)和 localRevision(学校自己的修改次数),两者不能混用。
| 场景 | 触发与处理 | 学校当前教学内容 |
|---|---|---|
| 首次分发 | 平台管理员选学校、编辑权限,创建来源快照和学校副本;学校管理员再分配到班级 | 获得平台已发布版本;初始未分班 |
| 同版本再次点击分发 | 检查来源版本与已分发版本相同,返回“已是最新”,不复制、不换 ID、不重置内容 | 完全不变;若只想改编辑权限,走独立的权限变更操作 |
| 平台发布新版,学校无本地改动 | 显示新旧版本和增删改清单;平台管理员确认升级后,将新版应用到原学校副本 | 内容变为新版,班级分配保持;新增课程随已分配章节可见 |
| 平台发布新版,学校有本地改动 | 标为“待校方确认”;学校管理员看三方差异并确认合并;合并前继续使用旧学校副本 | 校本改动继续可用,不自动覆盖 |
| 平台和学校改了同一内容 | 标为冲突;逐项选择“保留校本”或“采用平台”,全部处理后才能提交 | 未确认前仍用旧内容 |
| 学校暂不升级 | 保留旧来源版本和校本内容,可稍后从当前版本直接升级到最新已发布版本 | 老师、学生继续使用原分配和原内容 |
| 平台调整“可编辑/只读” | 单独更新分发权限并记录审计,不触发内容升级 | 内容和班级分配不变;改为只读后禁止后续校本写入 |
| 平台删除已分发章节 | 停止新分发,现有学校副本保留;对已用副本走显式停用/归档流程 | 已学进度、考试、课堂历史保留 |
三方合并:以“学校上次接收的平台快照 A、学校当前副本 L、平台新版本 B”比较。只有 B 改的字段采用 B;只有 L 改的字段保留 L;两边改了同一字段且结果不同则产生冲突。学校新增的课程/资料保留。平台删除的节点如果学校未改,可从当前教学目录移除,但历史记录仍保留;如果学校修改过该节点,按冲突处理。合并按稳定的来源节点 ID 匹配,不能靠标题或数组位置猜测。首期不做静默的“平台优先”或整份覆盖。
提交顺序:发布新版 → 平台选择学校并查看升级预览 → 无本地改动的学校由平台确认升级;有本地改动的学校收到待确认事项 → 学校管理员处理差异/冲突并确认 → 服务端在一个事务内写新副本修订、更新 sourceVersion、记录操作日志。预览时返回副本修订号;提交时若学校又编辑过,返回冲突并要求重新预览。失败时原副本保持不变,重复提交用幂等键返回同一结果。
引用与回退:学校副本 ID、未删除节点的课程 ID 保持稳定,原有 ClassCourse 不变。历史学习、课堂、答卷绑定当时的内容版本快照;新版删除或改题不能改写旧成绩。每次升级保留前一修订供管理员回退教学内容,回退也记录新修订,不删除已经发生的学习记录。升级预览须列出受影响班级、课程增删、资源替换、本地修改和冲突数量。
当前演示代码的 distribute() 会删旧副本并新建随机 ID,页面提示“将覆盖”;班级 courseIds 仍保存旧 ID,可能使课程从师生端消失。P1 接口上线时必须替换这段行为与提示文案。
4.6 学校停用、软删除与硬删除
学校生命周期:active(正常) ↔ disabled(停用) → soft_deleted(软删除) → hard_deleted(物理移除)。停用与软删除都可恢复;硬删除不能通过产品界面恢复。平台管理员执行这些操作;学校管理员无权删除自己的学校。
| 操作 | 学校与账号 | 教学数据及页面 | 恢复方式 |
|---|---|---|---|
| 停用学校 | 学校变 disabled;校内学校管理员、老师、学生账号一并禁用,已发令牌吊销;平台账号不受影响 | 班级、学校副本、分配、学习进度、答卷、课堂和竞赛记录全部保留;普通业务入口停止读写 | 启用学校,并仅恢复停用前原本启用的校内账号;原本就禁用的账号保持禁用 |
| 软删除学校 | 学校标记 soft_deleted/deletedAt,校内账号保持禁用;从正常学校列表、选择器和新分发目标中隐藏 | 所有业务数据继续保留,供恢复和硬删除预检;进行中的课堂/竞赛先结束或阻止软删除 | 从回收/已删除列表恢复到停用状态,经平台管理员确认后再启用学校和账号 |
| 硬删除学校 | 只对已软删除的学校开放;删除仅属于该校的账号与关系 | 物理删除该校班级、学校副本、班级分配、校本题库/试卷、答卷、学习记录、课堂/签到/提问、竞赛/成绩、学校统计源数据及独占资源引用;平台课程源、其他学校数据不动 | 无产品内恢复;备份恢复属于运维流程 |
停用时需要记录本次受影响账号的原状态,避免重新启用时把此前因其他原因禁用的账号一起放开。认证时除 sys_user.status 外还要查学校状态;禁用账号沿用现有令牌吊销机制,防止已登录会话继续写入。停用期间平台管理员仍可查看学校档案和执行恢复,但不能对其继续分发课程。
硬删除流程:平台管理员在已删除学校详情页查看预检摘要(校内账号、班级、课程副本、文件、答卷、课堂、竞赛及历史记录数量),确认没有正在执行的课堂、竞赛或导入任务,再输入学校编号执行。删除任务按依赖关系清理业务表与资源引用;对已被其他业务引用的共享文件只解除本校引用,不删共享文件。服务端按学校 ID 加锁,任务幂等、可追踪进度与失败原因;数据库清理完成后异步清理独占文件。完成后只保留不含校内个人信息的最小操作审计摘要。备份中的数据按备份保留周期到期清除,并在硬删除提示中明示。
云学院账号虽都使用 backend 类型,硬删除不能按学校 ID 盲删 sys_user:对只属于该校、且没有其他系统角色或归属的账号可删除系统用户;对还承担其他系统职责的账号只解除该校成员关系和云学院角色,保留系统账号。硬删除的预检必须展示这两类账号数量。
当前演示 removeSchool() 是一次性级联删除,学校列表只有一个“删除”按钮。接入时改为“停用”“移入回收站”和回收站内独立的“彻底删除”入口,避免把软删除与硬删除混为同一操作。
4.7 考试作答与成绩规则
试卷发布时冻结题目、选项、正确答案、解析和分值,后续题库编辑不影响已发布试卷。学生开始考试前,接口只返回作答所需内容,不返回正确答案或解析。服务端记录开始时间并控制时长;交卷时在事务内判分、保存答卷和提交时间,立即向该学生开放分数、逐题正确答案与解析。学生之后可从“考试与成绩”反复查看同一份结果。
对 (paper_id, student_id) 设置唯一约束,只允许一份有效答卷。网络重试携同一提交令牌时返回原答卷与原成绩;已交卷后重新开始、改答案再次提交或请求补考均拒绝创建新答卷。当前阶段不提供重考、补考、人工改分或成绩覆盖接口;老师端的“批阅”应改为只读答卷查看与成绩分析,演示页只弹提示的“复核完成”操作不作为正式功能。
4.8 课堂准入与签到规则
同校的已启用学生输入有效的 6 位课堂码,即可加入正在进行的课堂;不限制班级,也不要求该学生的班级已被分配对应课程。班级仅用于签到名单分组和事后统计。课堂码失效、课堂已结束、学生账号/学校已停用或学生属于其他学校时拒绝加入。加入成功即签到,同一学生重复进入同一课堂只保留一条签到记录。跨校访问仍受学校边界限制。
普通“我的课程”继续按班级课程分配展示;凭码进入课堂不自动获得该课程在“我的课程”中的长期访问权。当前演示 joinLive() 只按课堂码查找课堂,未校验学生与课堂是否同校,正式接口必须补上服务端校验。
4.9 刷题与 AI Gap 范围
刷题只在当前页面会话维护题序、作答、本轮分数和本轮错题,允许当场查看解析、重开一轮;离开页面后这些临时结果丢弃。服务端只提供有权限的题目内容,不创建练习提交表、练习记录接口或跨轮次错题本。正式题库接口仍须避免把尚未作答题目的正确答案提前暴露;提交本轮答案后再返回判定和解析。
AI 问答和“查看历史”各保留一条产品 Gap,暂不设计问答会话表、历史检索接口或模型调用链,也不纳入本次 P0–P3 验收。现有 AiPanel 的问答结果来自本地推演,不能在正式环境呈现为已接入 AI 服务;入口应标明演示/未开放或隐藏。AI 总结、导图、闪卡同样还是演示实现,后续若决定接入真实 PDF/模型,应另行排期,不依赖本次问答/历史 Gap。
4.10 权限矩阵
| 能力 | 平台管理员 | 学校管理员 | 老师 | 学生 |
|---|---|---|---|---|
| 管学校、平台课程库、向学校分发 | 全平台 | — | — | — |
| 管本校账号、班级、班级课程分配 | 必要的全平台运维入口 | 本校 | — | — |
| 编辑学校课程副本 | 可按运维规则 | 本校且分发允许编辑 | 任教范围内且分发允许编辑 | — |
| 管题库/考试 | 平台默认题库/试卷 | — | 本校题库和任教班级试卷 | — |
| 学习、考试、刷题、参赛、加入课堂 | — | — | — | 所在学校及授权班级 |
| 数据大屏 | 待定 | 本校 | 任教班级 | — |
前端 can() 仅用于显隐和提示;服务端权限码还必须叠加资源归属校验。演示站的“系统管理员可编辑学校副本”等宽权限,需要在实施时明确其审计与运维场景。
4.11 迁移、验收与风险处理
- 把
db.ts的种子作为开发演示数据导入脚本,不直接写入生产。迁移时保留稳定的业务 ID 映射或建立旧 ID→新 ID 表,保证已有课程深链能解析。 - 接口逐模块上线。每个模块保留显式的 demo/dev 模式和真实 API 模式;真实环境禁止回退到本地种子,避免“保存成功”却只写进浏览器。
- P0 验收:不同浏览器登录两校账号,跨校列表、详情 URL、文件下载和写接口均不可越权;停用学校后校内账号立即失效,软删除可恢复且原先禁用账号不被误启用;硬删除只能对已软删除学校执行,预检数量与实际清理一致;批量导入能报告重复与错误行。
- P1 验收:完整纵向路径在两台设备上完成;PDF/资料刷新后仍可读取;学校副本是否可编辑与班级是否已分配直接决定可见性;同版本重发不变更副本 ID;升级后班级分配不丢失,校本修改按三方合并规则保留或进入冲突处理。
- P2 验收:学生交卷后立即看到分数、正确答案与解析;同一试卷重试交卷只返回原答卷,重新作答/补考/改分均不可执行,老师报告可从答卷重算;本校不同班级且未分配该课程的学生可凭码加入,跨校学生被拒绝,重复加入不重复签到;跨设备课堂状态一致,导出的出勤/成绩与页面数一致。
- P3 验收:竞赛每个名次可追溯到真实作答;大屏数字可回溯到业务记录或事件。AI 问答与查看历史不在本批次验收范围。
5. 后续 Gap(本次不实施)
- AI 问答:明确资料来源、模型/知识库、引用与失败状态后再设计服务端能力。
- 查看历史:明确会话保存范围、权限与保留时间后再设计历史页和检索接口。
6. 依据
- 页面与导航:
packages/web/src/app/**/page.tsx、packages/web/src/components/AppShell.tsx;已在 5404 站点核对四种身份的导航与代表页面。 - 演示数据、状态与权限:
packages/web/src/data/db.ts、packages/web/src/data/types.ts、packages/web/src/data/permissions.ts、packages/web/src/store/useApp.ts。 - 课堂、竞赛、分析与 AI:
packages/web/src/lib/liveSync.ts、packages/web/src/data/contest.ts、packages/web/src/data/analytics.ts、packages/web/src/lib/ai.ts。 - 已有系统接口及约束:
packages/server/docs/01-架构与接口契约.md、packages/server/weiran-system/**/web/*Controller.java、packages/server/weiran-region/**/web/*Controller.java。