| @@ -37,8 +37,7 @@ export async function getInitialState(): Promise<GlobalInitialState> { | |||||
| ...response.user, | ...response.user, | ||||
| avatar: response.user.avatar || require('@/assets/img/avatar-default.png'), | avatar: response.user.avatar || require('@/assets/img/avatar-default.png'), | ||||
| permissions: response.permissions, | permissions: response.permissions, | ||||
| roles: response.roles, | |||||
| roleNames: response.user.roles, | |||||
| roleNames: response.roles, | |||||
| } as API.CurrentUser; | } as API.CurrentUser; | ||||
| } catch (error) { | } catch (error) { | ||||
| console.error('getInitialState', error); | console.error('getInitialState', error); | ||||
| @@ -1,4 +1,5 @@ | |||||
| import { clearSessionToken } from '@/access'; | import { clearSessionToken } from '@/access'; | ||||
| import DefaultAvatar from '@/assets/img/avatar-default.png'; | |||||
| import { getLabelStudioUrl } from '@/services/developmentEnvironment'; | import { getLabelStudioUrl } from '@/services/developmentEnvironment'; | ||||
| import { setRemoteMenu } from '@/services/session'; | import { setRemoteMenu } from '@/services/session'; | ||||
| import { logout } from '@/services/system/auth'; | import { logout } from '@/services/system/auth'; | ||||
| @@ -56,7 +57,14 @@ const AvatarLogo = () => { | |||||
| }, | }, | ||||
| }; | }; | ||||
| }); | }); | ||||
| return <Avatar size="small" className={avatarClassName} src={currentUser?.avatar} alt="avatar" />; | |||||
| return ( | |||||
| <Avatar | |||||
| size="small" | |||||
| className={avatarClassName} | |||||
| src={currentUser?.avatar || DefaultAvatar} | |||||
| alt="avatar" | |||||
| /> | |||||
| ); | |||||
| }; | }; | ||||
| const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => { | const AvatarDropdown: React.FC<GlobalHeaderRightProps> = ({ menu }) => { | ||||
| @@ -1,91 +1,107 @@ | |||||
| import KFModal from '@/components/KFModal'; | |||||
| import { updateUserProfile } from '@/services/system/user'; | import { updateUserProfile } from '@/services/system/user'; | ||||
| import { ProForm, ProFormRadio, ProFormText } from '@ant-design/pro-components'; | |||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | |||||
| import { Form, message, Row } from 'antd'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { Form, Input, message, Radio } from 'antd'; | |||||
| import React from 'react'; | import React from 'react'; | ||||
| export type BaseInfoProps = { | export type BaseInfoProps = { | ||||
| values: Partial<API.CurrentUser> | undefined; | |||||
| values: Partial<API.CurrentUser>; | |||||
| open: boolean; | |||||
| onFinished?: (isSuccess: boolean) => void; | |||||
| }; | }; | ||||
| const BaseInfo: React.FC<BaseInfoProps> = (props) => { | |||||
| const BaseInfo: React.FC<BaseInfoProps> = ({ open, onFinished, values: initialValues }) => { | |||||
| const [form] = Form.useForm(); | const [form] = Form.useForm(); | ||||
| const intl = useIntl(); | |||||
| const handleFinish = async (values: Record<string, any>) => { | |||||
| const data = { ...props.values, ...values } as API.CurrentUser; | |||||
| const resp = await updateUserProfile(data); | |||||
| if (resp.code === 200) { | |||||
| const handleFinish = async (formData: Record<string, any>) => { | |||||
| const data = { userId: initialValues.userId, ...formData } as API.CurrentUser; | |||||
| const [res] = await to(updateUserProfile(data)); | |||||
| if (res) { | |||||
| message.success('修改成功'); | message.success('修改成功'); | ||||
| } else { | |||||
| message.warning(resp.msg); | |||||
| onFinished?.(true); | |||||
| } | } | ||||
| }; | }; | ||||
| return ( | return ( | ||||
| <> | |||||
| <ProForm form={form} onFinish={handleFinish} initialValues={props.values}> | |||||
| <Row> | |||||
| <ProFormText | |||||
| name="nickName" | |||||
| label={intl.formatMessage({ | |||||
| id: 'system.user.nick_name', | |||||
| defaultMessage: '用户昵称', | |||||
| })} | |||||
| width="xl" | |||||
| placeholder="请输入用户昵称" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: ( | |||||
| <FormattedMessage id="请输入用户昵称!" defaultMessage="请输入用户昵称!" /> | |||||
| ), | |||||
| }, | |||||
| ]} | |||||
| /> | |||||
| </Row> | |||||
| <Row> | |||||
| <ProFormText | |||||
| name="phonenumber" | |||||
| label={intl.formatMessage({ | |||||
| id: 'system.user.phonenumber', | |||||
| defaultMessage: '手机号码', | |||||
| })} | |||||
| width="xl" | |||||
| placeholder="请输入手机号码" | |||||
| rules={[ | |||||
| { | |||||
| required: false, | |||||
| message: ( | |||||
| <FormattedMessage id="请输入手机号码!" defaultMessage="请输入手机号码!" /> | |||||
| ), | |||||
| }, | |||||
| ]} | |||||
| /> | |||||
| </Row> | |||||
| <Row> | |||||
| <ProFormText | |||||
| name="email" | |||||
| label={intl.formatMessage({ | |||||
| id: 'system.user.email', | |||||
| defaultMessage: '邮箱', | |||||
| })} | |||||
| width="xl" | |||||
| placeholder="请输入邮箱" | |||||
| rules={[ | |||||
| { | |||||
| type: 'email', | |||||
| message: '无效的邮箱地址!', | |||||
| }, | |||||
| { | |||||
| required: false, | |||||
| message: <FormattedMessage id="请输入邮箱!" defaultMessage="请输入邮箱!" />, | |||||
| }, | |||||
| ]} | |||||
| /> | |||||
| </Row> | |||||
| <Row> | |||||
| <ProFormRadio.Group | |||||
| <KFModal | |||||
| width={800} | |||||
| title="修改基本信息" | |||||
| open={open} | |||||
| okButtonProps={{ | |||||
| htmlType: 'submit', | |||||
| form: 'basic-info-form', | |||||
| }} | |||||
| onCancel={() => onFinished?.(false)} | |||||
| destroyOnClose | |||||
| > | |||||
| <Form | |||||
| name="basic-info-form" | |||||
| form={form} | |||||
| layout="vertical" | |||||
| size="large" | |||||
| autoComplete="off" | |||||
| scrollToFirstError | |||||
| initialValues={initialValues} | |||||
| onFinish={handleFinish} | |||||
| > | |||||
| <Form.Item | |||||
| name="nickName" | |||||
| label="用户昵称" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入用户昵称', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input placeholder="请输入用户昵称" allowClear></Input> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| name="phonenumber" | |||||
| label="手机号码" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入手机号码', | |||||
| }, | |||||
| { | |||||
| pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/, | |||||
| message: '请输入正确的手机号码', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input placeholder="请输入手机号码" allowClear></Input> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| name="email" | |||||
| label="邮箱" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: '请输入邮箱', | |||||
| }, | |||||
| { | |||||
| type: 'email', | |||||
| message: '请输入正确的邮箱地址', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Input placeholder="请输入邮箱" allowClear></Input> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| name="sex" | |||||
| label="性别" | |||||
| rules={[ | |||||
| { | |||||
| required: false, | |||||
| message: '请选择性别', | |||||
| }, | |||||
| ]} | |||||
| > | |||||
| <Radio.Group | |||||
| options={[ | options={[ | ||||
| { | { | ||||
| label: '男', | label: '男', | ||||
| @@ -96,22 +112,10 @@ const BaseInfo: React.FC<BaseInfoProps> = (props) => { | |||||
| value: '1', | value: '1', | ||||
| }, | }, | ||||
| ]} | ]} | ||||
| name="sex" | |||||
| label={intl.formatMessage({ | |||||
| id: 'system.user.sex', | |||||
| defaultMessage: 'sex', | |||||
| })} | |||||
| width="xl" | |||||
| rules={[ | |||||
| { | |||||
| required: false, | |||||
| message: <FormattedMessage id="请输入性别!" defaultMessage="请输入性别!" />, | |||||
| }, | |||||
| ]} | |||||
| /> | /> | ||||
| </Row> | |||||
| </ProForm> | |||||
| </> | |||||
| </Form.Item> | |||||
| </Form> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -1,81 +1,89 @@ | |||||
| import KFModal from '@/components/KFModal'; | |||||
| import { updateUserPwd } from '@/services/system/user'; | import { updateUserPwd } from '@/services/system/user'; | ||||
| import { ProForm, ProFormText } from '@ant-design/pro-components'; | |||||
| import { FormattedMessage, useIntl } from '@umijs/max'; | |||||
| import { Form, message } from 'antd'; | |||||
| import React from 'react'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { Form, Input, message } from 'antd'; | |||||
| const ResetPassword: React.FC = () => { | |||||
| export type ResetPasswordProps = { | |||||
| open: boolean; | |||||
| onFinished?: (isSuccess: boolean) => void; | |||||
| }; | |||||
| const ResetPassword = ({ open, onFinished }: ResetPasswordProps) => { | |||||
| const [form] = Form.useForm(); | const [form] = Form.useForm(); | ||||
| const intl = useIntl(); | |||||
| const handleFinish = async (values: Record<string, any>) => { | const handleFinish = async (values: Record<string, any>) => { | ||||
| const resp = await updateUserPwd(values.oldPassword, values.newPassword); | |||||
| if (resp.code === 200) { | |||||
| message.success('密码重置成功。'); | |||||
| } else { | |||||
| message.warning(resp.msg); | |||||
| const [res] = await to(updateUserPwd(values.oldPassword, values.newPassword)); | |||||
| if (res) { | |||||
| message.success('密码重置成功'); | |||||
| onFinished?.(true); | |||||
| } | } | ||||
| }; | }; | ||||
| const checkPassword = (_rule: any, value: string) => { | const checkPassword = (_rule: any, value: string) => { | ||||
| const login_password = form.getFieldValue('newPassword'); | const login_password = form.getFieldValue('newPassword'); | ||||
| if (value === login_password) { | |||||
| return Promise.resolve(); | |||||
| if (!value) { | |||||
| return Promise.reject(new Error('请输入确认密码')); | |||||
| } else if (value !== login_password) { | |||||
| return Promise.reject(new Error('两次密码输入不一致')); | |||||
| } | } | ||||
| return Promise.reject(new Error('两次密码输入不一致')); | |||||
| return Promise.resolve(); | |||||
| }; | }; | ||||
| return ( | return ( | ||||
| <> | |||||
| <ProForm form={form} onFinish={handleFinish}> | |||||
| <ProFormText.Password | |||||
| <KFModal | |||||
| width={800} | |||||
| title="重置密码" | |||||
| open={open} | |||||
| okButtonProps={{ | |||||
| htmlType: 'submit', | |||||
| form: 'reset-pwd-form', | |||||
| }} | |||||
| onCancel={() => onFinished?.(false)} | |||||
| destroyOnClose | |||||
| > | |||||
| <Form | |||||
| form={form} | |||||
| name="reset-pwd-form" | |||||
| layout="vertical" | |||||
| size="large" | |||||
| autoComplete="off" | |||||
| scrollToFirstError | |||||
| onFinish={handleFinish} | |||||
| > | |||||
| <Form.Item | |||||
| name="oldPassword" | name="oldPassword" | ||||
| label={intl.formatMessage({ | |||||
| id: 'system.user.old_password', | |||||
| defaultMessage: '旧密码', | |||||
| })} | |||||
| width="xl" | |||||
| placeholder="请输入旧密码" | |||||
| label="旧密码" | |||||
| rules={[ | rules={[ | ||||
| { | { | ||||
| required: true, | required: true, | ||||
| message: <FormattedMessage id="请输入旧密码!" defaultMessage="请输入旧密码!" />, | |||||
| message: '请输入旧密码', | |||||
| }, | }, | ||||
| ]} | ]} | ||||
| /> | |||||
| <ProFormText.Password | |||||
| > | |||||
| <Input.Password placeholder="请输入旧密码" allowClear></Input.Password> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| name="newPassword" | name="newPassword" | ||||
| label={intl.formatMessage({ | |||||
| id: 'system.user.new_password', | |||||
| defaultMessage: '新密码', | |||||
| })} | |||||
| width="xl" | |||||
| placeholder="请输入新密码" | |||||
| label="新密码" | |||||
| rules={[ | rules={[ | ||||
| { | { | ||||
| required: true, | required: true, | ||||
| message: <FormattedMessage id="请输入新密码!" defaultMessage="请输入新密码!" />, | |||||
| message: '请输入新密码', | |||||
| }, | }, | ||||
| ]} | ]} | ||||
| /> | |||||
| <ProFormText.Password | |||||
| > | |||||
| <Input.Password placeholder="请输入新密码" allowClear></Input.Password> | |||||
| </Form.Item> | |||||
| <Form.Item | |||||
| name="confirmPassword" | name="confirmPassword" | ||||
| label={intl.formatMessage({ | |||||
| id: 'system.user.confirm_password', | |||||
| defaultMessage: '确认密码', | |||||
| })} | |||||
| width="xl" | |||||
| placeholder="请输入确认密码" | |||||
| rules={[ | |||||
| { | |||||
| required: true, | |||||
| message: <FormattedMessage id="请输入确认密码!" defaultMessage="请输入确认密码!" />, | |||||
| }, | |||||
| { validator: checkPassword }, | |||||
| ]} | |||||
| /> | |||||
| </ProForm> | |||||
| </> | |||||
| label="确认密码" | |||||
| required | |||||
| rules={[{ validator: checkPassword }]} | |||||
| > | |||||
| <Input.Password placeholder="请输入确认密码" allowClear></Input.Password> | |||||
| </Form.Item> | |||||
| </Form> | |||||
| </KFModal> | |||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -2,7 +2,7 @@ | |||||
| position: relative; | position: relative; | ||||
| display: inline-block; | display: inline-block; | ||||
| height: 120px; | height: 120px; | ||||
| margin-bottom: 16px; | |||||
| margin-bottom: 30px; | |||||
| text-align: center; | text-align: center; | ||||
| & > img { | & > img { | ||||
| @@ -30,31 +30,34 @@ | |||||
| } | } | ||||
| } | } | ||||
| .teamTitle { | |||||
| margin-bottom: 12px; | |||||
| color: @heading-color; | |||||
| font-weight: 500; | |||||
| } | |||||
| .user-center { | |||||
| height: calc(100% - 50px - 120px); | |||||
| padding: 30px; | |||||
| background: white; | |||||
| border-radius: 8px; | |||||
| width: 50%; | |||||
| margin: 60px auto 0; | |||||
| display: flex; | |||||
| flex-direction: column; | |||||
| align-items: center; | |||||
| overflow-y: auto; | |||||
| .team { | |||||
| :global { | :global { | ||||
| .ant-avatar { | |||||
| margin-right: 12px; | |||||
| .ant-list { | |||||
| width: 100%; | |||||
| .ant-list-item { | |||||
| height: 80px; | |||||
| border-block-end: 1px solid rgba(5, 5, 5, 0.06); | |||||
| font-size: 16px; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| a { | |||||
| display: block; | |||||
| margin-bottom: 24px; | |||||
| overflow: hidden; | |||||
| color: @text-color; | |||||
| white-space: nowrap; | |||||
| text-overflow: ellipsis; | |||||
| word-break: break-all; | |||||
| transition: color 0.3s; | |||||
| &:hover { | |||||
| color: @primary-color; | |||||
| } | |||||
| &__buttons { | |||||
| display: flex; | |||||
| align-items: center; | |||||
| margin-top: 60px; | |||||
| flex-direction: row; | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,6 +1,9 @@ | |||||
| import { getUserInfo } from '@/services/session'; | |||||
| import DefaultAvatar from '@/assets/img/avatar-default.png'; | |||||
| import PageTitle from '@/components/PageTitle'; | |||||
| import { to } from '@/utils/promise'; | |||||
| import { | import { | ||||
| ClusterOutlined, | ClusterOutlined, | ||||
| HeartOutlined, | |||||
| MailOutlined, | MailOutlined, | ||||
| ManOutlined, | ManOutlined, | ||||
| MobileOutlined, | MobileOutlined, | ||||
| @@ -8,45 +11,52 @@ import { | |||||
| UserOutlined, | UserOutlined, | ||||
| } from '@ant-design/icons'; | } from '@ant-design/icons'; | ||||
| import { PageLoading } from '@ant-design/pro-components'; | import { PageLoading } from '@ant-design/pro-components'; | ||||
| import { useRequest } from '@umijs/max'; | |||||
| import { Card, Col, Divider, List, Row } from 'antd'; | |||||
| import React, { useState } from 'react'; | |||||
| import styles from './Center.less'; | |||||
| import { useModel } from '@umijs/max'; | |||||
| import { List } from 'antd'; | |||||
| import { useCallback, useState } from 'react'; | |||||
| import { flushSync } from 'react-dom'; | |||||
| import AvatarCropper from './components/AvatarCropper'; | import AvatarCropper from './components/AvatarCropper'; | ||||
| import BaseInfo from './components/BaseInfo'; | |||||
| import ResetPassword from './components/ResetPassword'; | |||||
| import BaseInfoModal from './components/BaseInfo'; | |||||
| import ResetPasswordModal from './components/ResetPassword'; | |||||
| import styles from './index.less'; | |||||
| const operationTabList = [ | |||||
| { | |||||
| key: 'base', | |||||
| tab: <span>基本资料</span>, | |||||
| }, | |||||
| { | |||||
| key: 'password', | |||||
| tab: <span>重置密码</span>, | |||||
| }, | |||||
| ]; | |||||
| const Center = () => { | |||||
| const [cropperModalOpen, setCropperModalOpen] = useState<boolean>(false); | |||||
| const [infoModalOpen, setInfoModalOpen] = useState<boolean>(false); | |||||
| const [resetModalOpen, setRestModalOpen] = useState<boolean>(false); | |||||
| export type tabKeyType = 'base' | 'password'; | |||||
| const { initialState, setInitialState } = useModel('@@initialState'); | |||||
| const { currentUser, fetchUserInfo } = initialState || {}; | |||||
| const Center: React.FC = () => { | |||||
| const [tabKey, setTabKey] = useState<tabKeyType>('base'); | |||||
| const refreshUserInfo = useCallback(async () => { | |||||
| if (fetchUserInfo) { | |||||
| const [res] = await to(fetchUserInfo()); | |||||
| if (res) { | |||||
| flushSync(() => { | |||||
| setInitialState((s) => ({ ...s, currentUser: res })); | |||||
| }); | |||||
| } | |||||
| } | |||||
| }, [setInitialState, fetchUserInfo]); | |||||
| const [cropperModalOpen, setCropperModalOpen] = useState<boolean>(false); | |||||
| const handleBaseInfoChange = (success: boolean) => { | |||||
| setInfoModalOpen(false); | |||||
| // 获取用户信息 | |||||
| const { data: userInfo, loading } = useRequest(async () => { | |||||
| return { data: await getUserInfo() }; | |||||
| }); | |||||
| if (loading) { | |||||
| return <div>loading...</div>; | |||||
| } | |||||
| if (success) { | |||||
| refreshUserInfo(); | |||||
| } | |||||
| }; | |||||
| const currentUser = userInfo?.user; | |||||
| const handleResetPassword = (success: boolean) => { | |||||
| setRestModalOpen(false); | |||||
| if (success) { | |||||
| } | |||||
| }; | |||||
| // 渲染用户信息 | // 渲染用户信息 | ||||
| const renderUserInfo = ({ | const renderUserInfo = ({ | ||||
| userName, | userName, | ||||
| nickName, | |||||
| phonenumber, | phonenumber, | ||||
| email, | email, | ||||
| sex, | sex, | ||||
| @@ -65,6 +75,17 @@ const Center: React.FC = () => { | |||||
| </div> | </div> | ||||
| <div>{userName}</div> | <div>{userName}</div> | ||||
| </List.Item> | </List.Item> | ||||
| <List.Item> | |||||
| <div> | |||||
| <HeartOutlined | |||||
| style={{ | |||||
| marginRight: 8, | |||||
| }} | |||||
| /> | |||||
| 昵称 | |||||
| </div> | |||||
| <div>{nickName}</div> | |||||
| </List.Item> | |||||
| <List.Item> | <List.Item> | ||||
| <div> | <div> | ||||
| <ManOutlined | <ManOutlined | ||||
| @@ -109,75 +130,53 @@ const Center: React.FC = () => { | |||||
| </div> | </div> | ||||
| <div>{dept?.deptName}</div> | <div>{dept?.deptName}</div> | ||||
| </List.Item> | </List.Item> | ||||
| <List.Item> | |||||
| <div> | |||||
| <TeamOutlined | |||||
| style={{ | |||||
| marginRight: 8, | |||||
| }} | |||||
| /> | |||||
| 角色 | |||||
| </div> | |||||
| <div>{currentUser?.roles?.map((item: any) => item.roleName)?.join(',')}</div> | |||||
| </List.Item> | |||||
| </List> | </List> | ||||
| ); | ); | ||||
| }; | }; | ||||
| // 渲染tab切换 | |||||
| const renderChildrenByTabKey = (tabValue: tabKeyType) => { | |||||
| if (tabValue === 'base') { | |||||
| return <BaseInfo values={currentUser} />; | |||||
| } | |||||
| if (tabValue === 'password') { | |||||
| return <ResetPassword />; | |||||
| } | |||||
| return null; | |||||
| }; | |||||
| if (!currentUser) { | if (!currentUser) { | ||||
| return <PageLoading />; | return <PageLoading />; | ||||
| } | } | ||||
| return ( | return ( | ||||
| <div> | |||||
| <Row gutter={[16, 24]}> | |||||
| <Col lg={8} md={24}> | |||||
| <Card title="个人信息" bordered={false} loading={loading}> | |||||
| {!loading && ( | |||||
| <div style={{ textAlign: 'center' }}> | |||||
| <div | |||||
| className={styles.avatarHolder} | |||||
| onClick={() => { | |||||
| setCropperModalOpen(true); | |||||
| }} | |||||
| > | |||||
| <img src={currentUser.avatar} draggable={false} alt="" /> | |||||
| </div> | |||||
| {renderUserInfo(currentUser)} | |||||
| <Divider dashed /> | |||||
| <div className={styles.team}> | |||||
| <div className={styles.teamTitle}>角色</div> | |||||
| <Row gutter={36}> | |||||
| {currentUser.roles && | |||||
| currentUser.roles.map((item: any) => ( | |||||
| <Col key={item.roleId} lg={24} xl={12}> | |||||
| <TeamOutlined | |||||
| style={{ | |||||
| marginRight: 8, | |||||
| }} | |||||
| /> | |||||
| {item.roleName} | |||||
| </Col> | |||||
| ))} | |||||
| </Row> | |||||
| </div> | |||||
| </div> | |||||
| )} | |||||
| </Card> | |||||
| </Col> | |||||
| <Col lg={16} md={24}> | |||||
| <Card | |||||
| bordered={false} | |||||
| tabList={operationTabList} | |||||
| activeTabKey={tabKey} | |||||
| onTabChange={(_tabKey: string) => { | |||||
| setTabKey(_tabKey as tabKeyType); | |||||
| }} | |||||
| <div style={{ height: '100%' }}> | |||||
| <PageTitle title="个人中心"></PageTitle> | |||||
| <div className={styles['user-center']}> | |||||
| <div | |||||
| className={styles.avatarHolder} | |||||
| onClick={() => { | |||||
| setCropperModalOpen(true); | |||||
| }} | |||||
| > | |||||
| <img src={currentUser.avatar || DefaultAvatar} draggable={false} alt="" /> | |||||
| </div> | |||||
| {renderUserInfo(currentUser)} | |||||
| {/* <div className={styles['user-center__buttons']}> | |||||
| <Button | |||||
| type="primary" | |||||
| size="large" | |||||
| style={{ marginRight: 50 }} | |||||
| onClick={() => setInfoModalOpen(true)} | |||||
| > | > | ||||
| {renderChildrenByTabKey(tabKey)} | |||||
| </Card> | |||||
| </Col> | |||||
| </Row> | |||||
| 修改基本信息 | |||||
| </Button> | |||||
| <Button type="primary" size="large" onClick={() => setRestModalOpen(true)}> | |||||
| 重置密码 | |||||
| </Button> | |||||
| </div> */} | |||||
| </div> | |||||
| <AvatarCropper | <AvatarCropper | ||||
| onFinished={() => { | onFinished={() => { | ||||
| setCropperModalOpen(false); | setCropperModalOpen(false); | ||||
| @@ -185,6 +184,17 @@ const Center: React.FC = () => { | |||||
| open={cropperModalOpen} | open={cropperModalOpen} | ||||
| data={currentUser.avatar} | data={currentUser.avatar} | ||||
| /> | /> | ||||
| <BaseInfoModal | |||||
| open={infoModalOpen} | |||||
| values={currentUser} | |||||
| onFinished={handleBaseInfoChange} | |||||
| ></BaseInfoModal> | |||||
| <ResetPasswordModal | |||||
| open={resetModalOpen} | |||||
| onFinished={handleResetPassword} | |||||
| ></ResetPasswordModal> | |||||
| </div> | </div> | ||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -31,7 +31,7 @@ function UserSpace({ users = [] }: UserSpaceProps) { | |||||
| } | } | ||||
| ></Avatar> | ></Avatar> | ||||
| <div className={styles['user-space__name']}>{currentUser?.nickName}</div> | <div className={styles['user-space__name']}>{currentUser?.nickName}</div> | ||||
| <div className={styles['user-space__role']}>{currentUser?.roleNames?.[0]?.roleName}</div> | |||||
| <div className={styles['user-space__role']}>{currentUser?.roles?.[0]?.roleName}</div> | |||||
| <Divider | <Divider | ||||
| dashed | dashed | ||||
| style={{ borderColor: 'rgba(22, 100, 255, 0.19)', margin: '20px 0' }} | style={{ borderColor: 'rgba(22, 100, 255, 0.19)', margin: '20px 0' }} | ||||