Files
fe_supplier_frontend/src/pages/login/login.tsx

274 lines
9.3 KiB
TypeScript
Raw Normal View History

2025-07-09 14:01:45 +08:00
import React, { useState, useEffect } from 'react';
2025-06-17 14:20:06 +08:00
import { Form, Input, Button, Checkbox, Tabs, message } from 'antd';
import { UserOutlined, LockOutlined, EyeInvisibleOutlined, EyeTwoTone } from '@ant-design/icons';
2025-06-17 14:20:06 +08:00
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';
2025-07-09 14:01:45 +08:00
import { encryptWithRsa } from '@/utils/encryptWithRsa'
2025-06-17 14:20:06 +08:00
const { TabPane } = Tabs;
const LoginPage: React.FC = () => {
2025-07-11 08:33:29 +08:00
const [activeKey, setActiveKey] = useState('supplierLogin');
2025-06-17 14:20:06 +08:00
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
2025-07-09 14:01:45 +08:00
const [captchaImg, setCaptchaImg] = useState<string>('');
const [userId, setUserId] = useState<string>('');
// ======= 修改密码弹窗控制 =======
const [showChangePwd, setShowChangePwd] = useState(false);
// const [captchaKey, setCaptchaKey] = useState<string>('');
2025-07-11 08:33:29 +08:00
//切换后 走不同接口
const loginApiMap: { [key: string]: (params: any) => Promise<any> } = {
supplierLogin,
expertLogin,
accountLogin
};
2025-07-09 14:01:45 +08:00
2025-06-17 14:20:06 +08:00
const intl = useIntl();
2025-07-09 14:01:45 +08:00
useEffect(() => {
fetchCaptcha();
2025-08-04 16:06:23 +08:00
if (!sessionStorage.getItem('dict')) {
2025-07-24 09:10:24 +08:00
refreshDictCache().then((res) => {
2025-08-04 16:06:23 +08:00
if (res.code == 200) {
2025-07-24 09:10:24 +08:00
sessionStorage.setItem('dict', JSON.stringify(res.data))
}
})
}
2025-08-04 16:06:23 +08:00
2025-08-05 16:44:02 +08:00
form.setFieldsValue({ password: 'cosco2025', identifying: '1' })
2025-08-04 16:06:23 +08:00
2025-07-24 09:10:24 +08:00
2025-07-09 14:01:45 +08:00
}, [activeKey]);
2025-08-05 16:44:02 +08:00
// 修改密码确认回调
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 || '修改密码失败');
}
};
2025-07-09 14:01:45 +08:00
const onFinish = async (values: any) => {
2025-06-17 14:20:06 +08:00
setLoading(true);
2025-07-09 14:01:45 +08:00
try {
const params = {
...values,
password: encryptWithRsa(values.password, false),
encryptValue: encryptWithRsa(values.identifying)
};
2025-07-11 08:33:29 +08:00
const loginRes = await loginApiMap[activeKey](params);
2025-07-09 14:01:45 +08:00
if (loginRes.code === 200) {
if (values.remember) {
localStorage.setItem('remember_user', JSON.stringify({
username: values.username,
password: values.password,
}));
} else {
localStorage.removeItem('remember_user');
}
2025-08-11 16:17:27 +08:00
sessionStorage.setItem('activeKey', activeKey)
2025-07-09 14:01:45 +08:00
sessionStorage.setItem('token', loginRes.data.token);
2025-07-11 08:33:29 +08:00
//存入供应商用户id
2025-07-16 08:59:49 +08:00
if (activeKey === 'supplierLogin') {
2025-07-11 08:33:29 +08:00
sessionStorage.setItem('userId', loginRes.data.supplierUser.userId);
2025-08-05 16:44:02 +08:00
if (loginRes.data?.supplierUser?.firstLogin === 1) {
setUserId(loginRes.data.supplierUser.userId)
setShowChangePwd(true);
return
}
2025-07-16 08:59:49 +08:00
} else if (activeKey === 'expertLogin') {
2025-07-11 08:33:29 +08:00
//存入专家用户id
// sessionStorage.setItem('userId', loginRes.data.expertUser.userId);
2025-07-16 08:59:49 +08:00
} else if (activeKey === 'accountLogin') {
2025-07-11 08:33:29 +08:00
//存入招标代理用户id
2025-07-15 16:10:33 +08:00
sessionStorage.setItem('userId', loginRes.data.user.userId);
2025-07-11 08:33:29 +08:00
}
2025-07-09 14:01:45 +08:00
sessionStorage.setItem('currentUser', JSON.stringify(loginRes.data));
2025-08-05 16:44:02 +08:00
2025-08-04 16:06:23 +08:00
await getUserinfo().then(async (res) => {
const roleIdList = res.authorityList.map((item: any) => item.roleId);
2025-07-18 16:09:31 +08:00
sessionStorage.setItem('Userinfo', JSON.stringify(res));
2025-08-04 16:06:23 +08:00
const menuList: any = await findMenuList({ roleIdList });
sessionStorage.setItem('menuList', JSON.stringify(menuList.data));
2025-08-05 16:44:02 +08:00
message.success('登录成功');
if (activeKey === 'supplierLogin') {
history.push('/backend/workbenches');
} else {
history.push('/index');
}
2025-08-04 16:06:23 +08:00
});
2025-07-09 14:01:45 +08:00
} else {
message.error(loginRes.message || '登录失败');
}
} finally {
2025-06-17 14:20:06 +08:00
setLoading(false);
2025-07-09 14:01:45 +08:00
}
};
2025-07-16 08:59:49 +08:00
2025-07-09 14:01:45 +08:00
const fetchCaptcha = async () => {
const res = await getCaptcha();
if (res.code === 200) {
setCaptchaImg(res.data.base64Image);
// setCaptchaKey(res.data.code);
2025-07-09 14:01:45 +08:00
}
2025-06-17 14:20:06 +08:00
};
const handleTabChange = (key: string) => {
setActiveKey(key);
form.resetFields();
};
// 根据当前选中的Tab决定跳转到哪个注册页面
const handleRegister = () => {
2025-07-16 08:59:49 +08:00
switch (activeKey) {
2025-07-11 08:33:29 +08:00
case 'supplierLogin':
2025-06-17 14:20:06 +08:00
history.push('/register/supplier');
break;
2025-07-11 08:33:29 +08:00
case 'expertLogin':
2025-06-17 14:20:06 +08:00
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 = () => {
2025-08-04 16:06:23 +08:00
history.push('/forgot?type=' + activeKey);
}
2025-06-17 14:20:06 +08:00
return (
<>
2025-08-05 16:44:02 +08:00
<ChangePasswordModal
visible={showChangePwd}
onOk={handleChangePwd}
/>
2025-08-05 16:44:02 +08:00
<div className='login-page'>
<div className='login-container'>
{/* <div className='back-home'>
2025-06-17 14:20:06 +08:00
<a onClick={() => history.push('/index')}>
<HomeOutlined /> {intl.formatMessage({ id: 'login.back.home' })}
</a>
2025-07-09 14:01:45 +08:00
</div> */}
2025-06-17 14:20:06 +08:00
2025-08-05 16:44:02 +08:00
<div className='login-title'>{intl.formatMessage({ id: 'login.title' })}</div>
2025-06-17 14:20:06 +08:00
2025-08-05 16:44:02 +08:00
<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>
2025-06-17 14:20:06 +08:00
2025-08-05 16:44:02 +08:00
<Form
form={form}
name="login"
className='login-form'
initialValues={{ remember: false }}
onFinish={onFinish}
2025-06-17 14:20:06 +08:00
>
2025-08-05 16:44:02 +08:00
<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>
2025-06-17 14:20:06 +08:00
2025-08-05 16:44:02 +08:00
<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>
2025-06-17 14:20:06 +08:00
2025-08-05 16:44:02 +08:00
<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>
2025-06-17 14:20:06 +08:00
2025-08-05 16:44:02 +08:00
<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>
2025-06-17 14:20:06 +08:00
</div>
</>
2025-06-17 14:20:06 +08:00
);
};
export default LoginPage;