Files
EVA-Tea/src/pages/User/Login/index.tsx
T
2024-04-02 02:55:09 +08:00

232 lines
6.4 KiB
TypeScript

import Settings from '@/../config/defaultSettings';
import oidcLogo from '@/assets/oidc-logo.svg';
import { PageFooter } from '@/components';
import { login } from '@/services/api';
import { API } from '@/services/typings';
import { LockOutlined, UserOutlined } from '@ant-design/icons';
import { LoginForm, ProFormCheckbox, ProFormText } from '@ant-design/pro-components';
import { Helmet, history, useModel } from '@umijs/max';
import { Alert, Button, Tabs, message } from 'antd';
import { createStyles } from 'antd-style';
import React, { CSSProperties, useState } from 'react';
import { flushSync } from 'react-dom';
const iconStyles: CSSProperties = {
transform: 'translateY(-12%)',
};
const useStyles = createStyles(({ token }) => {
return {
action: {
marginLeft: '8px',
color: 'rgba(0, 0, 0, 0.2)',
fontSize: '24px',
verticalAlign: 'middle',
cursor: 'pointer',
transition: 'color 0.3s',
'&:hover': {
color: token.colorPrimaryActive,
},
},
lang: {
width: 42,
height: 42,
lineHeight: '42px',
position: 'fixed',
right: 16,
borderRadius: token.borderRadius,
':hover': {
backgroundColor: token.colorBgTextHover,
},
},
container: {
display: 'flex',
flexDirection: 'column',
height: '100vh',
overflow: 'auto',
backgroundImage:
"url('https://mdn.alipayobjects.com/yuyan_qk0oxh/afts/img/V-_oS6r-i7wAAAAAAAAAAAAAFl94AQBr')",
backgroundSize: '100% 100%',
},
};
});
const LoginMessage: React.FC<{
content: string;
}> = ({ content }) => {
return (
<Alert
style={{
marginBottom: 24,
}}
message={content}
type="error"
showIcon
/>
);
};
const randomString = (length: number) => {
const chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
const maxPos = chars.length;
let randomStr = '';
for (let i = 0; i < length; i++) {
randomStr += chars.charAt(Math.floor(Math.random() * maxPos));
}
return randomStr;
};
const generateLink = () => {
const preLink =
'https://auth.zjueva.net/connect/authorize?response_type=code&client_id=ETA&redirect_uri=https://xms.zjueva.net/api/external_sign&scope=openid&state=';
return preLink + randomString(30);
};
const Login: React.FC = () => {
const [userLoginState, setUserLoginState] = useState<API.LoginResult>({});
const [type, setType] = useState<string>('account');
const { initialState, setInitialState } = useModel('@@initialState');
const { styles } = useStyles();
const fetchUserInfo = async () => {
const userInfo = await initialState?.fetchUserInfo?.();
if (userInfo) {
flushSync(() => {
setInitialState((s: any) => ({
...s,
currentUser: userInfo,
}));
});
}
};
const handleSubmit = async (values: API.LoginParams) => {
try {
// 登录
const msg = await login({
...values,
type,
});
if (msg.status === 'ok') {
const defaultLoginSuccessMessage = '登录成功!';
message.success(defaultLoginSuccessMessage);
await fetchUserInfo();
const urlParams = new URL(window.location.href).searchParams;
history.push(urlParams.get('redirect') || '/');
return;
}
console.log(msg);
// 如果失败去设置用户错误信息
setUserLoginState(msg);
} catch (error) {
const defaultLoginFailureMessage = '登录失败,请重试!';
console.log(error);
message.error(defaultLoginFailureMessage);
}
};
const { status, type: loginType } = userLoginState;
return (
<div className={styles.container}>
<Helmet>
<title>
{'登录'}- {Settings.title}
</title>
</Helmet>
<div
style={{
flex: '1',
padding: '32px 0',
}}
>
<LoginForm
contentStyle={{
minWidth: 280,
maxWidth: '75vw',
}}
logo={<img alt="logo" src="/logo.svg" />}
title="EVA Tea"
subTitle={'E志者协会是东区教学楼最专业的志愿维修组织'}
initialValues={{
autoLogin: true,
}}
onFinish={async (values: API.LoginParams) => {
await handleSubmit(values as API.LoginParams);
}}
>
<Tabs
activeKey={type}
onChange={setType}
centered
items={[
{
key: 'account',
label: '账户密码登录',
},
]}
/>
{status === 'error' && loginType === 'account' && (
<LoginMessage content={'错误的用户名和密码(admin/ant.design)'} />
)}
{type === 'account' && (
<>
<ProFormText
name="username"
fieldProps={{
size: 'large',
prefix: <UserOutlined />,
}}
placeholder={'用户名: admin or user'}
rules={[
{
required: true,
message: '用户名是必填项!',
},
]}
/>
<ProFormText.Password
name="password"
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
placeholder={'密码: ant.design'}
rules={[
{
required: true,
message: '密码是必填项!',
},
]}
/>
</>
)}
<div
style={{
marginBottom: 24,
}}
>
<ProFormCheckbox noStyle name="autoLogin">
自动登录
</ProFormCheckbox>
</div>
<div style={{ marginBottom: '2vh' }}>
{' '}
<Button
type="default"
block
size="large"
href={generateLink()}
style={{ backgroundColor: '#e0af68', color: '#ffffff' }}
>
<div>
<img src={oidcLogo} width="23px" style={iconStyles} />
&nbsp; 使用 EVA 统一身份认证
</div>
</Button>
</div>
</LoginForm>
</div>
<PageFooter />
</div>
);
};
export default Login;