对接关于我们 ,正则法规,帮助中心 ,用户提问模块
This commit is contained in:
@ -1,78 +1,162 @@
|
||||
@import '~antd/es/style/themes/default.less';
|
||||
|
||||
.aboutContainer {
|
||||
padding: 24px;
|
||||
padding: 20px;
|
||||
background-color: #fff;
|
||||
min-height: calc(100vh - 250px);
|
||||
}
|
||||
|
||||
.aboutContent {
|
||||
max-width: 1000px;
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.aboutTitle {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
|
||||
h2 {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.aboutSection {
|
||||
margin-bottom: 48px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.sectionTitle {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
position: relative;
|
||||
margin-bottom: 24px;
|
||||
padding-left: 12px;
|
||||
padding-left: 15px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 4px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 5px;
|
||||
height: 20px;
|
||||
width: 4px;
|
||||
background-color: #1890ff;
|
||||
}
|
||||
}
|
||||
|
||||
.sectionContent {
|
||||
color: #333;
|
||||
line-height: 2;
|
||||
font-size: 15px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.imageWrapper {
|
||||
margin: 24px 0;
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.aboutImage {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
border-radius: 4px;
|
||||
max-height: 400px;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.companyInfo {
|
||||
padding: 20px;
|
||||
background-color: #f5f5f5;
|
||||
padding: 24px;
|
||||
border-radius: 4px;
|
||||
margin-top: 24px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.infoItem {
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
line-height: 24px;
|
||||
|
||||
.label {
|
||||
font-weight: 500;
|
||||
margin-right: 8px;
|
||||
min-width: 80px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.aboutFooter {
|
||||
text-align: center;
|
||||
margin-top: 48px;
|
||||
color: rgba(0, 0, 0, 0.45);
|
||||
margin-top: 40px;
|
||||
color: #999;
|
||||
border-top: 1px solid #eee;
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
// 加载状态
|
||||
.loadingContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: calc(100vh - 250px);
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
// 错误状态
|
||||
.errorContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: calc(100vh - 250px);
|
||||
background-color: #fff;
|
||||
flex-direction: column;
|
||||
|
||||
h4 {
|
||||
margin-bottom: 20px;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
}
|
||||
|
||||
// 富文本内容样式
|
||||
.contentHtml {
|
||||
line-height: 1.8;
|
||||
color: #333;
|
||||
|
||||
p {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 16px 0;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #1890ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
padding-left: 20px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 16px 0;
|
||||
|
||||
th, td {
|
||||
border: 1px solid #e8e8e8;
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f5f5f5;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,61 @@
|
||||
import React from 'react';
|
||||
import { Typography, Divider, Row, Col } from 'antd';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Typography, Divider, Spin, message } from 'antd';
|
||||
import { useIntl } from 'umi';
|
||||
import { getAboutUs } from '@/servers/api/about';
|
||||
import styles from './about.less';
|
||||
|
||||
const { Title, Paragraph } = Typography;
|
||||
|
||||
const AboutPage: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const [aboutData, setAboutData] = useState<API.AboutUsData | null>(null);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const isEnglish = intl.locale === 'en-US';
|
||||
|
||||
// 获取关于我们数据
|
||||
useEffect(() => {
|
||||
const fetchAboutData = async () => {
|
||||
try {
|
||||
const response = await getAboutUs();
|
||||
if (response.success) {
|
||||
setAboutData(response.data);
|
||||
} else {
|
||||
message.error(response.message || '获取关于我们信息失败');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取关于我们信息失败:', error);
|
||||
message.error('获取关于我们信息失败,请稍后再试');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchAboutData();
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className={styles.loadingContainer}>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!aboutData) {
|
||||
return (
|
||||
<div className={styles.errorContainer}>
|
||||
<Title level={4}>暂无相关信息</Title>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// 根据当前语言获取对应内容
|
||||
const title = isEnglish ? aboutData.titleEn : aboutData.title;
|
||||
const content = isEnglish ? aboutData.contentEn : aboutData.content;
|
||||
const address = isEnglish ? aboutData.addressEn : aboutData.address;
|
||||
const contactsConsult = isEnglish ? aboutData.contactsConsultEn : aboutData.contactsConsult;
|
||||
const contactsPhone = isEnglish ? aboutData.contactsPhoneEn : aboutData.contactsPhone;
|
||||
const contactsEmail = isEnglish ? aboutData.contactsEmailEn : aboutData.contactsEmail;
|
||||
|
||||
return (
|
||||
<div className={styles.aboutContainer}>
|
||||
@ -20,133 +69,7 @@ const AboutPage: React.FC = () => {
|
||||
{intl.formatMessage({ id: 'about.company.title' })}
|
||||
</Title>
|
||||
<div className={styles.sectionContent}>
|
||||
<Paragraph>
|
||||
中远海运电子招投标平台是中国远洋海运集团有限公司旗下专业的采购与招标管理平台,
|
||||
致力于为集团内外部用户提供高效、透明、规范的电子化招投标服务。平台依托集团强大的资源优势,
|
||||
结合现代信息技术,构建了覆盖招标、采购、供应商管理等全流程的电子化解决方案。
|
||||
</Paragraph>
|
||||
|
||||
<div className={styles.imageWrapper}>
|
||||
<img
|
||||
src="/home_bg.png"
|
||||
alt="公司总部"
|
||||
className={styles.aboutImage}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Paragraph>
|
||||
作为国内领先的航运物流企业集团的电子招投标平台,我们秉承“公开、公平、公正”的原则,
|
||||
通过标准化、信息化、智能化手段,持续优化招投标流程,提升采购效率,降低采购成本,
|
||||
为集团战略实施和业务发展提供有力支撑。
|
||||
</Paragraph>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div className={styles.aboutSection}>
|
||||
<Title level={3} className={styles.sectionTitle}>
|
||||
{intl.formatMessage({ id: 'about.advantages.title' })}
|
||||
</Title>
|
||||
<div className={styles.sectionContent}>
|
||||
<Row gutter={[24, 24]}>
|
||||
<Col xs={24} md={8}>
|
||||
<div>
|
||||
<Title level={4}>全流程电子化</Title>
|
||||
<Paragraph>
|
||||
从招标公告发布到开标评标,再到结果公示,全流程在线操作,
|
||||
减少纸质文档,提高工作效率,降低运营成本。
|
||||
</Paragraph>
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} md={8}>
|
||||
<div>
|
||||
<Title level={4}>安全可靠</Title>
|
||||
<Paragraph>
|
||||
采用先进的加密技术和安全措施,确保招投标过程的安全性和数据的保密性,
|
||||
有效防范信息泄露和网络攻击风险。
|
||||
</Paragraph>
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} md={8}>
|
||||
<div>
|
||||
<Title level={4}>公开透明</Title>
|
||||
<Paragraph>
|
||||
严格遵循国家招投标法律法规,确保招投标过程公开、透明、可追溯,
|
||||
有效防范舞弊行为,维护各方合法权益。
|
||||
</Paragraph>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<div className={styles.imageWrapper}>
|
||||
<img
|
||||
src="/home_bg.png"
|
||||
alt="平台功能展示"
|
||||
className={styles.aboutImage}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Row gutter={[24, 24]}>
|
||||
<Col xs={24} md={8}>
|
||||
<div>
|
||||
<Title level={4}>智能化服务</Title>
|
||||
<Paragraph>
|
||||
引入人工智能和大数据分析技术,为招标采购决策提供数据支持,
|
||||
实现精准匹配和智能推荐,提升用户体验。
|
||||
</Paragraph>
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} md={8}>
|
||||
<div>
|
||||
<Title level={4}>供应商管理</Title>
|
||||
<Paragraph>
|
||||
建立完善的供应商库和评价体系,实现供应商全生命周期管理,
|
||||
促进供应商良性竞争,提升供应链质量。
|
||||
</Paragraph>
|
||||
</div>
|
||||
</Col>
|
||||
<Col xs={24} md={8}>
|
||||
<div>
|
||||
<Title level={4}>合规监管</Title>
|
||||
<Paragraph>
|
||||
内置合规检查机制,确保招投标活动符合国家法律法规和集团规章制度,
|
||||
降低合规风险,提升管理水平。
|
||||
</Paragraph>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Divider />
|
||||
|
||||
<div className={styles.aboutSection}>
|
||||
<Title level={3} className={styles.sectionTitle}>
|
||||
{intl.formatMessage({ id: 'about.history.title' })}
|
||||
</Title>
|
||||
<div className={styles.sectionContent}>
|
||||
<Paragraph>
|
||||
<strong>2018年</strong> - 中远海运电子招投标平台正式启动建设,完成顶层设计和技术选型。
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<strong>2019年</strong> - 平台一期建设完成并上线试运行,实现基础招投标功能。
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<strong>2020年</strong> - 平台功能全面升级,增加供应商管理、合同管理等模块,用户规模快速增长。
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<strong>2021年</strong> - 平台二期建设完成,引入大数据分析和人工智能技术,提升平台智能化水平。
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<strong>2022年</strong> - 平台实现与集团ERP系统的深度集成,构建完整的采购管理生态。
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<strong>2023年</strong> - 平台进行全面技术改造,采用微服务架构,提升系统性能和可扩展性。
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<strong>2024年</strong> - 平台3.0版本发布,引入区块链技术,进一步提升数据安全性和业务透明度。
|
||||
</Paragraph>
|
||||
<div className={styles.contentHtml} dangerouslySetInnerHTML={{ __html: content }} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -160,23 +83,19 @@ const AboutPage: React.FC = () => {
|
||||
<div className={styles.companyInfo}>
|
||||
<div className={styles.infoItem}>
|
||||
<span className={styles.label}>{intl.formatMessage({ id: 'about.address' })}:</span>
|
||||
<span>上海市虹口区东大名路666号中远海运大厦</span>
|
||||
<span>{address}</span>
|
||||
</div>
|
||||
<div className={styles.infoItem}>
|
||||
<span className={styles.label}>{intl.formatMessage({ id: 'about.phone' })}:</span>
|
||||
<span>021-65966666</span>
|
||||
<span>{contactsPhone}</span>
|
||||
</div>
|
||||
<div className={styles.infoItem}>
|
||||
<span className={styles.label}>{intl.formatMessage({ id: 'about.hotline' })}:</span>
|
||||
<span>400-888-9999</span>
|
||||
<span>{contactsConsult}</span>
|
||||
</div>
|
||||
<div className={styles.infoItem}>
|
||||
<span className={styles.label}>{intl.formatMessage({ id: 'about.email' })}:</span>
|
||||
<span>service@ebidding.cosco.com</span>
|
||||
</div>
|
||||
<div className={styles.infoItem}>
|
||||
<span className={styles.label}>{intl.formatMessage({ id: 'about.worktime' })}:</span>
|
||||
<span>周一至周五 9:00-17:30(法定节假日除外)</span>
|
||||
<span>{contactsEmail}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
37
src/pages/help/help.less
Normal file
37
src/pages/help/help.less
Normal file
@ -0,0 +1,37 @@
|
||||
.help-container {
|
||||
width: 100%;
|
||||
min-height: calc(100vh - 200px);
|
||||
padding: 40px;
|
||||
background-color: #f5f5f5;
|
||||
|
||||
.help-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
|
||||
h2 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.ask-button {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.help-table {
|
||||
background-color: #fff;
|
||||
border-radius: 8px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
|
||||
|
||||
.help-title {
|
||||
color: #1890ff;
|
||||
|
||||
&:hover {
|
||||
color: #40a9ff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
143
src/pages/help/help.tsx
Normal file
143
src/pages/help/help.tsx
Normal file
@ -0,0 +1,143 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Table, Typography, Button } from 'antd';
|
||||
import { history, useIntl } from 'umi';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
import { getHelpCenterList } from '@/servers/api/help';
|
||||
import { QUESTION_TYPES } from '@/dicts/help';
|
||||
import './help.less';
|
||||
|
||||
const { Title } = Typography;
|
||||
|
||||
const HelpPage: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const [helpData, setHelpData] = useState<API.HelpCenterRecord[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [pagination, setPagination] = useState({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
// 获取帮助中心数据
|
||||
const fetchHelpData = async (current = 1, pageSize = 10) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await getHelpCenterList({
|
||||
basePageRequest: {
|
||||
pageNo: current,
|
||||
pageSize: pageSize,
|
||||
},
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setHelpData(response.data.records || []);
|
||||
setPagination({
|
||||
current: response.data.current,
|
||||
pageSize: response.data.size,
|
||||
total: response.data.total,
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取帮助中心列表失败:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 初始加载数据
|
||||
useEffect(() => {
|
||||
fetchHelpData();
|
||||
}, []);
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleTableChange = (newPagination: any) => {
|
||||
fetchHelpData(newPagination.current, newPagination.pageSize);
|
||||
};
|
||||
|
||||
// 处理点击问题标题
|
||||
const handleHelpClick = (id: string) => {
|
||||
history.push(`/help/helpInfo?id=${id}`);
|
||||
};
|
||||
|
||||
// 处理点击提问按钮
|
||||
const handleAskQuestion = () => {
|
||||
history.push('/help/helpQuestion');
|
||||
};
|
||||
|
||||
// 获取问题分类名称
|
||||
const getQuestionTypeName = (type: string) => {
|
||||
const found = QUESTION_TYPES.find(item => item.value === type);
|
||||
return found ? found.label : type;
|
||||
};
|
||||
|
||||
// 定义表格列
|
||||
const columns = [
|
||||
{
|
||||
title: intl.formatMessage({ id: 'help.column.index' }),
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
render: (_: any, __: any, index: number) => {
|
||||
return (pagination.current - 1) * pagination.pageSize + index + 1;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'help.column.title' }),
|
||||
dataIndex: 'title',
|
||||
key: 'title',
|
||||
render: (text: string, record: any) => (
|
||||
<a onClick={() => handleHelpClick(record.id)} className="help-title">
|
||||
{text}
|
||||
</a>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'help.column.type' }),
|
||||
dataIndex: 'type',
|
||||
key: 'type',
|
||||
width: 120,
|
||||
render: (type: string) => getQuestionTypeName(type),
|
||||
},
|
||||
{
|
||||
title: intl.formatMessage({ id: 'help.column.time' }),
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
width: 180,
|
||||
align: 'center' as 'center',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="help-container">
|
||||
<div className="help-header">
|
||||
<Title level={2}>{intl.formatMessage({ id: 'help.title' })}</Title>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={handleAskQuestion}
|
||||
className="ask-button"
|
||||
>
|
||||
{intl.formatMessage({ id: 'help.ask' })}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="help-table">
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={helpData}
|
||||
rowKey="id"
|
||||
pagination={{
|
||||
...pagination,
|
||||
showTotal: (total) => `${intl.formatMessage({ id: 'help.total' }, { total })}`,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
}}
|
||||
loading={loading}
|
||||
onChange={handleTableChange}
|
||||
bordered
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HelpPage;
|
88
src/pages/help/helpInfo.less
Normal file
88
src/pages/help/helpInfo.less
Normal file
@ -0,0 +1,88 @@
|
||||
@import '~antd/es/style/themes/default.less';
|
||||
|
||||
.helpInfoContainer {
|
||||
padding: 24px;
|
||||
background-color: #fff;
|
||||
min-height: calc(100vh - 200px);
|
||||
}
|
||||
|
||||
.helpInfoHeader {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.backButton {
|
||||
color: rgb(0, 79, 142);
|
||||
padding: 0;
|
||||
|
||||
&:hover {
|
||||
color: lighten(rgb(0, 79, 142), 10%);
|
||||
}
|
||||
}
|
||||
|
||||
.helpInfoContent {
|
||||
width: 100%;
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.titleContainer {
|
||||
text-align: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.title {
|
||||
color: rgb(0, 79, 142);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.metaInfo {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 24px;
|
||||
color: #999;
|
||||
|
||||
.metaLeft, .metaRight {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.metaRight {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 16px 0;
|
||||
border-top: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.contentBody {
|
||||
font-size: 16px;
|
||||
line-height: 1.8;
|
||||
|
||||
p {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: 500;
|
||||
color: rgb(0, 79, 142);
|
||||
margin-top: 24px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.loadingContainer {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.notFoundContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 400px;
|
||||
gap: 24px;
|
||||
}
|
121
src/pages/help/helpInfo.tsx
Normal file
121
src/pages/help/helpInfo.tsx
Normal file
@ -0,0 +1,121 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Typography, Button, Divider, Spin, message } from 'antd';
|
||||
import { ArrowLeftOutlined } from '@ant-design/icons';
|
||||
import { history, useIntl } from 'umi';
|
||||
import { getHelpCenterDetail } from '@/servers/api/help';
|
||||
import { QUESTION_TYPES } from '@/dicts/help';
|
||||
import styles from './helpInfo.less';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
const HelpInfoPage: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const [helpDetail, setHelpDetail] = useState<API.HelpCenterDetailResponse | null>(null);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
|
||||
useEffect(() => {
|
||||
// 获取URL中的id参数
|
||||
const query = new URLSearchParams(window.location.search);
|
||||
const id = query.get('id');
|
||||
|
||||
if (!id) {
|
||||
message.error(intl.formatMessage({ id: 'help.message.idNotFound' }));
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 请求详情数据
|
||||
const fetchHelpDetail = async () => {
|
||||
try {
|
||||
const response = await getHelpCenterDetail({ id });
|
||||
if (response.success) {
|
||||
setHelpDetail(response.data);
|
||||
} else {
|
||||
message.error(response.message || intl.formatMessage({ id: 'help.message.loadFailed' }));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取帮助中心详情失败:', error);
|
||||
message.error(intl.formatMessage({ id: 'help.message.loadFailed' }));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchHelpDetail();
|
||||
}, [intl]);
|
||||
|
||||
// 返回列表页
|
||||
const handleBack = () => {
|
||||
history.push('/help');
|
||||
};
|
||||
|
||||
// 获取问题分类名称
|
||||
const getQuestionTypeName = (type: string) => {
|
||||
const found = QUESTION_TYPES.find(item => item.value === type);
|
||||
return found ? found.label : type;
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div className={styles.loadingContainer}>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!helpDetail) {
|
||||
return (
|
||||
<div className={styles.notFoundContainer}>
|
||||
<Title level={4}>{intl.formatMessage({ id: 'help.info.notFound' })}</Title>
|
||||
<Button type="primary" onClick={handleBack}>
|
||||
{intl.formatMessage({ id: 'help.back' })}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.helpInfoContainer}>
|
||||
<div className={styles.helpInfoHeader}>
|
||||
<Button
|
||||
type="link"
|
||||
icon={<ArrowLeftOutlined />}
|
||||
onClick={handleBack}
|
||||
className={styles.backButton}
|
||||
>
|
||||
{intl.formatMessage({ id: 'help.back' })}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className={styles.helpInfoContent}>
|
||||
<div className={styles.titleContainer}>
|
||||
<Title level={2} className={styles.title}>
|
||||
{helpDetail.title}
|
||||
</Title>
|
||||
</div>
|
||||
|
||||
<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} />
|
||||
|
||||
<div className={styles.contentBody}>
|
||||
<div dangerouslySetInnerHTML={{ __html: helpDetail.answerContent || helpDetail.content || '暂无内容' }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HelpInfoPage;
|
92
src/pages/help/helpQuestion.less
Normal file
92
src/pages/help/helpQuestion.less
Normal file
@ -0,0 +1,92 @@
|
||||
@import '~antd/es/style/themes/default.less';
|
||||
|
||||
.helpQuestionContainer {
|
||||
padding: 24px;
|
||||
background-color: #fff;
|
||||
min-height: calc(100vh - 200px);
|
||||
}
|
||||
|
||||
.helpQuestionHeader {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.backButton {
|
||||
color: rgb(0, 79, 142);
|
||||
padding: 0;
|
||||
|
||||
&:hover {
|
||||
color: lighten(rgb(0, 79, 142), 10%);
|
||||
}
|
||||
}
|
||||
|
||||
.helpQuestionContent {
|
||||
width: 100%;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.titleContainer {
|
||||
text-align: center;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.title {
|
||||
color: rgb(0, 79, 142);
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.titleDesc {
|
||||
display: block;
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.divider {
|
||||
margin: 16px 0 24px;
|
||||
border-top: 1px solid #e8e8e8;
|
||||
}
|
||||
|
||||
.questionForm {
|
||||
.ant-form-item-label > label {
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.ant-form-item {
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.ant-input-affix-wrapper,
|
||||
.ant-input,
|
||||
.ant-select-selector {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.ant-input:focus,
|
||||
.ant-input-focused,
|
||||
.ant-select-focused .ant-select-selector {
|
||||
border-color: rgb(0, 79, 142);
|
||||
box-shadow: 0 0 0 2px rgba(0, 79, 142, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.formButtons {
|
||||
text-align: center;
|
||||
margin-top: 40px;
|
||||
|
||||
.cancelButton {
|
||||
margin-right: 16px;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.submitButton {
|
||||
background-color: rgb(0, 79, 142);
|
||||
border-color: rgb(0, 79, 142);
|
||||
min-width: 100px;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
background-color: lighten(rgb(0, 79, 142), 10%);
|
||||
border-color: lighten(rgb(0, 79, 142), 10%);
|
||||
}
|
||||
}
|
||||
}
|
257
src/pages/help/helpQuestion.tsx
Normal file
257
src/pages/help/helpQuestion.tsx
Normal file
@ -0,0 +1,257 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Form, Input, Button, Typography, Select, Row, Col, Divider, message } from 'antd';
|
||||
import { ArrowLeftOutlined } from '@ant-design/icons';
|
||||
import { history, useIntl } from 'umi';
|
||||
import WangEditor from 'wangeditor';
|
||||
import { QUESTION_TYPES } from '@/dicts/help';
|
||||
import { addHelpQuestion } from '@/servers/api/help';
|
||||
import styles from './helpQuestion.less';
|
||||
|
||||
const { Title } = Typography;
|
||||
const { Option } = Select;
|
||||
|
||||
// 表单字段接口定义
|
||||
interface FormValues {
|
||||
title: string;
|
||||
content: string;
|
||||
type: string;
|
||||
name: string;
|
||||
company: string;
|
||||
account: string;
|
||||
email: string;
|
||||
phone?: string; // 可选字段
|
||||
}
|
||||
|
||||
const HelpQuestionPage: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const [form] = Form.useForm();
|
||||
const [editor, setEditor] = useState<WangEditor | null>(null);
|
||||
const [content, setContent] = useState<string>('');
|
||||
const [submitting, setSubmitting] = useState<boolean>(false);
|
||||
|
||||
// 初始化编辑器
|
||||
useEffect(() => {
|
||||
const editorInstance = new WangEditor('#editor');
|
||||
|
||||
// 配置编辑器
|
||||
editorInstance.config.height = 300;
|
||||
editorInstance.config.placeholder = intl.formatMessage({ id: 'help.form.content.placeholder' });
|
||||
editorInstance.config.zIndex = 10;
|
||||
|
||||
// 上传图片相关配置
|
||||
editorInstance.config.uploadImgShowBase64 = true;
|
||||
|
||||
// 设置编辑器内容变化回调
|
||||
editorInstance.config.onchange = (html: string) => {
|
||||
setContent(html);
|
||||
form.setFieldsValue({ content: html });
|
||||
};
|
||||
|
||||
// 创建编辑器
|
||||
editorInstance.create();
|
||||
setEditor(editorInstance);
|
||||
|
||||
// 组件销毁时销毁编辑器实例
|
||||
return () => {
|
||||
if (editorInstance) {
|
||||
editorInstance.destroy();
|
||||
}
|
||||
};
|
||||
}, [form, intl]);
|
||||
|
||||
// 表单提交处理
|
||||
const handleSubmit = async (values: FormValues) => {
|
||||
// 确保内容非空
|
||||
if (!content.trim()) {
|
||||
message.error(intl.formatMessage({ id: 'help.form.content.required' }));
|
||||
return;
|
||||
}
|
||||
|
||||
setSubmitting(true);
|
||||
|
||||
try {
|
||||
const response = await addHelpQuestion({
|
||||
...values,
|
||||
content: content,
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
message.success(intl.formatMessage({ id: 'help.message.submitSuccess' }));
|
||||
// 提交成功后返回帮助中心列表页
|
||||
setTimeout(() => {
|
||||
history.push('/help');
|
||||
}, 1500);
|
||||
} else {
|
||||
message.error(response.message || intl.formatMessage({ id: 'help.message.submitFailed' }));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('提交问题失败:', error);
|
||||
message.error(intl.formatMessage({ id: 'help.message.submitFailed' }));
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 处理取消按钮点击
|
||||
const handleCancel = () => {
|
||||
history.push('/help');
|
||||
};
|
||||
|
||||
// 处理返回列表按钮点击
|
||||
const handleBack = () => {
|
||||
history.push('/help');
|
||||
};
|
||||
|
||||
// 邮箱验证规则
|
||||
const emailValidator = (rule: any, value: string) => {
|
||||
if (!value || /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(value)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(intl.formatMessage({ id: 'help.form.email.invalid' }));
|
||||
};
|
||||
|
||||
// 手机号验证规则 (可选字段)
|
||||
const phoneValidator = (rule: any, value: string) => {
|
||||
if (!value || /^1[3-9]\d{9}$/.test(value)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(intl.formatMessage({ id: 'help.form.phone.invalid' }));
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.helpQuestionContainer}>
|
||||
<div className={styles.header}>
|
||||
<Button
|
||||
type="link"
|
||||
icon={<ArrowLeftOutlined />}
|
||||
onClick={handleBack}
|
||||
className={styles.backButton}
|
||||
>
|
||||
{intl.formatMessage({ id: 'help.back' })}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className={styles.contentWrapper}>
|
||||
<div className={styles.titleContainer}>
|
||||
<Title level={2}>{intl.formatMessage({ id: 'help.question.title' })}</Title>
|
||||
<p className={styles.subtitle}>
|
||||
{intl.formatMessage({ id: 'help.question.subtitle' })}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Divider className={styles.divider} />
|
||||
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
onFinish={handleSubmit}
|
||||
initialValues={{ type: QUESTION_TYPES[0]?.value }}
|
||||
className={styles.questionForm}
|
||||
>
|
||||
<Row gutter={24}>
|
||||
<Col span={24} md={12}>
|
||||
<Form.Item
|
||||
name="type"
|
||||
label={intl.formatMessage({ id: 'help.form.type' })}
|
||||
rules={[{ required: true, message: intl.formatMessage({ id: 'help.form.type.required' }) }]}
|
||||
>
|
||||
<Select placeholder={intl.formatMessage({ id: 'help.form.type.placeholder' })}>
|
||||
{QUESTION_TYPES.map(type => (
|
||||
<Option key={type.value} value={type.value}>
|
||||
{type.label}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={24} md={12}>
|
||||
<Form.Item
|
||||
name="title"
|
||||
label={intl.formatMessage({ id: 'help.form.title' })}
|
||||
rules={[{ required: true, message: intl.formatMessage({ id: 'help.form.title.required' }) }]}
|
||||
>
|
||||
<Input placeholder={intl.formatMessage({ id: 'help.form.title.placeholder' })} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Form.Item
|
||||
name="content"
|
||||
label={intl.formatMessage({ id: 'help.form.content' })}
|
||||
rules={[{ required: true, message: intl.formatMessage({ id: 'help.form.content.required' }) }]}
|
||||
>
|
||||
<div id="editor" className={styles.editor}></div>
|
||||
</Form.Item>
|
||||
|
||||
<Row gutter={24}>
|
||||
<Col span={24} md={12}>
|
||||
<Form.Item
|
||||
name="name"
|
||||
label={intl.formatMessage({ id: 'help.form.name' })}
|
||||
rules={[{ required: true, message: intl.formatMessage({ id: 'help.form.name.required' }) }]}
|
||||
>
|
||||
<Input placeholder={intl.formatMessage({ id: 'help.form.name.placeholder' })} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={24} md={12}>
|
||||
<Form.Item
|
||||
name="company"
|
||||
label={intl.formatMessage({ id: 'help.form.company' })}
|
||||
rules={[{ required: true, message: intl.formatMessage({ id: 'help.form.company.required' }) }]}
|
||||
>
|
||||
<Input placeholder={intl.formatMessage({ id: 'help.form.company.placeholder' })} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row gutter={24}>
|
||||
<Col span={24} md={12}>
|
||||
<Form.Item
|
||||
name="account"
|
||||
label={intl.formatMessage({ id: 'help.form.account' })}
|
||||
rules={[{ required: true, message: intl.formatMessage({ id: 'help.form.account.required' }) }]}
|
||||
>
|
||||
<Input placeholder={intl.formatMessage({ id: 'help.form.account.placeholder' })} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={24} md={12}>
|
||||
<Form.Item
|
||||
name="email"
|
||||
label={intl.formatMessage({ id: 'help.form.email' })}
|
||||
rules={[
|
||||
{ required: true, message: intl.formatMessage({ id: 'help.form.email.required' }) },
|
||||
{ validator: emailValidator }
|
||||
]}
|
||||
>
|
||||
<Input placeholder={intl.formatMessage({ id: 'help.form.email.placeholder' })} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row gutter={24}>
|
||||
<Col span={24} md={12}>
|
||||
<Form.Item
|
||||
name="phone"
|
||||
label={intl.formatMessage({ id: 'help.form.phone' })}
|
||||
rules={[{ validator: phoneValidator }]}
|
||||
>
|
||||
<Input placeholder={intl.formatMessage({ id: 'help.form.phone.placeholder' })} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Form.Item className={styles.buttonGroup}>
|
||||
<Button type="primary" htmlType="submit" loading={submitting} className={styles.submitButton}>
|
||||
{intl.formatMessage({ id: 'help.submit' })}
|
||||
</Button>
|
||||
<Button onClick={handleCancel} className={styles.cancelButton}>
|
||||
{intl.formatMessage({ id: 'help.cancel' })}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HelpQuestionPage;
|
@ -180,60 +180,67 @@ const IndexPage: React.FC = () => {
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
<Tabs onChange={tabChange}>
|
||||
{tabList.map((item) => (
|
||||
<Tabs.TabPane tab={item.label} key={item.key} />
|
||||
))}
|
||||
</Tabs>
|
||||
<div style={{ backgroundColor: '#fff', marginTop: '20px', padding: '20px' }}>
|
||||
<Tabs onChange={tabChange}>
|
||||
{tabList.map((item) => (
|
||||
<Tabs.TabPane tab={item.label} key={item.key} />
|
||||
))}
|
||||
</Tabs>
|
||||
|
||||
<Table loading={tableLoading} dataSource={dataSource} columns={columns} pagination={false} />
|
||||
<Table
|
||||
loading={tableLoading}
|
||||
dataSource={dataSource}
|
||||
columns={columns}
|
||||
pagination={false}
|
||||
/>
|
||||
|
||||
<div className="tableLoadMore">
|
||||
<Link
|
||||
to={{
|
||||
pathname: '/announce',
|
||||
}}
|
||||
>
|
||||
{intl.formatMessage({ id: '加载更多' })}
|
||||
</Link>
|
||||
<div className="tableLoadMore">
|
||||
<Link
|
||||
to={{
|
||||
pathname: '/announce',
|
||||
}}
|
||||
>
|
||||
{intl.formatMessage({ id: '加载更多' })}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<Row style={{ marginTop: '20px' }}>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
|
@ -1,66 +1,14 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Table, Typography } from 'antd';
|
||||
import { history } from 'umi';
|
||||
import { Table, Typography, message, ConfigProvider } from 'antd';
|
||||
import { history, useIntl, formatMessage } from 'umi';
|
||||
import styles from './policy.less';
|
||||
import { getRegulationsList, RegulationsRecord } from '@/servers/api/policy';
|
||||
|
||||
const { Title } = Typography;
|
||||
|
||||
// 模拟政策法规数据
|
||||
const mockPolicyData = [
|
||||
{
|
||||
id: '1',
|
||||
title: '关于进一步规范招标采购活动的管理办法',
|
||||
publishDate: '2023-08-15',
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
title: '中远海运集团供应商管理实施细则(2023年修订版)',
|
||||
publishDate: '2023-07-20',
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
title: '关于加强采购合同履约管理的通知',
|
||||
publishDate: '2023-06-10',
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
title: '中远海运集团招标采购管理办法',
|
||||
publishDate: '2023-05-25',
|
||||
},
|
||||
{
|
||||
id: '5',
|
||||
title: '关于优化招标采购流程提高采购效率的实施意见',
|
||||
publishDate: '2023-04-18',
|
||||
},
|
||||
{
|
||||
id: '6',
|
||||
title: '中远海运集团电子招标采购平台操作指南',
|
||||
publishDate: '2023-03-30',
|
||||
},
|
||||
{
|
||||
id: '7',
|
||||
title: '关于进一步加强采购风险防控的指导意见',
|
||||
publishDate: '2023-02-15',
|
||||
},
|
||||
{
|
||||
id: '8',
|
||||
title: '中远海运集团采购评审专家管理办法',
|
||||
publishDate: '2023-01-10',
|
||||
},
|
||||
{
|
||||
id: '9',
|
||||
title: '关于推进绿色采购的实施方案',
|
||||
publishDate: '2022-12-20',
|
||||
},
|
||||
{
|
||||
id: '10',
|
||||
title: '中远海运集团采购人员职业道德规范',
|
||||
publishDate: '2022-11-05',
|
||||
},
|
||||
];
|
||||
|
||||
const PolicyPage: React.FC = () => {
|
||||
const [policyData, setPolicyData] = useState<any[]>([]);
|
||||
const intl = useIntl();
|
||||
const [policyData, setPolicyData] = useState<RegulationsRecord[]>([]);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
const [pagination, setPagination] = useState({
|
||||
current: 1,
|
||||
@ -68,33 +16,56 @@ const PolicyPage: React.FC = () => {
|
||||
total: 0,
|
||||
});
|
||||
|
||||
// 模拟获取政策法规数据
|
||||
useEffect(() => {
|
||||
// 实际项目中应该通过API获取数据
|
||||
setTimeout(() => {
|
||||
setPolicyData(mockPolicyData);
|
||||
setPagination((prevPagination) => ({
|
||||
...prevPagination,
|
||||
total: mockPolicyData.length,
|
||||
}));
|
||||
// 获取政策法规数据
|
||||
const fetchPolicyData = async (pageNo: number = 1, pageSize: number = 10) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await getRegulationsList({
|
||||
basePageRequest: {
|
||||
pageNo,
|
||||
pageSize,
|
||||
}
|
||||
});
|
||||
|
||||
if (response.success) {
|
||||
setPolicyData(response.data.records || []);
|
||||
setPagination({
|
||||
current: response.data.current,
|
||||
pageSize: response.data.size,
|
||||
total: response.data.total,
|
||||
});
|
||||
} else {
|
||||
message.error(response.message || intl.formatMessage({ id: 'policy.message.getListFailed' }));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取政策法规列表出错:', error);
|
||||
message.error(intl.formatMessage({ id: 'policy.message.getListFailed' }));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}, 500);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
fetchPolicyData();
|
||||
}, []);
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleTableChange = (newPagination: any) => {
|
||||
fetchPolicyData(newPagination.current, newPagination.pageSize);
|
||||
setPagination(newPagination);
|
||||
};
|
||||
|
||||
// 处理点击政策标题
|
||||
const handlePolicyClick = (id: string) => {
|
||||
history.push(`/policy/policyInfo?id=${id}`);
|
||||
const handlePolicyClick = (id: string | undefined) => {
|
||||
if (id) {
|
||||
history.push(`/policy/policyInfo?id=${id}`);
|
||||
}
|
||||
};
|
||||
|
||||
// 定义表格列
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
title: intl.formatMessage({ id: 'policy.list.column.index' }),
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
width: 80,
|
||||
@ -103,20 +74,20 @@ const PolicyPage: React.FC = () => {
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '标题',
|
||||
title: intl.formatMessage({ id: 'policy.list.column.title' }),
|
||||
dataIndex: 'title',
|
||||
key: 'title',
|
||||
render: (text: string, record: any) => (
|
||||
render: (text: string, record: RegulationsRecord) => (
|
||||
<a onClick={() => handlePolicyClick(record.id)} className={styles.policyTitle}>
|
||||
{text}
|
||||
</a>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '发布时间',
|
||||
dataIndex: 'publishDate',
|
||||
key: 'publishDate',
|
||||
width: 150,
|
||||
title: intl.formatMessage({ id: 'policy.list.column.publishTime' }),
|
||||
dataIndex: 'createTime',
|
||||
key: 'createTime',
|
||||
width: 250,
|
||||
align: 'center' as 'center',
|
||||
},
|
||||
];
|
||||
@ -124,20 +95,29 @@ const PolicyPage: React.FC = () => {
|
||||
return (
|
||||
<div className={styles.policyContainer}>
|
||||
<div className={styles.policyTable}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={policyData}
|
||||
rowKey="id"
|
||||
pagination={{
|
||||
...pagination,
|
||||
showTotal: (total) => `共 ${total} 条记录`,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
}}
|
||||
loading={loading}
|
||||
onChange={handleTableChange}
|
||||
bordered
|
||||
/>
|
||||
<ConfigProvider
|
||||
renderEmpty={() => (
|
||||
<div className={styles.emptyData}>{intl.formatMessage({ id: 'policy.list.empty' })}</div>
|
||||
)}
|
||||
>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={policyData}
|
||||
rowKey="id"
|
||||
pagination={{
|
||||
...pagination,
|
||||
showTotal: (total) => intl.formatMessage(
|
||||
{ id: 'policy.list.total' },
|
||||
{ total }
|
||||
),
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
}}
|
||||
loading={loading}
|
||||
onChange={handleTableChange}
|
||||
bordered
|
||||
/>
|
||||
</ConfigProvider>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,8 +1,9 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useLocation } from 'umi';
|
||||
import { useLocation, history, useIntl } from 'umi';
|
||||
import { Typography, Button, Space, Divider, Row, Col, Spin, message } from 'antd';
|
||||
import { DownloadOutlined, ArrowLeftOutlined, FilePdfOutlined, FileWordOutlined, FileExcelOutlined } from '@ant-design/icons';
|
||||
import styles from './policyInfo.less';
|
||||
import { getRegulationsInfo, RegulationsRecord } from '@/servers/api/policy';
|
||||
|
||||
const { Title, Text } = Typography;
|
||||
|
||||
@ -167,28 +168,43 @@ const mockPolicyDetails: PolicyDetails = {
|
||||
};
|
||||
|
||||
const PolicyInfo: React.FC = () => {
|
||||
const intl = useIntl();
|
||||
const location = useLocation();
|
||||
const id = new URLSearchParams(location.search).get("id");
|
||||
const [policyDetail, setPolicyDetail] = useState<PolicyDetail | null>(null);
|
||||
const [policyDetail, setPolicyDetail] = useState<RegulationsRecord | null>(null);
|
||||
const [loading, setLoading] = useState<boolean>(true);
|
||||
|
||||
// 模拟获取政策法规详情数据
|
||||
// 获取政策法规详情数据
|
||||
useEffect(() => {
|
||||
// 实际项目中应该通过API获取数据
|
||||
setTimeout(() => {
|
||||
if (id && mockPolicyDetails[id]) {
|
||||
setPolicyDetail(mockPolicyDetails[id]);
|
||||
} else {
|
||||
// 处理ID不存在的情况
|
||||
message.error('政策法规不存在');
|
||||
const fetchPolicyDetail = async () => {
|
||||
if (!id) {
|
||||
message.error(intl.formatMessage({ id: 'policy.message.idNotExist' }));
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
setLoading(false);
|
||||
}, 500);
|
||||
}, [id]);
|
||||
|
||||
try {
|
||||
const response = await getRegulationsInfo({ id });
|
||||
|
||||
if (response.success) {
|
||||
setPolicyDetail(response.data);
|
||||
} else {
|
||||
message.error(response.message || intl.formatMessage({ id: 'policy.message.getDetailFailed' }));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取政策法规详情出错:', error);
|
||||
message.error(intl.formatMessage({ id: 'policy.message.getDetailFailed' }));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchPolicyDetail();
|
||||
}, [id, intl]);
|
||||
|
||||
// 处理返回列表
|
||||
const handleBack = () => {
|
||||
window.history.back();
|
||||
history.push('/policy');
|
||||
};
|
||||
|
||||
// 处理下载附件
|
||||
@ -216,7 +232,7 @@ const PolicyInfo: React.FC = () => {
|
||||
if (loading) {
|
||||
return (
|
||||
<div className={styles.loadingContainer}>
|
||||
<Spin size="large" />
|
||||
<Spin size="large" tip={intl.formatMessage({ id: 'policy.detail.loading' })} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -224,8 +240,10 @@ const PolicyInfo: React.FC = () => {
|
||||
if (!policyDetail) {
|
||||
return (
|
||||
<div className={styles.notFoundContainer}>
|
||||
<Title level={4}>未找到相关政策法规</Title>
|
||||
<Button type="primary" onClick={handleBack}>返回列表</Button>
|
||||
<Title level={4}>{intl.formatMessage({ id: 'policy.detail.notFound' })}</Title>
|
||||
<Button type="primary" onClick={handleBack}>
|
||||
{intl.formatMessage({ id: 'policy.detail.back' })}
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -239,7 +257,7 @@ const PolicyInfo: React.FC = () => {
|
||||
onClick={handleBack}
|
||||
className={styles.backButton}
|
||||
>
|
||||
返回列表
|
||||
{intl.formatMessage({ id: 'policy.detail.back' })}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@ -250,19 +268,28 @@ const PolicyInfo: React.FC = () => {
|
||||
</Title>
|
||||
</div>
|
||||
|
||||
<div className={styles.metaInfo}>
|
||||
<div className={styles.metaLeft}>
|
||||
<Text type="secondary">发布时间: {policyDetail.publishDate}</Text>
|
||||
</div>
|
||||
<div className={styles.metaRight}>
|
||||
<Text type="secondary">发布人: {policyDetail.publisher}</Text>
|
||||
</div>
|
||||
<div className={styles.metaContainer}>
|
||||
<Row>
|
||||
<Col span={12}>
|
||||
<Text type="secondary">
|
||||
{intl.formatMessage({ id: 'policy.detail.publishTime' })}: {policyDetail.createTime}
|
||||
</Text>
|
||||
</Col>
|
||||
<Col span={12} style={{ textAlign: 'right' }}>
|
||||
<Text type="secondary">
|
||||
{intl.formatMessage({ id: 'policy.detail.publisher' })}: {policyDetail.createBy}
|
||||
</Text>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
|
||||
<Divider className={styles.divider} />
|
||||
<Divider />
|
||||
|
||||
<div className={styles.contentBody}>
|
||||
<div dangerouslySetInnerHTML={{ __html: policyDetail.content }} />
|
||||
<div className={styles.contentContainer}>
|
||||
<div
|
||||
className={styles.content}
|
||||
dangerouslySetInnerHTML={{ __html: policyDetail.content || '' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{policyDetail.attachments && policyDetail.attachments.length > 0 && (
|
||||
|
Reference in New Issue
Block a user