From aa8349d54936b530a822ccd705878c10aa19e26b Mon Sep 17 00:00:00 2001 From: linxd <544554903@qq.com> Date: Mon, 14 Jul 2025 14:00:12 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8E=A5=E5=85=A5=E7=99=BB=E5=BD=95=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- config/proxy.ts | 9 +- package.json | 2 + pnpm-lock.yaml | 10 + src/layouts/BasicLayout.tsx | 16 +- src/locales/zh-CN/login.ts | 1 + src/models/tab.ts | 4 +- .../friendLinkManage/friendLinkManage.tsx | 4 +- src/pages/index/Link.tsx | 17 -- src/pages/index/index.less | 53 ---- src/pages/index/index.tsx | 240 +----------------- src/pages/login/login.tsx | 101 ++++++-- src/servers/api/login.ts | 41 +++ src/servers/api/typings.d.ts | 8 +- src/utils/encryptWithRsa.ts | 21 ++ 14 files changed, 191 insertions(+), 336 deletions(-) delete mode 100644 src/pages/index/Link.tsx create mode 100644 src/servers/api/login.ts create mode 100644 src/utils/encryptWithRsa.ts diff --git a/config/proxy.ts b/config/proxy.ts index b87da51..b9068c1 100644 --- a/config/proxy.ts +++ b/config/proxy.ts @@ -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': '' }, }, diff --git a/package.json b/package.json index 0c3845e..fce5752 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b8db067..14521a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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'} diff --git a/src/layouts/BasicLayout.tsx b/src/layouts/BasicLayout.tsx index 2b5bedf..eb47638 100644 --- a/src/layouts/BasicLayout.tsx +++ b/src/layouts/BasicLayout.tsx @@ -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 = (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 = (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', diff --git a/src/locales/zh-CN/login.ts b/src/locales/zh-CN/login.ts index e00f4f8..75c6084 100644 --- a/src/locales/zh-CN/login.ts +++ b/src/locales/zh-CN/login.ts @@ -13,4 +13,5 @@ export default { "login.register.tip": "还没有账号?", "login.register.action": "立即注册", "login.back.home": "返回首页", + "login.captcha.placeholder": "请输入验证码", }; diff --git a/src/models/tab.ts b/src/models/tab.ts index 56a14f4..8588929 100644 --- a/src/models/tab.ts +++ b/src/models/tab.ts @@ -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', diff --git a/src/pages/friendLinkManage/friendLinkManage.tsx b/src/pages/friendLinkManage/friendLinkManage.tsx index 9466277..2fbc906 100644 --- a/src/pages/friendLinkManage/friendLinkManage.tsx +++ b/src/pages/friendLinkManage/friendLinkManage.tsx @@ -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' }), diff --git a/src/pages/index/Link.tsx b/src/pages/index/Link.tsx deleted file mode 100644 index 567b11c..0000000 --- a/src/pages/index/Link.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -const LinkComponent: React.FC = () => { - return ( -
-
友情链接
-
- 百度 - 百度 - 百度 - 百度 - 百度 -
-
- ); -}; - -export default LinkComponent; diff --git a/src/pages/index/index.less b/src/pages/index/index.less index 1a528f6..e69de29 100644 --- a/src/pages/index/index.less +++ b/src/pages/index/index.less @@ -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; - } - } -} diff --git a/src/pages/index/index.tsx b/src/pages/index/index.tsx index 5ba3efb..7016320 100644 --- a/src/pages/index/index.tsx +++ b/src/pages/index/index.tsx @@ -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) => ( - {text}, - }, - ]; return ( -
- {/* 通知列表 */} - - {noticeList.map((item) => ( - - - } - > -

{item.content}

-
- - ))} -
- - {tabList.map((item) => ( - - ))} - - - - -
- - {intl.formatMessage({ id: '加载更多' })} - -
- - - -
紧急问题咨询
- -
- - 北京市前门大街173号 -
-
- - 17676373746 -
-
- - i723648723@383.com -
- - -
CA服务
- - - CA办理 - - - CA客服 - - - -
联系方式
-

客服1: 400-300-9989

-

客服1: 400-300-9989

-

客服1: 400-300-9989

-

客服1: 400-300-9989

- - - -
- -
+
+ 首页
); }; diff --git a/src/pages/login/login.tsx b/src/pages/login/login.tsx index 870d61e..304e1b9 100644 --- a/src/pages/login/login.tsx +++ b/src/pages/login/login.tsx @@ -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(''); + const [captchaKey, setCaptchaKey] = useState(''); + //切换后 走不同接口 + const loginApiMap: { [key: string]: (params: any) => Promise } = { + supplierLogin, + expertLogin, + accountLogin + }; + const intl = useIntl(); - const onFinish = (values: any) => { + + const onFinish = async (values: any) => { setLoading(true); - console.log('登录信息:', values); - // 这里添加登录逻辑 - setTimeout(() => { + 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'); + } else { + message.error(loginRes.message || '登录失败'); + } + } finally { setLoading(false); - message.success('登录成功'); - history.push('/index'); - }, 1000); + } }; + + 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 (
- */}
{intl.formatMessage({ id: 'login.title' })}
- - + + +
@@ -85,7 +133,7 @@ const LoginPage: React.FC = () => { onFinish={onFinish} > { size="large" /> + + + } + /> +
@@ -122,6 +190,7 @@ const LoginPage: React.FC = () => { + {activeKey !== 'accountLogin' && renderRegisterLink()}
diff --git a/src/servers/api/login.ts b/src/servers/api/login.ts new file mode 100644 index 0000000..fdff6d4 --- /dev/null +++ b/src/servers/api/login.ts @@ -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 + }); +} + + diff --git a/src/servers/api/typings.d.ts b/src/servers/api/typings.d.ts index dbdc259..1b90848 100644 --- a/src/servers/api/typings.d.ts +++ b/src/servers/api/typings.d.ts @@ -5,7 +5,13 @@ declare namespace API { message: string; data: T; } - + //登录 + interface LoginSupplier { + account: string; + password: string; + identifying: string; + encryptValue: string; + } export type PolicyRequest = { /** * 内容 diff --git a/src/utils/encryptWithRsa.ts b/src/utils/encryptWithRsa.ts new file mode 100644 index 0000000..caa1162 --- /dev/null +++ b/src/utils/encryptWithRsa.ts @@ -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; +} + +