Newer
Older
smartwell_front / src / utils / structure.ts
liyaguang on 26 Feb 6 KB 新装设备完成
// 数据结构转换工具
// 定义数组项的数据类型,包含id、name、parentId基本属性
interface ArrayItem {
  pid: string
  id: string
  name?: string
}
// 定义树节点的数据类型,包含id、name、可能存在的子节点
interface TreeNode {
  id: string
  name?: string
  pid: string
  children?: TreeNode[] // 叶子节点没有子节点
}
/**
 * 判断是否有转树的必要
 * @param plainList 平行数据列表
 * @param id 祖宗id
 * @returns {boolean}  有返回true,无返回false
 */
export function judgeTree(plainList: ArrayItem[], id?: '0') {
  if (plainList && plainList.length > 0) {
    let flag = false // 是否需要转成树结构
    const pid = id
    for (const item of plainList) {
      if (item.pid !== pid) { // 只要有一个元素的pid没有指向第一个元素的父id,认为有必要转换成树,否则认为无必要
        // console.log(item, 'item')
        flag = true
        break
      }
    }
    return flag
  }
  else { return false }
}

/**
 * 平面数据数据转树结构
 * @param plainList 平行数据列表
 * @param id 祖宗id
 * @param isSelect 是否是下拉需要顶级的树
 * @returns {*}
 */
export function toTreeList<T extends ArrayItem>(plainList: T[], rootId = '0', isSelect = false): T[] {
  const pid = findPid(plainList)
  if (pid.length > 1) { // 如果有多个pid,直接返回列表, 不去构造树
    console.log(pid, 'pid')
    return plainList
  }
  else if (pid.length === 1) {
    const tree = cleanChildren(buildTree<T>(plainList, pid[0], isSelect))
    return tree
  }
  else {
    const tree = cleanChildren(buildTree<T>(plainList, rootId, isSelect))
    return tree
  }
}
// 构建树
/**
 *
 * @param plainList 待转换数组
 * @param id 父节点
 * @param isSelect 是否是下拉框所使用的树
 * @returns 树节点列表
 */
function buildTree<T extends TreeNode>(plainList: T[], id = '0', isSelect = false): T[] | [] {
  // 递归函数
  const fa = (parentId: string): Array<T> | [] => {
    const temp = []
    for (let i = 0; i < plainList.length; i++) {
      const n: TreeNode = { ...plainList[i] }
      const id = `${n.id}`
      const pid = `${n.pid}`
      if (pid === parentId) {
        n.children = fa(id)
        temp.push(n)
      }
    }
    return temp as T[]
  }
  // 如果是下拉框需要使用的树,首先寻找顶级,将顶级也放入列表
  if (isSelect) {
    let flag = 1
    const list = []
    if (Array.isArray(plainList)) {
      for (const item of plainList) {
        const n: T = { ...item }
        const nid = `${n.id}`
        if (nid === id) {
          n.children = fa(id)
          flag = 0
          list.push(n)
          return list
        }
        else {
          continue
        }
      }
    }

    if (flag === 1) { // 没有找到父级,按原流程走
      return fa(id)
    }
    else {
      return []
    }
  }
  else {
    return fa(id)
  }
}

// 清除children为空列表的children项
function cleanChildren<T extends TreeNode>(data: T[]): T[] {
  const fa = (list: TreeNode[]): T[] => {
    list.map((e) => {
      if (e && e.children && e.children.length) {
        fa(e.children)
      }
      else {
        delete e.children
      }
      return e
    })
    return list as T[]
  }
  return fa(data)
}
/**
 *
 * @param plainList 寻找列表中的父id
 * @returns 父id列表
 */
function findPid(plainList: Array<ArrayItem>): Array<string> {
  const pidList = new Set<string>()
  if (plainList) {
    for (const item of plainList) { // 1.添加所有的父id
      pidList.add(item.pid)
    }
    for (const item of plainList) { // 2.删除所有的子id
      if (pidList.has(item.id)) {
        pidList.delete(item.id)
      }
    }
    const arr = Array.from(pidList) // 剩下的就是最终的父节点
    return arr
  }
  else {
    return []
  }
}

// 从树列表中删除指定元素
export function deleteItem(list: Array<TreeNode>, des: TreeNode) {
  const del = (list: Array<TreeNode>, item: TreeNode) => {
    for (let i = 0; i < list.length; i++) {
      if (list[i].id === item.id) {
        list.splice(i, 1)
        return
      }
      else { // 遍历子孙,继续递归寻找
        if (list[i].children && list[i].children!.length > 0) {
          del(list[i].children!, item)
        }
      }
    }
  }
  del(list, des)
}

interface treeItem {
  id: string
  open: string | boolean
  checked: string | boolean
}
/**
 *获取列表中的展开项和选中项
 * @param plainList
 * @param id
 * @returns{展开项, 选中项}
 */
export function getShowItem(plainList: treeItem[]): { expandList: string[]; openedList: string[] } {
  const expandList = []
  const openedList = []
  for (let i = 0; i < plainList.length; i++) {
    if (plainList[i].open === 'true' || plainList[i].open === true) {
      expandList.push(plainList[i].id)
    }
    if (plainList[i].checked === 'true' || plainList[i].checked === true) {
      openedList.push(plainList[i].id)
    }
  }
  return { expandList, openedList }
}

export function findAllChildrenInArray(nodes, targetId) {
  let result = [];
  function traverse(nodes) {
    nodes.forEach(node => {
      if (node.id === targetId) {
        result = node.children || []; // 直接返回其子节点列表(如果有的话)
        return; // 提前返回,避免进一步递归
      } else if (node.children) {
        traverse(node.children); // 递归查找子节点中的目标节点
      }
    });
  }
  traverse(nodes); // 从根节点开始遍历
  return result;
}

export function treeToArr(data, pid = null, res = []) {
  data.forEach(item => {
    res.push({ pid: pid, id: item.id, name: item.name });
    if (item.children && item.children.length !== 0) {
      treeToArr(item.children, item.id, res);
    }
  });
  return res;
}

// 根据子元素的id找出所有父元素(树形结构数据)
export const findParentPids = (tree: TreeNode[], targetId: string): string[] => {
  const parentPids: string[] = [];

  const traverse = (node: TreeNode, parentPid?: string): boolean => {
    if (node.id === targetId) {
      if (parentPid) {
        parentPids.push(parentPid);
      }
      return true;
    }

    if (node.children) {
      for (const child of node.children) {
        if (traverse(child, node.id)) {
          if (parentPid) {
            parentPids.push(parentPid);
          }
          return true;
        }
      }
    }

    return false;
  };

  for (const node of tree) {
    traverse(node);
  }

  return parentPids;
}
// 根据子元素的id找出所有父元素(平面数据数据)
export const findParentPids1 = (flatData: TreeNode[], targetId: string): string[] => {
  const parentPids: string[] = [];
  let currentNode = flatData.find(node => node.id === targetId);

  while (currentNode && currentNode.pid !== '0') {
    parentPids.push(currentNode.pid);
    currentNode = flatData.find(node => node.id === currentNode.pid);
  }

  return parentPids;
};