index.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. import {Checkbox, Table} from '@douyinfe/semi-ui';
  2. import React, {useCallback, useMemo, useState} from 'react';
  3. import * as _ from 'lodash';
  4. const getKey = (record, rowKey) => (typeof rowKey === 'function' ? rowKey(rowKey) : _.get(record, rowKey));
  5. const storeKeys = (parent = null, dataSource = [], map = {}, rowKey = 'key', childrenRecordName = 'children') => {
  6. if (Array.isArray(dataSource) && dataSource.length) {
  7. dataSource.forEach(record => {
  8. const key = getKey(record, rowKey);
  9. const children = _.get(record, childrenRecordName);
  10. if (Array.isArray(children) && children.length) {
  11. storeKeys(record, children, map, rowKey, childrenRecordName);
  12. }
  13. if (parent) {
  14. if (Array.isArray(map[key])) {
  15. map[key].push(parent);
  16. } else {
  17. map[key] = [parent];
  18. }
  19. }
  20. });
  21. }
  22. return map;
  23. };
  24. function ChildrenDataSelectedDemo(props = {}) {
  25. const childrenRecordName = 'children';
  26. const rowKey = 'key';
  27. const [expandedRowKeys, setExpandedRowKeys] = useState([1, 2]);
  28. const [selectedRowKeys, setSelectedRowKeys] = useState([]);
  29. const getRecordKey = useCallback(record => getKey(record, rowKey), [rowKey]);
  30. const disabledRecord = useCallback(
  31. record => {
  32. const children = _.get(record, childrenRecordName);
  33. return !(Array.isArray(children) && children.length);
  34. },
  35. [childrenRecordName]
  36. );
  37. const data = useMemo(
  38. () => [
  39. {
  40. key: 1,
  41. name: 'ZhangSan',
  42. age: 30,
  43. address: 'bytedance 1',
  44. children: [
  45. {
  46. key: 11,
  47. name: 'LiSi',
  48. age: 40,
  49. address: 'bytedance 2',
  50. },
  51. {
  52. key: 12,
  53. name: 'WangWu',
  54. age: 30,
  55. address: 'bytedance 2',
  56. children: [
  57. {
  58. key: 121,
  59. name: 'XiaoMing',
  60. age: 50,
  61. address: 'bytedance 3',
  62. },
  63. ],
  64. },
  65. {
  66. key: 13,
  67. name: 'XiaoZhang',
  68. age: 60,
  69. address: 'bytedance 4',
  70. children: [
  71. {
  72. key: 131,
  73. name: 'XiaoLi',
  74. age: 50,
  75. address: 'bytedance 5',
  76. children: [
  77. {
  78. key: 1311,
  79. name: 'XiaoGuo',
  80. age: 40,
  81. address: 'bytedance 6',
  82. },
  83. {
  84. key: 1312,
  85. name: 'XiaoHong',
  86. age: 30,
  87. address: 'bytedance 7',
  88. },
  89. ],
  90. },
  91. ],
  92. },
  93. ],
  94. },
  95. {
  96. key: 2,
  97. name: 'XiaoGang',
  98. age: 80,
  99. address: 'bytedance 8',
  100. },
  101. ],
  102. []
  103. );
  104. const keysMap = useMemo(() => storeKeys(null, data, {}, rowKey, childrenRecordName), [
  105. data,
  106. rowKey,
  107. childrenRecordName,
  108. ]);
  109. const doSelect = (record, selected) => {
  110. const key = getRecordKey(record, rowKey);
  111. const children = _.get(record, childrenRecordName, []);
  112. const parents = _.get(keysMap, key);
  113. const set = new Set([...selectedRowKeys]);
  114. if (selected) {
  115. set.add(key);
  116. } else {
  117. set.delete(key);
  118. }
  119. const selectChildren = (selected = false, children = []) => {
  120. if (typeof disabledRecord === 'function') {
  121. children = _.filter(children, child => !disabledRecord(child));
  122. }
  123. if (Array.isArray(children) && children.length) {
  124. _.each(children, child => {
  125. const key = getKey(child, rowKey);
  126. const curChildren = _.get(child, childrenRecordName);
  127. if (selected) {
  128. set.add(key);
  129. } else {
  130. set.delete(key);
  131. }
  132. selectChildren(selected, curChildren);
  133. });
  134. }
  135. };
  136. selectChildren(selected, children);
  137. _.each(parents, parent => {
  138. const childrenKeys = _.get(parent, childrenRecordName, [])
  139. .filter(parentChild => !disabledRecord(parentChild))
  140. .map(getRecordKey);
  141. const allSelected = childrenKeys.length && childrenKeys.every(key => set.has(key));
  142. const parentKey = getRecordKey(parent);
  143. if (allSelected) {
  144. set.add(parentKey);
  145. } else {
  146. set.delete(parentKey);
  147. }
  148. return false;
  149. });
  150. setSelectedRowKeys(Array.from(set));
  151. };
  152. const doSelectAll = useCallback((selected, selectedRows) => {
  153. const keys = selected ? _.map(selectedRows, row => getRecordKey(row, rowKey)) : [];
  154. setSelectedRowKeys(keys);
  155. }, []);
  156. const columns = useMemo(
  157. () => [
  158. {
  159. title: 'Name',
  160. dataIndex: 'name',
  161. key: 'name',
  162. width: 300,
  163. render: (text, record) => (
  164. <span style={{display: 'inline-flex', alignItems: 'center'}}>
  165. {_.size(_.get(record, childrenRecordName)) ? (
  166. <Checkbox
  167. checked={selectedRowKeys.includes(_.get(record, rowKey))}
  168. onChange={e => doSelect(record, e.target.checked)}
  169. style={{display: 'inline-flex', marginRight: 5}}
  170. />
  171. ) : null}
  172. {text}
  173. </span>
  174. ),
  175. },
  176. {
  177. title: 'Age',
  178. dataIndex: 'age',
  179. key: 'age',
  180. width: 150,
  181. },
  182. {
  183. title: 'Address',
  184. dataIndex: 'address',
  185. key: 'address',
  186. },
  187. ],
  188. [selectedRowKeys]
  189. );
  190. return (
  191. <Table
  192. columns={columns}
  193. rowKey={rowKey}
  194. childrenRecordName={childrenRecordName}
  195. expandedRowKeys={expandedRowKeys}
  196. onExpandedRowsChange={rows => setExpandedRowKeys(rows.map(item => item[rowKey]))}
  197. dataSource={data}
  198. />
  199. );
  200. }
  201. export default ChildrenDataSelectedDemo;