This commit is contained in:
2025-10-05 16:30:18 +08:00
parent 98785d6419
commit de21261b1b
3 changed files with 61 additions and 23 deletions

View File

@@ -3,6 +3,7 @@ import { copyToClipboard } from "~/utils/functions"
import { code, input, output } from "oj/composables/code" import { code, input, output } from "oj/composables/code"
import { problem } from "oj/composables/problem" import { problem } from "oj/composables/problem"
import { injectSyncStatus } from "oj/composables/syncStatus" import { injectSyncStatus } from "oj/composables/syncStatus"
import { SYNC_MESSAGES } from "~/shared/composables/sync"
import { LANGUAGE_SHOW_VALUE, SOURCES, STORAGE_KEY } from "utils/constants" import { LANGUAGE_SHOW_VALUE, SOURCES, STORAGE_KEY } from "utils/constants"
import { isDesktop, isMobile } from "~/shared/composables/breakpoints" import { isDesktop, isMobile } from "~/shared/composables/breakpoints"
import { useUserStore } from "~/shared/store/user" import { useUserStore } from "~/shared/store/user"
@@ -185,7 +186,7 @@ defineExpose({
? 'streamline-stickies-color:earpod-connected' ? 'streamline-stickies-color:earpod-connected'
: 'streamline-stickies-color:earpod-connected-duo' : 'streamline-stickies-color:earpod-connected-duo'
" "
:tip="syncEnabled ? '断开同步' : '打开同步'" :tip="syncEnabled ? SYNC_MESSAGES.SYNC_ON : SYNC_MESSAGES.SYNC_OFF"
:type="syncEnabled ? 'info' : 'default'" :type="syncEnabled ? 'info' : 'default'"
@click="toggleSync" @click="toggleSync"
/> />
@@ -193,13 +194,13 @@ defineExpose({
<!-- 同步状态标签 --> <!-- 同步状态标签 -->
<template v-if="props.isConnected"> <template v-if="props.isConnected">
<n-tag v-if="syncStatus.otherUser.value" type="info"> <n-tag v-if="syncStatus.otherUser.value" type="info">
{{ syncStatus.otherUser.value.name }} 同步中 {{ SYNC_MESSAGES.SYNCING_WITH(syncStatus.otherUser.value.name) }}
</n-tag> </n-tag>
<n-tag <n-tag
v-if="userStore.isSuperAdmin && !syncStatus.otherUser.value && syncStatus.hadConnection.value" v-if="userStore.isSuperAdmin && !syncStatus.otherUser.value && syncStatus.hadConnection.value"
type="warning" type="warning"
> >
学生已退出可以关闭同步 {{ SYNC_MESSAGES.STUDENT_LEFT }}
</n-tag> </n-tag>
</template> </template>
</template> </template>

View File

@@ -7,7 +7,7 @@ import type { Extension } from "@codemirror/state"
import { LANGUAGE } from "~/utils/types" import { LANGUAGE } from "~/utils/types"
import { oneDark } from "../themes/oneDark" import { oneDark } from "../themes/oneDark"
import { smoothy } from "../themes/smoothy" import { smoothy } from "../themes/smoothy"
import { useCodeSync } from "../composables/sync" import { useCodeSync, SYNC_ERROR_CODES } from "../composables/sync"
import { isDesktop } from "../composables/breakpoints" import { isDesktop } from "../composables/breakpoints"
interface EditorReadyPayload { interface EditorReadyPayload {
@@ -88,7 +88,8 @@ const initSync = async () => {
onStatusChange: (status) => { onStatusChange: (status) => {
// 处理需要断开同步的情况 // 处理需要断开同步的情况
if ( if (
(status.error === "超管已离开" || status.error === "缺少超级管理员") (status.errorCode === SYNC_ERROR_CODES.SUPER_ADMIN_LEFT ||
status.errorCode === SYNC_ERROR_CODES.MISSING_SUPER_ADMIN)
&& !status.connected && !status.connected
) { ) {
emit("syncClosed") emit("syncClosed")

View File

@@ -13,8 +13,40 @@ const SYNC_CONSTANTS = {
REGULAR_USER_COLOR: "#4dabf7", REGULAR_USER_COLOR: "#4dabf7",
} as const } as const
// 错误类型码
export const SYNC_ERROR_CODES = {
SUPER_ADMIN_LEFT: "SUPER_ADMIN_LEFT",
MISSING_SUPER_ADMIN: "MISSING_SUPER_ADMIN",
} as const
// 界面和通知文案
export const SYNC_MESSAGES = {
// 超管离开
SUPER_ADMIN_LEFT: (name: string) => `👋 超管 ${name} 已离开`,
// 缺少超管
MISSING_SUPER_ADMIN: "⚠️ 协同编辑需要超管",
// 连接成功
SYNC_ACTIVE: "✅ 协同编辑已激活!",
// 连接断开
CONNECTION_LOST: "⚠️ 协同编辑已断开",
// 等待相关
WAITING_STUDENT: "⏳ 正在等待学生加入...",
WAITING_ADMIN: "⏳ 正在等待超管加入...",
// Form.vue 界面文案
SYNC_ON: "断开同步",
SYNC_OFF: "开启同步",
SYNCING_WITH: (name: string) => `🔗 与 ${name} 同步中`,
STUDENT_LEFT: "💡 可以关闭同步",
} as const
// 类型定义 // 类型定义
type SyncState = "waiting" | "active" | "error" type SyncState = "waiting" | "active" | "error"
type SyncErrorCode = typeof SYNC_ERROR_CODES[keyof typeof SYNC_ERROR_CODES]
interface UserInfo { interface UserInfo {
name: string name: string
@@ -45,6 +77,7 @@ export interface SyncStatus {
canSync: boolean canSync: boolean
message: string message: string
error?: string error?: string
errorCode?: SyncErrorCode
otherUser?: UserInfo otherUser?: UserInfo
} }
@@ -108,17 +141,19 @@ export function useCodeSync() {
if (superAdminInfo) { if (superAdminInfo) {
hasShownSuperAdminLeftMessage = true hasShownSuperAdminLeftMessage = true
const leftMessage = SYNC_MESSAGES.SUPER_ADMIN_LEFT(superAdminInfo.name)
updateStatus( updateStatus(
{ {
connected: false, connected: false,
roomUsers: 0, roomUsers: 0,
canSync: false, canSync: false,
message: `超管 ${superAdminInfo.name} 已离开`, message: leftMessage,
error: "超管已离开", error: leftMessage,
errorCode: SYNC_ERROR_CODES.SUPER_ADMIN_LEFT,
}, },
onStatusChange, onStatusChange,
) )
message.warning(`超管 ${superAdminInfo.name} 已离开`) message.warning(leftMessage)
stopSync() stopSync()
} }
} }
@@ -142,13 +177,14 @@ export function useCodeSync() {
connected: false, connected: false,
roomUsers, roomUsers,
canSync: false, canSync: false,
message: "房间内必须有一个超级管理员", message: SYNC_MESSAGES.MISSING_SUPER_ADMIN,
error: "缺少超级管理员", error: SYNC_MESSAGES.MISSING_SUPER_ADMIN,
errorCode: SYNC_ERROR_CODES.MISSING_SUPER_ADMIN,
otherUser, otherUser,
}, },
onStatusChange, onStatusChange,
) )
message.error("协同编辑需要一位超管") message.error(SYNC_MESSAGES.MISSING_SUPER_ADMIN)
lastSyncState = "error" lastSyncState = "error"
stopSync() stopSync()
return return
@@ -158,13 +194,13 @@ export function useCodeSync() {
connected: true, connected: true,
roomUsers, roomUsers,
canSync: true, canSync: true,
message: "协同编辑已激活!", message: SYNC_MESSAGES.SYNC_ACTIVE,
otherUser, otherUser,
}, },
onStatusChange, onStatusChange,
) )
if (lastSyncState !== "active") { if (lastSyncState !== "active") {
message.success("协同编辑已激活!") message.success(SYNC_MESSAGES.SYNC_ACTIVE)
lastSyncState = "active" lastSyncState = "active"
} }
} else { } else {
@@ -174,7 +210,7 @@ export function useCodeSync() {
roomUsers, roomUsers,
canSync: false, canSync: false,
message: message:
roomUsers === 1 ? "正在等待小伙伴加入..." : "等待超级管理员加入...", roomUsers === 1 ? SYNC_MESSAGES.WAITING_STUDENT : SYNC_MESSAGES.WAITING_ADMIN,
otherUser, otherUser,
}, },
onStatusChange, onStatusChange,
@@ -241,12 +277,12 @@ export function useCodeSync() {
connected: false, connected: false,
roomUsers: 0, roomUsers: 0,
canSync: false, canSync: false,
message: "连接已断开", message: SYNC_MESSAGES.CONNECTION_LOST,
error: "WebRTC 连接断开", error: SYNC_MESSAGES.CONNECTION_LOST,
}, },
onStatusChange, onStatusChange,
) )
message.warning("协同编辑连接已断开") message.warning(SYNC_MESSAGES.CONNECTION_LOST)
} }
}) })
@@ -311,21 +347,21 @@ export function useCodeSync() {
setupContentSync(ytext, provider, savedContent) setupContentSync(ytext, provider, savedContent)
// 设置初始状态 // 设置初始状态
const waitingMessage = userStore.isSuperAdmin
? SYNC_MESSAGES.WAITING_STUDENT
: SYNC_MESSAGES.WAITING_ADMIN
updateStatus( updateStatus(
{ {
connected: true, connected: true,
roomUsers: 1, roomUsers: 1,
canSync: false, canSync: false,
message: "协同编辑已准备就绪,等待伙伴加入...", message: waitingMessage,
}, },
onStatusChange, onStatusChange,
) )
message.info( message.info(waitingMessage)
userStore.isSuperAdmin
? "正在等待学生加入..."
: "正在等待超管加入...",
)
lastSyncState = "waiting" lastSyncState = "waiting"
} }