Complete main UI #37
@@ -30,6 +30,7 @@ export const SYSTEM_TIMEOUT = 10051
|
|||||||
export const SYSTEM_REQUEST_ILLEGAL = 10052
|
export const SYSTEM_REQUEST_ILLEGAL = 10052
|
||||||
export const SYSTEM_ARGUMENT_NOT_VALID = 10053
|
export const SYSTEM_ARGUMENT_NOT_VALID = 10053
|
||||||
export const SYSTEM_INVALID_CAPTCHA_CODE = 10054
|
export const SYSTEM_INVALID_CAPTCHA_CODE = 10054
|
||||||
|
export const SYSTEM_REQUEST_TOO_FREQUENT = 10055
|
||||||
|
|
||||||
export const PERMISSION_LOGIN_SUCCESS = 20000
|
export const PERMISSION_LOGIN_SUCCESS = 20000
|
||||||
export const PERMISSION_PASSWORD_CHANGE_SUCCESS = 20001
|
export const PERMISSION_PASSWORD_CHANGE_SUCCESS = 20001
|
||||||
|
|||||||
3
src/global.d.ts
vendored
3
src/global.d.ts
vendored
@@ -62,6 +62,7 @@ interface RegisterParam {
|
|||||||
username: string
|
username: string
|
||||||
email: string
|
email: string
|
||||||
password: string
|
password: string
|
||||||
|
captchaCode: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface VerifyParam {
|
interface VerifyParam {
|
||||||
@@ -72,11 +73,13 @@ interface VerifyParam {
|
|||||||
|
|
||||||
interface ForgetParam {
|
interface ForgetParam {
|
||||||
email: string
|
email: string
|
||||||
|
captchaCode: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface RetrieveParam {
|
interface RetrieveParam {
|
||||||
code: string
|
code: string
|
||||||
password: string
|
password: string
|
||||||
|
captchaCode: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LoginParam {
|
interface LoginParam {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState } from 'react'
|
import React, { useState } from 'react'
|
||||||
import { useNavigate } from 'react-router'
|
import { useNavigate } from 'react-router'
|
||||||
import Icon from '@ant-design/icons'
|
import Icon from '@ant-design/icons'
|
||||||
import { Turnstile } from '@marsidev/react-turnstile'
|
import { Turnstile, TurnstileInstance } from '@marsidev/react-turnstile'
|
||||||
import '@/assets/css/pages/sign.scss'
|
import '@/assets/css/pages/sign.scss'
|
||||||
import {
|
import {
|
||||||
COLOR_BACKGROUND,
|
COLOR_BACKGROUND,
|
||||||
@@ -41,9 +41,11 @@ import { r_api_avatar_random_base64 } from '@/services/api/avatar.tsx'
|
|||||||
const SignUp: React.FC = () => {
|
const SignUp: React.FC = () => {
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
const turnstileRef = useRef<TurnstileInstance>()
|
||||||
const [isSigningUp, setIsSigningUp] = useState(false)
|
const [isSigningUp, setIsSigningUp] = useState(false)
|
||||||
const [isFinish, setIsFinish] = useState(false)
|
const [isFinish, setIsFinish] = useState(false)
|
||||||
const [isSending, setIsSending] = useState(false)
|
const [isSending, setIsSending] = useState(false)
|
||||||
|
const [captchaCode, setCaptchaCode] = useState('')
|
||||||
|
|
||||||
useUpdatedEffect(() => {
|
useUpdatedEffect(() => {
|
||||||
if (location.pathname !== '/register') {
|
if (location.pathname !== '/register') {
|
||||||
@@ -54,6 +56,9 @@ const SignUp: React.FC = () => {
|
|||||||
replace: true
|
replace: true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
turnstileRef.current?.execute()
|
||||||
|
}, 200)
|
||||||
}, [location.pathname])
|
}, [location.pathname])
|
||||||
|
|
||||||
const handleOnFinish = (registerParam: RegisterParam) => {
|
const handleOnFinish = (registerParam: RegisterParam) => {
|
||||||
@@ -61,10 +66,18 @@ const SignUp: React.FC = () => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
setIsSigningUp(true)
|
setIsSigningUp(true)
|
||||||
|
|
||||||
|
if (!captchaCode) {
|
||||||
|
void message.warning('请先通过验证')
|
||||||
|
setIsSigningUp(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
void r_auth_register({
|
void r_auth_register({
|
||||||
username: registerParam.username,
|
username: registerParam.username,
|
||||||
email: registerParam.email,
|
email: registerParam.email,
|
||||||
password: registerParam.password
|
password: registerParam.password,
|
||||||
|
captchaCode
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const response = res.data
|
const response = res.data
|
||||||
@@ -78,6 +91,9 @@ const SignUp: React.FC = () => {
|
|||||||
void message.error('用户名或邮箱已被注册,请重试')
|
void message.error('用户名或邮箱已被注册,请重试')
|
||||||
setIsSigningUp(false)
|
setIsSigningUp(false)
|
||||||
break
|
break
|
||||||
|
case SYSTEM_INVALID_CAPTCHA_CODE:
|
||||||
|
void message.error('验证码有误,请刷新重试')
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
void message.error('服务器出错了,请稍后重试')
|
void message.error('服务器出错了,请稍后重试')
|
||||||
setIsSigningUp(false)
|
setIsSigningUp(false)
|
||||||
@@ -97,7 +113,6 @@ const SignUp: React.FC = () => {
|
|||||||
void r_auth_resend()
|
void r_auth_resend()
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const response = res.data
|
const response = res.data
|
||||||
message.destroy('sending')
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
void message.success('已发送验证邮件,请查收')
|
void message.success('已发送验证邮件,请查收')
|
||||||
} else {
|
} else {
|
||||||
@@ -105,6 +120,7 @@ const SignUp: React.FC = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
message.destroy('sending')
|
||||||
setIsSending(false)
|
setIsSending(false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -189,6 +205,15 @@ const SignUp: React.FC = () => {
|
|||||||
disabled={isSigningUp}
|
disabled={isSigningUp}
|
||||||
/>
|
/>
|
||||||
</AntdForm.Item>
|
</AntdForm.Item>
|
||||||
|
<AntdForm.Item>
|
||||||
|
<Turnstile
|
||||||
|
id={'sign-up-turnstile'}
|
||||||
|
ref={turnstileRef}
|
||||||
|
siteKey={H_CAPTCHA_SITE_KEY}
|
||||||
|
options={{ theme: 'light', execution: 'execute' }}
|
||||||
|
onSuccess={setCaptchaCode}
|
||||||
|
/>
|
||||||
|
</AntdForm.Item>
|
||||||
<AntdForm.Item>
|
<AntdForm.Item>
|
||||||
<AntdButton
|
<AntdButton
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
@@ -286,7 +311,6 @@ const Verify: React.FC = () => {
|
|||||||
void r_auth_resend()
|
void r_auth_resend()
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
const response = res.data
|
const response = res.data
|
||||||
message.destroy('sending')
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
void message.success('已发送验证邮件,请查收')
|
void message.success('已发送验证邮件,请查收')
|
||||||
} else {
|
} else {
|
||||||
@@ -294,6 +318,7 @@ const Verify: React.FC = () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
message.destroy('sending')
|
||||||
setIsSending(false)
|
setIsSending(false)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -435,10 +460,28 @@ const Verify: React.FC = () => {
|
|||||||
const Forget: React.FC = () => {
|
const Forget: React.FC = () => {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const [searchParams] = useSearchParams()
|
const [searchParams] = useSearchParams()
|
||||||
|
const turnstileRef = useRef<TurnstileInstance>()
|
||||||
|
const retrieveTurnstileRef = useRef<TurnstileInstance>()
|
||||||
const [isSending, setIsSending] = useState(false)
|
const [isSending, setIsSending] = useState(false)
|
||||||
const [isSent, setIsSent] = useState(false)
|
const [isSent, setIsSent] = useState(false)
|
||||||
const [isChanging, setIsChanging] = useState(false)
|
const [isChanging, setIsChanging] = useState(false)
|
||||||
const [isChanged, setIsChanged] = useState(false)
|
const [isChanged, setIsChanged] = useState(false)
|
||||||
|
const [captchaCode, setCaptchaCode] = useState('')
|
||||||
|
const [retrieveCpatchaCode, setRetrieveCpatchaCode] = useState('')
|
||||||
|
|
||||||
|
useUpdatedEffect(() => {
|
||||||
|
if (location.pathname !== '/forget') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!searchParams.get('code')) {
|
||||||
|
turnstileRef.current?.execute()
|
||||||
|
} else {
|
||||||
|
retrieveTurnstileRef.current?.execute()
|
||||||
|
}
|
||||||
|
}, 200)
|
||||||
|
}, [location.pathname])
|
||||||
|
|
||||||
const handleOnSend = (forgetParam: ForgetParam) => {
|
const handleOnSend = (forgetParam: ForgetParam) => {
|
||||||
if (isSending) {
|
if (isSending) {
|
||||||
@@ -446,28 +489,40 @@ const Forget: React.FC = () => {
|
|||||||
}
|
}
|
||||||
setIsSending(true)
|
setIsSending(true)
|
||||||
|
|
||||||
void r_auth_forget(forgetParam)
|
if (!captchaCode) {
|
||||||
.then((res) => {
|
void message.warning('请先通过验证')
|
||||||
const response = res.data
|
setIsSending(false)
|
||||||
switch (response.code) {
|
return
|
||||||
case PERMISSION_FORGET_SUCCESS:
|
}
|
||||||
void message.success('已发送验证邮件,请查收')
|
|
||||||
setIsSent(true)
|
void r_auth_forget({ email: forgetParam.email, captchaCode }).then((res) => {
|
||||||
break
|
const response = res.data
|
||||||
case PERMISSION_USER_NOT_FOUND:
|
switch (response.code) {
|
||||||
void message.error('用户不存在')
|
case PERMISSION_FORGET_SUCCESS:
|
||||||
break
|
void message.success('已发送验证邮件,请查收')
|
||||||
default:
|
setIsSent(true)
|
||||||
void message.error('出错了,请稍后重试')
|
setIsSending(false)
|
||||||
}
|
break
|
||||||
})
|
case PERMISSION_USER_NOT_FOUND:
|
||||||
.finally(() => {
|
void message.error('用户不存在')
|
||||||
setIsSending(false)
|
setIsSending(false)
|
||||||
})
|
break
|
||||||
|
case SYSTEM_INVALID_CAPTCHA_CODE:
|
||||||
|
void message.error('验证码有误,请刷新重试')
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
void message.error('出错了,请稍后重试')
|
||||||
|
setIsSending(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOnRetry = () => {
|
const handleOnRetry = () => {
|
||||||
setIsSent(false)
|
setIsSent(false)
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
turnstileRef.current?.execute()
|
||||||
|
}, 200)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleOnChange = (retrieveParam: RetrieveParam) => {
|
const handleOnChange = (retrieveParam: RetrieveParam) => {
|
||||||
@@ -478,26 +533,29 @@ const Forget: React.FC = () => {
|
|||||||
|
|
||||||
void r_auth_retrieve({
|
void r_auth_retrieve({
|
||||||
code: searchParams.get('code') ?? '',
|
code: searchParams.get('code') ?? '',
|
||||||
password: retrieveParam.password
|
password: retrieveParam.password,
|
||||||
})
|
captchaCode: retrieveCpatchaCode
|
||||||
.then((res) => {
|
}).then((res) => {
|
||||||
const response = res.data
|
const response = res.data
|
||||||
|
|
||||||
switch (response.code) {
|
switch (response.code) {
|
||||||
case PERMISSION_RETRIEVE_SUCCESS:
|
case PERMISSION_RETRIEVE_SUCCESS:
|
||||||
void message.success('密码已更新')
|
void message.success('密码已更新')
|
||||||
setIsChanged(true)
|
setIsChanged(true)
|
||||||
break
|
setIsChanging(false)
|
||||||
case PERMISSION_RETRIEVE_CODE_ERROR_OR_EXPIRED:
|
break
|
||||||
void message.error('验证码有误,请重新获取')
|
case PERMISSION_RETRIEVE_CODE_ERROR_OR_EXPIRED:
|
||||||
break
|
void message.error('请重新获取邮件')
|
||||||
default:
|
setIsChanging(false)
|
||||||
void message.error('出错了,请稍后重试')
|
break
|
||||||
}
|
case SYSTEM_INVALID_CAPTCHA_CODE:
|
||||||
})
|
void message.error('验证码有误,请刷新重试')
|
||||||
.finally(() => {
|
break
|
||||||
setIsChanging(false)
|
default:
|
||||||
})
|
void message.error('出错了,请稍后重试')
|
||||||
|
setIsChanging(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -526,6 +584,15 @@ const Forget: React.FC = () => {
|
|||||||
disabled={isSending}
|
disabled={isSending}
|
||||||
/>
|
/>
|
||||||
</AntdForm.Item>
|
</AntdForm.Item>
|
||||||
|
<AntdForm.Item>
|
||||||
|
<Turnstile
|
||||||
|
id={'forget-turnstile'}
|
||||||
|
ref={turnstileRef}
|
||||||
|
siteKey={H_CAPTCHA_SITE_KEY}
|
||||||
|
options={{ theme: 'light', execution: 'execute' }}
|
||||||
|
onSuccess={setCaptchaCode}
|
||||||
|
/>
|
||||||
|
</AntdForm.Item>
|
||||||
<AntdForm.Item>
|
<AntdForm.Item>
|
||||||
<AntdButton
|
<AntdButton
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
@@ -589,6 +656,15 @@ const Forget: React.FC = () => {
|
|||||||
disabled={isChanging}
|
disabled={isChanging}
|
||||||
/>
|
/>
|
||||||
</AntdForm.Item>
|
</AntdForm.Item>
|
||||||
|
<AntdForm.Item>
|
||||||
|
<Turnstile
|
||||||
|
id={'retrieve-turnstile'}
|
||||||
|
ref={retrieveTurnstileRef}
|
||||||
|
siteKey={H_CAPTCHA_SITE_KEY}
|
||||||
|
options={{ theme: 'light', execution: 'execute' }}
|
||||||
|
onSuccess={setRetrieveCpatchaCode}
|
||||||
|
/>
|
||||||
|
</AntdForm.Item>
|
||||||
<AntdForm.Item>
|
<AntdForm.Item>
|
||||||
<AntdButton
|
<AntdButton
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
@@ -621,12 +697,18 @@ const SignIn: React.FC = () => {
|
|||||||
const { refreshRouter } = useContext(AppContext)
|
const { refreshRouter } = useContext(AppContext)
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const [searchParams] = useSearchParams()
|
const [searchParams] = useSearchParams()
|
||||||
|
const turnstileRef = useRef<TurnstileInstance>()
|
||||||
const [isSigningIn, setIsSigningIn] = useState(false)
|
const [isSigningIn, setIsSigningIn] = useState(false)
|
||||||
const [captchaCode, setCaptchaCode] = useState('')
|
const [captchaCode, setCaptchaCode] = useState('')
|
||||||
|
|
||||||
const handleOnTurnstileSuccess = (token: string) => {
|
useUpdatedEffect(() => {
|
||||||
setCaptchaCode(token)
|
if (location.pathname !== '/login') {
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
turnstileRef.current?.execute()
|
||||||
|
}, 200)
|
||||||
|
}, [location.pathname])
|
||||||
|
|
||||||
const handleOnFinish = (loginParam: LoginParam) => {
|
const handleOnFinish = (loginParam: LoginParam) => {
|
||||||
if (isSigningIn) {
|
if (isSigningIn) {
|
||||||
@@ -749,9 +831,11 @@ const SignIn: React.FC = () => {
|
|||||||
</AntdForm.Item>
|
</AntdForm.Item>
|
||||||
<AntdForm.Item>
|
<AntdForm.Item>
|
||||||
<Turnstile
|
<Turnstile
|
||||||
|
id={'sign-in-turnstile'}
|
||||||
|
ref={turnstileRef}
|
||||||
siteKey={H_CAPTCHA_SITE_KEY}
|
siteKey={H_CAPTCHA_SITE_KEY}
|
||||||
options={{ theme: 'light' }}
|
options={{ theme: 'light', execution: 'execute' }}
|
||||||
onSuccess={handleOnTurnstileSuccess}
|
onSuccess={setCaptchaCode}
|
||||||
/>
|
/>
|
||||||
</AntdForm.Item>
|
</AntdForm.Item>
|
||||||
<FlexBox direction={'horizontal'} className={'addition'}>
|
<FlexBox direction={'horizontal'} className={'addition'}>
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import {
|
|||||||
PERMISSION_TOKEN_HAS_EXPIRED,
|
PERMISSION_TOKEN_HAS_EXPIRED,
|
||||||
PERMISSION_TOKEN_ILLEGAL,
|
PERMISSION_TOKEN_ILLEGAL,
|
||||||
PERMISSION_TOKEN_RENEW_SUCCESS,
|
PERMISSION_TOKEN_RENEW_SUCCESS,
|
||||||
PERMISSION_UNAUTHORIZED
|
PERMISSION_UNAUTHORIZED,
|
||||||
|
SYSTEM_REQUEST_TOO_FREQUENT
|
||||||
} from '@/constants/common.constants'
|
} from '@/constants/common.constants'
|
||||||
import { getRedirectUrl } from '@/util/route'
|
import { getRedirectUrl } from '@/util/route'
|
||||||
import { getToken, setToken, removeToken } from '@/util/auth'
|
import { getToken, setToken, removeToken } from '@/util/auth'
|
||||||
@@ -97,6 +98,13 @@ service.interceptors.response.use(
|
|||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
throw response?.data
|
throw response?.data
|
||||||
|
case SYSTEM_REQUEST_TOO_FREQUENT:
|
||||||
|
void message.warning(
|
||||||
|
<>
|
||||||
|
<strong>请求过于频繁,请稍后重试</strong>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
throw response?.data
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user