225 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			225 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
import { OriginalTreeData, StringOrNumber } from "./tree.type";
 | 
						|
import { Nullable } from "../../types";
 | 
						|
import { Ref, ref } from "vue";
 | 
						|
import { check } from "prettier";
 | 
						|
 | 
						|
type CustomKey = string | number;
 | 
						|
type CustomString = (() => string) | string;
 | 
						|
 | 
						|
export interface TreeData {
 | 
						|
  id: CustomKey;
 | 
						|
  title: CustomString;
 | 
						|
  children: TreeData[];
 | 
						|
  parentKey: Nullable<StringOrNumber>;
 | 
						|
  isRoot: boolean;
 | 
						|
  isChecked: boolean;
 | 
						|
  isDisabled: boolean;
 | 
						|
  isLeaf: boolean;
 | 
						|
  hasNextSibling: boolean;
 | 
						|
  parentNode: Nullable<TreeData>;
 | 
						|
}
 | 
						|
 | 
						|
interface ReplaceFields {
 | 
						|
  id: string;
 | 
						|
  title: string;
 | 
						|
  children: string;
 | 
						|
}
 | 
						|
 | 
						|
interface TreeConfig {
 | 
						|
  checkStrictly: boolean | string;
 | 
						|
  showCheckbox: boolean;
 | 
						|
  checkedKeys: StringOrNumber[];
 | 
						|
  expandKeys: StringOrNumber[];
 | 
						|
  nodeMap: Map<StringOrNumber, TreeData>;
 | 
						|
  originMap: Map<StringOrNumber, OriginalTreeData>;
 | 
						|
  replaceFields: ReplaceFields;
 | 
						|
}
 | 
						|
 | 
						|
