You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

54 lines
2.1 KiB

2 years ago
  1. type TreeKey = string | number;
  2. interface TreeNode {
  3. key: TreeKey;
  4. id?: TreeKey;
  5. children?: TreeNode[];
  6. }
  7. export function getTreeCheckedStatus(tree: TreeNode[], selectKeys: TreeKey[]): { checked: TreeKey[], halfChecked: TreeKey[] } {
  8. const checked: TreeKey[] = []
  9. const halfChecked: TreeKey[] = []
  10. if (!tree || tree.length === 0) return { checked, halfChecked }
  11. if (!selectKeys || selectKeys.length === 0) return { checked, halfChecked }
  12. // 辅助函数来递归地检查每个节点
  13. function checkNode(node: TreeNode, ancestors: TreeKey[]): void {
  14. const key = node.key ?? node.id
  15. const isLeaf = !node.children || node.children.length === 0
  16. const isSelected = selectKeys.includes(key)
  17. // 如果是叶节点并且被选中,则直接加入到checked数组
  18. if (isLeaf && isSelected) {
  19. checked.push(key)
  20. // 标记所有祖先为半选状态,除非它们已经被完全选中
  21. ancestors.forEach(ancestorKey => {
  22. if (!halfChecked.includes(ancestorKey) && !checked.includes(ancestorKey)) {
  23. halfChecked.push(ancestorKey)
  24. }
  25. })
  26. return
  27. }
  28. // 非叶节点,递归检查其子节点
  29. if (node.children) {
  30. const childAncestors = [ ...ancestors, key ]
  31. node.children.forEach(child => checkNode(child, childAncestors))
  32. // 检查当前节点的所有子节点是否全部或部分被选中
  33. const childSelectedCount = node.children.filter(child => checked.includes(child.key ?? child.id)).length
  34. if (childSelectedCount === node.children.length) {
  35. // 如果所有子节点都被选中,将当前节点标为全选
  36. checked.push(key)
  37. } else if (childSelectedCount > 0) {
  38. // 如果部分子节点被选中,将当前节点标为半选
  39. halfChecked.push(key)
  40. }
  41. }
  42. }
  43. // 遍历每一个根节点
  44. tree.forEach(node => checkNode(node, []))
  45. return { checked, halfChecked }
  46. }