🎉 2.5.2.RELEASE 增加个人中心

This commit is contained in:
smallchill 2019-10-20 22:55:46 +08:00
parent 21e8a20f0a
commit 9acf4e2984
16 changed files with 319 additions and 151 deletions

View File

@ -52,18 +52,19 @@ export default [
},
{
path: '/account/settings',
component: './Account/Settings/Info',
//component: './Account/Settings/Info',
routes: [
{ path: '/account/settings', redirect: '/account/settings/base' },
{ path: '/account/settings/base', component: './Account/Settings/BaseView' },
{ path: '/account/settings/security', component: './Account/Settings/SecurityView' },
{ path: '/account/settings/binding', component: './Account/Settings/BindingView' },
{ path: '/account/settings/password', component: './Account/Settings/PasswordView' },
//{ path: '/account/settings/security', component: './Account/Settings/SecurityView' },
//{ path: '/account/settings/binding', component: './Account/Settings/BindingView' },
{
path: '/account/settings/notification',
component: './Account/Settings/NotificationView',
},
],
},
}
],
},
{

View File

@ -1,6 +1,6 @@
{
"name": "sword",
"version": "2.5.1",
"version": "2.5.2",
"description": "An out-of-box UI solution for enterprise applications",
"private": true,
"scripts": {

View File

@ -96,14 +96,14 @@ export default class GlobalHeaderRight extends PureComponent {
selectedKeys={[]}
onClick={onMenuClick}
>
<Menu.Item key="userCenter">
<Icon type="user" />
<FormattedMessage id="menu.account.center" defaultMessage="account center" />
</Menu.Item>
<Menu.Item key="userinfo">
<Icon type="setting" />
<FormattedMessage id="menu.account.settings" defaultMessage="account settings" />
</Menu.Item>
<Menu.Item key="password">
<Icon type="user" />
<FormattedMessage id="menu.account.password" defaultMessage="password settings" />
</Menu.Item>
<Menu.Divider />
<Menu.Item key="logout">
<Icon type="logout" />

View File

@ -52,10 +52,12 @@ export default class PageHeader extends PureComponent {
<div className={styles.detail}>
{logo && <div className={styles.logo}>{logo}</div>}
<div className={styles.main}>
<div className={styles.row}>
{title && <h1 className={styles.title}>{title}</h1>}
{action && <div className={styles.action}>{action}</div>}
</div>
{title && (
<div className={styles.row}>
<h1 className={styles.title}>{title}</h1>
{action && <div className={styles.action}>{action}</div>}
</div>
)}
<div className={styles.row}>
{content && <div className={styles.content}>{content}</div>}
{extraContent && <div className={styles.extraContent}>{extraContent}</div>}

View File

@ -62,8 +62,11 @@ class HeaderView extends React.Component {
return;
}
if (key === 'userinfo') {
message.success('即将开放');
// router.push('/account/settings/base');
router.push('/account/settings/base');
return;
}
if (key === 'password') {
router.push('/account/settings/password');
return;
}
if (key === 'triggerError') {

View File

@ -35,6 +35,7 @@ export default {
'menu.exception.trigger': 'Trigger',
'menu.account': 'Account',
'menu.account.center': 'Account Center',
'menu.account.password': 'Modify Password',
'menu.account.settings': 'Account Settings',
'menu.account.trigger': 'Trigger Error',
'menu.account.logout': 'Logout',

View File

@ -9,6 +9,8 @@ export default {
'app.settings.basic.email-message': 'Please input your email!',
'app.settings.basic.nickname': 'Nickname',
'app.settings.basic.nickname-message': 'Please input your Nickname!',
'app.settings.basic.realname': 'Realname',
'app.settings.basic.realname-message': 'Please input your Realname!',
'app.settings.basic.profile': 'Personal profile',
'app.settings.basic.profile-message': 'Please input your personal profile!',
'app.settings.basic.profile-placeholder': 'Brief introduction to yourself',
@ -21,6 +23,12 @@ export default {
'app.settings.basic.phone': 'Phone Number',
'app.settings.basic.phone-message': 'Please input your phone!',
'app.settings.basic.update': 'Update Information',
'app.settings.password.old': 'Old Password',
'app.settings.password.old-message': 'Please input your Old Password!',
'app.settings.password.new': 'New Password',
'app.settings.password.new-message': 'Please input your new Password!',
'app.settings.password.new1': 'New Password1',
'app.settings.password.new1-message': 'Please comfirm your new Password!',
'app.settings.security.strong': 'Strong',
'app.settings.security.medium': 'Medium',
'app.settings.security.weak': 'Weak',

View File

@ -35,6 +35,7 @@ export default {
'menu.exception.trigger': '触发错误',
'menu.account': '个人页',
'menu.account.center': '个人中心',
'menu.account.password': '密码修改',
'menu.account.settings': '个人设置',
'menu.account.trigger': '触发报错',
'menu.account.logout': '退出登录',

View File

@ -9,6 +9,8 @@ export default {
'app.settings.basic.email-message': '请输入您的邮箱!',
'app.settings.basic.nickname': '昵称',
'app.settings.basic.nickname-message': '请输入您的昵称!',
'app.settings.basic.realname': '姓名',
'app.settings.basic.realname-message': '请输入您的姓名!',
'app.settings.basic.profile': '个人简介',
'app.settings.basic.profile-message': '请输入个人简介!',
'app.settings.basic.profile-placeholder': '个人简介',
@ -21,6 +23,12 @@ export default {
'app.settings.basic.phone': '联系电话',
'app.settings.basic.phone-message': '请输入您的联系电话!',
'app.settings.basic.update': '更新基本信息',
'app.settings.password.old': '旧密码',
'app.settings.password.old-message': '请输入你的旧密码!',
'app.settings.password.new': '新密码',
'app.settings.password.new-message': '请输入你的新密码!',
'app.settings.password.new1': '确认密码',
'app.settings.password.new1-message': '请输入你的确认密码!',
'app.settings.security.strong': '强',
'app.settings.security.medium': '中',
'app.settings.security.weak': '弱',

View File

@ -35,6 +35,7 @@ export default {
'menu.exception.trigger': '觸發錯誤',
'menu.account': '個人頁',
'menu.account.center': '個人中心',
'menu.account.password': '密碼修改',
'menu.account.settings': '個人設置',
'menu.account.trigger': '觸發報錯',
'menu.account.logout': '退出登錄',

View File

@ -9,6 +9,8 @@ export default {
'app.settings.basic.email-message': '請輸入您的郵箱!',
'app.settings.basic.nickname': '昵稱',
'app.settings.basic.nickname-message': '請輸入您的昵稱!',
'app.settings.basic.realname': '姓名',
'app.settings.basic.realname-message': '請輸入您的姓名!',
'app.settings.basic.profile': '個人簡介',
'app.settings.basic.profile-message': '請輸入個人簡介!',
'app.settings.basic.profile-placeholder': '個人簡介',
@ -21,6 +23,12 @@ export default {
'app.settings.basic.phone': '聯系電話',
'app.settings.basic.phone-message': '請輸入您的聯系電話!',
'app.settings.basic.update': '更新基本信息',
'app.settings.password.old': '舊密碼',
'app.settings.password.old-message': '請輸入妳的舊密碼!',
'app.settings.password.new': '新密碼',
'app.settings.password.new-message': '請輸入妳的新密碼!',
'app.settings.password.new1': '確認密碼',
'app.settings.password.new1-message': '請輸入妳的確認密碼!',
'app.settings.security.strong': '強',
'app.settings.security.medium': '中',
'app.settings.security.weak': '弱',

View File

@ -1,106 +1,161 @@
import React, { Component, Fragment } from 'react';
import { formatMessage, FormattedMessage } from 'umi/locale';
import { Form, Input, Upload, Select, Button } from 'antd';
import { connect } from 'dva';
import styles from './BaseView.less';
import GeographicView from './GeographicView';
import PhoneView from './PhoneView';
// import { getTimeDistance } from '@/utils/utils';
import React, { Component } from 'react';
import { formatMessage } from 'umi/locale';
import { Form, Input, Upload, Button, message, Icon, Card } from 'antd';
import Panel from '../../../components/Panel';
import { getUserInfo, update } from '../../../services/user';
import { getToken } from '../../../utils/authority';
const FormItem = Form.Item;
const { Option } = Select;
// 头像组件 方便以后独立,增加裁剪之类的功能
const AvatarView = ({ avatar }) => (
<Fragment>
<div className={styles.avatar_title}>
<FormattedMessage id="app.settings.basic.avatar" defaultMessage="Avatar" />
</div>
<div className={styles.avatar}>
<img src={avatar} alt="avatar" />
</div>
<Upload fileList={[]}>
<div className={styles.button_view}>
<Button icon="upload">
<FormattedMessage id="app.settings.basic.change-avatar" defaultMessage="Change avatar" />
</Button>
</div>
</Upload>
</Fragment>
);
const validatorGeographic = (rule, value, callback) => {
const { province, city } = value;
if (!province.key) {
callback('Please input your province!');
}
if (!city.key) {
callback('Please input your city!');
}
callback();
};
const validatorPhone = (rule, value, callback) => {
const values = value.split('-');
if (!values[0]) {
callback('Please input your area code!');
}
if (!values[1]) {
callback('Please input your phone number!');
}
callback();
};
@connect(({ user }) => ({
currentUser: user.currentUser,
}))
@Form.create()
class BaseView extends Component {
state = {
userId: '',
avatar: '',
loading: false,
};
componentDidMount() {
this.setBaseInfo();
}
setBaseInfo = () => {
const { currentUser, form } = this.props;
Object.keys(form.getFieldsValue()).forEach(key => {
const obj = {};
obj[key] = currentUser[key] || null;
form.setFieldsValue(obj);
const { form } = this.props;
getUserInfo().then(resp => {
if (resp.success) {
const userInfo = resp.data;
Object.keys(form.getFieldsValue()).forEach(key => {
const obj = {};
obj[key] = userInfo[key] || null;
form.setFieldsValue(obj);
});
this.setState({ userId: userInfo.id, avatar: userInfo.avatar });
} else {
message.error(resp.msg || '获取数据失败');
}
});
};
getAvatarURL() {
const { currentUser } = this.props;
if (currentUser.avatar) {
return currentUser.avatar;
beforeUpload = file => {
const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
if (!isJpgOrPng) {
message.error('You can only upload JPG/PNG file!');
}
const url = 'https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png';
return url;
}
const isLt2M = file.size / 1024 / 1024 < 2;
if (!isLt2M) {
message.error('Image must smaller than 2MB!');
}
return isJpgOrPng && isLt2M;
};
getViewDom = ref => {
this.view = ref;
handleChange = info => {
if (info.file.status === 'uploading') {
this.setState({ loading: true });
return;
}
if (info.file.status === 'done') {
this.setState({ loading: false, avatar: info.file.response.data.link });
}
};
handleSubmit = e => {
e.preventDefault();
const { form } = this.props;
const { userId, avatar } = this.state;
form.validateFieldsAndScroll((err, values) => {
if (!err) {
const params = {
id: userId,
...values,
avatar,
};
update(params).then(resp => {
if (resp.success) {
message.success(resp.msg);
} else {
message.error(resp.msg || '提交失败');
}
});
}
});
};
render() {
const {
form: { getFieldDecorator },
} = this.props;
const { avatar, loading } = this.state;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 7 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 12 },
md: { span: 10 },
},
};
const uploadProp = {
action: '/api/blade-resource/oss/endpoint/put-file',
headers: {
'Blade-Auth': getToken(),
},
};
const uploadButton = (
<div>
<Icon type={loading ? 'loading' : 'plus'} />
<div className="ant-upload-text">上传头像</div>
</div>
);
const action = (
<Button type="primary" onClick={this.handleSubmit}>
提交
</Button>
);
return (
<div className={styles.baseView} ref={this.getViewDom}>
<div className={styles.left}>
<Form layout="vertical" onSubmit={this.handleSubmit} hideRequiredMark>
<FormItem label={formatMessage({ id: 'app.settings.basic.email' })}>
{getFieldDecorator('email', {
<Panel title="个人设置" back="/" action={action}>
<Form style={{ marginTop: 8 }} hideRequiredMark>
<Card title="基本信息" bordered={false}>
<FormItem
{...formItemLayout}
label={formatMessage({ id: 'app.settings.basic.avatar' })}
>
{getFieldDecorator('avatar', {
rules: [
{
required: true,
message: formatMessage({ id: 'app.settings.basic.email-message' }, {}),
message: formatMessage({ id: 'app.settings.basic.avatar' }, {}),
},
],
})(<Input />)}
})(
<Upload
name="file"
listType="picture-card"
className="avatar-uploader"
showUploadList={false}
beforeUpload={this.beforeUpload}
onChange={this.handleChange}
{...uploadProp}
>
{avatar ? (
<img src={avatar} alt="avatar" style={{ width: '100%' }} />
) : (
uploadButton
)}
</Upload>
)}
</FormItem>
<FormItem label={formatMessage({ id: 'app.settings.basic.nickname' })}>
<FormItem
{...formItemLayout}
label={formatMessage({ id: 'app.settings.basic.nickname' })}
>
{getFieldDecorator('name', {
rules: [
{
@ -110,81 +165,42 @@ class BaseView extends Component {
],
})(<Input />)}
</FormItem>
<FormItem label={formatMessage({ id: 'app.settings.basic.profile' })}>
{getFieldDecorator('profile', {
<FormItem
{...formItemLayout}
label={formatMessage({ id: 'app.settings.basic.realname' })}
>
{getFieldDecorator('realName', {
rules: [
{
required: true,
message: formatMessage({ id: 'app.settings.basic.profile-message' }, {}),
},
],
})(
<Input.TextArea
placeholder={formatMessage({ id: 'app.settings.basic.profile-placeholder' })}
rows={4}
/>
)}
</FormItem>
<FormItem label={formatMessage({ id: 'app.settings.basic.country' })}>
{getFieldDecorator('country', {
rules: [
{
required: true,
message: formatMessage({ id: 'app.settings.basic.country-message' }, {}),
},
],
})(
<Select style={{ maxWidth: 220 }}>
<Option value="China">中国</Option>
</Select>
)}
</FormItem>
<FormItem label={formatMessage({ id: 'app.settings.basic.geographic' })}>
{getFieldDecorator('geographic', {
rules: [
{
required: true,
message: formatMessage({ id: 'app.settings.basic.geographic-message' }, {}),
},
{
validator: validatorGeographic,
},
],
})(<GeographicView />)}
</FormItem>
<FormItem label={formatMessage({ id: 'app.settings.basic.address' })}>
{getFieldDecorator('address', {
rules: [
{
required: true,
message: formatMessage({ id: 'app.settings.basic.address-message' }, {}),
message: formatMessage({ id: 'app.settings.basic.realname-message' }, {}),
},
],
})(<Input />)}
</FormItem>
<FormItem label={formatMessage({ id: 'app.settings.basic.phone' })}>
<FormItem {...formItemLayout} label={formatMessage({ id: 'app.settings.basic.phone' })}>
{getFieldDecorator('phone', {
rules: [
{
required: true,
message: formatMessage({ id: 'app.settings.basic.phone-message' }, {}),
},
{ validator: validatorPhone },
],
})(<PhoneView />)}
})(<Input />)}
</FormItem>
<Button type="primary">
<FormattedMessage
id="app.settings.basic.update"
defaultMessage="Update Information"
/>
</Button>
</Form>
</div>
<div className={styles.right}>
<AvatarView avatar={this.getAvatarURL()} />
</div>
</div>
<FormItem {...formItemLayout} label={formatMessage({ id: 'app.settings.basic.email' })}>
{getFieldDecorator('email', {
rules: [
{
required: true,
message: formatMessage({ id: 'app.settings.basic.email-message' }, {}),
},
],
})(<Input />)}
</FormItem>
</Card>
</Form>
</Panel>
);
}
}

View File

@ -0,0 +1,98 @@
import React, { Component } from 'react';
import { formatMessage } from 'umi/locale';
import { Form, Input, Button, Card, message } from 'antd';
import Panel from '../../../components/Panel';
import { updatePassword } from '../../../services/user';
const FormItem = Form.Item;
@Form.create()
class PasswordView extends Component {
handleSubmit = e => {
e.preventDefault();
const { form } = this.props;
form.validateFieldsAndScroll((err, values) => {
if (!err) {
updatePassword(values).then(resp => {
if (resp.success) {
message.success(resp.msg);
}
});
}
});
};
render() {
const {
form: { getFieldDecorator },
} = this.props;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 7 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 12 },
md: { span: 10 },
},
};
const action = (
<Button type="primary" onClick={this.handleSubmit}>
提交
</Button>
);
return (
<Panel title="密码修改" back="/" action={action}>
<Form style={{ marginTop: 8 }} hideRequiredMark>
<Card title="基本信息" bordered={false}>
<FormItem
{...formItemLayout}
label={formatMessage({ id: 'app.settings.password.old' })}
>
{getFieldDecorator('oldPassword', {
rules: [
{
required: true,
message: formatMessage({ id: 'app.settings.password.old-message' }, {}),
},
],
})(<Input type="password" />)}
</FormItem>
<FormItem
{...formItemLayout}
label={formatMessage({ id: 'app.settings.password.new' })}
>
{getFieldDecorator('newPassword', {
rules: [
{
required: true,
message: formatMessage({ id: 'app.settings.password.new-message' }, {}),
},
],
})(<Input type="password" />)}
</FormItem>
<FormItem
{...formItemLayout}
label={formatMessage({ id: 'app.settings.password.new1' })}
>
{getFieldDecorator('newPassword1', {
rules: [
{
required: true,
message: formatMessage({ id: 'app.settings.password.new1-message' }, {}),
},
],
})(<Input type="password" />)}
</FormItem>
</Card>
</Form>
</Panel>
);
}
}
export default PasswordView;

View File

@ -103,7 +103,14 @@ class Workplace extends PureComponent {
</Collapse>
</Col>
<Col span={8}>
<Collapse bordered={false} defaultActiveKey={['10']}>
<Collapse bordered={false} defaultActiveKey={['11']}>
<Panel header="2.5.2发布 增加个人中心" key="11">
<div>1.增加个人中心支持用户信息自定义修改</div>
<div>2.增加网关鉴权配置示例</div>
<div>3.token的SIGN_KEY修改为一致</div>
<div>4.admin模块增加对seata服务的过滤</div>
<div>5.blade-tool增加部分工具类方法</div>
</Panel>
<Panel header="2.5.1发布 增加网关动态鉴权" key="10">
<div>1.增加网关动态鉴权</div>
<div>2.secure安全模块token校验默认关闭交由网关处理</div>

View File

@ -122,6 +122,7 @@ class LoginPage extends Component {
{tenantMode ? (
<TenantId
name="tenantId"
defaultValue="000000"
placeholder={`${formatMessage({ id: 'app.login.tenantId' })}: 000000`}
rules={[
{
@ -133,6 +134,7 @@ class LoginPage extends Component {
) : null}
<UserName
name="account"
defaultValue="admin"
placeholder={`${formatMessage({ id: 'app.login.userName' })}: admin`}
rules={[
{
@ -143,6 +145,7 @@ class LoginPage extends Component {
/>
<Password
name="password"
defaultValue="admin"
placeholder={`${formatMessage({ id: 'app.login.password' })}: admin`}
rules={[
{

View File

@ -61,3 +61,14 @@ export async function update(params) {
export async function detail(params) {
return request(`/api/blade-user/detail?${stringify(params)}`);
}
export async function getUserInfo() {
return request('/api/blade-user/info');
}
export async function updatePassword(params) {
return request('/api/blade-user/update-password', {
method: 'POST',
body: func.toFormData(params),
});
}