mirror of https://github.com/fantasticit/think.git
feat: improve update user, reset password
This commit is contained in:
parent
355b666704
commit
95400da337
|
@ -1,10 +1,11 @@
|
||||||
import { IconSpin } from '@douyinfe/semi-icons';
|
import { IconSpin } from '@douyinfe/semi-icons';
|
||||||
import { Avatar, Button, Dropdown, Typography } from '@douyinfe/semi-ui';
|
import { Avatar, Button, Dropdown, Modal, Toast, Typography } from '@douyinfe/semi-ui';
|
||||||
import { useUser } from 'data/user';
|
import { useUser } from 'data/user';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
import Router from 'next/router';
|
import Router from 'next/router';
|
||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
|
|
||||||
|
import { ResetPassword } from './reset-password';
|
||||||
import { UserSetting } from './setting';
|
import { UserSetting } from './setting';
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
@ -12,11 +13,17 @@ const { Text } = Typography;
|
||||||
export const User: React.FC = () => {
|
export const User: React.FC = () => {
|
||||||
const { user, loading, error, toLogin, logout } = useUser();
|
const { user, loading, error, toLogin, logout } = useUser();
|
||||||
const [visible, toggleVisible] = useToggle(false);
|
const [visible, toggleVisible] = useToggle(false);
|
||||||
|
const [resetVisible, toggleResetVisible] = useToggle(false);
|
||||||
|
|
||||||
const toAdmin = useCallback(() => {
|
const toAdmin = useCallback(() => {
|
||||||
Router.push('/admin');
|
Router.push('/admin');
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const onResetSuccess = useCallback(() => {
|
||||||
|
Toast.success('请重新登录');
|
||||||
|
Router.replace(`/login?redirect=${Router.asPath}`);
|
||||||
|
}, []);
|
||||||
|
|
||||||
if (loading) return <Button icon={<IconSpin />} theme="borderless" type="tertiary" />;
|
if (loading) return <Button icon={<IconSpin />} theme="borderless" type="tertiary" />;
|
||||||
|
|
||||||
if (error || !user) {
|
if (error || !user) {
|
||||||
|
@ -37,6 +44,9 @@ export const User: React.FC = () => {
|
||||||
<Dropdown.Item onClick={() => toggleVisible(true)}>
|
<Dropdown.Item onClick={() => toggleVisible(true)}>
|
||||||
<Text>账户设置</Text>
|
<Text>账户设置</Text>
|
||||||
</Dropdown.Item>
|
</Dropdown.Item>
|
||||||
|
<Dropdown.Item onClick={toggleResetVisible}>
|
||||||
|
<Text>重置密码</Text>
|
||||||
|
</Dropdown.Item>
|
||||||
{user.isSystemAdmin ? (
|
{user.isSystemAdmin ? (
|
||||||
<Dropdown.Item onClick={toAdmin}>
|
<Dropdown.Item onClick={toAdmin}>
|
||||||
<Text>管理后台</Text>
|
<Text>管理后台</Text>
|
||||||
|
@ -64,6 +74,9 @@ export const User: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
<UserSetting visible={visible} toggleVisible={toggleVisible} />
|
<UserSetting visible={visible} toggleVisible={toggleVisible} />
|
||||||
|
<Modal title="重置密码" visible={resetVisible} onCancel={toggleResetVisible} footer={null}>
|
||||||
|
<ResetPassword onSuccess={onResetSuccess} />
|
||||||
|
</Modal>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
import { Button, Col, Form, Row, Toast, Typography } from '@douyinfe/semi-ui';
|
||||||
|
import { useResetPassword, useVerifyCode } from 'data/user';
|
||||||
|
import { useInterval } from 'hooks/use-interval';
|
||||||
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
|
import React, { useCallback, useState } from 'react';
|
||||||
|
|
||||||
|
export const ResetPassword = ({ onSuccess }) => {
|
||||||
|
const [email, setEmail] = useState('');
|
||||||
|
const [hasSendVerifyCode, toggleHasSendVerifyCode] = useToggle(false);
|
||||||
|
const [countDown, setCountDown] = useState(0);
|
||||||
|
const { reset, loading } = useResetPassword();
|
||||||
|
const { sendVerifyCode, loading: sendVerifyCodeLoading } = useVerifyCode();
|
||||||
|
|
||||||
|
const onFormChange = useCallback((formState) => {
|
||||||
|
setEmail(formState.values.email);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const { start, stop } = useInterval(() => {
|
||||||
|
setCountDown((v) => {
|
||||||
|
if (v - 1 <= 0) {
|
||||||
|
stop();
|
||||||
|
toggleHasSendVerifyCode(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return v - 1;
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
const onFinish = useCallback(
|
||||||
|
(values) => {
|
||||||
|
reset(values).then((res) => {
|
||||||
|
onSuccess && onSuccess();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[reset, onSuccess]
|
||||||
|
);
|
||||||
|
|
||||||
|
const getVerifyCode = useCallback(() => {
|
||||||
|
stop();
|
||||||
|
sendVerifyCode({ email })
|
||||||
|
.then(() => {
|
||||||
|
Toast.success('请前往邮箱查收验证码');
|
||||||
|
setCountDown(60);
|
||||||
|
start();
|
||||||
|
toggleHasSendVerifyCode(true);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
toggleHasSendVerifyCode(false);
|
||||||
|
});
|
||||||
|
}, [email, toggleHasSendVerifyCode, sendVerifyCode, start, stop]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form initValues={{ name: '', password: '' }} onChange={onFormChange} onSubmit={onFinish}>
|
||||||
|
<Form.Input
|
||||||
|
noLabel
|
||||||
|
field="email"
|
||||||
|
placeholder={'请输入邮箱'}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
type: 'email',
|
||||||
|
message: '请输入正确的邮箱地址!',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: '请输入邮箱地址!',
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Row gutter={8} style={{ paddingTop: 12 }}>
|
||||||
|
<Col span={16}>
|
||||||
|
<Form.Input
|
||||||
|
noLabel
|
||||||
|
fieldStyle={{ paddingTop: 0 }}
|
||||||
|
placeholder={'请输入验证码'}
|
||||||
|
field="verifyCode"
|
||||||
|
rules={[{ required: true, message: '请输入邮箱收到的验证码!' }]}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={8}>
|
||||||
|
<Button disabled={!email || countDown > 0} loading={sendVerifyCodeLoading} onClick={getVerifyCode} block>
|
||||||
|
{hasSendVerifyCode ? countDown : '获取验证码'}
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
<Form.Input
|
||||||
|
noLabel
|
||||||
|
mode="password"
|
||||||
|
field="password"
|
||||||
|
label="密码"
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
placeholder="输入用户密码"
|
||||||
|
rules={[{ required: true, message: '请输入新密码' }]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Form.Input
|
||||||
|
noLabel
|
||||||
|
mode="password"
|
||||||
|
field="confirmPassword"
|
||||||
|
label="密码"
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
placeholder="确认用户密码"
|
||||||
|
rules={[{ required: true, message: '请再次输入密码' }]}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button htmlType="submit" type="primary" theme="solid" block loading={loading} style={{ margin: '16px 0' }}>
|
||||||
|
重置密码
|
||||||
|
</Button>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,8 +1,10 @@
|
||||||
import { Avatar, Form, Modal, Space } from '@douyinfe/semi-ui';
|
import { Avatar, Button, Col, Form, Modal, Row, Space, Toast } from '@douyinfe/semi-ui';
|
||||||
import { FormApi } from '@douyinfe/semi-ui/lib/es/form';
|
import { FormApi } from '@douyinfe/semi-ui/lib/es/form';
|
||||||
import { Upload } from 'components/upload';
|
import { Upload } from 'components/upload';
|
||||||
import { useUser } from 'data/user';
|
import { useUser, useVerifyCode } from 'data/user';
|
||||||
import { Dispatch, SetStateAction, useEffect, useRef, useState } from 'react';
|
import { useInterval } from 'hooks/use-interval';
|
||||||
|
import { useToggle } from 'hooks/use-toggle';
|
||||||
|
import { Dispatch, SetStateAction, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
|
@ -13,24 +15,60 @@ export const UserSetting: React.FC<IProps> = ({ visible, toggleVisible }) => {
|
||||||
const $form = useRef<FormApi>();
|
const $form = useRef<FormApi>();
|
||||||
const { user, loading, updateUser } = useUser();
|
const { user, loading, updateUser } = useUser();
|
||||||
const [currentAvatar, setCurrentAvatar] = useState('');
|
const [currentAvatar, setCurrentAvatar] = useState('');
|
||||||
|
const [email, setEmail] = useState('');
|
||||||
|
const { sendVerifyCode, loading: sendVerifyCodeLoading } = useVerifyCode();
|
||||||
|
const [hasSendVerifyCode, toggleHasSendVerifyCode] = useToggle(false);
|
||||||
|
const [countDown, setCountDown] = useState(0);
|
||||||
|
|
||||||
const setAvatar = (url) => {
|
const setAvatar = useCallback((url) => {
|
||||||
$form.current.setValue('avatar', url);
|
$form.current.setValue('avatar', url);
|
||||||
setCurrentAvatar(url);
|
setCurrentAvatar(url);
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
const handleOk = () => {
|
const handleOk = useCallback(() => {
|
||||||
$form.current.validate().then((values) => {
|
$form.current.validate().then((values) => {
|
||||||
if (!values.email) {
|
if (!values.email) {
|
||||||
delete values.email;
|
delete values.email;
|
||||||
}
|
}
|
||||||
updateUser(values);
|
updateUser(values).then(() => {
|
||||||
toggleVisible(false);
|
Toast.success('账户信息已更新');
|
||||||
|
toggleVisible(false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
}, [toggleVisible, updateUser]);
|
||||||
const handleCancel = () => {
|
|
||||||
|
const handleCancel = useCallback(() => {
|
||||||
toggleVisible(false);
|
toggleVisible(false);
|
||||||
};
|
}, [toggleVisible]);
|
||||||
|
|
||||||
|
const onFormChange = useCallback((formState) => {
|
||||||
|
setEmail(formState.values.email);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const { start, stop } = useInterval(() => {
|
||||||
|
setCountDown((v) => {
|
||||||
|
if (v - 1 <= 0) {
|
||||||
|
stop();
|
||||||
|
toggleHasSendVerifyCode(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return v - 1;
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
const getVerifyCode = useCallback(() => {
|
||||||
|
stop();
|
||||||
|
sendVerifyCode({ email })
|
||||||
|
.then(() => {
|
||||||
|
Toast.success('请前往邮箱查收验证码');
|
||||||
|
setCountDown(60);
|
||||||
|
start();
|
||||||
|
toggleHasSendVerifyCode(true);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
toggleHasSendVerifyCode(false);
|
||||||
|
});
|
||||||
|
}, [email, toggleHasSendVerifyCode, sendVerifyCode, start, stop]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!user || !$form.current) return;
|
if (!user || !$form.current) return;
|
||||||
|
@ -51,6 +89,7 @@ export const UserSetting: React.FC<IProps> = ({ visible, toggleVisible }) => {
|
||||||
initValues={{ avatar: user.avatar, name: user.name, email: user.email }}
|
initValues={{ avatar: user.avatar, name: user.name, email: user.email }}
|
||||||
getFormApi={(formApi) => ($form.current = formApi)}
|
getFormApi={(formApi) => ($form.current = formApi)}
|
||||||
labelPosition="left"
|
labelPosition="left"
|
||||||
|
onChange={onFormChange}
|
||||||
>
|
>
|
||||||
<Form.Slot label="头像">
|
<Form.Slot label="头像">
|
||||||
<Space align="end">
|
<Space align="end">
|
||||||
|
@ -58,6 +97,7 @@ export const UserSetting: React.FC<IProps> = ({ visible, toggleVisible }) => {
|
||||||
<Upload onOK={setAvatar} />
|
<Upload onOK={setAvatar} />
|
||||||
</Space>
|
</Space>
|
||||||
</Form.Slot>
|
</Form.Slot>
|
||||||
|
|
||||||
<Form.Input
|
<Form.Input
|
||||||
label="账户"
|
label="账户"
|
||||||
field="name"
|
field="name"
|
||||||
|
@ -65,13 +105,34 @@ export const UserSetting: React.FC<IProps> = ({ visible, toggleVisible }) => {
|
||||||
disabled
|
disabled
|
||||||
placeholder="请输入账户名称"
|
placeholder="请输入账户名称"
|
||||||
></Form.Input>
|
></Form.Input>
|
||||||
<Form.Input
|
|
||||||
disabled
|
<Form.Input label="邮箱" field="email" style={{ width: '100%' }} placeholder="请输入账户邮箱"></Form.Input>
|
||||||
label="邮箱"
|
|
||||||
field="email"
|
{email && email !== user.email ? (
|
||||||
style={{ width: '100%' }}
|
<Form.Slot label="验证码">
|
||||||
placeholder="请输入账户邮箱"
|
<Row gutter={8}>
|
||||||
></Form.Input>
|
<Col span={16}>
|
||||||
|
<Form.Input
|
||||||
|
noLabel
|
||||||
|
fieldStyle={{ paddingTop: 0 }}
|
||||||
|
placeholder={'请输入验证码'}
|
||||||
|
field="verifyCode"
|
||||||
|
rules={[{ required: true, message: '请输入邮箱收到的验证码!' }]}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col span={8}>
|
||||||
|
<Button
|
||||||
|
disabled={!email || countDown > 0}
|
||||||
|
loading={sendVerifyCodeLoading}
|
||||||
|
onClick={getVerifyCode}
|
||||||
|
block
|
||||||
|
>
|
||||||
|
{hasSendVerifyCode ? countDown : '获取验证码'}
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Form.Slot>
|
||||||
|
) : null}
|
||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import { Button, Col, Form, Layout, Modal, Row, Space, Toast, Typography } from '@douyinfe/semi-ui';
|
import { Layout, Modal, Space, Typography } from '@douyinfe/semi-ui';
|
||||||
import { Author } from 'components/author';
|
import { Author } from 'components/author';
|
||||||
import { LogoImage, LogoText } from 'components/logo';
|
import { LogoImage, LogoText } from 'components/logo';
|
||||||
import { Seo } from 'components/seo';
|
import { Seo } from 'components/seo';
|
||||||
import { useResetPassword, useVerifyCode } from 'data/user';
|
import { ResetPassword } from 'components/user/reset-password';
|
||||||
import { useInterval } from 'hooks/use-interval';
|
|
||||||
import { useRouterQuery } from 'hooks/use-router-query';
|
import { useRouterQuery } from 'hooks/use-router-query';
|
||||||
import { useToggle } from 'hooks/use-toggle';
|
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
import Router from 'next/router';
|
import Router from 'next/router';
|
||||||
import React, { useCallback, useState } from 'react';
|
import React, { useCallback, useState } from 'react';
|
||||||
|
@ -18,57 +16,17 @@ const { Title, Text } = Typography;
|
||||||
const Page = () => {
|
const Page = () => {
|
||||||
const query = useRouterQuery();
|
const query = useRouterQuery();
|
||||||
|
|
||||||
const [email, setEmail] = useState('');
|
const onResetSucccess = useCallback(() => {
|
||||||
const [hasSendVerifyCode, toggleHasSendVerifyCode] = useToggle(false);
|
Modal.confirm({
|
||||||
const [countDown, setCountDown] = useState(0);
|
title: <Title heading={5}>密码修改成功</Title>,
|
||||||
const { reset, loading } = useResetPassword();
|
content: <Text>是否跳转至登录?</Text>,
|
||||||
const { sendVerifyCode, loading: sendVerifyCodeLoading } = useVerifyCode();
|
okText: '确认',
|
||||||
|
cancelText: '取消',
|
||||||
const onFormChange = useCallback((formState) => {
|
onOk() {
|
||||||
setEmail(formState.values.email);
|
Router.push('/login', { query });
|
||||||
}, []);
|
},
|
||||||
|
|
||||||
const { start, stop } = useInterval(() => {
|
|
||||||
setCountDown((v) => {
|
|
||||||
if (v - 1 <= 0) {
|
|
||||||
stop();
|
|
||||||
toggleHasSendVerifyCode(false);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return v - 1;
|
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, [query]);
|
||||||
|
|
||||||
const onFinish = useCallback(
|
|
||||||
(values) => {
|
|
||||||
reset(values).then((res) => {
|
|
||||||
Modal.confirm({
|
|
||||||
title: <Title heading={5}>密码修改成功</Title>,
|
|
||||||
content: <Text>是否跳转至登录?</Text>,
|
|
||||||
okText: '确认',
|
|
||||||
cancelText: '取消',
|
|
||||||
onOk() {
|
|
||||||
Router.push('/login', { query });
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[reset, query]
|
|
||||||
);
|
|
||||||
|
|
||||||
const getVerifyCode = useCallback(() => {
|
|
||||||
stop();
|
|
||||||
sendVerifyCode({ email })
|
|
||||||
.then(() => {
|
|
||||||
Toast.success('请前往邮箱查收验证码');
|
|
||||||
setCountDown(60);
|
|
||||||
start();
|
|
||||||
toggleHasSendVerifyCode(true);
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
toggleHasSendVerifyCode(false);
|
|
||||||
});
|
|
||||||
}, [email, toggleHasSendVerifyCode, sendVerifyCode, start, stop]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout className={styles.wrap}>
|
<Layout className={styles.wrap}>
|
||||||
|
@ -80,72 +38,11 @@ const Page = () => {
|
||||||
<LogoText></LogoText>
|
<LogoText></LogoText>
|
||||||
</Space>
|
</Space>
|
||||||
</Title>
|
</Title>
|
||||||
<Form
|
<div className={styles.form}>
|
||||||
className={styles.form}
|
|
||||||
initValues={{ name: '', password: '' }}
|
|
||||||
onChange={onFormChange}
|
|
||||||
onSubmit={onFinish}
|
|
||||||
>
|
|
||||||
<Title type="tertiary" heading={5} style={{ marginBottom: 16, textAlign: 'center' }}>
|
<Title type="tertiary" heading={5} style={{ marginBottom: 16, textAlign: 'center' }}>
|
||||||
重置密码
|
重置密码
|
||||||
</Title>
|
</Title>
|
||||||
|
<ResetPassword onSuccess={onResetSucccess} />
|
||||||
<Form.Input
|
|
||||||
noLabel
|
|
||||||
field="email"
|
|
||||||
placeholder={'请输入邮箱'}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
type: 'email',
|
|
||||||
message: '请输入正确的邮箱地址!',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: '请输入邮箱地址!',
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Row gutter={8} style={{ paddingTop: 12 }}>
|
|
||||||
<Col span={16}>
|
|
||||||
<Form.Input
|
|
||||||
noLabel
|
|
||||||
fieldStyle={{ paddingTop: 0 }}
|
|
||||||
placeholder={'请输入验证码'}
|
|
||||||
field="verifyCode"
|
|
||||||
rules={[{ required: true, message: '请输入邮箱收到的验证码!' }]}
|
|
||||||
/>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
|
||||||
<Button disabled={!email || countDown > 0} loading={sendVerifyCodeLoading} onClick={getVerifyCode} block>
|
|
||||||
{hasSendVerifyCode ? countDown : '获取验证码'}
|
|
||||||
</Button>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
|
|
||||||
<Form.Input
|
|
||||||
noLabel
|
|
||||||
mode="password"
|
|
||||||
field="password"
|
|
||||||
label="密码"
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
placeholder="输入用户密码"
|
|
||||||
rules={[{ required: true, message: '请输入新密码' }]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Form.Input
|
|
||||||
noLabel
|
|
||||||
mode="password"
|
|
||||||
field="confirmPassword"
|
|
||||||
label="密码"
|
|
||||||
style={{ width: '100%' }}
|
|
||||||
placeholder="确认用户密码"
|
|
||||||
rules={[{ required: true, message: '请再次输入密码' }]}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Button htmlType="submit" type="primary" theme="solid" block loading={loading} style={{ margin: '16px 0' }}>
|
|
||||||
重置密码
|
|
||||||
</Button>
|
|
||||||
<footer>
|
<footer>
|
||||||
<Link
|
<Link
|
||||||
href={{
|
href={{
|
||||||
|
@ -158,7 +55,7 @@ const Page = () => {
|
||||||
</Text>
|
</Text>
|
||||||
</Link>
|
</Link>
|
||||||
</footer>
|
</footer>
|
||||||
</Form>
|
</div>
|
||||||
</Content>
|
</Content>
|
||||||
<Footer>
|
<Footer>
|
||||||
<Author></Author>
|
<Author></Author>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { IsEmail, IsOptional, IsString } from 'class-validator';
|
import { IsEmail, IsOptional, IsString, MinLength } from 'class-validator';
|
||||||
|
|
||||||
export class UpdateUserDto {
|
export class UpdateUserDto {
|
||||||
@IsString({ message: '用户头像类型错误(正确类型为:String)' })
|
@IsString({ message: '用户头像类型错误(正确类型为:String)' })
|
||||||
|
@ -9,4 +9,9 @@ export class UpdateUserDto {
|
||||||
@IsEmail()
|
@IsEmail()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
readonly email?: string;
|
readonly email?: string;
|
||||||
|
|
||||||
|
@MinLength(5, { message: '邮箱验证码至少5个字符' })
|
||||||
|
@IsString({ message: '邮箱验证码错误(正确类型为:String)' })
|
||||||
|
@IsOptional({ message: '邮箱验证码不能为空' })
|
||||||
|
verifyCode?: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ export class UserService {
|
||||||
throw new Error(`请指定名称、密码和邮箱`);
|
throw new Error(`请指定名称、密码和邮箱`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (await this.userRepo.findOne({ name: config.name })) {
|
if (await this.userRepo.findOne({ email: config.email })) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,6 +251,17 @@ export class UserService {
|
||||||
*/
|
*/
|
||||||
async updateUser(user: UserEntity, dto: UpdateUserDto): Promise<IUser> {
|
async updateUser(user: UserEntity, dto: UpdateUserDto): Promise<IUser> {
|
||||||
const oldData = await this.userRepo.findOne(user.id);
|
const oldData = await this.userRepo.findOne(user.id);
|
||||||
|
|
||||||
|
if (oldData.email !== dto.email) {
|
||||||
|
if (await this.userRepo.findOne({ where: { email: dto.email } })) {
|
||||||
|
throw new HttpException('该邮箱已被注册', HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(await this.verifyService.checkVerifyCode(dto.email, dto.verifyCode))) {
|
||||||
|
throw new HttpException('验证码不正确,请检查', HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const res = await this.userRepo.merge(oldData, dto);
|
const res = await this.userRepo.merge(oldData, dto);
|
||||||
const ret = await this.userRepo.save(res);
|
const ret = await this.userRepo.save(res);
|
||||||
return instanceToPlain(ret) as IUser;
|
return instanceToPlain(ret) as IUser;
|
||||||
|
|
|
@ -40,7 +40,7 @@ export class VerifyService {
|
||||||
await this.redis.set(`verify-${email}`, verifyCode, 'EX', 5 * 60);
|
await this.redis.set(`verify-${email}`, verifyCode, 'EX', 5 * 60);
|
||||||
await this.systemService.sendEmail({
|
await this.systemService.sendEmail({
|
||||||
to: email,
|
to: email,
|
||||||
subject: '验证码',
|
subject: '云策文档-验证码',
|
||||||
html: `<p>您的验证码为 ${verifyCode}</p>`,
|
html: `<p>您的验证码为 ${verifyCode}</p>`,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue