From ed3b2cf6de7d479119f34c91fbf9c51be69d697f Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Tue, 15 Sep 2026 08:48:40 -0600 Subject: [PATCH] =?UTF-8?q?feat(=E8=AF=BE=E5=A0=82=E6=B1=82=E5=8A=A9):=20?= =?UTF-8?q?=E6=95=99=E5=B8=88=E5=8D=8F=E4=BD=9C=E5=BC=B9=E6=A1=86=E5=B7=A6?= =?UTF-8?q?=E4=BE=A7=E7=9B=B4=E6=8E=A5=E6=98=BE=E7=A4=BA=E9=A2=98=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 原来弹框里只有编辑器,要看题得点「打开题面」另开标签页来回切。 现在左右分栏(可拖动):左侧只读题面(描述、输入输出、例子、提示, SQL 题显示数据表与期望结果),右侧协作编辑器。 不复用 ProblemContent:它读写全局 problemStore,老师接单时正开着 的题目页会被换掉题面,测试按钮跑的也是老师自己的代码。 Co-Authored-By: Claude Opus 5 --- .../web/src/shared/components/CollabModal.vue | 202 ++++++++++++++++-- 1 file changed, 186 insertions(+), 16 deletions(-) diff --git a/apps/web/src/shared/components/CollabModal.vue b/apps/web/src/shared/components/CollabModal.vue index df2f5c0..2c47542 100644 --- a/apps/web/src/shared/components/CollabModal.vue +++ b/apps/web/src/shared/components/CollabModal.vue @@ -15,6 +15,11 @@ import { enhanceCompletion } from "shared/extensions/autocompletion" import { languageExtension } from "shared/extensions/language" import { useCollabDoc } from "../composables/collabDoc" import { useCollabStore } from "shared/store/collab" +import { MdPreview } from "md-editor-v3" +import "md-editor-v3/lib/preview.css" +import { getProblem } from "oj/api" +import type { Problem } from "utils/types" +import SQLDataTable from "oj/problem/components/SQLDataTable.vue" const isDark = useDark() const collabStore = useCollabStore() @@ -54,6 +59,51 @@ const extensions = computed(() => [ getInitialExtension(), ]) +/** + * 题面直接放在弹框左侧。原来只有一个「打开题面」链接,老师得在两个标签页之间 + * 来回切着对照学生的代码。 + * + * 不复用 ProblemContent:它读写全局的 problemStore,老师接单时可能正开着另一道题 + * 的详情页,一写就把那边的题面换掉了;它的「测试」按钮跑的也是 codeStore 里老师 + * 自己的代码。这里只要只读的题面。 + * + * 求助入口在比赛里是关掉的(Form.vue 的 showHelpButton),problemId 一定是公开 + * 题目的展示 ID,按非比赛的接口取就行。 + */ +const problem = ref(null) +const problemLoading = ref(false) + +watch( + () => collabStore.room?.problemId, + async (problemId) => { + if (!problemId) { + problem.value = null + problemLoading.value = false + return + } + if (problem.value?._id === problemId) return + problem.value = null + problemLoading.value = true + try { + const res = await getProblem(problemId, "") + // 请求在路上时老师结束协作、又接了另一道题的单,旧响应不能盖掉新题面 + if (collabStore.room?.problemId === problemId) problem.value = res + } catch { + // 取不到就留空,右上角的「打开题面」还能兜底 + } finally { + if (collabStore.room?.problemId === problemId) + problemLoading.value = false + } + }, + { immediate: true }, +) + +const sqlDisplay = computed(() => problem.value?.sqlDisplay ?? null) +const sqlExpectedQuery = computed(() => { + const exp = sqlDisplay.value?.expected + return exp && "columns" in exp ? exp : null +}) + const bind = (view: EditorView) => { if (!collabStore.isTeacher || !collabStore.room) return // ★ 教师端 seedContent 必须是 null —— 内容全部来自学生端 @@ -98,7 +148,7 @@ onUnmounted(() => { - - + + + + + +