添加模块文件
This commit is contained in:
@ -0,0 +1,23 @@
|
||||
|
||||
.supplier-task-manage-container {
|
||||
// 使用公共容器样式,不需要重复定义padding和background-color
|
||||
|
||||
.task-detail {
|
||||
padding: 16px;
|
||||
|
||||
.detail-item {
|
||||
margin-bottom: 16px;
|
||||
line-height: 22px;
|
||||
|
||||
.label {
|
||||
font-weight: bold;
|
||||
margin-right: 8px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.content {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,623 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
Button,
|
||||
Table,
|
||||
Space,
|
||||
Modal,
|
||||
message,
|
||||
Input,
|
||||
Select,
|
||||
Form,
|
||||
Tooltip,
|
||||
Tag,
|
||||
TablePaginationConfig,
|
||||
DatePicker,
|
||||
Row,
|
||||
Col,
|
||||
} from 'antd';
|
||||
import {
|
||||
PlusOutlined,
|
||||
DeleteOutlined,
|
||||
ExclamationCircleOutlined,
|
||||
SearchOutlined,
|
||||
EditOutlined,
|
||||
EyeOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { TaskStatus, TaskType, TaskStatusText, TaskStatusColor, TaskTypeText } from '@/dicts/supplierTaskDict';
|
||||
import './supplierTaskManage.less';
|
||||
|
||||
const { Option } = Select;
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
// 任务记录类型
|
||||
interface TaskRecord {
|
||||
id: string;
|
||||
taskName: string;
|
||||
taskCode: string;
|
||||
taskType: string;
|
||||
templateName: string;
|
||||
status: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
createBy: string;
|
||||
createTime: string;
|
||||
updateBy?: string;
|
||||
updateTime?: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
interface SearchParams {
|
||||
taskName?: string;
|
||||
status?: string;
|
||||
dateRange?: [string, string];
|
||||
}
|
||||
|
||||
const SupplierTaskManage: React.FC = () => {
|
||||
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<TaskRecord | null>(null);
|
||||
const [taskData, setTaskData] = useState<TaskRecord[]>([]);
|
||||
const [pagination, setPagination] = useState<TablePaginationConfig>({
|
||||
current: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
showSizeChanger: true,
|
||||
showQuickJumper: true,
|
||||
showTotal: (total) => `共 ${total} 条记录`,
|
||||
});
|
||||
const [searchParams, setSearchParams] = useState<SearchParams>({});
|
||||
|
||||
// 模拟获取任务列表
|
||||
const fetchTaskList = async (
|
||||
current = 1,
|
||||
pageSize = 10,
|
||||
params: SearchParams = searchParams,
|
||||
) => {
|
||||
// 更新搜索参数状态
|
||||
if (params !== searchParams) {
|
||||
setSearchParams(params);
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
// 模拟API请求
|
||||
setTimeout(() => {
|
||||
// 模拟数据
|
||||
const mockData: TaskRecord[] = Array.from({ length: 35 }).map((_, index) => {
|
||||
const id = `${index + 1}`;
|
||||
const status = Object.values(TaskStatus)[Math.floor(Math.random() * 3)];
|
||||
const taskType = Math.random() > 0.5 ? TaskType.REGULAR : TaskType.SPECIAL;
|
||||
|
||||
// 生成随机单位名称
|
||||
const units = ['中山市合创展包装材料有限公司', '广州市科技发展有限公司', '深圳市创新科技有限公司', '东莞市制造业有限公司'];
|
||||
const unitIndex = Math.floor(Math.random() * units.length);
|
||||
|
||||
return {
|
||||
id,
|
||||
key: id,
|
||||
taskName: `供应商评价任务${index + 1}`,
|
||||
taskCode: `TASK${String(index + 1).padStart(4, '0')}`,
|
||||
taskType,
|
||||
templateName: `${TaskTypeText[taskType]}模板${Math.floor(Math.random() * 5) + 1}`,
|
||||
status,
|
||||
startTime: '2023-01-01',
|
||||
endTime: '2023-12-31',
|
||||
createBy: units[unitIndex],
|
||||
createTime: '2023-01-01 12:00:00',
|
||||
};
|
||||
});
|
||||
|
||||
// 根据搜索条件过滤
|
||||
let filteredData = [...mockData];
|
||||
if (params.taskName) {
|
||||
filteredData = filteredData.filter(item =>
|
||||
item.taskName.includes(params.taskName || '')
|
||||
);
|
||||
}
|
||||
if (params.status) {
|
||||
filteredData = filteredData.filter(item =>
|
||||
item.status === params.status
|
||||
);
|
||||
}
|
||||
|
||||
// 分页
|
||||
const startIndex = (current - 1) * pageSize;
|
||||
const endIndex = startIndex + pageSize;
|
||||
const paginatedData = filteredData.slice(startIndex, endIndex);
|
||||
|
||||
setTaskData(paginatedData);
|
||||
setPagination({
|
||||
...pagination,
|
||||
current,
|
||||
pageSize,
|
||||
total: filteredData.length,
|
||||
});
|
||||
|
||||
setLoading(false);
|
||||
}, 500);
|
||||
} catch (error) {
|
||||
console.error('获取任务列表失败:', error);
|
||||
message.error('获取任务列表失败');
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
// 首次加载获取数据
|
||||
useEffect(() => {
|
||||
fetchTaskList(pagination.current, pagination.pageSize, {});
|
||||
}, []);
|
||||
|
||||
// 处理查看
|
||||
const handleView = (record: TaskRecord) => {
|
||||
setCurrentId(record.id);
|
||||
setIsViewMode(true);
|
||||
setViewData(record);
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
// 处理编辑
|
||||
const handleEdit = (record: TaskRecord) => {
|
||||
setIsEdit(true);
|
||||
setIsViewMode(false);
|
||||
setCurrentId(record.id);
|
||||
setViewData(record);
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
// 处理删除
|
||||
const showDeleteConfirm = (record: TaskRecord) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除',
|
||||
icon: <ExclamationCircleOutlined />,
|
||||
content: `确定要删除任务: ${record.taskName}?`,
|
||||
okText: '确定',
|
||||
okType: 'danger',
|
||||
cancelText: '取消',
|
||||
maskClosable: false,
|
||||
onOk: async () => {
|
||||
try {
|
||||
// 模拟删除请求
|
||||
setTimeout(() => {
|
||||
message.success('删除成功');
|
||||
fetchTaskList(pagination.current, pagination.pageSize, searchParams);
|
||||
}, 500);
|
||||
} catch (error) {
|
||||
console.error('删除任务失败:', error);
|
||||
message.error('删除任务失败');
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 处理发布/取消
|
||||
const handlePublishStatus = (record: TaskRecord) => {
|
||||
const isInProgress = record.status === TaskStatus.PROCESSING;
|
||||
const actionText = isInProgress ? '取消' : '开始';
|
||||
|
||||
Modal.confirm({
|
||||
title: `确认${actionText}`,
|
||||
icon: <ExclamationCircleOutlined />,
|
||||
content: `确定要${actionText}任务: ${record.taskName}?`,
|
||||
okText: '确定',
|
||||
cancelText: '取消',
|
||||
maskClosable: false,
|
||||
onOk: async () => {
|
||||
try {
|
||||
// 模拟请求
|
||||
setTimeout(() => {
|
||||
message.success(`${actionText}成功`);
|
||||
fetchTaskList(pagination.current, pagination.pageSize, searchParams);
|
||||
}, 500);
|
||||
} catch (error) {
|
||||
console.error(`${actionText}失败:`, error);
|
||||
message.error(`${actionText}失败`);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 获取状态标签
|
||||
const getStatusTag = (status: string) => {
|
||||
const color = TaskStatusColor[status as keyof typeof TaskStatusColor] || 'default';
|
||||
const text = TaskStatusText[status as keyof typeof TaskStatusText] || '未知状态';
|
||||
return <Tag color={color}>{text}</Tag>;
|
||||
};
|
||||
|
||||
// 处理表格分页变化
|
||||
const handleTableChange = (newPagination: TablePaginationConfig) => {
|
||||
fetchTaskList(newPagination.current, newPagination.pageSize, searchParams);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
render: (_: any, __: TaskRecord, index: number) =>
|
||||
(pagination.current! - 1) * pagination.pageSize! + index + 1,
|
||||
width: 80,
|
||||
},
|
||||
{
|
||||
title: '评价主题',
|
||||
dataIndex: 'taskName',
|
||||
key: 'taskName',
|
||||
width: 200,
|
||||
ellipsis: {
|
||||
showTitle: false,
|
||||
},
|
||||
render: (taskName: string) => (
|
||||
<Tooltip placement="topLeft" title={taskName}>
|
||||
{taskName}
|
||||
</Tooltip>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: '发起单位',
|
||||
dataIndex: 'createBy',
|
||||
key: 'createBy',
|
||||
width: 150,
|
||||
},
|
||||
{
|
||||
title: '评价开始时间',
|
||||
dataIndex: 'startTime',
|
||||
key: 'startTime',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '评价结束时间',
|
||||
dataIndex: 'endTime',
|
||||
key: 'endTime',
|
||||
width: 120,
|
||||
},
|
||||
{
|
||||
title: '评价状态',
|
||||
dataIndex: 'status',
|
||||
key: 'status',
|
||||
width: 100,
|
||||
render: (status: string) => getStatusTag(status),
|
||||
},
|
||||
{
|
||||
title: '操作',
|
||||
key: 'action',
|
||||
width: 180,
|
||||
align: 'center' as const,
|
||||
render: (_: unknown, record: TaskRecord) => (
|
||||
<Space size="middle">
|
||||
<Button type="link" onClick={() => handleView(record)}>
|
||||
查看
|
||||
</Button>
|
||||
<Button type="link" onClick={() => handleEdit(record)}>
|
||||
修改
|
||||
</Button>
|
||||
<Button type="link" onClick={() => showDeleteConfirm(record)}>
|
||||
删除
|
||||
</Button>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
|
||||
setSelectedRowKeys(newSelectedRowKeys);
|
||||
};
|
||||
|
||||
const rowSelection = {
|
||||
selectedRowKeys,
|
||||
onChange: onSelectChange,
|
||||
};
|
||||
|
||||
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 {
|
||||
// 模拟批量删除
|
||||
setTimeout(() => {
|
||||
setSelectedRowKeys([]);
|
||||
message.success('批量删除成功');
|
||||
fetchTaskList(pagination.current, pagination.pageSize, searchParams);
|
||||
setLoading(false);
|
||||
}, 1000);
|
||||
} catch (error) {
|
||||
console.error('批量删除失败:', error);
|
||||
message.error('批量删除失败');
|
||||
setLoading(false);
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 处理搜索
|
||||
const handleSearch = (values: any) => {
|
||||
const { dateRange, ...rest } = values;
|
||||
const params: SearchParams = { ...rest };
|
||||
|
||||
if (dateRange && dateRange.length === 2) {
|
||||
params.dateRange = [dateRange[0].format('YYYY-MM-DD'), dateRange[1].format('YYYY-MM-DD')];
|
||||
}
|
||||
|
||||
fetchTaskList(1, pagination.pageSize, params);
|
||||
};
|
||||
|
||||
// 处理模态框取消
|
||||
const handleModalCancel = () => {
|
||||
setModalVisible(false);
|
||||
setIsViewMode(false);
|
||||
setViewData(null);
|
||||
};
|
||||
|
||||
// 渲染任务详情
|
||||
const renderTaskDetail = () => {
|
||||
if (!viewData) return null;
|
||||
|
||||
return (
|
||||
<div className="task-detail">
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={12}>
|
||||
<div className="detail-item">
|
||||
<span className="label">任务名称:</span>
|
||||
<span className="content">{viewData.taskName}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div className="detail-item">
|
||||
<span className="label">任务编号:</span>
|
||||
<span className="content">{viewData.taskCode}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div className="detail-item">
|
||||
<span className="label">任务类型:</span>
|
||||
<span className="content">
|
||||
{TaskTypeText[viewData.taskType as keyof typeof TaskTypeText] || '未知类型'}
|
||||
</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div className="detail-item">
|
||||
<span className="label">使用模板:</span>
|
||||
<span className="content">{viewData.templateName}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div className="detail-item">
|
||||
<span className="label">状态:</span>
|
||||
<span className="content">{getStatusTag(viewData.status)}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div className="detail-item">
|
||||
<span className="label">开始时间:</span>
|
||||
<span className="content">{viewData.startTime}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div className="detail-item">
|
||||
<span className="label">结束时间:</span>
|
||||
<span className="content">{viewData.endTime}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div className="detail-item">
|
||||
<span className="label">创建人:</span>
|
||||
<span className="content">{viewData.createBy}</span>
|
||||
</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<div className="detail-item">
|
||||
<span className="label">创建时间:</span>
|
||||
<span className="content">{viewData.createTime}</span>
|
||||
</div>
|
||||
</Col>
|
||||
{viewData.updateBy && (
|
||||
<Col span={12}>
|
||||
<div className="detail-item">
|
||||
<span className="label">更新人:</span>
|
||||
<span className="content">{viewData.updateBy}</span>
|
||||
</div>
|
||||
</Col>
|
||||
)}
|
||||
{viewData.updateTime && (
|
||||
<Col span={12}>
|
||||
<div className="detail-item">
|
||||
<span className="label">更新时间:</span>
|
||||
<span className="content">{viewData.updateTime}</span>
|
||||
</div>
|
||||
</Col>
|
||||
)}
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
// 渲染任务表单
|
||||
const renderTaskForm = () => {
|
||||
return (
|
||||
<Form
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 16 }}
|
||||
initialValues={viewData || {}}
|
||||
>
|
||||
<Form.Item
|
||||
label="任务名称"
|
||||
name="taskName"
|
||||
rules={[{ required: true, message: '请输入任务名称' }]}
|
||||
>
|
||||
<Input placeholder="请输入任务名称" />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="任务编号"
|
||||
name="taskCode"
|
||||
rules={[{ required: true, message: '请输入任务编号' }]}
|
||||
>
|
||||
<Input placeholder="请输入任务编号" disabled={isEdit} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="任务类型"
|
||||
name="taskType"
|
||||
rules={[{ required: true, message: '请选择任务类型' }]}
|
||||
>
|
||||
<Select placeholder="请选择任务类型">
|
||||
<Option value={TaskType.REGULAR}>{TaskTypeText[TaskType.REGULAR]}</Option>
|
||||
<Option value={TaskType.SPECIAL}>{TaskTypeText[TaskType.SPECIAL]}</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="使用模板"
|
||||
name="templateName"
|
||||
rules={[{ required: true, message: '请选择使用模板' }]}
|
||||
>
|
||||
<Select placeholder="请选择使用模板">
|
||||
<Option value="常规评价模板1">常规评价模板1</Option>
|
||||
<Option value="常规评价模板2">常规评价模板2</Option>
|
||||
<Option value="专项评价模板1">专项评价模板1</Option>
|
||||
<Option value="专项评价模板2">专项评价模板2</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label="时间范围"
|
||||
rules={[{ required: true, message: '请选择时间范围' }]}
|
||||
>
|
||||
<RangePicker />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item wrapperCol={{ offset: 6, span: 16 }}>
|
||||
<Button type="primary" htmlType="submit">
|
||||
保存
|
||||
</Button>
|
||||
<Button style={{ marginLeft: 8 }} onClick={handleModalCancel}>
|
||||
取消
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="supplier-task-manage-container common-container">
|
||||
<div className="filter-action-row">
|
||||
<Form
|
||||
form={form}
|
||||
name="search"
|
||||
onFinish={handleSearch}
|
||||
layout="inline"
|
||||
className="filter-form"
|
||||
>
|
||||
<Form.Item name="taskName" label="评价主题">
|
||||
<Input placeholder="请输入评价主题" allowClear />
|
||||
</Form.Item>
|
||||
<Form.Item name="status" label="评价状态">
|
||||
<Select placeholder="请选择状态" allowClear>
|
||||
<Option value={TaskStatus.DRAFT}>未开始</Option>
|
||||
<Option value={TaskStatus.PROCESSING}>进行中</Option>
|
||||
<Option value={TaskStatus.COMPLETED}>已结束</Option>
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item name="dateRange" label="评价时间">
|
||||
<RangePicker />
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
|
||||
<div className="button-row">
|
||||
<div className="left-buttons">
|
||||
<Button type="primary" htmlType="submit" icon={<SearchOutlined />} onClick={() => form.submit()}>
|
||||
搜索
|
||||
</Button>
|
||||
<Button
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={() => {
|
||||
form.resetFields();
|
||||
fetchTaskList(1, pagination.pageSize, {});
|
||||
}}
|
||||
>
|
||||
重置
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="right-buttons">
|
||||
<Button type="primary" ghost icon={<PlusOutlined />} onClick={handleAdd}>
|
||||
新增
|
||||
</Button>
|
||||
<Button
|
||||
danger
|
||||
icon={<DeleteOutlined />}
|
||||
onClick={handleBatchDelete}
|
||||
disabled={!hasSelected}
|
||||
loading={loading}
|
||||
>
|
||||
批量删除
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="content-area">
|
||||
<Table
|
||||
rowSelection={rowSelection}
|
||||
columns={columns}
|
||||
dataSource={taskData}
|
||||
pagination={pagination}
|
||||
loading={loading}
|
||||
onChange={handleTableChange}
|
||||
scroll={{ x: 1500 }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 新增/编辑/查看模态框 */}
|
||||
<Modal
|
||||
title={isViewMode
|
||||
? "查看任务详情"
|
||||
: isEdit
|
||||
? "编辑任务"
|
||||
: "新增任务"}
|
||||
visible={modalVisible}
|
||||
onCancel={handleModalCancel}
|
||||
width={800}
|
||||
maskClosable={false}
|
||||
destroyOnClose
|
||||
footer={
|
||||
isViewMode
|
||||
? [
|
||||
<Button key="close" onClick={handleModalCancel}>
|
||||
关闭
|
||||
</Button>,
|
||||
]
|
||||
: null
|
||||
}
|
||||
>
|
||||
{isViewMode ? renderTaskDetail() : renderTaskForm()}
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SupplierTaskManage;
|
Reference in New Issue
Block a user