diff --git a/src/forge/Head/AppPullRefresh.jsx b/src/forge/Head/AppPullRefresh.jsx new file mode 100644 index 000000000..d609c176e --- /dev/null +++ b/src/forge/Head/AppPullRefresh.jsx @@ -0,0 +1,108 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { Icon } from 'antd'; +import _ from 'lodash'; +import Nodata from '../Nodata'; + + +class PullRefresh extends Component { + constructor(props) { + super(props); + this.state = { + } + this.pullRef = {}; + // 节流 + this.onScrollList = _.throttle(this.handleScroll, 200, { + leading: false, + trailing: true, + }); + } + + componentDidMount() { + let dom = document.querySelector('.pull-refresh-wrap'); + dom && dom.addEventListener('scroll', this.onScrollList); + } + + componentWillUnmount() { + let dom = document.querySelector('.pull-refresh-wrap'); + dom && dom.removeEventListener('scroll', this.onScrollList) + } + + + handleScroll = () => { + if (this.props.count < this.props.pageSize) return; + if (this.props.type === 1 || this.props.type === 2) return; + const wrap = this.pullRef; + const currentScroll = wrap.scrollTop + wrap.clientHeight + + // 触底 + if (currentScroll >= (wrap.scrollHeight - 10)) { + this.loadData() + } + } + + + handleLoadClick = () => { + this.loadData(); + } + + loadData = () => { + this.props.onPullRefresh() + } + + + renderLoading() { + switch (this.props.type) { + case 0: // 加载更多 + return
显示更多
+ case 1: // 加载中 + return ( +
+ + 加载中... +
+ ) + case 2: // 无样式 + return
没有更多了
+ default: + return
没有更多了
+ } + } + + + render() { + const { className, count, children } = this.props; + return ( +
{ this.pullRef = dom }} + > + + {children} + + { + count < 1 && + } + + {/* 大于分页数据才显示loading */} + {/* {this.props.count >= this.props.pageSize ? this.renderLoading() : null} */} + +
+ + ) + } + +} + + +PullRefresh.propTypes = { + className: PropTypes.string, + children: PropTypes.any, + onPullRefresh: PropTypes.func.isRequired, + type: PropTypes.oneOf([0, 1, 2]), + count: PropTypes.number.isRequired, + pageSize: PropTypes.number.isRequired, +} + + +export default PullRefresh diff --git a/src/forge/Head/Header.js b/src/forge/Head/Header.js index 6232439e1..776e9e44f 100644 --- a/src/forge/Head/Header.js +++ b/src/forge/Head/Header.js @@ -48,6 +48,7 @@ class NewHeader extends Component { settings: null, visiblemyss: false, openSearch:false, + visible:false, //浮动消息框展示控制 } } componentDidMount() { @@ -93,9 +94,6 @@ class NewHeader extends Component { this.setState({ user: newProps.user }) - if (newProps.Headertop !== undefined) { - old_url = newProps.Headertop.old_url - } } educoderlogin = () => { @@ -277,8 +275,12 @@ class NewHeader extends Component { ) } + handleVisibleChange = visible => { + this.setState({ visible }); + }; + render() { - const { match} = this.props; + const { match ,hisroty ,showNotification} = this.props; let current_user = this.props.user; let { AccountProfiletype, @@ -287,6 +289,7 @@ class NewHeader extends Component { headtypesonClickbool, headtypess, settings, + visible, } = this.state; /*用户名称 用户头像url*/ let activeIndex = false; @@ -366,6 +369,7 @@ class NewHeader extends Component { let search_url = settings && settings.common && settings.common.search; let notice_url = settings && settings.common && settings.common.notice; + console.log(current_user); return (
@@ -428,7 +432,6 @@ class NewHeader extends Component { }
- {/* {search_url ? this.SearchInput(openSearch,search_url):""} */} { search_url && } { current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)? @@ -437,13 +440,18 @@ class NewHeader extends Component { :"" } - {/* {current_user && current_user.login && notice_url ? */} {current_user && current_user.login ? - }> - - - - + } + visible={visible} + onVisibleChange={this.handleVisibleChange} + > + + + + : "" diff --git a/src/forge/Head/NoticeContent.jsx b/src/forge/Head/NoticeContent.jsx index 970b4eb37..9e5bfea5f 100644 --- a/src/forge/Head/NoticeContent.jsx +++ b/src/forge/Head/NoticeContent.jsx @@ -1,157 +1,227 @@ import React, { useEffect, useState } from 'react'; -import { Badge, Menu} from 'antd'; +import { Badge, Menu } from 'antd'; +import { Link } from 'react-router-dom'; +import axios from 'axios'; +import AppPullRefresh from './AppPullRefresh'; import './header.scss'; import '../SecuritySetting/notice/manager/Index.scss'; import '../SecuritySetting/Index.scss'; -import '../SecuritySetting/notice/myNotice/Index.scss' -import { timeAgo } from '../../common/DateUtil'; -import { Link } from 'react-router-dom'; -import Axios from 'axios'; +import '../SecuritySetting/notice/myNotice/Index.scss'; -function NoticeContent(props) { - const[noticeType,setNoticeType] = useState("0"); - const[notice_unread_count,setNotice_unread_count]=useState();//未读系统通知数量 - const[letter_unread_count,setLetter_unread_count]=useState(10);//未读私信数量 - const[at_unread_count,setAt_unread_count]=useState();//未读@我数量 - const [message_list, setMessage_list] = useState([]); + +function NoticeContent({ showNotification, current_user: { login } }) { + const [initialize, setInitialize] = useState(true); + const [noticeType, setNoticeType] = useState("notification"); + const [letterUnreadCount, setLetterUnreadCount] = useState(0);//未读私信数量 + + const [noticeUnreadCount, setNoticeUnreadCount] = useState(0);//未读系统通知数量 + const [noticePage, setNoticePage] = useState(0); + const [noticeUnreadList, setNoticeUnreadList] = useState([]);//未读系统通知列表 + + const [atUnreadCount, setAtUnreadCount] = useState();//未读@我数量 + const [atPage, setAtPage] = useState(0); + const [atUnreadList, setAtUnreadList] = useState([]);//未读@我列表 + const [reload, setReload] = useState(0); useEffect(() => { const params = { - type:noticeType==="0"?"notification":noticeType==="2"?"atme":"", - limit: 20, - page: 0, + type: noticeType, + limit: 10, + page: noticeType === "notification" ? noticePage : noticeType === "atme" ? atPage : "", + status: 1, } getMessageList(params); - }, [noticeType]) + }, [noticePage, atPage]); + + useEffect(() => { + const params = { + type: noticeType, + limit: 10, + page: 0, + status: 1, + }; + if (initialize) { + params.type = "atme" + } + getMessageList(params); + }, [reload]); + function getMessageList(params) { - console.log(params); - Axios.get(`/users/yystopf/messages.json`, { + axios.get(`/users/${login}/messages.json`, { params: params, }).then((response) => { - setNotice_unread_count(response.data.unread_notification); - setAt_unread_count(response.data.unread_atme); - setMessage_list(response.data.messages); - console.log(message_list); + if (response && response.data) { + setNoticeUnreadCount(response.data.unread_notification); + setAtUnreadCount(response.data.unread_atme); + if (params.type === "notification") { + let list = response.data.messages; + if (params.page !== 0) { + list = [...noticeUnreadList, ...list]; + } + setNoticeUnreadList(list); + if (initialize) { + // 如果是第一次加载,根据数据量判断是否切换tab栏 + setInitialize(false); + if (response.data.unread_notification === 0 && response.data.unread_atme !== 0) { + setNoticeType("atme"); + } + } + } else if (params.type === "atme") { + let list = response.data.messages; + if (params.page !== 0) { + list = [...atUnreadList, ...list]; + } + setAtUnreadList(list); + } + } }) } - const[letter_unread_list,setLetter_unread_list]=useState([ - { - id: 122, - read: 0, //是否已读,0未读,1已读 - send_name: "蒋宇航", //消息发送人 - send_login: "jiangYuHang", //消息发送人的login,前端根据这个跳转到消息内页 - content: "私信内容", //最近一条未读消息的内容 - create_time: "2019-03-04 18:08", //发送时间 - }, - { - id: 122, - read: 0, //是否已读,0未读,1已读 - send_name: "景霞", //消息发送人 - send_login: "jiangYuHang", //消息发送人的login,前端根据这个跳转到消息内页 - content: "最好的OpenStack控制台,对标OpenStack社区Horizon项目,在易用性、页面性能等方面进行深度优化,提供简单控制台。", //最近一条未读消息的内容 - create_time: "2019-03-04 18:08", //发送时间 - }, - { - id: 122, - read: 0, //是否已读,0未读,1已读 - send_name: "陈银花", //消息发送人 - send_login: "jiangYuHang", //消息发送人的login,前端根据这个跳转到消息内页 - content: "A Vue 3 Component Library. Fairly Complete. Customizable Themes. Uses TypeScript. Not too Slow.", //最近一条未读消息的内容 - create_time: "2019-03-04 18:08", //发送时间 - }, - { - id: 122, - read: 0, //是否已读,0未读,1已读 - send_name: "蒋宇航", //消息发送人 - send_login: "jiangYuHang", //消息发送人的login,前端根据这个跳转到消息内页 - content: "您好?", //最近一条未读消息的内容 - create_time: "2019-03-04 18:08", //发送时间 - }, - { - id: 122, - read: 0, //是否已读,0未读,1已读 - send_name: "蒋宇航", //消息发送人 - send_login: "jiangYuHang", //消息发送人的login,前端根据这个跳转到消息内页 - content: "Open-source high-performance RISC-V processor", //最近一条未读消息的内容 - create_time: "2019-03-04 18:08", //发送时间 - }, - { - id: 122, - read: 0, //是否已读,0未读,1已读 - send_name: "蒋宇航", //消息发送人 - send_login: "jiangYuHang", //消息发送人的login,前端根据这个跳转到消息内页 - content: "构建卷积神经网络,训练模型,预测模型效果。", //最近一条未读消息的内容 - create_time: "2019-03-04 18:08", //发送时间 + + function readAll() { + axios.post(`/users/${login}/messages/read.json`, { + type: noticeType, + ids: [-1] + }).then((response) => { + let data = response.data; + if (!data) return; + if (data.status === 0) { + setReload(Math.random()); + } else { + showNotification(data.message); + } + }); + } + + // const [letter_unread_list, setLetter_unread_list] = useState([ + // { + // id: 122, + // read: 0, //是否已读,0未读,1已读 + // send_name: "蒋宇航", //消息发送人 + // send_login: "jiangYuHang", //消息发送人的login,前端根据这个跳转到消息内页 + // content: "私信内容", //最近一条未读消息的内容 + // create_time: "2019-03-04 18:08", //发送时间 + // }, + // ]); + + function readItem(item) { + axios.post(`/users/${login}/messages/read.json`, { + type: noticeType, + ids: [item.id] + }).then((response) => { + let data = response.data; + if (!data) return; + if (data.status === 0) { + changeReadMark(item); + item.notification_url && window.open(item.notification_url); + } else { + showNotification(data.message); + } + }); + } + + function changeReadMark(item) { + if (item.type === "notification") { + let list = noticeUnreadList.slice(); + let index = noticeUnreadList.indexOf(item); + list[index].status = 2; + setNoticeUnreadList(list); + } else if (item.type === "atme") { + let list = atUnreadList.slice(); + let index = atUnreadList.indexOf(item); + list[index].status = 2; + setAtUnreadList(list); } - ]); + } - return( + return (
-
- setNoticeType(e.key)}> - 系统通知 - 私信 - @我 - -
-
- - {message_list.map(item=>{ - // 系统消息 - if(noticeType ==="0" && item.type === "notification" && item.status===1){ - let contentStr = item.content.endsWith("") && item.content.length>=50 && item.content.replace("","").substr(0,40)+"..."; - // let iconName = item.type===1?"icon-xitongtongzhiicon":item.type===2?"icon-xiaoxi2":item.type===3?"icon-yixiuicon1":item.type===4?"icon-hebingqingqiuicon":item.type===5?"icon-lichengbeiicon":"icon-daimakuicon1"; - return( -
-
30 && item.content.length<=34?'65px':""}}> - - -
- =48?item.content.substr(0,48)+"...":item.content}}> - {item.time_ago} -
-
-
- ) - }else if(noticeType ==="2" && item.type === "atme" && item.status===1){ - // @我 - return( -
-
30 && item.content.length<=42?'65px':""}}> - -
- =56?item.content.substr(0,56)+"...@我":item.content}}> - {item.time_ago} -
-
-
- ) - } - })} +
+ setNoticeType(e.key)}> + 系统通知 + {/* 私信 */} + @我 + +
- {/* 私信 */} - {noticeType==="1"?letter_unread_list.length>0?letter_unread_list.map(item=>{ - return( -
-
=30 && item.content.length<=34?'65px':""}}> + {/* 系统通知 */} + {noticeType === "notification" && { setNoticePage(noticePage + 1); }} //触发加载ajax的function + // type={2} // 传送加载组件的状态 + count={noticeUnreadCount} // 数据当前的总数量 + pageSize={10} // + > + { + noticeUnreadList.map(item => { + let contentStr = item.content.endsWith("") && item.content.length >= 50 && item.content.replace("", "").substr(0, 40) + "..."; + return ( +
{ readItem(item) }}> +
30 && item.content.length <= 34 ? '65px' : "" }}> + + + + +
+ = 48 ? item.content.substr(0, 48) + "..." : item.content }}> + {item.time_ago} +
+
+
+ ) + }) + } +
+ } + + {/* @我 */} + {noticeType === "atme" && { setAtPage(atPage + 1); }} //触发加载ajax的function + // type={1} // 传送加载组件的状态 + count={atUnreadCount} // 数据当前的总数量 + pageSize={10} // + > + {atUnreadList.map(item => { + return ( +
{ readItem(item) }}> +
30 && item.content.length <= 42 ? '65px' : "" }}> + + + +
+ = 50 ? item.content.substr(0, 50) + "...@我" : item.content }}> + {item.time_ago} +
+
+
+ ) + }) + } +
+ } + + {/* 私信 */} + {/* {noticeType === "1" ? letter_unread_list.length > 0 ? letter_unread_list.map(item => { + return ( +
+
= 30 && item.content.length <= 34 ? '65px' : "" }}>
{item.send_name}: - =50?item.content.substr(0,50)+"...":item.content}}> - {item.create_time?timeAgo(item.create_time):"刚刚"} + = 50 ? item.content.substr(0, 50) + "..." : item.content }}> + {item.create_time ? timeAgo(item.create_time) : "刚刚"}
-
- ) - }):"暂无数据":""} -
- +
+ ) + }) : "暂无数据" : ""} */} + - +
+ ) } export default NoticeContent; diff --git a/src/forge/Head/header.scss b/src/forge/Head/header.scss index 2dc5a657b..d870a5f50 100644 --- a/src/forge/Head/header.scss +++ b/src/forge/Head/header.scss @@ -129,19 +129,26 @@ } } -//popover小尖尖 -.ant-popover-arrow{ - display: none; +// 右上角小铃铛单独样式 +.notice-popover{ + //popover小尖尖 + .ant-popover-arrow{ + display: none; + } + + //popover框 + .ant-popover-inner-content { + width: 386px; + height: 446px; + box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5); + border-radius: 4px; + margin-top: -10px; + padding: 12px 1px 12px 0; + } } -//popover框 -.ant-popover-inner-content { - width: 386px; - height: 446px; - box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5); - border-radius: 4px; - margin-top: -10px; - padding: 12px 1px 12px 0; +.messageHoverDiv .ant-menu-item{ + margin-right: 24px !important; } .hoverNotice-head{ @@ -164,23 +171,37 @@ font-weight: 400; text-shadow: 0.5px 0 0 #333; } + + .none_panels{ + height: 100%; + } } +.message-icon{ + position: relative; + .ant-scroll-number{ + right:12px; + } +} + + + .hoverNotice-buttom{ display: flex; justify-content: space-between; padding: 12px 18px; a{ color: #466AFF; - } - a:hover{ - opacity:0.85; + &:hover{ + opacity:0.85; + } } } .noticeCont-back{ &:hover{ background: #F3F4F6; + cursor: pointer; } } @@ -203,7 +224,6 @@ } .noticeCont-text{ - flex: auto; position: relative; max-height: 48px; @@ -221,4 +241,8 @@ margin-right: 12px; } } +} + +.text-center{ + text-align: center; } \ No newline at end of file