RightContent.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import React, { PureComponent } from 'react';
  2. import { FormattedMessage, formatMessage } from 'umi/locale';
  3. import { Spin, Tag, Menu, Icon, Avatar, Tooltip, message } from 'antd';
  4. import moment from 'moment';
  5. import groupBy from 'lodash/groupBy';
  6. import NoticeIcon from '../NoticeIcon';
  7. import HeaderSearch from '../HeaderSearch';
  8. import HeaderDropdown from '../HeaderDropdown';
  9. import SelectLang from '../SelectLang';
  10. import styles from './index.less';
  11. export default class GlobalHeaderRight extends PureComponent {
  12. getNoticeData() {
  13. const { notices = [] } = this.props;
  14. if (notices.length === 0) {
  15. return {};
  16. }
  17. const newNotices = notices.map(notice => {
  18. const newNotice = { ...notice };
  19. if (newNotice.datetime) {
  20. newNotice.datetime = moment(notice.datetime).fromNow();
  21. }
  22. if (newNotice.id) {
  23. newNotice.key = newNotice.id;
  24. }
  25. if (newNotice.extra && newNotice.status) {
  26. const color = {
  27. todo: '',
  28. processing: 'blue',
  29. urgent: 'red',
  30. doing: 'gold',
  31. }[newNotice.status];
  32. newNotice.extra = (
  33. <Tag color={color} style={{ marginRight: 0 }}>
  34. {newNotice.extra}
  35. </Tag>
  36. );
  37. }
  38. return newNotice;
  39. });
  40. return groupBy(newNotices, 'type');
  41. }
  42. getUnreadData = noticeData => {
  43. const unreadMsg = {};
  44. Object.entries(noticeData).forEach(([key, value]) => {
  45. if (!unreadMsg[key]) {
  46. unreadMsg[key] = 0;
  47. }
  48. if (Array.isArray(value)) {
  49. unreadMsg[key] = value.filter(item => !item.read).length;
  50. }
  51. });
  52. return unreadMsg;
  53. };
  54. changeReadState = clickedItem => {
  55. const { id } = clickedItem;
  56. const { dispatch } = this.props;
  57. dispatch({
  58. type: 'global/changeNoticeReadState',
  59. payload: id,
  60. });
  61. };
  62. render() {
  63. const {
  64. currentUser,
  65. fetchingNotices,
  66. onNoticeVisibleChange,
  67. onMenuClick,
  68. onNoticeClear,
  69. theme,
  70. } = this.props;
  71. const menu = (
  72. <Menu className={styles.menu} selectedKeys={[]} onClick={onMenuClick}>
  73. <Menu.Item key="userCenter">
  74. <Icon type="user" />
  75. <FormattedMessage id="menu.account.center" defaultMessage="account center" />
  76. </Menu.Item>
  77. <Menu.Item key="userinfo">
  78. <Icon type="setting" />
  79. <FormattedMessage id="menu.account.settings" defaultMessage="account settings" />
  80. </Menu.Item>
  81. <Menu.Item key="triggerError">
  82. <Icon type="close-circle" />
  83. <FormattedMessage id="menu.account.trigger" defaultMessage="Trigger Error" />
  84. </Menu.Item>
  85. <Menu.Divider />
  86. <Menu.Item key="logout">
  87. <Icon type="logout" />
  88. <FormattedMessage id="menu.account.logout" defaultMessage="logout" />
  89. </Menu.Item>
  90. </Menu>
  91. );
  92. const noticeData = this.getNoticeData();
  93. const unreadMsg = this.getUnreadData(noticeData);
  94. let className = styles.right;
  95. if (theme === 'dark') {
  96. className = `${styles.right} ${styles.dark}`;
  97. }
  98. return (
  99. <div className={className}>
  100. <HeaderSearch
  101. className={`${styles.action} ${styles.search}`}
  102. placeholder={formatMessage({ id: 'component.globalHeader.search' })}
  103. dataSource={[
  104. formatMessage({ id: 'component.globalHeader.search.example1' }),
  105. formatMessage({ id: 'component.globalHeader.search.example2' }),
  106. formatMessage({ id: 'component.globalHeader.search.example3' }),
  107. ]}
  108. onSearch={value => {
  109. console.log('input', value); // eslint-disable-line
  110. }}
  111. onPressEnter={value => {
  112. console.log('enter', value); // eslint-disable-line
  113. }}
  114. />
  115. <Tooltip title={formatMessage({ id: 'component.globalHeader.help' })}>
  116. <a
  117. target="_blank"
  118. href="https://pro.ant.design/docs/getting-started"
  119. rel="noopener noreferrer"
  120. className={styles.action}
  121. >
  122. <Icon type="question-circle-o" />
  123. </a>
  124. </Tooltip>
  125. <NoticeIcon
  126. className={styles.action}
  127. count={currentUser.unreadCount}
  128. onItemClick={(item, tabProps) => {
  129. console.log(item, tabProps); // eslint-disable-line
  130. this.changeReadState(item, tabProps);
  131. }}
  132. loading={fetchingNotices}
  133. locale={{
  134. emptyText: formatMessage({ id: 'component.noticeIcon.empty' }),
  135. clear: formatMessage({ id: 'component.noticeIcon.clear' }),
  136. viewMore: formatMessage({ id: 'component.noticeIcon.view-more' }),
  137. notification: formatMessage({ id: 'component.globalHeader.notification' }),
  138. message: formatMessage({ id: 'component.globalHeader.message' }),
  139. event: formatMessage({ id: 'component.globalHeader.event' }),
  140. }}
  141. onClear={onNoticeClear}
  142. onPopupVisibleChange={onNoticeVisibleChange}
  143. onViewMore={() => message.info('Click on view more')}
  144. clearClose
  145. >
  146. <NoticeIcon.Tab
  147. count={unreadMsg.notification}
  148. list={noticeData.notification}
  149. title="notification"
  150. emptyText={formatMessage({ id: 'component.globalHeader.notification.empty' })}
  151. emptyImage="https://gw.alipayobjects.com/zos/rmsportal/wAhyIChODzsoKIOBHcBk.svg"
  152. showViewMore
  153. />
  154. <NoticeIcon.Tab
  155. count={unreadMsg.message}
  156. list={noticeData.message}
  157. title="message"
  158. emptyText={formatMessage({ id: 'component.globalHeader.message.empty' })}
  159. emptyImage="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg"
  160. showViewMore
  161. />
  162. <NoticeIcon.Tab
  163. count={unreadMsg.event}
  164. list={noticeData.event}
  165. title="event"
  166. emptyText={formatMessage({ id: 'component.globalHeader.event.empty' })}
  167. emptyImage="https://gw.alipayobjects.com/zos/rmsportal/HsIsxMZiWKrNUavQUXqx.svg"
  168. showViewMore
  169. />
  170. </NoticeIcon>
  171. {currentUser.name ? (
  172. <HeaderDropdown overlay={menu}>
  173. <span className={`${styles.action} ${styles.account}`}>
  174. <Avatar
  175. size="small"
  176. className={styles.avatar}
  177. src={currentUser.avatar}
  178. alt="avatar"
  179. />
  180. <span className={styles.name}>{currentUser.name}</span>
  181. </span>
  182. </HeaderDropdown>
  183. ) : (
  184. <Spin size="small" style={{ marginLeft: 8, marginRight: 8 }} />
  185. )}
  186. <SelectLang className={styles.action} />
  187. </div>
  188. );
  189. }
  190. }