Commit ca994e24 authored by 邓晓峰's avatar 邓晓峰

feat: add AvatarDropdown

parent c57d778f
Pipeline #47277 skipped with stages
......@@ -110,7 +110,7 @@
"@wisdom-map/Map": "^1.0.12-17",
"@wisdom-map/arcgismap": "^1.0.79-17",
"@wisdom-map/util": "^1.0.27-0",
"@wisdom-utils/components": "0.0.34",
"@wisdom-utils/components": "0.0.37",
"@wisdom-utils/runtime": "0.0.15",
"@wisdom-utils/utils": "0.0.77",
"animate.css": "^4.1.1",
......@@ -131,7 +131,6 @@
"kit_utils": "^1.3.11",
"lodash": "4.17.11",
"minimist": "1.2.0",
"mqtt-client": "^1.0.11",
"omit.js": "^2.0.2",
"pinyin-match": "^1.1.1",
"promise.prototype.finally": "^3.1.2",
......@@ -159,8 +158,7 @@
"reselect": "4.0.0",
"sanitize.css": "8.0.0",
"sha1": "^1.1.1",
"styled-components": "4.2.0",
"use-merge-value": "^1.0.2"
"styled-components": "4.2.0"
},
"devDependencies": {
"@babel/cli": "7.4.3",
......@@ -243,11 +241,9 @@
"less-loader": "5.0.0",
"lint-staged": "8.1.5",
"memoizee": "^0.4.15",
"microser-data": "^2.1.3",
"mini-css-extract-plugin": "^0.12.0",
"mockjs": "^1.0.1-beta3",
"moment": "^2.29.1",
"mousetrap": "^1.6.5",
"multer": "^1.4.2",
"nanoid": "^3.1.16",
"node-fetch": "^2.6.1",
......
import React from 'react';
import { BaseComponent } from '@wisdom-utils/components';
import mousetrap from 'mousetrap';
import propTypes from 'prop-types';
/* eslint-disable */
export default class HandlerMap extends BaseComponent {
componentDidMount() {
const { keyHandlerMap } = this.props;
if (keyHandlerMap) {
// eslint-disable-next-line no-multi-assign
const mouse = (this.mousetrap = mousetrap);
let c = !0;
let d = !1;
// eslint-disable-next-line no-void
const e = void 0;
try {
for (
// eslint-disable-next-line no-var,vars-on-top
var f, g = keyHandlerMap.entries()[Symbol.iterator]();
!(c = (f = g.next()).done);
c = !0
) {
const { value } = f;
mouse.bind(value[0], value[1]);
}
// eslint-disable-next-line no-shadow
} catch (e) {
d = !0;
// eslint-disable-next-line no-ex-assign
e = mouse;
} finally {
try {
// eslint-disable-next-line no-unused-expressions,block-scoped-var
!c && g.return && g.return();
} finally {
if (d) {
// eslint-disable-next-line no-unsafe-finally
throw e;
}
}
}
}
}
componentWillUnmount() {
// eslint-disable-next-line no-unused-expressions
this.mousetrap && this.mousetrap.reset() && (this.mousetrap = null);
}
render() {
return this.props.children;
}
}
HandlerMap.propTypes = {
keyHandlerMap: propTypes.object,
children: propTypes.node,
};
import React from 'react';
import HandlerMap from './HandlerMap';
import { HandlerMap } from '@wisdom-utils/components';
const MaintenanceHost = window.location.origin;
const MaintenancePath = 'civmanage';
......
import React from 'react';
import {
Avatar,
Form,
Input,
message,
Modal,
Popover,
Spin,
Upload,
} from 'antd';
import { withRouter } from 'react-router';
import { request } from '@wisdom-utils/utils';
import { FormattedMessage, useIntl } from '@wisdom-utils/components';
import { appService } from '../../api';
// eslint-disable-next-line import/named
import { API } from '../../api/service/base';
import globalHeader from '@wisdom-utils/components/lib/AppLayout/locales/zh-CN/globalHeader';
import styles from './index.less';
// import i18n from '../../utils/share';
// const app = i18n.getI18n('component');
const formItemLayout = {
labelCol: {
xs: { span: 4 },
sm: { span: 4 },
},
};
/* eslint-disable */
const getIOT = () =>
(window.globalConfig.loginTemplate === 'Dark - IOTMultiLogin.html' ||
window.globalConfig.loginTemplate === '新春 - 智联.html')
class AvatarDropdown extends React.Component {
/* eslint-disable no-unused-vars */
constructor(props) {
super(props);
let {
currentUser = {
avatar: this.transformAvatarImage(),
name:
(props.global &&
props.global.userInfo &&
props.global.userInfo.fullName) ||
'Serati Ma',
},
} = this.props;
this.state = {
currentUser: currentUser,
visible: false,
popVisible: false,
path: null,
version: null,
action: API.UPLOAD_FILE_URL
}
}
loginout = event => {
// eslint-disable-next-line no-undef
this.props.logout();
if (
window.globalConfig.style === 'ios' &&
window.globalConfig.loginTemplate === 'IOSCloud.html'
) {
window.location.href = `${window.location.origin}/#login`;
return false;
}
// console.log(this.props)
// this.props.history.push('/login')
// window.location.reload();
//
};
getRoles = () => {
const roles = this.props.global.userInfo.roles || [];
const ret = [];
roles.forEach(item => {
ret.push(item.name);
});
return ret.join(',');
};
showModal = event => {
event.stopPropagation();
this.setState({
visible: true,
});
};
handleOk = (event, form) => {
event.stopPropagation();
form
.validateFields()
.then(res => {
const params = getIOT()
? {
newPassword: res.newPwd,
phone: window.globalConfig.userInfo.Phone,
}
: {
password: res.oldPwd,
newpassword: res.newPwd,
token: window.globalConfig.token,
};
appService.changePassword(params)
.then(res => {
if (res.success) {
//message.success(useIntl().formatMessage({id: 'component.account.password.update.success'}));
message.success(globalHeader['component.account.password.update.success']);
setTimeout(() => {
this.setState({
visible: false,
});
}, 300);
} else {
message.error(useIntl().formatMessage({id: 'component.account.oldpassword.errorMessage'}));
}
})
.catch(error => {
message.error(useIntl().formatMessage({id: 'component.account.password.update.fail'}));
});
})
.catch(error => {
console.log(error);
});
};
handleCancel = (event, form) => {
event.stopPropagation();
form.resetFields();
this.setState({
visible: false,
});
};
transformAvatarImage() {
const { userInfo } = this.props.global;
const defaultImage = `${
window.location.origin
}/civweb4/assets/images/icon/熊猫新2.png`;
let image = defaultImage;
if (
userInfo &&
userInfo.UserImge &&
userInfo.UserImge.indexOf('个人信息') > -1
) {
image = `/cityinterface/rest/services/filedownload.svc/download/${userInfo.UserImge}`;
} else if (
userInfo.UserImge &&
userInfo.UserImge !== '' &&
userInfo.UserImge !== 'default_user.png'
) {
image = userInfo.UserImge;
} else if (userInfo.WxImage && userInfo.WxImage !== '') {
image = userInfo.WxImage;
}
return image;
}
beforeUpload(file) {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
message.error('You can only upload JPG/PNG file!');
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('Image must smaller than 2MB!');
}
const path = (new Date()).getTime();
this.setState({
path: path,
action: this.state.action.replace('{path}', path).replace('{filename}', file.name)
})
return isJpgOrPng && isLt2M;
}
handleChange(data) {
console.log(data)
}
componentDidMount() {
appService.getVersion({
ignoreSite: true
}).then(res => {
if(res.success) {
this.setState({
version: res.message
})
}
}).catch(error => {
message.error(useIntl().formatMessage({id: 'component.getVersion.errorMessage'}))
})
}
customRequest = ({
action,
data,
file,
filename,
headers,
onError,
onProgress,
onSuccess,
withCredentials,}) => {
const formData = new FormData();
if(data) {
Object.keys(data).forEach(key => {
formData.append(key, data[key]);
})
}
formData.append("filedata", file);
request(action, {
withCredentials,
headers: {
...headers,
Accept: '*/*',
'civ-site': ''
},
method: 'post',
data: formData,
ignoreSite: true,
onUploadProgress: ({ total, loaded }) => {
onProgress({ percent: Math.round((loaded / total) * 100).toFixed(2) }, file);
},
})
.then(res => {
onSuccess(res, file);
})
.catch(onError);
return {
abort() {
console.log('upload progress is aborted.');
}
}
}
render() {
const self = this;
const { props } = this;
const { userInfo } = props.global;
const site =
props.global &&
props.global.userInfo &&
props.global.userInfo.site &&
userInfo.site !== '' &&
props.global.client !== 'oms'
? userInfo.site
: '';
const uploadProps = {
action: this.state.action,
onStart(file) {
console.log('onStart', file, file.name);
},
onSuccess(res, file) {
if(res.success) {
const avatarPath = "/个人信息/" + self.state.path + '/' + file.name;
const params = {
userID: props.global.get("userInfo.OID"),
loginName: props.global.get("userInfo.loginName"),
userName: props.global.get("userInfo.fullName"),
_version: self.state.version,
mark: props.global.get("userInfo.Mark"),
phone: props.global.get("userInfo.Phone"),
email: props.global.get("userInfo.Email"),
userImage: decodeURIComponent(avatarPath),
WXid: props.global.get("userInfo.WXid")
}
appService.updateAvatar(params).then(res => {
if(res.success) {
// message.success(useIntl().formatMessage({id: 'component.avatar.update.success'}));
message.success(globalHeader['component.avatar.update.success']);
self.setState({
currentUser: {
name: self.state.currentUser.name,
avatar: `${API.AVATAR_FILE_URL}${avatarPath}`,
action: API.UPLOAD_FILE_URL
}
})
}
}).catch(e => {
message.error(useIntl().formatMessage({id: 'component.avatar.update.fail'}))
})
} else {
message.error(res.message);
}
},
onError(err) {
console.log('onError', err);
},
onProgress({ percent }, file) {
console.log('onProgress', `${percent}%`, file.name);
},
customRequest: this.customRequest.bind(this),
beforeUpload: this.beforeUpload.bind(this),
onChange: this.handleChange.bind(this)
}
const currentUser = this.state.currentUser;
const menuHeaderDropdown = (
<div className={styles.userInfo}>
<div className={styles.header}>
<Upload className="avatar-uploader" {...uploadProps} maxCount={1} itemRender={()=>(<></>)}>
<div
className={styles.avatar}
style={{ backgroundImage: `url(${currentUser.avatar})` }}
/>
</Upload>
<div className={styles.name}>{userInfo.fullName}</div>
</div>
<div className={styles.body}>
<div className={styles.item}>
<ul>
<li>
<span />
<span className={styles.label}><FormattedMessage id="component.avatar.account"/></span>
<span className={styles.value}>{userInfo.loginName}</span>
</li>
<li>
<span />
<span className={styles.label}><FormattedMessage id="component.avatar.name"/></span>
<span className={styles.value}>{userInfo.fullName}</span>
</li>
<li>
<span />
<span className={styles.label}><FormattedMessage id="component.avatar.depart"/></span>
<span className={styles.value}>
{userInfo && userInfo.depart && userInfo.depart.name}
</span>
</li>
<li>
<span />
<span className={styles.label}><FormattedMessage id="component.avatar.role"/></span>
<span className={styles.value}>{this.getRoles()}</span>
</li>
{site ? (
<li>
<span />
<span className={styles.label}><FormattedMessage id="component.siteCode"/></span>
<span className={styles.value}>{userInfo.site}</span>
</li>
) : null}
</ul>
</div>
<div className={styles.exit}>
{userInfo && userInfo.site === '' && (
<a onClick={event => this.showModal(event)}><FormattedMessage id="component.password.update"/></a>
)}
<a onClick={this.loginout}><FormattedMessage id="component.exit.login"/></a>
</div>
</div>
</div>
);
return currentUser && currentUser.name ? (
<>
<Popover
overlayClassName={styles.userWrapper}
placement="bottom"
trigger="click"
content={
props.global && props.global.userInfo ? menuHeaderDropdown : null
}
>
<span
className={`${styles.action} ${styles.account}`}
ref={r => (this.avatarRef = r)}
>
<Avatar
size="small"
className={styles.avatar}
src={currentUser.avatar}
alt="avatar"
/>
{/* <span className={`${styles.name} anticon`}>{currentUser.name}</span> */}
</span>
</Popover>
<Modal
title="修改密码"
centered
width="480px"
visible={this.state.visible}
wrapClassName={styles.updatePassword}
cancelText="取消"
okText="确定"
onOk={event => this.handleOk(event, this.form)}
onCancel={event => this.handleCancel(event, this.form)}
zIndex={2000}
>
<Form
labelAlign="right"
{...formItemLayout}
ref={f => (this.form = f)}
>
{!getIOT() && (
<Form.Item
name="oldPwd"
label="原密码"
rules={[
{
required: true,
message: '请输入原始密码',
},
]}
hasFeedback
>
<Input.Password />
</Form.Item>
)}
<Form.Item
name="newPwd"
label="新密码"
rules={[
{
required: true,
message: '请输入新密码',
},
{
pattern: /^(?![0-9]+$)(?![a-zA-Z]+$)[a-zA-Z0-9!@#$%^&*_]{8,16}$/,
message: '密码字符长度为8-16个字符',
},
]}
hasFeedback
>
<Input.Password />
</Form.Item>
<Form.Item
name="confirmPwd"
label="确认密码"
dependencies={['newPwd']}
hasFeedback
rules={[
{
required: true,
message: '请输入确认密码',
},
({ getFieldValue }) => ({
validator(rule, value) {
if (!value || getFieldValue('newPwd') === value) {
return Promise.resolve();
}
return Promise.reject('确认密码与新密码输入不一致');
},
}),
]}
>
<Input.Password />
</Form.Item>
</Form>
</Modal>
</>
) : (
<span className={`${styles.action} ${styles.account}`}>
<Spin
size="small"
style={{
marginLeft: 8,
marginRight: 8,
}}
/>
</span>
);
}
}
export default withRouter(AvatarDropdown);
......@@ -5,9 +5,12 @@ import { connect } from 'react-redux';
import Icon from '@ant-design/icons';
import classNames from 'classnames';
import { useHistory } from '@wisdom-utils/runtime';
import { HeaderSearch, useIntl } from '@wisdom-utils/components';
import {
HeaderSearch,
useIntl,
AvatarDropdown as Avatar,
} from '@wisdom-utils/components';
import { actionCreators } from '../../containers/App/store';
import Avatar from './AvatarDropdown';
import styles from './index.less';
import NoticeIconView from './NoticeIconView';
/* eslint-disable */
......
......@@ -2,7 +2,11 @@ import React, { Component } from 'react';
import { Button, Form, Input, Modal } from 'antd';
import { connect } from 'react-redux';
import { Notifier, NoticeIcon } from '@wisdom-utils/components';
import {
Notifier,
NoticeIcon,
FormattedMessage,
} from '@wisdom-utils/components';
import {
ERR_OK,
MESSAGE_TYPE,
......@@ -12,7 +16,6 @@ import {
findPathByWidget,
isJSON,
} from '@wisdom-utils/components/lib/AppLayout/helpers';
import { FormattedMessage } from '@wisdom-utils/components';
import service from '../../api/service/notification';
import { actionCreators } from '../../containers/App/store';
import isProd from '../../utils/env';
......
......@@ -4,10 +4,13 @@ import { message } from 'antd';
import _ from 'lodash';
import { connect } from 'react-redux';
import Icon from '@ant-design/icons';
import { HeaderSearch, useIntl } from '@wisdom-utils/components';
import {
HeaderSearch,
useIntl,
AvatarDropdown as Avatar,
} from '@wisdom-utils/components';
import { actionCreators } from '../../containers/App/store';
import Avatar from './AvatarDropdown';
import styles from './index.less';
import NoticeIconView from './NoticeIconView';
......
......@@ -13,7 +13,7 @@ const UserLayout = props => {
routes: [],
},
} = props;
console.log(props)
const { breadcrumb } = getMenuData(route.routes);
const title = getPageTitle({
breadcrumb,
......@@ -35,8 +35,7 @@ const UserLayout = props => {
<div className={styles.container}>
<div className={styles.content}>
{renderRoutes(route.routes, props
)}
{renderRoutes(route.routes, props)}
{props.children}
</div>
{/* <DefaultFooter links={[]} copyright="Copyright © 熊猫智慧水务 2020 All Rights Reserved 沪ICP备11036640-1"/> */}
......
......@@ -7,12 +7,12 @@ import { connect } from 'react-redux';
import { useIntl } from '@wisdom-utils/components';
import { useDocumentTitle } from '@ant-design/pro-utils';
import { useHistory } from '@wisdom-utils/runtime';
import defaultSetting from '../../../config/defaultSetting';
import { actionCreators } from '../../containers/App/store';
import SecurityLayout from '../../layouts/SecurityLayout';
import LoginAction from '../user/login/login';
import styles from './index.less';
import { useHistory } from '@wisdom-utils/runtime';
import { initMicroApps } from '@/micro';
import usingIcon from '@/assets/bootPage/using-icon.png';
import { appService } from '@/api';
......@@ -63,27 +63,28 @@ const BootPage = props => {
const [loadding, setLoadding] = useState(false);
const [hasRole, setHasRole] = useState(false);
const [scale, setScale] = useState(1);
const [loginAction, setAction] = useState(
() => new LoginAction(props),
);
const [loginAction, setAction] = useState(() => new LoginAction(props));
const history = useHistory();
useDocumentTitle(
{ title: defaultSetting.title, id: '', pageName: '行业切换' },
props.global.title || defaultSetting.title,
);
const handlePage = useCallback((event, type) => {
event.persist();
event.preventDefault();
setLoadding(true);
const config = props.global;
// const loginAction = new LoginAction(props);
config.uiwidgets = [];
config.widgets = [];
config.allWidgets = [];
props.instance && props.instance.updateConfig(config);
// props.instance && props.instance.getUserInfoAndConfig('', true, type);
loginAction && loginAction.getUserInfoAndConfig('', true, type);
}, []);
const handlePage = useCallback(
(event, type) => {
event.persist();
event.preventDefault();
setLoadding(true);
const config = props.global;
// const loginAction = new LoginAction(props);
config.uiwidgets = [];
config.widgets = [];
config.allWidgets = [];
props.instance && props.instance.updateConfig(config);
// props.instance && props.instance.getUserInfoAndConfig('', true, type);
loginAction && loginAction.getUserInfoAndConfig('', true, type);
},
[loginAction, props.global, props.instance],
);
useEffect(() => {
// eslint-disable-next-line no-use-before-define
handleResize();
......@@ -104,16 +105,16 @@ const BootPage = props => {
initMicroApps();
window.share.event.emit('triggerMicro', props.global);
props.updateCurrentIndex(0);
}
};
loginAction.events.on('toggleIndustry', handleToggleIndustry);
return () => {
window.removeEventListener('resize', handleResize);
loginAction.events.removeListener('toggleIndustry', handleToggleIndustry);
};
}, []);
}, [loginAction.events, props]);
const renderIndustr = useMemo(
() => renderIndustries(props.global, handlePage),
[],
[handlePage, props.global],
);
const intl = useIntl();
......@@ -123,20 +124,22 @@ const BootPage = props => {
};
useEffect(() => {
appService.getUserInfo({
token: props.global.token,
subOID: 'subOID',
site: 'cloud',
ignoreSite: true,
})
.then(res => {
const roles = res && !res.errMsg ? res.roles : null;
const _hasRole = roles && Array.isArray(roles) && roles.filter(r => {
return r.name == '客户运维管理员';
}).length;
setHasRole(!!_hasRole);
});
}, []);
appService
.getUserInfo({
token: props.global.token,
subOID: 'subOID',
site: 'cloud',
ignoreSite: true,
})
.then(res => {
const roles = res && !res.errMsg ? res.roles : null;
const _hasRole =
roles &&
Array.isArray(roles) &&
roles.filter(r => r.name == '客户运维管理员').length;
setHasRole(!!_hasRole);
});
}, [props.global.token]);
return (
<SecurityLayout>
......@@ -180,7 +183,10 @@ const BootPage = props => {
</div>
{hasRole ? (
<div className={styles.cloudMonitorBtns}>
<div className="cloud-using-anaylysis-btn" onClick={toOMSUsingAnalysis}>
<div
className="cloud-using-anaylysis-btn"
onClick={toOMSUsingAnalysis}
>
<img src={usingIcon} alt="" title="点击查看平台使用监控" />
<span>平台使用分析</span>
</div>
......
......@@ -4,7 +4,7 @@ import { connect } from 'react-redux';
import AMapLoader from '@amap/amap-jsapi-loader';
import { store } from '@wisdom-utils/utils';
import { actionCreators } from '@/containers/App/store';
import MapComponent from '@/components/mapView';
import MapComponent from '@/components/MapView';
class CreateMap extends React.Component {
constructor(props) {
super(props);
......
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