From 07ec772e9b58ac0fa8d45dd31596fbf964c26ed2 Mon Sep 17 00:00:00 2001 From: shawko Date: Mon, 11 May 2026 18:29:55 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E7=9B=91=E6=8E=A7=E5=92=8C=E8=AE=B2?= =?UTF-8?q?=E8=A7=A3=E5=A2=9E=E5=8A=A0=E5=BF=83=E8=B7=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/api/service/org/classroom-monitor.ts | 6 +++ .../src/api/service/question-bank/task-mgr.ts | 7 +++ .../src/views/org/classroom-monitor/home.vue | 26 +++++++++++ .../question-bank/task-mgr/paper-explain.vue | 46 +++++++++++++++++-- playground/vite.config.mts | 2 +- 5 files changed, 83 insertions(+), 4 deletions(-) diff --git a/playground/src/api/service/org/classroom-monitor.ts b/playground/src/api/service/org/classroom-monitor.ts index 099b0d4..e05c1d7 100644 --- a/playground/src/api/service/org/classroom-monitor.ts +++ b/playground/src/api/service/org/classroom-monitor.ts @@ -144,6 +144,12 @@ class ClassroomMonitorService { status, }) } + + async heartbeat(classId: number | string) { + return await post( + `/school/classMonitor/heartbeat?classId=${encodeURIComponent(String(classId))}`, + ) + } } export const classroomMonitorService = new ClassroomMonitorService() diff --git a/playground/src/api/service/question-bank/task-mgr.ts b/playground/src/api/service/question-bank/task-mgr.ts index 4b17147..e89a092 100644 --- a/playground/src/api/service/question-bank/task-mgr.ts +++ b/playground/src/api/service/question-bank/task-mgr.ts @@ -89,6 +89,13 @@ class TaskMgrService extends BasicService { return await post(`/school/questionExplain/share`, data) } + // 题目讲解心跳 + async questionExplainHeartbeat(classId: string) { + return await post( + `/school/questionExplain/heartbeat?classId=${encodeURIComponent(classId)}`, + ) + } + // 获取试卷详情 // async getpaperReleaseRecordDetail(recordId: any) { // return await get(`/school/paperReleaseRecord/get/${recordId}`) diff --git a/playground/src/views/org/classroom-monitor/home.vue b/playground/src/views/org/classroom-monitor/home.vue index f2be80d..eefab9b 100644 --- a/playground/src/views/org/classroom-monitor/home.vue +++ b/playground/src/views/org/classroom-monitor/home.vue @@ -43,7 +43,9 @@ const studentSnapshotPreviewList = computed(() => { return studentSnapshots.value.map((item) => item.url).filter(Boolean) }) const SNAPSHOT_REFRESH_INTERVAL = 5000 +const MONITOR_HEARTBEAT_INTERVAL = 60 * 1000 let snapshotRefreshTimer: ReturnType | undefined +let heartbeatTimer: ReturnType | undefined onMounted(() => { loadClassList() @@ -51,6 +53,7 @@ onMounted(() => { onBeforeUnmount(() => { stopSnapshotAutoRefresh() + stopMonitorHeartbeat() }) async function loadClassList() { @@ -64,6 +67,7 @@ async function loadClassList() { async function handleViewMonitor(item: ClassroomItem) { stopSnapshotAutoRefresh() + stopMonitorHeartbeat() selectedClass.value = item currentMonitor.value = undefined snapshots.value = [] @@ -79,8 +83,10 @@ async function loadMonitorDetail(classId = selectedClass.value?.id) { if (data?.monitoring) { await loadSnapshots(classId) startSnapshotAutoRefresh() + startMonitorHeartbeat() } else { stopSnapshotAutoRefresh() + stopMonitorHeartbeat() snapshots.value = [] } } finally { @@ -130,12 +136,31 @@ function startSnapshotAutoRefresh() { }, SNAPSHOT_REFRESH_INTERVAL) } +function startMonitorHeartbeat() { + if (heartbeatTimer) return + heartbeatTimer = setInterval(() => { + if (!isMonitoring.value || !selectedClass.value?.id) { + stopMonitorHeartbeat() + return + } + void classroomMonitorService + .heartbeat(selectedClass.value.id) + .catch(() => undefined) + }, MONITOR_HEARTBEAT_INTERVAL) +} + function stopSnapshotAutoRefresh() { if (!snapshotRefreshTimer) return clearInterval(snapshotRefreshTimer) snapshotRefreshTimer = undefined } +function stopMonitorHeartbeat() { + if (!heartbeatTimer) return + clearInterval(heartbeatTimer) + heartbeatTimer = undefined +} + async function updateMonitorStatus(status: 0 | 1) { if (!selectedClass.value?.id) return const option = status === 1 ? '开启' : '停止' @@ -151,6 +176,7 @@ async function updateMonitorStatus(status: 0 | 1) { function backToClassList() { stopSnapshotAutoRefresh() + stopMonitorHeartbeat() selectedClass.value = undefined currentMonitor.value = undefined snapshots.value = [] diff --git a/playground/src/views/question-bank/task-mgr/paper-explain.vue b/playground/src/views/question-bank/task-mgr/paper-explain.vue index c39c613..98c1441 100644 --- a/playground/src/views/question-bank/task-mgr/paper-explain.vue +++ b/playground/src/views/question-bank/task-mgr/paper-explain.vue @@ -1,5 +1,12 @@