feat(web): 课堂求助 store 与全局 collab 连接

连接全局常驻,不跟题目页起落 —— 老师在任何页面都要能收到求助。
列表按题目聚合,同题多人时能一眼看出该全班讲。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K1d8B3f4SXJwDvUY625eQd
This commit is contained in:
2026-08-28 05:36:51 -06:00
parent aef687bcfc
commit 17aa69f8a7
3 changed files with 226 additions and 0 deletions

View File

@@ -709,3 +709,44 @@ export function useConfigWebSocket(handler?: MessageHandler<ConfigUpdate>) {
removeHandler: (h: MessageHandler<ConfigUpdate>) => ws.removeHandler(h),
}
}
export interface CollabRequestItem {
studentId: number
studentName: string
className: string | null
problemId: string
problemTitle: string
createdAt: number
status: "pending" | "active"
teacherName: string | null
}
export interface CollabMessage extends WebSocketMessage {
type:
| "requests"
| "help_status"
| "room_open"
| "room_closed"
| "error"
}
/**
* 课堂求助 / 协作通道。和另外两条的区别是它**双向**且**收发二进制** ——
* 控制面是 JSONYjs 的 update / awareness 走 sendRaw 与 onBinary。
*/
export class CollabWebSocket extends BaseWebSocket<CollabMessage> {
private binaryHandler: ((data: ArrayBuffer) => void) | null = null
constructor() {
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:"
super({ url: `${protocol}//${window.location.host}/ws/collab` })
}
setBinaryHandler(handler: ((data: ArrayBuffer) => void) | null) {
this.binaryHandler = handler
}
protected override onBinary(data: ArrayBuffer) {
this.binaryHandler?.(data)
}
}