feat: support change password

This commit is contained in:
wfnuser 2019-07-28 15:20:29 +08:00
parent c5aec4c227
commit 486ef1e6f2
10 changed files with 266 additions and 4 deletions

View File

@ -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`;
}

View File

@ -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 },

View File

@ -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>
)}

View File

@ -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 => {

View File

@ -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',

View File

@ -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: '提示',

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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.
*/