feat: support change password
This commit is contained in:
parent
c5aec4c227
commit
486ef1e6f2
@ -619,6 +619,10 @@ const request = (function(_global) {
|
||||
// 跳转至login页
|
||||
// TODO: 用 react-router 重写,改造成本比较高,这里先hack
|
||||
const url = window.location.href;
|
||||
// TODO: 后端返回细致的错误码,如果原始密码不对 不应该直接跳到登陆页
|
||||
if (url.includes('password')) {
|
||||
return;
|
||||
}
|
||||
const base_url = url.split('#')[0];
|
||||
window.location = `${base_url}#/login`;
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import { LANGUAGE_KEY, REDUX_DEVTOOLS } from './constants';
|
||||
|
||||
import Login from './pages/Login';
|
||||
import Namespace from './pages/NameSpace';
|
||||
import Password from './pages/Password';
|
||||
import Newconfig from './pages/ConfigurationManagement/NewConfig';
|
||||
import Configsync from './pages/ConfigurationManagement/ConfigSync';
|
||||
import Configdetail from './pages/ConfigurationManagement/ConfigDetail';
|
||||
@ -74,6 +75,7 @@ const MENU = [
|
||||
{ path: '/', exact: true, render: () => <Redirect to="/welcome" /> },
|
||||
{ path: '/welcome', component: Welcome },
|
||||
{ path: '/namespace', component: Namespace },
|
||||
{ path: '/password', component: Password },
|
||||
{ path: '/newconfig', component: Newconfig },
|
||||
{ path: '/configsync', component: Configsync },
|
||||
{ path: '/configdetail', component: Configdetail },
|
||||
|
@ -49,6 +49,10 @@ class Header extends React.Component {
|
||||
this.props.history.push('/login');
|
||||
};
|
||||
|
||||
changePassword = () => {
|
||||
this.props.history.push('/password');
|
||||
};
|
||||
|
||||
getUsername = () => {
|
||||
const token = window.localStorage.getItem('token');
|
||||
if (token) {
|
||||
@ -94,6 +98,7 @@ class Header extends React.Component {
|
||||
<Dropdown trigger={<div className="logout">{this.getUsername()}</div>}>
|
||||
<Menu>
|
||||
<Menu.Item onClick={this.logout}>{locale.logout}</Menu.Item>
|
||||
<Menu.Item onClick={this.changePassword}>{locale.changePassword}</Menu.Item>
|
||||
</Menu>
|
||||
</Dropdown>
|
||||
)}
|
||||
|
@ -341,9 +341,6 @@ class MainLayout extends React.Component {
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.setState({
|
||||
noChild: !!nowNavObj.dontUseChild,
|
||||
});
|
||||
const { parentServiceName } = nowNavObj;
|
||||
|
||||
const parentNav = this.oneLevelNavArr[parentServiceName];
|
||||
@ -391,7 +388,11 @@ class MainLayout extends React.Component {
|
||||
refreshNav() {
|
||||
const { navList } = this.state;
|
||||
const { location, history, functionMode } = this.props;
|
||||
const [configUrl, serviceUrl, clusterUrl] = ['/configurationManagement', '/serviceManagement', '/clusterManagement'];
|
||||
const [configUrl, serviceUrl, clusterUrl] = [
|
||||
'/configurationManagement',
|
||||
'/serviceManagement',
|
||||
'/clusterManagement',
|
||||
];
|
||||
this.setState(
|
||||
{
|
||||
navList: navList.map(item => {
|
||||
|
@ -19,6 +19,7 @@ const I18N_CONF = {
|
||||
community: 'COMMUNITY',
|
||||
languageSwitchButton: '中',
|
||||
logout: 'logout',
|
||||
changePassword: 'modify password',
|
||||
passwordRequired: 'password should not be empty',
|
||||
usernameRequired: 'username should not be empty',
|
||||
},
|
||||
@ -50,6 +51,19 @@ const I18N_CONF = {
|
||||
clusterManagementVirtual: 'ClusterManagement',
|
||||
clusterManagement: 'Cluster Node List',
|
||||
},
|
||||
Password: {
|
||||
passwordNotConsistent: 'The passwords are not consistent',
|
||||
passwordRequired: 'password should not be empty',
|
||||
pleaseInputOldPassword: 'Please input original password',
|
||||
pleaseInputNewPassword: 'Please input new password',
|
||||
pleaseInputNewPasswordAgain: 'Please input new password again',
|
||||
oldPassword: 'Original password',
|
||||
newPassword: 'New password',
|
||||
checkPassword: 'Check password',
|
||||
changePassword: 'modify password',
|
||||
invalidPassword: 'Invalid original password',
|
||||
modifyPasswordFailed: 'Modify password failed',
|
||||
},
|
||||
NameSpace: {
|
||||
namespace: 'Namespaces',
|
||||
prompt: 'Notice',
|
||||
|
@ -19,6 +19,7 @@ const I18N_CONF = {
|
||||
community: '社区',
|
||||
languageSwitchButton: 'En',
|
||||
logout: '登出',
|
||||
changePassword: '修改密码',
|
||||
},
|
||||
Login: {
|
||||
login: '登录',
|
||||
@ -50,6 +51,19 @@ const I18N_CONF = {
|
||||
clusterManagementVirtual: '集群管理',
|
||||
clusterManagement: '节点列表',
|
||||
},
|
||||
Password: {
|
||||
passwordNotConsistent: '两次输入密码不一致',
|
||||
passwordRequired: '密码不能为空',
|
||||
pleaseInputOldPassword: '请输入原始密码',
|
||||
pleaseInputNewPassword: '请输入新密码',
|
||||
pleaseInputNewPasswordAgain: '请再次输入新密码',
|
||||
oldPassword: '原始密码',
|
||||
newPassword: '新密码',
|
||||
checkPassword: '再次输入',
|
||||
changePassword: '修改密码',
|
||||
invalidPassword: '原始密码错误',
|
||||
modifyPasswordFailed: '修改密码失败',
|
||||
},
|
||||
NameSpace: {
|
||||
namespace: '命名空间',
|
||||
prompt: '提示',
|
||||
|
@ -242,6 +242,22 @@ module.exports = {
|
||||
useRouter: false,
|
||||
id: 'namespace',
|
||||
},
|
||||
{
|
||||
enable: true,
|
||||
isExtend: false,
|
||||
name: '修改密码',
|
||||
title: '修改密码',
|
||||
isVirtual: false,
|
||||
projectName: 'nacos',
|
||||
serviceName: 'password',
|
||||
link: 'password',
|
||||
hasFusion: true,
|
||||
template: '',
|
||||
dontUseChild: true,
|
||||
registerName: 'com.alibaba.nacos.page.password',
|
||||
useRouter: false,
|
||||
id: 'password',
|
||||
},
|
||||
{
|
||||
enable: false,
|
||||
isExtend: true,
|
||||
|
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import RegionGroup from 'components/RegionGroup';
|
||||
import { ConfigProvider, Input, Field, Form, Message } from '@alifd/next';
|
||||
import { getParams, setParams, request } from '../../globalLib';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
const FormItem = Form.Item;
|
||||
|
||||
@ConfigProvider.config
|
||||
class Password extends React.Component {
|
||||
static displayName = 'Password';
|
||||
|
||||
static propTypes = {
|
||||
locale: PropTypes.object,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.field = new Field(this);
|
||||
this.state = {};
|
||||
}
|
||||
|
||||
componentDidMount() {}
|
||||
|
||||
validatePassword(rule, value, callback) {
|
||||
const { locale = {} } = this.props;
|
||||
if (this.field.getValue('newPassword') !== this.field.getValue('confirmNewPassword')) {
|
||||
callback(locale.passwordNotConsistent);
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
handleSubmit = () => {
|
||||
const { locale = {} } = this.props;
|
||||
this.field.validate((errors, values) => {
|
||||
if (errors) {
|
||||
return;
|
||||
}
|
||||
request({
|
||||
type: 'post',
|
||||
url: 'v1/auth/login',
|
||||
data: values,
|
||||
success: ({ code, data }) => {
|
||||
if (code === 200) {
|
||||
// TODO: 封装一个方法存储、读取token
|
||||
localStorage.setItem('token', data);
|
||||
// TODO: 使用react router
|
||||
this.props.history.push('/');
|
||||
}
|
||||
if (code === 401) {
|
||||
Message.error({
|
||||
content: locale.invalidUsernameOrPassword,
|
||||
});
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
Message.error({
|
||||
content: locale.invalidUsernameOrPassword,
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
changePassword() {
|
||||
const { locale = {} } = this.props;
|
||||
this.field.validate((errors, values) => {
|
||||
if (errors) {
|
||||
return;
|
||||
}
|
||||
request({
|
||||
type: 'put',
|
||||
url: 'v1/auth/password',
|
||||
data: values,
|
||||
success: ({ code, data }) => {
|
||||
if (code === 200) {
|
||||
window.localStorage.clear();
|
||||
this.props.history.push('/login');
|
||||
}
|
||||
if (code === 401) {
|
||||
Message.error({
|
||||
content: locale.invalidPassword,
|
||||
});
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
Message.error({
|
||||
content: locale.invalidPassword,
|
||||
});
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { locale = {} } = this.props;
|
||||
const formItemLayout = {
|
||||
labelCol: { fixedSpan: 6 },
|
||||
wrapperCol: { span: 18 },
|
||||
};
|
||||
return (
|
||||
<div style={{ padding: 10 }}>
|
||||
<RegionGroup left={locale.changePassword} />
|
||||
<Form style={{ width: '300px' }} field={this.field}>
|
||||
<FormItem label={locale.oldPassword} required {...formItemLayout}>
|
||||
<Input
|
||||
htmlType="password"
|
||||
placeholder={locale.pleaseInputOldPassword}
|
||||
{...this.field.init('oldPassword', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: locale.passwordRequired,
|
||||
},
|
||||
],
|
||||
})}
|
||||
disabled={this.state.type === 0}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label={locale.newPassword} required {...formItemLayout}>
|
||||
<Input
|
||||
htmlType="password"
|
||||
placeholder={locale.pleaseInputNewPassword}
|
||||
{...this.field.init('newPassword', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: locale.passwordRequired,
|
||||
},
|
||||
],
|
||||
})}
|
||||
disabled={this.state.type === 0}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label={locale.checkPassword} required {...formItemLayout}>
|
||||
<Input
|
||||
htmlType="password"
|
||||
placeholder={locale.pleaseInputNewPasswordAgain}
|
||||
{...this.field.init('confirmNewPassword', {
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: locale.passwordRequired,
|
||||
},
|
||||
{ validator: this.validatePassword.bind(this) },
|
||||
],
|
||||
})}
|
||||
disabled={this.state.type === 0}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem label=" " {...formItemLayout}>
|
||||
<Form.Submit type="primary" onClick={this.changePassword.bind(this)}>
|
||||
{locale.changePassword}
|
||||
</Form.Submit>
|
||||
</FormItem>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Password;
|
@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import Password from './Password';
|
||||
|
||||
export default Password;
|
@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 1999-2018 Alibaba Group Holding Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
Loading…
Reference in New Issue
Block a user