Table.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. import { FC, useEffect, useRef, useState } from 'react';
  2. import React from 'react';
  3. import { makeStyles } from '@material-ui/core/styles';
  4. import Table from '@material-ui/core/Table';
  5. import TableBody from '@material-ui/core/TableBody';
  6. import TableCell from '@material-ui/core/TableCell';
  7. import TableContainer from '@material-ui/core/TableContainer';
  8. import TableRow from '@material-ui/core/TableRow';
  9. import Checkbox from '@material-ui/core/Checkbox';
  10. import { TableType } from './Types';
  11. import { Box, Button, Typography } from '@material-ui/core';
  12. import EnhancedTableHead from './TableHead';
  13. import { stableSort, getComparator } from './Utils';
  14. import Copy from '../../components/copy/Copy';
  15. import ActionBar from './ActionBar';
  16. import LoadingTable from './LoadingTable';
  17. const useStyles = makeStyles(theme => ({
  18. root: {
  19. // minHeight: '29vh',
  20. width: '100%',
  21. flexGrow: 1,
  22. // flexBasis: 0,
  23. // change scrollbar style
  24. '&::-webkit-scrollbar': {
  25. width: '8px',
  26. },
  27. '&::-webkit-scrollbar-track': {
  28. backgroundColor: '#f9f9f9',
  29. },
  30. '&::-webkit-scrollbar-thumb': {
  31. borderRadius: '8px',
  32. backgroundColor: '#eee',
  33. },
  34. },
  35. box: {
  36. backgroundColor: '#fff',
  37. },
  38. paper: {
  39. width: '100%',
  40. marginBottom: theme.spacing(2),
  41. },
  42. table: {
  43. minWidth: 750,
  44. },
  45. tableCell: {
  46. background: theme.palette.common.white,
  47. paddingLeft: theme.spacing(2),
  48. },
  49. hoverActionCell: {
  50. transition: '0.2s all',
  51. padding: 0,
  52. width: '50px',
  53. backgroundColor: '#fff',
  54. '& span': {
  55. opacity: 0,
  56. },
  57. },
  58. checkbox: {
  59. background: theme.palette.common.white,
  60. },
  61. rowHover: {
  62. '&:hover': {
  63. backgroundColor: '#f3fcfe !important',
  64. '& td': {
  65. background: 'inherit',
  66. },
  67. '& $hoverActionCell': {
  68. backgroundColor: theme.palette.primary.main,
  69. '& span': {
  70. opacity: 1,
  71. },
  72. },
  73. },
  74. },
  75. cell: {
  76. '& p': {
  77. display: 'inline-block',
  78. verticalAlign: 'middle',
  79. overflow: 'hidden',
  80. textOverflow: 'ellipsis',
  81. whiteSpace: 'nowrap',
  82. maxWidth: '300px',
  83. fontSize: '12.8px',
  84. },
  85. '& button': {
  86. textTransform: 'inherit',
  87. justifyContent: 'flex-start',
  88. },
  89. // '& svg': {
  90. // color: 'rgba(0, 0, 0, 0.33)',
  91. // },
  92. },
  93. noData: {
  94. paddingTop: theme.spacing(6),
  95. textAlign: 'center',
  96. letterSpacing: '0.5px',
  97. color: 'rgba(0, 0, 0, 0.6)',
  98. },
  99. }));
  100. const EnhancedTable: FC<TableType> = props => {
  101. const {
  102. selected,
  103. onSelected,
  104. isSelected,
  105. onSelectedAll,
  106. rows = [],
  107. colDefinitions,
  108. primaryKey,
  109. openCheckBox = true,
  110. disableSelect,
  111. noData,
  112. showHoverStyle,
  113. isLoading,
  114. } = props;
  115. const classes = useStyles();
  116. const [order, setOrder] = React.useState('asc');
  117. const [orderBy, setOrderBy] = React.useState<string>('');
  118. const [tableMouseStatus, setTableMouseStatus] = React.useState<boolean[]>([]);
  119. const [loadingRowCount, setLoadingRowCount] = useState<number>(0);
  120. const containerRef = useRef(null);
  121. const handleRequestSort = (event: any, property: string) => {
  122. const isAsc = orderBy === property && order === 'asc';
  123. setOrder(isAsc ? 'desc' : 'asc');
  124. setOrderBy(property);
  125. };
  126. useEffect(() => {
  127. const height: number = (containerRef.current as any)!.offsetHeight;
  128. // table header 57px, loading row 40px
  129. const count = Math.floor((height - 57) / 40);
  130. setLoadingRowCount(count);
  131. }, []);
  132. return (
  133. <TableContainer ref={containerRef} className={classes.root}>
  134. <Box height="100%" className={classes.box}>
  135. <Table
  136. stickyHeader
  137. className={classes.table}
  138. aria-labelledby="tableTitle"
  139. size="medium"
  140. aria-label="enhanced table"
  141. >
  142. <EnhancedTableHead
  143. colDefinitions={colDefinitions}
  144. numSelected={selected.length}
  145. order={order}
  146. orderBy={orderBy}
  147. onSelectAllClick={onSelectedAll}
  148. onRequestSort={handleRequestSort}
  149. rowCount={rows.length}
  150. openCheckBox={openCheckBox}
  151. />
  152. {!isLoading && (
  153. <TableBody>
  154. {rows && rows.length ? (
  155. stableSort(rows, getComparator(order, orderBy)).map(
  156. (row, index) => {
  157. const isItemSelected = isSelected(row);
  158. const labelId = `enhanced-table-checkbox-${index}`;
  159. const handleMouseEnter = () => {
  160. setTableMouseStatus(v => {
  161. const copy = [...v];
  162. copy[index] = true;
  163. return copy;
  164. });
  165. };
  166. const handleMouseLeave = () =>
  167. setTableMouseStatus(v => {
  168. const copy = [...v];
  169. copy[index] = false;
  170. return copy;
  171. });
  172. return (
  173. <TableRow
  174. hover={showHoverStyle}
  175. key={'row' + row[primaryKey] + index}
  176. onClick={event => onSelected(event, row)}
  177. role="checkbox"
  178. aria-checked={isItemSelected}
  179. tabIndex={-1}
  180. selected={isItemSelected && !disableSelect}
  181. classes={{
  182. hover: classes.rowHover,
  183. }}
  184. onMouseEnter={handleMouseEnter}
  185. onMouseLeave={handleMouseLeave}
  186. >
  187. {openCheckBox && (
  188. <TableCell
  189. padding="checkbox"
  190. className={classes.checkbox}
  191. >
  192. <Checkbox
  193. checked={isItemSelected}
  194. color="primary"
  195. inputProps={{ 'aria-labelledby': labelId }}
  196. />
  197. </TableCell>
  198. )}
  199. {colDefinitions.map((colDef, i) => {
  200. const { actionBarConfigs = [], needCopy = false } =
  201. colDef;
  202. const cellStyle = colDef.getStyle
  203. ? colDef.getStyle(row[colDef.id])
  204. : {};
  205. return colDef.showActionCell ? (
  206. <TableCell
  207. className={`${classes.cell} ${
  208. classes.tableCell
  209. } ${
  210. colDef.isHoverAction
  211. ? classes.hoverActionCell
  212. : ''
  213. }`}
  214. key="manage"
  215. style={cellStyle}
  216. >
  217. <ActionBar
  218. showLabel={tableMouseStatus[index]}
  219. configs={actionBarConfigs}
  220. isHoverType={colDef.isHoverAction}
  221. row={row}
  222. ></ActionBar>
  223. </TableCell>
  224. ) : (
  225. <TableCell
  226. key={'cell' + row[primaryKey] + i}
  227. padding={i === 0 ? 'none' : 'default'}
  228. align={colDef.align || 'left'}
  229. className={`${classes.cell} ${classes.tableCell}`}
  230. style={cellStyle}
  231. >
  232. {row[colDef.id] &&
  233. typeof row[colDef.id] === 'string' ? (
  234. <Typography title={row[colDef.id]}>
  235. {colDef.onClick ? (
  236. <Button
  237. color="primary"
  238. data-data={row[colDef.id]}
  239. data-index={index}
  240. onClick={e => {
  241. colDef.onClick &&
  242. colDef.onClick(e, row);
  243. }}
  244. >
  245. {row[colDef.id]}
  246. </Button>
  247. ) : (
  248. row[colDef.id]
  249. )}
  250. </Typography>
  251. ) : (
  252. <>
  253. {colDef.onClick ? (
  254. <Button
  255. color="primary"
  256. data-data={row[colDef.id]}
  257. data-index={index}
  258. onClick={e => {
  259. colDef.onClick &&
  260. colDef.onClick(e, row);
  261. }}
  262. >
  263. {row[colDef.id]}
  264. </Button>
  265. ) : (
  266. row[colDef.id]
  267. )}
  268. </>
  269. )}
  270. {needCopy && row[colDef.id] && (
  271. <Copy data={row[colDef.id]} />
  272. )}
  273. </TableCell>
  274. );
  275. })}
  276. </TableRow>
  277. );
  278. }
  279. )
  280. ) : (
  281. <tr>
  282. <td
  283. className={classes.noData}
  284. colSpan={colDefinitions.length}
  285. >
  286. {noData}
  287. </td>
  288. </tr>
  289. )}
  290. </TableBody>
  291. )}
  292. </Table>
  293. {isLoading && <LoadingTable count={loadingRowCount} />}
  294. </Box>
  295. </TableContainer>
  296. );
  297. };
  298. export default EnhancedTable;