Compare commits
10 Commits
a419834198
...
dev
Author | SHA1 | Date | |
---|---|---|---|
9ed0e58454 | |||
1ee084d211 | |||
09c06d14e9 | |||
48ca4e9069 | |||
c7ae51ebd3 | |||
49105505fa | |||
747cceeb18 | |||
0af9171acd | |||
98de83d5f1 | |||
d8bdf33e79 |
@ -5,5 +5,7 @@ export default defineConfig({
|
|||||||
define: {
|
define: {
|
||||||
UPLOAD_URL: '/upload',
|
UPLOAD_URL: '/upload',
|
||||||
REQUEST_BASE: '/api',
|
REQUEST_BASE: '/api',
|
||||||
|
// 跳转注册地址 后面可追加 /expert (专家注册) /supplier (供应商注册)
|
||||||
|
REGISTER_URL: 'http://localhost:3002/register',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
15
src/app.tsx
Normal file
15
src/app.tsx
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// src/app.ts
|
||||||
|
import { message } from 'antd';
|
||||||
|
import { refreshDictCache } from './servers/api';
|
||||||
|
|
||||||
|
export async function getInitialState() {
|
||||||
|
try {
|
||||||
|
const res = await refreshDictCache();
|
||||||
|
if (res.code == 200) {
|
||||||
|
sessionStorage.setItem('dict', JSON.stringify(res.data));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
message.error('初始化失败');
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +1,23 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Divider, Select } from 'antd';
|
import { Divider, Select } from 'antd';
|
||||||
|
import { useIntl } from 'umi';
|
||||||
import { getCoscoPortalsLinksClassification } from '@/servers/api';
|
import { getCoscoPortalsLinksClassification } from '@/servers/api';
|
||||||
|
|
||||||
const Footer: React.FC = () => {
|
const Footer: React.FC = () => {
|
||||||
|
const intl = useIntl();
|
||||||
const [links, setLinks] = useState<API.CoscoPortalsLinksClassification>([]);
|
const [links, setLinks] = useState<API.CoscoPortalsLinksClassification>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getCoscoPortalsLinksClassification().then((res) => {
|
getCoscoPortalsLinksClassification().then((res) => {
|
||||||
setLinks(res.data);
|
setLinks(res.data);
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="footer">
|
<div className="footer">
|
||||||
<div className="footer-content">
|
<div className="footer-content">
|
||||||
<div className="link">
|
<div className="link">
|
||||||
<div>友情链接</div>
|
<div>{intl.formatMessage({ id: 'footer.friendLinks.title' })}</div>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
{links.map((link) => (
|
{links.map((link) => (
|
||||||
<>
|
<>
|
||||||
@ -43,11 +47,13 @@ const Footer: React.FC = () => {
|
|||||||
<img src={require('@/assets/img/logoWhite.png')} className="footerLogo" alt="" />
|
<img src={require('@/assets/img/logoWhite.png')} className="footerLogo" alt="" />
|
||||||
<div className="copyright-text">
|
<div className="copyright-text">
|
||||||
<div className="copyright-text-item">
|
<div className="copyright-text-item">
|
||||||
<span>网站首页</span>
|
<span>{intl.formatMessage({ id: 'footer.nav.home' })}</span>
|
||||||
<span>消息通知</span>
|
<span>{intl.formatMessage({ id: 'footer.nav.notifications' })}</span>
|
||||||
<span>公示公告</span>
|
<span>{intl.formatMessage({ id: 'footer.nav.announcements' })}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
{intl.formatMessage({ id: 'footer.copyright' })}
|
||||||
</div>
|
</div>
|
||||||
<div>Copyright ©中国远洋海运集团有限公司</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Menu } from 'antd';
|
import { Menu } from 'antd';
|
||||||
import Language from './Language';
|
import Language from './Language';
|
||||||
import { useIntl, Link, useHistory } from 'umi';
|
import { useIntl, Link, useHistory, useLocation } from 'umi';
|
||||||
import User from './User';
|
import User from './User';
|
||||||
interface IMenuItem {
|
interface IMenuItem {
|
||||||
label: string;
|
label: string;
|
||||||
@ -51,19 +51,17 @@ const HeaderMenu: React.FC = (props) => {
|
|||||||
//当前激活菜单
|
//当前激活菜单
|
||||||
const [current, setCurrent] = useState('index');
|
const [current, setCurrent] = useState('index');
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const history = useHistory();
|
const location = useLocation();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 获取当前激活菜单
|
const path = location.pathname;
|
||||||
const path = history.location.pathname;
|
|
||||||
const menu = items.find((item) => item.path === path);
|
const menu = items.find((item) => item.path === path);
|
||||||
if (menu) {
|
if (menu) {
|
||||||
setCurrent(menu.key);
|
setCurrent(menu.key);
|
||||||
}else{
|
} else {
|
||||||
// 如果跳转的详情页面获取根级激活菜单
|
|
||||||
const rootActiveMenu = path.split('/')[1];
|
const rootActiveMenu = path.split('/')[1];
|
||||||
setCurrent(rootActiveMenu);
|
setCurrent(rootActiveMenu);
|
||||||
}
|
}
|
||||||
}, [history.location.pathname]);
|
}, [location.pathname]);
|
||||||
return (
|
return (
|
||||||
<div className="header-menu">
|
<div className="header-menu">
|
||||||
<Menu selectedKeys={[current]} mode="horizontal">
|
<Menu selectedKeys={[current]} mode="horizontal">
|
||||||
|
@ -5,6 +5,7 @@ import policy from './en-US/policy';
|
|||||||
import register from './en-US/register';
|
import register from './en-US/register';
|
||||||
import home from './en-US/home';
|
import home from './en-US/home';
|
||||||
import login from './en-US/login';
|
import login from './en-US/login';
|
||||||
|
import footer from './en-US/footer';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
'menu.首页': 'Home',
|
'menu.首页': 'Home',
|
||||||
@ -61,4 +62,5 @@ export default {
|
|||||||
|
|
||||||
// Login page
|
// Login page
|
||||||
...login,
|
...login,
|
||||||
|
...footer
|
||||||
};
|
};
|
||||||
|
8
src/locales/en-US/footer.ts
Normal file
8
src/locales/en-US/footer.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export default {
|
||||||
|
// Footer
|
||||||
|
"footer.friendLinks.title": "Friend Links",
|
||||||
|
"footer.nav.home": "Home",
|
||||||
|
"footer.nav.notifications": "Notifications",
|
||||||
|
"footer.nav.announcements": "Announcements",
|
||||||
|
"footer.copyright": "Copyright © China COSCO Shipping Corporation Limited",
|
||||||
|
}
|
@ -1,7 +1,49 @@
|
|||||||
export default {
|
export default {
|
||||||
'home.data.contactsPhone': 'contactsPhoneEn',
|
// Homepage
|
||||||
'home.data.contactsEmail': 'contactsEmailEn',
|
"home.notice.title": "Notices",
|
||||||
'home.data.address': 'addressEn',
|
"home.button.enterNow": "Enter Now",
|
||||||
'home.data.addressEn': 'address',
|
"home.button.registerNow": "Register Now",
|
||||||
'home.data.contactsConsult': 'contactsConsultEn',
|
|
||||||
|
// Entry
|
||||||
|
"home.entry.supplier.title": "Supplier Entrance",
|
||||||
|
"home.entry.supplier.desc": "Supplier registration, bidding, contract management, settlement, and full-process services",
|
||||||
|
"home.entry.expert.title": "Procurement Expert Entrance",
|
||||||
|
"home.entry.expert.desc": "Procurement requirement release, review, contract signing, supplier management and other services",
|
||||||
|
"home.entry.agent.title": "Bidding Agent Entrance",
|
||||||
|
"home.entry.agent.desc": "Tender document preparation, announcement release, bid opening and evaluation, and other professional services",
|
||||||
|
|
||||||
|
// Procurement types
|
||||||
|
"home.procurement.title": "Procurement Types",
|
||||||
|
"home.procurement.type1": "Procurement Demand Announcement",
|
||||||
|
"home.procurement.type2": "Tender Procurement Announcement",
|
||||||
|
"home.procurement.type3": "Non-Tender Procurement Announcement",
|
||||||
|
"home.procurement.type4": "Prequalification Announcement",
|
||||||
|
"home.procurement.type5": "Recruitment Announcement",
|
||||||
|
"home.procurement.type6": "Change Announcement",
|
||||||
|
"home.procurement.type7": "Bid (Selection) Candidate Announcement",
|
||||||
|
"home.procurement.type8": "Bid (Selection) Result Announcement",
|
||||||
|
"home.procurement.type9": "Procurement Failure (Bidding Failure) Announcement",
|
||||||
|
|
||||||
|
// Table
|
||||||
|
"home.table.col.address": "Project Location",
|
||||||
|
"home.table.col.title": "Announcement Title",
|
||||||
|
"home.table.col.publishTime": "Publish Time",
|
||||||
|
"home.table.col.deadline": "Document Purchase Deadline",
|
||||||
|
"home.table.sampleTitle": "COSCO Air Transport Northern Logistics Base Signage Production and Installation Service",
|
||||||
|
"home.table.sampleAddress": "No.1, Underwater Park, Xihu District",
|
||||||
|
"home.table.remainingTime": "3 days 4 hours remaining",
|
||||||
|
|
||||||
|
// About us
|
||||||
|
"home.question.title": "Consultation Methods",
|
||||||
|
|
||||||
|
// CA Service
|
||||||
|
"home.ca.title": "Service",
|
||||||
|
"home.ca.handle": "CA Handling",
|
||||||
|
"home.ca.service": "CA Support",
|
||||||
|
|
||||||
|
// Contact
|
||||||
|
"home.contact.title": "Contact Information",
|
||||||
|
|
||||||
|
// Friend links
|
||||||
|
"home.friendlink.title": "Friend Links",
|
||||||
};
|
};
|
||||||
|
@ -5,6 +5,7 @@ import policy from './zh-CN/policy';
|
|||||||
import register from './zh-CN/register';
|
import register from './zh-CN/register';
|
||||||
import home from './zh-CN/home';
|
import home from './zh-CN/home';
|
||||||
import login from './zh-CN/login';
|
import login from './zh-CN/login';
|
||||||
|
import footer from './zh-CN/footer';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
'menu.首页': '首页',
|
'menu.首页': '首页',
|
||||||
@ -61,4 +62,5 @@ export default {
|
|||||||
|
|
||||||
// Login page
|
// Login page
|
||||||
...login,
|
...login,
|
||||||
|
...footer
|
||||||
};
|
};
|
||||||
|
8
src/locales/zh-CN/footer.ts
Normal file
8
src/locales/zh-CN/footer.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export default {
|
||||||
|
// Footer
|
||||||
|
"footer.friendLinks.title": "友情链接",
|
||||||
|
"footer.nav.home": "网站首页",
|
||||||
|
"footer.nav.notifications": "消息通知",
|
||||||
|
"footer.nav.announcements": "公示公告",
|
||||||
|
"footer.copyright": "Copyright ©中国远洋海运集团有限公司",
|
||||||
|
}
|
@ -1,7 +1,49 @@
|
|||||||
export default {
|
export default {
|
||||||
'home.data.contactsPhone': 'contactsPhone',
|
// 首页
|
||||||
'home.data.contactsEmail': 'contactsEmail',
|
"home.notice.title": "通知公告",
|
||||||
'home.data.address': 'address',
|
"home.button.enterNow": "立即进入",
|
||||||
'home.data.addressEn': 'addressEn',
|
"home.button.registerNow": "立即注册",
|
||||||
'home.data.contactsConsult': 'contactsConsult',
|
|
||||||
|
// 登录入口
|
||||||
|
"home.entry.supplier.title": "供应商入口",
|
||||||
|
"home.entry.supplier.desc": "供应商注册、投标、合同管理、结算等全流程服务",
|
||||||
|
"home.entry.expert.title": "采购专家入口",
|
||||||
|
"home.entry.expert.desc": "采购需求发布、评审、合同签订、供应商管理等服务",
|
||||||
|
"home.entry.agent.title": "招标代理入口",
|
||||||
|
"home.entry.agent.desc": "招标文件编制、公告发布、开标评标等专业服务",
|
||||||
|
|
||||||
|
// 采购类型
|
||||||
|
"home.procurement.title": "采购类型",
|
||||||
|
"home.procurement.type1": "采购需求公示",
|
||||||
|
"home.procurement.type2": "招标采购公告",
|
||||||
|
"home.procurement.type3": "非招标采购公告",
|
||||||
|
"home.procurement.type4": "资格预审公告",
|
||||||
|
"home.procurement.type5": "招募公告",
|
||||||
|
"home.procurement.type6": "变更公告",
|
||||||
|
"home.procurement.type7": "中标(中选)候选人公示",
|
||||||
|
"home.procurement.type8": "中标(中选)结果公示",
|
||||||
|
"home.procurement.type9": "采购失败(流标)公告",
|
||||||
|
|
||||||
|
// 表格
|
||||||
|
"home.table.col.address": "项目所在地",
|
||||||
|
"home.table.col.title": "公告标题",
|
||||||
|
"home.table.col.publishTime": "发布时间",
|
||||||
|
"home.table.col.deadline": "文件购买截止时间",
|
||||||
|
"home.table.sampleTitle": "中远海运空运北方物流基地标识制作及安装服务",
|
||||||
|
"home.table.sampleAddress": "西湖区湖底公园1号",
|
||||||
|
"home.table.remainingTime": "剩余3天4小时",
|
||||||
|
|
||||||
|
// 关于我们
|
||||||
|
"home.question.title": "问题咨询方式",
|
||||||
|
|
||||||
|
// CA 服务
|
||||||
|
"home.ca.title": "服务",
|
||||||
|
"home.ca.handle": "CA办理",
|
||||||
|
"home.ca.service": "CA客服",
|
||||||
|
|
||||||
|
// 联系方式
|
||||||
|
"home.contact.title": "联系方式",
|
||||||
|
|
||||||
|
// 友情链接
|
||||||
|
"home.friendlink.title": "友情链接",
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
@import '~antd/es/style/themes/default.less';
|
@import '~antd/es/style/themes/default.less';
|
||||||
|
@import '~@/baseStyle.less';
|
||||||
|
|
||||||
.aboutContainer {
|
.aboutContainer {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
@ -7,9 +8,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.aboutContent {
|
.aboutContent {
|
||||||
max-width: 1200px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
width: @width;
|
||||||
|
margin: 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.aboutTitle {
|
.aboutTitle {
|
||||||
|
@ -64,46 +64,7 @@ const AboutPage: React.FC = () => {
|
|||||||
<Title level={2}>{intl.formatMessage({ id: 'about.title' })}</Title>
|
<Title level={2}>{intl.formatMessage({ id: 'about.title' })}</Title>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.aboutSection}>
|
<div className={styles.aboutContent} dangerouslySetInnerHTML={{ __html: content }} />
|
||||||
<Title level={3} className={styles.sectionTitle}>
|
|
||||||
{intl.formatMessage({ id: 'about.company.title' })}
|
|
||||||
</Title>
|
|
||||||
<div className={styles.sectionContent}>
|
|
||||||
<div className={styles.contentHtml} dangerouslySetInnerHTML={{ __html: content }} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Divider />
|
|
||||||
|
|
||||||
<div className={styles.aboutSection}>
|
|
||||||
<Title level={3} className={styles.sectionTitle}>
|
|
||||||
{intl.formatMessage({ id: 'about.contact.title' })}
|
|
||||||
</Title>
|
|
||||||
<div className={styles.sectionContent}>
|
|
||||||
<div className={styles.companyInfo}>
|
|
||||||
<div className={styles.infoItem}>
|
|
||||||
<span className={styles.label}>{intl.formatMessage({ id: 'about.address' })}:</span>
|
|
||||||
<span>{address}</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.infoItem}>
|
|
||||||
<span className={styles.label}>{intl.formatMessage({ id: 'about.phone' })}:</span>
|
|
||||||
<span>{contactsPhone}</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.infoItem}>
|
|
||||||
<span className={styles.label}>{intl.formatMessage({ id: 'about.hotline' })}:</span>
|
|
||||||
<span>{contactsConsult}</span>
|
|
||||||
</div>
|
|
||||||
<div className={styles.infoItem}>
|
|
||||||
<span className={styles.label}>{intl.formatMessage({ id: 'about.email' })}:</span>
|
|
||||||
<span>{contactsEmail}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.aboutFooter}>
|
|
||||||
<Paragraph>{intl.formatMessage({ id: 'about.copyright' })}</Paragraph>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -13,7 +13,7 @@ const { Title, Text } = Typography;
|
|||||||
|
|
||||||
const DownloadPage: React.FC = () => {
|
const DownloadPage: React.FC = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [activeMenu, setActiveMenu] = useState<string>('template');
|
const [activeMenu, setActiveMenu] = useState<string>();
|
||||||
const [menuList, setMenuList] = useState<DictItem[]>([]);
|
const [menuList, setMenuList] = useState<DictItem[]>([]);
|
||||||
const [downloadData, setDownloadData] = useState<DownloadRecord[]>([]);
|
const [downloadData, setDownloadData] = useState<DownloadRecord[]>([]);
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
@ -29,7 +29,8 @@ const DownloadPage: React.FC = () => {
|
|||||||
try {
|
try {
|
||||||
const response = await getDownloadList({
|
const response = await getDownloadList({
|
||||||
pageNo: page.toString(),
|
pageNo: page.toString(),
|
||||||
pageSize: pageSize.toString()
|
pageSize: pageSize.toString(),
|
||||||
|
columnType:activeMenu
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.code === 200 && response.success) {
|
if (response.code === 200 && response.success) {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 20px;
|
// margin-bottom: 20px;
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
@ -34,4 +34,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.ant-tabs-nav {
|
||||||
|
&::before {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,43 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
import { Table, Typography, Button } from 'antd';
|
import { Table, Typography, Button, Tabs } from 'antd';
|
||||||
import { history, useIntl } from 'umi';
|
import { history, useIntl, connect } from 'umi';
|
||||||
|
import type { ConnectProps, Dispatch } from 'umi';
|
||||||
import { PlusOutlined } from '@ant-design/icons';
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
import { getHelpCenterList } from '@/servers/api/help';
|
import { getHelpCenterList, qandaGetPage } from '@/servers/api/help';
|
||||||
|
import type { UserModelState } from '@/models/user';
|
||||||
import { QUESTION_TYPES } from '@/dicts/help';
|
import { QUESTION_TYPES } from '@/dicts/help';
|
||||||
import './help.less';
|
import './help.less';
|
||||||
|
import type { UserInfo } from '@/models/user';
|
||||||
|
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
|
interface PageProps extends ConnectProps {
|
||||||
const HelpPage: React.FC = () => {
|
user: UserModelState; // dva model状态
|
||||||
|
dispatch: Dispatch; // dva dispatch方法
|
||||||
|
}
|
||||||
|
const HelpPage: React.FC<PageProps> = ({ user, dispatch }) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [helpData, setHelpData] = useState<API.HelpCenterRecord[]>([]);
|
const [helpData, setHelpData] = useState<API.HelpCenterRecord[]>([]);
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
|
const userInfo: UserInfo | undefined = user.userInfo;
|
||||||
const [pagination, setPagination] = useState({
|
const [pagination, setPagination] = useState({
|
||||||
current: 1,
|
current: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const tabActiveKey = useRef<string>('helpCenter');
|
||||||
// 获取帮助中心数据
|
// 获取帮助中心数据
|
||||||
const fetchHelpData = async (current = 1, pageSize = 10) => {
|
const fetchHelpData = async (current = 1, pageSize = 10) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
console.log(userInfo?.userId);
|
||||||
|
const request = tabActiveKey.current == 'helpCenter' ? getHelpCenterList : qandaGetPage;
|
||||||
try {
|
try {
|
||||||
const response = await getHelpCenterList({
|
const response = await request({
|
||||||
basePageRequest: {
|
basePageRequest: {
|
||||||
pageNo: current,
|
pageNo: current,
|
||||||
pageSize: pageSize,
|
pageSize: pageSize,
|
||||||
},
|
},
|
||||||
|
createBy: tabActiveKey.current == 'myQuestion' ? userInfo?.userId : null
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
@ -56,7 +67,7 @@ const HelpPage: React.FC = () => {
|
|||||||
|
|
||||||
// 处理点击问题标题
|
// 处理点击问题标题
|
||||||
const handleHelpClick = (id: string) => {
|
const handleHelpClick = (id: string) => {
|
||||||
history.push(`/help/helpInfo?id=${id}`);
|
history.push(`/help/helpInfo?id=${id}&tabActiveKey=${tabActiveKey.current}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理点击提问按钮
|
// 处理点击提问按钮
|
||||||
@ -66,7 +77,7 @@ const HelpPage: React.FC = () => {
|
|||||||
|
|
||||||
// 获取问题分类名称
|
// 获取问题分类名称
|
||||||
const getQuestionTypeName = (type: string) => {
|
const getQuestionTypeName = (type: string) => {
|
||||||
const found = QUESTION_TYPES.find(item => item.value === type);
|
const found = QUESTION_TYPES.find((item) => item.value === type);
|
||||||
return found ? found.label : type;
|
return found ? found.label : type;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -107,10 +118,19 @@ const HelpPage: React.FC = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// 处理标签页切换
|
||||||
|
const tabsOnChange = (key: string) => {
|
||||||
|
tabActiveKey.current = key;
|
||||||
|
fetchHelpData();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="help-container layout-content-main">
|
<div className="help-container layout-content-main">
|
||||||
<div className="help-header">
|
<div className="help-header">
|
||||||
<Title level={2}>{intl.formatMessage({ id: 'help.title' })}</Title>
|
<Tabs onChange={tabsOnChange} centered>
|
||||||
|
<Tabs.TabPane tab="帮助中心" key="helpCenter"></Tabs.TabPane>
|
||||||
|
{user.token && <Tabs.TabPane tab="我的提问" key="myQuestion"></Tabs.TabPane>}
|
||||||
|
</Tabs>
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
icon={<PlusOutlined />}
|
icon={<PlusOutlined />}
|
||||||
@ -140,4 +160,4 @@ const HelpPage: React.FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default HelpPage;
|
export default connect(({ user }: { user: UserModelState }) => ({ user }))(HelpPage);
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Typography, Button, Divider, Spin, message } from 'antd';
|
import { Typography, Button, Divider, Spin, message, Tag } from 'antd';
|
||||||
import { ArrowLeftOutlined } from '@ant-design/icons';
|
import { ArrowLeftOutlined, CommentOutlined } from '@ant-design/icons';
|
||||||
import { history, useIntl } from 'umi';
|
import { history, useIntl } from 'umi';
|
||||||
import { getHelpCenterDetail } from '@/servers/api/help';
|
import { getHelpCenterDetail, getQuestionDetail } from '@/servers/api/help';
|
||||||
import { QUESTION_TYPES } from '@/dicts/help';
|
import { QUESTION_TYPES } from '@/dicts/help';
|
||||||
import styles from './helpInfo.less';
|
import styles from './helpInfo.less';
|
||||||
|
|
||||||
@ -12,11 +12,13 @@ const HelpInfoPage: React.FC = () => {
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [helpDetail, setHelpDetail] = useState<API.HelpCenterDetailResponse | null>(null);
|
const [helpDetail, setHelpDetail] = useState<API.HelpCenterDetailResponse | null>(null);
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
|
let tabActiveKey = 'helpCenter';
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 获取URL中的id参数
|
// 获取URL中的id参数
|
||||||
const query = new URLSearchParams(window.location.search);
|
const query = new URLSearchParams(window.location.search);
|
||||||
const id = query.get('id');
|
const id = query.get('id');
|
||||||
|
tabActiveKey = query.get('tabActiveKey') || 'helpCenter';
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
message.error(intl.formatMessage({ id: 'help.message.idNotFound' }));
|
message.error(intl.formatMessage({ id: 'help.message.idNotFound' }));
|
||||||
@ -27,11 +29,15 @@ const HelpInfoPage: React.FC = () => {
|
|||||||
// 请求详情数据
|
// 请求详情数据
|
||||||
const fetchHelpDetail = async () => {
|
const fetchHelpDetail = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await getHelpCenterDetail({ id });
|
const response =
|
||||||
if (response.success) {
|
tabActiveKey == 'helpCenter' ? getHelpCenterDetail({ id }) : getQuestionDetail(id);
|
||||||
setHelpDetail(response.data);
|
const responseData = await response;
|
||||||
|
if (responseData.success) {
|
||||||
|
setHelpDetail(responseData.data);
|
||||||
} else {
|
} else {
|
||||||
message.error(response.message || intl.formatMessage({ id: 'help.message.loadFailed' }));
|
message.error(
|
||||||
|
responseData.message || intl.formatMessage({ id: 'help.message.loadFailed' }),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('获取帮助中心详情失败:', error);
|
console.error('获取帮助中心详情失败:', error);
|
||||||
@ -51,7 +57,7 @@ const HelpInfoPage: React.FC = () => {
|
|||||||
|
|
||||||
// 获取问题分类名称
|
// 获取问题分类名称
|
||||||
const getQuestionTypeName = (type: string) => {
|
const getQuestionTypeName = (type: string) => {
|
||||||
const found = QUESTION_TYPES.find(item => item.value === type);
|
const found = QUESTION_TYPES.find((item) => item.value === type);
|
||||||
return found ? found.label : type;
|
return found ? found.label : type;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -75,7 +81,7 @@ const HelpInfoPage: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.helpInfoContainer}>
|
<div className={`${styles.helpInfoContainer} layout-content-main`}>
|
||||||
<div className={styles.helpInfoHeader}>
|
<div className={styles.helpInfoHeader}>
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
@ -88,30 +94,23 @@ const HelpInfoPage: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.helpInfoContent}>
|
<div className={styles.helpInfoContent}>
|
||||||
<div className={styles.titleContainer}>
|
|
||||||
<Title level={2} className={styles.title}>
|
<Title level={2} className={styles.title}>
|
||||||
{helpDetail.title}
|
{/* <QuestionCircleOutlined /> */}
|
||||||
|
<CommentOutlined />
|
||||||
|
<span style={{ margin: '0 15px' }}>{helpDetail.title}</span>
|
||||||
|
{tabActiveKey == 'helpCenter' ? (
|
||||||
|
''
|
||||||
|
) : (
|
||||||
|
<Tag color="success">{helpDetail.isAnswer == '1' ? '已回答' : '未回答'}</Tag>
|
||||||
|
)}
|
||||||
</Title>
|
</Title>
|
||||||
</div>
|
<div dangerouslySetInnerHTML={{ __html: helpDetail.content || '' }} />
|
||||||
|
|
||||||
<div className={styles.metaInfo}>
|
|
||||||
<div className={styles.metaLeft}>
|
|
||||||
<Text type="secondary">
|
|
||||||
{intl.formatMessage({ id: 'help.info.publishTime' })}: {helpDetail.createTime}
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
<div className={styles.metaRight}>
|
|
||||||
<Text type="secondary">
|
|
||||||
{intl.formatMessage({ id: 'help.info.questionType' })}: {getQuestionTypeName(helpDetail.type)} |
|
|
||||||
{intl.formatMessage({ id: 'help.info.publisher' })}: {helpDetail.createBy || '系统管理员'}
|
|
||||||
</Text>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Divider className={styles.divider} />
|
<Divider className={styles.divider} />
|
||||||
|
|
||||||
<div className={styles.contentBody}>
|
<div className={styles.contentBody}>
|
||||||
<div dangerouslySetInnerHTML={{ __html: helpDetail.answerContent || helpDetail.content || '暂无内容' }} />
|
答:
|
||||||
|
<div dangerouslySetInnerHTML={{ __html: helpDetail.answerContent || '暂无内容' }} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -6,6 +6,8 @@ import WangEditor from 'wangeditor';
|
|||||||
import { QUESTION_TYPES } from '@/dicts/help';
|
import { QUESTION_TYPES } from '@/dicts/help';
|
||||||
import { addHelpCenterQuestion } from '@/servers/api/help';
|
import { addHelpCenterQuestion } from '@/servers/api/help';
|
||||||
import styles from './helpQuestion.less';
|
import styles from './helpQuestion.less';
|
||||||
|
import { getDictList } from '@/servers/api/dict';
|
||||||
|
import type { DictItem } from '@/servers/api/dict';
|
||||||
|
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
@ -28,9 +30,15 @@ const HelpQuestionPage: React.FC = () => {
|
|||||||
const [editor, setEditor] = useState<WangEditor | null>(null);
|
const [editor, setEditor] = useState<WangEditor | null>(null);
|
||||||
const [content, setContent] = useState<string>('');
|
const [content, setContent] = useState<string>('');
|
||||||
const [submitting, setSubmitting] = useState<boolean>(false);
|
const [submitting, setSubmitting] = useState<boolean>(false);
|
||||||
|
const [typeList, setTypeList] = useState<DictItem[]>([]);
|
||||||
|
|
||||||
// 初始化编辑器
|
// 初始化编辑器
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
getDictList('help_center').then((res) => {
|
||||||
|
if (res.code === 200 && res.success) {
|
||||||
|
setTypeList(res.data);
|
||||||
|
}
|
||||||
|
});
|
||||||
const editorInstance = new WangEditor('#editor');
|
const editorInstance = new WangEditor('#editor');
|
||||||
|
|
||||||
// 配置编辑器
|
// 配置编辑器
|
||||||
@ -138,9 +146,7 @@ const HelpQuestionPage: React.FC = () => {
|
|||||||
<div className={styles.contentWrapper}>
|
<div className={styles.contentWrapper}>
|
||||||
<div className={styles.titleContainer}>
|
<div className={styles.titleContainer}>
|
||||||
<Title level={2}>{intl.formatMessage({ id: 'help.question.title' })}</Title>
|
<Title level={2}>{intl.formatMessage({ id: 'help.question.title' })}</Title>
|
||||||
<p className={styles.subtitle}>
|
<p className={styles.subtitle}>{intl.formatMessage({ id: 'help.question.subtitle' })}</p>
|
||||||
{intl.formatMessage({ id: 'help.question.subtitle' })}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Divider className={styles.divider} />
|
<Divider className={styles.divider} />
|
||||||
@ -157,12 +163,17 @@ const HelpQuestionPage: React.FC = () => {
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
name="type"
|
name="type"
|
||||||
label={intl.formatMessage({ id: 'help.form.type' })}
|
label={intl.formatMessage({ id: 'help.form.type' })}
|
||||||
rules={[{ required: true, message: intl.formatMessage({ id: 'help.form.type.required' }) }]}
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: intl.formatMessage({ id: 'help.form.type.required' }),
|
||||||
|
},
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<Select placeholder={intl.formatMessage({ id: 'help.form.type.placeholder' })}>
|
<Select placeholder={intl.formatMessage({ id: 'help.form.type.placeholder' })}>
|
||||||
{QUESTION_TYPES.map(type => (
|
{typeList.map((type) => (
|
||||||
<Option key={type.value} value={type.value}>
|
<Option key={type.code} value={type.code}>
|
||||||
{type.label}
|
{type.dicName}
|
||||||
</Option>
|
</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
@ -172,7 +183,12 @@ const HelpQuestionPage: React.FC = () => {
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
name="title"
|
name="title"
|
||||||
label={intl.formatMessage({ id: 'help.form.title' })}
|
label={intl.formatMessage({ id: 'help.form.title' })}
|
||||||
rules={[{ required: true, message: intl.formatMessage({ id: 'help.form.title.required' }) }]}
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: intl.formatMessage({ id: 'help.form.title.required' }),
|
||||||
|
},
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<Input placeholder={intl.formatMessage({ id: 'help.form.title.placeholder' })} />
|
<Input placeholder={intl.formatMessage({ id: 'help.form.title.placeholder' })} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@ -182,7 +198,9 @@ const HelpQuestionPage: React.FC = () => {
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
name="content"
|
name="content"
|
||||||
label={intl.formatMessage({ id: 'help.form.content' })}
|
label={intl.formatMessage({ id: 'help.form.content' })}
|
||||||
rules={[{ required: true, message: intl.formatMessage({ id: 'help.form.content.required' }) }]}
|
rules={[
|
||||||
|
{ required: true, message: intl.formatMessage({ id: 'help.form.content.required' }) },
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<div id="editor" className={styles.editor}></div>
|
<div id="editor" className={styles.editor}></div>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@ -192,7 +210,12 @@ const HelpQuestionPage: React.FC = () => {
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
name="name"
|
name="name"
|
||||||
label={intl.formatMessage({ id: 'help.form.name' })}
|
label={intl.formatMessage({ id: 'help.form.name' })}
|
||||||
rules={[{ required: true, message: intl.formatMessage({ id: 'help.form.name.required' }) }]}
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: intl.formatMessage({ id: 'help.form.name.required' }),
|
||||||
|
},
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<Input placeholder={intl.formatMessage({ id: 'help.form.name.placeholder' })} />
|
<Input placeholder={intl.formatMessage({ id: 'help.form.name.placeholder' })} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@ -201,7 +224,12 @@ const HelpQuestionPage: React.FC = () => {
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
name="company"
|
name="company"
|
||||||
label={intl.formatMessage({ id: 'help.form.company' })}
|
label={intl.formatMessage({ id: 'help.form.company' })}
|
||||||
rules={[{ required: true, message: intl.formatMessage({ id: 'help.form.company.required' }) }]}
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: intl.formatMessage({ id: 'help.form.company.required' }),
|
||||||
|
},
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<Input placeholder={intl.formatMessage({ id: 'help.form.company.placeholder' })} />
|
<Input placeholder={intl.formatMessage({ id: 'help.form.company.placeholder' })} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@ -213,7 +241,12 @@ const HelpQuestionPage: React.FC = () => {
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
name="account"
|
name="account"
|
||||||
label={intl.formatMessage({ id: 'help.form.account' })}
|
label={intl.formatMessage({ id: 'help.form.account' })}
|
||||||
rules={[{ required: true, message: intl.formatMessage({ id: 'help.form.account.required' }) }]}
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
message: intl.formatMessage({ id: 'help.form.account.required' }),
|
||||||
|
},
|
||||||
|
]}
|
||||||
>
|
>
|
||||||
<Input placeholder={intl.formatMessage({ id: 'help.form.account.placeholder' })} />
|
<Input placeholder={intl.formatMessage({ id: 'help.form.account.placeholder' })} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@ -223,8 +256,11 @@ const HelpQuestionPage: React.FC = () => {
|
|||||||
name="email"
|
name="email"
|
||||||
label={intl.formatMessage({ id: 'help.form.email' })}
|
label={intl.formatMessage({ id: 'help.form.email' })}
|
||||||
rules={[
|
rules={[
|
||||||
{ required: true, message: intl.formatMessage({ id: 'help.form.email.required' }) },
|
{
|
||||||
{ validator: emailValidator }
|
required: true,
|
||||||
|
message: intl.formatMessage({ id: 'help.form.email.required' }),
|
||||||
|
},
|
||||||
|
{ validator: emailValidator },
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Input placeholder={intl.formatMessage({ id: 'help.form.email.placeholder' })} />
|
<Input placeholder={intl.formatMessage({ id: 'help.form.email.placeholder' })} />
|
||||||
@ -245,7 +281,12 @@ const HelpQuestionPage: React.FC = () => {
|
|||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Form.Item className={styles.buttonGroup}>
|
<Form.Item className={styles.buttonGroup}>
|
||||||
<Button type="primary" htmlType="submit" loading={submitting} className={styles.submitButton}>
|
<Button
|
||||||
|
type="primary"
|
||||||
|
htmlType="submit"
|
||||||
|
loading={submitting}
|
||||||
|
className={styles.submitButton}
|
||||||
|
>
|
||||||
{intl.formatMessage({ id: 'help.submit' })}
|
{intl.formatMessage({ id: 'help.submit' })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleCancel} className={styles.cancelButton}>
|
<Button onClick={handleCancel} className={styles.cancelButton}>
|
||||||
|
@ -97,7 +97,7 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
.ant-btn {
|
.ant-btn {
|
||||||
width: 100px;
|
min-width: 100px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,12 +159,15 @@ const IndexPage: React.FC<any> = ({ user }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const toRegister = (type: string) => {
|
const toRegister = (type: string) => {
|
||||||
history.push({
|
window.location.href = `${REGISTER_URL}/${type}?redirect=${encodeURIComponent(
|
||||||
pathname: '/register/supplier',
|
window.location.href,
|
||||||
query: {
|
)}`;
|
||||||
type: type,
|
// history.push({
|
||||||
},
|
// pathname: '/register/supplier',
|
||||||
});
|
// query: {
|
||||||
|
// type: type,
|
||||||
|
// },
|
||||||
|
// });
|
||||||
console.log(type);
|
console.log(type);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -189,7 +192,7 @@ const IndexPage: React.FC<any> = ({ user }) => {
|
|||||||
<img className="banner" src={require('@/assets/img/banner.jpg')} alt="" />
|
<img className="banner" src={require('@/assets/img/banner.jpg')} alt="" />
|
||||||
{/* 通知列表 */}
|
{/* 通知列表 */}
|
||||||
<div className="noticeList layout-content-main">
|
<div className="noticeList layout-content-main">
|
||||||
<div className="noticeName">通知公告</div>
|
<div className="noticeName">{intl.formatMessage({ id: 'home.notice.title' })}</div>
|
||||||
{noticeList.map((item) => (
|
{noticeList.map((item) => (
|
||||||
<div className="noticeItem" key={item.id}>
|
<div className="noticeItem" key={item.id}>
|
||||||
<div className="cardTitle">
|
<div className="cardTitle">
|
||||||
@ -197,7 +200,7 @@ const IndexPage: React.FC<any> = ({ user }) => {
|
|||||||
className="cardTitleText"
|
className="cardTitleText"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
history.push({
|
history.push({
|
||||||
pathname: '/announce/announceInfo',
|
pathname: '/notice/noticeInfo',
|
||||||
search: '?id=' + item.id,
|
search: '?id=' + item.id,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
@ -216,16 +219,18 @@ const IndexPage: React.FC<any> = ({ user }) => {
|
|||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
<div className="loginTypeItem">
|
<div className="loginTypeItem">
|
||||||
<img src={require('@/assets/img/loginType1.png')} alt="" />
|
<img src={require('@/assets/img/loginType1.png')} alt="" />
|
||||||
<div className="loginTypeItemTitle">供应商入口</div>
|
<div className="loginTypeItemTitle">
|
||||||
|
{intl.formatMessage({ id: 'home.entry.supplier.title' })}
|
||||||
|
</div>
|
||||||
<div className="loginTypeItemContent">
|
<div className="loginTypeItemContent">
|
||||||
供应商注册、投标、合同管理、结算等全流程服务
|
{intl.formatMessage({ id: 'home.entry.supplier.desc' })}
|
||||||
</div>
|
</div>
|
||||||
<div className="btns">
|
<div className="btns">
|
||||||
<Button type="primary" onClick={() => toSystem('supplier')}>
|
<Button type="primary" onClick={() => toSystem('supplier')}>
|
||||||
立即进入
|
{intl.formatMessage({ id: 'home.button.enterNow' })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="primary" ghost onClick={() => toRegister('supplier')}>
|
<Button type="primary" ghost onClick={() => toRegister('supplier')}>
|
||||||
立即注册
|
{intl.formatMessage({ id: 'home.button.registerNow' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -233,16 +238,18 @@ const IndexPage: React.FC<any> = ({ user }) => {
|
|||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
<div className="loginTypeItem">
|
<div className="loginTypeItem">
|
||||||
<img src={require('@/assets/img/loginType2.png')} alt="" />
|
<img src={require('@/assets/img/loginType2.png')} alt="" />
|
||||||
<div className="loginTypeItemTitle">采购专家入口</div>
|
<div className="loginTypeItemTitle">
|
||||||
|
{intl.formatMessage({ id: 'home.entry.expert.title' })}
|
||||||
|
</div>
|
||||||
<div className="loginTypeItemContent">
|
<div className="loginTypeItemContent">
|
||||||
采购需求发布、评审、合同签订、供应商管理等服务
|
{intl.formatMessage({ id: 'home.entry.expert.desc' })}
|
||||||
</div>
|
</div>
|
||||||
<div className="btns">
|
<div className="btns">
|
||||||
<Button type="primary" ghost onClick={() => toSystem('expert')}>
|
<Button type="primary" ghost onClick={() => toSystem('expert')}>
|
||||||
立即进入
|
{intl.formatMessage({ id: 'home.button.enterNow' })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="primary" ghost onClick={() => toRegister('expert')}>
|
<Button type="primary" ghost onClick={() => toRegister('expert')}>
|
||||||
立即注册
|
{intl.formatMessage({ id: 'home.button.registerNow' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -250,13 +257,15 @@ const IndexPage: React.FC<any> = ({ user }) => {
|
|||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
<div className="loginTypeItem">
|
<div className="loginTypeItem">
|
||||||
<img src={require('@/assets/img/loginType3.png')} alt="" />
|
<img src={require('@/assets/img/loginType3.png')} alt="" />
|
||||||
<div className="loginTypeItemTitle">招标代理入口</div>
|
<div className="loginTypeItemTitle">
|
||||||
|
{intl.formatMessage({ id: 'home.entry.agent.title' })}
|
||||||
|
</div>
|
||||||
<div className="loginTypeItemContent">
|
<div className="loginTypeItemContent">
|
||||||
招标文件编制、公告发布、开标评标等专业服务
|
{intl.formatMessage({ id: 'home.entry.agent.desc' })}
|
||||||
</div>
|
</div>
|
||||||
<div className="btns">
|
<div className="btns">
|
||||||
<Button type="primary" ghost onClick={() => toSystem('agent')}>
|
<Button type="primary" ghost onClick={() => toSystem('agent')}>
|
||||||
立即进入
|
{intl.formatMessage({ id: 'home.button.enterNow' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -269,7 +278,9 @@ const IndexPage: React.FC<any> = ({ user }) => {
|
|||||||
<Row gutter={40}>
|
<Row gutter={40}>
|
||||||
<Col span={5}>
|
<Col span={5}>
|
||||||
<div className="types bg">
|
<div className="types bg">
|
||||||
<div className="announceTitle">采购类型</div>
|
<div className="announceTitle">
|
||||||
|
{intl.formatMessage({ id: 'home.procurement.title' })}
|
||||||
|
</div>
|
||||||
{typeList.map((item) => (
|
{typeList.map((item) => (
|
||||||
<div
|
<div
|
||||||
className={`typeItem ${item.key === '1' ? 'active' : ''}`}
|
className={`typeItem ${item.key === '1' ? 'active' : ''}`}
|
||||||
@ -310,43 +321,61 @@ const IndexPage: React.FC<any> = ({ user }) => {
|
|||||||
<div className="layout-content-main">
|
<div className="layout-content-main">
|
||||||
<Row gutter={40}>
|
<Row gutter={40}>
|
||||||
<Col span={16}>
|
<Col span={16}>
|
||||||
<div className="blockTitle">问题咨询方式</div>
|
<div className="blockTitle">{intl.formatMessage({ id: 'home.question.title' })}</div>
|
||||||
<div className="borderBox">
|
<div className="borderBox">
|
||||||
{/* addressImg */}
|
{/* addressImg */}
|
||||||
<img src={aboutUs.addressImg} alt="" />
|
<img src={aboutUs.addressImg} alt="" />
|
||||||
<div className="questionItem">
|
<div className="questionItem">
|
||||||
<IconFont type="icon-dizhi" className="icon" />
|
<IconFont type="icon-dizhi" className="icon" />
|
||||||
<span dangerouslySetInnerHTML={{ __html: aboutUs[intl.formatMessage({ id: 'home.data.address' })] }} />
|
<span
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: aboutUs['address'],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="questionItem">
|
<div className="questionItem">
|
||||||
<IconFont type="icon-dianhua" className="icon" />
|
<IconFont type="icon-dianhua" className="icon" />
|
||||||
<span dangerouslySetInnerHTML={{ __html: aboutUs[intl.formatMessage({ id: 'home.data.contactsConsult' })] }} />
|
<span
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: aboutUs['contactsConsult'],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="questionItem">
|
<div className="questionItem">
|
||||||
<IconFont type="icon-youxiang" className="icon" />
|
<IconFont type="icon-youxiang" className="icon" />
|
||||||
<span dangerouslySetInnerHTML={{ __html: aboutUs[intl.formatMessage({ id: 'home.data.contactsEmail' })] }} />
|
<span
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: aboutUs['contactsEmail'],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={8} className="caBox">
|
<Col span={8} className="caBox">
|
||||||
<div>
|
<div>
|
||||||
<div className="blockTitle">CA服务</div>
|
<div className="blockTitle">CA {intl.formatMessage({ id: 'home.ca.title' })}</div>
|
||||||
<Row className="caRow">
|
<Row className="caRow">
|
||||||
<Col span={6} offset={6} className="caItem">
|
<Col span={6} offset={6} className="caItem">
|
||||||
<img src={require('@/assets/img/ca1.png')} alt="" />
|
<img src={require('@/assets/img/ca1.png')} alt="" />
|
||||||
<span>CA办理</span>
|
<span>{intl.formatMessage({ id: 'home.ca.handle' })}</span>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={6} className="caItem">
|
<Col span={6} className="caItem">
|
||||||
<img src={require('@/assets/img/ca2.png')} alt="" />
|
<img src={require('@/assets/img/ca2.png')} alt="" />
|
||||||
<span>CA客服</span>
|
<span>{intl.formatMessage({ id: 'home.ca.service' })}</span>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="contactBox">
|
<div className="contactBox">
|
||||||
<div className="blockTitle mt20">联系方式</div>
|
<div className="blockTitle mt20">
|
||||||
|
{intl.formatMessage({ id: 'home.contact.title' })}
|
||||||
|
</div>
|
||||||
<div className="contact">
|
<div className="contact">
|
||||||
<span dangerouslySetInnerHTML={{ __html: aboutUs[intl.formatMessage({ id: 'home.data.contactsPhone' })] }} />
|
<span
|
||||||
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: aboutUs[intl.formatMessage({ id: 'home.data.contactsPhone' })],
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
@ -356,10 +385,14 @@ const IndexPage: React.FC<any> = ({ user }) => {
|
|||||||
|
|
||||||
<div className="firendLink">
|
<div className="firendLink">
|
||||||
<div className="layout-content-main">
|
<div className="layout-content-main">
|
||||||
<div className="linkTitle">友情链接</div>
|
<div className="linkTitle">{intl.formatMessage({ id: 'home.friendlink.title' })}</div>
|
||||||
<Card>
|
<Card>
|
||||||
{friendshipConnections.map((item, index) => (
|
{friendshipConnections.map((item, index) => (
|
||||||
<Card.Grid key={item.id} style={{ width: '16.6667%', height: '130px' }}>
|
<Card.Grid
|
||||||
|
onClick={() => window.open(item.url)}
|
||||||
|
key={item.id}
|
||||||
|
style={{ width: '16.6667%', height: '130px' }}
|
||||||
|
>
|
||||||
<img src={item.thumbnail} alt="" />
|
<img src={item.thumbnail} alt="" />
|
||||||
</Card.Grid>
|
</Card.Grid>
|
||||||
))}
|
))}
|
||||||
|
@ -63,7 +63,8 @@ const LoginPage: React.FC<PageProps> = ({ user, dispatch }) => {
|
|||||||
const handleRegister = () => {
|
const handleRegister = () => {
|
||||||
switch (activeKey) {
|
switch (activeKey) {
|
||||||
case 'supplier':
|
case 'supplier':
|
||||||
history.push('/register/supplier');
|
window.location.href = `${REGISTER_URL}/${activeKey}?redirect=${encodeURIComponent(window.location.href)}`;
|
||||||
|
// history.push('/register/supplier');
|
||||||
break;
|
break;
|
||||||
case 'expert':
|
case 'expert':
|
||||||
history.push('/register/expert');
|
history.push('/register/expert');
|
||||||
|
@ -11,7 +11,7 @@ import type { DictItem } from '@/servers/api/dict';
|
|||||||
|
|
||||||
const NoticePage: React.FC = () => {
|
const NoticePage: React.FC = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [activeMenu, setActiveMenu] = useState<string>('system');
|
const [activeMenu, setActiveMenu] = useState<string>();
|
||||||
const [menuList, setMenuList] = useState<DictItem[]>([]);
|
const [menuList, setMenuList] = useState<DictItem[]>([]);
|
||||||
const [noticeData, setNoticeData] = useState<NoticeRecord[]>([]);
|
const [noticeData, setNoticeData] = useState<NoticeRecord[]>([]);
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
@ -27,7 +27,8 @@ const NoticePage: React.FC = () => {
|
|||||||
try {
|
try {
|
||||||
const response = await getNoticeList({
|
const response = await getNoticeList({
|
||||||
pageNo: page.toString(),
|
pageNo: page.toString(),
|
||||||
pageSize: pageSize.toString()
|
pageSize: pageSize.toString(),
|
||||||
|
columnType: activeMenu
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.code === 200 && response.success) {
|
if (response.code === 200 && response.success) {
|
||||||
|
@ -62,6 +62,7 @@
|
|||||||
.contentBody {
|
.contentBody {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 1.8;
|
line-height: 1.8;
|
||||||
|
word-break: break-all;
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
|
@ -79,7 +79,7 @@ const NoticeInfo: React.FC = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.noticeInfoContainer}>
|
<div className={`${styles.noticeInfoContainer} layout-content-main` }>
|
||||||
<div className={styles.noticeInfoHeader}>
|
<div className={styles.noticeInfoHeader}>
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
|
@ -249,7 +249,7 @@ const PolicyInfo: React.FC = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.policyInfoContainer}>
|
<div className={`${styles.policyInfoContainer} layout-content-main`}>
|
||||||
<div className={styles.policyInfoHeader}>
|
<div className={styles.policyInfoHeader}>
|
||||||
<Button
|
<Button
|
||||||
type="link"
|
type="link"
|
||||||
|
@ -90,77 +90,6 @@ const SupplierRegister: React.FC = () => {
|
|||||||
values.coscoSupplierBase = values.coscoSupplierBase || {};
|
values.coscoSupplierBase = values.coscoSupplierBase || {};
|
||||||
values.coscoSupplierBase.supplierType = supplierType;
|
values.coscoSupplierBase.supplierType = supplierType;
|
||||||
|
|
||||||
// 记录详细的表单数据,便于调试
|
|
||||||
console.log('表单原始数据:', JSON.parse(JSON.stringify(values)));
|
|
||||||
console.log('供应商基本信息:', values.coscoSupplierBase);
|
|
||||||
console.log('开票信息:', values.coscoSupplierInvoice);
|
|
||||||
console.log('银行账户信息:', values.coscoSupplierBank);
|
|
||||||
console.log('资质信息:', values.coscoSupplierQualifications);
|
|
||||||
console.log('调查问卷信息:', values.coscoSupplierSurvey);
|
|
||||||
console.log('调查问卷回复:', values.coscoSupplierSurveyQuestionReply);
|
|
||||||
console.log('调查问卷附件:', values.coscoSupplierSurveyAttachments);
|
|
||||||
|
|
||||||
// 处理文件上传组件返回的文件列表值
|
|
||||||
// 处理营业执照附件
|
|
||||||
if (
|
|
||||||
values.coscoSupplierBase.licenceAccessory &&
|
|
||||||
Array.isArray(values.coscoSupplierBase.licenceAccessory)
|
|
||||||
) {
|
|
||||||
const licenceFile = values.coscoSupplierBase.licenceAccessory[0];
|
|
||||||
values.coscoSupplierBase.licenceAccessory =
|
|
||||||
licenceFile?.response?.url || licenceFile?.response?.filePath || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理纳税人资格证明
|
|
||||||
if (
|
|
||||||
values.coscoSupplierInvoice?.qualificationCertificate &&
|
|
||||||
Array.isArray(values.coscoSupplierInvoice.qualificationCertificate)
|
|
||||||
) {
|
|
||||||
const taxFile = values.coscoSupplierInvoice.qualificationCertificate[0];
|
|
||||||
values.coscoSupplierInvoice.qualificationCertificate =
|
|
||||||
taxFile?.response?.url || taxFile?.response?.filePath || '';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理资质证书附件
|
|
||||||
if (values.coscoSupplierQualifications) {
|
|
||||||
values.coscoSupplierQualifications = values.coscoSupplierQualifications.map((qual: any) => {
|
|
||||||
if (qual.accessory && Array.isArray(qual.accessory)) {
|
|
||||||
const accessoryFile = qual.accessory[0];
|
|
||||||
qual.accessory =
|
|
||||||
accessoryFile?.response?.url || accessoryFile?.response?.filePath || '';
|
|
||||||
}
|
|
||||||
return qual;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理调查问卷附件
|
|
||||||
if (values.coscoSupplierSurveyAttachments) {
|
|
||||||
values.coscoSupplierSurveyAttachments = values.coscoSupplierSurveyAttachments.map(
|
|
||||||
(item: any) => {
|
|
||||||
if (item.fileUrl && Array.isArray(item.fileUrl)) {
|
|
||||||
const file = item.fileUrl[0];
|
|
||||||
item.fileUrl = file?.response?.url || file?.response?.filePath || '';
|
|
||||||
}
|
|
||||||
return item;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理调查问卷回复
|
|
||||||
if (values.coscoSupplierSurveyQuestionReply) {
|
|
||||||
// 过滤出有效的问卷回复并确保数据格式正确
|
|
||||||
values.coscoSupplierSurveyQuestionReply = values.coscoSupplierSurveyQuestionReply
|
|
||||||
.filter((item: any) => item && item.surveyQuestionId && item.replyValue)
|
|
||||||
.map((item: any) => ({
|
|
||||||
surveyQuestionId: item.surveyQuestionId,
|
|
||||||
replyValue: item.replyValue,
|
|
||||||
}));
|
|
||||||
|
|
||||||
console.log('处理后的问卷回复:', values.coscoSupplierSurveyQuestionReply);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('最终提交的表单数据:', JSON.parse(JSON.stringify(values)));
|
|
||||||
|
|
||||||
// 直接调用API
|
// 直接调用API
|
||||||
const response = await coscoSupplierBaseAdd(values);
|
const response = await coscoSupplierBaseAdd(values);
|
||||||
|
|
||||||
|
@ -119,7 +119,14 @@ const DomesticForm: React.FC<DomesticFormProps> = ({
|
|||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
valuePropName="value"
|
getValueProps={(value) => {
|
||||||
|
return {
|
||||||
|
value: value?.length > 0 ? value[0]?.url : undefined,
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
getValueFromEvent={(value) => {
|
||||||
|
return value?.length > 0 ? value[0]?.url : undefined;
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<FileUpload
|
<FileUpload
|
||||||
maxSize={10}
|
maxSize={10}
|
||||||
@ -452,7 +459,7 @@ const DomesticForm: React.FC<DomesticFormProps> = ({
|
|||||||
{/* 使用通用表单组件 */}
|
{/* 使用通用表单组件 */}
|
||||||
<QualificationSection form={form} />
|
<QualificationSection form={form} />
|
||||||
<InvoiceSection form={form} />
|
<InvoiceSection form={form} />
|
||||||
<BankAccountSection form={form} />
|
<BankAccountSection form={form} supplierType="dvs" />
|
||||||
<SurveySection form={form} surveyQuestions={surveyQuestions} />
|
<SurveySection form={form} surveyQuestions={surveyQuestions} />
|
||||||
<AttachmentSection form={form} />
|
<AttachmentSection form={form} />
|
||||||
</>
|
</>
|
||||||
|
@ -232,7 +232,7 @@ const ForeignForm: React.FC<ForeignFormProps> = ({
|
|||||||
{/* 使用通用表单组件 */}
|
{/* 使用通用表单组件 */}
|
||||||
<QualificationSection form={form} />
|
<QualificationSection form={form} />
|
||||||
<InvoiceSection form={form} />
|
<InvoiceSection form={form} />
|
||||||
<BankAccountSection form={form} />
|
<BankAccountSection form={form} supplierType="ovs" />
|
||||||
<SurveySection form={form} surveyQuestions={surveyQuestions} />
|
<SurveySection form={form} surveyQuestions={surveyQuestions} />
|
||||||
<AttachmentSection form={form} />
|
<AttachmentSection form={form} />
|
||||||
</>
|
</>
|
||||||
|
@ -42,7 +42,17 @@ export type DictItem = {
|
|||||||
* @returns 字典列表
|
* @returns 字典列表
|
||||||
*/
|
*/
|
||||||
export async function getDictList(code: string): Promise<DictResponse> {
|
export async function getDictList(code: string): Promise<DictResponse> {
|
||||||
return request(`/cosco/dictProject/getAllList/${code}`, {
|
const data: string | null = sessionStorage.getItem('dict');
|
||||||
method: 'GET',
|
if (data) {
|
||||||
});
|
const dictData = JSON.parse(data);
|
||||||
|
const codeType = `${code.trim()}=supplier_manage_type`;
|
||||||
|
return Promise.resolve({
|
||||||
|
code: 200,
|
||||||
|
data: dictData[codeType],
|
||||||
|
message: 'success',
|
||||||
|
success: true,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
return Promise.reject(new Error('请先请求字典数据'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import request from '@/utils/request';
|
|||||||
export type DownloadListParams = {
|
export type DownloadListParams = {
|
||||||
pageNo: string;
|
pageNo: string;
|
||||||
pageSize: string;
|
pageSize: string;
|
||||||
|
columnType: string | undefined; // 可选参数,默认为 undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
// 下载项记录类型
|
// 下载项记录类型
|
||||||
|
@ -35,3 +35,22 @@ export async function addHelpCenterQuestion(params: API.HelpCenterQuestionAddReq
|
|||||||
data: params,
|
data: params,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
获取我的提问
|
||||||
|
*/
|
||||||
|
|
||||||
|
export async function qandaGetPage(params: API.HelpCenterListRequest) {
|
||||||
|
return request<API.APIResponse<any>>('/portals/qanda/getPage', {
|
||||||
|
method: 'POST',
|
||||||
|
data: params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
查询我的提问详情
|
||||||
|
*/
|
||||||
|
export async function getQuestionDetail(id: string) {
|
||||||
|
return request<API.APIResponse<any>>(`/portals/qanda/${id}`, {
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -14,3 +14,11 @@ export async function getCoscoPortalsLinksFriendshipConnections() {
|
|||||||
method: 'get',
|
method: 'get',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 字典缓存接口
|
||||||
|
*/
|
||||||
|
export async function refreshDictCache() {
|
||||||
|
return request('/v1/dictProject/refreshDictCache', {
|
||||||
|
method: 'GET'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@ import request from '@/utils/request';
|
|||||||
export type NoticeListParams = {
|
export type NoticeListParams = {
|
||||||
pageNo: string;
|
pageNo: string;
|
||||||
pageSize: string;
|
pageSize: string;
|
||||||
|
columnType: string | undefined; // 可选参数,默认为 undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
// 通知中心记录类型
|
// 通知中心记录类型
|
||||||
|
2
src/typings.d.ts
vendored
2
src/typings.d.ts
vendored
@ -62,3 +62,5 @@ declare const REACT_APP_CUSTOMERSERVICE_CLIENT_ID: string
|
|||||||
declare const REACT_APP_CUSTOMERSERVICE_REDIRECT: string
|
declare const REACT_APP_CUSTOMERSERVICE_REDIRECT: string
|
||||||
declare const UPLOAD_URL: string
|
declare const UPLOAD_URL: string
|
||||||
declare const REQUEST_BASE: string
|
declare const REQUEST_BASE: string
|
||||||
|
// 注册地址
|
||||||
|
declare const REGISTER_URL: string
|
||||||
|
Reference in New Issue
Block a user