menus.jsx 3.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import React from 'react';
  2. import { Button, Card, Tree, message } from 'antd';
  3. import useBool from '@/utils/hooks/useBool';
  4. import { arr2Tree, uniq } from '@/utils/array';
  5. import { getResourceList, authRoleResource } from '@/services/role';
  6. export default (props) => {
  7. const { role } = props;
  8. const [loading, startLoading, cancelLoading] = useBool();
  9. const [list, setList] = React.useState([]);
  10. const [expandedKeys, setExpandedKeys] = React.useState([]);
  11. const [treeData, setTreeData] = React.useState([]);
  12. const treeDictRef = React.useRef();
  13. const [checkedKeys, setCheckedKeys] = React.useState({ checked: [], halfChecked: [] });
  14. const keys = checkedKeys.checked.concat(checkedKeys.halfChecked);
  15. const title = role ? `${role.name} - 授权菜单` : '授权菜单';
  16. const getListData = () => {
  17. return new Promise((resolve, reject) => {
  18. getResourceList({ type: 'menu' }).then((res = []) => {
  19. setList(res);
  20. resolve(res)
  21. }).catch(reject);
  22. });
  23. }
  24. const onCheck = (keys, { halfCheckedKeys }) => {
  25. setCheckedKeys({ checked: keys, halfChecked: halfCheckedKeys });
  26. };
  27. const onSubmit = () => {
  28. // 如果一个都不选,代表清空授权
  29. const data = [];
  30. const roleId = role.id;
  31. for (let resourceId of keys) {
  32. data.push({ roleId, resourceId });
  33. }
  34. startLoading();
  35. authRoleResource(roleId, data).then((res) => {
  36. cancelLoading();
  37. }).catch(() => {
  38. cancelLoading();
  39. })
  40. }
  41. React.useEffect(() => {
  42. const p = !list.length ? getListData : () => Promise.resolve(list);
  43. if (!role || !role.id) {
  44. p();
  45. } else {
  46. startLoading();
  47. p().then((allData) => {
  48. getResourceList({ type: 'menu', roleId: role.id }).then((res = []) => {
  49. cancelLoading();
  50. // 数据分为2部分, 一部分叶子节点, 一部分非叶子节点
  51. const checked = [], halfChecked = [];
  52. for (let item of res) {
  53. // 获取子节点, 没有的话则为叶子节点, 否则为非叶子节点
  54. const children = allData.filter(x => x.parentId === item.id);
  55. if (!children.length) {
  56. // 没有子节点, 则为叶子节点, 算入选中节点
  57. checked.push(item.id);
  58. } else {
  59. // 获取选中子节点
  60. const checkedChildren = res.filter(x => x.parentId === item.id);
  61. if (checkedChildren.length === children.length) {
  62. // 非叶子节点如果 子节点全部包含, 那么算入选中节点
  63. checked.push(item.id);
  64. } else {
  65. halfChecked.push(item.id);
  66. }
  67. }
  68. }
  69. setCheckedKeys({ checked, halfChecked });
  70. }).catch(() => {
  71. cancelLoading();
  72. })
  73. }).catch(() => {
  74. cancelLoading();
  75. })
  76. }
  77. }, [role]);
  78. React.useEffect(() => {
  79. // 展开节点
  80. setExpandedKeys((list).filter(x => x.parentId === -1).map(x => x.id));
  81. // 先转为需要的格式
  82. const arr = list.map(x => ({ title: x.name, key: x.id, parentId: x.parentId }));
  83. // 再转为 tree
  84. const [tree, dict] = arr2Tree(arr);
  85. setTreeData(tree);
  86. treeDictRef.current = dict;
  87. }, [list]);
  88. return (
  89. <Card
  90. loading={loading}
  91. title={title}
  92. extra={<Button type='primary' disabled={!role || !role.id} ghost onClick={onSubmit}>保存</Button>}
  93. >
  94. <Tree
  95. checkable
  96. autoExpandParent
  97. expandedKeys={expandedKeys}
  98. checkStrictly={false}
  99. selectable={false}
  100. checkedKeys={checkedKeys}
  101. onCheck={onCheck}
  102. onExpand={setExpandedKeys}
  103. treeData={treeData}
  104. />
  105. </Card>
  106. )
  107. }
  108. function getKeysWithParent(node, dict) {
  109. if (node.parentId === -1) return [node.key];
  110. const parentKeys = getKeysWithParent(dict[node.parentId], dict);
  111. return parentKeys ? [node.key].concat(parentKeys) : [node.key];
  112. }