From 18227e29ada5222ffaf4c45ccbc5636b8b6172a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=E4=BA=86=E4=B8=AAJ?= Date: Tue, 12 May 2026 20:33:39 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E6=94=AF=E6=8C=81=E5=B1=8F?= =?UTF-8?q?=E5=B9=95=E5=85=B1=E4=BA=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- playground/src/types/global.d.ts | 6 + .../src/views/org/classroom-monitor/home.vue | 117 ++++++++++++------ 2 files changed, 82 insertions(+), 41 deletions(-) diff --git a/playground/src/types/global.d.ts b/playground/src/types/global.d.ts index 80ea773..c200f44 100644 --- a/playground/src/types/global.d.ts +++ b/playground/src/types/global.d.ts @@ -4,6 +4,12 @@ interface Window { requests: any[] tokenRefreshing: boolean unique: number + /** teacher-electron 注入,仅在桌面客户端内嵌题库页时存在 */ + teacherApi?: { + startSfu: () => Promise<{ port: number; already?: boolean }> + stopSfu: () => Promise + openScreenShareWindow: () => Promise + } } interface Option { diff --git a/playground/src/views/org/classroom-monitor/home.vue b/playground/src/views/org/classroom-monitor/home.vue index eefab9b..180c100 100644 --- a/playground/src/views/org/classroom-monitor/home.vue +++ b/playground/src/views/org/classroom-monitor/home.vue @@ -166,7 +166,10 @@ async function updateMonitorStatus(status: 0 | 1) { const option = status === 1 ? '开启' : '停止' controlLoading.value = true try { - await classroomMonitorService.updateMonitorStatus(selectedClass.value.id, status) + await classroomMonitorService.updateMonitorStatus( + selectedClass.value.id, + status, + ) hud.success(`${option}监控成功`) await loadMonitorDetail(selectedClass.value.id) } finally { @@ -206,10 +209,13 @@ async function loadSessions() { if (!selectedClass.value?.id) return sessionsLoading.value = true try { - const data = await classroomMonitorService.getSessions(selectedClass.value.id, { - current: sessionsPage.current, - size: sessionsPage.size, - }) + const data = await classroomMonitorService.getSessions( + selectedClass.value.id, + { + current: sessionsPage.current, + size: sessionsPage.size, + }, + ) sessionsRows.value = data?.rows ?? [] sessionsPage.total = data?.totalRows ?? 0 } finally { @@ -244,10 +250,27 @@ function formatTime(time?: number | string) { if (!time) return '-' const timestamp = Number(time) if (Number.isNaN(timestamp)) return String(time) - const date = new Date(String(timestamp).length === 10 ? timestamp * 1000 : timestamp) + const date = new Date( + String(timestamp).length === 10 ? timestamp * 1000 : timestamp, + ) if (Number.isNaN(date.getTime())) return String(time) return date.toLocaleString() } + +/** teacher-electron 注入:打开独立屏幕共享窗口 */ +async function openTeacherScreenShareWindow() { + const api = window.teacherApi + if (!api?.openScreenShareWindow) { + ElMessage.warning('请在教师端桌面客户端中使用「共享屏幕」') + return + } + try { + await api.openScreenShareWindow() + } catch (e) { + console.error(e) + ElMessage.error('打开屏幕共享窗口失败') + } +} @@ -273,9 +305,7 @@ function formatTime(time?: number | string) { :type="item.monitorState === 1 ? 'success' : 'info'" size="small" > - {{ - item.monitorState === 1 ? '监控开启' : '监控关闭' - }} + {{ item.monitorState === 1 ? '监控开启' : '监控关闭' }} @@ -283,7 +313,10 @@ function formatTime(time?: number | string) { - + @@ -297,6 +330,9 @@ function formatTime(time?: number | string) {
返回班级列表 历史监控 + + 共享屏幕 + @@ -476,16 +516,11 @@ function formatTime(time?: number | string) { :preview-src-list="studentSnapshotPreviewList" :src="item.url" /> -
- 截图时间:{{ formatTime(item.ts) }} -
+
截图时间:{{ formatTime(item.ts) }}
- + @@ -500,21 +535,21 @@ function formatTime(time?: number | string) { .card-header { display: flex; + gap: 16px; align-items: center; justify-content: space-between; - gap: 16px; } .page-title { - color: #1f2937; font-size: 20px; font-weight: 600; + color: #1f2937; } .page-desc { margin-top: 6px; - color: #6b7280; font-size: 14px; + color: #6b7280; } .header-actions { @@ -540,16 +575,16 @@ function formatTime(time?: number | string) { .class-row-info { display: flex; - align-items: center; - gap: 12px; flex-wrap: wrap; + gap: 12px; + align-items: center; min-width: 0; } .class-name { - color: #111827; font-size: 16px; font-weight: 500; + color: #111827; } .monitor-detail { @@ -558,8 +593,8 @@ function formatTime(time?: number | string) { .status-panel { display: flex; - align-items: center; gap: 24px; + align-items: center; padding: 16px; margin-bottom: 18px; background: #f8fafc; @@ -568,19 +603,19 @@ function formatTime(time?: number | string) { > div { display: flex; - align-items: center; gap: 8px; + align-items: center; } strong { - color: #111827; font-weight: 600; + color: #111827; } } .status-label { - color: #6b7280; font-size: 14px; + color: #6b7280; } .snapshot-header { @@ -591,21 +626,21 @@ function formatTime(time?: number | string) { } .section-title { - color: #111827; font-size: 16px; font-weight: 600; + color: #111827; } .snapshot-grid { display: grid; - min-height: 220px; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; + min-height: 220px; } .snapshot-card { - cursor: pointer; overflow: hidden; + cursor: pointer; transition: border-color 0.2s, box-shadow 0.2s; @@ -637,14 +672,14 @@ function formatTime(time?: number | string) { } .student-name { - color: #111827; font-weight: 600; + color: #111827; } .student-meta { margin-top: 4px; - color: #6b7280; font-size: 12px; + color: #6b7280; } .student-snapshot-dialog { @@ -653,8 +688,8 @@ function formatTime(time?: number | string) { .student-snapshot-summary { display: flex; - align-items: center; gap: 12px; + align-items: center; padding-bottom: 16px; margin-bottom: 16px; border-bottom: 1px solid #edf0f5; @@ -681,14 +716,14 @@ function formatTime(time?: number | string) { } .sessions-table { - cursor: pointer; width: 100%; + cursor: pointer; } .sessions-pagination { - margin-top: 16px; display: flex; justify-content: flex-end; + margin-top: 16px; } } @@ -711,8 +746,8 @@ function formatTime(time?: number | string) { } .status-panel { - align-items: flex-start; flex-direction: column; + align-items: flex-start; } } } @@ -722,8 +757,8 @@ function formatTime(time?: number | string) { .card-header, .class-row, .snapshot-header { - align-items: stretch; flex-direction: column; + align-items: stretch; } .header-actions {