Преглед на файлове

feat(tree): 节点序号错乱的情况下支持正常上下移

vian преди 3 години
родител
ревизия
43949d633b
променени са 3 файла, в които са добавени 85 реда и са изтрити 1 реда
  1. 1 1
      tree/package.json
  2. 47 0
      tree/src/tree.ts
  3. 37 0
      tree/tests/tree.ts

+ 1 - 1
tree/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@sc/tree",
-  "version": "1.0.20",
+  "version": "1.0.21",
   "description": "通用树",
   "main": "./dist/index.cjs.js",
   "module": "./dist/index.esm.js",

+ 47 - 0
tree/src/tree.ts

@@ -432,6 +432,43 @@ export class Tree<T extends TreeRaw = TreeRaw> {
     return deleteNodes;
   }
 
+  // 检查节点是否有相同顺序号的错误情况(协作的时候可能导致)
+  checkSeq(nodes: TreeNode<T>[]) {
+    const seqList: number[] = nodes.map(node => node.seq);
+    const seqSet = new Set(seqList);
+    return seqList.length === seqSet.size;
+  }
+
+  // 序号错乱了,移动的时候,只能重新排编号
+  prepareSpecialMove(
+    allNodes: TreeNode<T>[],
+    sourceNodes: TreeNode<T>[],
+    targetNode: TreeNode<T>
+  ): UpdateData[] {
+    const fisrtNodeIdx = allNodes.indexOf(sourceNodes[0]);
+    const targetNodeIdx = allNodes.indexOf(targetNode);
+    const position = fisrtNodeIdx > targetNodeIdx ? 'prev' : 'next';
+    const nodes = []; // 防止改了原始数组顺序
+    for (const node of allNodes) {
+      if (!sourceNodes.includes(node)) {
+        nodes.push(node);
+      }
+    }
+    const targetIdx = nodes.indexOf(targetNode);
+    if (position === 'prev') {
+      // 插到targetNode前面
+      nodes.splice(targetIdx, 0, ...sourceNodes);
+    } else {
+      // 插到targetNode后面
+      nodes.splice(targetIdx + 1, 0, ...sourceNodes);
+    }
+    // 重新编码
+    return nodes.map((node, index) => ({
+      ID: node.ID,
+      update: { seq: index },
+    }));
+  }
+
   // 准备上移节点块(连续的兄弟节点),注意节点的seq可能不连号
   prepareUpMove(nodes: TreeNode<T>[]): UpdateData[] {
     const updateData: UpdateData[] = [];
@@ -440,6 +477,11 @@ export class Tree<T extends TreeRaw = TreeRaw> {
     if (!firstNodePrev) {
       return [];
     }
+    const brothers = firstNode.getCtx().brothers();
+    if (!this.checkSeq(brothers)) {
+      // 存在序号异常情况,需要特殊处理
+      return this.prepareSpecialMove(brothers, nodes, firstNodePrev);
+    }
     let tempSeq = firstNodePrev.seq;
     nodes.forEach(node => {
       const orgSeq = node.seq;
@@ -464,6 +506,11 @@ export class Tree<T extends TreeRaw = TreeRaw> {
     if (!lastNodeNext) {
       return [];
     }
+    const brothers = lastNode.getCtx().brothers();
+    if (!this.checkSeq(brothers)) {
+      // 存在序号异常情况,需要特殊处理
+      return this.prepareSpecialMove(brothers, nodes, lastNodeNext);
+    }
     let tempSeq = lastNodeNext.seq;
     for (let i = nodes.length - 1; i >= 0; i--) {
       const node = nodes[i];

+ 37 - 0
tree/tests/tree.ts

@@ -248,6 +248,25 @@ describe('Tree change', () => {
     expect(node3).to.have.property('seq', 4);
   });
 
+  it('specialUpMove', () => {
+    const tree = new Tree([
+      { ID: '1', parentID: '-1', seq: 1 },
+      { ID: '2', parentID: '-1', seq: 2 },
+      { ID: '3', parentID: '-1', seq: 2 },
+      { ID: '4', parentID: '-1', seq: 2 },
+      { ID: '5', parentID: '-1', seq: 5 },
+    ]);
+    const nodes = [tree.find('3'), tree.find('4')];
+    const updateData = tree.prepareUpMove(nodes as TreeNode[]);
+    tree.move(nodes as TreeNode[], updateData);
+    const IDList = getIDList(tree.data);
+    expect(IDList).to.have.ordered.members(['1', '3', '4', '2', '5']);
+    expect(nodes[0]).to.have.property('seq', 1);
+    expect(nodes[1]).to.have.property('seq', 2);
+    const node3 = tree.find('1');
+    expect(node3).to.have.property('seq', 0);
+  });
+
   it('downMove', () => {
     const tree = new Tree(cloneDeep(rawData));
     const nodes = [tree.find('3'), tree.find('2')];
@@ -271,6 +290,24 @@ describe('Tree change', () => {
     expect(node4).to.have.property('seq', 2);
   });
 
+  it('specialDownMove', () => {
+    const tree = new Tree([
+      { ID: '1', parentID: '-1', seq: 1 },
+      { ID: '2', parentID: '-1', seq: 2 },
+      { ID: '3', parentID: '-1', seq: 2 },
+      { ID: '4', parentID: '-1', seq: 4 },
+      { ID: '5', parentID: '-1', seq: 5 },
+    ]);
+    const nodes = [tree.find('2')];
+    const updateData = tree.prepareDownMove(nodes as TreeNode[]);
+    tree.move(nodes as TreeNode[], updateData);
+    const IDList = getIDList(tree.data);
+    expect(IDList).to.have.ordered.members(['1', '3', '2', '4', '5']);
+    expect(nodes[0]).to.have.property('seq', 2);
+    const node3 = tree.find('3');
+    expect(node3).to.have.property('seq', 1);
+  });
+
   it('single-upLevel', () => {
     const tree = new Tree(cloneDeep(complicatedRawData));
     const node10 = tree.find('10');