diff --git a/apps/web/src/oj/classroom/board.vue b/apps/web/src/oj/classroom/board.vue index 0ea3a57..8d76edb 100644 --- a/apps/web/src/oj/classroom/board.vue +++ b/apps/web/src/oj/classroom/board.vue @@ -6,6 +6,7 @@ import { useTone } from "oj/submission/composables/tone" import { groupClassOptions } from "oj/submission/utils" import UserName from "shared/components/UserName.vue" import { useLeaveStudents } from "shared/composables/leaveStudents" +import { useTeacherHelp } from "shared/composables/teacherHelp" import { useCollabStore } from "shared/store/collab" import { useConfigStore } from "shared/store/config" import type { LessonLanguage } from "@oj2/contract" @@ -40,9 +41,18 @@ const message = useMessage() const theme = useThemeVars() const tone = useTone() const router = useRouter() +const route = useRoute() +const { help, peek } = useTeacherHelp() const board = ref(null) -const className = ref(null) +/** + * 带着 ?className= 进来的(协作条「帮完了」回来、举手面板「讲这道题」)就看那个班, + * 否则第一次由后端猜 + */ +const queryText = (value: unknown) => (typeof value === "string" && value ? value : null) +const className = ref(queryText(route.query.className)) +/** ?problem= 带来的题号:加载完选中那道题,下面展开它的错法(「讲这道题」) */ +let wantedProblem = queryText(route.query.problem) const classOptions = computed(() => { const list = configStore.config?.classList ?? [] @@ -56,6 +66,12 @@ async function load() { board.value = data // 第一次由后端猜,之后就固定在这个班上,别每次刷新都换 className.value = data.className + if (wantedProblem) { + const wanted = wantedProblem.toLowerCase() + const hit = data.problems.find((item) => item.problemDisplayId.toLowerCase() === wanted) + if (hit) selectedId.value = hit.problemId + wantedProblem = null + } } catch (error) { message.error(errorMessage(error)) } @@ -69,6 +85,26 @@ function changeClass(value: string) { } onMounted(load) +// 已经停在看板上时又从举手面板点了「讲这道题」:同一条路由只换 query,组件不重建 +watch( + () => route.query, + (query) => { + wantedProblem = queryText(query.problem) + const next = queryText(query.className) + if (next && next !== className.value) { + className.value = next + editing.value = false + } + load() + }, +) + +/** 举手多久了,每秒走一格 */ +const now = useNow({ scheduler: (cb) => useIntervalFn(cb, 1000) }) +function waitedText(createdAt: number) { + const seconds = Math.max(0, Math.floor((now.value.getTime() - createdAt) / 1000)) + return `${Math.floor(seconds / 60)}:${String(seconds % 60).padStart(2, "0")}` +} const { pause } = useIntervalFn(load, REFRESH_MS) onUnmounted(pause) @@ -637,6 +673,7 @@ function shortTitle(title: string, size: number) { 学生 + 在写