|
|
@@ -3909,6 +3909,31 @@ const getMessages = (msgObj: any) => {
|
|
|
sendMessage({ slideIndex: curIndex, courseid: props.courseid, type: 'slideIndex' })
|
|
|
console.log('🔗 老师响应 class_begin,回发 slideIndex:', curIndex)
|
|
|
}
|
|
|
+
|
|
|
+ // ★ 老师收到学生的计时器查询后,若本地计时器仍在显示,按当前真实进度重发状态
|
|
|
+ // (学生刷新后服务器持久化不可靠,老师内存状态才是权威数据源)
|
|
|
+ if (msgObj.type === 'timer_query' && isCreator.value && props.type === '1') {
|
|
|
+ if (timerIndicator.value.visible) {
|
|
|
+ const now = Date.now()
|
|
|
+ let payload: { isCountdown: boolean; startAt: string; durationSec?: number }
|
|
|
+ if (timerIndicator.value.isCountdown) {
|
|
|
+ // 倒计时:以"现在"为锚点、当前剩余为时长重发,学生端按锚点重算即得正确剩余
|
|
|
+ const remain = Math.max(Number(timerIndicator.value.remainingSec || 0), 0)
|
|
|
+ payload = { isCountdown: true, startAt: new Date(now).toISOString(), durationSec: remain }
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ // 秒表:锚点回推已计时长,学生端从正确进度继续
|
|
|
+ const elapsed = Math.max(Number(timerIndicator.value.elapsedSec || 0), 0)
|
|
|
+ payload = { isCountdown: false, startAt: new Date(now - elapsed * 1000).toISOString() }
|
|
|
+ }
|
|
|
+ sendMessage({ type: 'timer_start', courseid: props.courseid, payload: JSON.stringify(payload) })
|
|
|
+ // 本地处于暂停态(tick 未运行且未结束)→ 补发 pause,让学生端停在同一剩余值
|
|
|
+ if (!timerInterval.value && !timerIndicator.value.finished) {
|
|
|
+ sendMessage({ type: 'timer_pause', courseid: props.courseid })
|
|
|
+ }
|
|
|
+ console.log('⏱️ 老师响应 timer_query,重发计时器状态:', payload)
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -4154,6 +4179,8 @@ onMounted(() => {
|
|
|
'10. provider synced': providerSocket.value?.synced,
|
|
|
'11. ws.readyState': providerSocket.value?.ws?.readyState,
|
|
|
'12. messageV3?.get("slideIndex")': msgV3Type?.get?.('slideIndex'),
|
|
|
+ '13. yTimerMesssage': doc.getArray('timerMessages'),
|
|
|
+ '14. timerState':docSocket.value.getMap('timerState')
|
|
|
}
|
|
|
console.log('════════ Yjs 诊断 ════════')
|
|
|
for (const [k, v] of Object.entries(report)) {
|
|
|
@@ -4542,6 +4569,11 @@ const createWebSocketConnection = async (type = 1) => {
|
|
|
getMessages(slideIndex)
|
|
|
}
|
|
|
}
|
|
|
+ // ★ 学生 sync 完成后主动向老师查询计时器状态
|
|
|
+ // (服务器持久化不可靠时,由老师内存状态重发,保证刷新后接着跑)
|
|
|
+ if (props.type === '2') {
|
|
|
+ sendMessage({ type: 'timer_query', courseid: props.courseid })
|
|
|
+ }
|
|
|
}
|
|
|
catch (e) {
|
|
|
console.warn('sync 兜底恢复失败', e)
|
|
|
@@ -4577,16 +4609,7 @@ const createWebSocketConnection = async (type = 1) => {
|
|
|
console.log('📨 解析业务消息:', obj)
|
|
|
// 简化判断逻辑:writingBoard 类型永远跳过 getMessages;
|
|
|
// timer 类型仅在非创建人时才走 getMessages;其余类型一律走 getMessages
|
|
|
- const isWritingBoard = writingBoardTypes.includes(obj.type)
|
|
|
- const isTimer = timerTypes.includes(obj.type)
|
|
|
- if (isTimer && !isCreator.value) {
|
|
|
- getMessages(obj)
|
|
|
- return
|
|
|
- }
|
|
|
- if (!isWritingBoard) {
|
|
|
- getMessages(obj)
|
|
|
- return
|
|
|
- }
|
|
|
+ getMessages(obj)
|
|
|
}
|
|
|
|
|
|
// ★ 消息处理后检查特殊消息数组长度,超出则清理(替代 observe 里的清理逻辑)
|