SqlPreview.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import React from 'react'
  2. import { findDOMNode } from 'react-dom'
  3. import memoizeOne from 'memoize-one'
  4. import { Table } from 'antd'
  5. import { ColumnProps, TableProps } from 'antd/lib/table'
  6. import { PaginationConfig } from 'antd/lib/pagination'
  7. import Styles from '../View.less'
  8. import { IExecuteSqlResponse, ISqlColumn } from '../types'
  9. import { DEFAULT_SQL_PREVIEW_PAGE_SIZE, SQL_PREVIEW_PAGE_SIZE_OPTIONS } from '../constants'
  10. import { getTextWidth } from 'utils/util'
  11. export interface ISqlPreviewProps {
  12. loading: boolean
  13. response: IExecuteSqlResponse
  14. height?: number
  15. size: TableProps<any>['size']
  16. }
  17. interface ISqlPreviewStates {
  18. tableBodyHeight: number
  19. }
  20. export class SqlPreview extends React.PureComponent<ISqlPreviewProps, ISqlPreviewStates> {
  21. private static readonly TableCellPaddingWidth = 8
  22. private static readonly TableCellMaxWidth = 300
  23. private static ExcludeElems = ['.ant-table-thead', '.ant-pagination.ant-table-pagination']
  24. private static basePagination: PaginationConfig = {
  25. pageSize: DEFAULT_SQL_PREVIEW_PAGE_SIZE,
  26. pageSizeOptions: SQL_PREVIEW_PAGE_SIZE_OPTIONS.map((size) => size.toString()),
  27. showQuickJumper: true,
  28. showSizeChanger: true
  29. }
  30. private prepareTable = memoizeOne((columns: ISqlColumn[], resultList: any[]) => {
  31. const rowKey = `rowKey_${new Date().getTime()}`
  32. resultList.forEach((record, idx) => record[rowKey] = Object.values(record).join('_') + idx)
  33. const tableColumns = columns.map<ColumnProps<any>>((col) => {
  34. const width = SqlPreview.computeColumnWidth(resultList, col.name)
  35. return {
  36. title: col.name,
  37. dataIndex: col.name,
  38. width
  39. }
  40. })
  41. return { tableColumns, rowKey }
  42. })
  43. private static computeColumnWidth = (resultList: any[], columnName: string) => {
  44. let textList = resultList.map((item) => item[columnName])
  45. textList = textList.filter((text, idx) => textList.indexOf(text) === idx)
  46. const contentMaxWidth = textList.reduce((maxWidth, text) =>
  47. Math.max(maxWidth, getTextWidth(text, '700', '14px')), -Infinity)
  48. const titleWidth = getTextWidth(columnName, '500', '14px')
  49. let maxWidth = Math.max(contentMaxWidth, titleWidth) + (2 * SqlPreview.TableCellPaddingWidth) + 2
  50. maxWidth = Math.min(maxWidth, SqlPreview.TableCellMaxWidth)
  51. return maxWidth
  52. }
  53. private table = React.createRef<Table<any>>()
  54. public state: Readonly<ISqlPreviewStates> = { tableBodyHeight: 0 }
  55. public componentDidMount () {
  56. const tableBodyHeight = this.computeTableBody()
  57. this.setState({ tableBodyHeight })
  58. }
  59. public componentDidUpdate () {
  60. const newTableBodyHeight = this.computeTableBody()
  61. if (Math.abs(newTableBodyHeight - this.state.tableBodyHeight) > 5) { // FIXED table body compute vibration
  62. this.setState({ tableBodyHeight: newTableBodyHeight })
  63. }
  64. }
  65. private computeTableBody = () => {
  66. const tableDom = findDOMNode(this.table.current) as Element
  67. if (!tableDom) { return 0 }
  68. const excludeElemsHeight = SqlPreview.ExcludeElems.reduce((acc, exp) => {
  69. const elem = tableDom.querySelector(exp)
  70. if (!elem) { return acc }
  71. const style = window.getComputedStyle(elem)
  72. const { marginTop, marginBottom } = style
  73. const height = elem.clientHeight + parseInt(marginTop, 10) + parseInt(marginBottom, 10)
  74. return acc + height
  75. }, 0)
  76. const tableBodyHeight = this.props.height - excludeElemsHeight
  77. return tableBodyHeight
  78. }
  79. public render () {
  80. const { loading, response, size } = this.props
  81. const { totalCount, columns = [], resultList =[] } = response
  82. const paginationConfig: PaginationConfig = {
  83. ...SqlPreview.basePagination,
  84. total: totalCount
  85. }
  86. const { tableColumns, rowKey } = this.prepareTable(columns, resultList)
  87. const scroll: TableProps<any>['scroll'] = {
  88. x: tableColumns.reduce((acc, col) => (col.width as number + acc), 0),
  89. y: this.state.tableBodyHeight
  90. }
  91. return (
  92. <Table
  93. ref={this.table}
  94. className={Styles.sqlPreview}
  95. bordered
  96. size={size}
  97. pagination={paginationConfig}
  98. dataSource={resultList}
  99. columns={tableColumns}
  100. scroll={scroll}
  101. loading={loading}
  102. rowKey={rowKey}
  103. />
  104. )
  105. }
  106. }
  107. export default SqlPreview