Files
oxygen-ui/src/pages/sign/SignIn.tsx
2024-01-04 10:17:06 +08:00

213 lines
8.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import React, { useCallback } from 'react'
import Icon from '@ant-design/icons'
import { Turnstile, TurnstileInstance } from '@marsidev/react-turnstile'
import {
H_CAPTCHA_SITE_KEY,
PERMISSION_LOGIN_SUCCESS,
PERMISSION_LOGIN_USERNAME_PASSWORD_ERROR,
PERMISSION_USER_DISABLE,
PERMISSION_USERNAME_NOT_FOUND,
SYSTEM_INVALID_CAPTCHA_CODE
} from '@/constants/common.constants'
import { useUpdatedEffect } from '@/util/hooks'
import { getUserInfo, setToken } from '@/util/auth'
import { utcToLocalTime } from '@/util/datetime'
import { r_auth_login } from '@/services/auth'
import { AppContext } from '@/App'
import FitCenter from '@/components/common/FitCenter'
import FlexBox from '@/components/common/FlexBox'
const SignIn: React.FC = () => {
const { refreshRouter } = useContext(AppContext)
const navigate = useNavigate()
const [searchParams] = useSearchParams()
const turnstileRef = useRef<TurnstileInstance>()
const turnstileRefCallback = useCallback(
(node: TurnstileInstance) => {
turnstileRef.current = node
if (location.pathname === '/login') {
turnstileRef.current?.execute()
}
},
[location.pathname]
)
const [isSigningIn, setIsSigningIn] = useState(false)
const [captchaCode, setCaptchaCode] = useState('')
useUpdatedEffect(() => {
if (!isSigningIn) {
setCaptchaCode('')
turnstileRef.current?.reset()
turnstileRef.current?.execute()
}
}, [isSigningIn])
const handleOnFinish = (loginParam: LoginParam) => {
if (isSigningIn) {
return
}
setIsSigningIn(true)
if (!captchaCode) {
void message.warning('请先通过验证')
setIsSigningIn(false)
return
}
void r_auth_login({
account: loginParam.account,
password: loginParam.password,
captchaCode
})
.then((res) => {
const response = res.data
const { code, data } = response
switch (code) {
case PERMISSION_LOGIN_SUCCESS:
setToken(data?.token ?? '')
void message.success('登录成功')
setTimeout(() => {
void getUserInfo().then((user) => {
refreshRouter()
if (searchParams.has('redirect')) {
navigate(searchParams.get('redirect') ?? '/')
} else {
navigate('/')
}
notification.success({
message: '欢迎回来',
description: (
<>
<span>
<strong>{user.userInfo.nickname}</strong>
</span>
<br />
<span>
{user.lastLoginTime
? `${utcToLocalTime(user.lastLoginTime)}${
user.lastLoginIp
}`
: '无'}
</span>
</>
),
placement: 'topRight'
})
})
}, 1500)
break
case PERMISSION_USERNAME_NOT_FOUND:
case PERMISSION_LOGIN_USERNAME_PASSWORD_ERROR:
void message.error(
<>
<strong></strong><strong></strong>
</>
)
setIsSigningIn(false)
break
case PERMISSION_USER_DISABLE:
void message.error(
<>
<strong></strong>
</>
)
setIsSigningIn(false)
break
case SYSTEM_INVALID_CAPTCHA_CODE:
void message.error('验证码有误,请重试')
setIsSigningIn(false)
break
default:
void message.error(
<>
<strong></strong>
</>
)
setIsSigningIn(false)
}
})
.catch(() => {
setIsSigningIn(false)
})
}
return (
<div className={'sign-in'}>
<FitCenter>
<FlexBox>
<div className={'title'}>
<div className={'primary'}></div>
<div className={'secondary'}>Welcome back</div>
</div>
<AntdForm autoComplete={'on'} onFinish={handleOnFinish} className={'form'}>
<AntdForm.Item
name={'account'}
rules={[{ required: true, message: '请输入账号' }]}
>
<AntdInput
prefix={<Icon component={IconOxygenUser} />}
placeholder={'邮箱/用户名'}
disabled={isSigningIn}
/>
</AntdForm.Item>
<AntdForm.Item
name={'password'}
rules={[{ required: true, message: '请输入密码' }]}
>
<AntdInput.Password
prefix={<Icon component={IconOxygenPassword} />}
placeholder={'密码'}
disabled={isSigningIn}
/>
</AntdForm.Item>
<AntdForm.Item>
<Turnstile
id={'sign-in-turnstile'}
ref={turnstileRefCallback}
siteKey={H_CAPTCHA_SITE_KEY}
options={{ theme: 'light', execution: 'execute' }}
onSuccess={setCaptchaCode}
/>
</AntdForm.Item>
<FlexBox direction={'horizontal'} className={'addition'}>
<AntdCheckbox disabled={isSigningIn}></AntdCheckbox>
<a
onClick={() => {
navigate(`/forget${location.search}`, { replace: true })
}}
>
</a>
</FlexBox>
<AntdForm.Item>
<AntdButton
style={{ width: '100%' }}
type={'primary'}
htmlType={'submit'}
disabled={isSigningIn}
loading={isSigningIn}
>
&ensp;&ensp;&ensp;&ensp;
</AntdButton>
</AntdForm.Item>
<div className={'footer'}>
<a
onClick={() =>
navigate(`/register${location.search}`, { replace: true })
}
>
</a>
</div>
</AntdForm>
</FlexBox>
</FitCenter>
</div>
)
}
export default SignIn