类似云图日志分析, 后续补充图
    支持功能

    1. 下载
    2. 复制
    3. 搜索
    4. 定位
    5. 行号
    6. 样式
    7. 全屏
    8. 回到顶部
    9. 虚拟加载
    1. import React, { Fragment, PureComponent } from '@alipay/bigfish/react';
    2. import { Empty, BackTop } from '@alipay/bigfish/antd';
    3. import cs from '@alipay/bigfish/util/classnames';
    4. import styles from './index.less';
    5. export interface LogResultProps<T extends any> {
    6. className?: string;
    7. style?: React.CSSProperties;
    8. logRender?: (item: T) => JSX.Element;
    9. dataSource?: T[];
    10. empty?: JSX.Element;
    11. footerRender?: () => JSX.Element;
    12. }
    13. /**
    14. * 1. 动态计算 height
    15. * 2. 添加滚动顶部
    16. * 3. 添加行数
    17. */
    18. class LogResult<T> extends PureComponent<LogResultProps<T>> {
    19. domRef: any = React.createRef<HTMLDivElement | null>();
    20. static defaultProps: LogResultProps<any> = {
    21. empty: <Empty />,
    22. dataSource: [],
    23. footerRender: () => <Fragment />,
    24. };
    25. getSnapshotBeforeUpdate(prevProps: LogResultProps<T>) {
    26. // @ts-ignore
    27. if (prevProps.dataSource?.length < this.props.dataSource?.length) {
    28. const list = this.domRef.current;
    29. return list.scrollHeight - list.scrollTop;
    30. }
    31. return null;
    32. }
    33. componentDidUpdate(
    34. _prevProps: LogResultProps<T>,
    35. _prevState: any,
    36. snapshot: number
    37. ) {
    38. if (snapshot !== null) {
    39. const list = this.domRef.current;
    40. list.scrollTop = list.scrollHeight - snapshot;
    41. }
    42. }
    43. goToTop = () => {
    44. if (this.domRef.current) {
    45. this.domRef.current.scrollTop = 0;
    46. }
    47. };
    48. renderLine = (item: T) => {
    49. const { logRender } = this.props;
    50. if (typeof logRender === 'function') {
    51. return logRender(item);
    52. }
    53. return <span>{JSON.stringify(item)}</span>;
    54. };
    55. /** 动态计算最大 height */
    56. render() {
    57. const {
    58. className,
    59. empty,
    60. style,
    61. dataSource = [],
    62. footerRender,
    63. } = this.props;
    64. const cls = cs(styles.wrapper, className);
    65. return (
    66. <div className={cls} style={style} ref={this.domRef}>
    67. <div className={styles.content}>
    68. {dataSource.length ? (
    69. <Fragment>
    70. {dataSource.map((item, index) => (
    71. <Fragment key={index}>
    72. <div className={styles.line}>{this.renderLine(item)}</div>
    73. </Fragment>
    74. ))}
    75. <BackTop
    76. onClick={this.goToTop}
    77. target={() => this.domRef.current}
    78. visibilityHeight={200}
    79. />
    80. </Fragment>
    81. ) : (
    82. empty
    83. )}
    84. <div className="footer">{footerRender?.()}</div>
    85. </div>
    86. </div>
    87. );
    88. }
    89. }
    90. export default LogResult;
    1. .wrapper {
    2. .content {
    3. counter-reset: line-numbering;
    4. .line {
    5. font-size: 12px;
    6. line-height: 14px;
    7. &::before {
    8. display: inline-block;
    9. padding-right: 1em;
    10. content: counter(line-numbering);
    11. counter-increment: line-numbering;
    12. }
    13. }
    14. }
    15. }