Files
shihezi-admin/src/pages/User/Login/index.tsx

466 lines
14 KiB
TypeScript
Raw Normal View History

2024-11-18 16:38:38 +08:00
import Footer from '@/components/Footer';
import { getCaptchaImg, login } from '@/services/system/auth';
import { getFakeCaptcha } from '@/services/ant-design-pro/login';
import {
AlipayCircleOutlined,
LockOutlined,
MobileOutlined,
TaobaoCircleOutlined,
UserOutlined,
WeiboCircleOutlined,
} from '@ant-design/icons';
import {
LoginForm,
ProFormCaptcha,
ProFormCheckbox,
ProFormText,
} from '@ant-design/pro-components';
import { useEmotionCss } from '@ant-design/use-emotion-css';
2025-03-28 15:30:35 +08:00
import { FormattedMessage, Helmet, history, SelectLang, useIntl, useModel } from '@umijs/max';
2025-11-24 18:20:35 +08:00
import { Alert, Col, Image, message, Row, Tabs, QRCode } from 'antd';
2024-11-18 16:38:38 +08:00
import Settings from '../../../../config/defaultSettings';
import React, { useEffect, useState } from 'react';
import { flushSync } from 'react-dom';
2025-03-28 15:30:35 +08:00
// flushSync 允许你强制 React 同步刷新提供的回调中的任何更新。这确保了 DOM 立即更新
2024-11-18 16:38:38 +08:00
import { clearSessionToken, setSessionToken } from '@/access';
2025-03-28 15:30:35 +08:00
import logoImg from '@/assets/logo.svg';
2025-11-24 18:20:35 +08:00
import login_imge2b033b1 from '@/assets/login_img.e2b033b1.png';
2024-11-18 16:38:38 +08:00
const ActionIcons = () => {
const langClassName = useEmotionCss(({ token }) => {
return {
marginLeft: '8px',
color: 'rgba(0, 0, 0, 0.2)',
fontSize: '24px',
verticalAlign: 'middle',
cursor: 'pointer',
transition: 'color 0.3s',
'&:hover': {
color: token.colorPrimaryActive,
},
};
});
return (
<>
<AlipayCircleOutlined key="AlipayCircleOutlined" className={langClassName} />
<TaobaoCircleOutlined key="TaobaoCircleOutlined" className={langClassName} />
<WeiboCircleOutlined key="WeiboCircleOutlined" className={langClassName} />
</>
);
};
const Lang = () => {
const langClassName = useEmotionCss(({ token }) => {
return {
width: 42,
height: 42,
lineHeight: '42px',
position: 'fixed',
right: 16,
borderRadius: token.borderRadius,
':hover': {
backgroundColor: token.colorBgTextHover,
},
};
});
return (
<div className={langClassName} data-lang>
{SelectLang && <SelectLang />}
</div>
);
};
const LoginMessage: React.FC<{
content: string;
}> = ({ content }) => {
return (
<Alert
style={{
marginBottom: 24,
}}
message={content}
type="error"
showIcon
/>
);
};
const Login: React.FC = () => {
2025-03-28 15:30:35 +08:00
const [userLoginState, setUserLoginState] = useState<API.LoginResult>({ code: 200 });
2024-11-18 16:38:38 +08:00
const [type, setType] = useState<string>('account');
const { initialState, setInitialState } = useModel('@@initialState');
const [captchaCode, setCaptchaCode] = useState<string>('');
const [uuid, setUuid] = useState<string>('');
2025-11-24 18:20:35 +08:00
const [qrcodeVal, setQrcodeVal] = useState<string>('7655212');
2024-11-18 16:38:38 +08:00
const containerClassName = useEmotionCss(() => {
return {
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 intl = useIntl();
const getCaptchaCode = async () => {
const response = await getCaptchaImg();
const imgdata = `data:image/png;base64,${response.img}`;
setCaptchaCode(imgdata);
setUuid(response.uuid);
};
const fetchUserInfo = async () => {
const userInfo = await initialState?.fetchUserInfo?.();
if (userInfo) {
flushSync(() => {
setInitialState((s) => ({
...s,
currentUser: userInfo,
}));
});
}
};
const handleSubmit = async (values: API.LoginParams) => {
try {
// 登录
const response = await login({ ...values, uuid });
if (response.code === 200) {
const defaultLoginSuccessMessage = intl.formatMessage({
id: 'pages.login.success',
defaultMessage: '登录成功!',
});
const current = new Date();
const expireTime = current.setTime(current.getTime() + 1000 * 12 * 60 * 60);
setSessionToken(response?.token, response?.token, expireTime);
message.success(defaultLoginSuccessMessage);
await fetchUserInfo();
console.log('login ok');
const urlParams = new URL(window.location.href).searchParams;
history.push(urlParams.get('redirect') || '/');
2025-03-28 15:30:35 +08:00
setTimeout(() => history.go(0), 0);
2024-11-18 16:38:38 +08:00
return;
} else {
2024-11-19 16:16:30 +08:00
message.error(response.msg);
2024-11-18 16:38:38 +08:00
clearSessionToken();
// 如果失败去设置用户错误信息
setUserLoginState({ ...response, type });
getCaptchaCode();
}
} catch (error) {
2024-11-19 16:16:30 +08:00
// message.error(response.msg);
2024-11-18 16:38:38 +08:00
const defaultLoginFailureMessage = intl.formatMessage({
id: 'pages.login.failure',
defaultMessage: '登录失败,请重试!',
});
2024-11-19 16:16:30 +08:00
// console.log(error);
2024-11-18 16:38:38 +08:00
message.error(defaultLoginFailureMessage);
}
};
const { code } = userLoginState;
const loginType = type;
useEffect(() => {
getCaptchaCode();
}, []);
return (
<div className={containerClassName}>
<Helmet>
<title>
{intl.formatMessage({
id: 'menu.login',
defaultMessage: '登录页',
})}
- {Settings.title}
</title>
</Helmet>
<Lang />
<div
style={{
flex: '1',
padding: '32px 0',
}}
>
<LoginForm
contentStyle={{
minWidth: 280,
maxWidth: '75vw',
}}
2025-11-24 18:20:35 +08:00
submitter={type === 'scanQode' ? false : true}
// logo={<img alt="logo" src={logoImg} />}
2024-11-19 16:16:30 +08:00
title="青岛智慧就业服务系统"
// subTitle={intl.formatMessage({ id: 'pages.layouts.userLayout.title' })}
2024-11-18 16:38:38 +08:00
initialValues={{
autoLogin: true,
}}
2024-11-19 16:16:30 +08:00
// actions={[
// <FormattedMessage
// key="loginWith"
// id="pages.login.loginWith"
// defaultMessage="其他登录方式"
// />,
// <ActionIcons key="icons" />,
// ]}
2024-11-18 16:38:38 +08:00
onFinish={async (values) => {
await handleSubmit(values as API.LoginParams);
}}
>
<Tabs
activeKey={type}
onChange={setType}
centered
items={[
{
key: 'account',
label: intl.formatMessage({
id: 'pages.login.accountLogin.tab',
defaultMessage: '账户密码登录',
}),
},
2025-11-24 18:20:35 +08:00
{
key: 'scanQode',
label: '社保卡扫码登录',
},
2025-10-29 17:34:55 +08:00
// {
// key: 'mobile',
// label: intl.formatMessage({
// id: 'pages.login.phoneLogin.tab',
// defaultMessage: '手机号登录',
// }),
// },
2024-11-18 16:38:38 +08:00
]}
/>
2025-11-24 18:20:35 +08:00
{/* {code !== 200 && loginType === 'account' && ( */}
2024-11-19 16:16:30 +08:00
{/* <LoginMessage*/}
{/* content={intl.formatMessage({*/}
{/* id: 'pages.login.accountLogin.errorMessage',*/}
{/* defaultMessage: '账户或密码错误(admin/admin123)',*/}
{/* })}*/}
{/* />*/}
{/*)}*/}
2025-11-24 18:20:35 +08:00
{type === 'scanQode' && (
<>
<Row>
<Col offset={1}>
<QRCode
errorLevel="H"
size={300}
iconSize={300 / 5}
value="https://ant.design/"
icon={login_imge2b033b1}
/>
</Col>
</Row>
</>
)}
2024-11-18 16:38:38 +08:00
{type === 'account' && (
<>
<ProFormText
name="username"
initialValue="admin"
fieldProps={{
size: 'large',
prefix: <UserOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.username.placeholder',
defaultMessage: '用户名: admin',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.username.required"
defaultMessage="请输入用户名!"
/>
),
},
]}
/>
<ProFormText.Password
name="password"
initialValue="admin123"
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
placeholder={intl.formatMessage({
id: 'pages.login.password.placeholder',
defaultMessage: '密码: admin123',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.password.required"
defaultMessage="请输入密码!"
/>
),
},
]}
/>
<Row>
<Col flex={3}>
<ProFormText
style={{
float: 'right',
}}
name="code"
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: '请输入验证',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.searchTable.updateForm.ruleName.nameRules"
defaultMessage="请输入验证啊"
/>
),
},
]}
/>
</Col>
<Col flex={2}>
<Image
src={captchaCode}
alt="验证码"
style={{
display: 'inline-block',
verticalAlign: 'top',
cursor: 'pointer',
paddingLeft: '10px',
width: '100px',
}}
preview={false}
onClick={() => getCaptchaCode()}
/>
</Col>
</Row>
</>
)}
{code !== 200 && loginType === 'mobile' && <LoginMessage content="验证码错误" />}
{type === 'mobile' && (
<>
<ProFormText
fieldProps={{
size: 'large',
prefix: <MobileOutlined />,
}}
name="mobile"
placeholder={intl.formatMessage({
id: 'pages.login.phoneNumber.placeholder',
defaultMessage: '手机号',
})}
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.phoneNumber.required"
defaultMessage="请输入手机号!"
/>
),
},
{
pattern: /^1\d{10}$/,
message: (
<FormattedMessage
id="pages.login.phoneNumber.invalid"
defaultMessage="手机号格式错误!"
/>
),
},
]}
/>
<ProFormCaptcha
fieldProps={{
size: 'large',
prefix: <LockOutlined />,
}}
captchaProps={{
size: 'large',
}}
placeholder={intl.formatMessage({
id: 'pages.login.captcha.placeholder',
defaultMessage: '请输入验证码',
})}
captchaTextRender={(timing, count) => {
if (timing) {
return `${count} ${intl.formatMessage({
id: 'pages.getCaptchaSecondText',
defaultMessage: '获取验证码',
})}`;
}
return intl.formatMessage({
id: 'pages.login.phoneLogin.getVerificationCode',
defaultMessage: '获取验证码',
});
}}
name="captcha"
rules={[
{
required: true,
message: (
<FormattedMessage
id="pages.login.captcha.required"
defaultMessage="请输入验证码!"
/>
),
},
]}
onGetCaptcha={async (phone) => {
const result = await getFakeCaptcha({
phone,
});
if (!result) {
return;
}
message.success('获取验证码成功验证码为1234');
}}
/>
</>
)}
2025-11-24 18:20:35 +08:00
{type !== 'scanQode' && (
<div
2024-11-18 16:38:38 +08:00
style={{
2025-11-24 18:20:35 +08:00
marginBottom: 24,
2024-11-18 16:38:38 +08:00
}}
>
2025-11-24 18:20:35 +08:00
<ProFormCheckbox noStyle name="autoLogin">
<FormattedMessage id="pages.login.rememberMe" defaultMessage="自动登录" />
</ProFormCheckbox>
<a
style={{
float: 'right',
}}
>
<FormattedMessage id="pages.login.forgotPassword" defaultMessage="忘记密码" />
</a>
</div>
)}
2024-11-18 16:38:38 +08:00
</LoginForm>
</div>
<Footer />
</div>
);
};
export default Login;