Commit 302f9e28 authored by 叶飞's avatar 叶飞

feat: notice

parent 175a10ee
...@@ -23,8 +23,7 @@ class HttpRequest { ...@@ -23,8 +23,7 @@ class HttpRequest {
// } // }
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
if (!config.ignoreSite && this.getSite()) { if (!config.ignoreSite && this.getSite()) {
// config.headers['civ-site'] = this.getSite(); config.headers['civ-site'] = this.getSite();
config.headers['civ-site'] = "192_168_19_105_site_c8de50fc";
} }
this.removePending(config); //在一个ajax发送前执行一下取消操作 this.removePending(config); //在一个ajax发送前执行一下取消操作
config.cancelToken = new cancelToken(c => { config.cancelToken = new cancelToken(c => {
......
...@@ -8,8 +8,6 @@ const API = { ...@@ -8,8 +8,6 @@ const API = {
GET_USER_INFO: '/CityInterface/rest/services.svc/getUserInfo', GET_USER_INFO: '/CityInterface/rest/services.svc/getUserInfo',
GET_OA: '/CityInterface/rest/services/OA.svc/getLoginInfo', GET_OA: '/CityInterface/rest/services/OA.svc/getLoginInfo',
GET_LOGS: '/CityInterface/rest/services/portal.svc/OMMonitor/SaveLoginInfo', GET_LOGS: '/CityInterface/rest/services/portal.svc/OMMonitor/SaveLoginInfo',
GET_INFORMATION:'/CityInterface/rest/services/CountyProduct.svc/SCADAOper/GetInformationInfo',
GET_MQTT_SITE_CODE:'/CityInterface/rest/services/CountyProduct.svc/SCADAOper/getMqttSitecode',
GET_CITY: 'https://pv.sohu.com/cityjson?ie=utf-8', GET_CITY: 'https://pv.sohu.com/cityjson?ie=utf-8',
GET_ALL_GROUPS_INFO_FORUSER: GET_ALL_GROUPS_INFO_FORUSER:
'CityInterface/rest/Services/Portal.svc/AuthorityManage/GetAllGroupsInfoForUser', 'CityInterface/rest/Services/Portal.svc/AuthorityManage/GetAllGroupsInfoForUser',
...@@ -35,12 +33,6 @@ export default vm => { ...@@ -35,12 +33,6 @@ export default vm => {
vm.writeLogs = (data = {}, config = {}) => vm.writeLogs = (data = {}, config = {}) =>
vm.post(API.GET_LOGS, data, config).then(res => Promise.resolve(res)); vm.post(API.GET_LOGS, data, config).then(res => Promise.resolve(res));
vm.getInformationInfo = (data = {}) =>
vm.get(API.GET_INFORMATION, data).then(res => Promise.resolve(res));
vm.getMqttSiteCode = (data = {}) =>
vm.get(API.GET_MQTT_SITE_CODE, data).then(res => Promise.resolve(res));
vm.getCity = () => vm.get(API.GET_CITY).then(res => Promise.resolve(res)); vm.getCity = () => vm.get(API.GET_CITY).then(res => Promise.resolve(res));
vm.generateTokenQuick = (data = {}) => vm.generateTokenQuick = (data = {}) =>
......
import http from './apiConfig'; import http from './apiConfig';
import BaseService from './baseService'; import BaseService from './baseService';
import NotificationService from './notificationService';
BaseService(http); BaseService(http);
NotificationService(http);
export default http export default http
import { params } from 'kit_utils';
import qs from 'qs';
const API = {
GET_INFORMATION:
'/CityInterface/rest/services/CountyProduct.svc/SCADAOper/GetInformationInfo',
GET_MQTT_SITE_CODE:
'/CityInterface/rest/services/CountyProduct.svc/SCADAOper/getMqttSitecode',
POST_INFORMATION_STATUS:
'/CityInterface/rest/services/CountyProduct.svc/SCADAOper/PostInformationStatus',
};
export default vm => {
vm.getInformationInfo = (data = {}) =>
vm.get(API.GET_INFORMATION, data).then(res => Promise.resolve(res));
vm.getMqttSiteCode = (data = {}) =>
vm.get(API.GET_MQTT_SITE_CODE, data).then(res => Promise.resolve(res));
vm.postInformationStatus = (params = {}) =>{
let paramsStr=qs.stringify(params, { arrayFormat: 'brackets' });
return vm.post(API.POST_INFORMATION_STATUS+"?"+paramsStr).then(res => Promise.resolve(res));
}
};
...@@ -9,19 +9,25 @@ import styles from './index.less'; ...@@ -9,19 +9,25 @@ import styles from './index.less';
import Notifier, {NEW_MESSAGE} from '../Notifier'; import Notifier, {NEW_MESSAGE} from '../Notifier';
class NoticeIconView extends Component { class NoticeIconView extends Component {
state = { constructor(props){
super(props);
this.state = {
count: 0, count: 0,
noticeData: [], noticeData: [],
}; };
this.notifier = new Notifier(this.props.global.userInfo);
}
async componentDidMount() { async componentDidMount() {
let notifier = new Notifier(this.props.global.userInfo); this.notifier.subscribe(NEW_MESSAGE,this.onNewMessage.bind(this));
notifier.subscribe("NEW_MESSAGE",this.onNewMessage.bind(this)); this.notifier.start();
notifier.start(); }
componentWillUnmount(){
this.notifier && this.notifier.stop();
} }
onNewMessage = messages => { onNewMessage = messages => {
debugger;
this.setState({ this.setState({
count:messages.totalCount, count:messages.totalCount,
noticeData:messages.messages noticeData:messages.messages
...@@ -84,13 +90,12 @@ class NoticeIconView extends Component { ...@@ -84,13 +90,12 @@ class NoticeIconView extends Component {
return ( return (
<NoticeIcon <NoticeIcon
className={styles.action} className={styles.action}
count={this.state.count > 99 ? 99 : this.state.count} count={this.state.count}
onItemClick={item => { onItemClick={item => {
this.changeReadState(item); this.changeReadState(item);
}} }}
loading={fetchingNotices} loading={fetchingNotices}
clearText="清空" confirmRead={this.notifier.confirmRead.bind(this.notifier)}
viewMoreText="查看更多"
onClear={this.handleNoticeClear} onClear={this.handleNoticeClear}
onPopupVisibleChange={onNoticeVisibleChange} onPopupVisibleChange={onNoticeVisibleChange}
onViewMore={() => message.info('Click on view more')} onViewMore={() => message.info('Click on view more')}
...@@ -102,6 +107,7 @@ class NoticeIconView extends Component { ...@@ -102,6 +107,7 @@ class NoticeIconView extends Component {
title="通知" title="通知"
emptyText="你已查看所有通知" emptyText="你已查看所有通知"
showViewMore showViewMore
confirmRead={this.notifier.confirmRead.bind(this.notifier)}
/> />
</NoticeIcon> </NoticeIcon>
); );
......
import { Button, Result } from 'antd';
import React from 'react';
const NoFoundPage = (props) => {
return (
<Result
status="404"
title="404"
subTitle="Sorry, the page you visited does not exist."
extra={
<Button type="primary" onClick={() => {props.history.push('/civbase')}}>
Back Home
</Button>
}
/>
)
};
export default NoFoundPage;
import React from 'react'; import React from 'react';
import { import { Avatar, List } from 'antd';
Avatar,
List,
} from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import styles from './NoticeList.less'; import styles from './NoticeList.less';
import Alarm from './Templates/Alarm';
import Case from './Templates/Case';
import Notice from './Templates/Notice';
import Unknown from './Templates/Unknown';
const NoticeList = ({ const Empty = ({ emptyText }) => (
data = [],
onClick,
onClear,
title,
onViewMore,
emptyText,
showClear = true,
clearText,
viewMoreText,
showViewMore = false,
}) => {
if (!data || data.length === 0) {
return (
<div className={styles.notFound}> <div className={styles.notFound}>
<img <img
src="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg" src="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg"
...@@ -29,9 +16,12 @@ const NoticeList = ({ ...@@ -29,9 +16,12 @@ const NoticeList = ({
/> />
<div>{emptyText}</div> <div>{emptyText}</div>
</div> </div>
); );
}
const NoticeList = ({ data = [], onGoToWidget, emptyText, confirmRead }) => {
if (!data || data.length === 0) {
return <Empty emptyText={emptyText} />;
}
return ( return (
<div> <div>
<List <List
...@@ -41,65 +31,37 @@ const NoticeList = ({ ...@@ -41,65 +31,37 @@ const NoticeList = ({
const itemCls = classNames(styles.item, { const itemCls = classNames(styles.item, {
[styles.read]: item.read, [styles.read]: item.read,
}); });
// eslint-disable-next-line no-nested-ternary let messageTemplate = <></>;
const leftIcon = item.avatar ? ( switch (item.infoType) {
typeof item.avatar === 'string' ? ( case 'scadaType':
<Avatar className={styles.avatar} src={item.avatar} /> messageTemplate = (
) : ( <Alarm message={item} confirmRead={confirmRead} />
<span className={styles.iconElement}>{item.avatar}</span> );
) break;
) : null; case 'caseType':
const content = item.InfoContent.replace('\n', ''); messageTemplate = (
console.log(content); <Case message={item} confirmRead={confirmRead} />
return ( );
<List.Item break;
className={itemCls} case 'sysType':
key={item.key || i} messageTemplate = (
onClick={() => onClick && onClick(item)} <Notice message={item} confirmRead={confirmRead} />
> );
<List.Item.Meta break;
className={styles.meta} default:
avatar={leftIcon} messageTemplate = (
title={ <Unknown message={item} confirmRead={confirmRead} />
<div className={styles.title}> );
{item.title} break;
<div
className={styles.extra}
dangerouslySetInnerHTML={{
__html: content,
}}
/>
</div>
}
description={
<div>
<div className={styles.description}>{item.description}</div>
<div className={styles.datetime}>{item.datetime}</div>
</div>
} }
/> return (
<List.Item className={itemCls} key={item.id || i}>
{messageTemplate}
</List.Item> </List.Item>
); );
}} }}
/> />
<div className={styles.bottomBar}> <div className={styles.bottomBar}>下拉加载更多</div>
{showClear ? (
<div onClick={onClear}>
{clearText} {title}
</div>
) : null}
{showViewMore ? (
<div
onClick={e => {
if (onViewMore) {
onViewMore(e);
}
}}
>
{viewMoreText}
</div>
) : null}
</div>
</div> </div>
); );
}; };
......
...@@ -7,63 +7,19 @@ ...@@ -7,63 +7,19 @@
display: none; display: none;
} }
.item { .item {
padding-right: 24px;
padding-left: 24px;
overflow: hidden; overflow: hidden;
cursor: pointer; cursor: pointer;
transition: all 0.3s;
.meta { .meta {
width: 100%; width: 100%;
} }
&:hover {
.avatar { background-color: @primary-1;
margin-top: 4px;
background: @component-background;
}
.iconElement {
font-size: 32px;
}
&.read {
opacity: 0.4;
} }
&:last-child { &:last-child {
border-bottom: 0; border-bottom: 0;
} }
&:hover {
background: @primary-1;
}
.title {
margin-bottom: 8px;
font-weight: normal;
}
.description {
font-size: 12px;
line-height: @line-height-base;
}
.datetime {
margin-top: 4px;
font-size: 12px;
line-height: @line-height-base;
}
.extra {
float: right;
margin-top: -1.5px;
margin-right: 0;
color: @text-color-secondary;
font-weight: normal;
}
}
.loadMore {
padding: 8px 0;
color: @primary-6;
text-align: center;
cursor: pointer;
&.loadedAll {
color: rgba(0, 0, 0, 0.25);
cursor: unset;
}
} }
} }
......
import React from 'react';
import styles from './index.less';
import commonStyles from '../common.less';
import classNames from 'classnames';
import { useHistory } from 'react-router-dom';
export class AlarmContent {
constructor({
alarmType,
deviceCode,
alarmDevice,
alarmContent,
alarmValue,
alarmThreshold,
time,
} = content) {
this.alarmType = alarmType;
this.deviceCode = deviceCode;
this.alarmDevice = alarmDevice;
this.alarmContent = alarmContent;
this.alarmValue = alarmValue;
this.alarmThreshold = alarmThreshold;
this.time = time;
}
}
const Alarm = ({ message, confirmRead }) => {
let alarmContent = message.infoContent;
const history = useHistory();
const goPath = (item) => {
confirmRead(false,[message.id]);
let path= item.webPath ? `/civweb4/${item.webPath}` : `/civweb4/product/scada/AlertMonitoring/AlertMonitoring`
history.push(path);
}
return (
<div className={classNames(styles.scada,commonStyles.messageContainer) } title="点击查看详情" onClick={()=> goPath(message)}>
<div className={commonStyles.title}>
<span>消息</span>
<img
className={commonStyles.confirm}
title="点击标为已读"
onClick={() => {
confirmRead(false,[message.id]);
}}
src="https://panda-water.cn/Web4/assets/images/message/%E5%8B%BE%E6%B5%85.png"
/>
</div>
<div className={commonStyles.content}>
<p>
<i>{alarmContent.alarmType}</i>
{alarmContent.alarmDevice}
</p>
<p>{alarmContent.alarmContent}</p>
<p>
<font style={{ color: '#ff0000' }} title="点击查看详情">
{alarmContent.alarmValue.split(' ')[0]}
</font>
{alarmContent.alarmValue.split(' ')[1] +
' / ' +
alarmContent.alarmThreshold.split(' ').join('')}
</p>
<p className={commonStyles.messageTime}>{message.time}</p>
</div>
</div>
);
};
export default Alarm;
.scada {
background: url(https://panda-water.cn/Web4/assets/images/message/%E6%B6%88%E6%81%AF.png)
16px 10px no-repeat;
}
import React from 'react';
import styles from './index.less';
import commonStyles from '../common.less';
import classNames from 'classnames';
import { useHistory } from 'react-router-dom';
//"caseType":"待办工单","flowName":"维修处理流程","nodeName":"审核关单","content":"请迅速到现场处理","time":"2020-11-03 09:11:12"
export class CaseContent {
constructor({
caseType,
flowName,
nodeName,
content,
time
} = content) {
this.caseType = caseType;
this.flowName = flowName;
this.nodeName = nodeName;
this.content = content;
this.time = time;
}
}
const Case = ({ message, confirmRead }) => {
let caseContent = message.infoContent;
const history = useHistory();
const goPath = (item) => {
confirmRead(false,[message.id]);
let path= item.webPath ? `/civweb4/${item.webPath}` : `/civweb4/product/maintenance/CaseManage/CaseDoingBox/StardCaseDoingBoxView|isDelay=1`
history.push(path);
}
return (
<div className={classNames(styles.case,commonStyles.messageContainer)} title="点击查看详情" onClick={()=> goPath(message)}>
<div className={commonStyles.title}>
<span>消息</span>
<img
className={commonStyles.confirm}
title="点击标为已读"
onClick={() => {
confirmRead(false,[message.id]);
}}
src="https://panda-water.cn/Web4/assets/images/message/%E5%8B%BE%E6%B5%85.png"
/>
</div>
<div className={commonStyles.content}>
<p>
<i>{caseContent.caseType}</i>
{caseContent.flowName}
</p>
<p>{caseContent.nodeName} : {caseContent.content}</p>
<p className={commonStyles.messageTime}>{message.time}</p>
</div>
</div>
);
};
export default Case;
.case {
background: url(https://panda-water.cn/Web4/assets/images/message/%E6%B6%88%E6%81%AF.png)
16px 10px no-repeat;
}
\ No newline at end of file
import React from 'react';
import styles from './index.less';
import commonStyles from '../common.less';
import classNames from 'classnames';
import { useHistory } from 'react-router-dom';
//'平台公告','{"noticeTitle":"光谷智慧园停水","noticeType":"停水公告","noticeContent":"从今天中午20点开始停水,停三个小时!","time":"2020-11-03 09:11:12"
export class NoticeContent {
constructor({
noticeTitle,
noticeType,
noticeContent,
time
} = content) {
this.noticeTitle = noticeTitle;
this.noticeType = noticeType;
this.noticeContent = noticeContent;
this.time = time;
}
}
const Notice = ({ message, confirmRead }) => {
let noticeContent = message.infoContent;
const history = useHistory();
const goPath = (item) => {
confirmRead(false,[message.id]);
let path= item.webPath ? `/civweb4/${item.webPath}` : `/civweb4/product/notification/HistoryNotice/HistoryNotice`
history.push(path);
}
return (
<div className={classNames(styles.notice,commonStyles.messageContainer)} title="点击查看详情" onClick={()=> goPath(message)}>
<div className={commonStyles.title}>
<span>公告</span>
<img
className={commonStyles.confirm}
title="点击标为已读"
onClick={() => {
confirmRead(false,[message.id]);
}}
src="https://panda-water.cn/Web4/assets/images/message/%E5%8B%BE%E6%B5%85.png"
/>
</div>
<div className={commonStyles.content}>
<p>
<i>{noticeContent.noticeType}</i>
{noticeContent.noticeTitle}
</p>
<p>{noticeContent.noticeContent}</p>
<p className={commonStyles.messageTime}>{message.time}</p>
</div>
</div>
);
};
export default Notice;
.notice {
background: url(https://panda-water.cn/Web4/assets/images/message/%E6%B6%88%E6%81%AF.png)
16px 10px no-repeat;
}
\ No newline at end of file
import React from 'react';
import styles from './index.less';
import commonStyles from '../common.less';
import classNames from 'classnames';
const Unknown = ({ message, confirmRead }) => {
let alarmContent = message.infoContent;
return (
<div className={classNames(styles.unknown,commonStyles.messageContainer) } title="点击查看详情">
<div className={commonStyles.title}>
<span>消息</span>
<img
className={commonStyles.confirm}
title="点击标为已读"
onClick={() => {
confirmRead(false,[message.id]);
}}
src="https://panda-water.cn/Web4/assets/images/message/%E5%8B%BE%E6%B5%85.png"
/>
</div>
<div className={commonStyles.content}>
<p>{message.infoContent}</p>
<p className={commonStyles.messageTime}>{message.time}</p>
</div>
</div>
);
};
export default Unknown;
.unknown {
background: url(https://panda-water.cn/Web4/assets/images/message/%E6%B6%88%E6%81%AF.png)
16px 10px no-repeat;
}
.messageContainer {
padding-left: 50px;
padding-right: 20px;
padding-top: 8px;
width: 100%;
.title {
display: flex;
justify-content: space-between;
span {
font-size: 16px;
color: #666;
font-weight: normal;
text-shadow: none;
letter-spacing: 0;
}
.confirm {
margin-right: 20px;
width: 20px;
height: 16px;
}
}
.content {
margin-top: 10px;
p {
i {
font-size: 14px;
text-shadow: none;
color: #000;
font-style: normal;
color: #1ba6f9;
margin-right: 10px;
}
margin-bottom: 5px;
}
.messageTime {
float: right;
margin-right: 30px;
}
}
}
\ No newline at end of file
import React from 'react'; import React from 'react';
import { import { Badge, Tabs } from 'antd';
Badge,
Tabs,
} from 'antd';
import classNames from 'classnames'; import classNames from 'classnames';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import useMergeValue from 'use-merge-value'; import useMergeValue from 'use-merge-value';
...@@ -13,41 +10,56 @@ import Icon from '@ant-design/icons'; ...@@ -13,41 +10,56 @@ import Icon from '@ant-design/icons';
import HeaderDropdown from '../HeaderDropdown'; import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less'; import styles from './index.less';
import NoticeList from './NoticeList'; import NoticeList from './NoticeList';
import http from '../../api';
const { TabPane } = Tabs; const { TabPane } = Tabs;
const messageSvg = () => ( const messageSvg = () => (
<svg version="1.1" x="0px" y="0px" <svg
width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" space="preserve"> version="1.1"
<path fill="#5F718C" d="M20.486,16.373l-1.721-2.246v-0.984v-0.352V9.924c0-1.919-0.664-3.698-1.871-5.007 x="0px"
y="0px"
width="24px"
height="24px"
viewBox="0 0 24 24"
enable-background="new 0 0 24 24"
space="preserve"
>
<path
fill="#5F718C"
d="M20.486,16.373l-1.721-2.246v-0.984v-0.352V9.924c0-1.919-0.664-3.698-1.871-5.007
c-0.712-0.776-1.57-1.349-2.551-1.705c-0.091-0.514-0.35-0.983-0.737-1.335c-0.879-0.791-2.334-0.791-3.21,0 c-0.712-0.776-1.57-1.349-2.551-1.705c-0.091-0.514-0.35-0.983-0.737-1.335c-0.879-0.791-2.334-0.791-3.21,0
c-0.394,0.354-0.653,0.823-0.741,1.336C8.676,3.568,7.817,4.14,7.105,4.917C5.899,6.229,5.234,8.008,5.234,9.923l0.005,4.194 c-0.394,0.354-0.653,0.823-0.741,1.336C8.676,3.568,7.817,4.14,7.105,4.917C5.899,6.229,5.234,8.008,5.234,9.923l0.005,4.194
l-1.708,2.234c-0.241,0.256-0.372,0.584-0.372,0.932v1.092c0,0.75,0.615,1.357,1.372,1.357H19.47c0.757,0,1.371-0.607,1.371-1.357 l-1.708,2.234c-0.241,0.256-0.372,0.584-0.372,0.932v1.092c0,0.75,0.615,1.357,1.372,1.357H19.47c0.757,0,1.371-0.607,1.371-1.357
v-1.092C20.841,16.936,20.71,16.607,20.486,16.373z M4.899,17.996v1.016l-0.001-2.061l1.628-2.154 v-1.092C20.841,16.936,20.71,16.607,20.486,16.373z M4.899,17.996v1.016l-0.001-2.061l1.628-2.154
c0.227-0.244,0.353-0.561,0.353-0.893v-4.05c0-1.516,0.509-2.914,1.436-3.935c0.459-0.506,1.001-0.895,1.608-1.166 c0.227-0.244,0.353-0.561,0.353-0.893v-4.05c0-1.516,0.509-2.914,1.436-3.935c0.459-0.506,1.001-0.895,1.608-1.166
c1.276-0.565,2.883-0.565,4.155,0c0.609,0.273,1.15,0.667,1.608,1.168c0.925,1.021,1.437,2.417,1.437,3.934v2.762v0.338v0.949 c1.276-0.565,2.883-0.565,4.155,0c0.609,0.273,1.15,0.667,1.608,1.168c0.925,1.021,1.437,2.417,1.437,3.934v2.762v0.338v0.949
c0,0.334,0.123,0.654,0.336,0.875l1.642,2.164l0.013,1.037L4.899,17.996z"/> c0,0.334,0.123,0.654,0.336,0.875l1.642,2.164l0.013,1.037L4.899,17.996z"
<path fill="#5F718C" d="M13.685,20.236c-0.101,0.238-0.248,0.453-0.444,0.631c-0.677,0.617-1.799,0.615-2.473,0.002 />
<path
fill="#5F718C"
d="M13.685,20.236c-0.101,0.238-0.248,0.453-0.444,0.631c-0.677,0.617-1.799,0.615-2.473,0.002
c-0.194-0.18-0.344-0.396-0.446-0.633H8.895c0.146,0.627,0.474,1.199,0.955,1.639c0.588,0.543,1.354,0.841,2.158,0.841 c-0.194-0.18-0.344-0.396-0.446-0.633H8.895c0.146,0.627,0.474,1.199,0.955,1.639c0.588,0.543,1.354,0.841,2.158,0.841
c0.801,0,1.566-0.298,2.154-0.837c0.481-0.439,0.808-1.012,0.954-1.641L13.685,20.236z"/> c0.801,0,1.566-0.298,2.154-0.837c0.481-0.439,0.808-1.012,0.954-1.641L13.685,20.236z"
/>
</svg> </svg>
) );
const BellOutlined = props => <Icon component={messageSvg} {...props} style={{transform: 'scale(0.88)'}}/>; const BellOutlined = props => <Icon component={messageSvg} {...props} />;
const NoticeIcon = props => { const NoticeIcon = props => {
const getNotificationBox = () => { const getNotificationBox = () => {
const { const {
children, children,
loading, loading,
confirmRead,
onClear, onClear,
onTabChange, onTabChange,
onItemClick, onItemClick,
onViewMore, onViewMore,
clearText,
viewMoreText,
} = props; } = props;
if (!children) { if (!children) {
return null; return null;
} }
const panes = []; const panes = [];
React.Children.forEach(children, child => { React.Children.forEach(children, child => {
if (!child) { if (!child) {
return; return;
...@@ -66,8 +78,6 @@ const NoticeIcon = props => { ...@@ -66,8 +78,6 @@ const NoticeIcon = props => {
panes.push( panes.push(
<NoticeList <NoticeList
{...child.props} {...child.props}
clearText={clearText}
viewMoreText={viewMoreText}
data={list} data={list}
key={child} key={child}
onClear={() => onClear && onClear(title, tabKey)} onClear={() => onClear && onClear(title, tabKey)}
...@@ -82,8 +92,8 @@ const NoticeIcon = props => { ...@@ -82,8 +92,8 @@ const NoticeIcon = props => {
return ( return (
<> <>
<div className={styles.header}> <div className={styles.header}>
<span>通知</span> <span className={styles.title}>通知</span>
<span>全部标记已读</span> <span onClick={()=>{confirmRead(true)}}>全部标记已读</span>
</div> </div>
{panes} {panes}
</> </>
...@@ -103,6 +113,8 @@ const NoticeIcon = props => { ...@@ -103,6 +113,8 @@ const NoticeIcon = props => {
<span className={classNames(noticeButtonClass, { opened: visible })}> <span className={classNames(noticeButtonClass, { opened: visible })}>
<Badge <Badge
count={props.count} count={props.count}
overflowCount={99}
offset={[-8, 8]}
style={{ boxShadow: 'none' }} style={{ boxShadow: 'none' }}
className={styles.badge} className={styles.badge}
> >
......
...@@ -39,10 +39,17 @@ ...@@ -39,10 +39,17 @@
padding: 8px; padding: 8px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
.title{
font-size: 16px;
font-weight: bold;
margin-left: 5px;
color: rgb(102,102,102);
}
span { span {
&:last-child { &:last-child {
cursor: pointer; cursor: pointer;
color: @primary-color; color: @primary-color;
font-size: 12px;
} }
} }
} }
\ No newline at end of file
import MqttClient from './mqttws31'; import MqttClient from './mqttws31';
import mock from './mock.json';
export const NEW_MESSAGE = 'NEW_MESSAGE'; export const NEW_MESSAGE = 'NEW_MESSAGE';
export class Message { export class Message {
constructor() { constructor({
this.CreateTime, id,
this.HisCreateTime, infoContent,
this.HisID, infoLevel,
this.ID, time,
this.InfoContent, infoType,
this.InfoDist, dateTime,
this.InfoLevel, webConfig,
this.InfoType, webPath,
this.IsRead, messType,
this.MessType, } = message) {
this.ToUsers, this.id = id;
this.UserID, this.infoContent = infoContent;
this.app_config, this.infoLevel = infoLevel;
this.app_path, this.time = time;
this.web_config, this.infoType = infoType; // 方案类型 - 工单 报警 公告 定时推送
this.web_path, this.dateTime = dateTime;
this.time; this.webConfig = webConfig;
this.webPath = webPath;
this.messType = messType; //方案名称 - 大类型下细类型
} }
} }
class Notifier { class Notifier {
constructor(userInfo) { constructor(userInfo) {
// this.userInfo=userInfo; this.userInfo = userInfo;
this.userInfo = {
site: '192_168_19_105_site_c8de50fc',
OID: 5,
};
this.messageCache = { this.messageCache = {
totalCount: 0, totalCount: 0,
messages: [], messages: [],
...@@ -60,12 +57,15 @@ class Notifier { ...@@ -60,12 +57,15 @@ class Notifier {
// 对外接口 // 对外接口
async start() { async start() {
this._getMqttSiteCode().then(() => {
this.loadHisMessages({ userID: this.userInfo.OID }); this.loadHisMessages({ userID: this.userInfo.OID });
this.connectMQTTServer(); this.connectMQTTServer();
});
} }
stop() { stop() {
this.disconnectMQTTServer(); this.disconnectMQTTServer();
} }
subscribe(type, handler) { subscribe(type, handler) {
if (!(type in this._subscribers)) { if (!(type in this._subscribers)) {
this._subscribers[type] = []; this._subscribers[type] = [];
...@@ -102,9 +102,49 @@ class Notifier { ...@@ -102,9 +102,49 @@ class Notifier {
}); });
} }
confirmRead(isAll = false, hisIDs = []) {
let list = [];
if (
this.messageCache &&
this.messageCache.totalCount == 0 &&
this.messageCache.messages.length == 0
)
return;
if (isAll) hisIDs = this.messageCache.messages.map(item => item.id);
let me = this;
Http.postInformationStatus({
userID: this.userInfo.OID,
hisID: hisIDs.join(','),
isAll: isAll ? 1 : '',
})
.then(res => {
if (res.statusCode != '0000') {
console.log(res.errMsg);
return;
}
if (isAll) {
me.messageCache.totalCount = 0;
me.messageCache.messages = [];
} else {
hisIDs.forEach(id => {
let index = me.messageCache.messages.findIndex(
item => item.id == id,
);
if (index != -1) {
me.messageCache.messages.splice(index, 1);
me.messageCache.totalCount--;
}
});
}
me.publish(NEW_MESSAGE, me.messageCache);
})
.catch(err => {
console.log('postInformationStatus调用失败' + err);
});
}
// mqtt // mqtt
async connectMQTTServer() { async connectMQTTServer() {
this._getMqttSiteCode().then(() => {
let hostname = this._siteConfig.TcpIP, let hostname = this._siteConfig.TcpIP,
port = this._siteConfig.TcpPort, port = this._siteConfig.TcpPort,
clientId = 'client-' + this._createGuid(), clientId = 'client-' + this._createGuid(),
...@@ -132,13 +172,13 @@ class Notifier { ...@@ -132,13 +172,13 @@ class Notifier {
password: password, password: password,
onSuccess: this.onMQTTConnect.bind(this), onSuccess: this.onMQTTConnect.bind(this),
onFailure: function(e) { onFailure: function(e) {
debugger;
console.log(e); console.log(e);
}, },
}; };
this.MQTTClient.connect(this.MQTTOptions); this.MQTTClient.connect(this.MQTTOptions);
this.MQTTClient.onConnectionLost = this.onMQTTConnectionLost.bind(this); this.MQTTClient.onConnectionLost = this.onMQTTConnectionLost.bind(this);
this.MQTTClient.onMessageArrived = this.onMessageArrived.bind(this); this.MQTTClient.onMessageArrived = this.onMessageArrived.bind(this);
});
} }
disconnectMQTTServer() { disconnectMQTTServer() {
if (this.MQTTClient) { if (this.MQTTClient) {
...@@ -169,7 +209,7 @@ class Notifier { ...@@ -169,7 +209,7 @@ class Notifier {
this.MQTTClient.subscribe(UserTopic); this.MQTTClient.subscribe(UserTopic);
} }
onMQTTConnectionLost(responseObject) { onMQTTConnectionLost(responseObject) {
debugger; console.log('连接丢失', responseObject);
var me = this; var me = this;
if (this.IsNeedReconnect) { if (this.IsNeedReconnect) {
this.MQTTClient.connect(me.MQTTOptions); this.MQTTClient.connect(me.MQTTOptions);
...@@ -182,12 +222,12 @@ class Notifier { ...@@ -182,12 +222,12 @@ class Notifier {
}, 1000); }, 1000);
} }
} }
onMessageArrived(message) { onMessageArrived(buffer) {
let me = this; let me = this;
try { try {
console.log('收到消息:' + message.payloadString); console.log('收到消息:' + buffer.payloadString);
let temp = JSON.parse(message.payloadString); let temp = JSON.parse(buffer.payloadString);
let infoType = this._typeInfo(temp); let infoType = this._typeInfo(temp.infoType);
if ( if (
temp.tousers == '' || temp.tousers == '' ||
me.userInfo.OID == temp.tousers || me.userInfo.OID == temp.tousers ||
...@@ -195,12 +235,6 @@ class Notifier { ...@@ -195,12 +235,6 @@ class Notifier {
temp.tousers.includes(',' + me.userInfo.OID) temp.tousers.includes(',' + me.userInfo.OID)
) { ) {
let messContent = temp.content; let messContent = temp.content;
if (
me._siteConfig.MessageLevel &&
me._siteConfig.MessageLevel == '2.0'
) {
messContent = me._messageThrome(infoType, JSON.parse(temp.content));
}
let timeH = (new Date() - new Date(temp.createTime)) / 1000 / 60; let timeH = (new Date() - new Date(temp.createTime)) / 1000 / 60;
let timeMss = let timeMss =
Math.abs(timeH) > 1440 Math.abs(timeH) > 1440
...@@ -211,24 +245,29 @@ class Notifier { ...@@ -211,24 +245,29 @@ class Notifier {
? timeH.toFixed(0) + '分钟前' ? timeH.toFixed(0) + '分钟前'
: '刚刚'; : '刚刚';
let messString = { let messString = {
ID: temp.infoId, id: temp.ID,
Info: messContent, infoContent: messContent,
InfoLevel: temp.level, infoLevel: temp.level,
time: `${timeMss}`, time: `${timeMss}`,
infoType: infoType, infoType: infoType,
messageType: '',
dateTime: temp.createTime, dateTime: temp.createTime,
web_config: temp.web_config, webConfig: temp.web_config,
web_path: temp.web_path, webPath: temp.web_path,
messType: temp.MessType, messType: temp.MessType,
}; };
let message = me._handleMqttToMessage(messString); if (this._IsVersion1())
messString.infoContent = this._handleMessageStrToJSON(
infoType,
messString,
);
else messString.infoContent = JSON.parse(messString.content);
let message = new Message(messString);
this.messageCache.totalCount += 1; this.messageCache.totalCount += 1;
this.messageCache.messages.push(message); this.messageCache.messages.push(message);
me.publish(NEW_MESSAGE, this.messageCache); me.publish(NEW_MESSAGE, this.messageCache);
} }
} catch (e) { } catch (e) {
console.log('收到消息处理异常:'+e.message); console.log('收到消息处理异常:' + e.message);
} }
} }
...@@ -243,7 +282,7 @@ class Notifier { ...@@ -243,7 +282,7 @@ class Notifier {
}).then(res => { }).then(res => {
let result = { let result = {
totalCount: res.totalRcdNum, totalCount: res.totalRcdNum,
messages: res.getMe.map(this._handleHisToMessage), messages: res.getMe.map(this._handleHisToMessage.bind(this)),
}; };
this.messageCache.totalCount += result.totalCount; this.messageCache.totalCount += result.totalCount;
this.messageCache.messages.push(...result.messages); this.messageCache.messages.push(...result.messages);
...@@ -294,9 +333,9 @@ class Notifier { ...@@ -294,9 +333,9 @@ class Notifier {
}) })
.toUpperCase(); .toUpperCase();
} }
_typeInfo(temp) { _typeInfo(infoTypeStr) {
var infoType = 'scadaType'; var infoType = 'unknown';
switch (temp.infoType) { switch (infoTypeStr) {
case '工单流程': case '工单流程':
infoType = 'caseType'; infoType = 'caseType';
break; break;
...@@ -313,63 +352,110 @@ class Notifier { ...@@ -313,63 +352,110 @@ class Notifier {
case '消息提醒': case '消息提醒':
infoType = 'remindType'; infoType = 'remindType';
break; break;
case 'SCADA报警':
infoType = 'scadaType';
default: default:
break; break;
} }
return infoType; return infoType;
} }
_messageThrome(themeName, info) {
var messInfo = ''; _handleHisToMessage(hisMessage) {
switch (themeName) { var timeH = (new Date() - new Date(hisMessage.HisCreateTime)) / 1000 / 60;
case 'caseType': var timeMss =
case '工单提醒': Math.abs(timeH) > 1440
messInfo = `【${info.caseType}${info.flowName}\\n${ ? hisMessage.HisCreateTime.split('.')[0]
info.nodeName : Math.abs(timeH) > 60
}\\n承办意见:${info.content}`; ? (timeH / 60).toFixed(0) + '小时前'
break; : Math.abs(timeH) > 1
? timeH.toFixed(0) + '分钟前'
: '刚刚';
let message = {
id: hisMessage.HisID,
infoContent: hisMessage.InfoContent,
time: `${timeMss}`,
infoType: this._typeInfo(hisMessage.InfoType),
dateTime: hisMessage.HisCreateTime,
infoLevel: hisMessage.InfoLevel,
webConfig: hisMessage.web_config,
webPath: hisMessage.web_path,
messType: hisMessage.MessType,
};
if (this._IsVersion1())
message.infoContent = this._handleMessageStrToJSON(
message.infoType,
message,
);
else message.infoContent = JSON.parse(message.infoContent);
return new Message(message);
}
// 1.0 解析规则
_IsVersion1() {
return (
!this._siteConfig.MessageLevel || this._siteConfig.MessageLevel != '2.0'
);
}
_handleMessageStrToJSON(infoType, messString) {
let infoContent = messString;
switch (infoType) {
case 'scadaType': case 'scadaType':
case '通用报警': infoContent = this._analysisAlarm(messString);
messInfo = `【${info.alarmType}${info.alarmDevice}\\n${ break;
info.alarmContent case 'caseType':
}\\n${info.alarmValue} / ${info.alarmThreshold}\\n${info.deviceCode}`; infoContent = this._analysisCase(messString);
break; break;
case 'sysType': case 'sysType':
case '系统通知': infoContent = this._analysisNotice(messString);
messInfo = `【${info.noticeType}${info.noticeTitle}\\n${ break;
info.noticeContent case 'saveWaType':
}`; break;
case 'EIMType':
break; break;
// case "remindType": case "remindType":
// messInfo = ``;
// break;
default: default:
break; break;
} }
return messInfo; return infoContent;
} }
_handleHisToMessage(hisMessage) { _analysisCase(messString) {
let message = new Message(); let attr = messString.infoContent.split('\\n');
message = { let caseContent = {
...hisMessage, caseType: attr[0].split('】')[0].split('【')[1],
...{ flowName: attr[0].split('】')[1],
ToUsers: hisMessage.Tousers, nodeName: attr[1],
}, content: attr[2],
time: messString.dateTime,
};
return caseContent;
}
_analysisAlarm(messString) {
let attr = messString.infoContent.split('\\n');
let alarmContent = {
alarmType: attr[0].split('】')[0].split('【')[1],
deviceCode: '',
alarmDevice: attr[0].split('】')[1],
alarmContent: attr[1],
alarmThreshold: attr[2].includes(' / ')
? attr[2].split('/')[1].trim(' ')
: '',
alarmValue: attr[2].includes(' / ')
? attr[2].split('/')[0].trim(' ')
: attr[2].includes(':')
? attr[2].split(':')[1]
: '',
time: messString.dateTime,
};
return alarmContent;
}
_analysisNotice(messString) {
let attr = messString.infoContent.split('\\n');
let noticeContent = {
noticeType: attr[0].split('】')[0].split('【')[1],
noticeTitle: attr[0].split('】')[1],
noticeContent: attr[1],
time: messString.dateTime,
}; };
delete message['Tousers']; return noticeContent;
return message;
}
_handleMqttToMessage(mqttMessage) {
let message = new Message();
message.ID = mqttMessage.ID;
message.InfoContent = mqttMessage.Info;
message.InfoLevel = mqttMessage.InfoLevel;
message.time = mqttMessage.time;
message.infoType = mqttMessage.infoType;
message.CreateTime = mqttMessage.dateTime;
message.web_config = mqttMessage.web_config;
message.web_path = mqttMessage.web_path;
message.MessType = mqttMessage.messType;
return message;
} }
} }
......
...@@ -3,7 +3,7 @@ import React from 'react'; ...@@ -3,7 +3,7 @@ import React from 'react';
import { Helmet } from 'react-helmet'; import { Helmet } from 'react-helmet';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { renderRoutes } from 'react-router-config'; import { renderRoutes } from 'react-router-config';
import { BrowserRouter as Router, Switch } from 'react-router-dom'; import { BrowserRouter as Router, Switch,Redirect } from 'react-router-dom';
import { dyRoutes } from '../../routes/config'; import { dyRoutes } from '../../routes/config';
...@@ -25,7 +25,11 @@ function App(props) { ...@@ -25,7 +25,11 @@ function App(props) {
/> />
</Helmet> </Helmet>
<Router basename="civbase"> <Router basename="civbase">
<Switch>{renderRoutes(dyRoutes(props.menu || []).routes)}</Switch> <Switch>
{renderRoutes(dyRoutes(props.menu || []).routes)}
{/* <Redirect to="/notFound" /> */}
</Switch>
</Router> </Router>
</> </>
); );
......
...@@ -4,6 +4,7 @@ import BootPage from '../pages/bootpage'; ...@@ -4,6 +4,7 @@ import BootPage from '../pages/bootpage';
import Login from '../pages/user/login'; import Login from '../pages/user/login';
export const dyRoutes = routes => { export const dyRoutes = routes => {
debugger;
const dyRoutes = routes; const dyRoutes = routes;
return { return {
routes: [ routes: [
......
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