fix
This commit is contained in:
@@ -11,6 +11,9 @@
|
|||||||
- [API 文档](#api-文档)
|
- [API 文档](#api-文档)
|
||||||
- [使用示例](#使用示例)
|
- [使用示例](#使用示例)
|
||||||
- [故障排查](#故障排查)
|
- [故障排查](#故障排查)
|
||||||
|
- [使用限制](#使用限制)
|
||||||
|
- [安全考虑](#安全考虑)
|
||||||
|
- [配置](#配置)
|
||||||
|
|
||||||
## 概述
|
## 概述
|
||||||
|
|
||||||
@@ -25,6 +28,7 @@
|
|||||||
- ✅ 权限控制(必须有一个超管)
|
- ✅ 权限控制(必须有一个超管)
|
||||||
- ✅ 房间人数限制(最多 2 人)
|
- ✅ 房间人数限制(最多 2 人)
|
||||||
- ✅ 离线检测和自动清理
|
- ✅ 离线检测和自动清理
|
||||||
|
- 🖥️ 仅支持桌面端(移动端不可用)
|
||||||
|
|
||||||
## 技术栈
|
## 技术栈
|
||||||
|
|
||||||
@@ -617,6 +621,41 @@ setTimeout(() => {
|
|||||||
}, AWARENESS_SYNC_DELAY)
|
}, AWARENESS_SYNC_DELAY)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## 使用限制
|
||||||
|
|
||||||
|
### 平台支持
|
||||||
|
|
||||||
|
协同编辑功能**仅支持桌面端**,移动端不可用。
|
||||||
|
|
||||||
|
**原因:**
|
||||||
|
|
||||||
|
1. **屏幕空间限制**
|
||||||
|
- 移动端屏幕较小,难以同时显示光标位置和多用户状态
|
||||||
|
- 协同编辑的用户信息标签需要足够的显示空间
|
||||||
|
|
||||||
|
2. **交互体验**
|
||||||
|
- 移动端触摸输入与协同编辑的光标跟随机制不够友好
|
||||||
|
- 桌面端的键盘和鼠标操作更适合代码编辑协作
|
||||||
|
|
||||||
|
3. **性能考虑**
|
||||||
|
- WebRTC 连接在移动设备上可能不够稳定
|
||||||
|
- 移动端的网络切换(WiFi/4G/5G)可能影响连接质量
|
||||||
|
|
||||||
|
**检测逻辑:**
|
||||||
|
|
||||||
|
```vue
|
||||||
|
<!-- Form.vue -->
|
||||||
|
<IconButton
|
||||||
|
v-if="isDesktop && userStore.isAuthed"
|
||||||
|
:icon="isSynced ? '...' : '...'"
|
||||||
|
@click="toggleSync"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<template v-if="isDesktop && props.isSynced">
|
||||||
|
<n-tag>同步状态</n-tag>
|
||||||
|
</template>
|
||||||
|
```
|
||||||
|
|
||||||
## 安全考虑
|
## 安全考虑
|
||||||
|
|
||||||
### 1. 权限控制
|
### 1. 权限控制
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ defineExpose({
|
|||||||
@click="toggleSync"
|
@click="toggleSync"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<template v-if="props.isSynced">
|
<template v-if="isDesktop && props.isSynced">
|
||||||
<n-tag v-if="otherUserInfo" type="info">
|
<n-tag v-if="otherUserInfo" type="info">
|
||||||
与 {{ otherUserInfo.name }} 同步中
|
与 {{ otherUserInfo.name }} 同步中
|
||||||
</n-tag>
|
</n-tag>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ 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 } from "../composables/sync"
|
||||||
|
import { isDesktop } from "../composables/breakpoints"
|
||||||
|
|
||||||
interface EditorReadyPayload {
|
interface EditorReadyPayload {
|
||||||
view: EditorView
|
view: EditorView
|
||||||
@@ -59,7 +60,7 @@ const lang = computed((): Extension => {
|
|||||||
return ["Python2", "Python3"].includes(props.language) ? python() : cpp()
|
return ["Python2", "Python3"].includes(props.language) ? python() : cpp()
|
||||||
})
|
})
|
||||||
|
|
||||||
const extensions = computed((): Extension[] => [
|
const extensions = computed(() => [
|
||||||
styleTheme,
|
styleTheme,
|
||||||
lang.value,
|
lang.value,
|
||||||
isDark.value ? oneDark : smoothy,
|
isDark.value ? oneDark : smoothy,
|
||||||
@@ -79,7 +80,7 @@ const cleanupSyncResources = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const initSync = async () => {
|
const initSync = async () => {
|
||||||
if (!editorView.value || !props.problem) return
|
if (!editorView.value || !props.problem || !isDesktop.value) return
|
||||||
|
|
||||||
cleanupSyncResources()
|
cleanupSyncResources()
|
||||||
|
|
||||||
@@ -97,7 +98,7 @@ const initSync = async () => {
|
|||||||
|
|
||||||
const handleEditorReady = (payload: EditorReadyPayload) => {
|
const handleEditorReady = (payload: EditorReadyPayload) => {
|
||||||
editorView.value = payload.view as EditorView
|
editorView.value = payload.view as EditorView
|
||||||
if (props.sync && props.problem) {
|
if (props.sync) {
|
||||||
initSync()
|
initSync()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,7 +106,7 @@ const handleEditorReady = (payload: EditorReadyPayload) => {
|
|||||||
watch(
|
watch(
|
||||||
() => props.sync,
|
() => props.sync,
|
||||||
(shouldSync) => {
|
(shouldSync) => {
|
||||||
if (shouldSync && props.problem && editorView.value) {
|
if (shouldSync) {
|
||||||
initSync()
|
initSync()
|
||||||
} else {
|
} else {
|
||||||
cleanupSyncResources()
|
cleanupSyncResources()
|
||||||
@@ -116,7 +117,7 @@ watch(
|
|||||||
watch(
|
watch(
|
||||||
() => props.problem,
|
() => props.problem,
|
||||||
(newProblem, oldProblem) => {
|
(newProblem, oldProblem) => {
|
||||||
if (newProblem !== oldProblem && props.sync && editorView.value) {
|
if (newProblem !== oldProblem && props.sync) {
|
||||||
initSync()
|
initSync()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -234,6 +234,8 @@ export function useCodeSync() {
|
|||||||
import("y-codemirror.next"),
|
import("y-codemirror.next"),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
console.log("Yjs 相关模块导入完成")
|
||||||
|
|
||||||
// 初始化文档和提供者
|
// 初始化文档和提供者
|
||||||
ydoc = new Y.Doc()
|
ydoc = new Y.Doc()
|
||||||
ytext = ydoc.getText("codemirror")
|
ytext = ydoc.getText("codemirror")
|
||||||
|
|||||||
Reference in New Issue
Block a user