index.tsx 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import React, { Component } from 'react';
  2. import { Icon, Tabs, Badge, Spin } from 'antd';
  3. import classNames from 'classnames';
  4. import HeaderDropdown from '../HeaderDropdown';
  5. import NoticeList, { NoticeIconTabProps } from './NoticeList';
  6. import styles from './index.less';
  7. const { TabPane } = Tabs;
  8. export interface NoticeIconData {
  9. avatar?: string | React.ReactNode;
  10. title?: React.ReactNode;
  11. description?: React.ReactNode;
  12. datetime?: React.ReactNode;
  13. extra?: React.ReactNode;
  14. style?: React.CSSProperties;
  15. key?: string | number;
  16. read?: boolean;
  17. }
  18. export interface NoticeIconProps {
  19. count?: number;
  20. bell?: React.ReactNode;
  21. className?: string;
  22. loading?: boolean;
  23. onClear?: (tabName: string, tabKey: string) => void;
  24. onItemClick?: (item: NoticeIconData, tabProps: NoticeIconTabProps) => void;
  25. onViewMore?: (tabProps: NoticeIconTabProps, e: MouseEvent) => void;
  26. onTabChange?: (tabTile: string) => void;
  27. style?: React.CSSProperties;
  28. onPopupVisibleChange?: (visible: boolean) => void;
  29. popupVisible?: boolean;
  30. clearText?: string;
  31. viewMoreText?: string;
  32. clearClose?: boolean;
  33. children: React.ReactElement<NoticeIconTabProps>[];
  34. }
  35. export default class NoticeIcon extends Component<NoticeIconProps> {
  36. public static Tab: typeof NoticeList = NoticeList;
  37. static defaultProps = {
  38. onItemClick: () => {},
  39. onPopupVisibleChange: () => {},
  40. onTabChange: () => {},
  41. onClear: () => {},
  42. onViewMore: () => {},
  43. loading: false,
  44. clearClose: false,
  45. emptyImage: 'https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg',
  46. };
  47. state = {
  48. visible: false,
  49. };
  50. onItemClick = (item: NoticeIconData, tabProps: NoticeIconTabProps) => {
  51. const { onItemClick } = this.props;
  52. if (onItemClick) {
  53. onItemClick(item, tabProps);
  54. }
  55. };
  56. onClear = (name: string, key: string) => {
  57. const { onClear } = this.props;
  58. if (onClear) {
  59. onClear(name, key);
  60. }
  61. };
  62. onTabChange = (tabType: string) => {
  63. const { onTabChange } = this.props;
  64. if (onTabChange) {
  65. onTabChange(tabType);
  66. }
  67. };
  68. onViewMore = (tabProps: NoticeIconTabProps, event: MouseEvent) => {
  69. const { onViewMore } = this.props;
  70. if (onViewMore) {
  71. onViewMore(tabProps, event);
  72. }
  73. };
  74. getNotificationBox() {
  75. const { children, loading, clearText, viewMoreText } = this.props;
  76. if (!children) {
  77. return null;
  78. }
  79. const panes = React.Children.map(children, (child: React.ReactElement<NoticeIconTabProps>) => {
  80. if (!child) {
  81. return null;
  82. }
  83. const { list, title, count, tabKey, showClear, showViewMore } = child.props;
  84. const len = list && list.length ? list.length : 0;
  85. const msgCount = count || count === 0 ? count : len;
  86. const tabTitle: string = msgCount > 0 ? `${title} (${msgCount})` : title;
  87. return (
  88. <TabPane tab={tabTitle} key={title}>
  89. <NoticeList
  90. clearText={clearText}
  91. viewMoreText={viewMoreText}
  92. data={list}
  93. onClear={() => this.onClear(title, tabKey)}
  94. onClick={item => this.onItemClick(item, child.props)}
  95. onViewMore={event => this.onViewMore(child.props, event)}
  96. showClear={showClear}
  97. showViewMore={showViewMore}
  98. title={title}
  99. {...child.props}
  100. />
  101. </TabPane>
  102. );
  103. });
  104. return (
  105. <Spin spinning={loading} delay={0}>
  106. <Tabs className={styles.tabs} onChange={this.onTabChange}>
  107. {panes}
  108. </Tabs>
  109. </Spin>
  110. );
  111. }
  112. handleVisibleChange = (visible: boolean) => {
  113. const { onPopupVisibleChange } = this.props;
  114. this.setState({ visible });
  115. if (onPopupVisibleChange) {
  116. onPopupVisibleChange(visible);
  117. }
  118. };
  119. render() {
  120. const { className, count, popupVisible, bell } = this.props;
  121. const { visible } = this.state;
  122. const noticeButtonClass = classNames(className, styles.noticeButton);
  123. const notificationBox = this.getNotificationBox();
  124. const NoticeBellIcon = bell || <Icon type="bell" className={styles.icon} />;
  125. const trigger = (
  126. <span className={classNames(noticeButtonClass, { opened: visible })}>
  127. <Badge count={count} style={{ boxShadow: 'none' }} className={styles.badge}>
  128. {NoticeBellIcon}
  129. </Badge>
  130. </span>
  131. );
  132. if (!notificationBox) {
  133. return trigger;
  134. }
  135. const popoverProps: {
  136. visible?: boolean;
  137. } = {};
  138. if ('popupVisible' in this.props) {
  139. popoverProps.visible = popupVisible;
  140. }
  141. return (
  142. <HeaderDropdown
  143. placement="bottomRight"
  144. overlay={notificationBox}
  145. overlayClassName={styles.popover}
  146. trigger={['click']}
  147. visible={visible}
  148. onVisibleChange={this.handleVisibleChange}
  149. {...popoverProps}
  150. >
  151. {trigger}
  152. </HeaderDropdown>
  153. );
  154. }
  155. }