对接通知中心与政策法规,包括多语言维护
This commit is contained in:
@ -7,12 +7,12 @@ export default {
|
|||||||
// },
|
// },
|
||||||
'/api': {
|
'/api': {
|
||||||
// target: 'http://10.242.37.148:18022',//连接天宫的ng
|
// target: 'http://10.242.37.148:18022',//连接天宫的ng
|
||||||
target: 'http://10.0.0.125:18012',//连接天宫的ng
|
target: 'http://10.0.0.14:18013',//连接天宫的ng
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
pathRewrite: { '^/api': '' },
|
pathRewrite: { '^/api': '' },
|
||||||
},
|
},
|
||||||
'/upload': {
|
'/upload': {
|
||||||
target: 'http://10.0.0.125:18012',//
|
target: 'http://10.0.0.14:18013',//
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
pathRewrite: { '^/upload': '' },
|
pathRewrite: { '^/upload': '' },
|
||||||
},
|
},
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import help from './en-US/help';
|
import help from './en-US/help';
|
||||||
import policy from './en-US/policy';
|
import policy from './en-US/policy';
|
||||||
|
import download from './en-US/download';
|
||||||
|
import notice from './en-US/notice';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
'menu.首页': 'Home',
|
'menu.首页': 'Home',
|
||||||
@ -104,4 +106,10 @@ export default {
|
|||||||
|
|
||||||
// Policy and Regulations module
|
// Policy and Regulations module
|
||||||
...policy,
|
...policy,
|
||||||
|
|
||||||
|
// Download Center module
|
||||||
|
...download,
|
||||||
|
|
||||||
|
// Notice Center module
|
||||||
|
...notice,
|
||||||
};
|
};
|
||||||
|
15
src/locales/en-US/download.ts
Normal file
15
src/locales/en-US/download.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export default {
|
||||||
|
// Download center page
|
||||||
|
'download.title': 'Download Center',
|
||||||
|
'download.menu.template': 'Templates',
|
||||||
|
'download.menu.manual': 'Manuals',
|
||||||
|
'download.card.date': 'Published: {publishTime}',
|
||||||
|
'download.button': 'Download',
|
||||||
|
'download.empty': 'No files available for download',
|
||||||
|
'download.list.total': 'Total {total} Records',
|
||||||
|
|
||||||
|
// Download center messages
|
||||||
|
'download.message.downloadFailed': 'Download failed, please try again later',
|
||||||
|
'download.message.getListFailed': 'Failed to get download list',
|
||||||
|
'download.message.getListError': 'Error getting download list, please try again later',
|
||||||
|
};
|
29
src/locales/en-US/notice.ts
Normal file
29
src/locales/en-US/notice.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
export default {
|
||||||
|
// Notice center list page
|
||||||
|
'notice.title': 'Notifications',
|
||||||
|
'notice.menu.system': 'System Updates',
|
||||||
|
'notice.menu.other': 'Other Notifications',
|
||||||
|
'notice.list.column.index': 'No.',
|
||||||
|
'notice.list.column.title': 'Title',
|
||||||
|
'notice.list.column.publishTime': 'Publish Time',
|
||||||
|
'notice.list.empty': 'No notifications',
|
||||||
|
'notice.list.total': 'Total {total} Records',
|
||||||
|
|
||||||
|
// Notice center detail page
|
||||||
|
'notice.detail.back': 'Back to List',
|
||||||
|
'notice.detail.publishTime': 'Publish Time',
|
||||||
|
'notice.detail.publisher': 'Publisher',
|
||||||
|
'notice.detail.type': 'Notice Type',
|
||||||
|
'notice.detail.type.notice': 'Announcement',
|
||||||
|
'notice.detail.type.system': 'System Notification',
|
||||||
|
'notice.detail.type.other': 'Other Notification',
|
||||||
|
'notice.detail.notFound': 'Notice Not Found',
|
||||||
|
'notice.detail.loading': 'Loading...',
|
||||||
|
|
||||||
|
// Notice center messages
|
||||||
|
'notice.message.getListFailed': 'Failed to get notification list',
|
||||||
|
'notice.message.getListError': 'Error getting notification list, please try again later',
|
||||||
|
'notice.message.getDetailFailed': 'Failed to get notification detail',
|
||||||
|
'notice.message.getDetailError': 'Error getting notification detail, please try again later',
|
||||||
|
'notice.message.idNotExist': 'Notice ID cannot be empty',
|
||||||
|
};
|
@ -1,5 +1,7 @@
|
|||||||
import help from './zh-CN/help';
|
import help from './zh-CN/help';
|
||||||
import policy from './zh-CN/policy';
|
import policy from './zh-CN/policy';
|
||||||
|
import download from './zh-CN/download';
|
||||||
|
import notice from './zh-CN/notice';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
'menu.首页': '首页',
|
'menu.首页': '首页',
|
||||||
@ -104,4 +106,10 @@ export default {
|
|||||||
|
|
||||||
// 政策法规模块
|
// 政策法规模块
|
||||||
...policy,
|
...policy,
|
||||||
|
|
||||||
|
// 下载中心模块
|
||||||
|
...download,
|
||||||
|
|
||||||
|
// 通知中心模块
|
||||||
|
...notice,
|
||||||
};
|
};
|
||||||
|
15
src/locales/zh-CN/download.ts
Normal file
15
src/locales/zh-CN/download.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
export default {
|
||||||
|
// 下载中心页面
|
||||||
|
'download.title': '下载中心',
|
||||||
|
'download.menu.template': '模板文件',
|
||||||
|
'download.menu.manual': '操作手册',
|
||||||
|
'download.card.date': '发布时间: {publishTime}',
|
||||||
|
'download.button': '下载',
|
||||||
|
'download.empty': '暂无可下载的文件',
|
||||||
|
'download.list.total': '共 {total} 条记录',
|
||||||
|
|
||||||
|
// 下载中心消息
|
||||||
|
'download.message.downloadFailed': '下载失败,请稍后重试',
|
||||||
|
'download.message.getListFailed': '获取下载列表失败',
|
||||||
|
'download.message.getListError': '获取下载列表出错,请稍后重试',
|
||||||
|
};
|
29
src/locales/zh-CN/notice.ts
Normal file
29
src/locales/zh-CN/notice.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
export default {
|
||||||
|
// 通知中心列表页面
|
||||||
|
'notice.title': '通知中心',
|
||||||
|
'notice.menu.system': '系统更新通知',
|
||||||
|
'notice.menu.other': '其他通知',
|
||||||
|
'notice.list.column.index': '序号',
|
||||||
|
'notice.list.column.title': '标题',
|
||||||
|
'notice.list.column.publishTime': '发布时间',
|
||||||
|
'notice.list.empty': '暂无通知',
|
||||||
|
'notice.list.total': '共 {total} 条记录',
|
||||||
|
|
||||||
|
// 通知中心详情页面
|
||||||
|
'notice.detail.back': '返回列表',
|
||||||
|
'notice.detail.publishTime': '发布时间',
|
||||||
|
'notice.detail.publisher': '发布人',
|
||||||
|
'notice.detail.type': '通知类型',
|
||||||
|
'notice.detail.type.notice': '通知公告',
|
||||||
|
'notice.detail.type.system': '系统通知',
|
||||||
|
'notice.detail.type.other': '其他通知',
|
||||||
|
'notice.detail.notFound': '未找到相关通知',
|
||||||
|
'notice.detail.loading': '加载中...',
|
||||||
|
|
||||||
|
// 通知中心消息
|
||||||
|
'notice.message.getListFailed': '获取通知列表失败',
|
||||||
|
'notice.message.getListError': '获取通知列表出错,请稍后重试',
|
||||||
|
'notice.message.getDetailFailed': '获取通知详情失败',
|
||||||
|
'notice.message.getDetailError': '获取通知详情出错,请稍后重试',
|
||||||
|
'notice.message.idNotExist': '通知ID不能为空',
|
||||||
|
};
|
@ -1,121 +1,22 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Card, Menu, Row, Col, Pagination, Button, Typography, Space, message } from 'antd';
|
import { Card, Menu, Row, Col, Pagination, Button, Typography, Space, message } from 'antd';
|
||||||
import { FileOutlined, BookOutlined, DownloadOutlined } from '@ant-design/icons';
|
import { FileOutlined, BookOutlined, DownloadOutlined } from '@ant-design/icons';
|
||||||
|
import { useIntl, FormattedMessage } from 'umi';
|
||||||
import styles from './download.less';
|
import styles from './download.less';
|
||||||
import { downloadFile } from './service';
|
import { downloadFile, getDownloadList, DownloadRecord } from '@/servers/api/download';
|
||||||
|
|
||||||
const { Title, Text } = Typography;
|
const { Title, Text } = Typography;
|
||||||
|
|
||||||
// 模拟模板文件数据
|
// 模拟模板文件数据 - 后期将通过API获取分类
|
||||||
const mockTemplateFiles = [
|
const mockCategories: { [key: string]: string } = {
|
||||||
{
|
template: '模板文件',
|
||||||
id: '1',
|
manual: '操作手册'
|
||||||
title: '公开招标操作手册',
|
};
|
||||||
description: '公开招标各角色操作手册',
|
|
||||||
publishDate: '2025年2月3日',
|
|
||||||
type: 'template',
|
|
||||||
icon: <FileOutlined />,
|
|
||||||
fileName: '公开招标操作手册.pdf',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '2',
|
|
||||||
title: '询价采购模板',
|
|
||||||
description: '标准询价采购流程文档模板',
|
|
||||||
publishDate: '2025年1月15日',
|
|
||||||
type: 'template',
|
|
||||||
icon: <FileOutlined />,
|
|
||||||
fileName: '询价采购模板.docx',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3',
|
|
||||||
title: '竞争性谈判模板',
|
|
||||||
description: '竞争性谈判标准文档模板',
|
|
||||||
publishDate: '2024年12月20日',
|
|
||||||
type: 'template',
|
|
||||||
icon: <FileOutlined />,
|
|
||||||
fileName: '竞争性谈判模板.docx',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '4',
|
|
||||||
title: '单一来源采购模板',
|
|
||||||
description: '单一来源采购申请及实施模板',
|
|
||||||
publishDate: '2024年12月5日',
|
|
||||||
type: 'template',
|
|
||||||
icon: <FileOutlined />,
|
|
||||||
fileName: '单一来源采购模板.docx',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '5',
|
|
||||||
title: '供应商评估表格',
|
|
||||||
description: '供应商资质与能力评估标准表格',
|
|
||||||
publishDate: '2024年11月18日',
|
|
||||||
type: 'template',
|
|
||||||
icon: <FileOutlined />,
|
|
||||||
fileName: '供应商评估表格.xlsx',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '6',
|
|
||||||
title: '合同范本模板',
|
|
||||||
description: '标准采购合同范本',
|
|
||||||
publishDate: '2024年11月1日',
|
|
||||||
type: 'template',
|
|
||||||
icon: <FileOutlined />,
|
|
||||||
fileName: '合同范本模板.docx',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
// 模拟操作手册数据
|
|
||||||
const mockManuals = [
|
|
||||||
{
|
|
||||||
id: '7',
|
|
||||||
title: '供应商注册指南',
|
|
||||||
description: '供应商平台注册及资质提交操作指南',
|
|
||||||
publishDate: '2025年1月25日',
|
|
||||||
type: 'manual',
|
|
||||||
icon: <BookOutlined />,
|
|
||||||
fileName: '供应商注册指南.pdf',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '8',
|
|
||||||
title: '投标操作指南',
|
|
||||||
description: '电子投标全流程操作手册',
|
|
||||||
publishDate: '2025年1月10日',
|
|
||||||
type: 'manual',
|
|
||||||
icon: <BookOutlined />,
|
|
||||||
fileName: '投标操作指南.pdf',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '9',
|
|
||||||
title: '在线开标指南',
|
|
||||||
description: '在线开标会议参与指南',
|
|
||||||
publishDate: '2024年12月15日',
|
|
||||||
type: 'manual',
|
|
||||||
icon: <BookOutlined />,
|
|
||||||
fileName: '在线开标指南.pdf',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '10',
|
|
||||||
title: '评标专家操作手册',
|
|
||||||
description: '评标专家系统使用指南',
|
|
||||||
publishDate: '2024年11月28日',
|
|
||||||
type: 'manual',
|
|
||||||
icon: <BookOutlined />,
|
|
||||||
fileName: '评标专家操作手册.pdf',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '11',
|
|
||||||
title: '合同签署指南',
|
|
||||||
description: '电子合同签署流程指南',
|
|
||||||
publishDate: '2024年11月10日',
|
|
||||||
type: 'manual',
|
|
||||||
icon: <BookOutlined />,
|
|
||||||
fileName: '合同签署指南.pdf',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const DownloadPage: React.FC = () => {
|
const DownloadPage: React.FC = () => {
|
||||||
|
const intl = useIntl();
|
||||||
const [activeMenu, setActiveMenu] = useState<string>('template');
|
const [activeMenu, setActiveMenu] = useState<string>('template');
|
||||||
const [downloadData, setDownloadData] = useState<any[]>([]);
|
const [downloadData, setDownloadData] = useState<DownloadRecord[]>([]);
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
const [pagination, setPagination] = useState({
|
const [pagination, setPagination] = useState({
|
||||||
current: 1,
|
current: 1,
|
||||||
@ -123,51 +24,75 @@ const DownloadPage: React.FC = () => {
|
|||||||
total: 0,
|
total: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 根据当前选中的菜单加载对应的下载数据
|
// 加载下载数据
|
||||||
useEffect(() => {
|
const loadDownloadData = async (page: number, pageSize: number) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// 模拟API请求
|
try {
|
||||||
setTimeout(() => {
|
const response = await getDownloadList({
|
||||||
const data = activeMenu === 'template' ? mockTemplateFiles : mockManuals;
|
pageNo: page.toString(),
|
||||||
setDownloadData(data);
|
pageSize: pageSize.toString()
|
||||||
setPagination((prevPagination) => ({
|
});
|
||||||
...prevPagination,
|
|
||||||
total: data.length,
|
if (response.code === 200 && response.success) {
|
||||||
current: 1,
|
// 根据当前选中的菜单过滤数据
|
||||||
}));
|
// 目前没有分类的API,暂时都显示,后期可以根据columnType进行过滤
|
||||||
|
const data = response.data.records;
|
||||||
|
|
||||||
|
setDownloadData(data);
|
||||||
|
setPagination({
|
||||||
|
current: response.data.current,
|
||||||
|
pageSize: response.data.size,
|
||||||
|
total: response.data.total,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
message.error(response.message || intl.formatMessage({ id: 'download.message.getListFailed' }));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取下载列表出错:', error);
|
||||||
|
message.error(intl.formatMessage({ id: 'download.message.getListError' }));
|
||||||
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}, 500);
|
}
|
||||||
}, [activeMenu]);
|
};
|
||||||
|
|
||||||
|
// 初始加载和分页变化时加载数据
|
||||||
|
useEffect(() => {
|
||||||
|
loadDownloadData(pagination.current, pagination.pageSize);
|
||||||
|
}, [pagination.current, activeMenu]);
|
||||||
|
|
||||||
// 处理菜单切换
|
// 处理菜单切换
|
||||||
const handleMenuClick = (e: any) => {
|
const handleMenuClick = (e: any) => {
|
||||||
setActiveMenu(e.key);
|
setActiveMenu(e.key);
|
||||||
|
setPagination({
|
||||||
|
...pagination,
|
||||||
|
current: 1, // 切换分类时重置页码
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理分页变化
|
// 处理分页变化
|
||||||
const handlePageChange = (page: number, pageSize?: number) => {
|
const handlePageChange = (page: number, pageSize?: number) => {
|
||||||
|
const newPageSize = pageSize || pagination.pageSize;
|
||||||
setPagination({
|
setPagination({
|
||||||
...pagination,
|
...pagination,
|
||||||
current: page,
|
current: page,
|
||||||
pageSize: pageSize || pagination.pageSize,
|
pageSize: newPageSize,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理下载按钮点击
|
// 处理下载按钮点击
|
||||||
const handleDownload = async (id: string, fileName: string) => {
|
const handleDownload = async (item: DownloadRecord) => {
|
||||||
try {
|
try {
|
||||||
await downloadFile(id, fileName);
|
window.open(item.fileUrl, '_blank');
|
||||||
|
// await downloadFile(id, fileName);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
message.error('下载失败,请稍后重试');
|
message.error(intl.formatMessage({ id: 'download.message.downloadFailed' }));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 计算当前页显示的数据
|
// 获取文件图标
|
||||||
const getCurrentPageData = () => {
|
const getFileIcon = (fileType: string) => {
|
||||||
const { current, pageSize } = pagination;
|
// 根据文件类型返回不同图标,可以进一步完善
|
||||||
const startIndex = (current - 1) * pageSize;
|
return <FileOutlined />;
|
||||||
const endIndex = startIndex + pageSize;
|
|
||||||
return downloadData.slice(startIndex, endIndex);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -181,55 +106,78 @@ const DownloadPage: React.FC = () => {
|
|||||||
className={styles.downloadMenu}
|
className={styles.downloadMenu}
|
||||||
>
|
>
|
||||||
<Menu.Item key="template" icon={<FileOutlined />}>
|
<Menu.Item key="template" icon={<FileOutlined />}>
|
||||||
模板文件
|
<FormattedMessage id="download.menu.template" />
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item key="manual" icon={<BookOutlined />}>
|
<Menu.Item key="manual" icon={<BookOutlined />}>
|
||||||
操作手册
|
<FormattedMessage id="download.menu.manual" />
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col span={20}>
|
<Col span={20}>
|
||||||
<div className={styles.downloadContent}>
|
<div className={styles.downloadContent}>
|
||||||
<Title level={4}>{activeMenu === 'template' ? '模板文件' : '操作手册'}</Title>
|
<Title level={4}>
|
||||||
|
<FormattedMessage id={`download.menu.${activeMenu}`} defaultMessage={intl.formatMessage({ id: 'download.title' })} />
|
||||||
|
</Title>
|
||||||
|
|
||||||
<Row gutter={[16, 16]} className={styles.downloadCardList}>
|
<Row gutter={[16, 16]} className={styles.downloadCardList}>
|
||||||
{getCurrentPageData().map((item) => (
|
{loading ? (
|
||||||
<Col xs={24} sm={12} md={8} key={item.id}>
|
Array(6).fill(null).map((_, index) => (
|
||||||
<Card
|
<Col xs={24} sm={12} md={8} key={`loading-${index}`}>
|
||||||
hoverable
|
<Card loading={true} className={styles.downloadCard}></Card>
|
||||||
className={styles.downloadCard}
|
</Col>
|
||||||
loading={loading}
|
))
|
||||||
>
|
) : downloadData.length > 0 ? (
|
||||||
<Space direction="vertical" size="small" style={{ width: '100%' }}>
|
downloadData.map((item) => (
|
||||||
<div className={styles.cardTitle}>
|
<Col xs={24} sm={12} md={8} key={item.id}>
|
||||||
<span className={styles.downloadIcon}>{item.icon}</span>
|
<Card
|
||||||
{item.title}
|
hoverable
|
||||||
</div>
|
className={styles.downloadCard}
|
||||||
<div className={styles.cardDate}>{item.publishDate}</div>
|
>
|
||||||
<Text type="secondary" ellipsis={{ tooltip: true }}>{item.description}</Text>
|
<Space direction="vertical" size="small" style={{ width: '100%' }}>
|
||||||
<Button
|
<div className={styles.cardTitle}>
|
||||||
type="primary"
|
<span className={styles.downloadIcon}>{getFileIcon(item.fileType)}</span>
|
||||||
icon={<DownloadOutlined />}
|
{item.name}
|
||||||
className={styles.downloadButton}
|
</div>
|
||||||
onClick={() => handleDownload(item.id, item.fileName)}
|
<div className={styles.cardDate}>
|
||||||
>
|
{intl.formatMessage(
|
||||||
下载
|
{ id: 'download.card.date' },
|
||||||
</Button>
|
{ publishTime: item.publishTime || '' }
|
||||||
</Space>
|
)}
|
||||||
</Card>
|
</div>
|
||||||
|
<Text type="secondary" ellipsis={{ tooltip: true }}>{item.keywords || ''}</Text>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
icon={<DownloadOutlined />}
|
||||||
|
className={styles.downloadButton}
|
||||||
|
onClick={() => handleDownload(item)}
|
||||||
|
>
|
||||||
|
<FormattedMessage id="download.button" />
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Col span={24} style={{ textAlign: 'center', margin: '30px 0' }}>
|
||||||
|
<Text type="secondary"><FormattedMessage id="download.empty" /></Text>
|
||||||
</Col>
|
</Col>
|
||||||
))}
|
)}
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Pagination
|
{downloadData.length > 0 && (
|
||||||
current={pagination.current}
|
<Pagination
|
||||||
pageSize={pagination.pageSize}
|
current={pagination.current}
|
||||||
total={pagination.total}
|
pageSize={pagination.pageSize}
|
||||||
onChange={handlePageChange}
|
total={pagination.total}
|
||||||
showTotal={(total) => `共 ${total} 条记录`}
|
onChange={handlePageChange}
|
||||||
style={{ marginTop: 24, textAlign: 'right' }}
|
showTotal={(total) => intl.formatMessage(
|
||||||
/>
|
{ id: 'download.list.total' },
|
||||||
|
{ total }
|
||||||
|
)}
|
||||||
|
style={{ marginTop: 24, textAlign: 'right' }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
@ -1,75 +0,0 @@
|
|||||||
import { message } from 'antd';
|
|
||||||
import request from '@/utils/request';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取下载中心文件列表
|
|
||||||
* @param params 查询参数
|
|
||||||
*/
|
|
||||||
export async function getDownloadList(params: {
|
|
||||||
type: string;
|
|
||||||
current: number;
|
|
||||||
pageSize: number;
|
|
||||||
}) {
|
|
||||||
try {
|
|
||||||
// 实际项目中应该通过API获取数据
|
|
||||||
// return request('/api/download/list', {
|
|
||||||
// method: 'GET',
|
|
||||||
// params,
|
|
||||||
// });
|
|
||||||
|
|
||||||
// 模拟API请求返回数据
|
|
||||||
return Promise.resolve({
|
|
||||||
success: true,
|
|
||||||
data: {
|
|
||||||
list: [],
|
|
||||||
total: 0,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
message.error('获取下载列表失败');
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
data: {
|
|
||||||
list: [],
|
|
||||||
total: 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载文件
|
|
||||||
* @param fileId 文件ID
|
|
||||||
* @param fileName 文件名称
|
|
||||||
*/
|
|
||||||
export async function downloadFile(fileId: string, fileName: string) {
|
|
||||||
try {
|
|
||||||
// 实际项目中应该通过API下载文件
|
|
||||||
// const response = await request(`/api/download/file/${fileId}`, {
|
|
||||||
// method: 'GET',
|
|
||||||
// responseType: 'blob',
|
|
||||||
// });
|
|
||||||
|
|
||||||
// 创建下载链接
|
|
||||||
// const blob = new Blob([response]);
|
|
||||||
// const url = window.URL.createObjectURL(blob);
|
|
||||||
// const link = document.createElement('a');
|
|
||||||
// link.href = url;
|
|
||||||
// link.download = fileName;
|
|
||||||
// document.body.appendChild(link);
|
|
||||||
// link.click();
|
|
||||||
// window.URL.revokeObjectURL(url);
|
|
||||||
// document.body.removeChild(link);
|
|
||||||
|
|
||||||
// 模拟下载成功
|
|
||||||
message.success(`文件"${fileName}"开始下载`);
|
|
||||||
return {
|
|
||||||
success: true,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
message.error(`下载文件"${fileName}"失败`);
|
|
||||||
return {
|
|
||||||
success: false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
@ -4,7 +4,7 @@ import { ArrowLeftOutlined } from '@ant-design/icons';
|
|||||||
import { history, useIntl } from 'umi';
|
import { history, useIntl } from 'umi';
|
||||||
import WangEditor from 'wangeditor';
|
import WangEditor from 'wangeditor';
|
||||||
import { QUESTION_TYPES } from '@/dicts/help';
|
import { QUESTION_TYPES } from '@/dicts/help';
|
||||||
import { addHelpQuestion } from '@/servers/api/help';
|
import { addHelpCenterQuestion } from '@/servers/api/help';
|
||||||
import styles from './helpQuestion.less';
|
import styles from './helpQuestion.less';
|
||||||
|
|
||||||
const { Title } = Typography;
|
const { Title } = Typography;
|
||||||
@ -70,9 +70,13 @@ const HelpQuestionPage: React.FC = () => {
|
|||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await addHelpQuestion({
|
const response = await addHelpCenterQuestion({
|
||||||
...values,
|
...values,
|
||||||
content: content,
|
content: content,
|
||||||
|
companyName: values.company,
|
||||||
|
contactDetails: values.email,
|
||||||
|
fullName: values.name,
|
||||||
|
userName: values.account,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.success) {
|
if (response.success) {
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Card, Row, Col, Tabs, Table } from 'antd';
|
import { Card, Row, Col, Tabs, Table } from 'antd';
|
||||||
import { useIntl, Link } from 'umi';
|
import { useIntl, Link } from 'umi';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
import IconFont from '@/components/IconFont/IconFont';
|
import IconFont from '@/components/IconFont/IconFont';
|
||||||
import LinkComponent from './Link';
|
import LinkComponent from './Link';
|
||||||
|
import { getCoscoPortalsLinksClassification } from '@/servers/api';
|
||||||
const IndexPage: React.FC = () => {
|
const IndexPage: React.FC = () => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [noticeLoading, setNoticeLoading] = useState(false);
|
const [noticeLoading, setNoticeLoading] = useState(false);
|
||||||
@ -152,6 +153,12 @@ const IndexPage: React.FC = () => {
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getCoscoPortalsLinksClassification().then((res) => {
|
||||||
|
console.log(res);
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{/* 通知列表 */}
|
{/* 通知列表 */}
|
||||||
|
@ -45,7 +45,7 @@ const LoginPage: React.FC = () => {
|
|||||||
|
|
||||||
// 渲染注册链接(只在供应商和专家Tab下显示)
|
// 渲染注册链接(只在供应商和专家Tab下显示)
|
||||||
const renderRegisterLink = () => {
|
const renderRegisterLink = () => {
|
||||||
if (activeKey === 'agent') {
|
if (activeKey === 'agent' || activeKey === 'expert') {
|
||||||
return null; // 招标代理不显示注册链接
|
return null; // 招标代理不显示注册链接
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,80 +1,20 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Table, Menu, Row, Col } from 'antd';
|
import { Table, Menu, Row, Col, message } from 'antd';
|
||||||
import { history } from 'umi';
|
import { history, useIntl, FormattedMessage } from 'umi';
|
||||||
import { BellOutlined, AppstoreOutlined } from '@ant-design/icons';
|
import { BellOutlined, AppstoreOutlined } from '@ant-design/icons';
|
||||||
import styles from './notice.less';
|
import styles from './notice.less';
|
||||||
|
import { getNoticeList, NoticeRecord } from '@/servers/api/notice';
|
||||||
|
|
||||||
// 模拟系统更新通知数据
|
// 通知类型映射
|
||||||
const mockSystemNotices = [
|
const noticeTypes: { [key: string]: string } = {
|
||||||
{
|
system: '系统更新通知',
|
||||||
id: '1',
|
other: '其他通知'
|
||||||
title: '系统将于2023年9月15日进行版本升级',
|
};
|
||||||
publishDate: '2023-09-10',
|
|
||||||
type: 'system',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '2',
|
|
||||||
title: '招标模块功能优化更新通知',
|
|
||||||
publishDate: '2023-08-25',
|
|
||||||
type: 'system',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '3',
|
|
||||||
title: '系统安全性能升级维护通知',
|
|
||||||
publishDate: '2023-08-10',
|
|
||||||
type: 'system',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '4',
|
|
||||||
title: '移动端应用同步更新通知',
|
|
||||||
publishDate: '2023-07-28',
|
|
||||||
type: 'system',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '5',
|
|
||||||
title: '供应商管理模块功能升级通知',
|
|
||||||
publishDate: '2023-07-15',
|
|
||||||
type: 'system',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
// 模拟其他通知数据
|
|
||||||
const mockOtherNotices = [
|
|
||||||
{
|
|
||||||
id: '6',
|
|
||||||
title: '关于开展2023年度供应商评估工作的通知',
|
|
||||||
publishDate: '2023-09-05',
|
|
||||||
type: 'other',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '7',
|
|
||||||
title: '关于调整采购审批流程的通知',
|
|
||||||
publishDate: '2023-08-20',
|
|
||||||
type: 'other',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '8',
|
|
||||||
title: '关于加强信息安全管理的通知',
|
|
||||||
publishDate: '2023-08-05',
|
|
||||||
type: 'other',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '9',
|
|
||||||
title: '关于开展采购人员培训的通知',
|
|
||||||
publishDate: '2023-07-25',
|
|
||||||
type: 'other',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '10',
|
|
||||||
title: '关于优化供应商准入机制的通知',
|
|
||||||
publishDate: '2023-07-10',
|
|
||||||
type: 'other',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const NoticePage: React.FC = () => {
|
const NoticePage: React.FC = () => {
|
||||||
|
const intl = useIntl();
|
||||||
const [activeMenu, setActiveMenu] = useState<string>('system');
|
const [activeMenu, setActiveMenu] = useState<string>('system');
|
||||||
const [noticeData, setNoticeData] = useState<any[]>([]);
|
const [noticeData, setNoticeData] = useState<NoticeRecord[]>([]);
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
const [pagination, setPagination] = useState({
|
const [pagination, setPagination] = useState({
|
||||||
current: 1,
|
current: 1,
|
||||||
@ -82,33 +22,58 @@ const NoticePage: React.FC = () => {
|
|||||||
total: 0,
|
total: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
// 根据当前选中的菜单加载对应的通知数据
|
// 加载通知数据
|
||||||
useEffect(() => {
|
const loadNoticeData = async (page: number, pageSize: number) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// 模拟API请求
|
try {
|
||||||
setTimeout(() => {
|
const response = await getNoticeList({
|
||||||
const data = activeMenu === 'system' ? mockSystemNotices : mockOtherNotices;
|
pageNo: page.toString(),
|
||||||
setNoticeData(data);
|
pageSize: pageSize.toString()
|
||||||
setPagination((prevPagination) => ({
|
});
|
||||||
...prevPagination,
|
|
||||||
total: data.length,
|
if (response.code === 200 && response.success) {
|
||||||
}));
|
// 根据当前选中的菜单过滤数据
|
||||||
|
// 目前没有分类的API,暂时都显示,后期可以根据不同类型进行过滤
|
||||||
|
const data = response.data.records;
|
||||||
|
|
||||||
|
setNoticeData(data);
|
||||||
|
setPagination({
|
||||||
|
current: response.data.current,
|
||||||
|
pageSize: response.data.size,
|
||||||
|
total: response.data.total,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
message.error(response.message || intl.formatMessage({ id: 'notice.message.getListFailed' }));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取通知列表出错:', error);
|
||||||
|
message.error(intl.formatMessage({ id: 'notice.message.getListError' }));
|
||||||
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}, 500);
|
}
|
||||||
}, [activeMenu]);
|
};
|
||||||
|
|
||||||
|
// 初始加载和分页变化时加载数据
|
||||||
|
useEffect(() => {
|
||||||
|
loadNoticeData(pagination.current, pagination.pageSize);
|
||||||
|
}, [pagination.current, activeMenu]);
|
||||||
|
|
||||||
// 处理菜单切换
|
// 处理菜单切换
|
||||||
const handleMenuClick = (e: any) => {
|
const handleMenuClick = (e: any) => {
|
||||||
setActiveMenu(e.key);
|
setActiveMenu(e.key);
|
||||||
setPagination({
|
setPagination({
|
||||||
...pagination,
|
...pagination,
|
||||||
current: 1,
|
current: 1, // 切换分类时重置页码
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理表格分页变化
|
// 处理表格分页变化
|
||||||
const handleTableChange = (newPagination: any) => {
|
const handleTableChange = (newPagination: any) => {
|
||||||
setPagination(newPagination);
|
setPagination({
|
||||||
|
...pagination,
|
||||||
|
current: newPagination.current,
|
||||||
|
pageSize: newPagination.pageSize,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 处理点击通知标题
|
// 处理点击通知标题
|
||||||
@ -119,7 +84,7 @@ const NoticePage: React.FC = () => {
|
|||||||
// 定义表格列
|
// 定义表格列
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: '序号',
|
title: intl.formatMessage({ id: 'notice.list.column.index' }),
|
||||||
dataIndex: 'index',
|
dataIndex: 'index',
|
||||||
key: 'index',
|
key: 'index',
|
||||||
width: 80,
|
width: 80,
|
||||||
@ -128,19 +93,19 @@ const NoticePage: React.FC = () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '标题',
|
title: intl.formatMessage({ id: 'notice.list.column.title' }),
|
||||||
dataIndex: 'title',
|
dataIndex: 'title',
|
||||||
key: 'title',
|
key: 'title',
|
||||||
render: (text: string, record: any) => (
|
render: (text: string, record: NoticeRecord) => (
|
||||||
<a onClick={() => handleNoticeClick(record.id)} className={styles.noticeTitle}>
|
<a onClick={() => handleNoticeClick(record.id)} className={styles.noticeTitle}>
|
||||||
{text}
|
{text}
|
||||||
</a>
|
</a>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '发布时间',
|
title: intl.formatMessage({ id: 'notice.list.column.publishTime' }),
|
||||||
dataIndex: 'publishDate',
|
dataIndex: 'publishTime',
|
||||||
key: 'publishDate',
|
key: 'publishTime',
|
||||||
width: 150,
|
width: 150,
|
||||||
align: 'center' as 'center',
|
align: 'center' as 'center',
|
||||||
},
|
},
|
||||||
@ -157,10 +122,10 @@ const NoticePage: React.FC = () => {
|
|||||||
className={styles.noticeMenu}
|
className={styles.noticeMenu}
|
||||||
>
|
>
|
||||||
<Menu.Item key="system" icon={<AppstoreOutlined />}>
|
<Menu.Item key="system" icon={<AppstoreOutlined />}>
|
||||||
系统更新通知
|
<FormattedMessage id="notice.menu.system" />
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item key="other" icon={<BellOutlined />}>
|
<Menu.Item key="other" icon={<BellOutlined />}>
|
||||||
其他通知
|
<FormattedMessage id="notice.menu.other" />
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
</Col>
|
</Col>
|
||||||
@ -173,13 +138,19 @@ const NoticePage: React.FC = () => {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
pagination={{
|
pagination={{
|
||||||
...pagination,
|
...pagination,
|
||||||
showTotal: (total) => `共 ${total} 条记录`,
|
showTotal: (total) => intl.formatMessage(
|
||||||
|
{ id: 'notice.list.total' },
|
||||||
|
{ total }
|
||||||
|
),
|
||||||
showSizeChanger: true,
|
showSizeChanger: true,
|
||||||
showQuickJumper: true,
|
showQuickJumper: true,
|
||||||
}}
|
}}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
bordered
|
bordered
|
||||||
|
locale={{
|
||||||
|
emptyText: intl.formatMessage({ id: 'notice.list.empty' })
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
|
@ -1,182 +1,45 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { useLocation } from 'umi';
|
import { useLocation, useIntl, FormattedMessage } from 'umi';
|
||||||
import { Typography, Button, Divider, Spin, message } from 'antd';
|
import { Typography, Button, Divider, Spin, message } from 'antd';
|
||||||
import { ArrowLeftOutlined } from '@ant-design/icons';
|
import { ArrowLeftOutlined } from '@ant-design/icons';
|
||||||
import styles from './noticeInfo.less';
|
import styles from './noticeInfo.less';
|
||||||
|
import { getNoticeDetail, NoticeRecord } from '@/servers/api/notice';
|
||||||
|
|
||||||
const { Title, Text } = Typography;
|
const { Title, Text } = Typography;
|
||||||
|
|
||||||
interface NoticeDetail {
|
|
||||||
id: string;
|
|
||||||
title: string;
|
|
||||||
content: string;
|
|
||||||
publishDate: string;
|
|
||||||
publisher: string;
|
|
||||||
type: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface NoticeDetails {
|
|
||||||
[key: string]: NoticeDetail;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 模拟通知详情数据
|
|
||||||
const mockNoticeDetails: NoticeDetails = {
|
|
||||||
'1': {
|
|
||||||
id: '1',
|
|
||||||
title: '系统将于2023年9月15日进行版本升级',
|
|
||||||
publishDate: '2023-09-10',
|
|
||||||
publisher: '系统管理员',
|
|
||||||
type: 'system',
|
|
||||||
content: `
|
|
||||||
<p>尊敬的用户:</p>
|
|
||||||
<p>为了提供更好的用户体验和系统功能,我们计划于2023年9月15日晚上22:00至次日凌晨2:00进行系统版本升级。在此期间,系统将暂停服务,请您提前做好相关工作安排。</p>
|
|
||||||
|
|
||||||
<p><strong>本次升级内容:</strong></p>
|
|
||||||
<ol>
|
|
||||||
<li>优化招标采购流程,提高操作效率</li>
|
|
||||||
<li>增加供应商评价功能,完善评价体系</li>
|
|
||||||
<li>优化系统响应速度,提升用户体验</li>
|
|
||||||
<li>修复已知问题,提高系统稳定性</li>
|
|
||||||
<li>增强系统安全性,保障数据安全</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p><strong>升级注意事项:</strong></p>
|
|
||||||
<ol>
|
|
||||||
<li>请您在系统升级前保存并提交所有未完成的工作</li>
|
|
||||||
<li>系统升级后,建议清除浏览器缓存再登录系统</li>
|
|
||||||
<li>如遇到任何问题,请联系系统管理员</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>感谢您的理解与支持!</p>
|
|
||||||
<p>系统管理团队</p>
|
|
||||||
<p>2023年9月10日</p>
|
|
||||||
`
|
|
||||||
},
|
|
||||||
'2': {
|
|
||||||
id: '2',
|
|
||||||
title: '招标模块功能优化更新通知',
|
|
||||||
publishDate: '2023-08-25',
|
|
||||||
publisher: '系统管理员',
|
|
||||||
type: 'system',
|
|
||||||
content: `
|
|
||||||
<p>尊敬的用户:</p>
|
|
||||||
<p>我们很高兴地通知您,招标模块已完成功能优化升级,现已上线。本次更新主要针对招标流程进行了优化,提高了操作效率和用户体验。</p>
|
|
||||||
|
|
||||||
<p><strong>主要更新内容:</strong></p>
|
|
||||||
<ol>
|
|
||||||
<li>简化招标发布流程,减少操作步骤</li>
|
|
||||||
<li>优化投标文件管理功能,支持批量上传和下载</li>
|
|
||||||
<li>增加招标项目进度跟踪功能,实时掌握项目状态</li>
|
|
||||||
<li>完善评标功能,支持多种评标方法</li>
|
|
||||||
<li>增加中标结果自动生成功能,提高工作效率</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p><strong>使用建议:</strong></p>
|
|
||||||
<ol>
|
|
||||||
<li>请参考系统内置的操作指南熟悉新功能</li>
|
|
||||||
<li>如有任何问题或建议,请通过系统反馈功能提交</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>感谢您对我们工作的支持!</p>
|
|
||||||
<p>系统管理团队</p>
|
|
||||||
<p>2023年8月25日</p>
|
|
||||||
`
|
|
||||||
},
|
|
||||||
'6': {
|
|
||||||
id: '6',
|
|
||||||
title: '关于开展2023年度供应商评估工作的通知',
|
|
||||||
publishDate: '2023-09-05',
|
|
||||||
publisher: '采购管理部',
|
|
||||||
type: 'other',
|
|
||||||
content: `
|
|
||||||
<p>各相关部门:</p>
|
|
||||||
<p>为加强供应商管理,提高采购质量,根据《中远海运集团供应商管理实施细则》的要求,现决定开展2023年度供应商评估工作,具体事项通知如下:</p>
|
|
||||||
|
|
||||||
<p><strong>一、评估对象</strong></p>
|
|
||||||
<p>2023年度与我集团有业务往来的所有供应商。</p>
|
|
||||||
|
|
||||||
<p><strong>二、评估时间</strong></p>
|
|
||||||
<p>2023年9月15日至10月15日。</p>
|
|
||||||
|
|
||||||
<p><strong>三、评估内容</strong></p>
|
|
||||||
<ol>
|
|
||||||
<li>供应商资质情况</li>
|
|
||||||
<li>产品质量及服务水平</li>
|
|
||||||
<li>价格合理性</li>
|
|
||||||
<li>交货及时性</li>
|
|
||||||
<li>售后服务响应速度</li>
|
|
||||||
<li>合同履约情况</li>
|
|
||||||
<li>社会责任履行情况</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p><strong>四、评估方法</strong></p>
|
|
||||||
<p>采用百分制评分,根据评分结果将供应商分为A、B、C、D四个等级。</p>
|
|
||||||
|
|
||||||
<p><strong>五、工作要求</strong></p>
|
|
||||||
<ol>
|
|
||||||
<li>各部门应指定专人负责本部门供应商评估工作</li>
|
|
||||||
<li>评估过程应客观公正,实事求是</li>
|
|
||||||
<li>评估结果应于10月20日前报送采购管理部汇总</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>特此通知。</p>
|
|
||||||
<p>采购管理部</p>
|
|
||||||
<p>2023年9月5日</p>
|
|
||||||
`
|
|
||||||
},
|
|
||||||
'7': {
|
|
||||||
id: '7',
|
|
||||||
title: '关于调整采购审批流程的通知',
|
|
||||||
publishDate: '2023-08-20',
|
|
||||||
publisher: '采购管理部',
|
|
||||||
type: 'other',
|
|
||||||
content: `
|
|
||||||
<p>各相关部门:</p>
|
|
||||||
<p>为提高采购效率,优化业务流程,经公司研究决定,对采购审批流程进行调整,现将有关事项通知如下:</p>
|
|
||||||
|
|
||||||
<p><strong>一、调整内容</strong></p>
|
|
||||||
<ol>
|
|
||||||
<li>采购金额50万元以下的项目,由部门经理审批后直接提交采购部执行,无需总经理审批</li>
|
|
||||||
<li>采购金额50万元至200万元的项目,由部门经理和分管副总经理审批后提交采购部执行</li>
|
|
||||||
<li>采购金额200万元以上的项目,仍按原流程执行,需经总经理审批</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p><strong>二、实施时间</strong></p>
|
|
||||||
<p>本通知自2023年9月1日起实施。</p>
|
|
||||||
|
|
||||||
<p><strong>三、注意事项</strong></p>
|
|
||||||
<ol>
|
|
||||||
<li>各部门应严格按照新的审批流程执行,不得擅自变更</li>
|
|
||||||
<li>采购部应加强对采购项目的监督管理,确保采购质量</li>
|
|
||||||
<li>审批人应认真履行审批职责,对采购项目的必要性、合理性进行审核</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<p>特此通知。</p>
|
|
||||||
<p>采购管理部</p>
|
|
||||||
<p>2023年8月20日</p>
|
|
||||||
`
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const NoticeInfo: React.FC = () => {
|
const NoticeInfo: React.FC = () => {
|
||||||
|
const intl = useIntl();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const id = new URLSearchParams(location.search).get("id");
|
const id = new URLSearchParams(location.search).get("id");
|
||||||
const [noticeDetail, setNoticeDetail] = useState<NoticeDetail | null>(null);
|
const [noticeDetail, setNoticeDetail] = useState<NoticeRecord | null>(null);
|
||||||
const [loading, setLoading] = useState<boolean>(true);
|
const [loading, setLoading] = useState<boolean>(true);
|
||||||
|
|
||||||
// 模拟获取通知详情数据
|
// 获取通知详情数据
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 实际项目中应该通过API获取数据
|
const fetchNoticeDetail = async () => {
|
||||||
setTimeout(() => {
|
if (!id) {
|
||||||
if (id && mockNoticeDetails[id]) {
|
message.error(intl.formatMessage({ id: 'notice.message.idNotExist' }));
|
||||||
setNoticeDetail(mockNoticeDetails[id]);
|
setLoading(false);
|
||||||
} else {
|
return;
|
||||||
// 处理ID不存在的情况
|
|
||||||
message.error('通知不存在');
|
|
||||||
}
|
}
|
||||||
setLoading(false);
|
|
||||||
}, 500);
|
try {
|
||||||
}, [id]);
|
const response = await getNoticeDetail(id);
|
||||||
|
if (response.code === 200 && response.success) {
|
||||||
|
setNoticeDetail(response.data);
|
||||||
|
} else {
|
||||||
|
message.error(response.message || intl.formatMessage({ id: 'notice.message.getDetailFailed' }));
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取通知详情出错:', error);
|
||||||
|
message.error(intl.formatMessage({ id: 'notice.message.getDetailError' }));
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchNoticeDetail();
|
||||||
|
}, [id, intl]);
|
||||||
|
|
||||||
// 处理返回列表
|
// 处理返回列表
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
@ -186,7 +49,7 @@ const NoticeInfo: React.FC = () => {
|
|||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.loadingContainer}>
|
<div className={styles.loadingContainer}>
|
||||||
<Spin size="large" />
|
<Spin size="large" tip={intl.formatMessage({ id: 'notice.detail.loading' })} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -194,12 +57,27 @@ const NoticeInfo: React.FC = () => {
|
|||||||
if (!noticeDetail) {
|
if (!noticeDetail) {
|
||||||
return (
|
return (
|
||||||
<div className={styles.notFoundContainer}>
|
<div className={styles.notFoundContainer}>
|
||||||
<Title level={4}>未找到相关通知</Title>
|
<Title level={4}><FormattedMessage id="notice.detail.notFound" /></Title>
|
||||||
<Button type="primary" onClick={handleBack}>返回列表</Button>
|
<Button type="primary" onClick={handleBack}>
|
||||||
|
<FormattedMessage id="notice.detail.back" />
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取通知类型本地化文本
|
||||||
|
const getNoticeTypeText = (columnType: string) => {
|
||||||
|
if (!columnType) return intl.formatMessage({ id: 'notice.detail.type.notice' });
|
||||||
|
|
||||||
|
if (columnType === 'system') {
|
||||||
|
return intl.formatMessage({ id: 'notice.detail.type.system' });
|
||||||
|
} else if (columnType === 'other') {
|
||||||
|
return intl.formatMessage({ id: 'notice.detail.type.other' });
|
||||||
|
}
|
||||||
|
|
||||||
|
return intl.formatMessage({ id: 'notice.detail.type.notice' });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.noticeInfoContainer}>
|
<div className={styles.noticeInfoContainer}>
|
||||||
<div className={styles.noticeInfoHeader}>
|
<div className={styles.noticeInfoHeader}>
|
||||||
@ -209,7 +87,7 @@ const NoticeInfo: React.FC = () => {
|
|||||||
onClick={handleBack}
|
onClick={handleBack}
|
||||||
className={styles.backButton}
|
className={styles.backButton}
|
||||||
>
|
>
|
||||||
返回列表
|
<FormattedMessage id="notice.detail.back" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -222,14 +100,18 @@ const NoticeInfo: React.FC = () => {
|
|||||||
|
|
||||||
<div className={styles.metaInfo}>
|
<div className={styles.metaInfo}>
|
||||||
<div className={styles.metaLeft}>
|
<div className={styles.metaLeft}>
|
||||||
<Text type="secondary">发布时间: {noticeDetail.publishDate}</Text>
|
<Text type="secondary">
|
||||||
|
<FormattedMessage id="notice.detail.publishTime" />: {noticeDetail.publishTime}
|
||||||
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.metaCenter}>
|
<div className={styles.metaCenter}>
|
||||||
<Text type="secondary">发布人: {noticeDetail.publisher}</Text>
|
<Text type="secondary">
|
||||||
|
<FormattedMessage id="notice.detail.publisher" />: {noticeDetail.publishBy}
|
||||||
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.metaRight}>
|
<div className={styles.metaRight}>
|
||||||
<Text type="secondary">
|
<Text type="secondary">
|
||||||
通知类型: {noticeDetail.type === 'system' ? '系统更新通知' : '其他通知'}
|
<FormattedMessage id="notice.detail.type" />: {getNoticeTypeText(noticeDetail.columnType)}
|
||||||
</Text>
|
</Text>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
103
src/servers/api/download.ts
Normal file
103
src/servers/api/download.ts
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
// 下载中心列表请求参数类型
|
||||||
|
export type DownloadListParams = {
|
||||||
|
pageNo: string;
|
||||||
|
pageSize: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 下载项记录类型
|
||||||
|
export type DownloadRecord = {
|
||||||
|
pageNo: null;
|
||||||
|
pageSize: null;
|
||||||
|
createBy: string;
|
||||||
|
createTime: string;
|
||||||
|
updateBy: string;
|
||||||
|
updateTime: string;
|
||||||
|
remark: null;
|
||||||
|
lastUpdateTime: string;
|
||||||
|
id: string;
|
||||||
|
columnType: string;
|
||||||
|
name: string;
|
||||||
|
isBold: string;
|
||||||
|
keywords: string;
|
||||||
|
thumbnail: string;
|
||||||
|
fileName: string;
|
||||||
|
fileType: string;
|
||||||
|
fileSize: string;
|
||||||
|
filePath: string;
|
||||||
|
fileUrl: string;
|
||||||
|
isTop: string;
|
||||||
|
status: string;
|
||||||
|
publishBy: string;
|
||||||
|
publishTime: string;
|
||||||
|
delFlag: string;
|
||||||
|
statusText: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 下载中心列表响应类型
|
||||||
|
export type DownloadListResponse = {
|
||||||
|
records: DownloadRecord[];
|
||||||
|
total: number;
|
||||||
|
size: number;
|
||||||
|
current: number;
|
||||||
|
orders: string[];
|
||||||
|
optimizeCountSql: boolean;
|
||||||
|
hitCount: boolean;
|
||||||
|
countId: null;
|
||||||
|
maxLimit: null;
|
||||||
|
searchCount: boolean;
|
||||||
|
pages: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 下载中心详情请求参数类型
|
||||||
|
export type DownloadDetailParams = {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下载中心列表
|
||||||
|
* @param params 分页参数
|
||||||
|
* @returns 下载中心列表数据
|
||||||
|
*/
|
||||||
|
export async function getDownloadList(params: DownloadListParams) {
|
||||||
|
return request<API.APIResponse<DownloadListResponse>>('/homePage/getDownloadsPage', {
|
||||||
|
method: 'POST',
|
||||||
|
data: params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下载中心详情
|
||||||
|
* @param id 下载项ID
|
||||||
|
* @returns 下载中心详情数据
|
||||||
|
*/
|
||||||
|
export async function getDownloadDetail(id: string) {
|
||||||
|
return request<API.APIResponse<DownloadRecord>>(`/homePage/getDownloadsInfo/${id}`, {
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载文件
|
||||||
|
* @param id 文件ID
|
||||||
|
* @param fileName 文件名称
|
||||||
|
* @returns 文件下载结果
|
||||||
|
*/
|
||||||
|
export async function downloadFile(id: string, fileName: string) {
|
||||||
|
const response = await request(`/homePage/downloadFile/${id}`, {
|
||||||
|
method: 'GET',
|
||||||
|
responseType: 'blob',
|
||||||
|
});
|
||||||
|
|
||||||
|
// 创建下载链接
|
||||||
|
const url = window.URL.createObjectURL(new Blob([response]));
|
||||||
|
const link = document.createElement('a');
|
||||||
|
link.href = url;
|
||||||
|
link.setAttribute('download', fileName);
|
||||||
|
document.body.appendChild(link);
|
||||||
|
link.click();
|
||||||
|
document.body.removeChild(link);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
8
src/servers/api/index.ts
Normal file
8
src/servers/api/index.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// 首页api
|
||||||
|
|
||||||
|
import request from '@/utils/request';
|
||||||
|
export async function getCoscoPortalsLinksClassification() {
|
||||||
|
return request<API.APIResponse<API.HelpCenterListResponse>>('/homePage/coscoPortalsLinksClassification/getAll', {
|
||||||
|
method: 'get',
|
||||||
|
});
|
||||||
|
}
|
75
src/servers/api/notice.ts
Normal file
75
src/servers/api/notice.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import request from '@/utils/request';
|
||||||
|
|
||||||
|
// 通知中心列表请求参数类型
|
||||||
|
export type NoticeListParams = {
|
||||||
|
pageNo: string;
|
||||||
|
pageSize: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 通知中心记录类型
|
||||||
|
export type NoticeRecord = {
|
||||||
|
pageNo: null;
|
||||||
|
pageSize: null;
|
||||||
|
createBy: string;
|
||||||
|
createTime: string;
|
||||||
|
updateBy: string;
|
||||||
|
updateTime: string;
|
||||||
|
remark: null;
|
||||||
|
lastUpdateTime: string;
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
titleEn: string;
|
||||||
|
content: string;
|
||||||
|
contentEn: string;
|
||||||
|
settingEn: string;
|
||||||
|
columnType: string;
|
||||||
|
publishBy: string;
|
||||||
|
publishTime: string;
|
||||||
|
isTop: string;
|
||||||
|
status: string;
|
||||||
|
delFlag: string;
|
||||||
|
statusText: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 通知中心列表响应类型
|
||||||
|
export type NoticeListResponse = {
|
||||||
|
records: NoticeRecord[];
|
||||||
|
total: number;
|
||||||
|
size: number;
|
||||||
|
current: number;
|
||||||
|
orders: string[];
|
||||||
|
optimizeCountSql: boolean;
|
||||||
|
hitCount: boolean;
|
||||||
|
countId: null;
|
||||||
|
maxLimit: null;
|
||||||
|
searchCount: boolean;
|
||||||
|
pages: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 通知中心详情请求参数类型
|
||||||
|
export type NoticeDetailParams = {
|
||||||
|
id: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取通知中心列表
|
||||||
|
* @param params 分页参数
|
||||||
|
* @returns 通知中心列表数据
|
||||||
|
*/
|
||||||
|
export async function getNoticeList(params: NoticeListParams) {
|
||||||
|
return request<API.APIResponse<NoticeListResponse>>('/homePage/getNoticePage', {
|
||||||
|
method: 'POST',
|
||||||
|
data: params,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取通知中心详情
|
||||||
|
* @param id 通知ID
|
||||||
|
* @returns 通知中心详情数据
|
||||||
|
*/
|
||||||
|
export async function getNoticeDetail(id: string) {
|
||||||
|
return request<API.APIResponse<NoticeRecord>>(`/homePage/getNoticeInfo/${id}`, {
|
||||||
|
method: 'GET',
|
||||||
|
});
|
||||||
|
}
|
93
src/servers/api/typings.d.ts
vendored
93
src/servers/api/typings.d.ts
vendored
@ -6,6 +6,98 @@ declare namespace API {
|
|||||||
data: T;
|
data: T;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 下载中心相关类型
|
||||||
|
export type DownloadListParams = {
|
||||||
|
pageNo: string;
|
||||||
|
pageSize: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DownloadRecord = {
|
||||||
|
pageNo: null;
|
||||||
|
pageSize: null;
|
||||||
|
createBy: string;
|
||||||
|
createTime: string;
|
||||||
|
updateBy: string;
|
||||||
|
updateTime: string;
|
||||||
|
remark: null;
|
||||||
|
lastUpdateTime: string;
|
||||||
|
id: string;
|
||||||
|
columnType: string;
|
||||||
|
name: string;
|
||||||
|
isBold: string;
|
||||||
|
keywords: string;
|
||||||
|
thumbnail: string;
|
||||||
|
fileName: string;
|
||||||
|
fileType: string;
|
||||||
|
fileSize: string;
|
||||||
|
filePath: string;
|
||||||
|
fileUrl: string;
|
||||||
|
isTop: string;
|
||||||
|
status: string;
|
||||||
|
publishBy: string;
|
||||||
|
publishTime: string;
|
||||||
|
delFlag: string;
|
||||||
|
statusText: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DownloadListResponse = {
|
||||||
|
records: DownloadRecord[];
|
||||||
|
total: number;
|
||||||
|
size: number;
|
||||||
|
current: number;
|
||||||
|
orders: string[];
|
||||||
|
optimizeCountSql: boolean;
|
||||||
|
hitCount: boolean;
|
||||||
|
countId: null;
|
||||||
|
maxLimit: null;
|
||||||
|
searchCount: boolean;
|
||||||
|
pages: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通知中心相关类型
|
||||||
|
export type NoticeListParams = {
|
||||||
|
pageNo: string;
|
||||||
|
pageSize: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NoticeRecord = {
|
||||||
|
pageNo: null;
|
||||||
|
pageSize: null;
|
||||||
|
createBy: string;
|
||||||
|
createTime: string;
|
||||||
|
updateBy: string;
|
||||||
|
updateTime: string;
|
||||||
|
remark: null;
|
||||||
|
lastUpdateTime: string;
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
titleEn: string;
|
||||||
|
content: string;
|
||||||
|
contentEn: string;
|
||||||
|
settingEn: string;
|
||||||
|
columnType: string;
|
||||||
|
publishBy: string;
|
||||||
|
publishTime: string;
|
||||||
|
isTop: string;
|
||||||
|
status: string;
|
||||||
|
delFlag: string;
|
||||||
|
statusText: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type NoticeListResponse = {
|
||||||
|
records: NoticeRecord[];
|
||||||
|
total: number;
|
||||||
|
size: number;
|
||||||
|
current: number;
|
||||||
|
orders: string[];
|
||||||
|
optimizeCountSql: boolean;
|
||||||
|
hitCount: boolean;
|
||||||
|
countId: null;
|
||||||
|
maxLimit: null;
|
||||||
|
searchCount: boolean;
|
||||||
|
pages: number;
|
||||||
|
}
|
||||||
|
|
||||||
export type RegisterRequest = {
|
export type RegisterRequest = {
|
||||||
coscoSupplierBank: CoscoSupplierBank[];
|
coscoSupplierBank: CoscoSupplierBank[];
|
||||||
coscoSupplierBase: CoscoSupplierBase;
|
coscoSupplierBase: CoscoSupplierBase;
|
||||||
@ -218,7 +310,6 @@ declare namespace API {
|
|||||||
title: string;
|
title: string;
|
||||||
type: string;
|
type: string;
|
||||||
userName: string;
|
userName: string;
|
||||||
[property: string]: any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关于我们响应数据类型
|
// 关于我们响应数据类型
|
||||||
|
Reference in New Issue
Block a user