Jelajahi Sumber

feat: 增加消息推送中心

lanjianrong 5 tahun lalu
induk
melakukan
199d378ae2

+ 114 - 0
src/components/RightContent/NotifyDropdown.tsx

@@ -0,0 +1,114 @@
+import consts from '@/consts'
+import { queryNoticeList, queryUnreadNotice, updateNotice } from '@/services/login'
+import { BellOutlined } from '@ant-design/icons'
+import { Badge, Tabs, List, Typography, Popover } from 'antd'
+import { useState, useCallback, useEffect } from 'react'
+import styles from './index.less'
+
+const DropdownContent = ({ noticeCount }) => {
+  const [state, setState] = useState({
+    noticesTotal: 0,
+    notices: []
+  })
+  const getNotices = useCallback(async () => {
+    const {
+      code = -1,
+      data: { message, total }
+    } = await queryNoticeList()
+    if (code === consts.RET_CODE.SUCCESS) {
+      setState({ ...state, noticesTotal: total, notices: message })
+    }
+  }, [])
+  useEffect(() => {
+    getNotices()
+  }, [])
+  const toggleNotice = id => {
+    const nNotices = state.notices.map(item => {
+      if (item.id === id) {
+        return { ...item, isRead: 1 }
+      }
+      return item
+    })
+    setState({ ...state, notices: nNotices })
+  }
+
+  const handleTitleClick = async item => {
+    // 未读
+    if (!item.isRead) {
+      const { code = -1 } = await updateNotice({ id: item.id })
+      if (code === consts.RET_CODE.SUCCESS) {
+        toggleNotice(item.id)
+      }
+    }
+  }
+  return (
+    <Tabs>
+      <Tabs.TabPane
+        key="1"
+        tab={
+          <div>
+            通知
+            {noticeCount ? <span> ({noticeCount}) </span> : null}
+          </div>
+        }
+      >
+        <List
+          bordered
+          dataSource={state.notices}
+          renderItem={item => (
+            <List.Item>
+              <List.Item.Meta
+                description={item.createTime}
+                title={
+                  <Typography.Paragraph
+                    onClick={() => handleTitleClick(item)}
+                    ellipsis={{ rows: 1, tooltip: true }}
+                    delete={!!item.isRead}
+                    style={{
+                      cursor: !item.isRead ? 'pointer' : '',
+                      width: '100%',
+                      marginBottom: 0
+                    }}
+                  >
+                    {item.content}
+                  </Typography.Paragraph>
+                }
+              />
+            </List.Item>
+          )}
+        />
+      </Tabs.TabPane>
+      <Tabs.TabPane tab="消息" key="2" />
+      <Tabs.TabPane tab="代办" key="3" />
+    </Tabs>
+  )
+}
+
+const NotifyDropdown = () => {
+  const [count, setCount] = useState(0)
+  useEffect(() => {
+    async function getCount() {
+      const { code = -1, data = 0 } = await queryUnreadNotice()
+      if (code === consts.RET_CODE.SUCCESS) {
+        setCount(data)
+      }
+    }
+    getCount()
+  }, [])
+  return (
+    <Popover
+      arrow
+      trigger="click"
+      overlayClassName="!min-w-360px"
+      content={<DropdownContent noticeCount={count} />}
+    >
+      <span className={`${styles.action} ${styles.notice}`}>
+        <Badge dot count={count}>
+          <BellOutlined />
+        </Badge>
+      </span>
+    </Popover>
+  )
+}
+
+export default NotifyDropdown

+ 14 - 0
src/components/RightContent/index.less

@@ -59,4 +59,18 @@
       background: rgba(255, 255, 255, 0.85);
     }
   }
+  .notice {
+    :global(.ant-tabs-content) {
+      width: 300px;
+    }
+    :global(.ant-badge) {
+      font-size: 18px;
+      svg {
+        width: 0.9em;
+      }
+    }
+    :global(.ant-badge-multiple-words) {
+      padding: 0 4px;
+    }
+  }
 }

+ 2 - 0
src/components/RightContent/index.tsx

@@ -4,6 +4,7 @@ import { Tag, Space } from 'antd'
 import React from 'react'
 import { useModel, SelectLang } from 'umi'
 import Avatar from './AvatarDropdown'
+import Notify from './NotifyDropdown'
 // import HeaderSearch from '../HeaderSearch'
 import styles from './index.less'
 
@@ -59,6 +60,7 @@ const GlobalHeaderRight: React.FC = () => {
       >
         <QuestionCircleOutlined />
       </span> */}
+      <Notify />
       <Avatar />
       {REACT_APP_ENV && REACT_APP_ENV !== 'prod' && (
         <span>

+ 18 - 2
src/services/login.js

@@ -5,6 +5,22 @@ import request from '@/basic/utils/request'
  * @param {*} params 登录所需参数
  */
 export async function apiLogin(params) {
-  const data = await request.post('/login', { data: params })
-  return data
+  return request.post('/login', { data: params })
+}
+
+/** 未读新消息个数 */
+export async function queryUnreadNotice() {
+  return request.get('/message/read')
+}
+
+/** 获取消息列表 */
+export async function queryNoticeList() {
+  return request('/message/list')
+}
+
+/** 消息设置已读 */
+export async function updateNotice(params) {
+  return request.post('/message/update', {
+    data: params
+  })
 }