class Tree {
 | 
						|
  protected config: TreeConfig;
 | 
						|
  protected treeData: TreeData[];
 | 
						|
 | 
						|
  constructor(
 | 
						|
    config: TreeConfig,
 | 
						|
    origin: OriginalTreeData | OriginalTreeData[]
 | 
						|
  ) {
 | 
						|
    this.config = config;
 | 
						|
    this.treeData = [];
 | 
						|
    this.init(origin);
 | 
						|
  }
 | 
						|
 | 
						|
  init(origin: OriginalTreeData | OriginalTreeData[]): void {
 | 
						|
    const tree = this.createTree(origin);
 | 
						|
    this.treeData = tree;
 | 
						|
  }
 | 
						|
 | 
						|
  createTree(
 | 
						|
    origin: OriginalTreeData | OriginalTreeData[],
 | 
						|
    parentKey: StringOrNumber = ""
 | 
						|
  ): TreeData[] {
 | 
						|
    let data;
 | 
						|
    if (!Array.isArray(origin)) {
 | 
						|
      data = Array.of(Object.assign({}, origin));
 | 
						|
    } else {
 | 
						|
      data = origin;
 | 
						|
    }
 | 
						|
    const nodeList: TreeData[] = [];
 | 
						|
    const { children } = this.config.replaceFields;
 | 
						|
 | 
						|
    const len = data.length;
 | 
						|
    for (let i = 0; i < len; i++) {
 | 
						|
      const node = this.getNode(data[i], parentKey, i < len - 1);
 | 
						|
      const nodeChildren = Reflect.get(node, children);
 | 
						|
      const nodeHasChildren = !!Reflect.get(node, children);
 | 
						|
 | 
						|
      if (nodeHasChildren) {
 | 
						|
        Reflect.set(node, children, this.createTree(nodeChildren, node.id));
 | 
						|
      }
 | 
						|
 | 
						|
      nodeList.push(node);
 | 
						|
    }
 | 
						|
    return nodeList;
 | 
						|
  }
 | 
						|
 | 
						|
  getNode(
 | 
						|
    origin: OriginalTreeData,
 | 
						|
    parentKey: StringOrNumber,
 | 
						|
    hasNextSibling: boolean
 | 
						|
  ): TreeData {
 | 
						|
    const {
 | 
						|
      nodeMap,
 | 
						|
      originMap,
 | 
						|
      checkedKeys,
 | 
						|
      expandKeys,
 | 
						|
      checkStrictly,
 | 
						|
      replaceFields: { children, id, title },
 | 
						|
    } = this.config;
 | 
						|
 | 
						|
    const nodeKey = Reflect.get(origin, id);
 | 
						|
    const nodeTitle = Reflect.get(origin, title);
 | 
						|
    const nodeChildren = Reflect.get(origin, children);
 | 
						|
    const nodeDisabled = !!Reflect.get(origin, "disabled");
 | 
						|
    const nodeIsLeaf = !!Reflect.get(origin, "spread");
 | 
						|
    const parentNode = nodeMap.get(parentKey);
 | 
						|
 | 
						|
    const node = Object.assign({}, origin, {
 | 
						|
      id: nodeKey,
 | 
						|
      title: nodeTitle,
 | 
						|
      children: nodeChildren ? nodeChildren : [],
 | 
						|
      parentKey: parentKey,
 | 
						|
      isRoot: parentKey === "",
 | 
						|
      isDisabled: false,
 | 
						|
      isChecked: false,
 | 
						|
      isLeaf: false,
 | 
						|
      hasNextSibling: hasNextSibling,
 | 
						|
      parentNode: parentNode || null,
 | 
						|
    });
 | 
						|
 | 
						|
    node.isDisabled = nodeDisabled;
 | 
						|
    node.isChecked = checkedKeys.includes(nodeKey);
 | 
						|
    node.isLeaf = parentNode ? parentNode.isLeaf : expandKeys.includes(nodeKey);
 | 
						|
    node.isLeaf = nodeIsLeaf;
 | 
						|
 | 
						|
    if (!nodeMap.has(nodeKey)) {
 | 
						|
      nodeMap.set(nodeKey, node);
 | 
						|
    }
 | 
						|
    if (!originMap.has(nodeKey)) {
 | 
						|
      originMap.set(nodeKey, origin);
 | 
						|
    }
 | 
						|
    return node;
 | 
						|
  }
 | 
						|
 | 
						|
  treeForeach(tree: any, func: Function) {
 | 
						|
    tree.forEach((data: any) => {
 | 
						|
      data.children && this.treeForeach(data.children, func);
 | 
						|
      func(data);
 | 
						|
    });
 | 
						|
  }
 | 
						|
 | 
						|
  setChildrenChecked(checked: boolean, nodes: TreeData[]) {
 | 
						|
    var ableCount = 0;
 | 
						|
    var checkCount = 0;
 | 
						|
    const len = nodes.length;
 | 
						|
    this.treeForeach(nodes, (node: any) => {
 | 
						|
      if (!node.isDisabled) {
 | 
						|
        ableCount = ableCount + 1;
 | 
						|
        if (node.isChecked) {
 | 
						|
          checkCount = checkCount + 1;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    });
 | 
						|
    checkCount < ableCount ? (checked = true) : (checked = false);
 | 
						|
    for (let i = 0; i < len; i++) {
 | 
						|
      if (
 | 
						|
        !nodes[i].isDisabled ||
 | 
						|
        (nodes[i].isDisabled && nodes[i].children.length > 0)
 | 
						|
      ) {
 | 
						|
        nodes[i].isChecked = checked;
 | 
						|
      }
 | 
						|
      nodes[i].children &&
 | 
						|
        nodes[i].children.length > 0 &&
 | 
						|
        this.setChildrenChecked(checked, nodes[i].children);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  setParentChecked(checked: boolean, parent: TreeData) {
 | 
						|
    if (!parent) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
    parent.isChecked = checked;
 | 
						|
    const pChild = parent.children;
 | 
						|
    const pChildChecked = pChild.some((c) => c.isChecked);
 | 
						|
    if (pChildChecked) {
 | 
						|
      parent.isChecked = true;
 | 
						|
    }
 | 
						|
    if (parent.parentNode) {
 | 
						|
      this.setParentChecked(checked, parent.parentNode);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  setCheckedKeys(
 | 
						|
    checked: boolean,
 | 
						|
    checkStrictly: boolean | string,
 | 
						|
    node: TreeData
 | 
						|
  ) {
 | 
						|
    node.isChecked = checked;
 | 
						|
    if (!checkStrictly) {
 | 
						|
      if (node.parentNode) {
 | 
						|
        this.setParentChecked(checked, node.parentNode);
 | 
						|
      }
 | 
						|
      if (node.children) {
 | 
						|
        this.setChildrenChecked(checked, node.children);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  getData() {
 | 
						|
    return this.treeData;
 | 
						|
  }
 | 
						|
 | 
						|
  getKeys() {
 | 
						|
    const checkedKeys = [];
 | 
						|
    const expandKeys = [];
 | 
						|
    const iterator = this.config.nodeMap[Symbol.iterator]();
 | 
						|
    let next = iterator.next();
 | 
						|
    while (!next.done) {
 | 
						|
      const [, node] = next.value;
 | 
						|
      const id = Reflect.get(node, this.config.replaceFields.id);
 | 
						|
      if (node.isChecked) {
 | 
						|
        checkedKeys.push(id);
 | 
						|
      }
 | 
						|
      if (node.isLeaf) {
 | 
						|
        expandKeys.push(id);
 | 
						|
      }
 | 
						|
      next = iterator.next();
 | 
						|
    }
 | 
						|
    return { checkedKeys, expandKeys };
 | 
						|
  }
 | 
						|
 | 
						|
  getOriginData(key: StringOrNumber): OriginalTreeData {
 | 
						|
    return this.config.originMap.get(key)!;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
export { Tree };
 |