index.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. import { useEffect, useState } from 'react';
  2. import { Button, message, notification } from 'antd';
  3. import { groupBy } from 'lodash';
  4. import moment from 'moment';
  5. import Service from '@/services/notice';
  6. import NoticeIcon from './NoticeIcon';
  7. import styles from './index.less';
  8. import encodeQuery from '@/utils/encodeQuery';
  9. import { getMenuPathByCode, MENUS_CODE } from '@/utils/menu';
  10. import useHistory from '@/hooks/route/useHistory';
  11. import { throttleTime } from 'rxjs/operators';
  12. import Icon from '@ant-design/icons';
  13. import useSendWebsocketMessage from '@/hooks/websocket/useSendWebsocketMessage';
  14. export type GlobalHeaderRightProps = {
  15. fetchingNotices?: boolean;
  16. onNoticeVisibleChange?: (visible: boolean) => void;
  17. onNoticeClear?: (tabName?: string) => void;
  18. };
  19. const getNoticeData = (notices: API.NoticeIconItem[]): Record<string, API.NoticeIconItem[]> => {
  20. if (!notices || notices.length === 0 || !Array.isArray(notices)) {
  21. return {};
  22. }
  23. const newNotices = notices.map((notice) => {
  24. const newNotice = { ...notice };
  25. if (newNotice.notifyTime) {
  26. newNotice.notifyTime = moment(notice.notifyTime as string).fromNow();
  27. }
  28. if (newNotice.id) {
  29. newNotice.key = newNotice.id;
  30. }
  31. // newNotice.avatar = 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg';
  32. newNotice.title = notice.topicName;
  33. newNotice.description = notice.message;
  34. return newNotice;
  35. });
  36. return groupBy(
  37. newNotices.map((item) => ({ ...item, state: item.state.value })),
  38. 'state',
  39. );
  40. };
  41. // const getUnreadData = (noticeData: Record<string, API.NoticeIconItem[]>) => {
  42. // const unreadMsg: Record<string, number> = {};
  43. // Object.keys(noticeData).forEach((key) => {
  44. // const value = noticeData[key];
  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. export const service = new Service('notifications');
  55. const NoticeIconView = () => {
  56. // const { initialState } = useModel('@@initialState');
  57. // const { currentUser } = initialState || {};
  58. const [notices, setNotices] = useState<API.NoticeIconItem[]>([]);
  59. const [unreadCount, setUnreadCount] = useState<number>(0);
  60. const [visible, setVisible] = useState<boolean>(false);
  61. const [loading, setLoading] = useState<boolean>(true);
  62. // const { data } = useRequest(getNotices);
  63. const history = useHistory();
  64. const [subscribeTopic] = useSendWebsocketMessage();
  65. const getUnread = () => {
  66. setLoading(true);
  67. service
  68. .fetchNotices(
  69. encodeQuery({
  70. terms: { state: 'unread' },
  71. sorts: { notifyTime: 'desc' },
  72. }),
  73. )
  74. .then((resp) => {
  75. if (resp.status === 200) {
  76. setNotices(resp.result?.data || []);
  77. setUnreadCount(resp.result?.total || 0);
  78. }
  79. setLoading(false);
  80. });
  81. };
  82. const subscribeNotice = () => {
  83. const id = `notification`;
  84. const topic = `/notifications`;
  85. subscribeTopic!(id, topic, {})
  86. ?.pipe(throttleTime(2000))
  87. .subscribe((resp: any) => {
  88. getUnread();
  89. notification.open({
  90. message: resp?.payload?.topicName,
  91. description: resp?.payload?.message,
  92. key: resp.payload.id,
  93. top: 60,
  94. btn: (
  95. <Button
  96. type="primary"
  97. onClick={() => {
  98. service.changeNoticeReadState(resp.payload.id).then((response) => {
  99. if (response.status === 200) {
  100. notification.close(resp.payload.id);
  101. getUnread();
  102. }
  103. });
  104. }}
  105. >
  106. 标记已读
  107. </Button>
  108. ),
  109. icon: <Icon type="exclamation-circle" style={{ color: '#E23D38' }} />,
  110. });
  111. });
  112. };
  113. useEffect(() => {
  114. getUnread();
  115. subscribeNotice();
  116. }, []);
  117. const noticeData = getNoticeData(notices);
  118. // const unreadMsg = getUnreadData(noticeData || {});
  119. const changeReadState = async (item: any) => {
  120. const resp = await service.changeNoticeReadState(item.id);
  121. if (resp.status === 200) {
  122. getUnread();
  123. }
  124. const url = getMenuPathByCode(MENUS_CODE['account/NotificationRecord']);
  125. history.push(url, { ...item });
  126. setVisible(false);
  127. };
  128. const clearReadState = async (title: string) => {
  129. const clearIds = (getNoticeData(notices).unread || []).map((item) => item.id) || [];
  130. const resp = await service.clearNotices(clearIds);
  131. if (resp.status === 200) {
  132. message.success(`${'清空了'} ${title}`);
  133. getUnread();
  134. }
  135. };
  136. return (
  137. <NoticeIcon
  138. className={styles.action}
  139. count={unreadCount}
  140. onItemClick={(item) => {
  141. changeReadState(item!);
  142. }}
  143. onClear={(title: string) => clearReadState(title)}
  144. loading={loading}
  145. clearText="当前标记为已读"
  146. viewMoreText="查看更多"
  147. onViewMore={() => {
  148. const url = getMenuPathByCode(MENUS_CODE['account/NotificationRecord']);
  149. history.push(url);
  150. setVisible(false);
  151. }}
  152. popupVisible={visible}
  153. onPopupVisibleChange={(see: boolean) => {
  154. setVisible(see);
  155. }}
  156. clearClose
  157. >
  158. <NoticeIcon.Tab
  159. tabKey="read"
  160. count={0}
  161. list={noticeData.unread}
  162. title="未读消息"
  163. emptyText="您已读完所有消息"
  164. showViewMore
  165. />
  166. {/* <NoticeIcon.Tab
  167. tabKey="handle"
  168. title="待办消息"
  169. emptyText="暂无消息"
  170. count={0}
  171. list={noticeData.handle}
  172. showViewMore
  173. /> */}
  174. </NoticeIcon>
  175. );
  176. };
  177. export default NoticeIconView;