feat: 监控和讲解增加心跳
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
Some checks failed
CI / Test (ubuntu-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Lint (ubuntu-latest) (push) Has been cancelled
CI / Lint (windows-latest) (push) Has been cancelled
CI / Check (ubuntu-latest) (push) Has been cancelled
CI / Check (windows-latest) (push) Has been cancelled
CI / CI OK (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
Deploy Website on push / Deploy Push Playground Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Docs Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Antd Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Element Ftp (push) Has been cancelled
Deploy Website on push / Deploy Push Naive Ftp (push) Has been cancelled
Deploy Website on push / Rerun on failure (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
This commit is contained in:
parent
228ee4ba68
commit
07ec772e9b
@ -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()
|
||||
|
||||
@ -89,6 +89,13 @@ class TaskMgrService extends BasicService {
|
||||
return await post<any>(`/school/questionExplain/share`, data)
|
||||
}
|
||||
|
||||
// 题目讲解心跳
|
||||
async questionExplainHeartbeat(classId: string) {
|
||||
return await post<any>(
|
||||
`/school/questionExplain/heartbeat?classId=${encodeURIComponent(classId)}`,
|
||||
)
|
||||
}
|
||||
|
||||
// 获取试卷详情
|
||||
// async getpaperReleaseRecordDetail(recordId: any) {
|
||||
// return await get<any>(`/school/paperReleaseRecord/get/${recordId}`)
|
||||
|
||||
@ -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<typeof setInterval> | undefined
|
||||
let heartbeatTimer: ReturnType<typeof setInterval> | 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 = []
|
||||
|
||||
@ -1,5 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, onActivated, onBeforeUnmount, onMounted, ref } from 'vue'
|
||||
import {
|
||||
computed,
|
||||
onActivated,
|
||||
onBeforeUnmount,
|
||||
onDeactivated,
|
||||
onMounted,
|
||||
ref,
|
||||
} from 'vue'
|
||||
import { useRoute, useRouter } from 'vue-router'
|
||||
|
||||
import { taskMgrService } from '#/api/service/question-bank/task-mgr'
|
||||
@ -80,6 +87,7 @@ onMounted(() => {
|
||||
})
|
||||
|
||||
onActivated(() => {
|
||||
stopQuestionExplainHeartbeat()
|
||||
phase.value = 'detail'
|
||||
countdown.value = 3
|
||||
currentIndex.value = 0
|
||||
@ -92,6 +100,8 @@ type ExplainPhase = 'countdown' | 'detail' | 'explaining'
|
||||
const phase = ref<ExplainPhase>('detail')
|
||||
const countdown = ref(3)
|
||||
let countdownTimer: null | ReturnType<typeof setInterval> = null
|
||||
const QUESTION_EXPLAIN_HEARTBEAT_INTERVAL = 60 * 1000
|
||||
let questionExplainHeartbeatTimer: ReturnType<typeof setInterval> | undefined
|
||||
|
||||
function startCountdown() {
|
||||
document.documentElement.requestFullscreen?.().catch(() => {})
|
||||
@ -121,6 +131,11 @@ function clearCountdownTimer() {
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
clearCountdownTimer()
|
||||
stopQuestionExplainHeartbeat()
|
||||
})
|
||||
|
||||
onDeactivated(() => {
|
||||
stopQuestionExplainHeartbeat()
|
||||
})
|
||||
|
||||
// ======================== 拖动分隔条 ========================
|
||||
@ -260,12 +275,34 @@ async function enterExplaining() {
|
||||
collapseAnswerAnalysis()
|
||||
phase.value = 'explaining'
|
||||
currentIndex.value = 0
|
||||
await callExplainApi(1)
|
||||
const started = await callExplainApi(1)
|
||||
if (started) {
|
||||
startQuestionExplainHeartbeat()
|
||||
}
|
||||
}
|
||||
|
||||
function startQuestionExplainHeartbeat() {
|
||||
if (questionExplainHeartbeatTimer) return
|
||||
questionExplainHeartbeatTimer = setInterval(() => {
|
||||
if (phase.value !== 'explaining' || !classId) {
|
||||
stopQuestionExplainHeartbeat()
|
||||
return
|
||||
}
|
||||
void taskMgrService
|
||||
.questionExplainHeartbeat(classId)
|
||||
.catch(() => undefined)
|
||||
}, QUESTION_EXPLAIN_HEARTBEAT_INTERVAL)
|
||||
}
|
||||
|
||||
function stopQuestionExplainHeartbeat() {
|
||||
if (!questionExplainHeartbeatTimer) return
|
||||
clearInterval(questionExplainHeartbeatTimer)
|
||||
questionExplainHeartbeatTimer = undefined
|
||||
}
|
||||
|
||||
async function callExplainApi(status: number, overrideQuestionId?: string) {
|
||||
const questionId = overrideQuestionId || getTitleKey(currentQuestion.value)
|
||||
if (!questionId) return
|
||||
if (!questionId) return false
|
||||
const recordId = resourceId
|
||||
try {
|
||||
await taskMgrService.questionExplainShare({
|
||||
@ -274,8 +311,10 @@ async function callExplainApi(status: number, overrideQuestionId?: string) {
|
||||
recordId,
|
||||
status,
|
||||
})
|
||||
return true
|
||||
} catch {
|
||||
hud.error(status === 1 ? '开始讲解失败' : '结束讲解失败')
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@ -307,6 +346,7 @@ function endExplaining() {
|
||||
title: '提示',
|
||||
zIndex: 999_999,
|
||||
onConfirm: async () => {
|
||||
stopQuestionExplainHeartbeat()
|
||||
const lastQuestion = paperDetail.value[paperDetail.value.length - 1]
|
||||
const lastQuestionId = getTitleKey(lastQuestion)
|
||||
await callExplainApi(0, lastQuestionId)
|
||||
|
||||
@ -34,7 +34,7 @@ export default defineConfig(async () => {
|
||||
proxy: {
|
||||
'/api': {
|
||||
target: 'http://43.136.52.196:9053',
|
||||
// target: 'https://admin.xuexiaole.com',
|
||||
// target: 'https://admin.lingxixue.com',
|
||||
changeOrigin: true,
|
||||
},
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user