添加模块文件

This commit is contained in:
linxd
2025-06-18 22:04:33 +08:00
parent 73db059e7d
commit 0b2891a0e3
23 changed files with 1207 additions and 283 deletions

View File

@ -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;
}
}
}
}

View File

@ -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;