index.jsx 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. import React from 'react';
  2. import { Table, Switch, ButtonGroup, Button, Tooltip, Tag } from '@douyinfe/semi-ui';
  3. export default class App extends React.Component {
  4. constructor(props) {
  5. super(props);
  6. const dataTotalSize = 46;
  7. const columns = [
  8. {
  9. title: 'Name',
  10. dataIndex: 'name',
  11. width: 150,
  12. },
  13. {
  14. title: 'Age',
  15. dataIndex: 'age',
  16. width: 150,
  17. },
  18. {
  19. title: 'Address',
  20. dataIndex: 'address',
  21. },
  22. {
  23. render: (text, record) => (
  24. <Tooltip content={record.description}>
  25. <Tag color="green">Show Info</Tag>
  26. </Tooltip>
  27. ),
  28. width: 150,
  29. },
  30. ];
  31. const data = [];
  32. for (let i = 0; i < dataTotalSize; i++) {
  33. let age = (i * 1000) % 149 ;
  34. let name = `Edward King ${i}`;
  35. data.push({
  36. key: '' + i,
  37. name,
  38. age,
  39. address: `London, Park Lane no. ${i} Lake Park`,
  40. description: `My name is ${name}, I am ${age} years old, living in New York No. ${i + 1} Lake Park.`,
  41. });
  42. }
  43. this.data = data;
  44. this.mergeColumns = (column, columns, keys = ['dataIndex']) => {
  45. columns = [...columns];
  46. columns.forEach((curColumn, index) => {
  47. let isTarget = !!(keys && keys.length);
  48. for (let key of keys) {
  49. if (column[key] !== curColumn[key]) {
  50. isTarget = false;
  51. break;
  52. }
  53. }
  54. if (isTarget) {
  55. columns[index] = { ...curColumn, ...column };
  56. }
  57. });
  58. return columns;
  59. };
  60. this.filterData = (filters, dataSource) => {
  61. dataSource = [...dataSource];
  62. filters.forEach(filter => {
  63. let filteredValue = filter.filteredValue;
  64. let dataIndex = filter.dataIndex;
  65. if (Array.isArray(filteredValue) && filteredValue.length && dataIndex) {
  66. dataSource = dataSource.filter(
  67. data => filteredValue.filter(value => String(data[dataIndex]).indexOf(value) > -1).length
  68. );
  69. }
  70. });
  71. return dataSource;
  72. };
  73. this.getSelfSorterColumn = columns => {
  74. columns = columns || this.state.columns;
  75. return columns.filter(column => !!column.sorter)[0];
  76. };
  77. this.getSelfFilterColumns = columns => {
  78. columns = columns || this.state.columns;
  79. return columns.filter(column => Array.isArray(column.filteredValue) && column.filteredValue.length);
  80. };
  81. this.sortData = (sortObj, dataSource) => {
  82. let { sorter, sortOrder, dataIndex } = sortObj;
  83. if (sorter && sortOrder && typeof sorter !== 'function') {
  84. sorter = (a, b) => (a[dataIndex] > b[dataIndex] ? 1 : -1);
  85. }
  86. if (typeof sorter === 'function') {
  87. dataSource = [...dataSource].sort(sorter);
  88. if (sortOrder === 'descend') {
  89. dataSource = dataSource.reverse();
  90. }
  91. }
  92. return dataSource;
  93. };
  94. this.fetchData = (currentPage = 1, sorter = {}, filters = []) => {
  95. // console.log(`FetchData currentPage: `, currentPage);
  96. let pagination = { ...this.state.pagination, currentPage };
  97. return new Promise((res, rej) => {
  98. setTimeout(() => {
  99. let data = [...this.data];
  100. data = this.sortData(sorter, data);
  101. data = this.filterData(filters, data);
  102. let dataSource = data.slice(
  103. (currentPage - 1) * pagination.pageSize,
  104. currentPage * pagination.pageSize
  105. );
  106. pagination.total = data.length;
  107. res({
  108. dataSource,
  109. pagination,
  110. sorter,
  111. filters,
  112. });
  113. }, 1500);
  114. });
  115. };
  116. this.setPage = (currentPage, sorter, filters) => {
  117. if (this.state.loading) {
  118. return;
  119. }
  120. if (typeof currentPage !== 'number') {
  121. currentPage = (this.state.pagination && this.state.pagination.currentPage) || 1;
  122. }
  123. sorter = sorter || this.getSelfSorterColumn();
  124. filters = filters || this.getSelfFilterColumns();
  125. this.setState({ loading: true });
  126. this.fetchData(currentPage, sorter, filters)
  127. .then(({ dataSource, pagination, sorter, filters }) => {
  128. let columns = [...this.state.columns];
  129. columns = this.mergeColumns(sorter, columns);
  130. for (let filterObj of filters) {
  131. columns = this.mergeColumns(filterObj, columns);
  132. }
  133. this.setState({
  134. loading: false,
  135. pagination,
  136. dataSource,
  137. columns,
  138. });
  139. })
  140. .catch(err => {
  141. console.error(err);
  142. this.setState({ loading: false });
  143. });
  144. };
  145. this.toggleFixHeader = checked => {
  146. let scroll = { ...this.state.scroll };
  147. if (checked) {
  148. scroll.y = 300;
  149. } else {
  150. scroll.y = null;
  151. }
  152. this.setState({ scroll });
  153. };
  154. this.toggleFixColumns = checked => {
  155. let columns = [...this.state.columns];
  156. let scroll = { ...this.state.scroll };
  157. let expandCellFixed = this.state.expandCellFixed;
  158. let rowSelection = this.state.rowSelection;
  159. if (checked) {
  160. columns[0].fixed = true;
  161. if (rowSelection) {
  162. rowSelection = { ...rowSelection, fixed: true };
  163. }
  164. if (columns.length > 1) {
  165. columns[columns.length - 1].fixed = 'right';
  166. }
  167. scroll.x = '150%';
  168. expandCellFixed = true;
  169. } else {
  170. columns.forEach(column => {
  171. column.fixed = false;
  172. });
  173. scroll.x = null;
  174. expandCellFixed = false;
  175. if (rowSelection) {
  176. rowSelection = { ...rowSelection, fixed: false };
  177. }
  178. }
  179. this.setState({
  180. rowSelection,
  181. expandCellFixed,
  182. columns,
  183. scroll,
  184. });
  185. };
  186. this.toggleRowSelection = checked => {
  187. let rowSelection = this.state.rowSelection;
  188. // const anyColumnFixed = this.state.columns.some(column => !!column.fixed);
  189. if (checked) {
  190. rowSelection = {
  191. width: 48,
  192. fixed: true,
  193. onChange: (selectedRowKeys, selectedRows) =>
  194. console.log(
  195. 'Selection changed, selectedRowKeys: ',
  196. selectedRowKeys,
  197. 'selectedRows: ',
  198. selectedRows
  199. ),
  200. };
  201. } else {
  202. rowSelection = null;
  203. }
  204. this.setState({ rowSelection });
  205. };
  206. this.toggleLoading = checked => {
  207. let loading = this.state.loading;
  208. if (checked) {
  209. loading = true;
  210. } else {
  211. loading = false;
  212. }
  213. this.setState({ loading });
  214. };
  215. this.toggleExpandedRowRender = checked => {
  216. let expandedRowRender = this.state.expandedRowRender;
  217. if (checked) {
  218. expandedRowRender = record => {
  219. return {
  220. children: <p>{record.description}</p>,
  221. fixed: 'left',
  222. };
  223. };
  224. } else {
  225. expandedRowRender = null;
  226. }
  227. this.setState({ expandedRowRender });
  228. };
  229. this.toggleShowSorter = checked => {
  230. let columns = [...this.state.columns];
  231. if (checked) {
  232. columns.forEach(column => column.dataIndex === 'age' && (column.sorter = true));
  233. } else {
  234. columns.forEach(column => (column.sorter = null));
  235. }
  236. this.setState({ columns });
  237. };
  238. this.toggleShowFilter = checked => {
  239. let columns = [...this.state.columns];
  240. if (checked) {
  241. columns.forEach(column => {
  242. if (column.dataIndex === 'name') {
  243. column.filters = [
  244. {
  245. text: '姓名中包含 1',
  246. value: '1',
  247. },
  248. {
  249. text: '姓名中包含 2',
  250. value: '2',
  251. },
  252. {
  253. text: '姓名中包含 3',
  254. value: '3',
  255. },
  256. ];
  257. column.filteredValue = [];
  258. }
  259. });
  260. } else {
  261. columns.forEach(column => {
  262. column.filters = null;
  263. column.filteredValue = null;
  264. });
  265. }
  266. this.setState({ columns });
  267. if (!checked) {
  268. this.setPage(null, null, []);
  269. }
  270. };
  271. this.onChange = (data = {}) => {
  272. console.log('Table changed: ', data);
  273. let { pagination, sorter, filters } = data;
  274. this.setPage(pagination.currentPage, sorter, filters);
  275. };
  276. this.onExpandedRowsChange = rows => {
  277. console.log('Expanded rows changed to: ', rows);
  278. const expandedRowKeys = (Array.isArray(rows) && rows.map(row => row.key)) || [];
  279. this.setState({ expandedRowKeys });
  280. };
  281. this.toggleExpandedRowKeys = checked => {
  282. let defaultExpandedRowKeys = [];
  283. if (checked) {
  284. let dataSource = [...this.state.dataSource];
  285. defaultExpandedRowKeys.push(
  286. ...dataSource.reduce((arr, data) => {
  287. if (data.key) {
  288. arr.push(data.key);
  289. }
  290. return arr;
  291. }, [])
  292. );
  293. this.toggleExpandedRowRender(true);
  294. }
  295. this.setState({ defaultExpandedRowKeys });
  296. };
  297. this.toggleBordered = checked => {
  298. let bordered = false;
  299. if (checked) {
  300. bordered = true;
  301. }
  302. this.setState({ bordered });
  303. };
  304. this.toggleResizable = checked => {
  305. let resizable = !!checked || false;
  306. this.setState({ resizable, bordered: resizable });
  307. };
  308. this.toggleHideHeader = checked => {
  309. let showHeader = true;
  310. if (checked) {
  311. showHeader = false;
  312. }
  313. this.setState({ showHeader });
  314. };
  315. this.toggleFooter = checked => {
  316. const footer = checked ? dataSource => <p style={{ margin: 0 }}>This is footer.</p> : null;
  317. this.setState({ footer });
  318. };
  319. this.toggleTitle = checked => {
  320. const title = checked ? 'This is title.' : null;
  321. this.setState({ title });
  322. };
  323. this.toggleHidePagination = checked => {
  324. let pagination = checked
  325. ? false
  326. : {
  327. currentPage: 1,
  328. pageSize: 8,
  329. total: data.length,
  330. onPageChange: page => this.setPage(page),
  331. };
  332. this.setState({ pagination });
  333. };
  334. this.toggleDataSource = checked => {
  335. if (checked) {
  336. this.setState({ dataSource: [] });
  337. } else {
  338. this.setPage();
  339. }
  340. };
  341. this.switchPagination = position => {
  342. let pagination = this.state.pagination;
  343. const defaultPagination = {
  344. currentPage: 1,
  345. pageSize: 8,
  346. total: data.length,
  347. onPageChange: page => this.setPage(page),
  348. };
  349. const positions = ['bottom', 'top', 'both'];
  350. if (position === true || position === false) {
  351. pagination = position ? { ...defaultPagination, ...pagination } : false;
  352. } else if (positions.includes(position)) {
  353. pagination = { ...defaultPagination, ...pagination, position };
  354. }
  355. this.setState({ pagination });
  356. };
  357. this.switchSize = size => {
  358. this.setState({ size });
  359. };
  360. this.state = {
  361. loading: false,
  362. columns,
  363. scroll: {},
  364. rowSelection: null,
  365. expandedRowRender: null,
  366. expandCellFixed: false,
  367. defaultExpandAllRows: false,
  368. defaultExpandedRowKeys: [],
  369. title: null,
  370. footer: null,
  371. expandedRowKeys: [],
  372. showHeader: true,
  373. resizable: false,
  374. pagination: {
  375. currentPage: 1,
  376. pageSize: 8,
  377. total: data.length,
  378. onPageChange: page => this.setPage(page),
  379. },
  380. dataSource: [],
  381. };
  382. this.TableSwitch = function TableSwitch({
  383. text,
  384. children,
  385. checked,
  386. onChange,
  387. style = { display: 'inline-flex', alignItems: 'center', margin: 5 },
  388. }) {
  389. const switchProps = { onChange };
  390. if (checked != null) {
  391. switchProps.checked = !!checked;
  392. }
  393. return (
  394. <span style={style}>
  395. <span>{text}</span>
  396. {children != null ? children : <Switch size="small" {...switchProps} />}
  397. </span>
  398. );
  399. };
  400. }
  401. componentDidMount() {
  402. this.setPage(1);
  403. }
  404. render() {
  405. let {
  406. columns,
  407. dataSource,
  408. pagination,
  409. loading,
  410. scroll,
  411. rowSelection,
  412. expandedRowRender,
  413. expandCellFixed,
  414. expandedRowKeys,
  415. bordered,
  416. resizable,
  417. title,
  418. footer,
  419. showHeader,
  420. defaultExpandAllRows,
  421. defaultExpandedRowKeys,
  422. size,
  423. } = this.state;
  424. const wrapStyle = { marginBottom: 15, display: 'flex', justifyContent: 'space-around', flexWrap: 'wrap' };
  425. const TableSwitch = this.TableSwitch;
  426. return (
  427. <div>
  428. <div style={wrapStyle}>
  429. <TableSwitch text="固定表头:" checked={scroll && scroll.y} onChange={this.toggleFixHeader} />
  430. <TableSwitch text="隐藏表头:" onChange={this.toggleHideHeader} />
  431. <TableSwitch text="显示标题:" onChange={this.toggleTitle} />
  432. <TableSwitch text="显示底部:" onChange={this.toggleFooter} />
  433. <TableSwitch text="固定列:" onChange={this.toggleFixColumns} />
  434. <TableSwitch text="显示选择列:" onChange={this.toggleRowSelection} />
  435. <TableSwitch text="显示加载状态:" onChange={this.toggleLoading} checked={loading} />
  436. <TableSwitch
  437. text="无数据:"
  438. onChange={this.toggleDataSource}
  439. checked={!dataSource || !dataSource.length}
  440. />
  441. <TableSwitch text="开启排序功能:" onChange={this.toggleShowSorter} />
  442. <TableSwitch text="开启过滤功能:" onChange={this.toggleShowFilter} />
  443. <TableSwitch
  444. text="开启行展开功能:"
  445. onChange={this.toggleExpandedRowRender}
  446. checked={typeof expandedRowRender === 'function'}
  447. />
  448. <TableSwitch text="展开当前所有行:" onChange={this.toggleExpandedRowKeys} />
  449. <TableSwitch text="显示边框:" onChange={this.toggleBordered} checked={bordered} />
  450. <TableSwitch text="开启列伸缩功能:" onChange={this.toggleResizable} />
  451. <TableSwitch text="尺寸:">
  452. <ButtonGroup>
  453. <Button onClick={() => this.switchSize('default')}>Default</Button>
  454. <Button onClick={() => this.switchSize('middle')}>Middle</Button>
  455. <Button onClick={() => this.switchSize('small')}>Small</Button>
  456. </ButtonGroup>
  457. </TableSwitch>
  458. <TableSwitch text="分页控件:">
  459. <ButtonGroup>
  460. <Button onClick={() => this.switchPagination('bottom')}>Bottom</Button>
  461. <Button onClick={() => this.switchPagination('top')}>Top</Button>
  462. <Button onClick={() => this.switchPagination('both')}>Both</Button>
  463. <Button onClick={() => this.switchPagination(false)}>None</Button>
  464. </ButtonGroup>
  465. </TableSwitch>
  466. </div>
  467. <Table
  468. size={size}
  469. defaultExpandedRowKeys={defaultExpandedRowKeys}
  470. onExpandedRowsChange={this.onExpandedRowsChange}
  471. title={title}
  472. footer={footer}
  473. showHeader={showHeader}
  474. bordered={bordered}
  475. onChange={this.onChange}
  476. expandCellFixed={expandCellFixed}
  477. expandedRowRender={expandedRowRender}
  478. defaultExpandAllRows={defaultExpandAllRows}
  479. expandedRowKeys={expandedRowKeys}
  480. rowSelection={rowSelection}
  481. scroll={scroll}
  482. columns={columns}
  483. dataSource={dataSource}
  484. pagination={pagination}
  485. loading={loading}
  486. resizable={resizable}
  487. />
  488. </div>
  489. );
  490. }
  491. }