密码重置页
This commit is contained in:
parent
bd0332a582
commit
3aef983325
@ -3,6 +3,7 @@ import { type AxiosResponse } from 'axios'
|
|||||||
import {
|
import {
|
||||||
LoginInputDto,
|
LoginInputDto,
|
||||||
RegisterInputDto,
|
RegisterInputDto,
|
||||||
|
ForgetPasswordInputDto,
|
||||||
Token,
|
Token,
|
||||||
TokenRefreshPayload,
|
TokenRefreshPayload,
|
||||||
User,
|
User,
|
||||||
@ -16,6 +17,10 @@ export async function login(data: LoginInputDto) {
|
|||||||
return axios.post<Token>('/api/users/token', data)
|
return axios.post<Token>('/api/users/token', data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function forgetPassword(data: ForgetPasswordInputDto) {
|
||||||
|
return axios.patch<Token>('/api/users/password', data)
|
||||||
|
}
|
||||||
|
|
||||||
let refreshing: Promise<AxiosResponse<Token>> | null
|
let refreshing: Promise<AxiosResponse<Token>> | null
|
||||||
export async function refreshToken(data: TokenRefreshPayload) {
|
export async function refreshToken(data: TokenRefreshPayload) {
|
||||||
if (!refreshing) {
|
if (!refreshing) {
|
||||||
|
@ -12,6 +12,12 @@ export interface RegisterInputDto extends EmailVerifyDto {
|
|||||||
username?: string
|
username?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 重置密码入参 */
|
||||||
|
export interface ForgetPasswordInputDto extends EmailVerifyDto {
|
||||||
|
userId: string
|
||||||
|
password: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface Token {
|
export interface Token {
|
||||||
accessToken: string
|
accessToken: string
|
||||||
refreshToken: string
|
refreshToken: string
|
||||||
|
149
src/pages/forget-password.tsx
Normal file
149
src/pages/forget-password.tsx
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
import Avatar from '@mui/material/Avatar'
|
||||||
|
import Button from '@mui/material/Button'
|
||||||
|
import TextField from '@mui/material/TextField'
|
||||||
|
import Link from '@mui/material/Link'
|
||||||
|
import Grid from '@mui/material/Unstable_Grid2'
|
||||||
|
import Box from '@mui/material/Box'
|
||||||
|
import KeyIcon from '@mui/icons-material/Key'
|
||||||
|
import Typography from '@mui/material/Typography'
|
||||||
|
import Container from '@mui/material/Container'
|
||||||
|
import { useFormik } from 'formik'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import * as yup from '@/utils/validation'
|
||||||
|
import * as api from '@/api'
|
||||||
|
import { ForgetPasswordInputDto } from '@/api/user.interface'
|
||||||
|
import { EmailVerifyCodeScene } from '@/api/email.interface'
|
||||||
|
import { useCountdown, COUNTDOWN_SECONDS } from '@/utils/useCountdown'
|
||||||
|
import { toast } from 'react-toastify'
|
||||||
|
|
||||||
|
export default function ForgetPassword() {
|
||||||
|
const router = useRouter()
|
||||||
|
const { countdown, setCountdown } = useCountdown()
|
||||||
|
|
||||||
|
const formik = useFormik<ForgetPasswordInputDto>({
|
||||||
|
initialValues: {
|
||||||
|
email: '',
|
||||||
|
password: '',
|
||||||
|
verifyCode: '',
|
||||||
|
token: '',
|
||||||
|
userId: '',
|
||||||
|
},
|
||||||
|
validateOnChange: false,
|
||||||
|
validationSchema: yup.object({
|
||||||
|
email: yup.emailSchema,
|
||||||
|
password: yup.passwordSchema,
|
||||||
|
verifyCode: yup.verifyCodeSchema,
|
||||||
|
}),
|
||||||
|
onSubmit: async (values) => {
|
||||||
|
const res = await api.user.forgetPassword(values)
|
||||||
|
localStorage.setItem('accessToken', res.data.accessToken)
|
||||||
|
localStorage.setItem('refreshToken', res.data.refreshToken)
|
||||||
|
toast.success('密码重置成功!', {
|
||||||
|
onClose: () => router.push('/login'),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
async function sendVerifyCode() {
|
||||||
|
await formik.validateField('email')
|
||||||
|
if (formik.errors.email) return
|
||||||
|
setCountdown(COUNTDOWN_SECONDS)
|
||||||
|
try {
|
||||||
|
const res = await api.email.sendEmailVerifyCode({
|
||||||
|
email: formik.values.email,
|
||||||
|
scene: EmailVerifyCodeScene.forgetPassword,
|
||||||
|
})
|
||||||
|
formik.setFieldValue('token', res.data.token)
|
||||||
|
formik.setFieldValue('userId', res.data.userId)
|
||||||
|
} catch (err) {
|
||||||
|
setCountdown(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container component="main" sx={{ width: 400 }}>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
marginTop: '20vh',
|
||||||
|
display: 'flex',
|
||||||
|
flexDirection: 'column',
|
||||||
|
alignItems: 'center',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Avatar sx={{ m: 1, bgcolor: 'primary.main' }}>
|
||||||
|
<KeyIcon />
|
||||||
|
</Avatar>
|
||||||
|
<Typography component="h1" variant="h5">
|
||||||
|
找回密码
|
||||||
|
</Typography>
|
||||||
|
<Box
|
||||||
|
component="form"
|
||||||
|
onSubmit={formik.handleSubmit}
|
||||||
|
noValidate
|
||||||
|
sx={{ mt: 1, width: '100%' }}
|
||||||
|
>
|
||||||
|
<TextField
|
||||||
|
{...formik.getFieldProps('email')}
|
||||||
|
required
|
||||||
|
error={formik.touched.email && !!formik.errors.email}
|
||||||
|
helperText={(formik.touched.email && formik.errors.email) || ' '}
|
||||||
|
fullWidth
|
||||||
|
label="邮箱"
|
||||||
|
autoComplete="email"
|
||||||
|
autoFocus
|
||||||
|
sx={{ mt: 1 }}
|
||||||
|
/>
|
||||||
|
<Grid container spacing={2}>
|
||||||
|
<Grid>
|
||||||
|
<TextField
|
||||||
|
{...formik.getFieldProps('verifyCode')}
|
||||||
|
required
|
||||||
|
error={formik.touched.verifyCode && !!formik.errors.verifyCode}
|
||||||
|
helperText={
|
||||||
|
(formik.touched.verifyCode && formik.errors.verifyCode) || ' '
|
||||||
|
}
|
||||||
|
fullWidth
|
||||||
|
label="验证码"
|
||||||
|
autoComplete="verifyCode"
|
||||||
|
autoFocus
|
||||||
|
sx={{ mt: 1 }}
|
||||||
|
/>
|
||||||
|
</Grid>
|
||||||
|
<Grid mt={2} sx={{ flexGrow: 1 }}>
|
||||||
|
<Button
|
||||||
|
size="large"
|
||||||
|
fullWidth
|
||||||
|
variant="contained"
|
||||||
|
disabled={countdown > 0}
|
||||||
|
onClick={sendVerifyCode}
|
||||||
|
>
|
||||||
|
{countdown > 0 ? countdown : '发送验证码'}
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
<TextField
|
||||||
|
{...formik.getFieldProps('password')}
|
||||||
|
required
|
||||||
|
error={formik.touched.password && !!formik.errors.password}
|
||||||
|
helperText={
|
||||||
|
(formik.touched.password && formik.errors.password) || ' '
|
||||||
|
}
|
||||||
|
fullWidth
|
||||||
|
label="新密码"
|
||||||
|
type="password"
|
||||||
|
autoComplete="current-password"
|
||||||
|
sx={{ mt: 1 }}
|
||||||
|
/>
|
||||||
|
<Button type="submit" fullWidth variant="contained" sx={{ mt: 1 }}>
|
||||||
|
重置密码
|
||||||
|
</Button>
|
||||||
|
<Grid container justifyContent="flex-end" sx={{ mt: 2 }}>
|
||||||
|
<Grid>
|
||||||
|
<Link href="/login">登录</Link>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Box>
|
||||||
|
</Box>
|
||||||
|
</Container>
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user