Commit 7221a837 authored by 崔佳豪's avatar 崔佳豪

Merge branch 'master' into dev

parents 0df0818d 89c0da7c
Pipeline #66528 waiting for manual action with stages
......@@ -107,16 +107,16 @@
"@babel/runtime": "^7.10.5",
"@esri/calcite-colors": "6.0.3",
"@wisdom-cesium/cesium": "^1.1.6",
"@wisdom-cesium/krpano": "^1.0.29-2",
"@wisdom-cesium/krpano": "1.0.29-17",
"@wisdom-components/basictable": "^1.5.16",
"@wisdom-components/empty": "^1.4.1",
"@wisdom-map/amap": "1.1.0-beta.42",
"@wisdom-map/arcgismap": "1.4.0-88",
"@wisdom-map/basemap": "1.1.0-18",
"@wisdom-map/amap": "1.1.0-beta.47",
"@wisdom-map/arcgismap": "1.4.0-114",
"@wisdom-map/basemap": "1.1.0-20",
"@wisdom-map/util": "^1.0.28-0",
"@wisdom-utils/components": "0.1.283",
"@wisdom-utils/components": "0.1.286",
"@wisdom-utils/runtime": "0.0.38",
"@wisdom-utils/utils": "0.1.323",
"@wisdom-utils/utils": "0.1.326",
"animate.css": "^4.1.1",
"antd": "4.21.2",
"compression": "1.7.4",
......
......@@ -314,7 +314,7 @@ class NoticeIconView extends Component {
this.renderSysPlatform(message);
};
handlerUnknowDetail = message => {
handlerUnknowDetail = (message, type) => {
// 需要有跳转路径
if (!message.webPath)
return notification.info({ message: '提示', duration: 3, description: '未配置跳转路径' });
......@@ -343,6 +343,9 @@ class NoticeIconView extends Component {
}
params._source = '消息通知';
params._target = message.webPath;
if (type) {
if (/civweb4/.test(targetMenuPath)) return true;
}
sessionStorage.setItem('routerParams', JSON.stringify(params));
window.history.pushState(params, '', `/civbase/${targetMenuPath}?v=${Date.now()}`);
}
......
import React, {
useRef,
useState,
} from 'react';
import React, { useRef, useState } from 'react';
import {
message,
Popover,
} from 'antd';
import { message, Popover } from 'antd';
import _ from 'lodash';
import { connect } from 'react-redux';
import Icon from '@ant-design/icons';
import {
AvatarDropdown as Avatar,
useIntl,
} from '@wisdom-utils/components';
import { AvatarDropdown as Avatar, useIntl } from '@wisdom-utils/components';
import HeaderSearch from '@wisdom-utils/components/lib/layout/components/HeaderSearch';
import { useHistory } from '@wisdom-utils/runtime';
......@@ -112,7 +103,7 @@ const GlobalHeaderRight = props => {
const handleFeedback = event => {
event.stopPropagation();
window.open(`https://mis.panda-water.cn/feedback/?site_code="${props.global.get('userInfo.site')}`);
window.open(`https://work.panda-water.cn/feedback/?site_code=${props.global.get('userInfo.site')}`);
}
const handlerFavitor = event => {
......
......@@ -42,7 +42,9 @@ const proxy = require('../../../../config/proxy');
const keywordStorage = new Storage(`__global_search_keywords__micro_${window.location.hostname}`);
const recentVisitedStorage = new Storage(`__global_recent_visited__micro_${window.location.hostname}`);
const recentProductStorage = new Storage(`__global__recent_product__micro_${window.location.hostname}`);
const currentProduct = new Store(`__global__recent_productIndex__micro_${window.location.hostname}`);
const currentProduct = new Store(
`__global__recent_productIndex__micro_${window.location.hostname}_${sessionStorage.getItem('client') || 'city'}`,
);
Cookies.set('loginMode', Cookies.get('loginMode') || 'pdw');
export const initialState = fromJS({
globalConfig: {},
......
......@@ -7,7 +7,9 @@ body,
height: 100%;
overflow: hidden;
}
#app {
background: transparent!important;
}
* {
margin: 0;
padding: 0;
......
......@@ -17,7 +17,6 @@ export const MESSAGE_TYPE = {
export const NEW_MESSAGE = 'NEW_MESSAGE';
export const USERNAME = 'mao2080';
export const PASSWORD = '123';
export const PLATFORM_LEVEL = '4';
......
import React from 'react';
import { Badge, Button, ConfigProvider } from 'antd';
// eslint-disable-next-line import/no-unresolved
import classNames from 'classnames';
import useMergeValue from 'use-merge-value';
......@@ -40,8 +41,8 @@ const messageSvg = () => (
/>
</svg>
);
const BellOutlined = (props) => <Icon component={messageSvg} {...props} />;
const NoticeIcon = (props) => {
const BellOutlined = props => <Icon component={messageSvg} {...props} />;
const NoticeIcon = props => {
const { getPrefixCls } = React.useContext(ConfigProvider.ConfigContext);
const prefixCls = props.prefixCls || getPrefixCls();
const btnPrefixCls = `${prefixCls}-head-notifier-button`;
......@@ -54,14 +55,12 @@ const NoticeIcon = (props) => {
}
const panes = [];
React.Children.forEach(children, (child) => {
React.Children.forEach(children, child => {
if (!child) {
return;
}
const { list, title } = child.props;
panes.push(
<NoticeList {...child.props} data={list} key={child} title={title} config={props.config} />,
);
panes.push(<NoticeList {...child.props} data={list} key={child} title={title} config={props.config} />);
});
const childProps = panes.length === 1 ? panes[0].props : { list: [] };
return (
......@@ -72,7 +71,9 @@ const NoticeIcon = (props) => {
type="link"
onClick={() => (childProps.list.length > 0 ? confirmRead(true) : null)}
disabled={childProps.list.length === 0}
>全部标记已读</Button>
>
全部标记已读
</Button>
</div>
{panes}
{renderFooter && renderFooter()}
......
import React from 'react';
import { List, Spin, ConfigProvider } from 'antd';
// eslint-disable-next-line import/no-unresolved
import classNames from 'classnames';
import './style/list.less';
import { Alarm, Case, Notice, Unknown } from './templates';
......@@ -11,10 +12,7 @@ const Empty = ({ emptyText, ...props }) => {
const prefixCls = props.prefixCls || getPrefixCls();
return (
<div className={`${prefixCls}-notFound`}>
<img
src="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg"
alt="not found"
/>
<img src="https://gw.alipayobjects.com/zos/rmsportal/sAuJeJzSKbUmHfBQRzmZ.svg" alt="not found" />
<div>{emptyText}</div>
</div>
);
......@@ -113,11 +111,11 @@ class NoticeList extends React.Component {
switch (item.infoClasses) {
case MESSAGE_TYPE.ALARM_TYPE:
messageTemplate = (
<Alarm message={item} confirmRead={this.confirmRead} config={this.props.config} />
<Alarm message={item} confirmRead={this.confirmRead} config={this.props.config} handlerUnknowDetail={this.handlerUnknowDetail} />
);
break;
case MESSAGE_TYPE.CASE_TYPE:
messageTemplate = <Case message={item} confirmRead={this.confirmRead} />;
messageTemplate = <Case message={item} confirmRead={this.confirmRead} handlerUnknowDetail={this.handlerUnknowDetail} />;
break;
case MESSAGE_TYPE.SYS_TYPE:
messageTemplate = (
......
......@@ -12,6 +12,9 @@ class Message {
webConfig,
webPath,
messType,
defaultContent,
webIcon,
title,
infoClasses
} = message) {
this.id = id;
......@@ -23,6 +26,9 @@ class Message {
this.webConfig = webConfig;
this.webPath = webPath;
this.messType = messType; // 方案名称 - 大类型下细类型
this.webIcon = webIcon; // 消息图标
this.title = title; // 消息标题
this.defaultContent = defaultContent;
this.infoClasses = infoClasses;
}
}
......@@ -64,6 +70,9 @@ export const createMessageFromHis = (hisMessage, options = {}) => {
webConfig: hisMessage.web_config,
webPath: hisMessage.web_path,
messType: hisMessage.messType,
defaultContent: (_.isString(hisMessage.defaultContent) && hisMessage.defaultContent.replace(new RegExp(/ /g), "").length > 0) ? hisMessage.defaultContent : null,
webIcon: (_.isString(hisMessage.webIcon) && hisMessage.webIcon.replace(new RegExp(/ /g), "").length > 0) ? hisMessage.webIcon : null,
title: (_.isString(hisMessage.title) && hisMessage.title.replace(new RegExp(/ /g), "").length > 0) ? hisMessage.title : null,
infoClasses,
};
return createMessage(template);
......@@ -90,9 +99,9 @@ export const createMessageFromReal = (realMesssage, options = {}) => {
// 2.0 消息
infoContent = JSON.parse(realMesssage.content || '{}');
}
const template = {
id: realMesssage.infoId,
id: realMesssage.infoId || realMesssage.ID,
infoContent,
time,
infoType: realMesssage.infoType,
......@@ -100,7 +109,10 @@ export const createMessageFromReal = (realMesssage, options = {}) => {
dateTime: realMesssage.createTime,
webConfig: realMesssage.web_config,
webPath: realMesssage.web_path,
messType: realMesssage.messType,
messType: realMesssage.messType || realMesssage.MessType,
defaultContent: (_.isString(realMesssage.defaultContent) && realMesssage.defaultContent.replace(new RegExp(/ /g), "").length > 0) ? realMesssage.defaultContent : null,
webIcon: (_.isString(realMesssage.webIcon) && realMesssage.webIcon.replace(new RegExp(/ /g), "").length > 0) ? realMesssage.webIcon : null,
title: (_.isString(realMesssage.title) && realMesssage.title.replace(new RegExp(/ /g), "").length > 0) ? realMesssage.title : null,
infoClasses,
}
......
......@@ -351,6 +351,8 @@ class Notifier {
}
} catch (e) {
Logger.error(`收到消息处理异常:${e.message}`);
} finally {
window?.share?.event?.emit?.('event:messageArrived', buffer);
}
}
......@@ -449,8 +451,8 @@ class Notifier {
const alarmType = message?.infoContent?.alarmType; // 报警类型:“状态报警”
const content = message?.infoContent?.alarmContent; // 报警内容:“出水超压报警”
const alarmValue = message?.infoContent?.alarmValue ?? ''; // 报警值
let msg = `紧急报警:${device},${alarmType},${content},报警值:${isString(alarmValue) ? replaceSpeak(alarmValue) :'' },请注意!!!`;
const level = message?.infoLevel !== '1' ? '紧急报警,紧急报警,紧急报警:' : ''
let msg = `${level}${device},${alarmType},${content},报警值:${isString(alarmValue) ? replaceSpeak(alarmValue) :'' },请注意!!!`;
this.speak(msg);
};
speakCase = message => {
......@@ -473,12 +475,13 @@ class Notifier {
};
speakOther = message => {
// 类型区分‘全员公告’ 还是 ‘个人消息’
const type = isEmpty(message.tousers) || parseMessage.tousers === '' ? '公告' : '消息';
const type = message.title ?? (isEmpty(message.tousers) || parseMessage.tousers === '' ? '公告' : '消息');
// 构建语音消息内容
const { infoContent, time } = message;
let content = replaceSpeak((infoContent?.content ?? '').replace(/\\n/g, ','));
let msg = `您有新的${type}${content.substring(0, content.lastIndexOf(',')).replace(':', ',')} 时间:${time}`;
let content = replaceSpeak((infoContent?.content ?? message.defaultContent ?? '').replace(/\\n/g, ','));
const text = content.substring(0, content.lastIndexOf(',')).replace(':', ',');
let msg = `您有新的${type}${text !== '' ? text : content} 时间:${time}`;
this.speak(msg);
};
......
import React from 'react';
import _ from 'lodash';
// eslint-disable-next-line import/no-unresolved
import classNames from 'classnames';
import { findPathByWidget, isJSON } from '@wisdom-utils/components/lib/AppLayout/helpers';
import '../styles/common.less';
import './index.less';
import { ConfigProvider } from 'antd';
import { getMessageTypeIcon } from '../../utils';
/* eslint-disable */
export class AlarmContent {
constructor({
......@@ -26,7 +28,7 @@ export class AlarmContent {
}
}
const Alarm = ({ message, confirmRead, config }) => {
const Alarm = ({ message, confirmRead, config, handlerUnknowDetail }) => {
const { getPrefixCls } = React.useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls();
......@@ -39,20 +41,22 @@ const Alarm = ({ message, confirmRead, config }) => {
const alarmThreshold = message?.infoContent?.alarmThreshold;
const goPath = (item) => {
if(handlerUnknowDetail && handlerUnknowDetail(message, 'alarm')) {
const widgetID = 'widget_city_综合运营_管网监控_实时监控_报警监控';
const webPath = 'product/scada/AlertMonitoring/AlertMonitoring';
const widget = findPathByWidget(
'productex/water/IOTMonitor/RealTimeAlarm/RealTimeAlarm',
config.widgets,
'',
'url',
);
window.share.event.emit('listenerMointer', {
widgetId: widgetID,
label: '实时报警',
url: widget.url || webPath,
});
}
confirmRead(false, [message.id]);
const widgetID = 'widget_city_综合运营_管网监控_实时监控_报警监控';
const webPath = 'product/scada/AlertMonitoring/AlertMonitoring';
const widget = findPathByWidget(
'productex/water/IOTMonitor/RealTimeAlarm/RealTimeAlarm',
config.widgets,
'',
'url',
);
window.share.event.emit('listenerMointer', {
widgetId: widgetID,
label: '实时报警',
url: widget.url || webPath,
});
};
......@@ -62,6 +66,7 @@ const Alarm = ({ message, confirmRead, config }) => {
className={classNames(`${prefixCls}-notifier-message_scada`, `${prefixCls}-notifier-message-container`)}
title="点击查看详情"
onClick={() => goPath(message)}
style={{ backgroundImage: `url(${getMessageTypeIcon(message)})` }}
>
<div className={`${prefixCls}-notifier-message-title`}>
<span>{alarmType}</span>
......
import React from 'react';
import { ConfigProvider } from 'antd';
// eslint-disable-next-line import/no-unresolved
import classNames from 'classnames';
import '../styles/common.less';
import './index.less';
import { getMessageTypeIcon } from '../../utils';
// "caseType":"待办工单","flowName":"维修处理流程","nodeName":"审核关单","content":"请迅速到现场处理","time":"2020-11-03 09:11:12"
export class CaseContent {
......@@ -17,7 +19,7 @@ export class CaseContent {
}
}
const Case = ({ message, confirmRead }) => {
const Case = ({ message, confirmRead, handlerUnknowDetail }) => {
const { getPrefixCls } = React.useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls();
const caseType = message?.infoContent?.caseType;
......@@ -27,34 +29,36 @@ const Case = ({ message, confirmRead }) => {
const content = message?.infoContent?.content;
const goPath = item => {
confirmRead(false, [message.id]);
const messageType = item.messType;
let label = '';
let widgetID = '';
switch (messageType) {
case '任务派发':
label = '任务派发';
widgetID = 'widget_city_综合运营_二供管理_维修管理_工单办理';
break;
case '任务驳回':
label = '任务驳回';
widgetID = 'widget_city_综合运营_二供管理_维修管理_工单办理';
// eslint-disable-next-line no-underscore-dangle,no-case-declarations
let _tab;
// eslint-disable-next-line prefer-const
_tab = '任务驳回';
break;
default:
label = '工单办理';
widgetID = 'widget_city_综合运营_二供管理_维修管理_工单办理';
break;
if (handlerUnknowDetail && handlerUnknowDetail(message, 'case')) {
const messageType = item.messType;
let label = '';
let widgetID = '';
switch (messageType) {
case '任务派发':
label = '任务派发';
widgetID = 'widget_city_综合运营_二供管理_维修管理_工单办理';
break;
case '任务驳回':
label = '任务驳回';
widgetID = 'widget_city_综合运营_二供管理_维修管理_工单办理';
// eslint-disable-next-line no-underscore-dangle,no-case-declarations
let _tab;
// eslint-disable-next-line prefer-const
_tab = '任务驳回';
break;
default:
label = '工单办理';
widgetID = 'widget_city_综合运营_二供管理_维修管理_工单办理';
break;
}
const webPath = item.webPath || 'product/maintenance/CaseManage/CaseDoingBox/StardCaseDoingBoxView|isDelay=1';
window.share.event.emit('listenerMointer', {
widgetId: widgetID,
label,
url: webPath,
});
}
const webPath = item.webPath || 'product/maintenance/CaseManage/CaseDoingBox/StardCaseDoingBoxView|isDelay=1';
window.share.event.emit('listenerMointer', {
widgetId: widgetID,
label,
url: webPath,
});
confirmRead(false, [message.id]);
};
return (
......@@ -62,6 +66,7 @@ const Case = ({ message, confirmRead }) => {
className={classNames(`${prefixCls}-notifier-message_case`, `${prefixCls}-notifier-message-container`)}
title="点击查看详情"
onClick={() => goPath(message)}
style={{ backgroundImage: `url(${getMessageTypeIcon(message)})` }}
>
<div className={`${prefixCls}-notifier-message-title`}>
<span>{caseType}</span>
......@@ -72,7 +77,9 @@ const Case = ({ message, confirmRead }) => {
e.stopPropagation();
confirmRead(false, [message.id]);
}}
// eslint-disable-next-line global-require
src={require('../../images/oper/ok_line.png')}
alt=""
/>
</div>
<div className={`${prefixCls}-notifier-message-content`}>
......
import React from 'react';
import { ConfigProvider } from 'antd';
// eslint-disable-next-line import/no-unresolved
import classNames from 'classnames';
import '../styles/common.less';
import './index.less';
import './index.less';
import { getMessageTypeIcon } from '../../utils';
export class NoticeContent {
// eslint-disable-next-line no-undef
......@@ -15,7 +16,6 @@ export class NoticeContent {
}
}
const Notice = ({ message, confirmRead, config, handlerSysDetail }) => {
const { getPrefixCls } = React.useContext(ConfigProvider.ConfigContext);
const prefixCls = getPrefixCls();
......@@ -25,26 +25,31 @@ const Notice = ({ message, confirmRead, config, handlerSysDetail }) => {
const noticeContent = message?.infoContent?.noticeContent ?? '';
// const remark = message?.infoContent?.remark;
const goPath = (item) => {
const goPath = item => {
confirmRead(false, [message.id]);
handlerSysDetail && handlerSysDetail(message);
};
return (
<div
className={classNames(`${prefixCls}-notifier-message_notice`, `${prefixCls}-notifier-message-container`)}
title="点击查看详情"
onClick={() => goPath(message)}
style={{ backgroundImage: `url(${getMessageTypeIcon(message)})` }}
>
<div className={`${prefixCls}-notifier-message-title`}>
<span>{noticeType}{noticeTitle ? `:${noticeTitle}` : ''}</span>
<span>
{noticeType}
{noticeTitle ? `:${noticeTitle}` : ''}
</span>
<img
className={`${prefixCls}-notifier-message-confirm`}
title="点击标为已读"
onClick={(e) => {
onClick={e => {
e.stopPropagation();
confirmRead(false, [message.id]);
}}
// eslint-disable-next-line global-require
src={require('../../images/oper/ok_line.png')}
alt=""
/>
......@@ -52,7 +57,7 @@ const Notice = ({ message, confirmRead, config, handlerSysDetail }) => {
<div className={`${prefixCls}-notifier-message-content`}>
<p>{noticeContent}</p>
</div>
<p className={`${prefixCls}-notifier-message-time`}>{message.time}</p>
<p className={`${prefixCls}-notifier-message-time`}>{message.time}</p>
</div>
);
};
......
import React from 'react';
import { ConfigProvider } from 'antd';
// eslint-disable-next-line import/no-unresolved
import classNames from 'classnames';
import '../styles/common.less';
......@@ -11,24 +12,23 @@ const Unknown = ({ message, confirmRead, handlerUnknowDetail }) => {
const prefixCls = getPrefixCls();
let content = '';
let noticeTitle = '';
const { infoContent } = message;
try {
const type = typeof message.infoContent;
switch (type) {
case 'object':
let { infoContent } = message;
noticeTitle = infoContent.title || '';
content = infoContent.content || JSON.stringify(message.infoContent);
break;
case 'string':
content = message.infoContent;
noticeTitle = message.title || infoContent.title || '';
content = infoContent.content || message.defaultContent || JSON.stringify(message.infoContent);
break;
default:
noticeTitle = message.title || '';
content = message.defaultContent || message.infoContent;
break;
}
} catch (e) {
// i
}
const goPath = (item) => {
const goPath = item => {
handlerUnknowDetail && handlerUnknowDetail(message);
confirmRead(false, [message.id]);
};
......@@ -37,17 +37,18 @@ const Unknown = ({ message, confirmRead, handlerUnknowDetail }) => {
className={classNames(`${prefixCls}-notifier-message_unknown`, `${prefixCls}-notifier-message-container`)}
title="点击查看详情"
onClick={() => goPath(message)}
style={{backgroundImage: `url(${getMessageTypeIcon(message.messType)})`}}
style={{ backgroundImage: `url(${getMessageTypeIcon(message)})` }}
>
<div className={`${prefixCls}-notifier-message-title`}>
<span>{noticeTitle}</span>
<img
className={`${prefixCls}-notifier-message-confirm`}
title="点击标为已读"
onClick={(e) => {
onClick={e => {
e.stopPropagation();
confirmRead(false, [message.id]);
}}
// eslint-disable-next-line global-require
src={require('../../images/oper/ok_line.png')}
alt=""
/>
......
import { MESSAGE_TYPE } from '../constants';
import parseMessageToJSON from './parse';
import alarm_icon from '../images/types/alarm.png';
import approve_icon from '../images/types/approve.png';
import meeting_icon from '../images/types/meeting.png';
import notice_icon from '../images/types/notice.png';
import task_icon from '../images/types/task.png';
import work_icon from '../images/types/work.png';
import write_icon from '../images/types/write.png';
import other_icon from '../images/types/other.png';
import alarmIcon from '../images/types/alarm.png';
import approveIcon from '../images/types/approve.png';
import meetingIcon from '../images/types/meeting.png';
import noticeIcon from '../images/types/notice.png';
import taskIcon from '../images/types/task.png';
import workIcon from '../images/types/work.png';
import writeIcon from '../images/types/write.png';
import otherIcon from '../images/types/other.png';
export const getMessageTypeIcon = messageType => {
let icon = other_icon;
export const getMessageTypeIcon = message => {
const { webIcon } = message;
if (webIcon) return `${window.location.origin}/${webIcon}`;
const { messageType, infoType } = message;
let icon = otherIcon;
if (infoType === '通用报警') {
icon = alarmIcon;
} else if (infoType === '系统通知') {
icon = noticeIcon;
} else if (infoType === '工单提醒') {
icon = workIcon;
}
if (!messageType) return icon;
if (messageType === '工时填报') {
icon = write_icon;
icon = writeIcon;
} else if (messageType.indexOf('审批') > -1) {
icon = approve_icon;
icon = approveIcon;
} else if (messageType.indexOf('会议') > -1) {
icon = meeting_icon;
icon = meetingIcon;
} else if (messageType.indexOf('任务') > -1) {
icon = task_icon;
icon = taskIcon;
}
return icon;
};
export const getMessageClasses = messageType => {
let infoType = '';
switch (messageType) {
// 报警类
case 'SCADA报警':
case '通用报警':
infoType = MESSAGE_TYPE.ALARM_TYPE;
break;
// 工单类
case '工单流程':
case '工单提醒':
infoType = MESSAGE_TYPE.CASE_TYPE;
break;
// 系统消息类
case '系统通知':
case '系统消息':
infoType = MESSAGE_TYPE.SYS_TYPE;
break;
// 其他类
default:
infoType = MESSAGE_TYPE.UNKNOWN;
break;
}
return infoType;
let infoType = '';
switch (messageType) {
// 报警类
case 'SCADA报警':
case '通用报警':
infoType = MESSAGE_TYPE.ALARM_TYPE;
break;
// 工单类
case '工单流程':
case '工单提醒':
infoType = MESSAGE_TYPE.CASE_TYPE;
break;
// 系统消息类
case '系统通知':
case '系统消息':
infoType = MESSAGE_TYPE.SYS_TYPE;
break;
// 其他类
default:
infoType = MESSAGE_TYPE.UNKNOWN;
break;
}
return infoType;
};
/**
* 消息语音单位转换
* 说明:消息通过语音播放时,需要将一些字母单位转换成文字,不然会当做字母播放。
......@@ -76,16 +82,17 @@ export const replaceSpeak = msg => {
return msg;
};
// eslint-disable-next-line arrow-body-style
export const generatedId = () => {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
.replace(/[xy]/g, function(c) {
// eslint-disable-next-line no-bitwise
const r = (Math.random() * 16) | 0;
// eslint-disable-next-line no-bitwise
const v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
})
.toUpperCase();
};
export {
parseMessageToJSON,
}
\ No newline at end of file
export { parseMessageToJSON };
This diff is collapsed.
This diff is collapsed.
......@@ -9,6 +9,7 @@
import React, { useEffect } from 'react';
import BaseLogin from './template/baseLogin';
import NewYear from './template/newYear';
import baseLoginNewYear from './template/baseLoginNewYear';
import InfoLogin from './template/infoLogin';
import Yulin from './template/yulin';
// import { useParams } from '@wisdom-utils/runtime';
......@@ -28,6 +29,7 @@ import DazuLogin from './template/project/dazu';
import PanoramaLogin from './template/panorama';
import { AppInitState } from '../../../render';
const LoginTemplate = {
'新春.html': baseLoginNewYear,
'新春 - 智联.html': NewYear,
'Dark - IOTMultiLogin.html': BaseLogin,
'Dark.html': BaseLogin,
......
......@@ -98,25 +98,30 @@ class Login {
site: this.getLocalSiteBytoken(token),
'request.preventCache': Date.now(),
ignoreSite: true,
}).then(response => {
if (response && response.code === 0) {
self.globalConfig.userInfo = window?.globalConfig?.transformUserInfo?.(response.data) ?? {};
self.updateConfig && self.updateConfig(self.globalConfig);
self.getUserInfoAndConfig();
} else {
self.logout && self.logout();
if (params.getParams('token')) {
// token免登录失败,回到登录页,防止reload造成死循环
window.location.href = `${window.location.origin}`;
return false;
}
if (self.globalConfig.style === 'ios' && self.globalConfig.loginTemplate === 'IOSCloud.html') {
window.location.href = `${window.location.origin}`;
return false;
})
.then(response => {
if (response && response.code === 0) {
self.globalConfig.userInfo = window?.globalConfig?.transformUserInfo?.(response.data) ?? {};
self.updateConfig && self.updateConfig(self.globalConfig);
self.getUserInfoAndConfig();
} else {
self.logout && self.logout();
if (params.getParams('token')) {
// token免登录失败,回到登录页,防止reload造成死循环
window.location.href = `${window.location.origin}`;
return false;
}
if (self.globalConfig.style === 'ios' && self.globalConfig.loginTemplate === 'IOSCloud.html') {
window.location.href = `${window.location.origin}`;
return false;
}
window.location.reload();
}
window.location.reload();
}
});
})
.catch(error => {
this.handleLoginError();
Logger.log('获取用户配置失败');
});
}
writeLogs() {
......@@ -182,7 +187,6 @@ class Login {
getWebConfig(token, getIndustry) {
const self = this;
// eslint-disable-next-line no-undef
// 获取网站配置的同时,预先获取到mqtt配置,注册进子应用
Promise.all([
noticeService.getMqttSiteCode({ 'request.preventCache': Date.now() }),
......@@ -701,11 +705,16 @@ class Login {
self.updateConfig && self.updateConfig(self.globalConfig);
} catch (error) {
console.log(error);
message.error('登录失败');
if (self.goLogin()) {
return false;
}
// self.handleLoginError(failCallback);
}
})
.catch(error => {
this.handleLoginError();
Logger.log('获取用户配置失败');
});
} else {
self.handleLoginError();
......
/* eslint-disable no-empty */
/* eslint-disable react-hooks/exhaustive-deps */
/* eslint-disable no-undef */
import '@wisdom-utils/utils/lib/helpers/format';
import { params } from '@wisdom-utils/utils/lib/helpers';
import React, { forwardRef, useEffect, useRef, useState } from 'react';
......@@ -29,14 +32,23 @@ const Login = forwardRef((props, _ref) => {
action &&
action.events.on('loginSuccess', event => {
// http://127.0.0.1:8080/civbase/civweb4/
// props.updateConfig(Object.assign({}, props.global, {
// homepage: params.getParams('redirect')
// }));
props.updateConfig(
Object.assign({}, window.globalConfig, {
redirect,
}),
);
let url = '';
try {
url =
_.isString(redirect) && redirect.replace(new RegExp(/ /g), '').length > 0
? redirect.replace('&skipHome=true', '')
: '';
} catch (error) {}
// props.history.push('/' + params.getParams('redirect'))
props.history.push(`/?client=${props.global.client}`);
// window.share.event.emit('triggerMicro', props.global);
// initMicroApps();
defaultApp(redirect);
defaultApp(url);
});
return () => {
action && action.events && action.events.removeAllListeners('loginSuccess');
......
This diff is collapsed.
import 'kit_utils/lib/format';
import React, { forwardRef, useEffect, useRef, useState } from 'react';
import { Modal } from 'antd';
// eslint-disable-next-line import/no-unresolved
import classNames from 'classnames';
import { dom } from '@wisdom-utils/utils/lib/helpers';
import { Helmet, HelmetProvider } from 'react-helmet-async';
import { connect } from 'react-redux';
import { useHistory } from '@wisdom-utils/runtime';
import { actionCreators } from '@/containers/App/store';
import defaultSetting from '../../../../../../config/defaultSetting';
import LoginAction from '../../login';
import styles from './style.less';
import useRenderQcode from '../../js/useRenderQcode';
import Account from '../../js/useAccount';
import IotComponent from '../../js/useIOTComponent';
import { defaultApp } from '../../../../../micro';
import Krpano from '../../components/Krpano';
const PanoBaseLogin = forwardRef((props, _ref) => {
const videoRef = useRef();
const loginRef = useRef();
const timeRef = useRef();
const titleRef = useRef();
const sliVerify = useRef();
const loginFormRef = useRef();
const formRef = useRef(null);
const footerRef = useRef();
const [status, setStatus] = useState('normal');
const [autoLogin, setAutoLogin] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [currentDate, setCurrentDate] = useState({});
const [type, setType] = useState('Account');
const [visible, setVisible] = useState(false);
const history = useHistory();
const [action, setAction] = useState(() => new LoginAction(Object.assign({}, props, { history }), setVisible, false));
let { ddCode } = props.global;
const loginMode =props.loginMode;
const { projectName } = props.loginParams
if (loginMode && loginMode === 'iotWechat') ddCode = null;
// useEffect(() => {
// action.globalConfig = props.global;
// }, [props.global]);
const handleSubmit = values => {
/* eslint-disable */
action &&
(type === 'Account'
? action.loginHandler(
values.userName,
values.password,
null,
autoLogin,
sliVerify,
)
: type === 'Mobile'
? action.phoneLoginFormHandler(values.mobile, values.captcha)
: null);
setSubmitting(true);
props.updateCurrentIndex && props.updateCurrentIndex(-1);
};
useEffect(() => {
// if (props.loginMode === LOGIN_WAY.WeChart) {
action &&
action.events.on('loginSuccess', event => {
setSubmitting(false);
props.updateCurrentIndex && props.updateCurrentIndex(0);
props.history.push(`/?client=${props.global.client}`);
// window.share.event.emit('triggerMicro', props.global);
// initMicroApps();
defaultApp();
});
action &&
action.events.on('loginError', event => {
setVisible(false);
setSubmitting(false);
});
action &&
action.events.on('loginVisible', status => {
setVisible(status);
});
// }
return () => {
action && action.events && action.events.removeAllListeners('loginSuccess');
action && action.events && action.events.removeAllListeners('loginError');
action && action.events && action.events.removeAllListeners('loginVisible');
}
}, [props.loginMode]);
let loginTimeInterval = null;
useEffect(() => {
if (loginTimeInterval)
clearInterval(loginTimeInterval), (loginTimeInterval = null);
loginTimeInterval = setInterval(() => {
const date = new Date();
const weekday = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'];
const time = `${date.getHours() < 10 ? `0${date.getHours()}` : date.getHours()
}:${date.getMinutes() < 10 ? `0${date.getMinutes()}` : date.getMinutes()
}:${date.getSeconds() < 10 ? `0${date.getSeconds()}` : date.getSeconds()
}`;
setCurrentDate({
time,
dayofweek: weekday[date.getDay()],
date: date.pattern('yyyy/MM/dd'),
});
}, 1000);
return () => {
loginTimeInterval && clearInterval(loginTimeInterval);
};
}, []);
useEffect(() => {
setSubmitting(false);
}, [visible]);
const renderAddons = useRenderQcode(props.global);
const renderPlatform = () => {
const template = props.global.loginTemplate;
const params = {
fromRef: formRef,
type,
setType,
status,
submitting,
autoLogin,
setAutoLogin,
action,
onSubmit: handleSubmit,
loginMode: props.loginMode,
updateLoginMode: props.updateLoginMode,
};
switch (template) {
case 'DarkCloud.html':
case 'Dark.html':
return <Account {...params} />;
case 'Dark - IOTMultiLogin.html':
return <IotComponent {...params} />;
default:
return <Account {...params} />;
}
};
/* eslint-disable */
return (
<HelmetProvider>
<Helmet>
<title>{props.global.title || defaultSetting.title}</title>
<meta name="description" content={props.global.title || defaultSetting.title} />
</Helmet>
<div className={styles.main}>
<div className={styles.inner}>
<div
className={classNames(styles.loginTime)}
ref={loginRef}
>
<img
role="logo"
src={props.global && props.global.transformDevAssetsBaseURL && props.global.transformDevAssetsBaseURL(props.global.logo)}
/>
<div
className={classNames(
styles.titleCase
)}
ref={titleRef}
>
<span className={styles.title}>{props.global.title}</span>
<span className={styles.subtitle}>
{window.globalConfig && window.globalConfig.subtitle}
</span>
</div>
</div>
<div
className={classNames(
styles.timeCase
)}
ref={timeRef}
>
<span className={styles.time}>{currentDate.time}</span>
<span className={styles.dayofweek}>{currentDate.dayofweek}</span>
<span className={styles.date}>{currentDate.date}</span>
</div>
<div
className={classNames(
styles['login-block']
)}
ref={loginFormRef}
>
<div>
<img src="https://panda-water.cn/web4/assets/images/login/dark/login.png" />
</div>
<div className={styles['login-form']}>{renderPlatform()}</div>
</div>
</div>
{projectName ? <div className={styles.krpano}>
<Krpano projectName={projectName} />
</div> : null}
<Modal
centered
visible={visible}
width={340}
footer={null}
closable={false}
bodyStyle={{ padding: '15px' }}
>
<div ref={sliVerify} />
</Modal>
</div>
</HelmetProvider>
);
});
const mapStateToProps = state => ({
global: state.getIn(['global', 'globalConfig']),
loginMode: state.getIn(['global', 'loginMode']),
});
const mapDispatchToProps = dispatch => ({
updateConfig(config) {
dispatch(actionCreators.getConfig(config));
},
createContext(data) {
dispatch(actionCreators.createContext(data));
},
updateLoginMode(mode) {
dispatch(actionCreators.changeLoginMode(mode));
},
updateCurrentIndex(index) {
dispatch(actionCreators.updateCurrentIndex(index));
},
});
export default connect(
mapStateToProps,
mapDispatchToProps,
)((PanoBaseLogin));
import BaseLogin from "../baseLogin"
import PanoBaseLogin from "./PanoBaseLogin"
import TieShanLogin from "../project/tieshan"
import { useState , useEffect } from "react"
const LoginTemplate = {
"铁山" : TieShanLogin,
default : BaseLogin
default : PanoBaseLogin
}
const Panorama = props => {
......
@import '~antd/es/style/themes/variable.less';
@userPageLogin-prefix-cls: ~'@{ant-prefix}-pro-pages-user-login';
@keyframes loginTimeShow {
0% {
opacity: 1;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
zoom: 2;
}
50% {
opacity: 1;
top: 28px;
left: 45px;
transform: translate(0, 0);
zoom: 1;
}
60% {
opacity: 1;
left: 45px;
top: 28px;
transform: translate(0, 0);
}
70% {
opacity: 1;
left: 45px;
top: 28px;
transform: translate(0, 0);
}
75% {
opacity: 1;
left: 45px;
top: 28px;
transform: translate(0, 0);
}
100% {
opacity: 1;
left: 45px;
top: 28px;
transform: translate(0, 0);
}
}
.main {
// width: 368px;
margin: 0 auto;
height: 100%;
width: 100%;
@media screen and (max-width: @screen-sm) {
width: 95%;
}
.icon {
margin-left: 16px;
color: rgba(0, 0, 0, 0.2);
font-size: 24px;
vertical-align: middle;
cursor: pointer;
transition: color 0.3s;
&:hover {
color: @primary-color;
}
}
.other {
margin-top: 24px;
line-height: 22px;
text-align: left;
.register {
float: right;
}
}
.videLayer {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
object-fit: fill;
}
.inner {
position: absolute;
width: 100%;
height: 100%;
&.newYearInner {
height: 100%!important;
}
.loginTime {
position: absolute;
top: 25px;
left: 50px;
display: flex;
align-items: center;
justify-content: center;
opacity: 1;
z-index: 100;
&.newYearLoginTime {
position: absolute!important;
top: 28px!important;
left: 45px!important;
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
transform: inherit!important;
}
img[role='logo'] {
height: 40px;
vertical-align: middle;
}
&.loginTimeShow {
animation-name: loginTimeShow;
animation-duration: 1s;
animation-iteration-count: 1;
animation-fill-mode: forwards;
}
.titleCase {
display: flex;
flex-direction: column;
margin: -5px 0 0 20px;
max-width: 570px;
.title,
.subtitle {
font-family: 'Microsoft YaHei';
text-align: left;
overflow-wrap: break-word;
color: #ffffff;
}
.title {
font-size: 28px;
}
.subtitle {
font-size: 12px;
line-height: 1;
}
}
}
.timeCase{
position: absolute;
width: 100%;
z-index: 200;
}
.timeCase {
.time,
.dayofweek,
.date {
position: absolute;
font-family: 'MicrosoftYaHeiUI';
color: rgba(255, 255, 255, 1);
}
.time {
top: 26px;
right: 170px;
font-size: 40px;
margin-right: 10px;
}
.dayofweek {
top: 32px;
right: 125px;
font-size: 16px;
}
.date {
top: 57px;
right: 95px;
font-size: 14px;
}
}
.loginBlockWrapper {
width: 100%;
height: 100%;
background-image: url(https://panda-water.com/web4/assets/images/login/workflow/智联新春背景.png);
background-size: 100% 100%;
background-repeat: no-repeat;
}
.login-block {
width: 800px;
position: absolute;
left: 50%;
top: 50%;
display: flex;
background:rgba(255,255,255,0.5);
transform: translate(-50%,-50%);
z-index: 100;
&.login-newYear-block {
width: 994px!important;
height: 424px!important;
margin-left: -497px!important;
margin-top: -212px!important;
background: url(https://panda-water.com/web4/assets/images/login/workflow/%E6%99%BA%E8%81%94%E6%96%B0%E6%98%A5%E8%83%8C%E6%99%AF%E6%A1%86.png)!important;
//width: 994px;
//height: 424px;
//position: absolute;
//left: 50%;
//top: 50%;
//margin-left: -497px;
//margin-top: -212px;
//display: flex;
background-size: 100% 100%;
background-repeat: no-repeat;
img {
margin-top: 90px;
margin-left: 168px;
}
.login-form {
display: flex;
align-items: center;
margin-left: 32px;
padding: 0;
background: transparent;
margin-top: -36px;
// :global {
// .ant-btn-primary {
// background: #ff9600 !important;
// border-color: #ff9600 !important;
// }
// }
}
}
img {
margin-top: 50px;
margin-bottom: 50px;
margin-left: 30px;
}
.login-form {
padding: 50px 50px 50px;
// background-color: #ffffff;
}
}
}
.footerCase {
width: 100%;
height: 16%;
background: #fff;
position: absolute;
bottom: 0;
left: 0;
.quickMark {
position: absolute;
bottom: 48px;
text-align: center;
width: 100%;
font-size: 12px;
min-height: 71px;
&-single {
text-align: center;
width: 120px;
display: inline-block;
span {
&.Android {
display: block;
background-image: url(https://panda-water.cn/web4/assets/images/login/dark/Android1.png);
width: 26px;
height: 32px;
margin: auto;
margin-bottom: 6px;
}
&.Wechat {
display: block;
background-image: url(https://panda-water.cn/web4/assets/images/login/dark/Wechat1.png);
width: 34px;
height: 32px;
margin: auto;
margin-bottom: 6px;
}
&.iphone {
display: block;
background-image: url(https://panda-water.cn/web4/assets/images/login/dark/iphone1.png);
width: 28px;
height: 32px;
margin: auto;
margin-bottom: 6px;
}
}
}
.Android-single .Android-code,
.iphone-single .iphone-code {
margin: 0px 0px 10px 0px;
width: 150px;
height: 150px;
background: #fff;
padding: 5px;
display: none;
transform: translateX(-15px);
}
.icon-Container {
height: 50px;
cursor: pointer;
}
}
.copyright {
position: absolute;
z-index: 2;
text-align: center;
width: 100%;
bottom: 10px;
font-size: 13pz;
color: #000000;
.frontIcon {
margin-top: -5px;
}
a {
color: #000000;
}
.addons {
display: none;
}
.split {
border-left: 1px solid #000000;
margin: 0 8px;
}
.glyphicon-qrcode {
vertical-align: text-top;
}
}
}
:global {
.antd-pro-login-submit {
width: 100%;
margin-top: 24px;
}
}
.wechatQRcode {
width: 250px;
height: 220px;
margin: 0 15px;
}
.loginDisplay {
width: 100%;
display: flex;
justify-content: space-between;
font-size: 12px;
a {
&:hover {
color: @primary-color;
transition: all 0.3s ease-in-out;
}
}
}
.captcha {
color: @primary-6;
font-weight: 400;
cursor: pointer;
font-size: 12px;
}
}
.krpano {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
This diff was suppressed by a .gitattributes entry.
......@@ -58,9 +58,17 @@ export const AppInitState = () => {
const client = value && value !== 'undefined' ? value : 'city';
return client;
};
const getUrlToken = () => {
const value = params.getParams('token');
const token = value && value !== 'undefined' ? value : null;
return token;
};
const client = getClient();
const token = getUrlToken();
if (sessionStorage.getItem('client') !== client) {
sessionStorage.setItem('client', client);
}
let config = window.globalConfig || {};
// eslint-disable-next-line no-undef, no-restricted-globals
createStoreage.remove(`__PANDA_STORE__${location.hostname}`);
......@@ -162,7 +170,8 @@ export const AppInitState = () => {
initMicroApps();
}
// eslint-disable-next-line no-new
if (getToken()) {
// 增加免登判定
if (!token && getToken()) {
// eslint-disable-next-line no-new
const action = new Login(
{
......
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