feat(举手与协作): 顶栏「N 人举手」点开按题分组带错法;看板多一列「在写」点了就能看他的代码;帮完了回看板、还有人就「下一个」
学生那边按钮写「xuyue 在帮你 / 在看你的代码」。顺带修了老师接单后编辑器里留着自己的 草稿或模板、学生的代码插在前面、两边从此不一致的问题。 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
573a0f967f
commit
1fcd12f6f4
13 files changed
+621
-178
No files matched your search
@@ -66,9 +66,17 @@ export function useCollabDoc() {
|
||||
const ytext = doc.getText("codemirror")
|
||||
awareness = new awarenessProtocol.Awareness(doc)
|
||||
|
||||
// ★ 顺序不能反:先把内容写进 ytext,再挂 yCollab。
|
||||
// yCollab 挂上去时会用 ytext 覆盖编辑器内容,先挂就会把学生的代码清空。
|
||||
// ★ 先把内容写进 ytext,再挂 yCollab。yCollab 挂上去**不会**拿 ytext 覆盖编辑器,
|
||||
// 只同步此后的改动 —— 所以两边挂之前编辑器里的内容必须和 ytext 一致:
|
||||
// 学生端 ytext = 编辑器内容(种子);教师端 ytext 是空的,编辑器也得清空。
|
||||
if (seedContent) ytext.insert(0, seedContent)
|
||||
// 教师端编辑器里原本是老师自己这道题的草稿或模板。不清的话它一直留在老师那边,学生的代码
|
||||
// 同步过来插在它前面,两边从此不一致(实测:老师看到两行一样的 input(),学生只有一行)。
|
||||
// 清空会顺着 v-model 写回 codeStore,但协作中的老师不存草稿(ProblemEditor 的 persistCode),
|
||||
// 结束后 loadCode 会把他的草稿读回来
|
||||
if (seedContent === null && editorView.state.doc.length) {
|
||||
editorView.dispatch({ changes: { from: 0, to: editorView.state.doc.length, insert: "" } })
|
||||
}
|
||||
|
||||
const send = (build: (encoder: any) => void) => {
|
||||
const encoder = encoding.createEncoder()
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { useCollabStore } from "shared/store/collab"
|
||||
|
||||
/**
|
||||
* 老师接单 / 主动打开学生的编辑器。两处入口(顶栏举手面板、课堂看板)共用。
|
||||
*
|
||||
* 只发消息,不跳页面:房间开好(room_open 到了)才跳到那道题,跳转统一在 CollabHost 里做
|
||||
* —— 原来是点完就跳,服务端拒了(别的老师先接走、学生刚走)前端也已经跳过去了。
|
||||
*
|
||||
* 一个老师同时只在一个房间(服务端也拦)。这里先拦一道:不拦的话等新房间开好跳过去,
|
||||
* 等于把手上这场协作断掉。返回 false = 没发出去
|
||||
*/
|
||||
export function useTeacherHelp() {
|
||||
const collabStore = useCollabStore()
|
||||
const message = useMessage()
|
||||
|
||||
function busy() {
|
||||
if (!collabStore.room) return false
|
||||
message.warning("请先结束当前协作")
|
||||
return true
|
||||
}
|
||||
|
||||
return {
|
||||
help(studentId: number) {
|
||||
if (busy()) return false
|
||||
collabStore.accept(studentId)
|
||||
return true
|
||||
},
|
||||
peek(studentId: number) {
|
||||
if (busy()) return false
|
||||
collabStore.peek(studentId)
|
||||
return true
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,9 @@ import { useAuthModalStore } from "shared/store/authModal"
|
||||
import { useUserStore } from "shared/store/user"
|
||||
import { STORAGE_KEY } from "utils/constants"
|
||||
import storage from "utils/storage"
|
||||
import type { ClassBoardCell } from "utils/types"
|
||||
|
||||
type BoardLatest = NonNullable<ClassBoardCell["latest"]>
|
||||
|
||||
// 全站唯一一处,脱离 n-message-provider 也能弹 —— 强制登出跟当前挂着哪个组件无关。
|
||||
// utils/api.ts 里也是这么做的
|
||||
@@ -564,6 +567,8 @@ export interface CollabRequestItem {
|
||||
className: string | null
|
||||
problemId: string
|
||||
problemTitle: string
|
||||
/** 他这道题最后一次代码提交(和看板格子的 latest 同形),面板按它写错法;没交过为 null */
|
||||
latest: BoardLatest | null
|
||||
createdAt: number
|
||||
status: "pending" | "active"
|
||||
teacherName: string | null
|
||||
|
||||
Reference in new issue
Block a user