feat(协作): 老师协作时右栏顶上一条协作条,结果页签先摆学生最近一次交的,抽屉变成「他的提交」
- 协作条:「正在帮 谁 · 语言 · 看他交过什么 ↗ · 结束协作」,从工具栏里挪出来,一眼看得出 编辑器里是学生的代码。「看他交过什么」带上学生用户名、开新标签(原来只带题号,还得再筛一遍) - 老师接单后「结果」页签原来是空的:现在摆学生在这道题上最近一次交的结果,可刷新; 不给 AI 提示(那是按登录的人自己的失败次数解锁的) - 抽屉「我的提交」在协作中变成「他的提交」,列的是学生的提交,只能复制、不能放回编辑器 (放回去会经协作通道直接盖掉学生正在写的代码),也不显示老师自己的排名 - 学生排队求助中、或者老师正在帮他时换题:先确认一句。换题会断开协作 / 撤掉举手, 原来一点「下一题」就把正在帮他的老师踢出去了 - 求助按钮文案:「举手求助」→「已举手 · 前面 2 人」→「某某 老师在帮你」 - 提交列表加 exactUsername=1:用户名精确匹配。原来只有「包含」,ks24a1 会把 ks24a10 的提交 也捞进来 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
11368813cc
commit
0c2ff68e9b
13 files changed
+287
-45
No files matched your search
@@ -8,6 +8,8 @@ import { useMyFlowchartStore } from "shared/store/myFlowchart"
|
||||
import { useUserStore } from "shared/store/user"
|
||||
import { useSubmissionStore } from "oj/store/submission"
|
||||
import { useFlowchartStore } from "oj/store/flowchart"
|
||||
import { useCollabStore } from "shared/store/collab"
|
||||
import type { RouteLocationNormalized } from "vue-router"
|
||||
// 判完之后该发生的事(烟花、点评、回题单)。静态引入:它得在第一次判完之前就挂好
|
||||
import SubmissionEffects from "./components/SubmissionEffects.vue"
|
||||
import ResultTabLabel from "./components/ResultTabLabel.vue"
|
||||
@@ -17,6 +19,7 @@ import {
|
||||
useProblemPageContext,
|
||||
type ProblemDrawer as DrawerKey,
|
||||
} from "./composables/problemPageContext"
|
||||
import { useTeacherCollab } from "./composables/teacherCollab"
|
||||
|
||||
// 抽成具名 loader,便于进页面时与接口并行预取编辑器 chunk。
|
||||
// 题库、比赛、题单三种入口用的是同一个编辑器:原来比赛和题单用的是另一个精简版,
|
||||
@@ -88,12 +91,17 @@ watch(
|
||||
|
||||
const drawer = ref<DrawerKey | null>(null)
|
||||
|
||||
// 协作中的老师看的是学生的提交
|
||||
const teacherCollab = useTeacherCollab()
|
||||
const drawerLabel = (key: DrawerKey) =>
|
||||
key === "submission" && teacherCollab.value ? "他的提交" : DRAWER_TITLE[key]
|
||||
|
||||
function toggleDrawer(key: DrawerKey) {
|
||||
drawer.value = drawer.value === key ? null : key
|
||||
}
|
||||
|
||||
const drawerMenu = computed<DropdownOption[]>(() =>
|
||||
ctx.value.drawers.map((key) => ({ label: DRAWER_TITLE[key], key })),
|
||||
ctx.value.drawers.map((key) => ({ label: drawerLabel(key), key })),
|
||||
)
|
||||
|
||||
// 交上去、或者语法检查没过:切到「结果」,抽屉开着就先关掉。提交按钮在编辑器那边,页签归这一页管
|
||||
@@ -106,6 +114,35 @@ watch(
|
||||
},
|
||||
)
|
||||
|
||||
/**
|
||||
* 学生正在排队求助、或者老师正在帮他时换题:协作是开在这道题上的,换题就断了
|
||||
* (SyncCodeEditor 的 detach),排队的求助也跟着撤掉。先问一句,别让他一点「下一题」
|
||||
* 就把正在帮他的老师踢出去。只拦「离开这道题」,切页签改 `?tab=` 不算
|
||||
*/
|
||||
const collabStore = useCollabStore()
|
||||
const dialog = useDialog()
|
||||
function confirmLeavingHelp(to: RouteLocationNormalized, from: RouteLocationNormalized) {
|
||||
if (collabStore.isTeacher || collabStore.helpStatus === "idle") return true
|
||||
if (to.name === from.name && to.params.problemID === from.params.problemID) return true
|
||||
const active = collabStore.helpStatus === "active"
|
||||
return new Promise<boolean>((resolve) => {
|
||||
dialog.warning({
|
||||
title: active ? "老师正在帮你看这道题" : "你正在排队等老师",
|
||||
content: active
|
||||
? "换题之后,老师那边的协作就断了。确定要换吗?"
|
||||
: "换题之后这次举手就撤掉了,要在新的题目里重新举手。确定要换吗?",
|
||||
positiveText: "换题",
|
||||
negativeText: "留在这道题",
|
||||
onPositiveClick: () => resolve(true),
|
||||
onNegativeClick: () => resolve(false),
|
||||
onClose: () => resolve(false),
|
||||
onMaskClick: () => resolve(false),
|
||||
})
|
||||
})
|
||||
}
|
||||
onBeforeRouteUpdate(confirmLeavingHelp)
|
||||
onBeforeRouteLeave(confirmLeavingHelp)
|
||||
|
||||
// 结果页签的标题带状态图标(ResultTabLabel),n-tab-pane 的 tab 接受渲染函数
|
||||
const resultTab = () => h(ResultTabLabel)
|
||||
|
||||
@@ -187,7 +224,7 @@ onBeforeUnmount(() => {
|
||||
:secondary="drawer === key"
|
||||
@click="toggleDrawer(key)"
|
||||
>
|
||||
{{ DRAWER_TITLE[key] }}
|
||||
{{ drawerLabel(key) }}
|
||||
</n-button>
|
||||
</n-flex>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user