接入登录功能
This commit is contained in:
@ -1,13 +1,18 @@
|
||||
export default {
|
||||
dev: {
|
||||
'/api/v1': {
|
||||
target: 'http://10.0.0.10:18030',// 茂
|
||||
changeOrigin: true,
|
||||
pathRewrite: { '^/api/v1': '/v1' },
|
||||
},
|
||||
'/api': {
|
||||
// target: 'http://10.242.37.148:18022',//
|
||||
target: 'http://10.0.0.14:18013',//
|
||||
target: 'http://10.0.0.10:18013',//
|
||||
changeOrigin: true,
|
||||
pathRewrite: { '^/api': '' },
|
||||
},
|
||||
'/upload': {
|
||||
target: 'http://10.0.0.14:18013',//
|
||||
target: 'http://10.0.0.10:18013',//
|
||||
changeOrigin: true,
|
||||
pathRewrite: { '^/upload': '' },
|
||||
},
|
||||
|
@ -70,9 +70,11 @@
|
||||
"array-move": "3.0.1",
|
||||
"axios": "0.21.1",
|
||||
"classnames": "2.3.1",
|
||||
"dayjs": "^1.11.13",
|
||||
"dva": "2.4.1",
|
||||
"echarts": "^5.2.2",
|
||||
"echarts-for-react": "^3.0.2",
|
||||
"jsencrypt": "^3.3.2",
|
||||
"lodash": "4.17.21",
|
||||
"moment": "^2.29.4",
|
||||
"omit.js": "2.0.2",
|
||||
|
10
pnpm-lock.yaml
generated
10
pnpm-lock.yaml
generated
@ -50,6 +50,9 @@ dependencies:
|
||||
classnames:
|
||||
specifier: 2.3.1
|
||||
version: 2.3.1
|
||||
dayjs:
|
||||
specifier: ^1.11.13
|
||||
version: 1.11.13
|
||||
dva:
|
||||
specifier: 2.4.1
|
||||
version: 2.4.1(react-dom@16.14.0)(react@16.14.0)
|
||||
@ -59,6 +62,9 @@ dependencies:
|
||||
echarts-for-react:
|
||||
specifier: ^3.0.2
|
||||
version: 3.0.2(echarts@5.6.0)(react@16.14.0)
|
||||
jsencrypt:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2
|
||||
lodash:
|
||||
specifier: 4.17.21
|
||||
version: 4.17.21
|
||||
@ -10230,6 +10236,10 @@ packages:
|
||||
- utf-8-validate
|
||||
dev: true
|
||||
|
||||
/jsencrypt@3.3.2:
|
||||
resolution: {integrity: sha512-arQR1R1ESGdAxY7ZheWr12wCaF2yF47v5qpB76TtV64H1pyGudk9Hvw8Y9tb/FiTIaaTRUyaSnm5T/Y53Ghm/A==}
|
||||
dev: false
|
||||
|
||||
/jsesc@2.5.2:
|
||||
resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==}
|
||||
engines: {node: '>=4'}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// src/layouts/BasicLayout.tsx
|
||||
import React from 'react';
|
||||
import ProLayout, { PageContainer } from '@ant-design/pro-layout';
|
||||
import { Link, useLocation, useIntl, useHistory } from 'umi';
|
||||
import { Link, useLocation, useIntl } from 'umi';
|
||||
import { connect } from 'dva';
|
||||
import defaultSettings from '../../config/defaultSettings';
|
||||
import routes from '../../config/router.config'; // 引入你的自定义路由结构
|
||||
@ -9,7 +9,7 @@ import { ConfigProvider, Breadcrumb } from 'antd';
|
||||
import HeaderComponent from './Header';
|
||||
import IconFont from '@/components/IconFont/IconFont';
|
||||
import type { BreadcrumbState } from '@/models/breadcrumb';
|
||||
import type { TabModelState, TabItem } from '@/models/tab';
|
||||
import type { TabModelState } from '@/models/tab';
|
||||
|
||||
const MenuRender = (item: any, isSubMenu: boolean) => {
|
||||
const intl = useIntl();
|
||||
@ -72,12 +72,9 @@ interface BasicLayoutProps {
|
||||
}
|
||||
|
||||
const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
|
||||
const { children, breadcrumb, tab, dispatch } = props;
|
||||
const { children, tab, dispatch } = props;
|
||||
const location = useLocation();
|
||||
const intl = useIntl();
|
||||
const history = useHistory();
|
||||
|
||||
console.log('tab model state:', tab);
|
||||
|
||||
const handleTabChange = (key: string) => {
|
||||
dispatch({
|
||||
@ -121,9 +118,12 @@ const BasicLayout: React.FC<BasicLayoutProps> = (props) => {
|
||||
// BreadcrumbRender(routeBreadcrumb, intl, history, breadcrumb.breadcrumbName),
|
||||
}}
|
||||
// 将tab.tabList转换为需要的格式,添加国际化处理
|
||||
tabList={tab.tabList.map(item => ({
|
||||
tabList={tab.tabList.map((item) => ({
|
||||
...item,
|
||||
tab: typeof item.tab === 'string' ? intl.formatMessage({ id: `menu.${item.tab}` }) : item.tab
|
||||
tab:
|
||||
typeof item.tab === 'string'
|
||||
? intl.formatMessage({ id: `menu.${item.tab}` })
|
||||
: item.tab,
|
||||
}))}
|
||||
tabProps={{
|
||||
type: 'editable-card',
|
||||
|
@ -13,4 +13,5 @@ export default {
|
||||
"login.register.tip": "还没有账号?",
|
||||
"login.register.action": "立即注册",
|
||||
"login.back.home": "返回首页",
|
||||
"login.captcha.placeholder": "请输入验证码",
|
||||
};
|
||||
|
@ -146,6 +146,8 @@ const TabModel: TabModelType = {
|
||||
setup({ dispatch }) {
|
||||
return history.listen((location) => {
|
||||
const { pathname } = location;
|
||||
// 需要排除的路由
|
||||
const excludeRoutes = ['/login', '/register'];
|
||||
|
||||
// 首页不做特殊处理
|
||||
if (pathname === '/') {
|
||||
@ -161,7 +163,7 @@ const TabModel: TabModelType = {
|
||||
// 查找当前路由对应的菜单项
|
||||
const currentRoute = findRouteByPath(pathname, routes);
|
||||
|
||||
if (currentRoute) {
|
||||
if (currentRoute && !excludeRoutes.includes(pathname)) {
|
||||
// 如果找到对应路由,添加或激活对应的tab
|
||||
dispatch({
|
||||
type: 'addTab',
|
||||
|
@ -289,8 +289,8 @@ const FriendLinkManage: React.FC = () => {
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'friendLink.category' }),
|
||||
dataIndex: 'categoryName',
|
||||
key: 'categoryName',
|
||||
dataIndex: 'classificationName',
|
||||
key: 'classificationName',
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'friendLink.url' }),
|
||||
|
@ -1,17 +0,0 @@
|
||||
import React from 'react';
|
||||
const LinkComponent: React.FC = () => {
|
||||
return (
|
||||
<div className="link">
|
||||
<div>友情链接</div>
|
||||
<div className="flex">
|
||||
<a href="https://www.baidu.com">百度</a>
|
||||
<a href="https://www.baidu.com">百度</a>
|
||||
<a href="https://www.baidu.com">百度</a>
|
||||
<a href="https://www.baidu.com">百度</a>
|
||||
<a href="https://www.baidu.com">百度</a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default LinkComponent;
|
@ -1,53 +0,0 @@
|
||||
@import '../../baseStyle.less';
|
||||
.lastDate {
|
||||
color: @main-danger-color;
|
||||
}
|
||||
.tableAddress {
|
||||
color: @main-color;
|
||||
font-weight: 600;
|
||||
}
|
||||
.tableLoadMore {
|
||||
margin-top: 15px;
|
||||
text-align: center;
|
||||
}
|
||||
.blockTitle {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.questionItem {
|
||||
line-height: 40px;
|
||||
.icon {
|
||||
margin-right: 10px;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
.cardContent {
|
||||
color: @main-text-color-2;
|
||||
}
|
||||
.card {
|
||||
.ant-card-head {
|
||||
min-height: 40px;
|
||||
padding: 0 15px;
|
||||
.ant-card-head-title,
|
||||
.ant-card-extra {
|
||||
padding: 10px 0;
|
||||
}
|
||||
}
|
||||
.ant-card-body {
|
||||
min-height: 150px;
|
||||
text-indent: 26px;
|
||||
}
|
||||
}
|
||||
.link {
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
.flex {
|
||||
margin-left: 10px;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
a{
|
||||
margin: 0 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,242 +1,10 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Card, Row, Col, Tabs, Table } from 'antd';
|
||||
import { useIntl, Link } from 'umi';
|
||||
import './index.less';
|
||||
import IconFont from '@/components/IconFont/IconFont';
|
||||
import LinkComponent from './Link';
|
||||
import React from 'react';
|
||||
import styles from './index.less';
|
||||
const IndexPage: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const [noticeLoading, setNoticeLoading] = useState(false);
|
||||
const [noticeList, setNoticeList] = useState([
|
||||
{
|
||||
title: 'CA使用通知',
|
||||
id: '1',
|
||||
content: '系统将于2022年5月27日期开始对全流程使用CA服务,届时全部投标供应商需办理CA。',
|
||||
},
|
||||
{
|
||||
title: '5月27日系统优化升级通知',
|
||||
id: '2',
|
||||
content:
|
||||
'系统将于2022年5月27日(周五)22:00--2022年5月28日(周六)6:00进行系统优化升级,届时系统将暂停服务。',
|
||||
},
|
||||
{
|
||||
title: '测试标题123123',
|
||||
id: '3',
|
||||
content: '测试内容124145',
|
||||
},
|
||||
{
|
||||
title: '测试标题45435',
|
||||
id: '4',
|
||||
content: '测试内容6666',
|
||||
},
|
||||
]);
|
||||
const tabList = [
|
||||
{
|
||||
key: '1',
|
||||
label: intl.formatMessage({ id: '采购需求公示' }),
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: intl.formatMessage({ id: '招标采购公告' }),
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: intl.formatMessage({ id: '非招标采购公告' }),
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
label: intl.formatMessage({ id: '资格预审公告' }),
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
label: intl.formatMessage({ id: '招募公告' }),
|
||||
},
|
||||
{
|
||||
key: '6',
|
||||
label: intl.formatMessage({ id: '变更公告' }),
|
||||
},
|
||||
{
|
||||
key: '7',
|
||||
label: intl.formatMessage({ id: '中标(中选)候选人公示' }),
|
||||
},
|
||||
{
|
||||
key: '8',
|
||||
label: intl.formatMessage({ id: '中标(中选)结果公示' }),
|
||||
},
|
||||
{
|
||||
key: '9',
|
||||
label: intl.formatMessage({ id: '采购失败(流标)公告' }),
|
||||
},
|
||||
];
|
||||
//tab 切换事件
|
||||
const tabChange = (key: string) => {
|
||||
console.log(key);
|
||||
};
|
||||
const [tableLoading, setTableLoading] = useState(false);
|
||||
const dataSource = [
|
||||
{
|
||||
key: '1',
|
||||
title: '中远海运空运北方物流基地标识制作及安装服务',
|
||||
address: '西湖区湖底公园1号',
|
||||
date: '2025年01月23日',
|
||||
lastDate: '剩余3天4小时',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
title: '中远海运空运北方物流基地标识制作及安装服务',
|
||||
address: '西湖区湖底公园1号',
|
||||
date: '2025年01月23日',
|
||||
lastDate: '剩余3天4小时',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
title: '中远海运空运北方物流基地标识制作及安装服务',
|
||||
address: '西湖区湖底公园1号',
|
||||
date: '2025年01月23日',
|
||||
lastDate: '剩余3天4小时',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
title: '中远海运空运北方物流基地标识制作及安装服务',
|
||||
address: '西湖区湖底公园1号',
|
||||
date: '2025年01月23日',
|
||||
lastDate: '剩余3天4小时',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
title: '中远海运空运北方物流基地标识制作及安装服务',
|
||||
address: '西湖区湖底公园1号',
|
||||
date: '2025年01月23日',
|
||||
lastDate: '剩余3天4小时',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
title: '中远海运空运北方物流基地标识制作及安装服务',
|
||||
address: '西湖区湖底公园1号',
|
||||
date: '2025年01月23日',
|
||||
lastDate: '剩余3天4小时',
|
||||
},
|
||||
];
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '项目所在地',
|
||||
dataIndex: 'address',
|
||||
key: 'address',
|
||||
},
|
||||
{
|
||||
title: '公告标题',
|
||||
dataIndex: 'title',
|
||||
key: 'title',
|
||||
render: (text: string, record) => (
|
||||
<Link
|
||||
to={{
|
||||
pathname: '/announce/announceInfo',
|
||||
search: '?id=' + record.id,
|
||||
}}
|
||||
>
|
||||
{text}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '发布时间',
|
||||
dataIndex: 'date',
|
||||
key: 'date',
|
||||
},
|
||||
{
|
||||
title: '文件购买截止时间',
|
||||
dataIndex: 'lastDate',
|
||||
key: 'lastDate',
|
||||
render: (text: string) => <span className="lastDate">{text}</span>,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* 通知列表 */}
|
||||
<Row gutter={20}>
|
||||
{noticeList.map((item) => (
|
||||
<Col span={6} key={item.id}>
|
||||
<Card
|
||||
title={item.title}
|
||||
loading={noticeLoading}
|
||||
hoverable
|
||||
className="card"
|
||||
bodyStyle={{ padding: 10 }}
|
||||
extra={
|
||||
<Link
|
||||
to={{
|
||||
pathname: '/notice/noticeInfo',
|
||||
search: '?id=' + item.id,
|
||||
}}
|
||||
>
|
||||
{intl.formatMessage({ id: '查看' })}
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
<p className="cardContent">{item.content}</p>
|
||||
</Card>
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
<Tabs onChange={tabChange}>
|
||||
{tabList.map((item) => (
|
||||
<Tabs.TabPane tab={item.label} key={item.key} />
|
||||
))}
|
||||
</Tabs>
|
||||
|
||||
<Table loading={tableLoading} dataSource={dataSource} columns={columns} pagination={false} />
|
||||
|
||||
<div className="tableLoadMore">
|
||||
<Link
|
||||
to={{
|
||||
pathname: '/announce',
|
||||
}}
|
||||
>
|
||||
{intl.formatMessage({ id: '加载更多' })}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Row style={{ marginTop: '20px', backgroundColor: '#fff' }}>
|
||||
<Col span={12}>
|
||||
<div className="blockTitle">紧急问题咨询</div>
|
||||
<img src="" alt="" />
|
||||
<div className="questionItem">
|
||||
<IconFont type="icon-dizhi" className="icon" />
|
||||
北京市前门大街173号
|
||||
</div>
|
||||
<div className="questionItem">
|
||||
<IconFont type="icon-dianhua" className="icon" />
|
||||
17676373746
|
||||
</div>
|
||||
<div className="questionItem">
|
||||
<IconFont type="icon-youxiang" className="icon" />
|
||||
i723648723@383.com
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div className="blockTitle">CA服务</div>
|
||||
<Row>
|
||||
<Col span={6} offset={6}>
|
||||
<span>CA办理</span>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
<span>CA客服</span>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<div className="blockTitle">联系方式</div>
|
||||
<p style={{ marginTop: 20 }}>客服1: 400-300-9989</p>
|
||||
<p>客服1: 400-300-9989</p>
|
||||
<p>客服1: 400-300-9989</p>
|
||||
<p>客服1: 400-300-9989</p>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<div>
|
||||
<LinkComponent />
|
||||
</div>
|
||||
<div className="common-container">
|
||||
首页
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,28 +1,75 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Form, Input, Button, Checkbox, Tabs, message } from 'antd';
|
||||
import { UserOutlined, LockOutlined, EyeInvisibleOutlined, EyeTwoTone, HomeOutlined } from '@ant-design/icons';
|
||||
import { history, useIntl } from 'umi';
|
||||
import './login.less';
|
||||
import { getCaptcha, supplierLogin, expertLogin, accountLogin } from '@/servers/api/login';
|
||||
|
||||
import { encryptWithRsa } from '@/utils/encryptWithRsa'
|
||||
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
const LoginPage: React.FC = () => {
|
||||
const [activeKey, setActiveKey] = useState('supplier');
|
||||
const [activeKey, setActiveKey] = useState('supplierLogin');
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [captchaImg, setCaptchaImg] = useState<string>('');
|
||||
const [captchaKey, setCaptchaKey] = useState<string>('');
|
||||
//切换后 走不同接口
|
||||
const loginApiMap: { [key: string]: (params: any) => Promise<any> } = {
|
||||
supplierLogin,
|
||||
expertLogin,
|
||||
accountLogin
|
||||
};
|
||||
|
||||
const intl = useIntl();
|
||||
|
||||
const onFinish = (values: any) => {
|
||||
|
||||
const onFinish = async (values: any) => {
|
||||
setLoading(true);
|
||||
console.log('登录信息:', values);
|
||||
// 这里添加登录逻辑
|
||||
setTimeout(() => {
|
||||
setLoading(false);
|
||||
try {
|
||||
const params = {
|
||||
...values,
|
||||
password: encryptWithRsa(values.password, false),
|
||||
encryptValue: encryptWithRsa(values.identifying)
|
||||
};
|
||||
const loginRes = await loginApiMap[activeKey](params);
|
||||
if (loginRes.code === 200) {
|
||||
sessionStorage.setItem('token', loginRes.data.token);
|
||||
//存入供应商用户id
|
||||
if(activeKey === 'supplierLogin') {
|
||||
sessionStorage.setItem('userId', loginRes.data.supplierUser.userId);
|
||||
} else if(activeKey === 'expertLogin') {
|
||||
//存入专家用户id
|
||||
// sessionStorage.setItem('userId', loginRes.data.expertUser.userId);
|
||||
} else if(activeKey === 'accountLogin') {
|
||||
//存入招标代理用户id
|
||||
// sessionStorage.setItem('userId', loginRes.data.supplierUser.userId);
|
||||
}
|
||||
sessionStorage.setItem('currentUser', JSON.stringify(loginRes.data));
|
||||
message.success('登录成功');
|
||||
history.push('/index');
|
||||
}, 1000);
|
||||
} 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);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchCaptcha();
|
||||
}, [activeKey]);
|
||||
|
||||
const handleTabChange = (key: string) => {
|
||||
setActiveKey(key);
|
||||
form.resetFields();
|
||||
@ -31,10 +78,10 @@ const LoginPage: React.FC = () => {
|
||||
// 根据当前选中的Tab决定跳转到哪个注册页面
|
||||
const handleRegister = () => {
|
||||
switch(activeKey) {
|
||||
case 'supplier':
|
||||
case 'supplierLogin':
|
||||
history.push('/register/supplier');
|
||||
break;
|
||||
case 'expert':
|
||||
case 'expertLogin':
|
||||
history.push('/register/expert');
|
||||
break;
|
||||
default:
|
||||
@ -62,18 +109,19 @@ const LoginPage: React.FC = () => {
|
||||
return (
|
||||
<div className='login-page'>
|
||||
<div className='login-container'>
|
||||
<div className='back-home'>
|
||||
{/* <div className='back-home'>
|
||||
<a onClick={() => history.push('/index')}>
|
||||
<HomeOutlined /> {intl.formatMessage({ id: 'login.back.home' })}
|
||||
</a>
|
||||
</div>
|
||||
</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.manager' })} key="supplier" />
|
||||
<TabPane tab={intl.formatMessage({ id: 'login.tab.agent' })} key="agent" />
|
||||
<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>
|
||||
|
||||
@ -85,7 +133,7 @@ const LoginPage: React.FC = () => {
|
||||
onFinish={onFinish}
|
||||
>
|
||||
<Form.Item
|
||||
name="username"
|
||||
name="account"
|
||||
rules={[{ required: true, message: intl.formatMessage({ id: 'login.username.placeholder' }) + '!' }]}
|
||||
>
|
||||
<Input
|
||||
@ -106,6 +154,26 @@ const LoginPage: React.FC = () => {
|
||||
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'>
|
||||
@ -122,6 +190,7 @@ const LoginPage: React.FC = () => {
|
||||
<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>
|
||||
|
41
src/servers/api/login.ts
Normal file
41
src/servers/api/login.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 验证码
|
||||
*/
|
||||
export async function getCaptcha() {
|
||||
return request('/v1/login/getCaptcha', {
|
||||
method: 'GET'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 招标代理
|
||||
*/
|
||||
export async function accountLogin (data: API.LoginSupplier) {
|
||||
return request('/v1/login/accountLogin', {
|
||||
method: 'POST',
|
||||
data
|
||||
});
|
||||
}
|
||||
/**
|
||||
* 专家
|
||||
*/
|
||||
export async function expertLogin (data: API.LoginSupplier) {
|
||||
return request('/v1/login/expertLogin', {
|
||||
method: 'POST',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 供应商
|
||||
*/
|
||||
export async function supplierLogin (data: API.LoginSupplier) {
|
||||
return request('/v1/login/accountLogin/supplier', {
|
||||
method: 'POST',
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
|
8
src/servers/api/typings.d.ts
vendored
8
src/servers/api/typings.d.ts
vendored
@ -5,7 +5,13 @@ declare namespace API {
|
||||
message: string;
|
||||
data: T;
|
||||
}
|
||||
|
||||
//登录
|
||||
interface LoginSupplier {
|
||||
account: string;
|
||||
password: string;
|
||||
identifying: string;
|
||||
encryptValue: string;
|
||||
}
|
||||
export type PolicyRequest = {
|
||||
/**
|
||||
* 内容
|
||||
|
21
src/utils/encryptWithRsa.ts
Normal file
21
src/utils/encryptWithRsa.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import JSEncrypt from 'jsencrypt';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
const PUBLIC_KEY = `-----BEGIN PUBLIC KEY-----
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCvLBkALIYR/x9Rv5TiXQGWAXTzraN/He80r9gQovSQ5oTP8qllL9+Oc1LdTijPFRsddHWg37umvFliwhmukU1NT+o2loGcKpyMHFkc/UPNjQLvd+YFR4nYhgP8l+dmRNOtQWawOt5dbksRKTghMjA+FKT2+itMsawSs1+Ic+zoIwIDAQAB
|
||||
-----END PUBLIC KEY-----`;
|
||||
|
||||
export function encryptWithRsa(value: string, type: boolean = true, publicKey: string = PUBLIC_KEY): string {
|
||||
const nowStr = dayjs().format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
const content = type? `${value}_${nowStr}`: value;
|
||||
const encryptor = new JSEncrypt();
|
||||
encryptor.setPublicKey(publicKey);
|
||||
const encrypted = encryptor.encrypt(content);
|
||||
if (!encrypted) {
|
||||
throw new Error('RSA 加密失败');
|
||||
}
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user