Ant Design ProTable组件深度解析
目录
一、Mock 数据服务 (mock.ts)
二、ProTable 组件 (ProTableWithModal.tsx)
三、关键特性说明
四、技术栈关系图
以下是对基于 Ant Design Pro v6 (TypeScript) 的 ProTable 组件的分析,包含代码注释和关键功能说明:
一、Mock 数据服务 (mock.ts
)
// 模拟数据源(内存数据库)
import type { Request, Response } from 'express';
const dataSource: any[] = [{id: '1',name: '初始数据',description: '系统初始数据',status: 'active',createTime: '2025-07-10T08:30:00Z'}
];// RESTful API 模拟
export default {// GET /api/data 分页查询'GET /api/data': (req: Request, res: Response) => {// 1. 解析查询参数const page = parseInt(req.query.page as string) || 1; // 当前页码const pageSize = parseInt(req.query.pageSize as string) || 5; // 页大小const { name, status } = req.query; // 搜索条件// 2. 过滤逻辑(按名称/状态)let filteredData = [...dataSource]; // 复制原始数据if (name) filteredData = filteredData.filter(item => item.name.includes(name));if (status) filteredData = filteredData.filter(item => item.status === status);// 3. 分页处理 (slice实现)const start = (page - 1) * pageSize;const pageData = filteredData.slice(start, start + pageSize);// 4. 返回标准响应格式res.send({success: true,data: pageData, // 当前页数据total: filteredData.length // 总记录数});},// POST /api/data 创建数据'POST /api/data': (req: Request, res: Response) => {const newItem = {...req.body, // 接收请求体数据id: `id-${Date.now()}`, // 生成唯一IDcreateTime: new Date().toISOString() // 创建时间};dataSource.push(newItem); // 添加到数据源res.send({ success: true, data: newItem }); // 返回新建项},
// 更新数据'PUT /api/data/:id': (req: Request, res: Response) => {const { id } = req.params;const index = dataSource.findIndex(item => item.id === id);if (index !== -1) {dataSource[index] = { ...dataSource[index], ...req.body };res.send({ success: true });} else {res.status(404).send({ success: false, message: '数据未找到' });}},// 删除数据'DELETE /api/data/:id': (req: Request, res: Response) => {const { id } = req.params;const index = dataSource.findIndex(item => item.id === id);if (index !== -1) {dataSource.splice(index, 1);res.send({ success: true });} else {res.status(404).send({ success: false, message: '数据未找到' });}}
};
关键说明:
- 使用内存数组
dataSource
模拟数据库 - 实现 RESTful 接口规范:
- GET:分页查询 + 过滤
- POST:创建资源
- PUT:更新资源(通过ID定位)
- DELETE:删除资源
- 分页逻辑:
slice(start, start+pageSize)
实现内存分页 - 响应格式:标准
{success, data, total}
结构
二、ProTable 组件 (ProTableWithModal.tsx
)
import React, { useRef, useState } from 'react';
import { PlusOutlined, EditOutlined, DeleteOutlined } from '@ant-design/icons';
import { Button, Form, Input, Modal, Select, message, Popconfirm } from 'antd';
import { ProTable } from '@ant-design/pro-components';
import type { ActionType, ProColumns, ProFormInstance } from '@ant-design/pro-components';
import { request } from 'umi';// 定义数据类型
interface FormValues {name: string;description: string;status?: string;
}interface DataItem extends FormValues {id: string;createTime: string;
}const ProTableWithModal: React.FC = () => {const [form] = Form.useForm<FormValues>();const searchFormRef = useRef<ProFormInstance>();const [visible, setVisible] = useState(false);const [editingRecord, setEditingRecord] = useState<DataItem | null>(null);const actionRef = useRef<ActionType>();// 状态枚举值const statusEnum = {active: { text: '启用', status: 'Success' },inactive: { text: '停用', status: 'Error' },};// 处理编辑操作const handleEdit = (record: DataItem) => {setEditingRecord(record);form.setFieldsValue({name: record.name,description: record.description,status: record.status});setVisible(true);};// 处理删除操作const handleDelete = async (id: string) => {try {const response = await request(`/api/data/${id}`, {method: 'DELETE'});if (response.success) {message.success('删除成功');actionRef.current?.reload();}} catch (error) {message.error('删除失败');}};// 处理表格请求(带分页和搜索)const handleRequest = async (params: any & {pageSize?: number;current?: number;keyword?: string;}) => {const { current, pageSize, ...filters } = params;try {const response = await request('/api/data', {method: 'GET',params: {...filters,page: current,pageSize}});const tableData = Array.isArray(response.data)? response.data: response.data?.list || [];return {data: tableData,success: true,total: response.total,};} catch (error) {return {data: [],success: false,total: 0};}};// 表单提交处理(添加/编辑)const handleSubmit = async (values: FormValues) => {try {const method = editingRecord ? 'PUT' : 'POST';const url = editingRecord ? `/api/data/${editingRecord.id}` : '/api/data';const response = await request(url, {method,data: {...values,...(editingRecord ? {} : {id: `id-${Date.now()}`,createTime: new Date().toISOString()})}});if (response.success) {message.success(editingRecord ? '更新成功' : '添加成功');actionRef.current?.reload();setVisible(false);form.resetFields();setEditingRecord(null);}} catch (error) {message.error('操作失败');}};// 重置功能const handleReset = () => {if (searchFormRef.current) {searchFormRef.current.resetFields();}actionRef.current?.reset?.();actionRef.current?.reload();};// 表格列配置const columns: ProColumns<DataItem>[] = [{title: '名称',dataIndex: 'name',width: 120,search: true,fieldProps: { placeholder: '请输入名称搜索' },},{title: '描述',dataIndex: 'description',search: false,ellipsis: true,},{title: '状态',dataIndex: 'status',valueType: 'select',valueEnum: statusEnum,initialValue: 'active',search: {transform: (value) => ({ status: value }),},},{title: '创建时间',dataIndex: 'createTime',valueType: 'dateTime',hideInSearch: true,},{title: '操作',valueType: 'option',render: (_, record) => [<Buttonkey="edit"type="link"icon={<EditOutlined />}onClick={() => handleEdit(record)}/>,<Popconfirmkey="delete"title="确定要删除吗?"onConfirm={() => handleDelete(record.id)}><Button type="link" danger icon={<DeleteOutlined />} /></Popconfirm>],},];return (<div style={{ padding: 24 }}><ProTable<DataItem>actionRef={actionRef}formRef={searchFormRef}columns={columns}rowKey="id"pagination={{ pageSize: 5 }}request={handleRequest}toolBarRender={() => [<Buttonkey="add"type="primary"icon={<PlusOutlined />}onClick={() => {setEditingRecord(null);setVisible(true);}}>新建条目</Button>,]}search={{optionRender: (_, __, dom) => [...dom,<Buttonkey="global-reset"onClick={handleReset}style={{ marginLeft: 8 }}>全局重置</Button>]}}/>{/* 弹窗表单 */}<Modaltitle={editingRecord ? "编辑数据" : "添加新数据"}open={visible}onCancel={() => {setVisible(false);form.resetFields();setEditingRecord(null);}}onOk={() => form.submit()}destroyOnClose><Formform={form}layout="vertical"onFinish={handleSubmit}initialValues={{ status: 'active' }}><Form.Itemlabel="名称"name="name"rules={[{ required: true, message: '请输入名称' }]}><Input placeholder="请输入名称" /></Form.Item><Form.Itemlabel="描述"name="description"rules={[{ max: 100, message: '不超过100字符' }]}><Input.TextArea placeholder="请输入描述" rows={3} /></Form.Item><Form.Itemlabel="状态"name="status"><Select options={[{ value: 'active', label: '启用' },{ value: 'inactive', label: '停用' }]} /></Form.Item></Form></Modal></div>);
};export default ProTableWithModal;
三、关键特性说明
-
ProTable 核心功能:
- 自动分页:通过
request
属性绑定数据获取函数 - 搜索集成:
search: true
开启列搜索 - 值枚举映射:
valueEnum
实现状态→标签的转换
- 自动分页:通过
-
Umi Request 使用:
// 统一请求方法 request('/api/data', {method: 'GET',params: { page: 1, name: 'test' } });
- 内置错误处理
- 自动处理 loading 状态
-
表单管理最佳实践:
- 使用
Form.useForm()
管理表单状态 form.setFieldsValue()
实现数据回填destroyOnClose
保证弹窗关闭时重置状态
- 使用
-
全局重置功能:
const handleReset = () => {searchFormRef.current?.resetFields(); // 重置搜索表单actionRef.current?.reload(); // 重置表格数据 };
四、技术栈关系图
此实现完整展示了 CRUD 操作的现代前端架构,结合了 Ant Design Pro 的 UI 组件能力和 Umi 的工程化优势,适合作为中后台系统的模板代码。