|
|
@@ -4,7 +4,7 @@ export interface TreeRaw {
|
|
|
ID: string;
|
|
|
parentID: string;
|
|
|
seq: number;
|
|
|
- [propName: string]: any;
|
|
|
+ [props: string]: any;
|
|
|
}
|
|
|
|
|
|
export interface TreeNode extends TreeRaw {
|
|
|
@@ -47,7 +47,7 @@ export class Tree {
|
|
|
// 按照树结构拼装好、排好序的数据。实际只是原始数据进行排序,内部元素跟原始数据内部元素的引用是一致的
|
|
|
data: TreeNode[];
|
|
|
|
|
|
- readonly rootID: string = '-1';
|
|
|
+ rootID: string;
|
|
|
|
|
|
// 默认初始顺序号。在对树结构进行操作后,没必要保证seq连号,只需保证正确排序就行,以减少需要更新的节点。
|
|
|
readonly seqStartIndex = 0;
|
|
|
@@ -61,7 +61,8 @@ export class Tree {
|
|
|
// 节点上下文与节点ID映射
|
|
|
ctxMap: CtxIDMap;
|
|
|
|
|
|
- constructor(rawData: TreeRaw[]) {
|
|
|
+ constructor(rawData: TreeRaw[], rootID = '-1') {
|
|
|
+ this.rootID = rootID;
|
|
|
this.rawData = this.genNodeContext(rawData);
|
|
|
this.rawData = Tree.sort(this.rawData);
|
|
|
this.data = [];
|
|
|
@@ -308,7 +309,7 @@ export class Tree {
|
|
|
this.rawData.push(...nodes);
|
|
|
// 排序
|
|
|
this.reSortData(nodes);
|
|
|
- return this.data;
|
|
|
+ return nodes;
|
|
|
}
|
|
|
|
|
|
// 准备删除,返回所有需要删除的节点,包括嵌套节点
|
|
|
@@ -319,13 +320,14 @@ export class Tree {
|
|
|
/**
|
|
|
* 删除节点
|
|
|
* @param {TreeNode[]} treeNodes - 要删除的节点,不需要包含嵌套节点
|
|
|
- * @return {TreeNode[]} 返回删除节点后,树的data
|
|
|
+ * @return {TreeNode[]} 返回被删除的节点
|
|
|
*/
|
|
|
delete(treeNodes: TreeNode[]): TreeNode[] {
|
|
|
const allDeletedNodes: TreeNode[] = [];
|
|
|
// 递归删除节点
|
|
|
const deleteNodes = (nodes: TreeNode[]): void => {
|
|
|
// 删除映射、删除数据
|
|
|
+ const toDels: { nodes: TreeNode[]; delNode: TreeNode }[] = [];
|
|
|
nodes.forEach(node => {
|
|
|
allDeletedNodes.push(node);
|
|
|
delete this.IDMap[node.ID];
|
|
|
@@ -336,7 +338,7 @@ export class Tree {
|
|
|
if (nodesInParentMap && nodesInParentMap.length) {
|
|
|
const nIndex = nodesInParentMap.indexOf(node);
|
|
|
if (nIndex >= 0) {
|
|
|
- nodesInParentMap.splice(nIndex, 1);
|
|
|
+ toDels.push({ nodes: nodesInParentMap, delNode: node });
|
|
|
}
|
|
|
}
|
|
|
const index = this.rawData.indexOf(node);
|
|
|
@@ -347,11 +349,18 @@ export class Tree {
|
|
|
deleteNodes(children);
|
|
|
}
|
|
|
});
|
|
|
+ // 删除parentMap的数据
|
|
|
+ toDels.forEach(delItem => {
|
|
|
+ const delIndex = delItem.nodes.indexOf(delItem.delNode);
|
|
|
+ if (delIndex >= 0) {
|
|
|
+ delItem.nodes.splice(delIndex, 1);
|
|
|
+ }
|
|
|
+ });
|
|
|
};
|
|
|
deleteNodes(treeNodes);
|
|
|
// 排序
|
|
|
this.reSortData(allDeletedNodes);
|
|
|
- return this.data;
|
|
|
+ return allDeletedNodes;
|
|
|
}
|
|
|
|
|
|
// IDList 返回所有需要删除的节点,包括嵌套节点
|
|
|
@@ -468,10 +477,12 @@ export class Tree {
|
|
|
}
|
|
|
// 最末节点的所有后兄弟节点,成为最末节点的子节点
|
|
|
const lastNodeNextBrothers = lastNode.getCtx().nextBrothers();
|
|
|
+ const lastNodeLastChild = lastNode.getCtx().lastChild();
|
|
|
+ const lastNodeLastChildSeq = lastNodeLastChild ? lastNodeLastChild.seq : 0;
|
|
|
lastNodeNextBrothers.forEach((node, index) => {
|
|
|
updateData.push({
|
|
|
ID: node.ID,
|
|
|
- update: { parentID: lastNode.ID, seq: index },
|
|
|
+ update: { parentID: lastNode.ID, seq: index + lastNodeLastChildSeq },
|
|
|
});
|
|
|
});
|
|
|
return updateData;
|
|
|
@@ -536,5 +547,68 @@ export class Tree {
|
|
|
...nodes
|
|
|
);
|
|
|
this.updateValue(updateData);
|
|
|
+ this.reGenData();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 准备移动节点块(连续的兄弟节点),不维护seq连号
|
|
|
+ prepareMoveTo(
|
|
|
+ nodes: TreeNode[],
|
|
|
+ parent: TreeNode | None,
|
|
|
+ next: TreeNode | None
|
|
|
+ ): UpdateData[] {
|
|
|
+ const updateData: UpdateData[] = [];
|
|
|
+ let prev: TreeNode | None;
|
|
|
+ if (next) {
|
|
|
+ prev = next.getCtx().prev();
|
|
|
+ } else {
|
|
|
+ prev = parent ? parent.getCtx().lastChild() : null;
|
|
|
+ }
|
|
|
+ const baseSeq = prev ? prev.seq + 1 : this.seqStartIndex;
|
|
|
+ updateData.push(
|
|
|
+ ...nodes.map((node, index) => ({
|
|
|
+ ID: node.ID,
|
|
|
+ update: {
|
|
|
+ parentID: (parent && parent.ID) || this.rootID,
|
|
|
+ seq: baseSeq + index,
|
|
|
+ },
|
|
|
+ }))
|
|
|
+ );
|
|
|
+ const curBaseSeq = baseSeq + nodes.length;
|
|
|
+ const nextBrothers = prev ? prev.getCtx().nextBrothers() : [];
|
|
|
+ updateData.push(
|
|
|
+ ...nextBrothers.map((node, index) => ({
|
|
|
+ ID: node.ID,
|
|
|
+ update: {
|
|
|
+ seq: curBaseSeq + index,
|
|
|
+ },
|
|
|
+ }))
|
|
|
+ );
|
|
|
+ return updateData;
|
|
|
+ }
|
|
|
+
|
|
|
+ moveTo(
|
|
|
+ nodes: TreeNode[],
|
|
|
+ parent: TreeNode | None,
|
|
|
+ updateData: UpdateData[]
|
|
|
+ ): void {
|
|
|
+ const firstNode = nodes[0];
|
|
|
+ const newParentID = parent ? parent.ID : this.rootID;
|
|
|
+ const orgParentID = firstNode.parentID;
|
|
|
+ const orgBrothers = this.parentMap[orgParentID];
|
|
|
+ orgBrothers.splice(orgBrothers.indexOf(firstNode), nodes.length);
|
|
|
+ (this.parentMap[newParentID] || (this.parentMap[newParentID] = [])).push(
|
|
|
+ ...nodes
|
|
|
+ );
|
|
|
+ this.updateValue(updateData);
|
|
|
+ this.resortDataByID([orgParentID, newParentID]);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 清除所有节点(不变更data引用)
|
|
|
+ clear(): void {
|
|
|
+ this.rawData.splice(0, this.rawData.length);
|
|
|
+ this.data.splice(0, this.data.length);
|
|
|
+ Object.keys(this.parentMap).forEach(key => delete this.parentMap[key]);
|
|
|
+ Object.keys(this.IDMap).forEach(key => delete this.IDMap[key]);
|
|
|
+ Object.keys(this.ctxMap).forEach(key => delete this.ctxMap[key]);
|
|
|
}
|
|
|
}
|