【antd】将扁平的列表数据转换为antd级联选择器cascader需要的树形结构数据

扁平的列表数据结构

const data = [
	{
		deptId: '',
		deptName: '',
		parentId: '',
		orderNum: ''
	},
	...
]

符合antd的cascader的options的数据结构

[
	{
		label: '',
		value: '',
		children: [
			{
				label: '',
				value: '',
				children: [
					...
				]
			}
		],
		...
	}
]

附加逻辑:按orderNum对同级部门进行排序

步骤

1、创建一个Map集合,用于缓存所有部门节点,方便后续通过deptId快速查找对应的节点(避免多次遍历数组)
const deptMap = new Map();
2、最终要返回的树形结构数组,用来存放所有顶级部门(parentId = 0 或 ‘0’)
const treeData = [];
3、第一次遍历扁平的列表数组,为每个部门创建节点对象,并存入Map
data.forEach(i => {
	const node = {
		value: i.deptId,
		label: i.deptName,
		parentId: i.parentId,
		children: []
	}
	deptMap.set(i.deptId, node);   
	// 当前部门id作为key,新建的符合cascader数据结构的node作为value,存入deptMap,后续可通过deptMap.get(deptId)直接拿到对应的节点,时间复杂度O(1),比遍历数组快
})
4、第二次遍历扁平的列表数组,根据parentId建立父子节点的关联关系
data.forEach(i => {
	// 取出当前部门Id对应的node对象
	const currentNode = deptMap.get(i.deptId);
	// 取出当前部门的父级id,用于判断是顶级部门还是子部门
	const parentId = i.parentId;
	// 如果是顶级部门,push进treeData,否则进入else分支
	if(parentId === 0 ||  parentId === '0') {
		treeData.push(currentNode);
	}else {
		// 取出当前部门的父级的node
		const parentNode = deptMap.get(parentId);
		if(parentNode) {
			// 如果当前部门存在父级,把当前部门node塞进父级的children,就形成了树形结构数据
			parentNode.children.push(currentNode);
		}
	}
})
5、此时已经拿到cascader需要的数组treeData,再将子级部门按orderNum排列即可
const sortChildrenByOrder = (nodes) => {
	nodes.forEach(i => {
		i.children.sort((a, b) => {
       const orderA = Number(a.orderNum || 0);
       const orderB = Number(b.orderNum || 0);
       return orderA - orderB;
     });
     sortChildrenByOrder(i.children);
	})
}
sortChildrenByOrder(treeData);

完整代码

const convertDeptToCascaderData = (flatDeptData) => {
  const deptMap = new Map();
  const treeData = [];

  flatDeptData.forEach(item => {
    const node = {
      value: item.deptId,  
      label: item.deptName,  
      parentId: item.parentId, 
      children: []  
    };
    deptMap.set(item.deptId, node);
  });

  flatDeptData.forEach(item => {
    const currentNode = deptMap.get(item.deptId);
    const parentId = item.parentId;

    if (parentId === 0 || parentId === '0') {
      treeData.push(currentNode);
    } else {
      const parentNode = deptMap.get(parentId);
      if (parentNode) {
        parentNode.children.push(currentNode);
      }
    }
  });

  const sortChildrenByOrder = (nodes) => {
    nodes.forEach(node => {
      node.children.sort((a, b) => {
        const orderA = Number(a.orderNum || 0);
        const orderB = Number(b.orderNum || 0);
        return orderA - orderB;
      });
      sortChildrenByOrder(node.children);
    });
  };
  sortChildrenByOrder(treeData);

  return treeData;
};

示例数据

const flatDeptData = [
  { deptId: 1, deptName: '总部门', parentId: 0, orderNum: 1 },
  { deptId: 2, deptName: '技术部', parentId: 1, orderNum: 2 },
  { deptId: 3, deptName: '产品部', parentId: 1, orderNum: 1 },
  { deptId: 4, deptName: '前端组', parentId: 2, orderNum: 1 },
];

经过函数处理后,输出的是

[
  {
    value: 1,
    label: '总部门',
    parentId: 0,
    children: [
      {
        value: 3,
        label: '产品部',
        parentId: 1,
        children: []
      },
      {
        value: 2,
        label: '技术部',
        parentId: 1,
        children: [
          { value: 4, label: '前端组', parentId: 2, children: [] }
        ]
      }
    ]
  }
]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值