Files
fe_supplier_frontend/src/pages/noticeManage/noticeManage.tsx
2025-06-23 08:33:14 +08:00

521 lines
15 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useState, useEffect } from 'react';
import { useIntl } from 'umi';
import { Button, Table, Modal, message, Input, Select, Form, Tooltip, Tag, Tabs } from 'antd';
import {
PlusOutlined,
DeleteOutlined,
ExclamationCircleOutlined,
SearchOutlined,
EyeOutlined,
} from '@ant-design/icons';
import { getNoticeList, addNotice, updateNotice, deleteNotice, batchDeleteNotice, updateNoticeStatus, updateNoticeTopStatus, getNoticeDetail } from '@/servers/api/notice';
import styles from './noticeManage.less';
import {
NoticeStatus,
NoticeStatusText,
NoticeStatusColor,
TopStatus,
ModalType,
} from '@/dicts/noticeManageDict';
import NoticeManageForm from './NoticeManageForm';
import NoticeManageInfo from './NoticeManageInfo';
const { Option } = Select;
const { TabPane } = Tabs;
type NoticeType = API.NoticeRecord & {
key: string;
};
interface SearchParams {
title?: string;
status?: string;
}
const NoticeManage: React.FC = () => {
const intl = useIntl();
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [loading, setLoading] = useState<boolean>(false);
const [form] = Form.useForm();
const [modalVisible, setModalVisible] = useState<boolean>(false);
const [isEdit, setIsEdit] = useState<boolean>(false);
const [isViewMode, setIsViewMode] = useState<boolean>(false);
const [currentId, setCurrentId] = useState<string>('');
// 查看详情数据
const [viewData, setViewData] = useState<API.NoticeRecord | null>(null);
const [noticeData, setNoticeData] = useState<NoticeType[]>([]);
const [pagination, setPagination] = useState({
current: 1,
pageSize: 10,
total: 0,
showSizeChanger: true,
showQuickJumper: true,
showTotal: (total: number) => `${total} 条记录`,
});
const [searchParams, setSearchParams] = useState<SearchParams>({});
// 获取通知列表
const fetchNoticeList = (current: number = 1, pageSize: number = 10, params: SearchParams = searchParams) => {
// 更新搜索参数状态
if (params !== searchParams) {
setSearchParams(params);
}
setLoading(true);
// 实际项目中应调用API
getNoticeList({
...params,
pageNo: current,
pageSize: pageSize,
})
.then(res => {
if (res && res.success) {
const { records, total, current: currentPage, size } = res.data;
// 添加key属性
setNoticeData(
records.map((item: API.NoticeRecord) => ({
...item,
key: item.id,
}))
);
setPagination({
...pagination,
current: currentPage,
pageSize: size,
total: total,
});
} else {
message.error(res.message || '获取通知列表失败');
}
})
.catch(error => {
console.error('获取通知列表失败:', error);
message.error('获取通知列表失败');
})
.finally(() => {
setLoading(false);
});
};
// 首次加载时获取数据
useEffect(() => {
fetchNoticeList(1, pagination.pageSize, {});
}, []);
// 处理查看
const handleView = async (record: NoticeType) => {
setCurrentId(record.id);
setIsViewMode(true);
try {
const response = await getNoticeDetail(record.id);
if (response && response.success) {
// 设置查看详情数据
setViewData(response.data);
setModalVisible(true);
} else {
message.error(response.message || '获取详情失败');
}
} catch (error) {
console.error('获取通知详情失败:', error);
message.error('获取详情失败');
}
};
// 处理编辑
const handleEdit = (record: NoticeType) => {
// 检查是否为已发布状态
if (record.status === NoticeStatus.PUBLISHED) {
message.warning('已发布的通知不能编辑');
return;
}
setIsEdit(true);
setIsViewMode(false);
setCurrentId(record.id);
setModalVisible(true);
};
// 处理删除
const showDeleteConfirm = (record: NoticeType) => {
// 检查是否为已发布状态
if (record.status === NoticeStatus.PUBLISHED) {
message.warning('已发布的通知不能删除');
return;
}
Modal.confirm({
title: '确定要删除该通知吗?',
icon: <ExclamationCircleOutlined />,
content: `标题: ${record.title}`,
okText: '确定',
okType: 'danger',
cancelText: '取消',
maskClosable: false,
onOk: async () => {
try {
// 调用删除API
const response = await deleteNotice(record.id);
if (response && response.success) {
message.success('删除成功');
fetchNoticeList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据
} else {
message.error(response.message || '删除失败');
}
} catch (error) {
console.error('删除通知失败:', error);
message.error('删除失败');
}
},
});
};
// 处理发布/下架
const handlePublishStatus = async (record: NoticeType) => {
// 状态: 0-草稿1-已发布
const isPublished = record.status === NoticeStatus.PUBLISHED;
const actionText = isPublished ? '下架' : '发布';
const newStatus = isPublished ? NoticeStatus.UNPUBLISHED : NoticeStatus.PUBLISHED;
try {
// 调用API更新状态
const response = await updateNoticeStatus(record.id, newStatus);
if (response && response.success) {
message.success(`${actionText}成功`);
fetchNoticeList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据
} else {
message.error(response.message || `${actionText}失败`);
}
} catch (error) {
console.error(`${actionText}失败:`, error);
message.error(`${actionText}失败`);
}
};
// 处理置顶/取消置顶
const handleToggleTop = async (record: NoticeType) => {
const isTop = record.isTop === TopStatus.YES;
const actionText = isTop ? '取消置顶' : '置顶';
const newIsTop = isTop ? TopStatus.NO : TopStatus.YES;
try {
// 调用API更新置顶状态
const response = await updateNoticeTopStatus(record.id, newIsTop);
if (response && response.success) {
message.success(`${actionText}成功`);
fetchNoticeList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据
} else {
message.error(response.message || `${actionText}失败`);
}
} catch (error) {
console.error(`${actionText}失败:`, error);
message.error(`${actionText}失败`);
}
};
// 获取状态标签
const getStatusTag = (status: string) => {
const statusKey = status as keyof typeof NoticeStatusText;
const color = NoticeStatusColor[statusKey] || 'default';
const text = NoticeStatusText[statusKey] || '未知';
return <Tag color={color}>{text}</Tag>;
};
// 处理表格分页变化
const handleTableChange = (newPagination: any) => {
fetchNoticeList(newPagination.current, newPagination.pageSize, searchParams);
};
const columns = [
{
title: '序号',
render: (text: string, record: NoticeType, index: number) => index + 1,
width: 80,
align: 'center' as const,
},
{
title: '标题',
dataIndex: 'title',
key: 'title',
ellipsis: {
showTitle: false,
},
render: (title: string, record: NoticeType) => (
<Tooltip placement="topLeft" title={title}>
<span>
{record.isTop === TopStatus.YES && <Tag color="red" style={{ marginRight: 8 }}></Tag>}
{title}
</span>
</Tooltip>
),
},
{
title: '日期',
dataIndex: 'createTime',
key: 'createTime',
align: 'center' as const,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
align: 'center' as const,
render: (status: string) => getStatusTag(status),
},
{
title: '发布人',
dataIndex: 'createBy',
key: 'createBy',
align: 'center' as const,
},
{
title: '操作',
key: 'action',
width: 300,
align: 'center' as const,
render: (_: unknown, record: NoticeType) => (
<>
<Button type="link" onClick={() => handleView(record)}>
</Button>
{record.status === NoticeStatus.PUBLISHED ? (
<>
<Button type="link" onClick={() => handlePublishStatus(record)}>
</Button>
<Button
type="link"
onClick={() => handleToggleTop(record)}
>
{record.isTop === TopStatus.YES ? '取消置顶' : '置顶'}
</Button>
</>
) : (
<>
<Button type="link" onClick={() => handleEdit(record)}>
</Button>
<Button
type="link"
onClick={() => handlePublishStatus(record)}
>
</Button>
<Button
type="link"
onClick={() => showDeleteConfirm(record)}
>
</Button>
<Button
type="link"
onClick={() => handleToggleTop(record)}
>
{record.isTop === TopStatus.YES ? '取消置顶' : '置顶'}
</Button>
</>
)}
</>
),
},
];
// 行选择限制
const checkSelectable = (record: NoticeType) => {
return record.status !== NoticeStatus.PUBLISHED; // 已发布的不能选择
};
const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
setSelectedRowKeys(newSelectedRowKeys);
};
const rowSelection = {
selectedRowKeys,
onChange: onSelectChange,
getCheckboxProps: (record: NoticeType) => ({
disabled: record.status === NoticeStatus.PUBLISHED, // 已发布的不能选择
}),
};
const hasSelected = selectedRowKeys.length > 0;
// 处理添加
const handleAdd = () => {
setIsEdit(false);
setIsViewMode(false);
setCurrentId('');
setViewData(null);
setModalVisible(true);
};
// 处理批量删除
const handleBatchDelete = () => {
Modal.confirm({
title: '确定要删除选中的通知吗?',
icon: <ExclamationCircleOutlined />,
content: '删除后无法恢复',
okText: '确定',
okType: 'danger',
cancelText: '取消',
maskClosable: false,
onOk: async () => {
setLoading(true);
try {
// 获取可删除的ID非已发布状态
const deleteIds = selectedRowKeys.filter(key => {
const record = noticeData.find(item => item.key === key);
return record && record.status !== NoticeStatus.PUBLISHED;
}) as string[];
if (deleteIds.length > 0) {
// 调用批量删除API
const response = await batchDeleteNotice(deleteIds);
if (response && response.success) {
setSelectedRowKeys([]);
message.success('删除成功');
fetchNoticeList(pagination.current, pagination.pageSize, searchParams); // 重新加载数据
} else {
message.error(response.message || '批量删除失败');
}
} else {
message.warning('没有可删除的通知');
}
} catch (error) {
console.error('批量删除失败:', error);
message.error('批量删除失败');
} finally {
setLoading(false);
}
},
});
};
// 处理搜索
const handleSearch = (values: SearchParams) => {
fetchNoticeList(1, pagination.pageSize, values);
};
// 处理模态框取消
const handleModalCancel = () => {
setModalVisible(false);
setIsViewMode(false);
setViewData(null);
};
return (
<div className="common-container">
<div className="filter-action-row">
<Form
form={form}
name="search"
onFinish={handleSearch}
layout="inline"
className="filter-form"
>
<Form.Item name="title" label="标题">
<Input placeholder="请输入标题关键词" allowClear />
</Form.Item>
<Form.Item name="status" label="状态">
<Select placeholder="请选择状态" allowClear>
<Option value={NoticeStatus.DRAFT}>稿</Option>
<Option value={NoticeStatus.PUBLISHED}></Option>
<Option value={NoticeStatus.UNPUBLISHED}></Option>
</Select>
</Form.Item>
<Form.Item className="filter-btns">
<Button type="primary" htmlType="submit" icon={<SearchOutlined />}>
</Button>
<Button
type="primary"
danger
icon={<DeleteOutlined />}
onClick={() => {
form.resetFields();
fetchNoticeList(1, pagination.pageSize, {});
}}
>
</Button>
</Form.Item>
</Form>
<div className="right-buttons">
<Button
type="primary"
ghost
icon={<PlusOutlined />}
onClick={handleAdd}
>
</Button>
<Button
danger
icon={<DeleteOutlined />}
onClick={handleBatchDelete}
disabled={!hasSelected}
loading={loading}
>
</Button>
{hasSelected && (
<span className="selected-count">
{selectedRowKeys.length}
</span>
)}
</div>
</div>
<div className="content-area">
<Table
rowSelection={rowSelection}
columns={columns}
dataSource={noticeData}
pagination={pagination}
loading={loading}
onChange={handleTableChange}
/>
</div>
{/* 新增/编辑/查看模态框 */}
<Modal
title={isViewMode ? "查看通知" : isEdit ? "编辑通知" : "新增通知"}
visible={modalVisible}
onCancel={handleModalCancel}
width={900}
maskClosable={false}
destroyOnClose
footer={
isViewMode
? [
<Button key="close" onClick={handleModalCancel}>
</Button>,
]
: null
}
>
{isViewMode && viewData ? (
// 查看详情模式
<NoticeManageInfo data={viewData} />
) : (
// 编辑/新增模式
<NoticeManageForm
id={currentId}
isEdit={isEdit}
onSuccess={() => {
setModalVisible(false);
fetchNoticeList(pagination.current, pagination.pageSize, searchParams);
}}
/>
)}
</Modal>
</div>
);
};
export default NoticeManage;