Commit 42a1a428 authored by guang.wu's avatar guang.wu

fix: 去掉订单消息模块

parent 6c3c8269
import React, { useState, useEffect } from 'react';
import { Tag, message, Badge } from 'antd';
import { connect } from 'dva';
import groupBy from 'lodash/groupBy';
import moment from 'moment';
import { BellOutlined } from '@ant-design/icons';
import NoticeIcon from '../NoticeIcon';
import styles from './index.less';
const GlobalHeaderRight = props => {
const { messageReminderComplexRef, unReadCount = 0 } = props;
const [count, setCount] = useState(0);
const open = () => {
messageReminderComplexRef.current.open();
};
useEffect(() => {
setCount(unReadCount);
}, [unReadCount]);
return (
<span className={styles['badge-box']} onClick={open}>
<Badge count={count} className={styles['badge-box__self']}>
<BellOutlined className={styles['badge-box__icon']} />
</Badge>
</span>
);
};
export default connect(({ messageReminder }) => ({
unReadCount: messageReminder.unReadCount,
}))(GlobalHeaderRight);
import { Tooltip } from 'antd';
import React from 'react';
import { NotificationOutlined } from '@ant-design/icons';
import { connect } from 'dva';
import Avatar from './AvatarDropdown';
import HeaderSearch from '../HeaderSearch';
import styles from './index.less';
import MessageIcon from './MessageIcon';
const GlobalHeaderRight = props => {
const { theme, layout, messageReminderComplexRef } = props;
const { theme, layout } = props;
let className = styles.right;
if (theme === 'dark' && layout === 'topmenu') {
......@@ -17,7 +15,6 @@ const GlobalHeaderRight = props => {
return (
<div className={className}>
<MessageIcon messageReminderComplexRef={messageReminderComplexRef} />
<Avatar />
</div>
);
......
import React, { useState, useEffect, forwardRef, useImperativeHandle } from 'react';
import { useHistory } from 'react-router-dom';
import { Modal, Tabs, Pagination, Spin, notification, Checkbox, Badge } from 'antd';
import { apiGetBussinessMsgList, apiGetBusinessMsgUnReadCount } from '@/services/messageReminder';
import { connect } from 'dva';
import Empty from '../Empty';
import styles from './index.less';
import { CHANNEL_ID } from '@/utils/constants';
const INIT_PAGINATION = {
pageSize: 20,
pageNo: 1,
};
const INIT_QUERY_PARAMS = {
type: '0',
readStatus: '',
};
const MessageItem = props => {
const { item, onMark, viewDetail } = props;
/**
* type: 0订单消息,1售后消息
* readStatus: 0未读,1已读
*/
const { readStatus, type } = item;
let message = {};
try {
message = JSON.parse(item.sendContent || '{}');
} catch (e) {
console.error('消息数据格式错误');
}
const goodList = message.items.map((good, index) => (
<div className={styles.good} key={String(index)}>
<span className={styles.good__name}>{good.skuName}</span>
<span className={styles.good__count}>x{good.quantity}</span>
</div>
));
return (
<div className={styles['complex-list__item']}>
<div className={styles['complex-list__item--header']}>
<span className={styles['order-number']}> 订单编号:{message.orderNo}</span>
<span className={styles.time}>订单时间:{message.time}</span>
<span className={styles['read-status']}>
{readStatus === 0 ? (
<a className={styles['read-status--un-read']} onClick={() => onMark([item.id])}>
标记为已读
</a>
) : (
<span className={styles['read-status--read']}>已读</span>
)}
</span>
</div>
<div className={styles['complex-list__item--body']}>{goodList}</div>
<div className={styles['complex-list__item--footer']}>
<div className={styles.actions}>
<a
onClick={() => viewDetail(message)}
className={[styles.notice, readStatus === 0 ? styles['un-read'] : ''].join(' ')}
>
{message.title},请查看
</a>
</div>
</div>
</div>
);
};
const Complex = props => {
const { dispatch, refInstance } = props;
const history = useHistory();
const [visible, setVisible] = useState(false);
const [dataTotal, setDataTotal] = useState(10);
const [loading, setLoading] = useState(false);
// 消息列表数据
const [messageData, setMessageData] = useState([]);
// 未读消息
const [orderUnReadCount, setOrderUnReadCount] = useState(0);
const [afterUnReadCount, setAfterUnReadCount] = useState(0);
// 消息列表参数
const [queryParams, setQueryParams] = useState({ ...INIT_QUERY_PARAMS, ...INIT_PAGINATION });
const userInfo = JSON.parse(localStorage.getItem('user') || '{}');
// 获取信息列表
const getMsgList = async () => {
const params = {
pageSize: queryParams.pageSize,
pageNo: queryParams.pageNo,
};
const data = {
channelId: CHANNEL_ID,
bussinessId: userInfo.supplierCode,
...queryParams,
};
delete data.pageSize;
delete data.pageNo;
setLoading(true);
const res = await apiGetBussinessMsgList(data, params);
setLoading(false);
if (!res) return;
if (res.code !== '0000') {
notification.error(res.msg);
return;
}
const { content, totalElements } = res.data;
setMessageData(content);
setDataTotal(totalElements);
};
// 获取未读数量
const getMsgReadCount = async () => {
const data = {
channelId: CHANNEL_ID,
bussinessId: userInfo.supplierCode,
};
const res = await apiGetBusinessMsgUnReadCount(data);
if (res.code !== '0000') {
notification.error(res.msg);
return;
}
const { afterSalesUnRead, orderUnRead } = res.data;
setOrderUnReadCount(orderUnRead);
setAfterUnReadCount(afterSalesUnRead);
};
// 分页操作
const onPageChange = (page, size) => {
const current = queryParams.pageSize !== size ? 1 : page;
setQueryParams({
...queryParams,
pageNo: current,
pageSize: size,
});
};
// 筛选未读/已读
const onReadStatusChange = e => {
let { value } = e.target;
if (queryParams.readStatus === e.target.value) {
value = '';
}
setQueryParams({
...queryParams,
readStatus: value,
});
};
// 过滤参数,获取当前页未读消息数据的id
const onFilterMessageParams = msgList =>
msgList.filter(message => message.readStatus === 0).map(item => item.id);
const open = () => {
setVisible(true);
getMsgReadCount();
};
const close = () => {
setMessageData([]);
setVisible(false);
};
//
/**
* 跳转到详情
* type
* 1-待发货订单
* 2-超时发货
* 3-仅退款(未发货)申请单
* 4-仅退款申请单
* 5-退货退款申请单
* 6-退货入库待审核
*/
const viewDetail = message => {
const { orderNo, type } = message;
if ([1, 2].includes(type)) {
history.push({
pathname: '/orderManage/pendingDeliveryOrder',
query: { orderNo },
});
}
if ([3, 4, 5, 6].includes(type)) {
history.push({
pathname: '/afterSaleManage',
query: { orderNo },
});
}
close();
};
// 切换消息类型
const onTabChange = index => {
setQueryParams({
...queryParams,
...INIT_PAGINATION,
type: index,
});
};
// 标记已读
const onMark = idsList => {
if (!idsList.length) {
return;
}
const payload = {
channelId: CHANNEL_ID,
bussinessId: userInfo.supplierCode,
type: Number(queryParams.type),
idsList,
};
dispatch({
type: 'messageReminder/setMarkRead',
payload,
options: {
setLoading,
callback: () => {
getMsgReadCount();
getMsgList();
},
},
});
};
// 展开初始化
useEffect(() => {
if (visible) {
getMsgList();
}
}, [visible, queryParams]);
useEffect(() => {
if (!visible) {
setQueryParams({ ...INIT_QUERY_PARAMS, ...INIT_PAGINATION });
}
}, [visible]);
useImperativeHandle(refInstance, () => ({
open,
}));
const modalProps = {
bodyStyle: {
display: 'flex',
flexWrap: 'wrap',
padding: 0,
backgroundColor: '#f7f8f9',
},
wrapClassName: 'complex-modal',
width: '880px',
height: '650px',
visible,
title: <span className="title-icon">消息提醒</span>,
footer: null,
onCancel: close,
};
const TabRender = tabProps => {
const { title, count = 0 } = tabProps;
return (
<span className={styles['tab-render']}>
{title}
<Badge overflowCount={999} count={count} />
</span>
);
};
const FilterRender = filterProps => (
<div className={styles['filter-box']}>
<div className={styles['filter-box__content']}>
<Checkbox checked={queryParams.readStatus === '0'} value="0" onChange={onReadStatusChange}>
未读
</Checkbox>
<Checkbox checked={queryParams.readStatus === '1'} value="1" onChange={onReadStatusChange}>
已读
</Checkbox>
</div>
<div className={styles['filter-box__actions']}>
<a onClick={() => onMark(onFilterMessageParams(messageData))}>全部标记为已读</a>
</div>
</div>
);
return (
<Modal {...modalProps}>
<Tabs
className={styles.tabs}
activeKey={queryParams.type}
tabBarStyle={{
width: '150px',
}}
tabPosition="left"
tabBarGutter={0}
onChange={onTabChange}
>
<Tabs.TabPane tab={<TabRender title="订单消息" count={orderUnReadCount} />} key="0" />
<Tabs.TabPane tab={<TabRender title="售后消息" count={afterUnReadCount} />} key="1" />
</Tabs>
<div className={styles['tab-pane']}>
<Spin spinning={loading}>
<FilterRender />
<div className={styles['complex-list']}>
{visible && messageData.length ? (
messageData.map((item, index) => (
<MessageItem
key={String(index)}
item={item}
onMark={onMark}
viewDetail={viewDetail}
/>
))
) : (
<Empty text="暂无数据" />
)}
</div>
</Spin>
{dataTotal > 0 ? (
<div className={styles.pagination}>
<Pagination
onChange={onPageChange}
total={dataTotal}
showTotal={(total, range) => `第${range[0]}-${range[1]}条 /总共${total}条`}
showSizeChanger
pageSize={queryParams.pageSize}
current={queryParams.pageNo}
/>
</div>
) : (
''
)}
</div>
</Modal>
);
};
const MiddleComponent = connect(({ messageReminder }) => ({
unReadCount: messageReminder.unReadCount,
unReadData: messageReminder.unReadData,
}))(Complex);
// 注意:这里不要在Component上使用ref;换个属性名字比如refInstance;不然会导致覆盖
export default forwardRef((props, ref) => <MiddleComponent {...props} refInstance={ref} />);
.tab-pane {
flex: 1;
}
.tabs {
:global .ant-tabs-tab {
height: 48px;
line-height: 48px;
border-bottom: 1px solid #efefef;
}
:global .ant-tabs-ink-bar {
height: 40px !important;
margin-top: 4px !important;
}
}
.tab-render {
display: flex;
align-items: center;
:global .ant-badge {
margin-left: 5px;
}
}
.filter-box {
display: flex;
margin-top: 15px;
padding-right: 25px;
&__content {
flex: 1;
}
}
:global .complex-modal {
.ant-modal-header {
text-align: center;
background-color: #2d8cf0;
}
.ant-modal-title,
.ant-modal-close {
color: #fff;
.title-icon {
padding-left: 25px;
background: #1890ff url('https://img.op5po.net/notice.94d42513.png') no-repeat 0 center;
background-size: 20px 20px;
}
}
}
.complex-list {
min-height: 300px;
max-height: 500px;
margin-top: 20px;
padding-right: 25px;
overflow-y: auto;
& :first-child {
margin: 0;
}
&__item {
margin-top: 15px;
background: #fff;
border: 1px solid #efefef;
&--header {
display: flex;
width: 100%;
height: 40px;
padding: 0 15px;
line-height: 40px;
background: #fff;
border-bottom: 1px solid #efefef;
.order-number,
.time {
flex: 1;
padding-right: 20px;
color: #999;
word-break: break-all;
// white-space: nowrap
}
.read-status {
min-width: 80px;
text-align: right;
&--read {
color: #999;
}
}
}
&--body {
padding: 10px 15px;
.good {
display: flex;
padding: 5px 0;
line-height: 1.5;
&__name {
flex: 1;
word-break: break-all;
}
&__count {
min-width: 80px;
text-align: right;
}
}
}
&--footer {
display: flex;
border-top: 1px solid #efefef;
.actions {
display: flex;
width: 100%;
margin-left: 20px;
line-height: 40px;
.notice {
position: relative;
display: block;
flex: 1;
color: #999;
font-weight: 400;
&.un-read {
color: #ff1515;
&::before {
display: inline-block;
width: 6px;
height: 6px;
margin-top: 17px;
margin-right: 6px;
vertical-align: top;
background: #ff1515;
border-radius: 50%;
content: '';
}
}
&::after {
position: absolute;
top: 50%;
right: 10px;
display: block;
width: 0;
height: 0;
margin-top: -3px;
border: 6px solid transparent;
border-left: 8px solid #999;
content: '';
}
}
}
}
}
}
.pagination {
width: 100%;
padding: 25px;
text-align: right;
}
import React from 'react';
import styles from './index.less';
const MessageReminderEmpty = props => {
const { text } = props;
return (
<div className={styles.notFound}>
<img
src="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg"
alt="not found"
/>
<div>{text}</div>
</div>
);
};
export default MessageReminderEmpty;
@import '~antd/es/style/themes/default.less';
.notFound {
padding: 73px 0 88px;
color: @text-color-secondary;
text-align: center;
background-color: #fff;
img {
display: inline-block;
height: 76px;
margin-bottom: 16px;
}
}
import React, { useState, useEffect } from 'react';
import { Badge, notification, Spin } from 'antd';
import { CloseOutlined, DoubleLeftOutlined, DoubleRightOutlined } from '@ant-design/icons';
import classNames from 'classnames';
import { useHistory } from 'react-router-dom';
// import copy from 'copy-to-clipboard';
import { connect } from 'dva';
import { apiGetBussinessMsgList } from '@/services/messageReminder';
import Empty from '../Empty';
import styles from './index.less';
import { CHANNEL_ID } from '@/utils/constants';
const Horn = props => {
const { count, toggle, animationClass, stowClass, onStow } = props;
return (
<div
className={classNames(styles.horn, styles[animationClass], styles[stowClass])}
onClick={toggle}
>
<span className={styles['horn--btn']} onClick={e => onStow(e)}>
{stowClass ? <DoubleLeftOutlined /> : <DoubleRightOutlined />}
</span>
<Badge count={count}>
<div className={styles['horn--num']}>消息提醒</div>
</Badge>
</div>
);
};
const Message = props => {
const {
toggle,
animationClass,
messageData,
openComplex,
onMark,
loading,
viewDetail,
onStow,
stowClass,
} = props;
const ReminderItem = args => {
const { item } = args;
let message = {};
try {
message = JSON.parse(item.sendContent || '{}');
} catch (e) {
console.error('消息数据格式错误');
}
return (
<div className={styles.item}>
<div className={styles.info}>
<span className={styles['order-number']}>{message.orderNo}</span>
<span className={styles['mark-read']} onClick={() => onMark([item.id])}>
标记为已读
</span>
</div>
<div className={styles.time}>
<span>{message.time}</span>
</div>
<div className={styles.notice}>
<a onClick={() => viewDetail(message)}>{message.title},请查看</a>
</div>
</div>
);
};
return (
<div className={classNames(styles['message-reminder'], styles[animationClass])}>
<div className={styles['message-reminder__header']}>
<div className={styles['message-reminder__header--title']}>
消息提醒
<span className={styles.close} onClick={toggle}>
<CloseOutlined />
</span>
</div>
</div>
<div className={styles['message-reminder__body']}>
<Spin spinning={loading}>
<div className={styles['message-reminder__body--list']}>
{messageData.length ? (
messageData
.filter((e, i) => i < 10)
.map(item => <ReminderItem key={item.id} item={item} />)
) : (
<Empty text="暂无数据" />
)}
</div>
</Spin>
</div>
<div className={styles['message-reminder__footer']}>
<div className={styles['message-reminder__footer--actions']}>
<div className={styles.more} onClick={openComplex}>
查看更多
</div>
<div
className={styles['mark-all']}
onClick={() => {
onMark(messageData.filter((e, i) => i < 10).map(item => item.id));
}}
>
全部标记为已读
</div>
</div>
</div>
</div>
);
};
const Simple = props => {
const { dispatch, unReadCount, complexRef, unReadData } = props;
const history = useHistory();
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false);
const [count, setCount] = useState(0);
const [hornClass, setHornClass] = useState('');
const [messageClass, setMessageClass] = useState('');
const [stowClass, setStowClass] = useState('');
const [messageData, setMessageData] = useState([]);
let userInfo = JSON.parse(localStorage.getItem('user') || '{}');
const toggle = () => {
setVisible(!visible);
};
// 初始化获取数据
const getMsgList = async () => {
if (!userInfo.supplierCode) {
userInfo = JSON.parse(localStorage.getItem('user') || '{}');
setTimeout(() => {
getMsgList();
}, 1000);
return;
}
const params = {
pageNo: 1,
pageSize: 200,
};
const data = {
channelId: CHANNEL_ID,
bussinessId: userInfo.supplierCode,
readStatus: 0,
};
setLoading(true);
const res = await apiGetBussinessMsgList(data, params);
setLoading(false);
if (!res) return;
if (res.code !== '0000') {
notification.error(res.msg);
return;
}
const { content } = res.data;
setVisible(!!content.length);
dispatch({
type: 'messageReminder/setUnReadData',
payload: content,
options: {
unReadCount: content.length,
},
});
};
const viewDetail = message => {
const { orderNo, type } = message;
console.log(type);
if ([1, 2].includes(type)) {
history.push({
pathname: '/orderManage/pendingDeliveryOrder',
query: { orderNo },
});
}
if ([3, 4, 5, 6].includes(type)) {
history.push({
pathname: '/afterSaleManage',
query: { orderNo },
});
}
toggle();
};
// 打开消息提醒弹框
const openComplex = () => {
complexRef.current.open();
toggle();
};
const onStow = e => {
e.preventDefault();
e.stopPropagation();
if (stowClass) {
setStowClass('');
} else {
setStowClass('stow');
}
};
// 标记已读信息
const onMark = idsList => {
if (!idsList.length) {
return;
}
const payload = {
channelId: CHANNEL_ID,
bussinessId: userInfo.supplierCode,
idsList,
};
dispatch({
type: 'messageReminder/setMarkRead',
payload,
options: {
setLoading,
},
});
};
useEffect(() => {
setCount(unReadCount);
}, [unReadCount]);
useEffect(() => {
setHornClass(visible ? 'hide' : 'show');
setMessageClass(visible ? 'show' : 'hide');
}, [visible]);
useEffect(() => {
getMsgList();
}, []);
useEffect(() => {
setMessageData(unReadData);
}, [unReadData]);
const hornProps = {
animationClass: hornClass,
stowClass,
toggle,
count,
onStow,
};
const messageProps = {
animationClass: messageClass,
toggle,
messageData,
openComplex,
onMark,
loading,
viewDetail,
};
// 隐藏消息提醒
return (
<>
<Horn {...hornProps} />
<Message {...messageProps} />
</>
);
};
export default connect(({ messageReminder }) => ({
unReadCount: messageReminder.unReadCount,
unReadData: messageReminder.unReadData,
}))(Simple);
.horn {
position: fixed;
right: 30px;
bottom: 10px;
z-index: 19;
// width: 112px;
// height: 50px;
color: #fff;
background: #2d8cf0;
transform: translate(0, 0);
cursor: pointer;
opacity: 1;
transition: 0.2s ease-in;
&.hide {
transform: translateY(100%) scale(0.3);
opacity: 0;
transition: 0.2s ease-out;
}
&.stow {
transform: translateX(142px);
transition: 0.2s ease-out;
}
&--btn {
display: inline-block;
width: 20px;
height: 50px;
line-height: 50px;
text-align: center;
vertical-align: top;
background: #006ad9;
border-right: 1px solid #2479d3;
&:hover {
background: #2479d3;
transition: 0.2s ease-out;
}
}
&--num {
width: 112px;
height: 50px;
color: #fff;
font-size: 16px;
line-height: 50px;
text-align: center;
&::before {
display: inline-block;
width: 20px;
height: 20px;
margin-right: 5px;
vertical-align: -3px;
background: url('https://img.op5po.net/notice.94d42513.png') no-repeat;
background-size: 100% 100%;
content: '';
}
}
}
.message-reminder {
position: fixed;
right: 10px;
bottom: 10px;
z-index: 19;
display: flex;
flex-direction: column;
width: 404px;
height: 412px;
background: #fff;
transform: translate(50%, 110%) scale(0.5);
transition: 0.2s ease-in;
&.hide {
transform: translate(50%, 110%) scale(0.5);
opacity: 0;
transition: 0.2s ease-out;
}
&.show {
transform: translateY(0) scale(1);
opacity: 1;
transition: 0.2s ease-in;
}
&__header {
&--title {
position: relative;
padding-left: 35px;
color: #fff;
font-weight: 700;
font-size: 16px;
line-height: 50px;
background: #1890ff url('https://img.op5po.net/notice.94d42513.png') no-repeat 10px center;
background-size: 20px 20px;
.close {
position: absolute;
right: 20px;
font-weight: 400;
cursor: pointer;
}
}
}
&__body {
flex: 1;
padding: 15px;
overflow: auto;
background: #f8f8f9;
&--list {
& .item:first-child {
margin-top: 0;
}
.item {
margin-top: 15px;
padding: 15px 0;
background: #fff;
border: 1px solid #efefef;
&:hover {
// border-color: #ccc;
// transition: 0.2s linear;
}
}
.info {
display: flex;
padding: 0 15px;
.order-number {
flex: 1;
padding-left: 20px;
background: url('https://img.op5po.net/order_no.f4e0a8b3.png') no-repeat scroll 0 center;
}
.mark-read {
color: #178fff;
cursor: pointer;
}
}
.time {
display: flex;
margin-top: 12px;
padding: 0 15px;
span {
flex: 1;
padding-left: 20px;
background: url('https://img.op5po.net/datetime.1b5f9199.png') no-repeat scroll 0 center;
}
}
.notice {
margin-top: 12px;
padding: 10px 15px 0;
border-top: 1px solid #efefef;
a {
position: relative;
display: block;
color: #ff1515;
&::before {
display: inline-block;
width: 6px;
height: 6px;
margin-top: 8px;
margin-right: 6px;
vertical-align: top;
background: #ff1515;
border-radius: 50%;
content: '';
}
&::after {
position: absolute;
top: 50%;
right: 0;
display: block;
width: 0;
height: 0;
margin-top: -3px;
border: 6px solid transparent;
border-left: 8px solid #999;
content: '';
}
}
}
}
}
&__footer {
background-color: #fff;
border: 1px solid #efefef;
&--actions {
display: flex;
& div:first-child {
border: none;
}
> div {
flex: 1;
color: #2d8cf0;
line-height: 40px;
text-align: center;
border-left: 1px solid #efefef;
cursor: pointer;
// &:hover {
// background: #f9f9f9;
// cursor: pointer;
// }
}
}
}
}
import Simple from './Simple';
import Complex from './Complex';
const MessageReminder = {};
MessageReminder.Simple = Simple;
MessageReminder.Complex = Complex;
export default MessageReminder;
......@@ -12,15 +12,11 @@ import { Icon as LegacyIcon } from '@ant-design/compatible';
import { Result, Button, Layout, Menu } from 'antd';
import Authorized from '@/utils/Authorized';
import RightContent from '@/components/GlobalHeader/RightContent';
import MessageReminder from '@/components/MessageReminder';
import { getAuthorityFromRouter, getUrlSearchParams, getToken } from '@/utils/utils';
import { getSocketUrl } from '@/services/messageReminder';
import logo from '../assets/logo.png';
import style from './BasicLayout.less';
import Socket from '@/utils/websocket';
import { CHANNEL_ID } from '@/utils/constants';
const { Sider } = Layout;
const { SubMenu } = Menu;
......@@ -53,24 +49,12 @@ const BasicLayout = props => {
} = props;
const [siderCollapsed, setSiderCollapsed] = useState(false);
const messageReminderComplexRef = useRef();
// const audioRef = useRef()
useEffect(() => {
try {
const token = getToken();
const socket = new Socket({
url: getSocketUrl({ token, channelId: CHANNEL_ID }),
});
socket.connection();
socket.event.on('message', msg => {
dispatch({
type: 'messageReminder/setUnReadData',
payload: [JSON.parse(msg.data)],
});
});
} catch (e) {
console.log(e);
}
......@@ -82,9 +66,6 @@ const BasicLayout = props => {
dispatch({
type: 'menu/getMenuData',
});
dispatch({
type: 'messageReminder/getUnReadMsgList',
});
}
}, []);
/**
......@@ -184,9 +165,7 @@ const BasicLayout = props => {
);
}}
menuDataRender={() => menuData}
rightContentRender={rightProps => (
<RightContent {...rightProps} messageReminderComplexRef={messageReminderComplexRef} />
)}
rightContentRender={rightProps => <RightContent {...rightProps} />}
pageTitleRender={() => ''}
menuHeaderRender={() => (
<div className={style['custom-title-box']} onClick={toIndex}>
......@@ -199,10 +178,6 @@ const BasicLayout = props => {
<Authorized authority={authorized.authority} noMatch={noMatch}>
{children}
</Authorized>
<MessageReminder.Simple complexRef={messageReminderComplexRef} />
<MessageReminder.Complex ref={messageReminderComplexRef} />
{/* <Button ref={audioRef} onClick={() => { socket.play() }}>声音</Button> */}
</ProLayout>
);
......
import { apiUpdageBusinessMsgStatus } from '@/services/messageReminder';
const MessageReminderModel = {
namespace: 'messageReminder',
state: {
unReadCount: 0, // 未读总数
unReadData: [], // 未读数据
},
effects: {
*setUnReadData({ payload, options }, { put, call }) {
yield setTimeout(() => {
put({
type: 'setUnReadData',
payload,
options,
});
});
},
*setMarkRead({ payload, options = {} }, { put, call }) {
const { setLoading } = options;
if (setLoading) {
setLoading(true);
}
const res = yield call(apiUpdageBusinessMsgStatus, payload);
// console.log(res)
if (setLoading) {
setLoading(false);
}
if (res.code !== '0000') {
return;
}
if (
Object.hasOwnProperty.call(options, 'callback') &&
typeof options.callback === 'function'
) {
options.callback(res);
}
yield put({
type: 'updateUnReadData',
payload,
options,
});
},
},
reducers: {
setUnReadData(state, { payload, options = {} }) {
const currentData = [...payload, ...state.unReadData];
let unReadCount = state.unReadCount + 1;
if (options.unReadCount || options.unReadCount === 0) {
// eslint-disable-next-line prefer-destructuring
unReadCount = options.unReadCount;
}
return { ...state, unReadData: currentData, unReadCount };
},
updateUnReadData(state, { payload, options = {} }) {
// 删除已读的数据
const currentData = state.unReadData.filter(message => !payload.idsList.includes(message.id));
// 重置当前未读数量
const unReadCount = currentData.length; // state.unReadCount - (options.readCount || payload.idsList.length || 1)
return { ...state, unReadCount, unReadData: currentData };
},
},
};
export default MessageReminderModel;
import request from '@/utils/request';
import config from '../../config/env.config';
const { msgApi, wsApi } = config;
export const getSocketUrl = ({ token, channelId }) =>
`${wsApi}/ws?token=${token}&channelId=${channelId}`;
const { msgApi } = config;
/**
* @name 商户消息列表
......
import EventEmitter from 'events';
import { Modal } from 'antd';
class Socket extends EventEmitter {
event = new EventEmitter();
constructor(options) {
super();
this.options = options;
this.reconnectCount = 0;
this.socket = null;
this.taskRemindInterval = null;
this.connected = false;
this.waitingSendData = [];
this.heartBeatTimer = null;
return this;
}
connection = () => {
const { url, timeout = 0 } = this.options;
// 检测当前浏览器是什么浏览器来决定用什么socket
if ('WebSocket' in window) {
console.log('WebSocket');
this.socket = new WebSocket(url);
} else if ('MozWebSocket' in window) {
console.log('MozWebSocket');
// eslint-disable-next-line no-undef
this.socket = new MozWebSocket(url);
} else {
console.log('SockJS');
// eslint-disable-next-line no-undef
this.socket = new SockJS(url);
}
// 链接回调
this.socket.onopen = this.onopen;
this.socket.onmessage = this.onmessage;
this.socket.onclose = this.onclose;
this.socket.onerror = this.onerror;
this.socket.sendMessage = this.sendMessage;
// 检测返回的状态码 如果socket.readyState不等于1则连接失败,关闭连接
if (timeout) {
const time = setTimeout(() => {
if (this.socket && this.socket.readyState !== 1) {
console.log('主动触发关闭');
this.socket.close();
}
clearTimeout(time);
}, timeout);
}
};
// 连接成功触发
onopen = () => {
const { heartBeatTime } = this.options;
console.log('ws: 连接成功', new Date().getTime());
this.connected = true;
this.heartBeat(heartBeatTime);
this.checkWaitingData();
this.event.emit('open');
};
// 后端向前端推得数据
onmessage = msg => {
console.log('ws:接收数据:', msg);
this.event.emit('message', msg);
// 打印出后端推得数据
};
// 关闭连接触发
onclose = e => {
console.log('ws: 关闭连接', new Date().getTime());
this.connected = false; // 关闭将标识符改为true
if (this.heartBeatTimer) {
clearTimeout(this.heartBeatTimer);
}
this.event.emit('close', e);
// 最多重连10次
if (this.reconnectCount > 10) {
this.reconnectCount = 0;
return;
}
const reconnect = () => {
if (this.taskRemindInterval) {
clearTimeout(this.taskRemindInterval);
}
this.taskRemindInterval = setTimeout(() => {
if (!this.connected) {
this.reconnectCount++;
this.connection();
reconnect();
}
}, 5000);
};
if (process.env.NODE_ENV === 'production') {
reconnect();
}
};
onerror = e => {
try {
this.socket = null;
this.event.emit('error', e);
} catch {
console.log('ws: error', e);
}
};
sendMessage = value => {
console.log('ws: send', value);
// 向后端发送数据
if (this.socket) {
if (!this.connected) {
this.waitingSendData.unshift(value);
return;
}
const sendValue = typeof value === 'string' ? value : JSON.stringify(value);
if (this.socket.readyState === this.socket.OPEN) {
this.socket.send(sendValue);
}
}
};
checkWaitingData() {
console.log('ws: checkWaitingData', this.waitingSendData);
if (this.waitingSendData.length) {
this.sendMessage(this.waitingSendData.splice(0, 1));
this.checkWaitingData();
}
}
// 保持连接-默认每3分钟重置一下服务器关闭时间
heartBeat(time) {
// console.log('ws: call heartBeat', new Date().getTime());
this.heartBeatTimer = setTimeout(() => {
// console.log('ws: sent heart beat', new Date().getTime());
this.sendMessage('HeartBeat');
this.heartBeat(time);
}, time || 45000);
}
}
export default Socket;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment