fix
This commit is contained in:
51
src/oj/composables/syncStatus.ts
Normal file
51
src/oj/composables/syncStatus.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
// 同步状态管理 composable
|
||||
|
||||
export interface SyncStatusState {
|
||||
otherUser?: { name: string; isSuperAdmin: boolean }
|
||||
hadConnection: boolean
|
||||
}
|
||||
|
||||
// 提供/注入的 key
|
||||
export const SYNC_STATUS_KEY = Symbol('syncStatus')
|
||||
|
||||
// 创建同步状态
|
||||
export function createSyncStatus() {
|
||||
const otherUser = ref<{ name: string; isSuperAdmin: boolean }>()
|
||||
const hadConnection = ref(false)
|
||||
|
||||
const setOtherUser = (user?: { name: string; isSuperAdmin: boolean }) => {
|
||||
otherUser.value = user
|
||||
if (user) {
|
||||
hadConnection.value = true
|
||||
}
|
||||
}
|
||||
|
||||
const reset = () => {
|
||||
otherUser.value = undefined
|
||||
hadConnection.value = false
|
||||
}
|
||||
|
||||
return {
|
||||
otherUser,
|
||||
hadConnection,
|
||||
setOtherUser,
|
||||
reset,
|
||||
}
|
||||
}
|
||||
|
||||
// 提供同步状态
|
||||
export function provideSyncStatus() {
|
||||
const syncStatus = createSyncStatus()
|
||||
provide(SYNC_STATUS_KEY, syncStatus)
|
||||
return syncStatus
|
||||
}
|
||||
|
||||
// 注入同步状态
|
||||
export function injectSyncStatus() {
|
||||
const syncStatus = inject<ReturnType<typeof createSyncStatus>>(SYNC_STATUS_KEY)
|
||||
if (!syncStatus) {
|
||||
throw new Error('syncStatus must be provided by a parent component')
|
||||
}
|
||||
return syncStatus
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import { copyToClipboard } from "~/utils/functions"
|
||||
import { code, input, output } from "oj/composables/code"
|
||||
import { problem } from "oj/composables/problem"
|
||||
import { injectSyncStatus } from "oj/composables/syncStatus"
|
||||
import { LANGUAGE_SHOW_VALUE, SOURCES, STORAGE_KEY } from "utils/constants"
|
||||
import { isDesktop, isMobile } from "~/shared/composables/breakpoints"
|
||||
import { useUserStore } from "~/shared/store/user"
|
||||
@@ -15,17 +16,17 @@ import IconButton from "~/shared/components/IconButton.vue"
|
||||
interface Props {
|
||||
storageKey: string
|
||||
withTest?: boolean
|
||||
otherUserInfo?: { name: string; isSuperAdmin: boolean }
|
||||
isConnected?: boolean // WebSocket 实际的连接状态(已建立/未建立)
|
||||
hadConnection?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
withTest: false,
|
||||
isConnected: false,
|
||||
hadConnection: false,
|
||||
})
|
||||
|
||||
// 注入同步状态
|
||||
const syncStatus = injectSyncStatus()
|
||||
|
||||
const emit = defineEmits<{
|
||||
changeLanguage: [v: LANGUAGE]
|
||||
toggleSync: [v: boolean]
|
||||
@@ -191,11 +192,11 @@ defineExpose({
|
||||
|
||||
<!-- 同步状态标签 -->
|
||||
<template v-if="props.isConnected">
|
||||
<n-tag v-if="otherUserInfo" type="info">
|
||||
与 {{ otherUserInfo.name }} 同步中
|
||||
<n-tag v-if="syncStatus.otherUser.value" type="info">
|
||||
与 {{ syncStatus.otherUser.value.name }} 同步中
|
||||
</n-tag>
|
||||
<n-tag
|
||||
v-if="userStore.isSuperAdmin && !otherUserInfo && hadConnection"
|
||||
v-if="userStore.isSuperAdmin && !syncStatus.otherUser.value && syncStatus.hadConnection.value"
|
||||
type="warning"
|
||||
>
|
||||
学生已退出,可以关闭同步
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script lang="ts" setup>
|
||||
import { code } from "oj/composables/code"
|
||||
import { problem } from "oj/composables/problem"
|
||||
import { provideSyncStatus } from "oj/composables/syncStatus"
|
||||
import { SOURCES } from "utils/constants"
|
||||
import SyncCodeEditor from "~/shared/components/SyncCodeEditor.vue"
|
||||
import { isDesktop } from "~/shared/composables/breakpoints"
|
||||
@@ -12,8 +13,8 @@ const route = useRoute()
|
||||
const formRef = useTemplateRef<InstanceType<typeof Form>>("formRef")
|
||||
|
||||
const sync = ref(false)
|
||||
const otherUserInfo = ref<{ name: string; isSuperAdmin: boolean }>()
|
||||
const hadConnection = ref(false)
|
||||
// 提供同步状态给子组件使用
|
||||
const syncStatus = provideSyncStatus()
|
||||
|
||||
const contestID = route.params.contestID || null
|
||||
const storageKey = computed(
|
||||
@@ -48,24 +49,20 @@ const changeLanguage = (v: LANGUAGE) => {
|
||||
const toggleSync = (value: boolean) => {
|
||||
sync.value = value
|
||||
if (!value) {
|
||||
hadConnection.value = false
|
||||
syncStatus.reset()
|
||||
}
|
||||
}
|
||||
|
||||
const handleSyncClosed = () => {
|
||||
sync.value = false
|
||||
otherUserInfo.value = undefined
|
||||
hadConnection.value = false
|
||||
syncStatus.reset()
|
||||
formRef.value?.resetSyncStatus()
|
||||
}
|
||||
|
||||
const handleSyncStatusChange = (status: {
|
||||
otherUser?: { name: string; isSuperAdmin: boolean }
|
||||
}) => {
|
||||
otherUserInfo.value = status.otherUser
|
||||
if (status.otherUser) {
|
||||
hadConnection.value = true
|
||||
}
|
||||
syncStatus.setOtherUser(status.otherUser)
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -74,9 +71,7 @@ const handleSyncStatusChange = (status: {
|
||||
<Form
|
||||
ref="formRef"
|
||||
:storage-key="storageKey"
|
||||
:other-user-info="otherUserInfo"
|
||||
:is-connected="sync"
|
||||
:had-connection="hadConnection"
|
||||
@change-language="changeLanguage"
|
||||
@toggle-sync="toggleSync"
|
||||
/>
|
||||
|
||||
@@ -86,7 +86,11 @@ const initSync = async () => {
|
||||
problemId: props.problem,
|
||||
editorView: editorView.value as EditorView,
|
||||
onStatusChange: (status) => {
|
||||
if (status.error === "超管已离开" && !status.connected) {
|
||||
// 处理需要断开同步的情况
|
||||
if (
|
||||
(status.error === "超管已离开" || status.error === "缺少超级管理员")
|
||||
&& !status.connected
|
||||
) {
|
||||
emit("syncClosed")
|
||||
}
|
||||
emit("syncStatusChange", { otherUser: status.otherUser })
|
||||
|
||||
@@ -22,8 +22,6 @@ interface UserInfo {
|
||||
}
|
||||
|
||||
interface PeersEvent {
|
||||
added: string[]
|
||||
removed: string[]
|
||||
webrtcPeers: string[]
|
||||
}
|
||||
|
||||
@@ -54,7 +52,6 @@ export function useCodeSync() {
|
||||
const userStore = useUserStore()
|
||||
const message = useMessage()
|
||||
|
||||
// 状态变量
|
||||
let ydoc: Doc | null = null
|
||||
let provider: WebrtcProvider | null = null
|
||||
let ytext: Text | null = null
|
||||
@@ -138,9 +135,11 @@ export function useCodeSync() {
|
||||
const otherUser = getOtherUserInfo(awarenessStates)
|
||||
|
||||
if (roomUsers === SYNC_CONSTANTS.MAX_ROOM_USERS && !hasSuperAdmin) {
|
||||
if (lastSyncState === "error") return
|
||||
|
||||
updateStatus(
|
||||
{
|
||||
connected: true,
|
||||
connected: false,
|
||||
roomUsers,
|
||||
canSync: false,
|
||||
message: "房间内必须有一个超级管理员",
|
||||
@@ -149,23 +148,23 @@ export function useCodeSync() {
|
||||
},
|
||||
onStatusChange,
|
||||
)
|
||||
if (lastSyncState !== "error") {
|
||||
message.warning("协同编辑需要一位超级管理员坐镇哦")
|
||||
lastSyncState = "error"
|
||||
}
|
||||
message.error("协同编辑需要一位超管")
|
||||
lastSyncState = "error"
|
||||
stopSync()
|
||||
return
|
||||
} else if (canSync) {
|
||||
updateStatus(
|
||||
{
|
||||
connected: true,
|
||||
roomUsers,
|
||||
canSync: true,
|
||||
message: "协同编辑已激活,开始愉快的代码之旅吧!",
|
||||
message: "协同编辑已激活!",
|
||||
otherUser,
|
||||
},
|
||||
onStatusChange,
|
||||
)
|
||||
if (lastSyncState !== "active") {
|
||||
message.success("协同编辑已激活,开始愉快的代码之旅吧!")
|
||||
message.success("协同编辑已激活!")
|
||||
lastSyncState = "active"
|
||||
}
|
||||
} else {
|
||||
@@ -224,8 +223,6 @@ export function useCodeSync() {
|
||||
import("y-codemirror.next"),
|
||||
])
|
||||
|
||||
console.log("Yjs 相关模块导入完成")
|
||||
|
||||
// 初始化文档和提供者
|
||||
ydoc = new Y.Doc()
|
||||
ytext = ydoc.getText("codemirror")
|
||||
@@ -257,23 +254,6 @@ export function useCodeSync() {
|
||||
// 监听用户加入/离开
|
||||
provider.on("peers", (event: PeersEvent) => {
|
||||
const roomUsers = event.webrtcPeers.length + 1
|
||||
|
||||
if (roomUsers > SYNC_CONSTANTS.MAX_ROOM_USERS) {
|
||||
updateStatus(
|
||||
{
|
||||
connected: false,
|
||||
roomUsers,
|
||||
canSync: false,
|
||||
message: "房间人数已满,已自动断开连接",
|
||||
error: `房间最多只能有${SYNC_CONSTANTS.MAX_ROOM_USERS}个人`,
|
||||
},
|
||||
onStatusChange,
|
||||
)
|
||||
message.warning(`哎呀,房间已经坐满了,已自动断开连接`)
|
||||
stopSync()
|
||||
return
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
checkRoomPermissions(roomUsers, onStatusChange)
|
||||
}, SYNC_CONSTANTS.AWARENESS_SYNC_DELAY)
|
||||
@@ -344,8 +324,8 @@ export function useCodeSync() {
|
||||
|
||||
message.info(
|
||||
userStore.isSuperAdmin
|
||||
? "正在等待学生加入房间..."
|
||||
: "正在等待超管加入房间...",
|
||||
? "正在等待学生加入..."
|
||||
: "正在等待超管加入...",
|
||||
)
|
||||
lastSyncState = "waiting"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user