Files
fe_supplier_frontend/src/pages/login/login.tsx
2025-08-11 16:17:27 +08:00

274 lines
9.3 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, { 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;