274 lines
9.3 KiB
TypeScript
274 lines
9.3 KiB
TypeScript
import React, { useState, useEffect } from 'react';
|
||
import { Form, Input, Button, Checkbox, Tabs, message } from 'antd';
|
||
import { UserOutlined, LockOutlined, EyeInvisibleOutlined, EyeTwoTone } from '@ant-design/icons';
|
||
import { history, useIntl } from 'umi';
|
||
import './login.less';
|
||
import { getCaptcha, supplierLogin, expertLogin, accountLogin, getUserinfo, refreshDictCache, findMenuList, changePasswordOnFirstLogin } from '@/servers/api/login';
|
||
import ChangePasswordModal from './components/ChangePasswordModal';
|
||
|
||
import { encryptWithRsa } from '@/utils/encryptWithRsa'
|
||
|
||
const { TabPane } = Tabs;
|
||
|
||
const LoginPage: React.FC = () => {
|
||
const [activeKey, setActiveKey] = useState('supplierLogin');
|
||
const [form] = Form.useForm();
|
||
const [loading, setLoading] = useState(false);
|
||
const [captchaImg, setCaptchaImg] = useState<string>('');
|
||
const [userId, setUserId] = useState<string>('');
|
||
// ======= 修改密码弹窗控制 =======
|
||
const [showChangePwd, setShowChangePwd] = useState(false);
|
||
|
||
// const [captchaKey, setCaptchaKey] = useState<string>('');
|
||
//切换后 走不同接口
|
||
const loginApiMap: { [key: string]: (params: any) => Promise<any> } = {
|
||
supplierLogin,
|
||
expertLogin,
|
||
accountLogin
|
||
};
|
||
|
||
const intl = useIntl();
|
||
|
||
useEffect(() => {
|
||
fetchCaptcha();
|
||
if (!sessionStorage.getItem('dict')) {
|
||
refreshDictCache().then((res) => {
|
||
if (res.code == 200) {
|
||
sessionStorage.setItem('dict', JSON.stringify(res.data))
|
||
}
|
||
})
|
||
}
|
||
|
||
form.setFieldsValue({ password: 'cosco2025', identifying: '1' })
|
||
|
||
|
||
}, [activeKey]);
|
||
|
||
// 修改密码确认回调
|
||
const handleChangePwd = async (values: { userId: string; newPassword: string; confirmPassword: string; }) => {
|
||
try {
|
||
await changePasswordOnFirstLogin({
|
||
userId: userId,
|
||
newPassword: encryptWithRsa(values.newPassword, false),
|
||
confirmPassword: encryptWithRsa(values.confirmPassword, false)
|
||
}).then((res) => {
|
||
if (res.data) {
|
||
setShowChangePwd(false);
|
||
message.success('修改成功,请重新登录');
|
||
} else {
|
||
message.success('修改密码失败');
|
||
}
|
||
})
|
||
} catch (e: any) {
|
||
message.error(e?.message || '修改密码失败');
|
||
}
|
||
};
|
||
const onFinish = async (values: any) => {
|
||
setLoading(true);
|
||
try {
|
||
const params = {
|
||
...values,
|
||
password: encryptWithRsa(values.password, false),
|
||
encryptValue: encryptWithRsa(values.identifying)
|
||
};
|
||
const loginRes = await loginApiMap[activeKey](params);
|
||
if (loginRes.code === 200) {
|
||
|
||
if (values.remember) {
|
||
localStorage.setItem('remember_user', JSON.stringify({
|
||
username: values.username,
|
||
password: values.password,
|
||
}));
|
||
} else {
|
||
localStorage.removeItem('remember_user');
|
||
}
|
||
sessionStorage.setItem('activeKey', activeKey)
|
||
sessionStorage.setItem('token', loginRes.data.token);
|
||
//存入供应商用户id
|
||
if (activeKey === 'supplierLogin') {
|
||
sessionStorage.setItem('userId', loginRes.data.supplierUser.userId);
|
||
if (loginRes.data?.supplierUser?.firstLogin === 1) {
|
||
setUserId(loginRes.data.supplierUser.userId)
|
||
setShowChangePwd(true);
|
||
return
|
||
}
|
||
} else if (activeKey === 'expertLogin') {
|
||
//存入专家用户id
|
||
// sessionStorage.setItem('userId', loginRes.data.expertUser.userId);
|
||
} else if (activeKey === 'accountLogin') {
|
||
//存入招标代理用户id
|
||
sessionStorage.setItem('userId', loginRes.data.user.userId);
|
||
}
|
||
sessionStorage.setItem('currentUser', JSON.stringify(loginRes.data));
|
||
|
||
await getUserinfo().then(async (res) => {
|
||
const roleIdList = res.authorityList.map((item: any) => item.roleId);
|
||
sessionStorage.setItem('Userinfo', JSON.stringify(res));
|
||
const menuList: any = await findMenuList({ roleIdList });
|
||
sessionStorage.setItem('menuList', JSON.stringify(menuList.data));
|
||
message.success('登录成功');
|
||
if (activeKey === 'supplierLogin') {
|
||
history.push('/backend/workbenches');
|
||
} else {
|
||
history.push('/index');
|
||
}
|
||
});
|
||
} else {
|
||
message.error(loginRes.message || '登录失败');
|
||
}
|
||
} finally {
|
||
setLoading(false);
|
||
}
|
||
};
|
||
|
||
|
||
const fetchCaptcha = async () => {
|
||
const res = await getCaptcha();
|
||
if (res.code === 200) {
|
||
setCaptchaImg(res.data.base64Image);
|
||
// setCaptchaKey(res.data.code);
|
||
}
|
||
};
|
||
|
||
const handleTabChange = (key: string) => {
|
||
setActiveKey(key);
|
||
form.resetFields();
|
||
};
|
||
|
||
// 根据当前选中的Tab决定跳转到哪个注册页面
|
||
const handleRegister = () => {
|
||
switch (activeKey) {
|
||
case 'supplierLogin':
|
||
history.push('/register/supplier');
|
||
break;
|
||
case 'expertLogin':
|
||
history.push('/register/expert');
|
||
break;
|
||
default:
|
||
// 招标代理不提供注册功能
|
||
break;
|
||
}
|
||
};
|
||
|
||
// 渲染注册链接(只在供应商和专家Tab下显示)
|
||
const renderRegisterLink = () => {
|
||
if (activeKey === 'agent') {
|
||
return null; // 招标代理不显示注册链接
|
||
}
|
||
|
||
return (
|
||
<div className="register-link">
|
||
{intl.formatMessage({ id: 'login.register.tip' })}
|
||
<a onClick={handleRegister}>
|
||
{intl.formatMessage({ id: 'login.register.action' })}
|
||
</a>
|
||
</div>
|
||
);
|
||
};
|
||
|
||
// 忘记密码点击
|
||
const onForgot = () => {
|
||
history.push('/forgot?type=' + activeKey);
|
||
}
|
||
|
||
return (
|
||
<>
|
||
<ChangePasswordModal
|
||
visible={showChangePwd}
|
||
onOk={handleChangePwd}
|
||
/>
|
||
|
||
<div className='login-page'>
|
||
<div className='login-container'>
|
||
{/* <div className='back-home'>
|
||
<a onClick={() => history.push('/index')}>
|
||
<HomeOutlined /> {intl.formatMessage({ id: 'login.back.home' })}
|
||
</a>
|
||
</div> */}
|
||
|
||
<div className='login-title'>{intl.formatMessage({ id: 'login.title' })}</div>
|
||
|
||
<div className="login-tab-container">
|
||
<Tabs activeKey={activeKey} onChange={handleTabChange} className='login-tabs'>
|
||
<TabPane tab={intl.formatMessage({ id: 'login.tab.supplier' })} key="supplierLogin" />
|
||
{/* <TabPane tab={intl.formatMessage({ id: 'login.tab.expert' })} key="expertLogin" /> */}
|
||
<TabPane tab={intl.formatMessage({ id: 'login.tab.agent' })} key="accountLogin" />
|
||
</Tabs>
|
||
</div>
|
||
|
||
<Form
|
||
form={form}
|
||
name="login"
|
||
className='login-form'
|
||
initialValues={{ remember: false }}
|
||
onFinish={onFinish}
|
||
>
|
||
<Form.Item
|
||
name="account"
|
||
rules={[{ required: true, message: intl.formatMessage({ id: 'login.username.placeholder' }) + '!' }]}
|
||
>
|
||
<Input
|
||
prefix={<UserOutlined className="site-form-item-icon" />}
|
||
placeholder={intl.formatMessage({ id: 'login.username.placeholder' })}
|
||
size="large"
|
||
/>
|
||
</Form.Item>
|
||
|
||
<Form.Item
|
||
name="password"
|
||
rules={[{ required: true, message: intl.formatMessage({ id: 'login.password.placeholder' }) + '!' }]}
|
||
>
|
||
<Input.Password
|
||
prefix={<LockOutlined className="site-form-item-icon" />}
|
||
placeholder={intl.formatMessage({ id: 'login.password.placeholder' })}
|
||
iconRender={visible => (visible ? <EyeTwoTone /> : <EyeInvisibleOutlined />)}
|
||
size="large"
|
||
/>
|
||
</Form.Item>
|
||
<Form.Item
|
||
name="identifying"
|
||
rules={[{ required: true, message: intl.formatMessage({ id: 'login.captcha.placeholder' }) + '!' }]}
|
||
>
|
||
<Input
|
||
placeholder={intl.formatMessage({ id: 'login.captcha.placeholder' })}
|
||
size="large"
|
||
maxLength={6}
|
||
autoComplete="off"
|
||
prefix={null}
|
||
suffix={
|
||
<img
|
||
src={`data:image/png;base64,${captchaImg}`}
|
||
alt="验证码"
|
||
style={{ cursor: 'pointer', height: 32, verticalAlign: 'middle' }}
|
||
onClick={fetchCaptcha}
|
||
/>
|
||
}
|
||
/>
|
||
</Form.Item>
|
||
|
||
<Form.Item>
|
||
<div className='login-options'>
|
||
<Form.Item name="remember" valuePropName="checked" noStyle>
|
||
<Checkbox>{intl.formatMessage({ id: 'login.remember' })}</Checkbox>
|
||
</Form.Item>
|
||
<Button type="link" onClick={() => onForgot()} className="login-form-forgot" href="">
|
||
{intl.formatMessage({ id: 'login.forgot' })}
|
||
</Button>
|
||
</div>
|
||
</Form.Item>
|
||
|
||
<Form.Item>
|
||
<Button type="primary" htmlType="submit" className="login-form-button" loading={loading} size="large">
|
||
{intl.formatMessage({ id: 'login.button' })}
|
||
</Button>
|
||
{activeKey !== 'accountLogin' && renderRegisterLink()}
|
||
</Form.Item>
|
||
</Form>
|
||
</div>
|
||
</div>
|
||
</>
|
||
);
|
||
};
|
||
|
||
export default LoginPage;
|