From ffabcd4a0dac0944cf4dbfb337baa1327d00bf56 Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Sun, 30 Aug 2026 09:38:04 -0600 Subject: [PATCH] =?UTF-8?q?fix(collab):=20=E6=8F=90=E7=A4=BA=E4=BC=9A?= =?UTF-8?q?=E4=B8=A2=E3=80=81=E6=8E=92=E9=98=9F=E4=BD=8D=E7=BD=AE=E4=B8=8D?= =?UTF-8?q?=E5=88=B7=E6=96=B0=EF=BC=9B=E6=98=BE=E5=BC=8F=E5=A3=B0=E6=98=8E?= =?UTF-8?q?=20lib0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 一次性提示原来挂在题目页的 Form.vue 上消费:学生排着队切去看提交记录, 老师这时取消了他的求助,那条提示就永远没人消费。挪到顶栏统一弹, 教师端的 error 提示同理。另外加了序号——连着两次同样的文案在 Vue 眼里 === 相等,watch(notice) 不会第二次触发。 - queueAhead 原来只在「建请求 / 重连 / 退回排队」推过,前面的人被接走或 被取消之后不重算,第五个学生会一直显示「前面还有 4 人」。跟着 broadcastRequests 一起推,两件事永远同时发生。 - collabDoc 动态 import 了 lib0/encoding 和 lib0/decoding,但 lib0 不在 package.json 里,靠 yjs 提升到根 node_modules 才能解析。上游依赖树一变 就断,而且断在运行时不在构建时。按现装的 0.2.117 钉住。 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_016DHxhKNxXfG89JnVzHbvgj --- apps/web/package.json | 1 + apps/web/src/shared/components/Header.vue | 18 +++++++++++++++ apps/web/src/shared/store/collab.ts | 27 ++++++++++++++++++----- bun.lock | 1 + 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/apps/web/package.json b/apps/web/package.json index 52e5714..e596a16 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -40,6 +40,7 @@ "date-fns": "^4.4.0", "fflate": "^0.8.3", "highlight.js": "^11.12.0", + "lib0": "0.2.117", "md-editor-v3": "^6.5.6", "mermaid": "^11.17.2", "mermaid-legacy": "npm:mermaid@^9.4.3", diff --git a/apps/web/src/shared/components/Header.vue b/apps/web/src/shared/components/Header.vue index 4924de5..6a4dea5 100644 --- a/apps/web/src/shared/components/Header.vue +++ b/apps/web/src/shared/components/Header.vue @@ -4,6 +4,7 @@ import { RouterLink } from "vue-router" import { useBreakpoints } from "shared/composables/breakpoints" import { useLearnProgress } from "shared/composables/learnProgress" import { useAuthModalStore } from "shared/store/authModal" +import { useCollabStore } from "shared/store/collab" import { useScreenModeStore } from "shared/store/screenMode" import { logout } from "../api" import CollabModal from "./CollabModal.vue" @@ -14,6 +15,23 @@ import { trickOrTreat } from "utils/functions" const userStore = useUserStore() const configStore = useConfigStore() +const collabStore = useCollabStore() +const message = useMessage() + +/** + * 课堂求助的一次性提示,统一在这里弹。 + * + * 原来挂在题目页的 Form.vue 上:学生排着队切去看提交记录,老师这时候取消了 + * 他的求助,那条「老师已取消你的求助」就永远没人消费。顶栏是全局的,放这儿 + * 才收得全 —— 教师端的 error 提示(比如「请先退出当前协作」)同理。 + */ +watch( + () => collabStore.noticeSeq, + () => { + const text = collabStore.consumeNotice() + if (text) message.info(text) + }, +) const authStore = useAuthModalStore() const screenModeStore = useScreenModeStore() const route = useRoute() diff --git a/apps/web/src/shared/store/collab.ts b/apps/web/src/shared/store/collab.ts index c1d8b7b..06a34f6 100644 --- a/apps/web/src/shared/store/collab.ts +++ b/apps/web/src/shared/store/collab.ts @@ -32,8 +32,21 @@ export const useCollabStore = defineStore("collab", () => { const teacherName = ref("") /** 双方:当前房间。null 表示不在协作中 */ const room = ref(null) - /** 一次性提示,由组件消费后清空 */ + /** 一次性提示,由 Header 统一消费后清空 */ const notice = ref("") + /** + * 提示序号,每次设置都自增。 + * + * 消费方 watch 的是这个,不是 notice 本身:连着两次同样的文案(老师取消了 + * 求助、学生又求助、又被取消)在 Vue 眼里 `===` 相等,watch(notice) 不会 + * 第二次触发,第二条提示就这么没了。 + */ + const noticeSeq = ref(0) + + function setNotice(text: string) { + notice.value = text + noticeSeq.value += 1 + } const pendingCount = computed( () => requests.value.filter((it) => it.status === "pending").length, @@ -74,10 +87,10 @@ export const useCollabStore = defineStore("collab", () => { teacherName.value = String(data.teacherName ?? "") } else if (data.status === "cancelled") { helpStatus.value = "idle" - notice.value = "老师已取消你的求助" + setNotice("老师已取消你的求助") } else if (data.status === "no_teacher") { helpStatus.value = "idle" - notice.value = "当前没有老师在线" + setNotice("当前没有老师在线") } return case "room_open": @@ -97,11 +110,12 @@ export const useCollabStore = defineStore("collab", () => { // 这里先归零,那条 pending 补发会立刻把它纠正回来,不会被这次重置盖掉 room.value = null helpStatus.value = "idle" - notice.value = - data.reason === "peer_offline" ? "对方已断开连接" : "协作已结束" + setNotice( + data.reason === "peer_offline" ? "对方已断开连接" : "协作已结束", + ) return case "error": - notice.value = String(data.message ?? "") + setNotice(String(data.message ?? "")) return } } @@ -179,6 +193,7 @@ export const useCollabStore = defineStore("collab", () => { teacherName, room, notice, + noticeSeq, isTeacher: computed(() => userStore.isTeacherOrAbove), connect, disconnect, diff --git a/bun.lock b/bun.lock index d28cd3d..5a6a447 100644 --- a/bun.lock +++ b/bun.lock @@ -67,6 +67,7 @@ "date-fns": "^4.4.0", "fflate": "^0.8.3", "highlight.js": "^11.12.0", + "lib0": "0.2.117", "md-editor-v3": "^6.5.6", "mermaid": "^11.17.2", "mermaid-legacy": "npm:mermaid@^9.4.3",