|
|
@@ -419,7 +419,7 @@
|
|
|
</template>
|
|
|
|
|
|
<script lang="ts" setup>
|
|
|
-import { computed, ref, onMounted, onUnmounted, nextTick, inject, watch, provide } from 'vue'
|
|
|
+import { computed, ref, onMounted, onUnmounted, nextTick, inject, watch, provide, shallowRef } from 'vue'
|
|
|
import { storeToRefs } from 'pinia'
|
|
|
import { useSlidesStore } from '@/store'
|
|
|
import { ElementTypes } from '@/types/slides'
|
|
|
@@ -1068,6 +1068,7 @@ onUnmounted(() => {
|
|
|
aiBtn.removeEventListener('pointerup', handleAiBtnPointerUp)
|
|
|
aiBtn.removeEventListener('pointercancel', handleAiBtnPointerCancel)
|
|
|
}
|
|
|
+ cleanupWebSocketConnection()
|
|
|
})
|
|
|
|
|
|
const visibleAIChat = ref(false)
|
|
|
@@ -1119,8 +1120,15 @@ const currentIsResultArray = computed(() => {
|
|
|
// 跳转到指定幻灯片
|
|
|
const goToSlide = (index: number) => {
|
|
|
console.log('goToSlide 被调用,目标索引:', index)
|
|
|
- console.log('当前索引:', slideIndex.value)
|
|
|
-
|
|
|
+ console.log('当前索引:', slideIndex.value, 'slides长度:', slides.value.length)
|
|
|
+
|
|
|
+ // slides 还没加载完时,暂存目标索引,等 slides 就绪后再跳转
|
|
|
+ if (slides.value.length === 0) {
|
|
|
+ console.warn('goToSlide: slides 未加载,暂存目标索引:', index)
|
|
|
+ pendingSlideIndex.value = index
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
if (index >= 0 && index < slides.value.length) {
|
|
|
slidesStore.updateSlideIndex(index)
|
|
|
console.log('更新后的索引:', slideIndex.value)
|
|
|
@@ -1130,6 +1138,20 @@ const goToSlide = (index: number) => {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// 暂存的目标幻灯片索引(slides 未就绪时使用)
|
|
|
+const pendingSlideIndex = ref<number | null>(null)
|
|
|
+// slides 加载完成后应用暂存的跳转
|
|
|
+watch(() => slides.value.length, (len) => {
|
|
|
+ if (len > 0 && pendingSlideIndex.value !== null) {
|
|
|
+ const idx = pendingSlideIndex.value
|
|
|
+ pendingSlideIndex.value = null
|
|
|
+ if (idx >= 0 && idx < len) {
|
|
|
+ console.log('🔄 slides 就绪,应用暂存的跳转索引:', idx)
|
|
|
+ slidesStore.updateSlideIndex(idx)
|
|
|
+ }
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
// 上一页
|
|
|
const previousSlide = () => {
|
|
|
if (slideIndex.value > 0) {
|
|
|
@@ -3182,7 +3204,7 @@ const setCan = (Array: any[]) => {
|
|
|
}
|
|
|
|
|
|
const forceLogout = () => {
|
|
|
- // cleanupWebSocketConnection()
|
|
|
+ cleanupWebSocketConnection()
|
|
|
sendMessage({ type: 'logout' })
|
|
|
}
|
|
|
|
|
|
@@ -3211,158 +3233,141 @@ const checkIsCreator = () => {
|
|
|
* 初始化消息监听
|
|
|
*/
|
|
|
const messageInit = () => {
|
|
|
- if (!docSocket.value) return
|
|
|
+ const doc = docSocket.value
|
|
|
+ if (!doc) return
|
|
|
+
|
|
|
+ // ★ 关键:判断当前绑定的共享类型是否属于这个 doc
|
|
|
+ // y-websocket 内部重连复用同一个 doc → observe 仍有效,直接返回(避免重复 observe)
|
|
|
+ // 只有 doc 被销毁重建(full reconnect)时才全部重新绑定
|
|
|
+ const boundDoc = (yMessage.value as any)?.doc
|
|
|
+ if (boundDoc === doc) {
|
|
|
+ // 同 doc 重连:补发上线消息即可
|
|
|
+ if (props.type === '2') {
|
|
|
+ sendMessage({ type: 'class_begin', courseid: props.courseid })
|
|
|
+ }
|
|
|
+ return
|
|
|
+ }
|
|
|
|
|
|
- // 初始化普通消息数组(只保留最后一条)
|
|
|
- if (!yMessage.value) {
|
|
|
- console.log('初始化普通消息Map')
|
|
|
- // 必须使用 messageV2:服务器上旧的 message 是 Array 根类型,
|
|
|
- // 同名再 getMap 会导致根类型冲突、后注册的被改名,observe 间歇性失效
|
|
|
- yMessage.value = docSocket.value.getMap('messageV2')
|
|
|
- yMessage.value.observe((e: any) => {
|
|
|
- // Map 的 observe 事件中 keysChanged 包含被更新的 key
|
|
|
- if (e.keysChanged.has('latest')) {
|
|
|
- const message = yMessage.value.get('latest')
|
|
|
- console.log('yMessage', message)
|
|
|
- if (message && message.mId !== mId.value) {
|
|
|
- getMessages(message)
|
|
|
- }
|
|
|
- }
|
|
|
- })
|
|
|
+ console.log('🔗 检测到新 Y.Doc,重新绑定所有共享数据监听')
|
|
|
+
|
|
|
+ // ★ 先把旧 doc 上的引用全部置空,杜绝守卫误判指向旧 doc
|
|
|
+ yMessage.value = null
|
|
|
+ yTimerState.value = null
|
|
|
+ yLaserState.value = null
|
|
|
+ yWritingBoardState.value = null
|
|
|
+ yTimerMessages.value = null
|
|
|
+ yLaserMessages.value = null
|
|
|
+ yWritingBoardMessages.value = null
|
|
|
+ yIsResultArrayMessages.value = null
|
|
|
+
|
|
|
+ // 普通消息(Map,只保留最后一条)
|
|
|
+ // 必须使用 messageV2:服务器上旧的 message 是 Array 根类型,
|
|
|
+ // 同名再 getMap 会导致根类型冲突、后注册的被改名,observe 间歇性失效
|
|
|
+ yMessage.value = doc.getMap('messageV2')
|
|
|
+ yMessage.value.observe((e: any) => {
|
|
|
+ // 同时兼容 keysChanged 和 changes.keys(不同 Yjs 版本/事件结构)
|
|
|
+ const changed = e.keysChanged || e.changes?.keys
|
|
|
+ if (!changed || !changed.has('latest')) return
|
|
|
+ const message = yMessage.value!.get('latest')
|
|
|
+ console.log('yMessage', message)
|
|
|
+ if (message && message.mId !== mId.value) {
|
|
|
+ getMessages(message)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ // ★ 追平:连接建立后立即读取当前 latest,
|
|
|
+ // 防止老师在学生 observe 注册之前发的消息丢失(尤其是当前所在幻灯片)
|
|
|
+ const latest = yMessage.value.get('latest')
|
|
|
+ if (latest && latest.mId !== mId.value) {
|
|
|
+ console.log('🔗 追平当前 latest 消息:', latest)
|
|
|
+ getMessages(latest)
|
|
|
}
|
|
|
|
|
|
- // 初始化计时器消息数组
|
|
|
- if (!yTimerMessages.value) {
|
|
|
- console.log('初始化计时器消息数组')
|
|
|
- yTimerMessages.value = docSocket.value.getArray('timerMessages')
|
|
|
-
|
|
|
- // 初始化时检查一次是否需要清理
|
|
|
- if (yTimerMessages.value && yTimerMessages.value.length > 500 && isCreator.value && docSocket.value) {
|
|
|
- smartCleanupMessages(yTimerMessages.value, 500, 'timer', docSocket.value)
|
|
|
+ // 计时器消息数组
|
|
|
+ yTimerMessages.value = doc.getArray('timerMessages')
|
|
|
+ // 初始化时检查一次是否需要清理
|
|
|
+ if (yTimerMessages.value.length > 500 && isCreator.value) {
|
|
|
+ smartCleanupMessages(yTimerMessages.value, 500, 'timer', doc)
|
|
|
+ }
|
|
|
+ yTimerMessages.value.observe((e: any) => {
|
|
|
+ if (yTimerMessages.value.length > 500 && isCreator.value) {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (yTimerMessages.value && yTimerMessages.value.length > 500) {
|
|
|
+ smartCleanupMessages(yTimerMessages.value, 500, 'timer', doc)
|
|
|
+ }
|
|
|
+ }, 0)
|
|
|
}
|
|
|
-
|
|
|
- yTimerMessages.value.observe((e: any) => {
|
|
|
- console.log('yTimerMessages', yTimerMessages.value.length)
|
|
|
- console.log('yTimerMessages', yTimerMessages.value)
|
|
|
-
|
|
|
- // 每次有新消息添加后,检查是否需要清理
|
|
|
- if (yTimerMessages.value && yTimerMessages.value.length > 500 && isCreator.value && docSocket.value) {
|
|
|
- // 使用 setTimeout 确保在 observe 回调执行完成后再清理
|
|
|
- setTimeout(() => {
|
|
|
- if (docSocket.value && yTimerMessages.value && yTimerMessages.value.length > 500) {
|
|
|
- smartCleanupMessages(yTimerMessages.value, 500, 'timer', docSocket.value)
|
|
|
- }
|
|
|
- }, 0)
|
|
|
+ e.changes.added.forEach((i: any) => {
|
|
|
+ const message = i.content.getContent()[0]
|
|
|
+ if (message.mId !== mId.value) {
|
|
|
+ getMessages(message)
|
|
|
}
|
|
|
-
|
|
|
- e.changes.added.forEach((i: any) => {
|
|
|
- const message = i.content.getContent()[0]
|
|
|
- if (message.mId !== mId.value) {
|
|
|
- getMessages(message)
|
|
|
- }
|
|
|
- })
|
|
|
})
|
|
|
- }
|
|
|
+ })
|
|
|
|
|
|
- // 初始化激光笔消息数组
|
|
|
- if (!yLaserMessages.value) {
|
|
|
- console.log('初始化激光笔消息数组')
|
|
|
- yLaserMessages.value = docSocket.value.getArray('laserMessages')
|
|
|
-
|
|
|
- // 初始化时检查一次是否需要清理
|
|
|
- if (yLaserMessages.value && yLaserMessages.value.length > 500 && isCreator.value && docSocket.value) {
|
|
|
- smartCleanupMessages(yLaserMessages.value, 500, 'laser', docSocket.value)
|
|
|
+ // 激光笔消息数组
|
|
|
+ yLaserMessages.value = doc.getArray('laserMessages')
|
|
|
+ if (yLaserMessages.value.length > 500 && isCreator.value) {
|
|
|
+ smartCleanupMessages(yLaserMessages.value, 500, 'laser', doc)
|
|
|
+ }
|
|
|
+ yLaserMessages.value.observe((e: any) => {
|
|
|
+ if (yLaserMessages.value.length > 500 && isCreator.value) {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (yLaserMessages.value && yLaserMessages.value.length > 500) {
|
|
|
+ smartCleanupMessages(yLaserMessages.value, 500, 'laser', doc)
|
|
|
+ }
|
|
|
+ }, 0)
|
|
|
}
|
|
|
-
|
|
|
- yLaserMessages.value.observe((e: any) => {
|
|
|
- console.log('yLaserMessages', yLaserMessages.value.length)
|
|
|
- console.log('yLaserMessages', yLaserMessages.value)
|
|
|
-
|
|
|
- // 每次有新消息添加后,检查是否需要清理
|
|
|
- if (yLaserMessages.value && yLaserMessages.value.length > 500 && isCreator.value && docSocket.value) {
|
|
|
- // 使用 setTimeout 确保在 observe 回调执行完成后再清理
|
|
|
- setTimeout(() => {
|
|
|
- if (docSocket.value && yLaserMessages.value && yLaserMessages.value.length > 500) {
|
|
|
- smartCleanupMessages(yLaserMessages.value, 500, 'laser', docSocket.value)
|
|
|
- }
|
|
|
- }, 0)
|
|
|
+ e.changes.added.forEach((i: any) => {
|
|
|
+ const message = i.content.getContent()[0]
|
|
|
+ // 只处理开关消息,位置消息直接通过 Map 同步
|
|
|
+ if (message.type === 'laser_toggle' && message.mId !== mId.value) {
|
|
|
+ getMessages(message)
|
|
|
}
|
|
|
-
|
|
|
- e.changes.added.forEach((i: any) => {
|
|
|
- const message = i.content.getContent()[0]
|
|
|
- // 只处理开关消息,位置消息直接通过 Map 同步
|
|
|
- if (message.type === 'laser_toggle' && message.mId !== mId.value) {
|
|
|
- getMessages(message)
|
|
|
- }
|
|
|
- })
|
|
|
})
|
|
|
- }
|
|
|
+ })
|
|
|
|
|
|
- // 初始化画图消息数组
|
|
|
- if (!yWritingBoardMessages.value) {
|
|
|
- console.log('初始化画图消息数组')
|
|
|
- yWritingBoardMessages.value = docSocket.value.getArray('writingBoardMessages')
|
|
|
-
|
|
|
- // 初始化时检查一次是否需要清理
|
|
|
- if (yWritingBoardMessages.value && yWritingBoardMessages.value.length > 500 && isCreator.value && docSocket.value) {
|
|
|
- smartCleanupMessages(yWritingBoardMessages.value, 500, 'writingBoard', docSocket.value)
|
|
|
+ // 画图消息数组
|
|
|
+ yWritingBoardMessages.value = doc.getArray('writingBoardMessages')
|
|
|
+ if (yWritingBoardMessages.value.length > 500 && isCreator.value) {
|
|
|
+ smartCleanupMessages(yWritingBoardMessages.value, 500, 'writingBoard', doc)
|
|
|
+ }
|
|
|
+ yWritingBoardMessages.value.observe((e: any) => {
|
|
|
+ if (yWritingBoardMessages.value.length > 500 && isCreator.value) {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (yWritingBoardMessages.value && yWritingBoardMessages.value.length > 500) {
|
|
|
+ smartCleanupMessages(yWritingBoardMessages.value, 500, 'writingBoard', doc)
|
|
|
+ }
|
|
|
+ }, 0)
|
|
|
}
|
|
|
-
|
|
|
- yWritingBoardMessages.value.observe((e: any) => {
|
|
|
- console.log('yWritingBoardMessages', yWritingBoardMessages.value.length)
|
|
|
- console.log('yWritingBoardMessages', yWritingBoardMessages.value)
|
|
|
-
|
|
|
- // 每次有新消息添加后,检查是否需要清理
|
|
|
- if (yWritingBoardMessages.value && yWritingBoardMessages.value.length > 500 && isCreator.value && docSocket.value) {
|
|
|
- // 使用 setTimeout 确保在 observe 回调执行完成后再清理
|
|
|
- setTimeout(() => {
|
|
|
- if (docSocket.value && yWritingBoardMessages.value && yWritingBoardMessages.value.length > 500) {
|
|
|
- smartCleanupMessages(yWritingBoardMessages.value, 500, 'writingBoard', docSocket.value)
|
|
|
- }
|
|
|
- }, 0)
|
|
|
+ e.changes.added.forEach((i: any) => {
|
|
|
+ const message = i.content.getContent()[0]
|
|
|
+ if (message.mId !== mId.value) {
|
|
|
+ getMessages(message)
|
|
|
}
|
|
|
-
|
|
|
- e.changes.added.forEach((i: any) => {
|
|
|
- const message = i.content.getContent()[0]
|
|
|
- if (message.mId !== mId.value) {
|
|
|
- getMessages(message)
|
|
|
- }
|
|
|
- })
|
|
|
})
|
|
|
- }
|
|
|
-
|
|
|
- if (!yIsResultArrayMessages.value) {
|
|
|
- console.log('初始化isResultArray消息数组')
|
|
|
- yIsResultArrayMessages.value = docSocket.value.getArray('isResultArrayMessages')
|
|
|
+ })
|
|
|
|
|
|
- // 初始化时检查一次是否需要清理
|
|
|
- if (yIsResultArrayMessages.value && yIsResultArrayMessages.value.length > 1 && isCreator.value && docSocket.value) {
|
|
|
- smartCleanupMessages(yIsResultArrayMessages.value, 1, 'isResultArray', docSocket.value)
|
|
|
+ // isResultArray 消息数组
|
|
|
+ yIsResultArrayMessages.value = doc.getArray('isResultArrayMessages')
|
|
|
+ if (yIsResultArrayMessages.value.length > 1 && isCreator.value) {
|
|
|
+ smartCleanupMessages(yIsResultArrayMessages.value, 1, 'isResultArray', doc)
|
|
|
+ }
|
|
|
+ yIsResultArrayMessages.value.observe((e: any) => {
|
|
|
+ if (yIsResultArrayMessages.value.length > 1 && isCreator.value) {
|
|
|
+ setTimeout(() => {
|
|
|
+ if (yIsResultArrayMessages.value && yIsResultArrayMessages.value.length > 1) {
|
|
|
+ smartCleanupMessages(yIsResultArrayMessages.value, 1, 'isResultArray', doc)
|
|
|
+ }
|
|
|
+ }, 0)
|
|
|
}
|
|
|
-
|
|
|
- yIsResultArrayMessages.value.observe((e: any) => {
|
|
|
- console.log('yIsResultArrayMessages', yIsResultArrayMessages.value.length)
|
|
|
- console.log('yIsResultArrayMessages', yIsResultArrayMessages.value)
|
|
|
-
|
|
|
- // 每次有新消息添加后,检查是否需要清理
|
|
|
- if (yIsResultArrayMessages.value && yIsResultArrayMessages.value.length > 1 && isCreator.value && docSocket.value) {
|
|
|
- // 使用 setTimeout 确保在 observe 回调执行完成后再清理
|
|
|
- setTimeout(() => {
|
|
|
- if (docSocket.value && yIsResultArrayMessages.value && yIsResultArrayMessages.value.length > 1) {
|
|
|
- smartCleanupMessages(yIsResultArrayMessages.value, 1, 'isResultArray', docSocket.value)
|
|
|
- }
|
|
|
- }, 0)
|
|
|
+ e.changes.added.forEach((i: any) => {
|
|
|
+ const message = i.content.getContent()[0]
|
|
|
+ if (message.mId !== mId.value) {
|
|
|
+ getMessages(message)
|
|
|
}
|
|
|
-
|
|
|
- e.changes.added.forEach((i: any) => {
|
|
|
- const message = i.content.getContent()[0]
|
|
|
- if (message.mId !== mId.value) {
|
|
|
- getMessages(message)
|
|
|
- }
|
|
|
- })
|
|
|
})
|
|
|
-
|
|
|
- }
|
|
|
+ })
|
|
|
|
|
|
// 如果是首次进入且是创建者,清空所有同步状态
|
|
|
if (isFirstEnter.value && isCreator.value && docSocket.value) {
|
|
|
@@ -3407,66 +3412,54 @@ const messageInit = () => {
|
|
|
// 标记已不再是首次进入
|
|
|
isFirstEnter.value = false
|
|
|
}
|
|
|
- // 初始化计时器状态 Map 并监听
|
|
|
- if (docSocket.value && !yTimerState.value) {
|
|
|
- yTimerState.value = docSocket.value.getMap('timerState')
|
|
|
- // 初始状态同步(后加入用户会立即拿到当前 map 值)
|
|
|
- const snapshot = yTimerState.value.toJSON()
|
|
|
- applyTimerStateSnapshot(snapshot)
|
|
|
- // 监听变化
|
|
|
- yTimerState.value.observe((event: any) => {
|
|
|
- const snap = yTimerState.value.toJSON()
|
|
|
- applyTimerStateSnapshot(snap)
|
|
|
- })
|
|
|
- }
|
|
|
- // 初始化激光笔状态 Map 并监听
|
|
|
- if (docSocket.value && !yLaserState.value) {
|
|
|
- yLaserState.value = docSocket.value.getMap('laserState')
|
|
|
- const lsnap = yLaserState.value.toJSON()
|
|
|
- applyLaserStateSnapshot(lsnap)
|
|
|
- yLaserState.value.observe(() => {
|
|
|
- const s = yLaserState.value.toJSON()
|
|
|
- applyLaserStateSnapshot(s)
|
|
|
- })
|
|
|
- }
|
|
|
- // 初始化画图状态 Map 并监听
|
|
|
- if (docSocket.value && !yWritingBoardState.value) {
|
|
|
- yWritingBoardState.value = docSocket.value.getMap('writingBoardState')
|
|
|
- const wsnap = yWritingBoardState.value.toJSON()
|
|
|
- console.log('📝 初始化画图状态Map,快照:', wsnap, '当前幻灯片:', currentSlide.value?.id)
|
|
|
- // 延迟应用,确保 currentSlide 已初始化
|
|
|
- nextTick(() => {
|
|
|
- // 如果 currentSlide 还没准备好,再等一帧
|
|
|
- if (currentSlide.value && currentSlide.value.id) {
|
|
|
- applyWritingBoardStateSnapshot(wsnap)
|
|
|
- }
|
|
|
- else {
|
|
|
- // 如果还没准备好,等待 currentSlide 变化(最多等待3秒)
|
|
|
- let timeoutId: any = null
|
|
|
- const unwatch = watch(() => currentSlide.value?.id, (slideId) => {
|
|
|
- if (slideId) {
|
|
|
- applyWritingBoardStateSnapshot(wsnap)
|
|
|
- unwatch()
|
|
|
- if (timeoutId) clearTimeout(timeoutId)
|
|
|
- }
|
|
|
- }, { immediate: true })
|
|
|
- // 3秒后如果还没准备好,强制应用一次
|
|
|
- timeoutId = setTimeout(() => {
|
|
|
- if (currentSlide.value && currentSlide.value.id) {
|
|
|
- applyWritingBoardStateSnapshot(wsnap)
|
|
|
- }
|
|
|
+ // 计时器状态 Map 并监听
|
|
|
+ yTimerState.value = doc.getMap('timerState')
|
|
|
+ // 初始状态同步(后加入用户会立即拿到当前 map 值)
|
|
|
+ applyTimerStateSnapshot(yTimerState.value.toJSON())
|
|
|
+ yTimerState.value.observe(() => {
|
|
|
+ applyTimerStateSnapshot(yTimerState.value!.toJSON())
|
|
|
+ })
|
|
|
+
|
|
|
+ // 激光笔状态 Map 并监听
|
|
|
+ yLaserState.value = doc.getMap('laserState')
|
|
|
+ applyLaserStateSnapshot(yLaserState.value.toJSON())
|
|
|
+ yLaserState.value.observe(() => {
|
|
|
+ applyLaserStateSnapshot(yLaserState.value!.toJSON())
|
|
|
+ })
|
|
|
+
|
|
|
+ // 画图状态 Map 并监听
|
|
|
+ yWritingBoardState.value = doc.getMap('writingBoardState')
|
|
|
+ const wsnap = yWritingBoardState.value.toJSON()
|
|
|
+ console.log('📝 初始化画图状态Map,快照:', wsnap, '当前幻灯片:', currentSlide.value?.id)
|
|
|
+ nextTick(() => {
|
|
|
+ if (currentSlide.value && currentSlide.value.id) {
|
|
|
+ applyWritingBoardStateSnapshot(wsnap)
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ let timeoutId: any = null
|
|
|
+ const unwatch = watch(() => currentSlide.value?.id, (slideId) => {
|
|
|
+ if (slideId) {
|
|
|
+ applyWritingBoardStateSnapshot(wsnap)
|
|
|
unwatch()
|
|
|
- }, 3000)
|
|
|
- }
|
|
|
- })
|
|
|
- yWritingBoardState.value.observe(() => {
|
|
|
- const s = yWritingBoardState.value.toJSON()
|
|
|
- if (currentSlide.value && currentSlide.value.id) {
|
|
|
- applyWritingBoardStateSnapshot(s)
|
|
|
- }
|
|
|
- })
|
|
|
- }
|
|
|
+ if (timeoutId) clearTimeout(timeoutId)
|
|
|
+ }
|
|
|
+ }, { immediate: true })
|
|
|
+ timeoutId = setTimeout(() => {
|
|
|
+ if (currentSlide.value && currentSlide.value.id) {
|
|
|
+ applyWritingBoardStateSnapshot(wsnap)
|
|
|
+ }
|
|
|
+ unwatch()
|
|
|
+ }, 3000)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ yWritingBoardState.value.observe(() => {
|
|
|
+ const s = yWritingBoardState.value!.toJSON()
|
|
|
+ if (currentSlide.value && currentSlide.value.id) {
|
|
|
+ applyWritingBoardStateSnapshot(s)
|
|
|
+ }
|
|
|
+ })
|
|
|
|
|
|
+ // 新 doc 绑定完成,补发上线消息
|
|
|
if (props.type === '2') {
|
|
|
sendMessage({ type: 'class_begin', courseid: props.courseid })
|
|
|
}
|
|
|
@@ -4263,7 +4256,7 @@ const cleanupWebSocketConnection = () => {
|
|
|
}
|
|
|
|
|
|
// ★ 关键:doc 已销毁,必须把绑定在旧 doc 上的共享类型引用全部置空,
|
|
|
- // 否则重连后 messageInit() 的 if (!yXxx.value) 守卫会跳过绑定,
|
|
|
+ // 否则重连后 messadocSocket.value.guid === yMessazeInit() 的 if (!yXxx.value) 守卫会跳过绑定,
|
|
|
// 新 doc 收到更新时 observe 回调不会触发(表现为突然收不到消息)
|
|
|
yMessage.value = null
|
|
|
yTimerState.value = null
|