Skip to content

Commit 3aa8217

Browse files
committed
fix: node swap bug
1 parent 0742f73 commit 3aa8217

4 files changed

Lines changed: 50 additions & 19 deletions

File tree

packages/multi-person-collaboration/src/config/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ export const ROOT_SCHEMA_MAP = 'schema'
66

77
// 在监听器中需要被忽略的变更
88
export const IGNORE_OBSERVER_ORIGIN = 'YOUR_IGNORE_PATCHES'
9+
10+
// 内部 Yjs 键值,不能映射到 schema 上
11+
export const INTERNAL_YJS_KEYS = ['meta', '_methods_deleted', '_node_deleted']

packages/multi-person-collaboration/src/operation/operationHandler .ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,38 @@ export class OperationHandler {
191191
const targetIndex = childrenArray.toArray().findIndex((node) => node.get('id') === targetId)
192192
if (targetIndex === -1) return
193193

194-
const swapIndex = direction === 'up' ? targetIndex - 1 : targetIndex + 1
195-
if (swapIndex < 0 || swapIndex >= childrenArray.length) return
194+
let swapIndex = direction === 'up' ? targetIndex - 1 : targetIndex + 1
195+
196+
// 判断 swapIndex 索引所在的节点是否是已删除节点
197+
while (swapIndex >= 0 && swapIndex < childrenArray.length) {
198+
const swapNode = childrenArray.get(swapIndex)
199+
const isDelete = swapNode.get('_node_deleted') === true || swapNode.get('_node_deleted') === 'true'
200+
201+
if (!isDelete) {
202+
// 不是被删除节点,停止循环
203+
break
204+
}
205+
206+
// 如果是被删除节点,则继续往前找或往后找
207+
swapIndex = direction === 'up' ? swapIndex - 1 : swapIndex + 1
208+
}
209+
210+
if (swapIndex < 0 || swapIndex >= childrenArray.length) {
211+
// eslint-disable-next-line no-console
212+
console.warn(`[Move] No valid swap target found for direction: ${direction}`)
213+
return
214+
}
196215

197216
// 调用交换函数
198-
this.swapYArrayElements(childrenArray, targetIndex, swapIndex, parentId, targetId, direction)
217+
this.swapYArrayElements(
218+
childrenArray,
219+
targetIndex,
220+
swapIndex,
221+
parentId,
222+
targetId,
223+
childrenArray.get(swapIndex).get('id'),
224+
direction
225+
)
199226
}
200227

201228
// 修改节点样式
@@ -376,6 +403,7 @@ export class OperationHandler {
376403
index2: number,
377404
parentId: string | undefined,
378405
schemaId: string,
406+
swapId: string,
379407
direction: 'down' | 'up'
380408
): void {
381409
if (index1 === index2 || index1 < 0 || index2 < 0 || index1 >= yarray.length || index2 >= yarray.length) {
@@ -393,6 +421,7 @@ export class OperationHandler {
393421
direction,
394422
parentId,
395423
schemaId,
424+
swapId,
396425
targetIndex: index1,
397426
swapIndex: index2,
398427
timestamp: Date.now()

packages/multi-person-collaboration/src/services/schemaManager.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type { RootNode, UpdateAttributesRole } from '../type'
66
import { fromYjs, sanitizeSchema, toYjs } from '../utils'
77
import { toRaw } from 'vue'
88
import type { YjsProvider } from './providerManager'
9-
import { IGNORE_OBSERVER_ORIGIN, ROOT_SCHEMA_MAP } from '../config'
9+
import { IGNORE_OBSERVER_ORIGIN, INTERNAL_YJS_KEYS, ROOT_SCHEMA_MAP } from '../config'
1010

1111
type DiffPatch =
1212
| { type: 'add' | 'update' | 'delete'; path: (string | number)[]; value?: any }
@@ -27,11 +27,9 @@ type DiffPatch =
2727
| { type: 'methods-delete'; path: (string | number)[]; nodeId: string; methodsName: string }
2828
| {
2929
type: 'array-swap'
30-
direction: 'down' | 'up'
3130
parentId: string | undefined
3231
schemaId: string
33-
targetIndex: number
34-
swapIndex: number
32+
swapId: string
3533
}
3634
| {
3735
type: 'methods-add-node'
@@ -126,7 +124,6 @@ export class SchemaManager {
126124
// eslint-disable-next-line no-console
127125
console.log(`[${docName}] Remote has data. Importing remote schema to UI.`)
128126
const rawRemoteSchema = fromYjs(yMap!)
129-
const INTERNAL_YJS_KEYS = ['meta', '_methods_deleted', '_node_deleted', 'newNode']
130127
const cleanSchema = sanitizeSchema(rawRemoteSchema, INTERNAL_YJS_KEYS)
131128
useCanvas().importSchema(cleanSchema)
132129
}
@@ -199,13 +196,10 @@ export class SchemaManager {
199196
if (payload && payload.op === 'move') {
200197
const patch: DiffPatch = {
201198
type: 'array-swap',
202-
direction: payload.direction,
203199
parentId: payload.parentId,
204-
schemaId: payload.schemeId,
205-
targetIndex: payload.targetIndex,
206-
swapIndex: payload.swapIndex
200+
schemaId: payload.schemaId,
201+
swapId: payload.swapId
207202
}
208-
209203
this.applyPatches(docName, [patch])
210204
} else if (payload && payload.op === 'insert') {
211205
const patch: DiffPatch = {
@@ -422,10 +416,15 @@ export class SchemaManager {
422416
const parentNode = patch.parentId ? useCanvas().getNode(patch.parentId, false) : useCanvas().getPageSchema()
423417
const childrenArray: any[] = parentNode.children
424418

425-
if (patch.targetIndex > -1 && patch.swapIndex < childrenArray.length) {
426-
;[childrenArray[patch.targetIndex], childrenArray[patch.swapIndex]] = [
427-
childrenArray[patch.swapIndex],
428-
childrenArray[patch.targetIndex]
419+
// 通过 Id 找到需要交换位置两个节点的索引
420+
const targetIndex = childrenArray.findIndex((node) => node.id === patch.schemaId)
421+
const swapIndex = childrenArray.findIndex((node) => node.id === patch.swapId)
422+
423+
// 交换位置
424+
if (targetIndex > -1 && swapIndex < childrenArray.length) {
425+
;[childrenArray[targetIndex], childrenArray[swapIndex]] = [
426+
childrenArray[swapIndex],
427+
childrenArray[targetIndex]
429428
]
430429
}
431430

packages/multi-person-collaboration/src/utils/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ export const getValueByPath = (obj: any, path: (string | number)[]): any => {
9494
* @param keysToFilter - 一个包含需要被移除的键名的数组。
9595
* @returns 一个只包含纯 UI 数据的、干净的 schema 对象。
9696
*/
97-
export function sanitizeSchema(schema: any, keysToFilter: string[]): any {
97+
export function sanitizeSchema(schema: any, keysToFilter?: string[]): any {
9898
if (typeof schema !== 'object' || schema === null) {
9999
return schema
100100
}
@@ -112,7 +112,7 @@ export function sanitizeSchema(schema: any, keysToFilter: string[]): any {
112112
const sanitizedObject: { [key: string]: any } = {}
113113
const originalKeys = Object.keys(schema) // 保留原对象的键顺序
114114
for (const key of originalKeys) {
115-
if (keysToFilter.includes(key)) continue
115+
if (keysToFilter?.includes(key)) continue
116116
const child = sanitizeSchema(schema[key], keysToFilter)
117117
if (child !== undefined) {
118118
sanitizedObject[key] = child

0 commit comments

Comments
 (0)