• 中文
  • Demos

    代码演示

    基础用法

    Issue 管理
    标题
    状态
    标签
    创建时间
    操作
    暂无数据
    暂无数据
    查询表格
    import { EllipsisOutlined, PlusOutlined } from '@ant-design/icons';
    import type { ActionType, ProColumns } from '@ant-design/pro-components';
    import { ProTable, TableDropdown } from '@ant-design/pro-components';
    import { Button, Dropdown, message, Space, Tag } from 'antd';
    import { useRef } from 'react';
    import request from 'umi-request';
    export const waitTimePromise = async (time: number = 100) => {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(true);
        }, time);
      });
    };
    
    export const waitTime = async (time: number = 100) => {
      await waitTimePromise(time);
    };
    
    type GithubIssueItem = {
      url: string;
      id: number;
      number: number;
      title: string;
      labels: {
        name: string;
        color: string;
      }[];
      state: string;
      comments: number;
      created_at: string;
      updated_at: string;
      closed_at?: string;
    };
    
    const columns: ProColumns<GithubIssueItem>[] = [
      {
        dataIndex: 'index',
        valueType: 'indexBorder',
        width: 48,
      },
      {
        title: '标题',
        dataIndex: 'title',
        copyable: true,
        ellipsis: true,
        tooltip: '标题过长会自动收缩',
        formItemProps: {
          rules: [
            {
              required: true,
              message: '此项为必填项',
            },
          ],
        },
      },
      {
        disable: true,
        title: '状态',
        dataIndex: 'state',
        filters: true,
        onFilter: true,
        ellipsis: true,
        valueType: 'select',
        valueEnum: {
          all: { text: '超长'.repeat(50) },
          open: {
            text: '未解决',
            status: 'Error',
          },
          closed: {
            text: '已解决',
            status: 'Success',
            disabled: true,
          },
          processing: {
            text: '处理中',
            status: 'Processing',
          },
        },
      },
      {
        disable: true,
        title: '标签',
        dataIndex: 'labels',
        search: false,
        formItemRender: (_, { defaultRender }) => {
          return defaultRender(_);
        },
        render: (_, record) => (
          <Space>
            {record.labels.map(({ name, color }) => (
              <Tag color={color} key={name}>
                {name}
              </Tag>
            ))}
          </Space>
        ),
      },
      {
        title: '创建时间',
        key: 'showTime',
        dataIndex: 'created_at',
        valueType: 'date',
        sorter: true,
        search: false,
      },
      {
        title: '创建时间',
        dataIndex: 'created_at',
        valueType: 'dateRange',
        hideInTable: true,
        search: {
          transform: (value) => {
            return {
              startTime: value[0],
              endTime: value[1],
            };
          },
        },
      },
      {
        title: '操作',
        valueType: 'option',
        key: 'option',
        render: (text, record, _, action) => [
          <a
            key="editable"
            onClick={() => {
              action?.startEditable?.(record.id);
            }}
          >
            编辑
          </a>,
          <a href={record.url} target="_blank" rel="noopener noreferrer" key="view">
            查看
          </a>,
          <TableDropdown
            key="actionGroup"
            onSelect={() => action?.reload()}
            menus={[
              { key: 'copy', name: '复制' },
              { key: 'delete', name: '删除' },
            ]}
          />,
        ],
      },
    ];
    
    const Demo = () => {
      const actionRef = useRef<ActionType>();
      return (
        <ProTable<GithubIssueItem>
          columns={columns}
          actionRef={actionRef}
          cardBordered
          request={async (params) => {
            await waitTime(2000);
            return request<{
              data: GithubIssueItem[];
            }>('https://proapi.azurewebsites.net/github/issues', {
              params,
            });
          }}
          editable={{
            type: 'multiple',
          }}
          columnsState={{
            persistenceKey: 'pro-table-singe-demos',
            persistenceType: 'localStorage',
            defaultValue: {
              option: { fixed: 'right', disable: true },
            },
            onChange: () => {
              message.info('列设置已更新');
            },
          }}
          rowKey="id"
          search={{
            labelWidth: 'auto',
          }}
          options={{
            setting: {
              listsHeight: 400,
            },
          }}
          form={{
            syncToUrl: (values, type) => {
              if (type === 'get') {
                return {
                  ...values,
                  created_at: [values.startTime, values.endTime],
                };
              }
              return values;
            },
          }}
          pagination={{
            pageSize: 5,
            onChange: (page, pageSize) => {
              message.info(`第 ${page} 页${pageSize ? `,每页 ${pageSize} 条` : ''}`);
            },
          }}
          dateFormatter="string"
          headerTitle="Issue 管理"
          toolBarRender={() => [
            <Button
              key="button"
              icon={<PlusOutlined />}
              onClick={() => {
                actionRef.current?.reload();
              }}
              type="primary"
            >
              新建
            </Button>,
            <Dropdown
              key="menu"
              menu={{
                items: [
                  { label: '导入数据', key: 'import' },
                  { label: '导出数据', key: 'export' },
                  { label: '批量分配', key: 'assign' },
                ],
              }}
            >
              <Button>
                <EllipsisOutlined />
              </Button>
            </Dropdown>,
          ]}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    微服务应用列表
    应用名称
    容器数量
    状态负责人操作
    用户认证服务3已关闭书琰
    订单处理中心6运行中逄一
    支付网关9已上线期贤
    商品管理服务12异常玄霜
    物流追踪系统3已关闭怀渊
    • 第 1-5 条/总共 5 条
    • 1
    无查询表单
    import { DownOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable, TableDropdown } from '@ant-design/pro-components';
    import { Button } from 'antd';
    
    import {
      createTableDataSource,
      DEMO_CREATOR_VALUE_ENUM,
      DEMO_STATUS_VALUE_ENUM,
    } from '../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      containers: number;
      creator: string;
      status: string;
      createdAt: number;
      memo: string;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 5,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        width: 120,
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '容器数量',
        dataIndex: 'containers',
        align: 'right',
        sorter: (a, b) => a.containers - b.containers,
      },
      {
        title: '状态',
        width: 80,
        dataIndex: 'status',
        initialValue: 'all',
        valueEnum: DEMO_STATUS_VALUE_ENUM,
      },
      {
        title: '负责人',
        width: 80,
        dataIndex: 'creator',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
      {
        title: '操作',
        width: 180,
        key: 'option',
        valueType: 'option',
        render: () => [
          <a key="detail">详情</a>,
          <a key="log">日志</a>,
          <a key="monitor">监控</a>,
          <TableDropdown
            key="actionGroup"
            menus={[
              { key: 'restart', name: '重启' },
              { key: 'delete', name: '下线' },
            ]}
          />,
        ],
      },
    ];
    
    const Demo = () => {
      return (
        <ProTable<TableListItem>
          dataSource={tableListDataSource}
          rowKey="key"
          pagination={{
            showQuickJumper: true,
          }}
          columns={columns}
          search={false}
          dateFormatter="string"
          headerTitle="微服务应用列表"
          toolBarRender={() => [
            <Button key="log">查看日志</Button>,
            <Button key="export">
              导出数据
              <DownOutlined />
            </Button>,
            <Button type="primary" key="primary">
              部署应用
            </Button>,
          ]}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    卡片边框:
    基础表格
    名称
    状态
    创建时间进度金额操作
    暂无数据
    暂无数据
    卡片边框
    import { PlusOutlined } from '@ant-design/icons';
    import type { ActionType, ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Button, Space, Switch } from 'antd';
    import React, { useRef, useState } from 'react';
    
    const valueEnum: Record<number, string> = {
      0: 'close',
      1: 'running',
      2: 'online',
      3: 'error',
    };
    
    export type TableListItem = {
      key: number;
      name: string;
      status: string;
      updatedAt: number;
      createdAt: number;
      progress: number;
      money: number;
    };
    
    const tableListDataSource: TableListItem[] = [];
    
    for (let i = 0; i < 5; i += 1) {
      tableListDataSource.push({
        key: i,
        name: `TradeCode ${i}`,
        status: valueEnum[Math.floor(Math.random() * 10) % 4],
        updatedAt: Date.now() - Math.floor(Math.random() * 1000),
        createdAt: Date.now() - Math.floor(Math.random() * 2000),
        money: Math.floor(Math.random() * 2000) * i,
        progress: Math.ceil(Math.random() * 100) + 1,
      });
    }
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '状态',
        dataIndex: 'status',
        initialValue: 'all',
        filters: true,
        valueEnum: {
          all: { text: '全部', status: 'Default' },
          close: { text: '关闭', status: 'Default' },
          running: { text: '运行中', status: 'Processing' },
          online: { text: '已上线', status: 'Success' },
          error: { text: '异常', status: 'Error' },
        },
      },
      {
        title: '创建时间',
        dataIndex: 'createdAt',
        valueType: 'date',
      },
      {
        title: '进度',
        dataIndex: 'progress',
        valueType: 'progress',
      },
      {
        title: '金额',
        dataIndex: 'money',
        valueType: 'money',
      },
      {
        title: '操作',
        key: 'option',
        width: 120,
        valueType: 'option',
        render: () => [
          <a key="link">链路</a>,
          <a key="link2">报警</a>,
          <a key="link3">监控</a>,
        ],
      },
    ];
    
    const Demo = () => {
      const actionRef = useRef<ActionType>();
      const [bordered, setBordered] = useState(false);
    
      return (
        <>
          <Space style={{ marginBlockEnd: 16 }}>
            <span>卡片边框:</span>
            <Switch checked={bordered} onChange={setBordered} />
          </Space>
          <ProTable<TableListItem>
            columns={columns}
            actionRef={actionRef}
            cardBordered={bordered}
            request={async () => {
              return {
                data: tableListDataSource,
                success: true,
              };
            }}
            rowKey="key"
            search={{
              labelWidth: 'auto',
            }}
            pagination={{
              pageSize: 5,
            }}
            dateFormatter="string"
            headerTitle="基础表格"
            toolBarRender={() => [
              <Button
                key="button"
                icon={<PlusOutlined />}
                onClick={() => {
                  actionRef.current?.reload();
                }}
                type="primary"
              >
                新建
              </Button>,
            ]}
          />
        </>
      );
    };
    
    export default Demo;
    
    应用管理
    排序
    应用名称
    负责人
    状态
    备注操作
    暂无数据
    暂无数据
    使用 DataSource
    import { EllipsisOutlined, SearchOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable, TableDropdown } from '@ant-design/pro-components';
    import { Button, Dropdown, Input } from 'antd';
    
    import {
      createTableDataSource,
      DEMO_CREATOR_VALUE_ENUM,
      DEMO_STATUS_VALUE_ENUM,
    } from '../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      containers: number;
      creator: string;
      status: string;
      createdAt: number;
      progress: number;
      money: number;
      memo: string;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 5,
      withProgress: true,
      withMoney: true,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '排序',
        dataIndex: 'index',
        valueType: 'indexBorder',
        width: 48,
      },
      {
        title: '应用名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
        filterDropdown: () => (
          <div style={{ padding: 8 }}>
            <Input style={{ width: 188, marginBlockEnd: 8, display: 'block' }} />
          </div>
        ),
        filterIcon: (filtered) => (
          <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />
        ),
      },
      {
        title: '负责人',
        dataIndex: 'creator',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
      {
        title: '状态',
        dataIndex: 'status',
        initialValue: 'all',
        filters: true,
        onFilter: true,
        valueEnum: DEMO_STATUS_VALUE_ENUM,
      },
      {
        title: '备注',
        dataIndex: 'memo',
        ellipsis: true,
        copyable: true,
      },
      {
        title: '操作',
        width: 180,
        key: 'option',
        valueType: 'option',
        render: () => [
          <a key="detail">详情</a>,
          <a key="log">日志</a>,
          <a key="monitor">监控</a>,
          <TableDropdown
            key="actionGroup"
            menus={[
              { key: 'restart', name: '重启' },
              { key: 'delete', name: '下线' },
            ]}
          />,
        ],
      },
    ];
    
    const Demo = () => {
      return (
        <ProTable<TableListItem>
          columns={columns}
          request={(params, sorter, filter) => {
            console.log(params, sorter, filter);
            return Promise.resolve({
              data: tableListDataSource,
              total: tableListDataSource.length,
              success: true,
            });
          }}
          rowKey="key"
          pagination={{
            showQuickJumper: true,
          }}
          search={{
            layout: 'vertical',
            defaultCollapsed: false,
          }}
          dateFormatter="string"
          toolbar={{
            title: '应用管理',
            tooltip: '管理所有已部署的微服务应用',
          }}
          toolBarRender={() => [
            <Button key="danger" danger>
              批量下线
            </Button>,
            <Button key="log">查看日志</Button>,
            <Button type="primary" key="primary">
              部署应用
            </Button>,
            <Dropdown
              key="menu"
              menu={{
                items: [
                  { label: '导入配置', key: 'import' },
                  { label: '导出配置', key: 'export' },
                  { label: '批量更新', key: 'batch' },
                ],
              }}
            >
              <Button>
                <EllipsisOutlined />
              </Button>
            </Dropdown>,
          ]}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    成员名称账号角色权限范围操作
    暂无数据
    暂无数据
    无 ToolBar 的表格
    import { DownOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Avatar, Dropdown, Popconfirm, Space } from 'antd';
    import React from 'react';
    
    export type Member = {
      avatar: string;
      realName: string;
      nickName: string;
      email: string;
      outUserNo: string;
      phone: string;
      role: RoleType;
      permission?: string[];
    };
    
    export type RoleMapType = Record<
      string,
      {
        name: string;
        desc: string;
      }
    >;
    
    export type RoleType = 'admin' | 'operator';
    
    const RoleMap: RoleMapType = {
      admin: {
        name: '管理员',
        desc: '仅拥有指定项目的权限',
      },
      operator: {
        name: '操作员',
        desc: '拥有所有权限',
      },
    };
    
    const tableListDataSource: Member[] = [];
    
    const realNames = ['马巴巴', '测试', '测试2', '测试3'];
    const nickNames = ['巴巴', '测试', '测试2', '测试3'];
    const emails = [
      'baba@antfin.com',
      'test@antfin.com',
      'test2@antfin.com',
      'test3@antfin.com',
    ];
    const phones = ['12345678910', '10923456789', '109654446789', '109223346789'];
    const permissions = [[], ['权限点名称1', '权限点名称4'], ['权限点名称1'], []];
    
    for (let i = 0; i < 5; i += 1) {
      tableListDataSource.push({
        outUserNo: `${102047 + i}`,
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/upvrAjAPQX/Logo_Tech%252520UI.svg',
        role: i === 0 ? 'admin' : 'operator',
        realName: realNames[i % 4],
        nickName: nickNames[i % 4],
        email: emails[i % 4],
        phone: phones[i % 4],
        permission: permissions[i % 4],
      });
    }
    
    const MemberList: React.FC = () => {
      const renderRemoveUser = (text: string) => (
        <Popconfirm
          key="popconfirm"
          title={`确认${text}吗?`}
          okText="是"
          cancelText="否"
        >
          <a>{text}</a>
        </Popconfirm>
      );
    
      const columns: ProColumns<Member>[] = [
        {
          dataIndex: 'avatar',
          title: '成员名称',
          valueType: 'avatar',
          width: 150,
          render: (dom, record) => (
            <Space>
              <span>{dom}</span>
              {record.nickName}
            </Space>
          ),
        },
        {
          dataIndex: 'email',
          title: '账号',
          ellipsis: true,
          copyable: true,
          renderText: (_dom, row) => {
            return (
              <React.Fragment>
                <Avatar src={row.avatar} />
                {row.nickName}
              </React.Fragment>
            );
          },
        },
        {
          dataIndex: 'role',
          title: '角色',
          render: (_, record) => (
            <Dropdown
              menu={{
                items: [
                  {
                    label: '管理员',
                    key: 'admin',
                  },
                  {
                    label: '操作员',
                    key: 'operator',
                  },
                ],
              }}
            >
              <a>
                {RoleMap[record.role || 'admin'].name} <DownOutlined />
              </a>
            </Dropdown>
          ),
        },
        {
          dataIndex: 'permission',
          title: '权限范围',
          render: (_, record) => {
            const { role, permission = [] } = record;
            if (role === 'admin') {
              return '所有权限';
            }
            return permission && permission.length > 0
              ? permission.join('、')
              : '无';
          },
        },
        {
          title: '操作',
          dataIndex: 'x',
          valueType: 'option',
          render: (_, record) => {
            let node = renderRemoveUser('退出');
            if (record.role === 'admin') {
              node = renderRemoveUser('移除');
            }
            return [<a key="edit">编辑</a>, node];
          },
        },
      ];
    
      return (
        <ProTable<Member>
          columns={columns}
          request={(_params, _sorter, _filter) => {
            // 表单搜索项会从 params 传入,传递给后端接口。
            return Promise.resolve({
              data: tableListDataSource,
              total: tableListDataSource.length,
              success: true,
            });
          }}
          rowKey="outUserNo"
          pagination={{
            showQuickJumper: true,
          }}
          toolBarRender={false}
          search={false}
        />
      );
    
      <div
        style={{
          marginTop: '20px',
          padding: '20px',
          backgroundColor: '#f5f5f5',
          borderRadius: '6px',
        }}
      >
        <h4>ProTable 无标题 Props 说明:</h4>
        <ul>
          <li>
            <strong>ProTable</strong>: 专业表格组件
          </li>
          <li>
            <strong>Dropdown</strong>: 下拉菜单组件
          </li>
          <li>
            <strong>Popconfirm</strong>: 气泡确认框组件
          </li>
          <li>
            <strong>Space</strong>: 间距组件
          </li>
          <li>
            <strong>无标题</strong>: 展示无标题功能
          </li>
        </ul>
        <h4>ProTable 配置:</h4>
        <ul>
          <li>
            <strong>columns</strong>: 列配置
          </li>
          <li>
            <strong>request</strong>: 请求函数
          </li>
          <li>
            <strong>rowKey</strong>: 行键
          </li>
          <li>
            <strong>pagination</strong>: 分页配置
          </li>
          <li>
            <strong>toolBarRender</strong>: 工具栏渲染
          </li>
          <li>
            <strong>search</strong>: 搜索配置
          </li>
        </ul>
        <h4>无标题特点:</h4>
        <ul>
          <li>
            <strong>头像显示</strong>: 支持头像显示
          </li>
          <li>
            <strong>角色管理</strong>: 支持角色管理
          </li>
          <li>
            <strong>权限控制</strong>: 支持权限控制
          </li>
          <li>
            <strong>下拉菜单</strong>: 支持下拉菜单
          </li>
          <li>
            <strong>确认操作</strong>: 支持确认操作
          </li>
          <li>
            <strong>简洁布局</strong>: 支持简洁布局
          </li>
        </ul>
        <h4>使用场景:</h4>
        <ul>
          <li>
            <strong>成员管理</strong>: 成员管理系统
          </li>
          <li>
            <strong>权限管理</strong>: 权限管理功能
          </li>
          <li>
            <strong>用户列表</strong>: 用户列表展示
          </li>
        </ul>
      </div>;
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <MemberList />
      </div>
    );
    

    搜索栏类型切换

    通过 Segmented 切换 search.filterType,在查询表单(query)和轻量筛选(light)之间一键切换。

    search.filterType 搜索栏类型:
    搜索栏类型切换
    应用名称负责人状态
    暂无数据
    暂无数据
    搜索栏类型切换
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Segmented } from 'antd';
    import { useState } from 'react';
    
    import {
      createTableDataSource,
      DEMO_CREATOR_VALUE_ENUM,
      DEMO_STATUS_VALUE_ENUM,
      FIXED_BASE_DATE,
    } from '../mockData';
    
    type TableListItem = {
      key: number;
      name: string;
      creator: string;
      status: string;
      createdAt: number;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 5,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '负责人',
        dataIndex: 'creator',
        valueType: 'select',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
      {
        title: '状态',
        dataIndex: 'status',
        valueEnum: DEMO_STATUS_VALUE_ENUM,
      },
      {
        title: '日期范围',
        dataIndex: 'startTime',
        valueType: 'dateRange',
        hideInTable: true,
        initialValue: [FIXED_BASE_DATE, FIXED_BASE_DATE.add(7, 'day')],
      },
    ];
    
    const Demo = () => {
      const [filterType, setFilterType] = useState<'query' | 'light'>('query');
    
      return (
        <div>
          <div style={{ marginBlockEnd: 16 }}>
            <span>search.filterType 搜索栏类型:</span>
            <Segmented
              value={filterType}
              onChange={(v) => setFilterType(v as any)}
              options={[
                { label: '查询表单 query', value: 'query' },
                { label: '轻量筛选 light', value: 'light' },
              ]}
            />
          </div>
          <ProTable<TableListItem>
            columns={columns}
            request={() =>
              Promise.resolve({
                data: tableListDataSource,
                total: tableListDataSource.length,
                success: true,
              })
            }
            rowKey="key"
            search={{ filterType }}
            dateFormatter="string"
            headerTitle="搜索栏类型切换"
          />
        </div>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    搜索与筛选

    应用列表(无操作按钮)
    应用名称
    容器数量
    状态
    部署时间
    暂无数据
    暂无数据
    查询(无按钮)表格
    import { DownOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Button } from 'antd';
    
    import { createTableDataSource, DEMO_STATUS_VALUE_ENUM } from '../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      containers: number;
      creator: string;
      status: string;
      createdAt: number;
      memo: string;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 5,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        width: 120,
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '容器数量',
        dataIndex: 'containers',
        align: 'right',
        sorter: (a, b) => a.containers - b.containers,
      },
      {
        title: '状态',
        width: 80,
        dataIndex: 'status',
        initialValue: 'all',
        valueEnum: DEMO_STATUS_VALUE_ENUM,
      },
      {
        title: '部署时间',
        tooltip: '最近一次部署的时间',
        width: 140,
        key: 'since',
        search: false,
        dataIndex: 'createdAt',
        valueType: 'date',
        sorter: (a, b) => a.createdAt - b.createdAt,
      },
    ];
    
    const Demo = () => {
      return (
        <ProTable<TableListItem>
          columns={columns}
          request={(params, sorter, filter) => {
            console.log(params, sorter, filter);
            return Promise.resolve({
              data: tableListDataSource,
              total: tableListDataSource.length,
              success: true,
            });
          }}
          rowKey="key"
          pagination={{
            showQuickJumper: true,
          }}
          search={{
            optionRender: false,
            collapsed: false,
          }}
          dateFormatter="string"
          headerTitle="应用列表(无操作按钮)"
          toolBarRender={() => [
            <Button key="log">查看日志</Button>,
            <Button key="export">
              导出数据
              <DownOutlined />
            </Button>,
            <Button type="primary" key="primary">
              部署应用
            </Button>,
          ]}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    轻量筛选
    应用名称负责人
    暂无数据
    暂无数据
    轻量筛选替换查询表单
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    
    import {
      createTableDataSource,
      DEMO_CREATOR_VALUE_ENUM,
      FIXED_BASE_DATE,
    } from '../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      creator: string;
      createdAt: number;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 1,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
        formItemProps: {},
      },
      {
        title: '日期范围',
        dataIndex: 'startTime',
        valueType: 'dateRange',
        hideInTable: true,
        initialValue: [FIXED_BASE_DATE, FIXED_BASE_DATE.add(1, 'day')],
      },
      {
        title: '负责人',
        dataIndex: 'creator',
        valueType: 'select',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
    ];
    
    const Demo = () => {
      return (
        <ProTable<TableListItem>
          columns={columns}
          request={(params, sorter, filter) => {
            console.log(params, sorter, filter);
            return Promise.resolve({
              data: tableListDataSource,
              total: tableListDataSource.length,
              success: true,
            });
          }}
          headerTitle="轻量筛选"
          rowKey="key"
          pagination={{
            showQuickJumper: true,
          }}
          options={false}
          search={{
            filterType: 'light',
          }}
          dateFormatter="string"
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    快速搜索服务
    序号服务名称
    暂无数据
    暂无数据
    使用自带 keyWords 搜索的 table
    import { ProTable } from '@ant-design/pro-components';
    
    type ServiceItem = {
      key: number;
      name: string;
      createdAt: number;
    };
    
    const SearchTable = () => (
      <ProTable<ServiceItem>
        columns={[
          {
            title: '序号',
            dataIndex: 'index',
            valueType: 'indexBorder',
          },
          {
            title: '服务名称',
            dataIndex: 'name',
            search: false,
          },
        ]}
        request={async (_params) => {
    
          return {
            data: [
              {
                key: 1,
                name: '用户认证服务',
                createdAt: 1705286400000,
              },
              {
                key: 2,
                name: '订单处理中心',
                createdAt: 1705200000000,
              },
              {
                key: 3,
                name: '支付网关',
                createdAt: 1705113600000,
              },
            ],
            total: 3,
            success: true,
          };
        }}
        search={false}
        rowKey="key"
        options={{
          search: true,
        }}
        headerTitle="快速搜索服务"
      />
    );
    
    export default () => (
      <div style={{ padding: 24 }}>
        <SearchTable />
      </div>
    );
    
    搜索选项自定义
    序号服务名称合同金额
    暂无数据
    暂无数据
    搜索选项自定义
    import { PlusOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Button } from 'antd';
    
    type ServiceItem = {
      key: number;
      name: string;
      createdAt: number;
    };
    
    const columns: ProColumns<ServiceItem>[] = [
      {
        title: '序号',
        dataIndex: 'index',
        valueType: 'indexBorder',
      },
      {
        title: '服务名称',
        dataIndex: 'name',
      },
      {
        title: '合同金额',
        dataIndex: 'title',
        width: 100,
        valueType: 'money',
        renderText: () => '128000',
      },
    ];
    
    const Demo = () => (
      <ProTable<ServiceItem>
        columns={columns}
        request={async () => {
          return {
            data: [
              {
                key: 1,
                name: '企业版云服务套餐',
                createdAt: 1705286400000,
              },
            ],
            total: 1,
            success: true,
          };
        }}
        rowKey="key"
        dateFormatter="string"
        headerTitle="搜索选项自定义"
        search={{
          defaultCollapsed: false,
          labelWidth: 'auto',
          optionRender: (searchConfig, formProps, dom) => [
            ...dom.reverse(),
            <Button key="export" onClick={() => {}}>
              导出
            </Button>,
          ],
        }}
        toolBarRender={() => [
          <Button key="primary" type="primary">
            <PlusOutlined />
            新建
          </Button>,
        ]}
      />
    );
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    高级表格
    标题
    状态
    标签创建时间
    暂无数据
    暂无数据
    高级表格
    标题
    状态
    标签创建时间
    暂无数据
    暂无数据
    必填的查询表单
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Space, Tag } from 'antd';
    
    type GithubIssueItem = {
      id: number;
      number: number;
      title: string;
      labels: {
        name: string;
        color: string;
      }[];
      state: string;
      comments: number;
      created_at: number;
      updated_at: number;
    };
    
    const columns: ProColumns<GithubIssueItem>[] = [
      {
        title: '标题',
        dataIndex: 'title',
        copyable: true,
        ellipsis: true,
        tooltip: '标题过长会自动收缩',
        formItemProps: {
          rules: [
            {
              required: true,
              message: '此项为必填项',
            },
          ],
        },
        width: '30%',
      },
      {
        title: '状态',
        dataIndex: 'state',
        filters: true,
        onFilter: true,
        valueType: 'select',
        formItemProps: {
          rules: [
            {
              required: true,
              message: '此项为必填项',
            },
          ],
        },
        valueEnum: {
          all: { text: '全部', status: 'Default' },
          open: {
            text: '未解决',
            status: 'Error',
          },
          closed: {
            text: '已解决',
            status: 'Success',
            disabled: true,
          },
          processing: {
            text: '解决中',
            status: 'Processing',
          },
        },
      },
      {
        title: '标签',
        dataIndex: 'labels',
        search: false,
        formItemProps: {
          rules: [
            {
              required: true,
              message: '此项为必填项',
            },
          ],
        },
        formItemRender: (_, { defaultRender }) => {
          return defaultRender(_);
        },
        render: (_, record) => (
          <Space>
            {record.labels.map(({ name, color }) => (
              <Tag color={color} key={name}>
                {name}
              </Tag>
            ))}
          </Space>
        ),
      },
      {
        title: '创建时间',
        key: 'showTime',
        dataIndex: 'created_at',
        valueType: 'date',
        search: false,
        formItemProps: {
          rules: [
            {
              required: true,
              message: '此项为必填项',
            },
          ],
        },
      },
    ];
    
    const Demo = () => {
      return (
        <>
          <ProTable<GithubIssueItem>
            columns={columns}
            request={async () => ({
              success: true,
              data: [
                {
                  id: 624748504,
                  number: 6689,
                  title: '🐛 [BUG]yarn install命令 antd2.4.5会报错',
                  labels: [
                    {
                      name: 'bug',
                      color: 'error',
                    },
                  ],
                  state: 'open',
                  locked: false,
                  comments: 1,
                  created_at: 1590486176000,
                  updated_at: 1590487382000,
                  closed_at: null,
                  author_association: 'NONE',
                  user: 'shuyan',
                  avatar:
                    'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
                },
              ],
            })}
            rowKey="id"
            search={{
              labelWidth: 'auto',
            }}
            form={{
              ignoreRules: false,
            }}
            dateFormatter="string"
            headerTitle="高级表格"
          />
          <ProTable<GithubIssueItem>
            columns={columns}
            request={async () => ({
              success: true,
              data: [
                {
                  id: 624748504,
                  number: 6689,
                  title: '🐛 [BUG]yarn install命令 antd2.4.5会报错',
                  labels: [
                    {
                      name: 'bug',
                      color: 'error',
                    },
                  ],
                  state: 'open',
                  locked: false,
                  comments: 1,
                  created_at: 1590486176000,
                  updated_at: 1590487382000,
                  closed_at: null,
                  author_association: 'NONE',
                  user: 'shuyan',
                  avatar:
                    'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
                },
              ],
            })}
            rowKey="id"
            search={{
              labelWidth: 'auto',
            }}
            dateFormatter="string"
            headerTitle="高级表格"
          />
        </>
      );
    
      <div
        style={{
          marginTop: '20px',
          padding: '20px',
          backgroundColor: '#f5f5f5',
          borderRadius: '6px',
        }}
      >
        <h4>ProTable 开放规则 Props 说明:</h4>
        <ul>
          <li>
            <strong>ProTable</strong>: 专业表格组件
          </li>
          <li>
            <strong>Space</strong>: 间距组件
          </li>
          <li>
            <strong>Tag</strong>: 标签组件
          </li>
          <li>
            <strong>开放规则</strong>: 展示开放规则功能
          </li>
        </ul>
        <h4>ProTable 配置:</h4>
        <ul>
          <li>
            <strong>columns</strong>: 列配置
          </li>
          <li>
            <strong>request</strong>: 请求函数
          </li>
          <li>
            <strong>rowKey</strong>: 行键
          </li>
          <li>
            <strong>search</strong>: 搜索配置
          </li>
          <li>
            <strong>form</strong>: 表单配置
          </li>
          <li>
            <strong>dateFormatter</strong>: 日期格式化
          </li>
          <li>
            <strong>headerTitle</strong>: 表格标题
          </li>
        </ul>
        <h4>开放规则特点:</h4>
        <ul>
          <li>
            <strong>表单验证</strong>: 支持表单验证
          </li>
          <li>
            <strong>必填校验</strong>: 支持必填校验
          </li>
          <li>
            <strong>标签显示</strong>: 支持标签显示
          </li>
          <li>
            <strong>复制功能</strong>: 支持复制功能
          </li>
          <li>
            <strong>省略号显示</strong>: 支持省略号显示
          </li>
          <li>
            <strong>状态过滤</strong>: 支持状态过滤
          </li>
        </ul>
        <h4>使用场景:</h4>
        <ul>
          <li>
            <strong>表单验证</strong>: 表单验证需求
          </li>
          <li>
            <strong>数据校验</strong>: 数据校验功能
          </li>
          <li>
            <strong>规则配置</strong>: 规则配置需求
          </li>
        </ul>
      </div>;
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    尽量使用 initialValue 来解决问题,必填项挫败感比较强。

    搜索表单自定义

    当内置的表单项无法满足我们的基本需求,这时候我们就需要来自定义一下默认的组件,我们可以通过 fieldProps 和 formItemRender 配合来使用。

    fieldProps 可以把 props 透传,可以设置 select 的样式和多选等问题。

    formItemRender 可以完成重写渲染逻辑,传入 item 和 props 来进行渲染,需要注意的是我们必须要将 props 中的 value 和 onChange 必须要被赋值,否则 form 无法拿到参数。如果你需要自定义需要先了解 antd 表单的工作原理。

    formItemRender: (
      _,
      { type, defaultRender, formItemProps, fieldProps, ...rest },
      form,
    ) => {
      if (type === 'form') {
        return null;
      }
      const status = form.getFieldValue('state');
      if (status !== 'open') {
        return (
          // value 和 onchange 会通过 form 自动注入。
          <Input
            // 组件的配置
            {...fieldProps}
            // 自定义配置
            placeholder="请输入test"
          />
        );
      }
      return defaultRender(_);
    };

    formItemRender 的定义,具体的值可以打开控制台查看。

     formItemRender?: (
        item: ProColumns<T>,
        config: {
          value?: any;
          onSelect?: (value: any) => void;
          type: ProTableTypes;
          defaultRender: (newItem: ProColumns<any>) => JSX.Element | null;
        },
        form: FormInstance,
      ) => JSX.Element | false | null;

    实际类型定义见 ProSchema['formItemRender']:第三个参数为 FormInstance,还支持第四个参数 action(编辑工具方法集合,可编辑表格场景使用)。

    动态联动搜索栏
    序号服务名称查询周期
    暂无数据
    暂无数据
    动态联动搜索栏
    import { PlusOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Button, Input, Select } from 'antd';
    import React, { useEffect, useState } from 'react';
    
    type ServiceItem = {
      key: number;
      name: string;
      createdAt: number;
    };
    
    const MySelect: React.FC<{
      state: {
        type: number;
      };
      value?: string;
      onChange?: (value: string) => void;
    }> = (props) => {
      const { state } = props;
    
      const [innerOptions, setOptions] = useState<
        {
          label: React.ReactNode;
          value: number;
        }[]
      >([]);
    
      useEffect(() => {
        const { type } = state || {};
        if (type === 2) {
          setOptions([
            { label: '星期一', value: 1 },
            { label: '星期二', value: 2 },
          ]);
        } else {
          setOptions([
            { label: '一月', value: 1 },
            { label: '二月', value: 2 },
          ]);
        }
      }, [JSON.stringify(state)]);
    
      return (
        <Select
          options={innerOptions}
          value={props.value}
          onChange={props.onChange}
        />
      );
    };
    
    const Demo = () => {
      const columns: ProColumns<ServiceItem>[] = [
        {
          title: '序号',
          dataIndex: 'index',
          valueType: 'indexBorder',
        },
        {
          title: '服务名称',
          dataIndex: 'name',
        },
        {
          title: '动态表单',
          key: 'direction',
          hideInTable: true,
          dataIndex: 'direction',
          formItemRender: (
            item,
            { type, defaultRender: _defaultRender, ...rest },
            form,
          ) => {
            if (type === 'form') {
              return null;
            }
            const stateType = form.getFieldValue('state');
            if (stateType === 3) {
              return <Input />;
            }
            if (stateType === 4) {
              return null;
            }
            return (
              <MySelect
                {...rest}
                state={{
                  type: stateType,
                }}
              />
            );
          },
        },
        {
          title: '查询周期',
          dataIndex: 'state',
          initialValue: 1,
          valueType: 'select',
          request: async () => [
            { label: '按月', value: 1 },
            { label: '按周', value: 2 },
            { label: '自定义', value: 3 },
            { label: '不展示', value: 4 },
          ],
        },
      ];
    
      return (
        <ProTable<ServiceItem>
          columns={columns}
          request={async (_params) => {
    
            return {
              data: [
                {
                  key: 1,
                  name: '用户认证服务',
                  createdAt: 1705286400000,
                  state: 'closed',
                },
              ],
              total: 1,
              success: true,
            };
          }}
          rowKey="key"
          tableLayout="fixed"
          dateFormatter="string"
          headerTitle="动态联动搜索栏"
          search={{
            defaultCollapsed: false,
            optionRender: (searchConfig, formProps, dom) => [
              ...dom.reverse(),
              <Button
                key="export"
                onClick={() => {
                  const _values = searchConfig?.form?.getFieldsValue();
    
                }}
              >
                导出
              </Button>,
            ],
          }}
          toolBarRender={() => [
            <Button key="new" type="primary">
              <PlusOutlined />
              新建
            </Button>,
          ]}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    表单赋值
    应用名称部署时间
    暂无数据
    暂无数据
    通过 formRef 来操作查询表单
    import type { ProColumns, ProFormInstance } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Button } from 'antd';
    import { useRef, useState } from 'react';
    
    export type TableListItem = {
      key: number;
      name: string;
    };
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        dataIndex: 'name',
        key: 'name',
      },
      {
        title: '部署时间',
        key: 'since',
        dataIndex: 'createdAt',
        valueType: 'date',
      },
    ];
    
    const Demo = () => {
      const ref = useRef<ProFormInstance>();
      const [collapsed, setCollapsed] = useState(false);
    
      return (
        <ProTable<TableListItem>
          columns={columns}
          request={() =>
            Promise.resolve({
              data: [
                {
                  key: 1,
                  name: '用户认证服务',
                  createdAt: 1705286400000,
                },
              ],
              total: 1,
              success: true,
            })
          }
          rowKey="key"
          pagination={{
            showSizeChanger: true,
          }}
          search={{
            collapsed,
            onCollapse: setCollapsed,
          }}
          formRef={ref}
          toolBarRender={() => [
            <Button
              key="set"
              onClick={() => {
                if (ref.current) {
                  ref.current.setFieldsValue({
                    name: '支付网关',
                  });
                }
              }}
            >
              赋值
            </Button>,
            <Button
              key="submit"
              onClick={() => {
                if (ref.current) {
                  ref.current.submit();
                }
              }}
            >
              提交
            </Button>,
          ]}
          options={false}
          dateFormatter="string"
          headerTitle="表单赋值"
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    为什么不能自己设置 value 和 onchange

    被 ProTable 包装的控件,表单控件会自动添加 value(或 valuePropName 指定的其他属性) onChange(或 trigger 指定的其他属性),数据同步将被 Form 接管,这会导致以下结果:

    • 你不再需要也不应该用 onChange 来做数据收集同步(你可以使用 Form 的 onValuesChange),但还是可以继续监听 onChange 事件。

    • 你不能用控件的 value 或 defaultValue 等属性来设置表单域的值,默认值可以用 Form 里的 initialValues 来设置。注意 initialValues 不能被 setState 动态更新,你需要用 setFieldsValue 来更新。

    • 你不应该用 setState,可以使用 form.setFieldsValue 来动态改变表单值。

    为什么设置 defaultValue 不生效?

    因为 ProTable 子组件会转为受控模式。因而 defaultValue 不会生效。你需要在 Form 上通过 initialValues 设置默认值。

    表格功能

    游标分页仅显示「上一页 / 下一页」,适合无法或不需要获取总条数的场景。 request 返回的 nextToken 会被自动传入下一次请求。
    ID名称状态部门创建时间
    评分
    暂无数据
    暂无数据
    游标分页
    import { ProTable } from '@ant-design/pro-components';
    import { Typography } from 'antd';
    
    type Row = {
      id: number;
      name: string;
      status: 'active' | 'closed' | 'pending';
      department: string;
      createdAt: string;
      score: number;
    };
    
    const departments = ['技术部', '产品部', '设计部', '运营部', '市场部'];
    const statuses: Row['status'][] = ['active', 'closed', 'pending'];
    const names = [
      'Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon',
      'Zeta', 'Eta', 'Theta', 'Iota', 'Kappa',
      'Lambda', 'Mu', 'Nu', 'Xi', 'Omicron',
      'Pi', 'Rho', 'Sigma', 'Tau', 'Upsilon',
      'Phi', 'Chi', 'Psi', 'Omega', 'Nova',
      'Apex', 'Zenith', 'Vertex', 'Nexus', 'Pulse',
    ];
    
    const rows: Row[] = names.map((name, index) => ({
      id: index + 1,
      name,
      status: statuses[index % 3],
      department: departments[index % 5],
      createdAt: new Date(2026, 0, index + 1).toISOString().split('T')[0],
      score: Math.floor(Math.random() * 40) + 60,
    }));
    
    export default () => (
      <>
        <Typography.Paragraph type="secondary">
          游标分页仅显示「上一页 / 下一页」,适合无法或不需要获取总条数的场景。
          request 返回的 nextToken 会被自动传入下一次请求。
        </Typography.Paragraph>
        <ProTable<Row>
          rowKey="id"
          search={false}
          options={false}
          columns={[
            { title: 'ID', dataIndex: 'id', width: 64 },
            { title: '名称', dataIndex: 'name' },
            {
              title: '状态',
              dataIndex: 'status',
              valueEnum: {
                active: { text: '启用', status: 'Success' },
                closed: { text: '关闭', status: 'Default' },
                pending: { text: '待处理', status: 'Processing' },
              },
            },
            { title: '部门', dataIndex: 'department' },
            { title: '创建时间', dataIndex: 'createdAt', valueType: 'date' },
            {
              title: '评分',
              dataIndex: 'score',
              sorter: (a, b) => a.score - b.score,
              render: (_, row) => (
                <Typography.Text type={row.score >= 80 ? 'success' : 'warning'}>
                  {row.score}
                </Typography.Text>
              ),
            },
          ]}
          pagination={{ type: 'cursor', pageSize: 5 }}
          request={async (
            // 第一个参数 params 包含分页信息
            // 游标分页模式下会传入 nextToken
            params: {
              pageSize?: number;
              current?: number;
              nextToken?: string;
            },
          ) => {
            const index = Number(params.nextToken ?? 0);
            return {
              success: true,
              data: rows.slice(index, index + 5),
              nextToken: index + 5 < rows.length ? String(index + 5) : undefined,
            };
          }}
        />
      </>
    );
    
    批量操作
    已选 1 项取消选择
    容器总数: 0 个
    请求总量: 0 次
    应用名称
    容器数量
    请求量部署进度负责人
    部署时间
    备注操作
    用户认证服务35678
    24%
    书琰2024-01-15核心服务,承载全站用户登录与鉴权
    订单处理中心66912
    41%
    逄一2024-01-14日均处理订单量 50 万+,高峰期需要关注性能
    支付网关98146
    期贤2024-01-13对接微信、支付宝等第三方支付渠道
    商品管理服务129380
    玄霜2024-01-12负责全品类商品的增删改查及上下架管理
    物流追踪系统310614
    92%
    怀渊2024-01-11接入顺丰、中通等多家物流运力
    表格批量操作
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Button, DatePicker, Space, Table } from 'antd';
    
    import { createTableDataSource, DEMO_CREATOR_VALUE_ENUM } from '../mockData';
    
    const { RangePicker } = DatePicker;
    
    const ProcessMap = {
      close: 'normal',
      running: 'active',
      online: 'success',
      error: 'exception',
    } as const;
    
    export type TableListItem = {
      key: number;
      name: string;
      progress: number;
      containers: number;
      callNumber: number;
      creator: string;
      status: string;
      createdAt: number;
      memo: string;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 50,
      withProgress: true,
      withCallNumber: true,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        width: 140,
        dataIndex: 'name',
        fixed: 'left',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '容器数量',
        width: 100,
        dataIndex: 'containers',
        align: 'right',
        search: false,
        sorter: (a, b) => a.containers - b.containers,
      },
      {
        title: '请求量',
        width: 100,
        align: 'right',
        dataIndex: 'callNumber',
      },
      {
        title: '部署进度',
        dataIndex: 'progress',
        valueType: (item) => ({
          type: 'progress',
          status: ProcessMap[item.status as 'close'],
        }),
      },
      {
        title: '负责人',
        width: 100,
        dataIndex: 'creator',
        valueType: 'select',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
      {
        title: '部署时间',
        width: 140,
        key: 'since',
        dataIndex: 'createdAt',
        valueType: 'date',
        sorter: (a, b) => a.createdAt - b.createdAt,
        formItemRender: () => {
          return <RangePicker />;
        },
      },
      {
        title: '备注',
        dataIndex: 'memo',
        ellipsis: true,
        copyable: true,
        search: false,
      },
      {
        title: '操作',
        width: 80,
        key: 'option',
        valueType: 'option',
        fixed: 'right',
        render: () => [<a key="detail">详情</a>],
      },
    ];
    
    const Demo = () => {
      return (
        <ProTable<TableListItem>
          columns={columns}
          rowSelection={{
            selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT],
            defaultSelectedRowKeys: [1],
          }}
          tableAlertRender={({
            selectedRowKeys,
            selectedRows,
            onCleanSelected,
          }) => {
    
            return (
              <Space size={24}>
                <span>
                  已选 {selectedRowKeys.length} 项
                  <a style={{ marginInlineStart: 8 }} onClick={onCleanSelected}>
                    取消选择
                  </a>
                </span>
                <span>{`容器总数: ${selectedRows.reduce(
                  (pre, item) => pre + (item?.containers ?? 0),
                  0,
                )} 个`}</span>
                <span>{`请求总量: ${selectedRows.reduce(
                  (pre, item) => pre + (item?.callNumber ?? 0),
                  0,
                )} 次`}</span>
              </Space>
            );
          }}
          tableAlertOptionRender={() => {
            return (
              <Space size={16}>
                <a>批量重启</a>
                <a>批量下线</a>
                <a>导出数据</a>
              </Space>
            );
          }}
          dataSource={tableListDataSource}
          scroll={{ x: 1300 }}
          options={false}
          search={false}
          pagination={{
            pageSize: 5,
          }}
          rowKey="key"
          headerTitle="批量操作"
          toolBarRender={() => [<Button key="export">导出报表</Button>]}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    应用部署记录
    应用名称状态
    容器数量
    负责人
    暂无数据
    暂无数据
    嵌套表格
    import { DownOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Button, Tag } from 'antd';
    
    import {
      DEMO_APP_NAMES,
      DEMO_CREATORS,
      DEMO_CREATOR_VALUE_ENUM,
      FIXED_BASE_TIMESTAMP,
    } from '../mockData';
    
    export type Status = {
      color: string;
      text: string;
    };
    
    const statusMap: Record<string, Status> = {
      0: {
        color: 'blue',
        text: '部署中',
      },
      1: {
        color: 'green',
        text: '运行正常',
      },
      2: {
        color: 'volcano',
        text: '性能告警',
      },
      3: {
        color: 'red',
        text: '运行异常',
      },
      4: {
        color: '',
        text: '待部署',
      },
    };
    
    export type TableListItem = {
      key: number;
      name: string;
      containers: number;
      creator: string;
      status: Status;
      createdAt: number;
    };
    
    const tableListDataSource: TableListItem[] = Array.from(
      { length: 5 },
      (_, i) => ({
        key: i,
        name: DEMO_APP_NAMES[i % DEMO_APP_NAMES.length],
        containers: ((i * 3 + 2) % 12) + 1,
        creator: DEMO_CREATORS[i % DEMO_CREATORS.length],
        status: statusMap[String(i % 5)],
        createdAt: FIXED_BASE_TIMESTAMP - i * 86400000,
      }),
    );
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        width: 140,
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '状态',
        width: 120,
        dataIndex: 'status',
        render: (_, record) => (
          <Tag color={record.status.color}>{record.status.text}</Tag>
        ),
      },
      {
        title: '容器数量',
        width: 100,
        dataIndex: 'containers',
        align: 'right',
        sorter: (a, b) => a.containers - b.containers,
      },
      {
        title: '负责人',
        width: 100,
        dataIndex: 'creator',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
    ];
    
    const expandedRowRender = () => {
      const data = [
        {
          key: 0,
          date: '2024-01-15 08:30:00',
          name: '版本发布 v2.3.1',
          upgradeNum: '已更新 3 个实例',
        },
        {
          key: 1,
          date: '2024-01-14 16:20:00',
          name: '配置变更 - 数据库连接池',
          upgradeNum: '已更新 5 个实例',
        },
        {
          key: 2,
          date: '2024-01-13 10:15:00',
          name: '扩容 - 新增 2 个节点',
          upgradeNum: '已更新 2 个实例',
        },
      ];
      return (
        <ProTable
          columns={[
            { title: '操作时间', dataIndex: 'date', key: 'date' },
            { title: '变更内容', dataIndex: 'name', key: 'name' },
            { title: '更新状态', dataIndex: 'upgradeNum', key: 'upgradeNum' },
            {
              title: '操作',
              dataIndex: 'operation',
              key: 'operation',
              valueType: 'option',
              render: () => [<a key="rollback">回滚</a>, <a key="detail">详情</a>],
            },
          ]}
          headerTitle={false}
          search={false}
          options={false}
          dataSource={data}
          pagination={false}
        />
      );
    };
    
    const Demo = () => {
      return (
        <ProTable<TableListItem>
          columns={columns}
          request={(params, sorter, filter) => {
            console.log(params, sorter, filter);
            return Promise.resolve({
              data: tableListDataSource,
              total: tableListDataSource.length,
              success: true,
            });
          }}
          rowKey="key"
          pagination={{
            showQuickJumper: true,
          }}
          expandable={{ expandedRowRender }}
          search={false}
          dateFormatter="string"
          headerTitle="应用部署记录"
          options={false}
          toolBarRender={() => [
            <Button key="log">查看日志</Button>,
            <Button key="export">
              导出数据
              <DownOutlined />
            </Button>,
            <Button key="primary" type="primary">
              部署应用
            </Button>,
          ]}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    标题状态标签创建时间评分更新时间操作
    Issue 标题 1未解决bug2026-09-26 10:00:00
    2026-09-26 10:00:00
    Issue 标题 2已解决bug2026-09-26 10:00:00
    2026-09-26 10:00:00
    Issue 标题 3未解决bug2026-09-26 10:00:00
    2026-09-26 10:00:00
    Issue 标题 4已解决bug2026-09-26 10:00:00
    2026-09-26 10:00:00
    Issue 标题 5未解决bug2026-09-26 10:00:00
    2026-09-26 10:00:00
    Issue 标题 6已解决bug2026-09-26 10:00:00
    2026-09-26 10:00:00
    Issue 标题 7未解决bug2026-09-26 10:00:00
    2026-09-26 10:00:00
    Issue 标题 8已解决bug2026-09-26 10:00:00
    2026-09-26 10:00:00
    固定选择列
    /**
     * title: 固定选择列
     * description: 选择列使用 `fixed: 'start'` 固定后,配合其他固定列横向滚动时,表头勾选框不应被相邻固定列遮挡。
     */
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Table, Tag } from 'antd';
    
    type IssueItem = {
      key: number;
      title: string;
      labels: { name: string; color: string }[];
      state: string;
      createdAt: string;
      rate: number;
    };
    
    const columns: ProColumns<IssueItem>[] = [
      { title: '标题', dataIndex: 'title', width: 160, fixed: 'start' },
      {
        title: '状态',
        dataIndex: 'state',
        width: 100,
        valueType: 'select',
        valueEnum: {
          open: { text: '未解决', status: 'Error' },
          closed: { text: '已解决', status: 'Success' },
        },
      },
      {
        title: '标签',
        dataIndex: 'labels',
        width: 140,
        search: false,
        render: (_, record) => (
          <span>
            {record.labels.map(({ name, color }) => (
              <Tag color={color} key={name}>
                {name}
              </Tag>
            ))}
          </span>
        ),
      },
      {
        title: '创建时间',
        dataIndex: 'createdAt',
        width: 160,
        valueType: 'dateTime',
      },
      { title: '评分', dataIndex: 'rate', width: 160, valueType: 'rate' },
      {
        title: '更新时间',
        dataIndex: 'createdAt',
        width: 160,
        valueType: 'dateTime',
      },
      {
        title: '操作',
        dataIndex: 'option',
        valueType: 'option',
        width: 120,
        fixed: 'end',
      },
    ];
    
    const dataSource: IssueItem[] = Array.from({ length: 8 }).map((_, i) => ({
      key: i,
      title: `Issue 标题 ${i + 1}`,
      labels: [{ name: 'bug', color: 'error' }],
      state: i % 2 === 0 ? 'open' : 'closed',
      createdAt: '2026-09-26 10:00:00',
      rate: 4,
    }));
    
    export default () => (
      <ProTable<IssueItem>
        columns={columns}
        dataSource={dataSource}
        rowKey="key"
        search={false}
        toolBarRender={false}
        pagination={false}
        scroll={{ x: 1200 }}
        rowSelection={{
          fixed: 'start',
          selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT],
        }}
      />
    );
    
    服务器 IPCPU内存磁盘
    暂无数据
    暂无数据
    10.0.1.100
    时间点执行日志操作
    暂无数据
    暂无数据
    左右结构
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProCard, ProTable } from '@ant-design/pro-components';
    import type { BadgeProps } from 'antd';
    import { Badge, Button } from 'antd';
    import React, { useEffect, useState } from 'react';
    
    import { FIXED_BASE_TIMESTAMP } from '../mockData';
    
    type LogItem = {
      createdAtRange?: number[];
      createdAt: number;
      code: string;
    };
    
    type ServerDetailProps = {
      ip: string;
    };
    
    const ServerDetail: React.FC<ServerDetailProps> = (props) => {
      const { ip } = props;
      const [logDataSource, setLogDataSource] = useState<LogItem[]>([]);
    
      const columns: ProColumns<LogItem>[] = [
        {
          title: '时间点',
          key: 'createdAt',
          dataIndex: 'createdAt',
          valueType: 'dateTime',
        },
        {
          title: '执行日志',
          key: 'code',
          width: 80,
          dataIndex: 'code',
          valueType: 'code',
        },
        {
          title: '操作',
          key: 'option',
          width: 80,
          valueType: 'option',
          render: () => [<a key="alert">告警</a>],
        },
      ];
    
      useEffect(() => {
        const source = [];
        for (let i = 0; i < 15; i += 1) {
          source.push({
            createdAt: FIXED_BASE_TIMESTAMP - (i * 500 + 100),
            code: `const healthCheck = async (host) => {
              const res = await fetch(host + '/health');
              return { status: res.status, latency: res.headers.get('x-latency') };
            };`,
            key: i,
          });
        }
    
        setLogDataSource(source);
      }, [ip]);
    
      return (
        <ProTable<LogItem>
          columns={columns}
          dataSource={logDataSource}
          pagination={{
            pageSize: 3,
            showSizeChanger: false,
          }}
          rowKey="key"
          toolBarRender={false}
          search={false}
        />
      );
    };
    
    type statusType = BadgeProps['status'];
    
    const valueEnum: statusType[] = ['success', 'error', 'processing', 'default'];
    
    export type ServerItem = {
      ip?: string;
      cpu?: number | string;
      mem?: number | string;
      disk?: number | string;
      status: statusType;
    };
    
    const serverListDataSource: ServerItem[] = [];
    
    for (let i = 0; i < 10; i += 1) {
      serverListDataSource.push({
        ip: `10.0.${Math.floor(i / 3) + 1}.${(i * 11 + 100) % 256}`,
        cpu: ((i * 7 + 15) % 60) + 10,
        mem: ((i * 13 + 25) % 50) + 20,
        status: valueEnum[i % 4],
        disk: ((i * 11 + 30) % 40) + 15,
      });
    }
    
    type ServerListProps = {
      ip: string;
      onChange: (id: string) => void;
    };
    
    const ServerList: React.FC<ServerListProps> = (props) => {
      const { onChange } = props;
    
      const columns: ProColumns<ServerItem>[] = [
        {
          title: '服务器 IP',
          key: 'ip',
          dataIndex: 'ip',
          render: (_, item) => {
            return <Badge status={item.status} text={item.ip} />;
          },
        },
        {
          title: 'CPU',
          key: 'cpu',
          dataIndex: 'cpu',
          valueType: {
            type: 'percent',
            precision: 0,
          },
        },
        {
          title: '内存',
          key: 'mem',
          dataIndex: 'mem',
          valueType: {
            type: 'percent',
            precision: 0,
          },
        },
        {
          title: '磁盘',
          key: 'disk',
          dataIndex: 'disk',
          valueType: {
            type: 'percent',
            precision: 0,
          },
        },
      ];
      return (
        <ProTable<ServerItem>
          columns={columns}
          request={(params, sorter, filter) => {
            console.log(params, sorter, filter);
            return Promise.resolve({
              data: serverListDataSource,
              total: serverListDataSource.length,
              success: true,
            });
          }}
          rowKey="ip"
          toolbar={{
            search: {
              onSearch: (value) => {
                alert(value);
              },
            },
            actions: [
              <Button key="add" type="primary">
                添加节点
              </Button>,
            ],
          }}
          options={false}
          pagination={false}
          search={false}
          onRow={(record) => {
            return {
              onClick: () => {
                if (record.ip) {
                  onChange(record.ip);
                }
              },
            };
          }}
        />
      );
    };
    
    const Demo: React.FC = () => {
      const [ip, setIp] = useState('10.0.1.100');
      return (
        <ProCard split="vertical">
          <ProCard colSpan="384px" ghost>
            <ServerList onChange={(cIp) => setIp(cIp)} ip={ip} />
          </ProCard>
          <ProCard title={ip}>
            <ServerDetail ip={ip} />
          </ProCard>
        </ProCard>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    上次更新时间:10:00:00
    序号
    状态
    部署进度时间
    创建时间更新时间
    暂无数据
    暂无数据
    表格轮询
    import { LoadingOutlined, ReloadOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Button } from 'antd';
    import dayjs from 'dayjs';
    import { useState } from 'react';
    
    import {
      DEMO_STATUS_VALUE_ENUM,
      DEMO_VALUE_ENUM,
      FIXED_BASE_TIMESTAMP,
    } from '../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      status: string;
      updatedAt: number;
      createdAt: number;
      progress: number;
      money: number;
    };
    
    const tableListDataSource: TableListItem[] = Array.from(
      { length: 2 },
      (_, i) => ({
        key: i,
        name: i === 0 ? '用户认证服务' : '支付网关',
        status: DEMO_VALUE_ENUM[(i % 4) as keyof typeof DEMO_VALUE_ENUM],
        updatedAt: FIXED_BASE_TIMESTAMP - (i * 500 + 100),
        createdAt: FIXED_BASE_TIMESTAMP - (i * 1000 + 200),
        money: ((i * 3456 + 7890) % 50000) * 100,
        progress: ((i * 17 + 23) % 100) + 1,
      }),
    );
    
    const timeAwait = (waitTime: number): Promise<void> =>
      new Promise((res) =>
        window.setTimeout(() => {
          res();
        }, waitTime),
      );
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '序号',
        dataIndex: 'index',
        valueType: 'index',
        width: 80,
      },
      {
        title: '状态',
        dataIndex: 'status',
        initialValue: 'all',
        filters: true,
        onFilter: true,
        valueEnum: DEMO_STATUS_VALUE_ENUM,
      },
      {
        title: '部署进度',
        key: 'progress',
        dataIndex: 'progress',
        valueType: (item) => ({
          type: 'progress',
          status: item.status !== 'error' ? 'active' : 'exception',
        }),
      },
      {
        title: '时间',
        key: 'since',
        children: [
          {
            title: '创建时间',
            key: 'createdAt',
            dataIndex: 'createdAt',
            valueType: 'date',
          },
          {
            title: '更新时间',
            key: 'updatedAt',
            dataIndex: 'updatedAt',
            valueType: 'date',
          },
        ],
      },
    ];
    
    const Demo = () => {
      const [time, setTime] = useState(() => FIXED_BASE_TIMESTAMP);
      const [polling, setPolling] = useState<number>(2000);
      return (
        <ProTable<TableListItem>
          columns={columns}
          rowKey="key"
          pagination={{
            showSizeChanger: true,
          }}
          polling={polling}
          request={async () => {
            await timeAwait(2000);
            setTime(FIXED_BASE_TIMESTAMP);
            return {
              data: tableListDataSource,
              success: true,
              total: tableListDataSource.length,
            };
          }}
          dateFormatter="string"
          headerTitle={`上次更新时间:${dayjs(time).format('HH:mm:ss')}`}
          toolBarRender={() => [
            <Button
              key="polling"
              type="primary"
              onClick={() => {
                if (polling) {
                  setPolling(0);
                  return;
                }
                setPolling(2000);
              }}
            >
              {polling ? <LoadingOutlined /> : <ReloadOutlined />}
              {polling ? '停止轮询' : '开始轮询'}
            </Button>,
          ]}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    日期格式化为字符串
    服务名称部署时间
    暂无数据
    暂无数据
    日期格式化为数字
    服务名称部署时间
    暂无数据
    暂无数据
    使用自定义函数进行日期格式化
    服务名称部署时间
    暂无数据
    暂无数据
    dateFormatter - 日期格式化
    import type { ProColumns, ProFormInstance } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { useRef, useState } from 'react';
    
    export type TableListItem = {
      key: number;
      name: string;
      createdAt: string;
    };
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '服务名称',
        dataIndex: 'name',
        initialValue: '用户认证服务',
      },
      {
        title: '部署时间',
        dataIndex: 'createdAt',
        valueType: 'date',
        initialValue: '2024-01-15',
      },
    ];
    
    const mockData = {
      key: 1,
      name: '用户认证服务',
      createdAt: '2024-01-15',
    };
    
    const Demo = () => {
      const ref = useRef<ProFormInstance>();
      const [collapsed, setCollapsed] = useState(false);
    
      return (
        <>
          <ProTable<TableListItem>
            style={{
              margin: '16px',
            }}
            columns={columns}
            request={(_params) => {
    
              return Promise.resolve({
                data: [mockData],
                total: 1,
                success: true,
              });
            }}
            rowKey="key"
            pagination={{
              showSizeChanger: true,
            }}
            search={{
              collapsed,
              onCollapse: setCollapsed,
            }}
            formRef={ref}
            options={false}
            dateFormatter="string"
            headerTitle="日期格式化为字符串"
          />
    
          <ProTable<TableListItem>
            style={{
              margin: '16px',
            }}
            columns={columns}
            request={(_params) => {
    
              return Promise.resolve({
                data: [mockData],
                total: 1,
                success: true,
              });
            }}
            rowKey="key"
            pagination={{
              showSizeChanger: true,
            }}
            search={{
              collapsed,
              onCollapse: setCollapsed,
            }}
            formRef={ref}
            options={false}
            dateFormatter="number"
            headerTitle="日期格式化为数字"
          />
          <ProTable<TableListItem>
            style={{
              margin: '16px',
            }}
            columns={columns}
            request={(_params) => {
    
              return Promise.resolve({
                data: [mockData],
                total: 1,
                success: true,
              });
            }}
            rowKey="key"
            pagination={{
              showSizeChanger: true,
            }}
            search={{
              collapsed,
              onCollapse: setCollapsed,
            }}
            formRef={ref}
            options={false}
            dateFormatter={(value, _valueType) => {
    
              return value.format('YYYY-MM-DD HH:mm:ss');
            }}
            headerTitle="使用自定义函数进行日期格式化"
          />
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    Toolbar 自定义

    使用 toolbar 属性扩展配置工具栏渲染。

    应用名称负责人
    状态
    容器数量
    操作
    暂无数据
    暂无数据
    Toolbar 自定义
    import type { ProColumns } from '@ant-design/pro-components';
    import {
      LightFilter,
      ProFormDatePicker,
      ProTable,
    } from '@ant-design/pro-components';
    import { Badge, Button } from 'antd';
    import React, { useState } from 'react';
    
    import { createTableDataSource, DEMO_CREATOR_VALUE_ENUM } from '../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      containers: number;
      status: string;
      creator: string;
      createdAt: number;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 5,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '负责人',
        dataIndex: 'creator',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
      {
        title: '状态',
        dataIndex: 'status',
        initialValue: 'all',
        filters: true,
        onFilter: true,
        valueEnum: {
          all: { text: '全部', status: 'Default' },
          close: { text: '待发布', status: 'Default' },
          running: { text: '发布中', status: 'Processing' },
          online: { text: '发布成功', status: 'Success' },
          error: { text: '发布失败', status: 'Error' },
        },
      },
      {
        title: '容器数量',
        dataIndex: 'containers',
        align: 'right',
        sorter: (a, b) => a.containers - b.containers,
      },
      {
        title: '操作',
        key: 'option',
        width: 120,
        valueType: 'option',
        render: (_, record) => [
          record.status === 'close' && <a key="publish">发布</a>,
          (record.status === 'running' || record.status === 'online') && (
            <a key="stop">停用</a>
          ),
          record.status === 'error' && <a key="republish">重新发布</a>,
          <a
            key="monitor"
            style={
              record.status === 'running'
                ? {
                    color: 'rgba(0,0,0,.25)',
                    cursor: 'not-allowed',
                  }
                : {}
            }
          >
            监控
          </a>,
        ],
      },
    ];
    
    const renderBadge = (count: number, active = false) => {
      return (
        <Badge
          count={count}
          style={{
            marginBlockStart: -2,
            marginInlineStart: 4,
            color: active ? '#1890FF' : '#999',
            backgroundColor: active ? '#E6F7FF' : '#eee',
          }}
        />
      );
    };
    
    const Demo = () => {
      const [activeKey, setActiveKey] = useState<React.Key>('tab1');
    
      return (
        <ProTable<TableListItem>
          columns={columns}
          request={(params, sorter, filter) => {
            console.log(params, sorter, filter);
            return Promise.resolve({
              data: tableListDataSource,
              total: tableListDataSource.length,
              success: true,
            });
          }}
          toolbar={{
            filter: (
              <LightFilter>
                <ProFormDatePicker name="startdate" label="部署日期" />
              </LightFilter>
            ),
            menu: {
              type: 'tab',
              activeKey: activeKey,
              items: [
                {
                  key: 'tab1',
                  label: <span>应用{renderBadge(99, activeKey === 'tab1')}</span>,
                },
                {
                  key: 'tab2',
                  label: <span>项目{renderBadge(30, activeKey === 'tab2')}</span>,
                },
                {
                  key: 'tab3',
                  label: <span>文档{renderBadge(12, activeKey === 'tab3')}</span>,
                },
              ],
              onChange: (key) => {
                setActiveKey(key as string);
              },
            },
            actions: [
              <Button key="primary" type="primary">
                新建应用
              </Button>,
            ],
          }}
          rowKey="key"
          pagination={{
            showQuickJumper: true,
          }}
          search={false}
          dateFormatter="string"
          options={{
            setting: {
              draggable: true,
              checkable: true,
              checkedReset: false,
              extra: [<a key="confirm">确认</a>],
            },
          }}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    实例数0
    负责人书琰
    关联项目智慧零售平台
    创建时间2024-01-10
    上线时间2024-01-15
    自定义表格主体
    序号更新时间部署进度
    暂无数据
    暂无数据
    表格主体自定义
    import { MailOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Card, Descriptions, Menu } from 'antd';
    import { useState } from 'react';
    
    import { FIXED_BASE_TIMESTAMP } from '../mockData';
    
    const waitTime = (time: number = 100) => {
      return new Promise((resolve) => {
        setTimeout(() => {
          resolve(true);
        }, time);
      });
    };
    
    export type TableListItem = {
      key: number;
      name: string;
      createdAt: number;
      progress: number;
    };
    
    const tableListDataSource: TableListItem[] = Array.from(
      { length: 2 },
      (_, i) => ({
        key: i,
        name: i === 0 ? '用户认证服务' : '支付网关',
        createdAt: FIXED_BASE_TIMESTAMP - (i * 1000 + 200),
        progress: ((i * 17 + 23) % 100) + 1,
      }),
    );
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '序号',
        dataIndex: 'index',
        valueType: 'index',
        width: 80,
      },
      {
        title: '更新时间',
        key: 'since2',
        dataIndex: 'createdAt',
        valueType: 'date',
      },
      {
        title: '部署进度',
        dataIndex: 'progress',
        valueType: 'progress',
      },
    ];
    
    const Demo = () => {
      const [key, setKey] = useState('1');
    
      return (
        <ProTable<TableListItem>
          columns={columns}
          rowKey="key"
          pagination={{
            showSizeChanger: true,
          }}
          tableRender={(_, dom) => (
            <div
              style={{
                display: 'flex',
                width: '100%',
              }}
            >
              <Menu
                onSelect={(e) => setKey(e.key as string)}
                style={{ width: 256 }}
                defaultSelectedKeys={['1']}
                defaultOpenKeys={['sub1']}
                mode="inline"
                items={[
                  {
                    key: 'sub1',
                    label: (
                      <span>
                        <MailOutlined />
                        <span>服务管理</span>
                      </span>
                    ),
                    children: [
                      {
                        type: 'group',
                        key: 'g1',
                        label: '核心服务',
                        children: [
                          { key: '1', label: '用户认证服务' },
                          { key: '2', label: '订单处理中心' },
                        ],
                      },
                      {
                        type: 'group',
                        key: 'g2',
                        label: '基础设施',
                        children: [
                          { key: '3', label: '支付网关' },
                          { key: '4', label: '消息推送平台' },
                        ],
                      },
                    ],
                  },
                ]}
              />
              <div
                style={{
                  flex: 1,
                }}
              >
                {dom}
              </div>
            </div>
          )}
          tableExtraRender={(_, data) => (
            <Card>
              <Descriptions size="small" column={3}>
                <Descriptions.Item label="实例数">{data.length}</Descriptions.Item>
                <Descriptions.Item label="负责人">书琰</Descriptions.Item>
                <Descriptions.Item label="关联项目">
                  <a>智慧零售平台</a>
                </Descriptions.Item>
                <Descriptions.Item label="创建时间">2024-01-10</Descriptions.Item>
                <Descriptions.Item label="上线时间">2024-01-15</Descriptions.Item>
              </Descriptions>
            </Card>
          )}
          params={{
            key,
          }}
          request={async () => {
            await waitTime(200);
            return {
              success: true,
              data: tableListDataSource,
            };
          }}
          dateFormatter="string"
          headerTitle="自定义表格主体"
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    卡片表格

    有些业务有自己的定制逻辑,可以不完全遵循 ProTable 的设计规则,但可以利用 ProTable 的 API 实现:例如通过 cardProps.title(或 cardProps 其他字段)配置卡片标题区域,通过 headerTitle 在左上角放置主按钮等操作区(见示例)。

    业务定制
    应用名称
    容器数量
    创建者操作
    暂无数据
    暂无数据

    ProTable 卡片标题 Props 说明:

    • ProTable: 专业表格组件
    • 卡片标题: 展示卡片标题功能

    ProTable 配置:

    • columns: 列配置
    • request: 请求函数
    • cardProps: 卡片属性配置
    • headerTitle: 表格标题
    • rowKey: 行键
    • search: 搜索配置

    卡片标题特点:

    • 卡片包装: 支持卡片包装
    • 自定义标题: 支持自定义标题
    • 请求处理: 支持请求处理
    • 简洁配置: 简洁的配置方式

    使用场景:

    • 业务定制: 业务定制需求
    • 卡片展示: 卡片展示功能
    • 数据管理: 数据管理系统
    import { EllipsisOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Button } from 'antd';
    
    import { createTableDataSource, DEMO_CREATOR_VALUE_ENUM } from '../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      containers: number;
      creator: string;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 5,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '容器数量',
        dataIndex: 'containers',
        align: 'right',
        sorter: (a, b) => a.containers - b.containers,
      },
      {
        title: '创建者',
        dataIndex: 'creator',
        valueType: 'select',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
      {
        title: '操作',
        key: 'option',
        width: 120,
        valueType: 'option',
        render: () => [
          <a key="link">链路</a>,
          <a key="warn">报警</a>,
          <a key="more">
            <EllipsisOutlined />
          </a>,
        ],
      },
    ];
    
    const Demo = () => {
      return (
        <>
          <ProTable<TableListItem>
            columns={columns}
            request={(params, sorter, filter) => {
              // 表单搜索项会从 params 传入,传递给后端接口。
              console.log(params, sorter, filter);
              return Promise.resolve({
                data: tableListDataSource,
                total: tableListDataSource.length,
                success: true,
              });
            }}
            cardProps={{ title: '业务定制', variant: 'outlined' }}
            headerTitle={
              <Button
                key="primary"
                type="primary"
                onClick={() => {
                  alert('add');
                }}
              >
                添加
              </Button>
            }
            rowKey="key"
            search={false}
          />
          <div
            style={{
              marginTop: '20px',
              padding: '20px',
              backgroundColor: '#f5f5f5',
              borderRadius: '6px',
            }}
          >
            <h4>ProTable 卡片标题 Props 说明:</h4>
            <ul>
              <li>
                <strong>ProTable</strong>: 专业表格组件
              </li>
              <li>
                <strong>卡片标题</strong>: 展示卡片标题功能
              </li>
            </ul>
            <h4>ProTable 配置:</h4>
            <ul>
              <li>
                <strong>columns</strong>: 列配置
              </li>
              <li>
                <strong>request</strong>: 请求函数
              </li>
              <li>
                <strong>cardProps</strong>: 卡片属性配置
              </li>
              <li>
                <strong>headerTitle</strong>: 表格标题
              </li>
              <li>
                <strong>rowKey</strong>: 行键
              </li>
              <li>
                <strong>search</strong>: 搜索配置
              </li>
            </ul>
            <h4>卡片标题特点:</h4>
            <ul>
              <li>
                <strong>卡片包装</strong>: 支持卡片包装
              </li>
              <li>
                <strong>自定义标题</strong>: 支持自定义标题
              </li>
              <li>
                <strong>请求处理</strong>: 支持请求处理
              </li>
              <li>
                <strong>简洁配置</strong>: 简洁的配置方式
              </li>
            </ul>
            <h4>使用场景:</h4>
            <ul>
              <li>
                <strong>业务定制</strong>: 业务定制需求
              </li>
              <li>
                <strong>卡片展示</strong>: 卡片展示功能
              </li>
              <li>
                <strong>数据管理</strong>: 数据管理系统
              </li>
            </ul>
          </div>
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    无搜索表格

    关闭搜索栏时,只要存在 options(刷新、列设置等),表格仍会使用卡片包裹。

    应用名称
    容器数量
    创建者操作
    暂无数据
    暂无数据
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    
    import { createTableDataSource, DEMO_CREATOR_VALUE_ENUM } from '../mockData';
    
    type TableListItem = {
      key: number;
      name: string;
      containers: number;
      creator: string;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 5,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '容器数量',
        dataIndex: 'containers',
        align: 'right',
        sorter: (a, b) => a.containers - b.containers,
      },
      {
        title: '创建者',
        dataIndex: 'creator',
        valueType: 'select',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
      {
        title: '操作',
        key: 'option',
        width: 120,
        valueType: 'option',
        render: () => [<a key="link">链路</a>, <a key="warn">报警</a>],
      },
    ];
    
    export default () => (
      <ProTable<TableListItem>
        columns={columns}
        request={() =>
          Promise.resolve({
            data: tableListDataSource,
            total: tableListDataSource.length,
            success: true,
          })
        }
        rowKey="key"
        search={false}
        options={{ reload: true, setting: true }}
      />
    );
    

    值类型示例

    valueType - 日期类

    日期类型展示
    创建时间日期区间时间区间更新日期更新距今关闭时间操作
    暂无数据
    暂无数据
    import { ProTable } from '@ant-design/pro-components';
    
    import { DEMO_VALUE_ENUM, FIXED_BASE_TIMESTAMP } from '../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      status: string;
      updatedAt: number;
      createdAt: number;
      progress: number;
      money: number;
      percent: number | string;
      createdAtRange: number[];
      code: string;
    };
    
    const tableListDataSource: TableListItem[] = Array.from(
      { length: 2 },
      (_, i) => ({
        key: i,
        name: i === 0 ? '用户认证服务' : '支付网关',
        status: DEMO_VALUE_ENUM[(i % 4) as keyof typeof DEMO_VALUE_ENUM],
        updatedAt: FIXED_BASE_TIMESTAMP - (i * 500 + 100),
        createdAt: FIXED_BASE_TIMESTAMP - (i * 1000 + 200),
        createdAtRange: [
          FIXED_BASE_TIMESTAMP - (i * 1000 + 300),
          FIXED_BASE_TIMESTAMP - (i * 1000 + 400),
        ],
        money: ((i * 3456 + 7890) % 50000) * 100,
        progress: ((i * 17 + 23) % 100) + 1,
        percent:
          i % 2 === 0
            ? ((i + 1) * 10 + 0.123).toFixed(3)
            : -((i + 1) * 10 + 0.456).toFixed(2),
        code: `const healthCheck = async (host) => {
      const res = await fetch(host + '/health');
      return { status: res.status };
    };`,
      }),
    );
    
    const Demo = () => (
      <ProTable<TableListItem>
        columns={[
          {
            title: '创建时间',
            key: 'since',
            dataIndex: 'createdAt',
            valueType: 'dateTime',
          },
          {
            title: '日期区间',
            key: 'dateRange',
            dataIndex: 'createdAtRange',
            valueType: 'dateRange',
          },
          {
            title: '时间范围',
            key: 'dateTimeRangeCustom',
            dataIndex: 'dateTimeRange',
            hideInTable: true,
            valueType: 'dateTimeRange',
            fieldProps: {},
            formItemRender: (_, { type, defaultRender }) => {
              if (type === 'form') {
                return null;
              }
              return defaultRender(_);
            },
          },
          {
            title: '时间区间',
            key: 'dateTimeRange',
            dataIndex: 'createdAtRange',
            valueType: 'dateTimeRange',
            search: {
              transform: (value: any) => ({
                startTime: value[0],
                endTime: value[1],
              }),
            },
          },
          {
            title: '更新日期',
            key: 'since2',
            dataIndex: 'createdAt',
            valueType: 'date',
          },
          {
            title: '更新距今',
            key: 'since4',
            dataIndex: 'createdAt',
            valueType: 'fromNow',
          },
          {
            title: '关闭时间',
            key: 'since3',
            dataIndex: 'updatedAt',
            valueType: 'time',
          },
          {
            title: '操作',
            key: 'option',
            width: 120,
            valueType: 'option',
            render: (_, row, index, action) => [
              <a
                key="edit"
                onClick={() => {
                  action?.startEditable(row.key);
                }}
              >
                编辑
              </a>,
            ],
          },
        ]}
        request={() => {
          return Promise.resolve({
            total: 200,
            data: tableListDataSource,
            success: true,
          });
        }}
        rowKey="key"
        headerTitle="日期类型展示"
      />
    );
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    valueType - 数字类

    数值类型展示
    部署进度合同金额请求量响应时间CPU 占用操作
    暂无数据
    暂无数据
    import { ProTable } from '@ant-design/pro-components';
    
    import { DEMO_VALUE_ENUM, FIXED_BASE_TIMESTAMP } from '../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      status: string;
      updatedAt: number;
      createdAt: number;
      progress: number;
      money: number;
      percent: number | string;
      createdAtRange: number[];
      code: string;
    };
    
    const tableListDataSource: TableListItem[] = Array.from(
      { length: 2 },
      (_, i) => ({
        key: i,
        name: i === 0 ? '用户认证服务' : '支付网关',
        status: DEMO_VALUE_ENUM[(i % 4) as keyof typeof DEMO_VALUE_ENUM],
        updatedAt: FIXED_BASE_TIMESTAMP - (i * 500 + 100),
        createdAt: FIXED_BASE_TIMESTAMP - (i * 1000 + 200),
        createdAtRange: [
          FIXED_BASE_TIMESTAMP - (i * 1000 + 300),
          FIXED_BASE_TIMESTAMP - (i * 1000 + 400),
        ],
        money: ((i * 3456 + 7890) % 50000) * 100,
        progress: ((i * 17 + 23) % 100) + 1,
        percent:
          i % 2 === 0
            ? ((i + 1) * 10 + 0.123).toFixed(3)
            : -((i + 1) * 10 + 0.456).toFixed(2),
        code: `const healthCheck = async (host) => {
      const res = await fetch(host + '/health');
      return { status: res.status };
    };`,
      }),
    );
    
    const Demo = () => (
      <ProTable<TableListItem>
        columns={[
          {
            title: '部署进度',
            key: 'progress',
            dataIndex: 'progress',
            valueType: (item) => ({
              type: 'progress',
              status: item.status !== 'error' ? 'active' : 'exception',
            }),
            width: 200,
          },
          {
            title: '合同金额',
            dataIndex: 'money',
            valueType: 'money',
            width: 150,
          },
          {
            title: '请求量',
            dataIndex: 'money',
            key: 'digit',
            valueType: 'digit',
            width: 150,
          },
          {
            title: '响应时间',
            dataIndex: 'money',
            key: 'second',
            valueType: 'second',
            width: 150,
          },
          {
            title: 'CPU 占用',
            key: 'percent',
            width: 120,
            dataIndex: 'percent',
            valueType: () => ({
              type: 'percent',
            }),
          },
          {
            title: '操作',
            key: 'option',
            width: 120,
            valueType: 'option',
            render: (_, row, index, action) => [
              <a
                key="edit"
                onClick={() => {
                  action?.startEditable(row.key);
                }}
              >
                编辑
              </a>,
            ],
          },
        ]}
        request={() => {
          return Promise.resolve({
            total: 200,
            data: tableListDataSource,
            success: true,
          });
        }}
        rowKey="key"
        headerTitle="数值类型展示"
      />
    );
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    valueType - 样式类

    多值类型展示
    序号border 序号部署脚本负责人架构图操作
    暂无数据
    暂无数据
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Space } from 'antd';
    import dayjs from 'dayjs';
    
    import { DEMO_VALUE_ENUM } from '../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      status: string | number;
      updatedAt: number;
      createdAt: number;
      progress: number;
      money: number;
      percent: number | string;
      createdAtRange: number[];
      code: string;
      avatar: string;
      image: string;
    };
    
    const baseTime = dayjs('2024-01-15 10:30:00').valueOf();
    const tableListDataSource: TableListItem[] = Array.from(
      { length: 2 },
      (_, i) => ({
        key: i,
        avatar:
          'https://gw.alipayobjects.com/zos/antfincdn/efFD%24IOql2/weixintupian_20170331104822.jpg',
        image:
          'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png',
        name: i === 0 ? '用户认证服务' : '支付网关',
        status: DEMO_VALUE_ENUM[(i % 4) as keyof typeof DEMO_VALUE_ENUM],
        updatedAt: baseTime - (i * 500 + 100),
        createdAt: baseTime - (i * 1000 + 200),
        createdAtRange: [baseTime - (i * 1000 + 300), baseTime - (i * 1000 + 400)],
        money: ((i * 3456 + 7890) % 50000) * 100,
        progress: ((i * 17 + 23) % 100) + 1,
        percent:
          i % 2 === 0
            ? ((i + 1) * 10 + 0.123).toFixed(3)
            : -((i + 1) * 10 + 0.456).toFixed(2),
        code: `const healthCheck = async (host) => {
      const res = await fetch(host + '/health');
      return { status: res.status };
    };`,
      }),
    );
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '序号',
        dataIndex: 'index',
        valueType: 'index',
      },
      {
        title: 'border 序号',
        dataIndex: 'index',
        key: 'indexBorder',
        valueType: 'indexBorder',
      },
      {
        title: '部署脚本',
        key: 'code',
        width: 120,
        dataIndex: 'code',
        valueType: 'code',
      },
      {
        title: '负责人',
        dataIndex: 'avatar',
        key: 'avatar',
        valueType: 'avatar',
        width: 150,
        render: (dom) => (
          <Space>
            <span>{dom}</span>
            <a
              href="https://github.com/ant-design"
              target="_blank"
              rel="noopener noreferrer"
            >
              书琰
            </a>
          </Space>
        ),
      },
      {
        title: '架构图',
        dataIndex: 'image',
        key: 'image',
        valueType: 'image',
      },
      {
        title: '操作',
        key: 'option',
        width: 120,
        valueType: 'option',
        render: (_, row, index, action) => [
          <a
            key="edit"
            onClick={() => {
              action?.startEditable(row.key);
            }}
          >
            编辑
          </a>,
        ],
      },
    ];
    
    const Demo = () => (
      <ProTable<TableListItem>
        columns={columns}
        request={() => {
          return Promise.resolve({
            total: 200,
            data: tableListDataSource,
            success: true,
          });
        }}
        rowKey="key"
        headerTitle="多值类型展示"
      />
    );
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    valueType - 选择类

    枚举类型 valueType 切换
    状态列类型:
    应用名称状态(下拉选择 select)优先级(select)技术栈(cascader)所属部门(treeSelect)操作
    暂无数据
    暂无数据
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Radio, Space } from 'antd';
    import { useState } from 'react';
    
    /** 服务状态枚举 */
    const statusEnum = {
      all: { text: '全部', status: 'Default' },
      running: { text: '运行中', status: 'Processing' },
      online: { text: '已上线', status: 'Success' },
      error: { text: '异常', status: 'Error' },
    };
    
    /** 优先级枚举 */
    const priorityEnum = {
      urgent: { text: '紧急', status: 'Error' },
      high: { text: '高', status: 'Warning' },
      medium: { text: '中', status: 'Processing' },
      low: { text: '低', status: 'Default' },
    };
    
    /** 技术栈级联选项 */
    const techStackOptions = [
      {
        label: '前端',
        value: 'frontend',
        children: [
          { label: 'React', value: 'react' },
          { label: 'Vue', value: 'vue' },
          { label: 'Angular', value: 'angular' },
        ],
      },
      {
        label: '后端',
        value: 'backend',
        children: [
          { label: 'Java', value: 'java' },
          { label: 'Go', value: 'go' },
          { label: 'Node.js', value: 'nodejs' },
        ],
      },
      {
        label: '基础设施',
        value: 'infra',
        children: [
          { label: 'Kubernetes', value: 'k8s' },
          { label: 'Docker', value: 'docker' },
          { label: 'Terraform', value: 'terraform' },
        ],
      },
    ];
    
    /** 部门树形选项 */
    const departmentOptions = [
      {
        label: '技术研发部',
        value: 'tech',
        children: [
          { label: '前端开发组', value: 'tech-fe' },
          { label: '后端开发组', value: 'tech-be' },
          { label: '测试保障组', value: 'tech-qa' },
        ],
      },
      {
        label: '产品设计部',
        value: 'product',
        children: [
          { label: '产品策划组', value: 'product-pm' },
          { label: 'UX 设计组', value: 'product-ux' },
        ],
      },
    ];
    
    type ValueTypeKey =
      | 'select'
      | 'radio'
      | 'radioButton'
      | 'checkbox'
      | 'cascader'
      | 'treeSelect';
    
    const VALUE_TYPE_OPTIONS: { label: string; value: ValueTypeKey }[] = [
      { label: '下拉选择 select', value: 'select' },
      { label: '单选 radio', value: 'radio' },
      { label: '单选按钮 radioButton', value: 'radioButton' },
      { label: '多选 checkbox', value: 'checkbox' },
      { label: '级联 cascader', value: 'cascader' },
      { label: '树形 treeSelect', value: 'treeSelect' },
    ];
    
    export type TableListItem = {
      key: number;
      name: string;
      status: string;
      priority: string;
      techStack: string[];
      department: string[];
    };
    
    const tableListDataSource: TableListItem[] = [
      {
        key: 0,
        name: '用户认证服务',
        status: 'running',
        priority: 'high',
        techStack: ['frontend', 'react'],
        department: ['tech-fe'],
      },
      {
        key: 1,
        name: '订单处理中心',
        status: 'online',
        priority: 'urgent',
        techStack: ['backend', 'java'],
        department: ['tech-be'],
      },
      {
        key: 2,
        name: '支付网关',
        status: 'error',
        priority: 'medium',
        techStack: ['backend', 'go'],
        department: ['tech-be'],
      },
    ];
    
    const Demo = () => {
      const [statusType, setStatusType] = useState<ValueTypeKey>('select');
    
      const columns: ProColumns<TableListItem>[] = [
        {
          title: '应用名称',
          dataIndex: 'name',
          width: 140,
          search: false,
        },
        {
          title: `状态(${VALUE_TYPE_OPTIONS.find((o) => o.value === statusType)?.label})`,
          dataIndex: 'status',
          valueType: statusType,
          initialValue: statusType === 'checkbox' ? ['all'] : 'all',
          width: 160,
          valueEnum: statusEnum,
        },
        {
          title: '优先级(select)',
          dataIndex: 'priority',
          valueType: 'select',
          width: 120,
          valueEnum: priorityEnum,
        },
        {
          title: '技术栈(cascader)',
          key: 'techStack',
          dataIndex: 'techStack',
          width: 160,
          valueType: 'cascader',
          fieldProps: {
            options: techStackOptions,
          },
        },
        {
          title: '所属部门(treeSelect)',
          key: 'department',
          dataIndex: 'department',
          width: 180,
          valueType: 'treeSelect',
          fieldProps: {
            options: departmentOptions,
            showSearch: true,
            filterTreeNode: true,
            multiple: true,
            treeNodeFilterProp: 'label',
          },
        },
        {
          title: '操作',
          key: 'option',
          width: 80,
          valueType: 'option',
          render: (_, row, index, action) => [
            <a
              key="edit"
              onClick={() => {
                action?.startEditable(row.key);
              }}
            >
              编辑
            </a>,
          ],
        },
      ];
    
      return (
        <ProTable<TableListItem>
          columns={columns}
          request={() => {
            return Promise.resolve({
              data: tableListDataSource,
              total: tableListDataSource.length,
              success: true,
            });
          }}
          search={{
            defaultCollapsed: false,
            span: 12,
            labelWidth: 'auto',
          }}
          editable={{
            type: 'multiple',
          }}
          rowKey="key"
          headerTitle="枚举类型 valueType 切换"
          toolBarRender={() => [
            <Space key="switch">
              <span>状态列类型:</span>
              <Radio.Group
                optionType="button"
                size="small"
                value={statusType}
                onChange={(e) => setStatusType(e.target.value)}
                options={VALUE_TYPE_OPTIONS}
              />
            </Space>,
          ]}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    自定义 valueType

    自定义 valueType
    链接标签操作
    暂无数据
    暂无数据

    ProTable 自定义值类型 Props 说明:

    • ProTable: 专业表格组件
    • ProProvider: 专业提供者组件
    • Input: 输入框组件
    • Tag: 标签组件
    • 自定义值类型: 展示自定义值类型功能

    ProTable 配置:

    • columns: 列配置
    • request: 请求函数
    • rowKey: 行键
    • headerTitle: 表格标题

    自定义值类型特点:

    • valueTypeMap: 值类型映射
    • 自定义渲染: 支持自定义渲染
    • 表单项渲染: 支持表单项渲染
    • 链接类型: 支持链接类型
    • 标签类型: 支持标签类型
    • 可编辑: 支持可编辑功能

    使用场景:

    • 自定义展示: 自定义展示需求
    • 特殊数据类型: 特殊数据类型处理
    • 业务定制: 业务定制需求
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProProvider, ProTable } from '@ant-design/pro-components';
    import type { InputRef } from 'antd';
    import { Input, Space, Tag } from 'antd';
    import React, { useContext, useRef, useState } from 'react';
    
    import { DEMO_VALUE_ENUM } from '../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      status: {
        label: string | number;
        value: number;
      }[];
    };
    
    const tableListDataSource: TableListItem[] = Array.from(
      { length: 5 },
      (_, i) => ({
        key: i,
        name: `用户认证服务-${i}`,
        status: [
          {
            value: (i * 3 + 1) % 10,
            label: DEMO_VALUE_ENUM[(i % 4) as keyof typeof DEMO_VALUE_ENUM],
          },
          {
            value: (i * 5 + 2) % 10,
            label: DEMO_VALUE_ENUM[((i + 1) % 4) as keyof typeof DEMO_VALUE_ENUM],
          },
        ],
      }),
    );
    
    const TagList: React.FC<{
      value?: {
        key: string;
        label: string;
      }[];
      onChange?: (
        value: {
          key: string;
          label: string;
        }[],
      ) => void;
    }> = ({ value, onChange }) => {
      const ref = useRef<InputRef | null>(null);
      const [newTags, setNewTags] = useState<
        {
          key: string;
          label: string;
        }[]
      >([]);
      const [inputValue, setInputValue] = useState<string>('');
    
      const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        setInputValue(e.target.value);
      };
    
      const handleInputConfirm = () => {
        let tempsTags = [...(value || [])];
        if (
          inputValue &&
          tempsTags.filter((tag) => tag.label === inputValue).length === 0
        ) {
          tempsTags = [
            ...tempsTags,
            { key: `new-${tempsTags.length}`, label: inputValue },
          ];
        }
        onChange?.(tempsTags);
        setNewTags([]);
        setInputValue('');
      };
    
      return (
        <Space>
          {(value || []).concat(newTags).map((item) => (
            <Tag key={item.key}>{item.label}</Tag>
          ))}
          <Input
            ref={ref}
            type="text"
            size="small"
            style={{ width: 78 }}
            value={inputValue}
            onChange={handleInputChange}
            onBlur={handleInputConfirm}
            onPressEnter={handleInputConfirm}
          />
        </Space>
      );
    };
    
    const columns: ProColumns<TableListItem, 'link' | 'tags'>[] = [
      {
        title: '链接',
        dataIndex: 'name',
        valueType: 'link',
      },
      {
        title: '标签',
        dataIndex: 'status',
        key: 'status',
        valueType: 'tags',
      },
      {
        title: '操作',
        key: 'option',
        valueType: 'option',
        render: (_, row, index, action) => [
          <a
            key="a"
            onClick={() => {
              action?.startEditable(row.key);
            }}
          >
            编辑
          </a>,
        ],
      },
    ];
    
    const Demo = () => {
      const values = useContext(ProProvider);
      return (
        <>
          <ProProvider.Provider
            value={{
              ...values,
              valueTypeMap: {
                link: {
                  render: (text) => <a>{text}</a>,
                  formItemRender: (text, props) => (
                    <Input placeholder="请输入链接" {...props?.fieldProps} />
                  ),
                },
                tags: {
                  render: (text) => {
                    return (
                      <>
                        {[text].flat(1).map((item) => (
                          <Tag key={item.value}>{item.label}</Tag>
                        ))}
                      </>
                    );
                  },
                  formItemRender: (text, props) => (
                    <TagList {...props} {...props?.fieldProps} />
                  ),
                },
              },
            }}
          >
            <ProTable<TableListItem, Record<string, any>, 'link' | 'tags'>
              columns={columns}
              request={() => {
                return Promise.resolve({
                  total: 200,
                  data: tableListDataSource,
                  success: true,
                });
              }}
              rowKey="key"
              headerTitle="自定义 valueType"
            />
          </ProProvider.Provider>
          <div
            style={{
              marginTop: '20px',
              padding: '20px',
              backgroundColor: '#f5f5f5',
              borderRadius: '6px',
            }}
          >
            <h4>ProTable 自定义值类型 Props 说明:</h4>
            <ul>
              <li>
                <strong>ProTable</strong>: 专业表格组件
              </li>
              <li>
                <strong>ProProvider</strong>: 专业提供者组件
              </li>
              <li>
                <strong>Input</strong>: 输入框组件
              </li>
              <li>
                <strong>Tag</strong>: 标签组件
              </li>
              <li>
                <strong>自定义值类型</strong>: 展示自定义值类型功能
              </li>
            </ul>
            <h4>ProTable 配置:</h4>
            <ul>
              <li>
                <strong>columns</strong>: 列配置
              </li>
              <li>
                <strong>request</strong>: 请求函数
              </li>
              <li>
                <strong>rowKey</strong>: 行键
              </li>
              <li>
                <strong>headerTitle</strong>: 表格标题
              </li>
            </ul>
            <h4>自定义值类型特点:</h4>
            <ul>
              <li>
                <strong>valueTypeMap</strong>: 值类型映射
              </li>
              <li>
                <strong>自定义渲染</strong>: 支持自定义渲染
              </li>
              <li>
                <strong>表单项渲染</strong>: 支持表单项渲染
              </li>
              <li>
                <strong>链接类型</strong>: 支持链接类型
              </li>
              <li>
                <strong>标签类型</strong>: 支持标签类型
              </li>
              <li>
                <strong>可编辑</strong>: 支持可编辑功能
              </li>
            </ul>
            <h4>使用场景:</h4>
            <ul>
              <li>
                <strong>自定义展示</strong>: 自定义展示需求
              </li>
              <li>
                <strong>特殊数据类型</strong>: 特殊数据类型处理
              </li>
              <li>
                <strong>业务定制</strong>: 业务定制需求
              </li>
            </ul>
          </div>
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    国际化相关的配置

    ProTable 内置国际化相关文案。下面是 可被 createIntl 合并覆盖 的文案结构示意;与 antd ConfigProvider 的 locale 配合的完整切换方式,请直接参考下方 intl.tsx 示例。

    /** ProTable / 工具栏等区域会用到的文案 key,仅供结构参考 */
    export const proTableIntlShape = {
      tableForm: {
        search: 'Query',
        reset: 'Reset',
        submit: 'Submit',
        collapsed: 'Expand',
        expand: 'Collapse',
        inputPlaceholder: 'Please enter',
        selectPlaceholder: 'Please select',
      },
      alert: { clear: 'Clear' },
      tableToolBar: {
        leftPin: 'Pin to left',
        rightPin: 'Pin to right',
        noPin: 'Unpinned',
        leftFixedTitle: 'Fixed the left',
        rightFixedTitle: 'Fixed the right',
        noFixedTitle: 'Not Fixed',
        reset: 'Reset',
        columnDisplay: 'Column Display',
        columnSetting: 'Settings',
        fullScreen: 'Full Screen',
        exitFullScreen: 'Exit Full Screen',
        reload: 'Refresh',
        density: 'Density',
        densityDefault: 'Default',
        densityLarger: 'Larger',
        densityMiddle: 'Middle',
        densitySmall: 'Compact',
      },
    };
    国际化示例
    zhCNIntl
    indexTitleMoney
    暂无数据
    暂无数据
    国际化相关的配置
    import { PlusOutlined } from '@ant-design/icons';
    import type { ActionType, ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Button, ConfigProvider, Select, Space } from 'antd';
    import caESIntl from 'antd/locale/ca_ES';
    import enGBIntl from 'antd/locale/en_GB';
    import enUSIntl from 'antd/locale/en_US';
    import esESIntl from 'antd/locale/es_ES';
    import frFRIntl from 'antd/locale/fr_FR';
    import itITIntl from 'antd/locale/it_IT';
    import jaJPIntl from 'antd/locale/ja_JP';
    import msMYIntl from 'antd/locale/ms_MY';
    import ptBRIntl from 'antd/locale/pt_BR';
    import ruRUIntl from 'antd/locale/ru_RU';
    import srRSIntl from 'antd/locale/sr_RS';
    import thTHIntl from 'antd/locale/th_TH';
    import viVNIntl from 'antd/locale/vi_VN';
    import zhCNIntl from 'antd/locale/zh_CN';
    import zhTWIntl from 'antd/locale/zh_TW';
    import dayjs from 'dayjs';
    import { useRef, useState } from 'react';
    
    const intlMap = {
      zhCNIntl,
      enUSIntl,
      enGBIntl,
      viVNIntl,
      itITIntl,
      jaJPIntl,
      esESIntl,
      caESIntl,
      ruRUIntl,
      srRSIntl,
      msMYIntl,
      zhTWIntl,
      frFRIntl,
      ptBRIntl,
      thTHIntl,
    };
    
    type GithubIssueItem = {
      key: number;
      name: string;
      createdAt: number;
    };
    
    const columns: ProColumns<GithubIssueItem>[] = [
      {
        title: 'index',
        dataIndex: 'index',
        valueType: 'indexBorder',
      },
      {
        title: 'Title',
        dataIndex: 'name',
      },
      {
        title: 'Money',
        dataIndex: 'title',
        width: 100,
        order: 1,
        valueType: 'money',
        renderText: () => '128000',
      },
    ];
    
    const Demo = () => {
      const actionRef = useRef<ActionType>();
      const [intl, setIntl] = useState('zhCNIntl');
      return (
        <ConfigProvider locale={intlMap[intl as 'zhCNIntl']}>
          <ProTable<GithubIssueItem>
            columns={columns}
            actionRef={actionRef}
            request={async () => {
              return {
                data: [
                  {
                    key: 1,
                    name: '企业版云服务套餐',
                    createdAt: 1705286400000,
                  },
                ],
                total: 1,
                success: true,
              };
            }}
            rowKey="key"
            rowSelection={{}}
            search={{
              labelWidth: 'auto',
            }}
            dateFormatter="string"
            headerTitle={
              <Space>
                <span>国际化示例</span>
                <Select<string>
                  variant="borderless"
                  value={intl}
                  onChange={(value) => {
                    dayjs.locale(intlMap[value as 'zhCNIntl'].locale);
                    setIntl(value);
                  }}
                  options={Object.keys(intlMap).map((value) => ({
                    value,
                    label: value,
                  }))}
                />
              </Space>
            }
            toolBarRender={() => [
              <Button key="new" type="primary">
                <PlusOutlined />
                新建
              </Button>,
            ]}
          />
        </ConfigProvider>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    RTL (النسخة العربية)

    RTL means right-to-left.

    نموذج احترافي
    العنوان
    الحالة
    التسميةالتشغيل
    لا توجد بيانات
    لا توجد بيانات
    import { PlusOutlined } from '@ant-design/icons';
    import type { ActionType, ProColumns } from '@ant-design/pro-components';
    import { ProTable, TableDropdown } from '@ant-design/pro-components';
    import { Button, ConfigProvider, Space, Tag } from 'antd';
    import arEGIntl from 'antd/locale/ar_EG';
    import { useRef } from 'react';
    import request from 'umi-request';
    
    type GithubIssueItem = {
      url: string;
      id: number;
      number: number;
      title: string;
      labels: {
        name: string;
        color: string;
      }[];
      state: string;
      comments: number;
      created_at: string;
      updated_at: string;
      closed_at?: string;
    };
    
    const columns: ProColumns<GithubIssueItem>[] = [
      {
        dataIndex: 'index',
        valueType: 'indexBorder',
        width: 48,
      },
      {
        title: 'العنوان',
        dataIndex: 'title',
        copyable: true,
        ellipsis: true,
        tooltip: 'سيتم تقليص العنوان في حال كان طويل جدًا',
        formItemProps: {
          rules: [
            {
              required: true,
              message: 'هذا الحقل مطلوب',
            },
          ],
        },
        width: '30%',
        search: false,
      },
      {
        title: 'الحالة',
        dataIndex: 'state',
        initialValue: 'open',
        filters: true,
        onFilter: true,
        valueEnum: {
          all: { text: 'الكل', status: 'Default' },
          open: {
            text: 'غير محلولة',
            status: 'Error',
          },
          closed: {
            text: 'تم حلها',
            status: 'Success',
          },
          processing: {
            text: 'نعمل عليها',
            status: 'Processing',
          },
        },
      },
      {
        title: 'التسمية',
        dataIndex: 'labels',
        render: (_, record) => (
          <Space>
            {record.labels.map(({ name, color }) => (
              <Tag color={color} key={name}>
                {name}
              </Tag>
            ))}
          </Space>
        ),
      },
      {
        title: 'التشغيل',
        valueType: 'option',
        render: (text, record, _, action) => [
          <a href={record.url} target="_blank" rel="noopener noreferrer" key="link">
            رابط
          </a>,
          <a href={record.url} target="_blank" rel="noopener noreferrer" key="view">
            查看
          </a>,
          <TableDropdown
            key="actionGroup"
            onSelect={() => action?.reload()}
            menus={[
              { key: 'copy', name: 'نسخ' },
              { key: 'delete', name: 'حذف' },
            ]}
          />,
        ],
      },
    ];
    
    const Demo = () => {
      const actionRef = useRef<ActionType>();
    
      return (
        <ConfigProvider locale={arEGIntl} direction="rtl">
          <ProTable<GithubIssueItem>
            columns={columns}
            actionRef={actionRef}
            request={async (params = {} as Record<string, any>) =>
              request<{
                data: GithubIssueItem[];
              }>('https://proapi.azurewebsites.net/github/issues', {
                params,
              })
            }
            pagination={{
              pageSize: 5,
            }}
            rowKey="id"
            search={{
              labelWidth: 'auto',
            }}
            dateFormatter="string"
            headerTitle="نموذج احترافي"
            toolBarRender={() => [
              <Button key="button" icon={<PlusOutlined />} type="primary">
                جديد
              </Button>,
            ]}
          />
        </ConfigProvider>
      );
    
      <div
        style={{
          marginTop: '20px',
          padding: '20px',
          backgroundColor: '#f5f5f5',
          borderRadius: '6px',
        }}
      >
        <h4>ProTable RTL 表格 Props 说明:</h4>
        <ul>
          <li>
            <strong>ProTable</strong>: 专业表格组件
          </li>
          <li>
            <strong>TableDropdown</strong>: 表格下拉菜单组件
          </li>
          <li>
            <strong>ConfigProvider</strong>: 配置提供者组件
          </li>
          <li>
            <strong>Button</strong>: 按钮组件
          </li>
          <li>
            <strong>Space</strong>: 间距组件
          </li>
          <li>
            <strong>Tag</strong>: 标签组件
          </li>
          <li>
            <strong>RTL表格</strong>: 展示RTL表格功能
          </li>
        </ul>
        <h4>ProTable 配置:</h4>
        <ul>
          <li>
            <strong>columns</strong>: 列配置
          </li>
          <li>
            <strong>actionRef</strong>: 操作引用
          </li>
          <li>
            <strong>request</strong>: 请求函数
          </li>
          <li>
            <strong>pagination</strong>: 分页配置
          </li>
          <li>
            <strong>rowKey</strong>: 行键
          </li>
          <li>
            <strong>search</strong>: 搜索配置
          </li>
          <li>
            <strong>dateFormatter</strong>: 日期格式化
          </li>
          <li>
            <strong>headerTitle</strong>: 表格标题
          </li>
          <li>
            <strong>toolBarRender</strong>: 工具栏渲染
          </li>
        </ul>
        <h4>RTL表格特点:</h4>
        <ul>
          <li>
            <strong>RTL支持</strong>: 支持RTL布局
          </li>
          <li>
            <strong>阿拉伯语</strong>: 支持阿拉伯语
          </li>
          <li>
            <strong>国际化</strong>: 支持国际化
          </li>
          <li>
            <strong>方向控制</strong>: 支持方向控制
          </li>
          <li>
            <strong>本地化</strong>: 支持本地化
          </li>
          <li>
            <strong>多语言</strong>: 支持多语言
          </li>
        </ul>
        <h4>使用场景:</h4>
        <ul>
          <li>
            <strong>阿拉伯语应用</strong>: 阿拉伯语应用需求
          </li>
          <li>
            <strong>RTL布局</strong>: RTL布局需求
          </li>
          <li>
            <strong>国际化系统</strong>: 国际化系统
          </li>
        </ul>
      </div>;
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    主题

    黑色主题 / 紧凑主题
    import { EllipsisOutlined, PlusOutlined } from '@ant-design/icons';
    import type { ActionType, ProColumns } from '@ant-design/pro-components';
    import { ProTable, TableDropdown } from '@ant-design/pro-components';
    import {
      Button,
      ConfigProvider,
      Dropdown,
      message,
      Space,
      Tag,
      theme,
    } from 'antd';
    import { useRef } from 'react';
    import request from 'umi-request';
    
    type GithubIssueItem = {
      url: string;
      id: number;
      number: number;
      title: string;
      labels: {
        name: string;
        color: string;
      }[];
      state: string;
      comments: number;
      created_at: string;
      updated_at: string;
      closed_at?: string;
    };
    
    const columns: ProColumns<GithubIssueItem>[] = [
      {
        dataIndex: 'index',
        valueType: 'indexBorder',
        width: 48,
      },
      {
        title: '标题',
        dataIndex: 'title',
        copyable: true,
        ellipsis: true,
        tooltip: '标题过长会自动收缩',
        formItemProps: {
          rules: [
            {
              required: true,
              message: '此项为必填项',
            },
          ],
        },
      },
      {
        disable: true,
        title: '状态',
        dataIndex: 'state',
        filters: true,
        onFilter: true,
        ellipsis: true,
        valueType: 'select',
        valueEnum: {
          all: { text: '超长'.repeat(50) },
          open: {
            text: '未解决',
            status: 'Error',
          },
          closed: {
            text: '已解决',
            status: 'Success',
            disabled: true,
          },
          processing: {
            text: '解决中',
            status: 'Processing',
          },
        },
      },
      {
        disable: true,
        title: '标签',
        dataIndex: 'labels',
        search: false,
        formItemRender: (_, { defaultRender }) => {
          return defaultRender(_);
        },
        render: (_, record) => (
          <Space>
            {record.labels.map(({ name, color }) => (
              <Tag color={color} key={name}>
                {name}
              </Tag>
            ))}
          </Space>
        ),
      },
      {
        title: '创建时间',
        key: 'showTime',
        dataIndex: 'created_at',
        valueType: 'date',
        sorter: true,
        search: false,
      },
      {
        title: '创建时间',
        dataIndex: 'created_at',
        valueType: 'dateRange',
        hideInTable: true,
        search: {
          transform: (value) => {
            return {
              startTime: value[0],
              endTime: value[1],
            };
          },
        },
      },
      {
        title: '操作',
        valueType: 'option',
        key: 'option',
        render: (text, record, _, action) => [
          <a
            key="editable"
            onClick={() => {
              action?.startEditable?.(record.id);
            }}
          >
            编辑
          </a>,
          <a href={record.url} target="_blank" rel="noopener noreferrer" key="view">
            查看
          </a>,
          <TableDropdown
            key="actionGroup"
            onSelect={() => action?.reload()}
            menus={[
              { key: 'copy', name: '复制' },
              { key: 'delete', name: '删除' },
            ]}
          />,
        ],
      },
    ];
    
    const Demo = () => {
      const actionRef = useRef<ActionType>();
      const themeConfig = {
        token: {
          colorPrimary: 'red',
          borderRadius: 4,
        },
        algorithm: [theme.darkAlgorithm, theme.compactAlgorithm],
      };
      return (
        <div
          style={{
            backgroundColor: 'hsl(218,22%,7%)',
          }}
        >
          <ConfigProvider theme={themeConfig}>
            <ProTable<GithubIssueItem>
              columns={columns}
              actionRef={actionRef}
              cardBordered
              request={async (params) => {
                return request<{
                  data: GithubIssueItem[];
                }>('https://proapi.azurewebsites.net/github/issues', {
                  params,
                });
              }}
              editable={{
                type: 'multiple',
              }}
              columnsState={{
                persistenceKey: 'pro-table-singe-demos',
                persistenceType: 'localStorage',
                onChange: () => {
                  message.info('列设置已更新');
                },
              }}
              rowKey="id"
              search={{
                labelWidth: 'auto',
              }}
              options={{
                setting: {
                  listsHeight: 400,
                },
              }}
              form={{
                // 由于配置了 transform,提交的参数与定义的不同这里需要转化一下
                syncToUrl: (values, type) => {
                  if (type === 'get') {
                    return {
                      ...values,
                      created_at: [values.startTime, values.endTime],
                    };
                  }
                  return values;
                },
              }}
              pagination={{
                pageSize: 5,
                onChange: (page, pageSize) => {
                  message.info(`第 ${page} 页${pageSize ? `,每页 ${pageSize} 条` : ''}`);
                },
              }}
              dateFormatter="string"
              headerTitle="高级表格"
              toolBarRender={() => [
                <Button key="button" icon={<PlusOutlined />} type="primary">
                  新建
                </Button>,
                <Dropdown
                  key="menu"
                  menu={{
                    items: [
                      {
                        label: '1st item',
                        key: '1',
                      },
                      {
                        label: '2nd item',
                        key: '2',
                      },
                      {
                        label: '3rd item',
                        key: '3',
                      },
                    ],
                  }}
                >
                  <Button>
                    <EllipsisOutlined />
                  </Button>
                </Dropdown>,
              ]}
            />
          </ConfigProvider>
        </div>
      );
    
      <div
        style={{
          marginTop: '20px',
          padding: '20px',
          backgroundColor: '#f5f5f5',
          borderRadius: '6px',
        }}
      >
        <h4>ProTable 主题 Props 说明:</h4>
        <ul>
          <li>
            <strong>ProTable</strong>: 专业表格组件
          </li>
          <li>
            <strong>TableDropdown</strong>: 表格下拉菜单组件
          </li>
          <li>
            <strong>ConfigProvider</strong>: 配置提供者组件
          </li>
          <li>
            <strong>Button</strong>: 按钮组件
          </li>
          <li>
            <strong>Dropdown</strong>: 下拉菜单组件
          </li>
          <li>
            <strong>Space</strong>: 间距组件
          </li>
          <li>
            <strong>Tag</strong>: 标签组件
          </li>
          <li>
            <strong>theme</strong>: 主题配置
          </li>
          <li>
            <strong>主题</strong>: 展示主题功能
          </li>
        </ul>
        <h4>ProTable 配置:</h4>
        <ul>
          <li>
            <strong>columns</strong>: 列配置
          </li>
          <li>
            <strong>actionRef</strong>: 操作引用
          </li>
          <li>
            <strong>cardBordered</strong>: 卡片边框
          </li>
          <li>
            <strong>request</strong>: 请求函数
          </li>
          <li>
            <strong>editable</strong>: 可编辑配置
          </li>
          <li>
            <strong>columnsState</strong>: 列状态配置
          </li>
          <li>
            <strong>rowKey</strong>: 行键
          </li>
          <li>
            <strong>search</strong>: 搜索配置
          </li>
          <li>
            <strong>options</strong>: 选项配置
          </li>
          <li>
            <strong>form</strong>: 表单配置
          </li>
          <li>
            <strong>pagination</strong>: 分页配置
          </li>
          <li>
            <strong>dateFormatter</strong>: 日期格式化
          </li>
          <li>
            <strong>headerTitle</strong>: 表格标题
          </li>
          <li>
            <strong>toolBarRender</strong>: 工具栏渲染
          </li>
        </ul>
        <h4>主题特点:</h4>
        <ul>
          <li>
            <strong>暗色主题</strong>: 支持暗色主题
          </li>
          <li>
            <strong>紧凑算法</strong>: 支持紧凑算法
          </li>
          <li>
            <strong>自定义颜色</strong>: 支持自定义颜色
          </li>
          <li>
            <strong>主题配置</strong>: 支持主题配置
          </li>
          <li>
            <strong>算法组合</strong>: 支持算法组合
          </li>
          <li>
            <strong>背景色</strong>: 支持背景色
          </li>
        </ul>
        <h4>使用场景:</h4>
        <ul>
          <li>
            <strong>主题定制</strong>: 主题定制需求
          </li>
          <li>
            <strong>暗色模式</strong>: 暗色模式应用
          </li>
          <li>
            <strong>品牌定制</strong>: 品牌定制需求
          </li>
        </ul>
      </div>;
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    自定义错误边界

    import { EllipsisOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Button, Result, Switch } from 'antd';
    import type { ErrorInfo } from 'react';
    import React, { useState } from 'react';
    
    class CustomBoundary extends React.Component<
      Record<string, any>,
      { hasError: boolean; errorInfo: string }
    > {
      state = { hasError: false, errorInfo: '' };
    
      static getDerivedStateFromError(error: Error) {
        return { hasError: true, errorInfo: error.message };
      }
    
      componentDidCatch(error: any, errorInfo: ErrorInfo) {
        // You can also log the error to an error reporting service
        console.error(error, errorInfo);
      }
    
      render() {
        if (this.state.hasError) {
          // You can render any custom fallback UI
          return (
            <Result
              icon={
                <img
                  width={256}
                  src="https://gw.alipayobjects.com/zos/antfincdn/zIgkN%26mpMZ/shibaizhuangtaizuo.png"
                />
              }
              style={{
                height: '100%',
                background: '#fff',
              }}
              title="错误处理"
              extra={
                <>
                  <div
                    style={{
                      maxWidth: 620,
                      textAlign: 'start',
                      backgroundColor: 'rgba(255,229,100,0.3)',
                      borderInlineStartColor: '#ffe564',
                      borderInlineStartWidth: '9px',
                      borderInlineStartStyle: 'solid',
                      padding: '20px 45px 20px 26px',
                      margin: 'auto',
                      marginBlockEnd: '30px',
                      marginBlockStart: '20px',
                    }}
                  >
                    <p>注意</p>
                    <p>
                      错误边界<strong>无法</strong>捕获以下场景中产生的错误:
                    </p>
                    <ul
                      style={{
                        listStyle: 'none',
                      }}
                    >
                      <li>
                        事件处理(
                        <a href="https://zh-hans.reactjs.org/docs/error-boundaries.html#how-about-event-handlers#how-about-event-handlers">
                          了解更多
                        </a>
                        )
                      </li>
                      <li>
                        异步代码(例如 <code>setTimeout</code> 或{' '}
                        <code>requestAnimationFrame</code> 回调函数)
                      </li>
                      <li>服务端渲染</li>
                      <li>它自身抛出来的错误(并非它的子组件)</li>
                    </ul>
                  </div>
                  <Button
                    danger
                    type="primary"
                    onClick={() => {
                      window.location.reload();
                    }}
                  >
                    刷新页面
                  </Button>
                </>
              }
            />
          );
        }
        return this.props.children;
      }
    }
    
    import { createTableDataSource, DEMO_CREATOR_VALUE_ENUM } from '../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      containers: number;
      creator: string;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 5,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '容器数量',
        dataIndex: 'containers',
        align: 'right',
        sorter: (a, b) => a.containers - b.containers,
      },
      {
        title: '创建者',
        dataIndex: 'creator',
        valueType: 'select',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
      {
        title: '操作',
        key: 'option',
        width: 120,
        valueType: 'option',
        render: () => [
          <a key="link">链路</a>,
          <a key="warn">报警</a>,
          <a key="more">
            <EllipsisOutlined />
          </a>,
        ],
      },
    ];
    
    const ErrorTrigger = () => {
      // default to throw error for snapshot test
      const [error, setError] = useState<boolean>(true);
      if (error) throw new Error('渲染发生了错误');
      return (
        <Button
          danger
          type="primary"
          onClick={() => {
            setError(true);
          }}
        >
          触发错误
        </Button>
      );
    };
    
    const Demo = () => {
      const [custom, setCustom] = useState(true);
      return (
        <>
          <Switch
            checkedChildren="使用自定义错误边界"
            unCheckedChildren="使用默认错误边界"
            checked={custom}
            onChange={(checked) => setCustom(checked)}
          />
          <ProTable<TableListItem>
            columns={columns}
            request={(_params, _sorter, _filter) => {
              // 表单搜索项会从 params 传入,传递给后端接口。
              return Promise.resolve({
                data: tableListDataSource,
                total: tableListDataSource.length,
                success: true,
              });
            }}
            ErrorBoundary={custom ? CustomBoundary : undefined}
            headerTitle={<ErrorTrigger />}
            rowKey="key"
            search={false}
          />
          <div
            style={{
              marginTop: '20px',
              padding: '20px',
              backgroundColor: '#f5f5f5',
              borderRadius: '6px',
            }}
          >
            <h4>ProTable 错误边界 Props 说明:</h4>
            <ul>
              <li>
                <strong>ProTable</strong>: 专业表格组件
              </li>
              <li>
                <strong>Switch</strong>: 开关组件
              </li>
              <li>
                <strong>Result</strong>: 结果组件
              </li>
              <li>
                <strong>Button</strong>: 按钮组件
              </li>
              <li>
                <strong>错误边界</strong>: 展示错误边界功能
              </li>
            </ul>
            <h4>ProTable 配置:</h4>
            <ul>
              <li>
                <strong>columns</strong>: 列配置
              </li>
              <li>
                <strong>request</strong>: 请求函数
              </li>
              <li>
                <strong>ErrorBoundary</strong>: 错误边界配置
              </li>
              <li>
                <strong>headerTitle</strong>: 表格标题
              </li>
              <li>
                <strong>rowKey</strong>: 行键
              </li>
              <li>
                <strong>search</strong>: 搜索配置
              </li>
            </ul>
            <h4>错误边界特点:</h4>
            <ul>
              <li>
                <strong>自定义边界</strong>: 支持自定义错误边界
              </li>
              <li>
                <strong>错误捕获</strong>: 支持错误捕获
              </li>
              <li>
                <strong>错误处理</strong>: 支持错误处理
              </li>
              <li>
                <strong>容错机制</strong>: 支持容错机制
              </li>
              <li>
                <strong>错误展示</strong>: 支持错误展示
              </li>
              <li>
                <strong>错误恢复</strong>: 支持错误恢复
              </li>
            </ul>
            <h4>使用场景:</h4>
            <ul>
              <li>
                <strong>错误处理</strong>: 错误处理需求
              </li>
              <li>
                <strong>稳定性保证</strong>: 稳定性保证
              </li>
              <li>
                <strong>用户体验</strong>: 用户体验优化
              </li>
            </ul>
          </div>
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    取消自定义错误边界
    import { EllipsisOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    
    import { createTableDataSource, DEMO_CREATOR_VALUE_ENUM } from '../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      containers: number;
      creator: string;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 5,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '容器数量',
        dataIndex: 'containers',
        align: 'right',
        sorter: (a, b) => a.containers - b.containers,
      },
      {
        title: '创建者',
        dataIndex: 'creator',
        valueType: 'select',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
      {
        title: '操作',
        key: 'option',
        width: 120,
        valueType: 'option',
        render: () => [
          <a key="link">链路</a>,
          <a key="warn">报警</a>,
          <a key="more">
            <EllipsisOutlined />
          </a>,
        ],
      },
    ];
    
    const Demo = () => {
      return (
        <>
          <ProTable<TableListItem>
            columns={columns}
            request={(params, sorter, filter) => {
              // 表单搜索项会从 params 传入,传递给后端接口。
              console.log(params, sorter, filter);
              return Promise.resolve({
                data: tableListDataSource,
                total: tableListDataSource.length,
                success: true,
              });
            }}
            ErrorBoundary={false}
            rowKey="key"
            search={false}
          />
          <div
            style={{
              marginTop: '20px',
              padding: '20px',
              backgroundColor: '#f5f5f5',
              borderRadius: '6px',
            }}
          >
            <h4>ProTable 错误边界 Props 说明:</h4>
            <ul>
              <li>
                <strong>ProTable</strong>: 专业表格组件
              </li>
              <li>
                <strong>错误边界</strong>: 展示错误边界功能
              </li>
            </ul>
            <h4>ProTable 配置:</h4>
            <ul>
              <li>
                <strong>columns</strong>: 列配置
              </li>
              <li>
                <strong>request</strong>: 请求函数
              </li>
              <li>
                <strong>ErrorBoundary</strong>: 错误边界配置
              </li>
              <li>
                <strong>rowKey</strong>: 行键
              </li>
              <li>
                <strong>search</strong>: 搜索配置
              </li>
            </ul>
            <h4>错误边界特点:</h4>
            <ul>
              <li>
                <strong>错误捕获</strong>: 支持错误捕获
              </li>
              <li>
                <strong>错误处理</strong>: 支持错误处理
              </li>
              <li>
                <strong>容错机制</strong>: 支持容错机制
              </li>
              <li>
                <strong>禁用边界</strong>: 支持禁用错误边界
              </li>
              <li>
                <strong>异常处理</strong>: 支持异常处理
              </li>
            </ul>
            <h4>使用场景:</h4>
            <ul>
              <li>
                <strong>错误处理</strong>: 错误处理需求
              </li>
              <li>
                <strong>稳定性保证</strong>: 稳定性保证
              </li>
              <li>
                <strong>用户体验</strong>: 用户体验优化
              </li>
            </ul>
          </div>
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    高级表格
    序号
    标题
    状态
    标签操作
    暂无数据
    暂无数据
    import { PlusOutlined } from '@ant-design/icons';
    import type { ActionType, ProColumns } from '@ant-design/pro-components';
    import { ProTable, TableDropdown } from '@ant-design/pro-components';
    import { Button, ConfigProvider, Space, Tag } from 'antd';
    import { useRef } from 'react';
    import request from 'umi-request';
    
    type GithubIssueItem = {
      url: string;
      id: number;
      number: number;
      title: string;
      labels: {
        name: string;
        color: string;
      }[];
      state: string;
      comments: number;
      created_at: string;
      updated_at: string;
      closed_at?: string;
    };
    
    const columns: ProColumns<GithubIssueItem>[] = [
      {
        title: '序号',
        dataIndex: 'index',
        valueType: 'indexBorder',
      },
      {
        title: '标题',
        dataIndex: 'title',
        copyable: true,
        ellipsis: true,
        tooltip: '标题过长会自动收缩',
        formItemProps: {
          rules: [
            {
              required: true,
              message: '此项为必填项',
            },
          ],
        },
        width: '30%',
        search: false,
      },
      {
        title: '状态',
        dataIndex: 'state',
        initialValue: 'open',
        filters: true,
        valueType: 'select',
        valueEnum: {
          all: { text: '全部', status: 'Default' },
          open: {
            text: '未解决',
            status: 'Error',
          },
          closed: {
            text: '已解决',
            status: 'Success',
          },
          processing: {
            text: '解决中',
            status: 'Processing',
          },
        },
        width: '10%',
      },
      {
        title: '标签',
        dataIndex: 'labels',
        width: '10%',
        render: (_, row) => (
          <Space>
            {row.labels.map(({ name, color }) => (
              <Tag color={color} key={name}>
                {name}
              </Tag>
            ))}
          </Space>
        ),
      },
      {
        title: '操作',
        valueType: 'option',
        render: (text, row, _, action) => [
          <a href={row.url} target="_blank" rel="noopener noreferrer" key="link">
            链路
          </a>,
          <a href={row.url} target="_blank" rel="noopener noreferrer" key="warning">
            报警
          </a>,
          <a href={row.url} target="_blank" rel="noopener noreferrer" key="view">
            查看
          </a>,
          <TableDropdown
            key="actionGroup"
            onSelect={() => action?.reload()}
            menus={[
              { key: 'copy', name: '复制' },
              { key: 'delete', name: '删除' },
            ]}
          />,
        ],
      },
    ];
    
    const Demo = () => {
      const actionRef = useRef<ActionType>();
    
      return (
        <ConfigProvider prefixCls="qixian">
          <ProTable<GithubIssueItem>
            columns={columns}
            pagination={{
              showQuickJumper: true,
            }}
            actionRef={actionRef}
            request={async (params = {} as Record<string, any>) =>
              request<{
                data: GithubIssueItem[];
              }>('https://proapi.azurewebsites.net/github/issues', {
                params,
              })
            }
            rowKey="id"
            dateFormatter="string"
            headerTitle="高级表格"
            toolBarRender={() => [
              <Button key="3" type="primary">
                <PlusOutlined />
                新建
              </Button>,
            ]}
          />
        </ConfigProvider>
      );
    
      <div
        style={{
          marginTop: '20px',
          padding: '20px',
          backgroundColor: '#f5f5f5',
          borderRadius: '6px',
        }}
      >
        <h4>ProTable ConfigProvider Props 说明:</h4>
        <ul>
          <li>
            <strong>ProTable</strong>: 专业表格组件
          </li>
          <li>
            <strong>TableDropdown</strong>: 表格下拉菜单组件
          </li>
          <li>
            <strong>ConfigProvider</strong>: 配置提供者组件
          </li>
          <li>
            <strong>配置提供者</strong>: 展示配置提供者功能
          </li>
        </ul>
        <h4>ProTable 配置:</h4>
        <ul>
          <li>
            <strong>columns</strong>: 列配置
          </li>
          <li>
            <strong>pagination</strong>: 分页配置
          </li>
          <li>
            <strong>actionRef</strong>: 操作引用
          </li>
          <li>
            <strong>request</strong>: 请求函数
          </li>
          <li>
            <strong>rowKey</strong>: 行键
          </li>
          <li>
            <strong>dateFormatter</strong>: 日期格式化
          </li>
          <li>
            <strong>headerTitle</strong>: 表格标题
          </li>
          <li>
            <strong>toolBarRender</strong>: 工具栏渲染
          </li>
        </ul>
        <h4>配置提供者特点:</h4>
        <ul>
          <li>
            <strong>前缀定制</strong>: 支持前缀定制
          </li>
          <li>
            <strong>全局配置</strong>: 支持全局配置
          </li>
          <li>
            <strong>主题定制</strong>: 支持主题定制
          </li>
          <li>
            <strong>国际化</strong>: 支持国际化配置
          </li>
          <li>
            <strong>样式隔离</strong>: 支持样式隔离
          </li>
        </ul>
        <h4>使用场景:</h4>
        <ul>
          <li>
            <strong>多套主题</strong>: 多套主题系统
          </li>
          <li>
            <strong>样式隔离</strong>: 样式隔离需求
          </li>
          <li>
            <strong>全局配置</strong>: 全局配置管理
          </li>
        </ul>
      </div>;
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    col without dataIndexnormal col
    1
    • 第 1-1 条/总共 1 条
    • 1
    高级表格
    标题
    序号状态标签创建时间创建时间操作
    🐛 [BUG]yarn install命令 antd2.4.5会报错
    1
    未解决
    bug
    2020-05-262020-05-26T09:42:56Z
    🐛 [BUG]无法创建工程npm create umi
    2
    未解决
    bug
    2020-05-262020-05-26T08:19:22Z
    🧐 [问题] build 后还存在 es6 的代码(Umi@2.13.13)
    3
    未解决
    question
    2020-05-262020-05-26T07:54:25Z
    • 第 1-3 条/总共 3 条
    • 1
    import { PlusOutlined } from '@ant-design/icons';
    import type { ActionType, ProColumns } from '@ant-design/pro-components';
    import { ProTable, TableDropdown } from '@ant-design/pro-components';
    import { Button, ConfigProvider, Input, Space, Tag } from 'antd';
    import { useRef } from 'react';
    
    type GithubIssueItem = {
      url: string;
      id: number;
      number: number;
      title: string;
      labels: {
        name: string;
        color: string;
      }[];
      state: string;
      comments: number;
      created_at: string;
      updated_at: string;
      closed_at?: string;
    };
    
    const nestedColumns = [
      {
        title: 'col without dataIndex',
        key: 'expand',
      },
      {
        title: 'normal col',
        dataIndex: 'key',
      },
    ];
    
    const nestedData = [
      {
        key: 1,
        children: [
          {
            key: 11,
          },
        ],
      },
    ];
    
    const columns: ProColumns<GithubIssueItem>[] = [
      {
        title: '序号',
        dataIndex: 'index',
        valueType: 'indexBorder',
      },
      {
        title: '标题',
        dataIndex: 'title',
        fixed: 'left',
        order: 1,
        copyable: true,
        ellipsis: true,
        hideInForm: true,
        tooltip: '标题过长会自动收缩',
        formItemProps: {
          rules: [
            {
              required: true,
              message: '此项为必填项',
            },
          ],
        },
        width: '30%',
      },
      {
        title: '状态',
        dataIndex: 'state',
        initialValue: 'all',
        copyable: true,
        ellipsis: true,
        onFilter: true,
        valueType: 'select',
        order: 2,
        fieldProps: {
          noStyle: true,
        },
        valueEnum: {
          all: { text: '全部', status: 'Default' },
          open: {
            text: '未解决',
            status: 'Error',
          },
          closed: {
            text: '已解决',
            status: 'Success',
          },
          processing: {
            text: '解决中',
            status: 'Processing',
          },
        },
        width: '10%',
      },
      {
        title: '动态表单',
        key: 'direction',
        hideInTable: true,
        dataIndex: 'direction',
        formItemProps: {
          noStyle: true,
        },
        ignoreFormItem: true,
        formItemRender: () => {
          return <Input />;
        },
      },
      {
        title: '标签',
        dataIndex: 'labels',
        width: '10%',
        order: -1,
        colSize: 1.5,
        formItemProps: {
          noStyle: true,
        },
        formItemRender: (_, { defaultRender }) => defaultRender(_),
        render: (_, record) => (
          <Space>
            {record.labels.map(({ name, color }) => (
              <Tag color={color} key={name}>
                {name}
              </Tag>
            ))}
          </Space>
        ),
      },
      {
        title: '创建时间',
        key: 'since',
        dataIndex: 'created_at',
        valueType: 'date',
        width: '20%',
        copyable: true,
        ellipsis: true,
        render: (value) => {
          return {
            children: value,
            props: { colSpan: 2 },
          };
        },
      },
      {
        title: '创建时间',
        key: 'since',
        dataIndex: 'created_at',
        // @ts-ignore
        valueType: () => undefined,
        width: '20%',
      },
      {
        title: '操作',
        valueType: 'option',
        fixed: 'right',
        render: (text, record, _, action) => [
          <a href={record.url} target="_blank" rel="noopener noreferrer" key="view">
            查看
          </a>,
          <TableDropdown
            key="actionGroup"
            onSelect={() => action?.reload()}
            menus={[
              { key: 'copy', name: '复制' },
              { key: 'delete', name: '删除' },
            ]}
          />,
        ],
      },
    ];
    
    const Demo = () => {
      const actionRef = useRef<ActionType>();
      const staticTableActionRef = useRef<ActionType>();
    
      return (
        <ConfigProvider prefixCls="canvas">
          <ProTable<GithubIssueItem>
            columns={columns}
            pagination={{
              showQuickJumper: true,
            }}
            actionRef={actionRef}
            request={async () => ({
              data: [],
            })}
            type="form"
            rowKey="id"
            dateFormatter="string"
            headerTitle="高级表格"
            toolBarRender={() => [
              <Button key="3" type="primary">
                <PlusOutlined />
                新建
              </Button>,
            ]}
          />
          <ProTable columns={nestedColumns} dataSource={nestedData} />
          <ProTable<GithubIssueItem>
            columns={columns}
            actionRef={staticTableActionRef}
            dataSource={[
              {
                id: 624748504,
                number: 6689,
                title: '🐛 [BUG]yarn install命令 antd2.4.5会报错',
                labels: [{ name: 'bug', color: 'error' }],
                state: 'open',
                comments: 1,
                created_at: '2020-05-26T09:42:56Z',
                updated_at: '2020-05-26T10:03:02Z',
                url: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
              },
              {
                id: 624691229,
                number: 6688,
                title: '🐛 [BUG]无法创建工程npm create umi',
                labels: [{ name: 'bug', color: 'error' }],
                state: 'open',
                comments: 0,
                created_at: '2020-05-26T08:19:22Z',
                updated_at: '2020-05-26T08:19:22Z',
                url: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
              },
              {
                id: 624674790,
                number: 6685,
                title: '🧐 [问题] build 后还存在 es6 的代码(Umi@2.13.13)',
                labels: [{ name: 'question', color: 'success' }],
                state: 'open',
                comments: 0,
                created_at: '2020-05-26T07:54:25Z',
                updated_at: '2020-05-26T07:54:25Z',
                url: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png',
              },
            ]}
            pagination={{
              pageSize: 5,
            }}
            rowKey="id"
            dateFormatter="string"
            headerTitle="高级表格"
            toolBarRender={() => [
              <Button key="3" type="primary">
                <PlusOutlined />
                新建
              </Button>,
            ]}
          />
        </ConfigProvider>
      );
    
      <div
        style={{
          marginTop: '20px',
          padding: '20px',
          backgroundColor: '#f5f5f5',
          borderRadius: '6px',
        }}
      >
        <h4>ProTable 单表格测试 Props 说明:</h4>
        <ul>
          <li>
            <strong>ProTable</strong>: 专业表格组件
          </li>
          <li>
            <strong>TableDropdown</strong>: 表格下拉菜单组件
          </li>
          <li>
            <strong>ConfigProvider</strong>: 配置提供者组件
          </li>
          <li>
            <strong>Button</strong>: 按钮组件
          </li>
          <li>
            <strong>Input</strong>: 输入框组件
          </li>
          <li>
            <strong>Space</strong>: 间距组件
          </li>
          <li>
            <strong>Tag</strong>: 标签组件
          </li>
          <li>
            <strong>单表格测试</strong>: 展示单表格测试功能
          </li>
        </ul>
        <h4>ProTable 配置:</h4>
        <ul>
          <li>
            <strong>columns</strong>: 列配置
          </li>
          <li>
            <strong>pagination</strong>: 分页配置
          </li>
          <li>
            <strong>actionRef</strong>: 操作引用
          </li>
          <li>
            <strong>request</strong>: 请求函数
          </li>
          <li>
            <strong>type</strong>: 表格类型
          </li>
          <li>
            <strong>rowKey</strong>: 行键
          </li>
          <li>
            <strong>dateFormatter</strong>: 日期格式化
          </li>
          <li>
            <strong>headerTitle</strong>: 表格标题
          </li>
          <li>
            <strong>toolBarRender</strong>: 工具栏渲染
          </li>
          <li>
            <strong>dataSource</strong>: 数据源
          </li>
        </ul>
        <h4>单表格测试特点:</h4>
        <ul>
          <li>
            <strong>表单模式</strong>: 支持表单模式
          </li>
          <li>
            <strong>嵌套表格</strong>: 支持嵌套表格
          </li>
          <li>
            <strong>静态数据</strong>: 支持静态数据
          </li>
          <li>
            <strong>动态表单</strong>: 支持动态表单
          </li>
          <li>
            <strong>固定列</strong>: 支持固定列
          </li>
          <li>
            <strong>自定义渲染</strong>: 支持自定义渲染
          </li>
        </ul>
        <h4>使用场景:</h4>
        <ul>
          <li>
            <strong>测试验证</strong>: 测试验证需求
          </li>
          <li>
            <strong>复杂表单</strong>: 复杂表单功能
          </li>
          <li>
            <strong>开发调试</strong>: 开发调试工具
          </li>
        </ul>
      </div>;
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    其它示例

    列状态受控与动态列、自定义列设置图标、基于 search 配置的内容类搜索项(contentWords)等。

    动态列状态
    排序停机信息
    应用名称
    状态部署时间备注
    暂无数据
    暂无数据
    列状态 columnsState
    import { QuestionCircleOutlined, SearchOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    import { Input, Tooltip } from 'antd';
    import { useState } from 'react';
    
    import {
      DEMO_APP_NAMES,
      DEMO_CREATORS,
      FIXED_BASE_TIMESTAMP,
    } from '../mockData';
    
    const valueEnum: Record<string, string> = {
      0: 'close',
      1: 'running',
    };
    
    export type TableListItem = {
      key: number;
      name: string;
      containers: number;
      creator: string;
      status: string;
      createdAt: number;
      progress: number;
      money: number;
      memo: string;
      statusText: string;
    };
    
    const tableListDataSource: TableListItem[] = Array.from(
      { length: 5 },
      (_, i) => ({
        key: i,
        name: DEMO_APP_NAMES[i % DEMO_APP_NAMES.length],
        containers: ((i * 3 + 2) % 12) + 1,
        creator: DEMO_CREATORS[i % DEMO_CREATORS.length],
        status: valueEnum[String(i % 2)],
        createdAt: FIXED_BASE_TIMESTAMP - i * 86400000,
        money: ((i * 3456 + 7890) % 50000) * 100,
        progress: ((i * 17 + 23) % 100) + 1,
        memo:
          i % 2 === 1
            ? '核心服务,承载全站用户登录与鉴权,高峰期需要关注性能指标'
            : '日常运维中,当前运行状态正常',
        statusText: i % 2 === 0 ? '已关闭,等待重新部署' : '运行中,CPU 占用 35%',
      }),
    );
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
        filterDropdown: () => (
          <div style={{ padding: 8 }}>
            <Input style={{ width: 188, marginBottom: 8, display: 'block' }} />
          </div>
        ),
        filterIcon: (filtered) => (
          <SearchOutlined style={{ color: filtered ? '#1890ff' : undefined }} />
        ),
      },
      {
        title: '状态',
        dataIndex: 'status',
        initialValue: 'close',
        valueType: 'radioButton',
        valueEnum: {
          close: { text: '已关闭', status: 'Default' },
          running: { text: '运行中', status: 'Processing' },
        },
      },
      {
        title: (
          <>
            部署时间
            <Tooltip placement="top" title="最近一次部署的时间">
              <QuestionCircleOutlined style={{ marginLeft: 4 }} />
            </Tooltip>
          </>
        ),
        width: 140,
        key: 'since',
        dataIndex: 'createdAt',
        valueType: 'date',
      },
      {
        title: '备注',
        dataIndex: 'memo',
        ellipsis: true,
        copyable: true,
      },
    ];
    
    const Demo = () => {
      const [currentStatus, setCurrentStatus] = useState<string>('close');
    
      const closeColumns: ProColumns<TableListItem>[] = [
        {
          title: '排序',
          dataIndex: 'index',
          valueType: 'indexBorder',
          width: 48,
        },
        {
          title: '停机信息',
          dataIndex: 'statusText',
        },
        ...columns,
      ];
    
      const runningColumns: ProColumns<TableListItem>[] = [
        {
          title: '排序',
          dataIndex: 'index',
          valueType: 'indexBorder',
          width: 48,
        },
        {
          title: '运行信息',
          dataIndex: 'statusText',
        },
        ...columns,
      ];
      return (
        <ProTable<TableListItem>
          columns={currentStatus === 'close' ? closeColumns : runningColumns}
          request={() => {
            return Promise.resolve({
              data: tableListDataSource,
              total: tableListDataSource.length,
              success: true,
            });
          }}
          rowKey="key"
          search={{
            layout: 'vertical',
            defaultCollapsed: false,
          }}
          onSubmit={({ status }) => {
            setCurrentStatus(status);
          }}
          columnsState={{
            persistenceKey: `table_dynamic_status_${currentStatus}`,
            persistenceType: 'sessionStorage',
          }}
          dateFormatter="string"
          toolbar={{
            title: '动态列状态',
            tooltip: '根据状态切换动态显示不同列',
          }}
        />
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    User First NameUser Last NameID
    暂无数据
    暂无数据
    自定义列设置图标
    import type { ProColumns } from '@ant-design/pro-components';
    import { ProTable } from '@ant-design/pro-components';
    
    const HeartSvg = () => (
      <svg width="1em" height="1em" fill="currentColor" viewBox="0 0 1024 1024">
        <path d="M923 283.6c-13.4-31.1-32.6-58.9-56.9-82.8-24.3-23.8-52.5-42.4-84-55.5-32.5-13.5-66.9-20.3-102.4-20.3-49.3 0-97.4 13.5-139.2 39-10 6.1-19.5 12.8-28.5 20.1-9-7.3-18.5-14-28.5-20.1-41.8-25.5-89.9-39-139.2-39-35.5 0-69.9 6.8-102.4 20.3-31.4 13-59.7 31.7-84 55.5-24.4 23.9-43.5 51.7-56.9 82.8-13.9 32.3-21 66.6-21 101.9 0 33.3 6.8 68 20.3 103.3 11.3 29.5 27.5 60.1 48.2 91 32.8 48.9 77.9 99.9 133.9 151.6 92.8 85.7 184.7 144.9 188.6 147.3l23.7 15.2c10.5 6.7 24 6.7 34.5 0l23.7-15.2c3.9-2.5 95.7-61.6 188.6-147.3 56-51.7 101.1-102.7 133.9-151.6 20.7-30.9 37-61.5 48.2-91 13.5-35.3 20.3-70 20.3-103.3 0.1-35.3-7-69.6-20.9-101.9z" />
      </svg>
    );
    
    export type TableListItem = {
      id: number;
      name: string;
      lastName: string;
    };
    const tableListDataSource: TableListItem[] = [];
    
    for (let i = 0; i < 2; i += 1) {
      tableListDataSource.push({
        id: i,
        name: `John ${i}`,
        lastName: `Doe ${i}`,
      });
    }
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: 'User First Name',
        dataIndex: 'name',
      },
      {
        title: 'User Last Name',
        dataIndex: 'surname',
      },
      {
        title: 'ID',
        dataIndex: 'id',
      },
    ];
    
    const Demo = () => {
      return (
        <ProTable<TableListItem>
          columns={columns}
          request={() => Promise.resolve(tableListDataSource)}
          options={{
            search: true,
            setting: {
              children: <HeartSvg />,
            },
          }}
          rowKey="id"
          search={false}
        />
      );
    
      <div
        style={{
          marginTop: '20px',
          padding: '20px',
          backgroundColor: '#f5f5f5',
          borderRadius: '6px',
        }}
      >
        <h4>ProTable 列设置自定义图标 Props 说明:</h4>
        <ul>
          <li>
            <strong>ProTable</strong>: 专业表格组件
          </li>
          <li>
            <strong>列设置自定义图标</strong>: 展示列设置自定义图标功能
          </li>
        </ul>
        <h4>ProTable 配置:</h4>
        <ul>
          <li>
            <strong>columns</strong>: 列配置
          </li>
          <li>
            <strong>request</strong>: 请求函数
          </li>
          <li>
            <strong>options</strong>: 选项配置
          </li>
          <li>
            <strong>rowKey</strong>: 行键
          </li>
          <li>
            <strong>search</strong>: 搜索配置
          </li>
        </ul>
        <h4>列设置自定义图标特点:</h4>
        <ul>
          <li>
            <strong>自定义图标</strong>: 支持自定义图标
          </li>
          <li>
            <strong>列设置</strong>: 支持列设置功能
          </li>
          <li>
            <strong>搜索功能</strong>: 支持搜索功能
          </li>
          <li>
            <strong>SVG图标</strong>: 支持SVG图标
          </li>
        </ul>
        <h4>使用场景:</h4>
        <ul>
          <li>
            <strong>界面定制</strong>: 界面定制需求
          </li>
          <li>
            <strong>用户体验</strong>: 用户体验优化
          </li>
          <li>
            <strong>品牌展示</strong>: 品牌展示需求
          </li>
        </ul>
      </div>;
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    问题标注
    暂无数据
    暂无数据
    内容类查询项
    import { ProColumns, ProTable } from '@ant-design/pro-components';
    
    type ContentWordsItem = {
      id: string;
      problemCause: string;
    };
    
    const getData = () => {
      const arr = Array.from({ length: 100 }).map((_, idx) => ({
        id: (idx + 1).toString(),
        problemCause: 'problemCause',
      }));
      return arr;
    };
    
    const Demo = () => {
      const columns: ProColumns<ContentWordsItem>[] = [
        {
          disable: true,
          title: '问题标注',
          dataIndex: 'problemCause',
          editable: false,
          onFilter: false,
          ellipsis: true,
          search: true,
          valueType: 'select',
          width: 180,
        },
      ];
    
      return (
        <div>
          <ProTable<ContentWordsItem>
            rowKey="id"
            columns={columns}
            request={async () => {
              const data = getData();
              return {
                data: data,
                total: data.length,
                success: true,
              };
            }}
          />
        </div>
      );
    
      <div
        style={{
          marginTop: '20px',
          padding: '20px',
          backgroundColor: '#f5f5f5',
          borderRadius: '6px',
        }}
      >
        <h4>ProTable 内容词项 Props 说明:</h4>
        <ul>
          <li>
            <strong>ProTable</strong>: 专业表格组件
          </li>
          <li>
            <strong>内容词项</strong>: 展示内容词项功能
          </li>
        </ul>
        <h4>ProTable 配置:</h4>
        <ul>
          <li>
            <strong>rowKey</strong>: 行键
          </li>
          <li>
            <strong>columns</strong>: 列配置
          </li>
          <li>
            <strong>request</strong>: 请求函数
          </li>
        </ul>
        <h4>列配置特点:</h4>
        <ul>
          <li>
            <strong>disable</strong>: 禁用状态
          </li>
          <li>
            <strong>title</strong>: 列标题
          </li>
          <li>
            <strong>dataIndex</strong>: 数据索引
          </li>
          <li>
            <strong>editable</strong>: 可编辑状态
          </li>
          <li>
            <strong>onFilter</strong>: 过滤功能
          </li>
          <li>
            <strong>ellipsis</strong>: 省略号显示
          </li>
          <li>
            <strong>search</strong>: 搜索功能
          </li>
          <li>
            <strong>valueType</strong>: 值类型
          </li>
          <li>
            <strong>width</strong>: 列宽度
          </li>
        </ul>
        <h4>使用场景:</h4>
        <ul>
          <li>
            <strong>内容管理</strong>: 内容管理系统
          </li>
          <li>
            <strong>词汇标注</strong>: 词汇标注功能
          </li>
          <li>
            <strong>数据展示</strong>: 数据展示需求
          </li>
        </ul>
      </div>;
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    列表工具栏

    用于自定义表格的工具栏部分。

    代码演示

    这里是标题
    这里是子标题
    应用名称
    容器数量
    创建者操作
    暂无数据
    暂无数据

    ProTable 基础工具栏 Props 说明:

    • ProTable: 专业表格组件
    • LightFilter: 轻量过滤器组件
    • ProFormDatePicker: 专业表单日期选择器组件
    • 基础工具栏: 展示基础工具栏功能

    ProTable 配置:

    • columns: 列配置
    • request: 请求函数
    • toolbar: 工具栏配置
    • rowKey: 行键
    • search: 搜索配置

    基础工具栏特点:

    • 标题和子标题: 支持标题和子标题
    • 搜索功能: 支持搜索功能
    • 过滤器: 支持过滤器
    • 操作按钮: 支持操作按钮
    • 设置选项: 支持设置选项

    使用场景:

    • 数据管理: 数据管理系统
    • 列表展示: 列表展示功能
    • 操作工具: 操作工具集合
    列表工具栏-基本使用
    import {
      EllipsisOutlined,
      FullscreenOutlined,
      SettingOutlined,
    } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import {
      LightFilter,
      ProFormDatePicker,
      ProTable,
    } from '@ant-design/pro-components';
    import { Button } from 'antd';
    
    import { createTableDataSource } from '../../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      containers: number;
      creator: string;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 5,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '容器数量',
        dataIndex: 'containers',
        align: 'right',
        sorter: (a, b) => a.containers - b.containers,
      },
      {
        title: '创建者',
        dataIndex: 'creator',
        valueEnum: {
          all: { text: '全部' },
          书琰: { text: '书琰' },
          逄一: { text: '逄一' },
          期贤: { text: '期贤' },
          玄霜: { text: '玄霜' },
          怀渊: { text: '怀渊' },
        },
      },
      {
        title: '操作',
        key: 'option',
        width: 120,
        valueType: 'option',
        render: () => [
          <a key="link">链路</a>,
          <a key="warn">报警</a>,
          <a key="more">
            <EllipsisOutlined />
          </a>,
        ],
      },
    ];
    
    const Demo = () => {
      return (
        <>
          <ProTable<TableListItem>
            columns={columns}
            request={(params, sorter, filter) => {
              // 表单搜索项会从 params 传入,传递给后端接口。
              console.log(params, sorter, filter);
              return Promise.resolve({
                data: tableListDataSource,
                total: tableListDataSource.length,
                success: true,
              });
            }}
            toolbar={{
              title: '这里是标题',
              subTitle: '这里是子标题',
              tooltip: '这是一个段描述',
              search: {
                onSearch: (value: string) => {
                  alert(value);
                },
              },
              filter: (
                <LightFilter>
                  <ProFormDatePicker name="startdate" label="响应日期" />
                </LightFilter>
              ),
              actions: [
                <Button
                  key="key"
                  type="primary"
                  onClick={() => {
                    alert('add');
                  }}
                >
                  添加
                </Button>,
              ],
              settings: [
                {
                  icon: <SettingOutlined />,
                  tooltip: '设置',
                },
                {
                  icon: <FullscreenOutlined />,
                  tooltip: '全屏',
                },
              ],
            }}
            rowKey="key"
            search={false}
          />
          <div
            style={{
              marginTop: '20px',
              padding: '20px',
              backgroundColor: '#f5f5f5',
              borderRadius: '6px',
            }}
          >
            <h4>ProTable 基础工具栏 Props 说明:</h4>
            <ul>
              <li>
                <strong>ProTable</strong>: 专业表格组件
              </li>
              <li>
                <strong>LightFilter</strong>: 轻量过滤器组件
              </li>
              <li>
                <strong>ProFormDatePicker</strong>: 专业表单日期选择器组件
              </li>
              <li>
                <strong>基础工具栏</strong>: 展示基础工具栏功能
              </li>
            </ul>
            <h4>ProTable 配置:</h4>
            <ul>
              <li>
                <strong>columns</strong>: 列配置
              </li>
              <li>
                <strong>request</strong>: 请求函数
              </li>
              <li>
                <strong>toolbar</strong>: 工具栏配置
              </li>
              <li>
                <strong>rowKey</strong>: 行键
              </li>
              <li>
                <strong>search</strong>: 搜索配置
              </li>
            </ul>
            <h4>基础工具栏特点:</h4>
            <ul>
              <li>
                <strong>标题和子标题</strong>: 支持标题和子标题
              </li>
              <li>
                <strong>搜索功能</strong>: 支持搜索功能
              </li>
              <li>
                <strong>过滤器</strong>: 支持过滤器
              </li>
              <li>
                <strong>操作按钮</strong>: 支持操作按钮
              </li>
              <li>
                <strong>设置选项</strong>: 支持设置选项
              </li>
            </ul>
            <h4>使用场景:</h4>
            <ul>
              <li>
                <strong>数据管理</strong>: 数据管理系统
              </li>
              <li>
                <strong>列表展示</strong>: 列表展示功能
              </li>
              <li>
                <strong>操作工具</strong>: 操作工具集合
              </li>
            </ul>
          </div>
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    应用名称
    容器数量
    创建者操作
    暂无数据
    暂无数据

    ProTable 无标题工具栏 Props 说明:

    • ProTable: 专业表格组件
    • LightFilter: 轻量过滤器组件
    • ProFormDatePicker: 专业表单日期选择器组件
    • 无标题工具栏: 展示无标题工具栏功能

    ProTable 配置:

    • columns: 列配置
    • request: 请求函数
    • toolbar: 工具栏配置
    • rowKey: 行键
    • search: 搜索配置

    无标题工具栏特点:

    • 简洁布局: 简洁的布局设计
    • 搜索功能: 支持搜索功能
    • 过滤器: 支持过滤器
    • 操作按钮: 支持操作按钮
    • 无标题: 无标题显示

    使用场景:

    • 简洁界面: 简洁界面需求
    • 嵌入式表格: 嵌入式表格展示
    • 空间节省: 空间节省需求
    无标题
    import { EllipsisOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import {
      LightFilter,
      ProFormDatePicker,
      ProTable,
    } from '@ant-design/pro-components';
    import { Button } from 'antd';
    
    import { createTableDataSource, DEMO_CREATOR_VALUE_ENUM } from '../../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      containers: number;
      creator: string;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 5,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '容器数量',
        dataIndex: 'containers',
        align: 'right',
        sorter: (a, b) => a.containers - b.containers,
      },
      {
        title: '创建者',
        dataIndex: 'creator',
        valueType: 'select',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
      {
        title: '操作',
        key: 'option',
        width: 120,
        valueType: 'option',
        render: () => [
          <a key="link">链路</a>,
          <a key="warn">报警</a>,
          <a key="more">
            <EllipsisOutlined />
          </a>,
        ],
      },
    ];
    
    const Demo = () => {
      return (
        <>
          <ProTable<TableListItem>
            columns={columns}
            request={(params, sorter, filter) => {
              // 表单搜索项会从 params 传入,传递给后端接口。
              console.log(params, sorter, filter);
              return Promise.resolve({
                data: tableListDataSource,
                total: tableListDataSource.length,
                success: true,
              });
            }}
            toolbar={{
              search: {
                onSearch: (value: string) => {
                  alert(value);
                },
              },
              filter: (
                <LightFilter>
                  <ProFormDatePicker name="startdate" label="响应日期" />
                </LightFilter>
              ),
              actions: [
                <Button
                  key="primary"
                  type="primary"
                  onClick={() => {
                    alert('add');
                  }}
                >
                  添加
                </Button>,
              ],
            }}
            rowKey="key"
            search={false}
          />
          <div
            style={{
              marginTop: '20px',
              padding: '20px',
              backgroundColor: '#f5f5f5',
              borderRadius: '6px',
            }}
          >
            <h4>ProTable 无标题工具栏 Props 说明:</h4>
            <ul>
              <li>
                <strong>ProTable</strong>: 专业表格组件
              </li>
              <li>
                <strong>LightFilter</strong>: 轻量过滤器组件
              </li>
              <li>
                <strong>ProFormDatePicker</strong>: 专业表单日期选择器组件
              </li>
              <li>
                <strong>无标题工具栏</strong>: 展示无标题工具栏功能
              </li>
            </ul>
            <h4>ProTable 配置:</h4>
            <ul>
              <li>
                <strong>columns</strong>: 列配置
              </li>
              <li>
                <strong>request</strong>: 请求函数
              </li>
              <li>
                <strong>toolbar</strong>: 工具栏配置
              </li>
              <li>
                <strong>rowKey</strong>: 行键
              </li>
              <li>
                <strong>search</strong>: 搜索配置
              </li>
            </ul>
            <h4>无标题工具栏特点:</h4>
            <ul>
              <li>
                <strong>简洁布局</strong>: 简洁的布局设计
              </li>
              <li>
                <strong>搜索功能</strong>: 支持搜索功能
              </li>
              <li>
                <strong>过滤器</strong>: 支持过滤器
              </li>
              <li>
                <strong>操作按钮</strong>: 支持操作按钮
              </li>
              <li>
                <strong>无标题</strong>: 无标题显示
              </li>
            </ul>
            <h4>使用场景:</h4>
            <ul>
              <li>
                <strong>简洁界面</strong>: 简洁界面需求
              </li>
              <li>
                <strong>嵌入式表格</strong>: 嵌入式表格展示
              </li>
              <li>
                <strong>空间节省</strong>: 空间节省需求
              </li>
            </ul>
          </div>
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    两行的情况
    应用名称
    容器数量
    创建者操作
    暂无数据
    暂无数据
    );

    ProTable 多行工具栏 Props 说明:

    • ProTable: 专业表格组件
    • LightFilter: 轻量过滤器组件
    • ProFormDatePicker: 专业表单日期选择器组件
    • Dropdown: 下拉菜单组件
    • 多行工具栏: 展示多行工具栏功能

    ProTable 配置:

    • columns: 列配置
    • request: 请求函数
    • headerTitle: 表格标题
    • toolbar: 工具栏配置
    • rowKey: 行键
    • search: 搜索配置

    多行工具栏特点:

    • 多行布局: 支持多行布局
    • 搜索功能: 支持搜索功能
    • 过滤器: 支持过滤器
    • 下拉菜单: 支持下拉菜单
    • 操作按钮: 支持操作按钮

    使用场景:

    • 复杂操作: 复杂操作需求
    • 空间利用: 空间利用优化
    • 功能丰富: 功能丰富的表格
    双行布局
    import { DownOutlined, EllipsisOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import {
      LightFilter,
      ProFormDatePicker,
      ProTable,
    } from '@ant-design/pro-components';
    import { Button, Dropdown } from 'antd';
    
    import { createTableDataSource, DEMO_CREATOR_VALUE_ENUM } from '../../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      containers: number;
      creator: string;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 5,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '容器数量',
        dataIndex: 'containers',
        align: 'right',
        sorter: (a, b) => a.containers - b.containers,
      },
      {
        title: '创建者',
        dataIndex: 'creator',
        valueType: 'select',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
      {
        title: '操作',
        key: 'option',
        valueType: 'option',
        width: 120,
        render: () => [
          <a key="link">链路</a>,
          <a key="warn">报警</a>,
          <a key="more">
            <EllipsisOutlined />
          </a>,
        ],
      },
    ];
    
    const Demo = () => {
      return (
        <>
          <ProTable<TableListItem>
            columns={columns}
            request={(params, sorter, filter) => {
              // 表单搜索项会从 params 传入,传递给后端接口。
              console.log(params, sorter, filter);
              return Promise.resolve({
                data: tableListDataSource,
                total: tableListDataSource.length,
                success: true,
              });
            }}
            headerTitle="两行的情况"
            toolbar={{
              multipleLine: true,
              search: {
                onSearch: (value: string) => {
                  alert(value);
                },
              },
              filter: (
                <LightFilter>
                  <ProFormDatePicker name="startdate" label="响应日期" />
                </LightFilter>
              ),
              actions: [
                <Dropdown
                  key="overlay"
                  menu={{
                    items: [
                      {
                        label: '菜单',
                        key: '1',
                      },
                      {
                        label: '列表',
                        key: '2',
                      },
                      {
                        label: '表单',
                        key: '3',
                      },
                    ],
                    onClick: () => alert('menu click'),
                  }}
                >
                  <Button>
                    移动自
                    <DownOutlined
                      style={{
                        marginInlineStart: 8,
                      }}
                    />
                  </Button>
                </Dropdown>,
                <Button
                  key="add"
                  type="primary"
                  onClick={() => {
                    alert('add');
                  }}
                >
                  添加
                </Button>,
              ],
            }}
            rowKey="key"
            search={false}
          />
          );
          <div
            style={{
              marginTop: '20px',
              padding: '20px',
              backgroundColor: '#f5f5f5',
              borderRadius: '6px',
            }}
          >
            <h4>ProTable 多行工具栏 Props 说明:</h4>
            <ul>
              <li>
                <strong>ProTable</strong>: 专业表格组件
              </li>
              <li>
                <strong>LightFilter</strong>: 轻量过滤器组件
              </li>
              <li>
                <strong>ProFormDatePicker</strong>: 专业表单日期选择器组件
              </li>
              <li>
                <strong>Dropdown</strong>: 下拉菜单组件
              </li>
              <li>
                <strong>多行工具栏</strong>: 展示多行工具栏功能
              </li>
            </ul>
            <h4>ProTable 配置:</h4>
            <ul>
              <li>
                <strong>columns</strong>: 列配置
              </li>
              <li>
                <strong>request</strong>: 请求函数
              </li>
              <li>
                <strong>headerTitle</strong>: 表格标题
              </li>
              <li>
                <strong>toolbar</strong>: 工具栏配置
              </li>
              <li>
                <strong>rowKey</strong>: 行键
              </li>
              <li>
                <strong>search</strong>: 搜索配置
              </li>
            </ul>
            <h4>多行工具栏特点:</h4>
            <ul>
              <li>
                <strong>多行布局</strong>: 支持多行布局
              </li>
              <li>
                <strong>搜索功能</strong>: 支持搜索功能
              </li>
              <li>
                <strong>过滤器</strong>: 支持过滤器
              </li>
              <li>
                <strong>下拉菜单</strong>: 支持下拉菜单
              </li>
              <li>
                <strong>操作按钮</strong>: 支持操作按钮
              </li>
            </ul>
            <h4>使用场景:</h4>
            <ul>
              <li>
                <strong>复杂操作</strong>: 复杂操作需求
              </li>
              <li>
                <strong>空间利用</strong>: 空间利用优化
              </li>
              <li>
                <strong>功能丰富</strong>: 功能丰富的表格
              </li>
            </ul>
          </div>
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    标签
    名称状态
    容器数量
    创建人操作
    暂无数据
    暂无数据
    );

    ProTable 标签工具栏 Props 说明:

    • ProTable: 专业表格组件
    • LightFilter: 轻量过滤器组件
    • ProFormDatePicker: 专业表单日期选择器组件
    • 标签工具栏: 展示标签工具栏功能

    ProTable 配置:

    • columns: 列配置
    • request: 请求函数
    • toolbar: 工具栏配置
    • rowKey: 行键
    • search: 搜索配置

    标签工具栏特点:

    • 标签切换: 支持标签切换
    • 多行布局: 支持多行布局
    • 过滤器: 支持过滤器
    • 动态列: 支持动态列配置
    • 状态管理: 支持状态管理

    使用场景:

    • 分类展示: 分类展示需求
    • 多视图切换: 多视图切换功能
    • 数据分组: 数据分组管理
    带标签
    import { EllipsisOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import {
      LightFilter,
      ProFormDatePicker,
      ProTable,
    } from '@ant-design/pro-components';
    import { useState } from 'react';
    
    import { createTableDataSource, DEMO_CREATOR_VALUE_ENUM } from '../../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      status: number;
      containers: number;
      creator: string;
    };
    
    const baseData = createTableDataSource({
      count: 5,
    }) as unknown as TableListItem[];
    const tableListDataSource = baseData.map((item, i) => ({
      ...item,
      status: i % 2,
    }));
    
    const columnsMap: Record<string, ProColumns<TableListItem>[]> = {
      tab1: [
        {
          title: '名称',
          dataIndex: 'name',
          render: (_) => <a>{_}</a>,
        },
        {
          title: '状态',
          key: 'status1',
          dataIndex: 'status',
          valueType: 'select',
          request: () =>
            Promise.resolve([
              {
                label: '成功',
                value: 1,
              },
              {
                label: '失败',
                value: 0,
              },
            ]),
        },
        {
          title: '容器数量',
          dataIndex: 'containers',
          align: 'right',
          sorter: (a, b) => a.containers - b.containers,
        },
        {
          title: '创建人',
          dataIndex: 'creator',
          valueType: 'select',
          valueEnum: DEMO_CREATOR_VALUE_ENUM,
        },
        {
          title: '操作',
          key: 'option',
          valueType: 'option',
          width: 120,
          render: () => [
            <a key="link">链路</a>,
            <a key="warn">报警</a>,
            <a key="more">
              <EllipsisOutlined />
            </a>,
          ],
        },
      ],
      tab2: [
        {
          title: '应用名称',
          dataIndex: 'name',
          render: (_) => <a>{_}</a>,
        },
        {
          title: '状态',
          key: 'status2',
          dataIndex: 'status',
          valueType: 'select',
          request: () =>
            Promise.resolve([
              {
                label: '启用',
                value: 1,
              },
              {
                label: '停用',
                value: 0,
              },
            ]),
        },
        {
          title: '创建者',
          dataIndex: 'creator',
          valueType: 'select',
          valueEnum: DEMO_CREATOR_VALUE_ENUM,
        },
        {
          title: '操作',
          key: 'option',
          valueType: 'option',
          width: 120,
          render: () => [
            <a key="link">链路</a>,
            <a key="warn">报警</a>,
            <a key="more">
              <EllipsisOutlined />
            </a>,
          ],
        },
      ],
    };
    
    const Demo = () => {
      const [activeKey, setActiveKey] = useState<string>('tab1');
    
      return (
        <>
          <ProTable<TableListItem>
            columns={columnsMap[activeKey]}
            request={(params, sorter, filter) => {
              // 表单搜索项会从 params 传入,传递给后端接口。
              console.log(params, sorter, filter);
              return Promise.resolve({
                data: tableListDataSource,
                total: tableListDataSource.length,
                success: true,
              });
            }}
            toolbar={{
              title: '标签',
              multipleLine: true,
              filter: (
                <LightFilter>
                  <ProFormDatePicker name="startdate" label="响应日期" />
                </LightFilter>
              ),
              tabs: {
                activeKey,
                onChange: (key) => setActiveKey(key as string),
                items: [
                  {
                    key: 'tab1',
                    tab: '标签一',
                  },
                  {
                    key: 'tab2',
                    tab: '标签二',
                  },
                ],
              },
            }}
            rowKey="key"
            search={false}
          />
          );
          <div
            style={{
              marginTop: '20px',
              padding: '20px',
              backgroundColor: '#f5f5f5',
              borderRadius: '6px',
            }}
          >
            <h4>ProTable 标签工具栏 Props 说明:</h4>
            <ul>
              <li>
                <strong>ProTable</strong>: 专业表格组件
              </li>
              <li>
                <strong>LightFilter</strong>: 轻量过滤器组件
              </li>
              <li>
                <strong>ProFormDatePicker</strong>: 专业表单日期选择器组件
              </li>
              <li>
                <strong>标签工具栏</strong>: 展示标签工具栏功能
              </li>
            </ul>
            <h4>ProTable 配置:</h4>
            <ul>
              <li>
                <strong>columns</strong>: 列配置
              </li>
              <li>
                <strong>request</strong>: 请求函数
              </li>
              <li>
                <strong>toolbar</strong>: 工具栏配置
              </li>
              <li>
                <strong>rowKey</strong>: 行键
              </li>
              <li>
                <strong>search</strong>: 搜索配置
              </li>
            </ul>
            <h4>标签工具栏特点:</h4>
            <ul>
              <li>
                <strong>标签切换</strong>: 支持标签切换
              </li>
              <li>
                <strong>多行布局</strong>: 支持多行布局
              </li>
              <li>
                <strong>过滤器</strong>: 支持过滤器
              </li>
              <li>
                <strong>动态列</strong>: 支持动态列配置
              </li>
              <li>
                <strong>状态管理</strong>: 支持状态管理
              </li>
            </ul>
            <h4>使用场景:</h4>
            <ul>
              <li>
                <strong>分类展示</strong>: 分类展示需求
              </li>
              <li>
                <strong>多视图切换</strong>: 多视图切换功能
              </li>
              <li>
                <strong>数据分组</strong>: 数据分组管理
              </li>
            </ul>
          </div>
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    
    应用名称
    容器数量
    创建者操作
    暂无数据
    暂无数据

    ProTable 菜单工具栏 Props 说明:

    • ProTable: 专业表格组件
    • LightFilter: 轻量过滤器组件
    • ProFormDatePicker: 专业表单日期选择器组件
    • 菜单工具栏: 展示菜单工具栏功能

    ProTable 配置:

    • columns: 列配置
    • request: 请求函数
    • toolbar: 工具栏配置
    • rowKey: 行键
    • search: 搜索配置

    菜单工具栏特点:

    • 标签菜单: 支持标签菜单
    • 搜索功能: 支持搜索功能
    • 过滤器: 支持过滤器
    • 操作按钮: 支持操作按钮
    • 菜单切换: 支持菜单切换

    使用场景:

    • 分类管理: 分类管理系统
    • 标签切换: 标签切换功能
    • 多视图展示: 多视图展示需求
    列表工具栏-标题下拉菜单
    import { EllipsisOutlined } from '@ant-design/icons';
    import type { ProColumns } from '@ant-design/pro-components';
    import {
      LightFilter,
      ProFormDatePicker,
      ProTable,
    } from '@ant-design/pro-components';
    import { Button } from 'antd';
    
    import { createTableDataSource, DEMO_CREATOR_VALUE_ENUM } from '../../mockData';
    
    export type TableListItem = {
      key: number;
      name: string;
      containers: number;
      creator: string;
    };
    
    const tableListDataSource = createTableDataSource({
      count: 5,
    }) as TableListItem[];
    
    const columns: ProColumns<TableListItem>[] = [
      {
        title: '应用名称',
        dataIndex: 'name',
        render: (_) => <a>{_}</a>,
      },
      {
        title: '容器数量',
        dataIndex: 'containers',
        align: 'right',
        sorter: (a, b) => a.containers - b.containers,
      },
      {
        title: '创建者',
        dataIndex: 'creator',
        valueType: 'select',
        valueEnum: DEMO_CREATOR_VALUE_ENUM,
      },
      {
        title: '操作',
        key: 'option',
        valueType: 'option',
        width: 120,
        render: () => [
          <a key="link">链路</a>,
          <a key="warn">报警</a>,
          <a key="more">
            <EllipsisOutlined />
          </a>,
        ],
      },
    ];
    
    const Demo = () => {
      return (
        <>
          <ProTable<TableListItem>
            columns={columns}
            request={(params, sorter, filter) => {
              // 表单搜索项会从 params 传入,传递给后端接口。
              console.log(params, sorter, filter);
              return Promise.resolve({
                data: tableListDataSource,
                total: tableListDataSource.length,
                success: true,
              });
            }}
            toolbar={{
              search: {
                onSearch: (value) => {
                  alert(value);
                },
              },
              filter: (
                <LightFilter>
                  <ProFormDatePicker name="startdate" label="响应日期" />
                </LightFilter>
              ),
              actions: [
                <Button
                  key="primary"
                  type="primary"
                  onClick={() => {
                    alert('add');
                  }}
                >
                  添加
                </Button>,
              ],
              menu: {
                type: 'tab',
                items: [
                  {
                    label: '全部事项',
                    key: 'all',
                  },
                  {
                    label: '已办事项',
                    key: 'done',
                  },
                  {
                    key: 'tab1',
                    label: <span>应用</span>,
                  },
                  {
                    key: 'tab2',
                    label: <span>项目</span>,
                  },
                  {
                    key: 'tab3',
                    label: <span>文章</span>,
                  },
                  {
                    key: 'tab4',
                    label: <span>文章1</span>,
                  },
                  {
                    key: 'tab5',
                    label: <span>文章2</span>,
                  },
                  {
                    key: 'tab6',
                    label: <span>文章3</span>,
                  },
                ],
                onChange: (activeKey) => {
                  console.log('activeKey', activeKey);
                },
              },
            }}
            rowKey="key"
            search={false}
          />
          <div
            style={{
              marginTop: '20px',
              padding: '20px',
              backgroundColor: '#f5f5f5',
              borderRadius: '6px',
            }}
          >
            <h4>ProTable 菜单工具栏 Props 说明:</h4>
            <ul>
              <li>
                <strong>ProTable</strong>: 专业表格组件
              </li>
              <li>
                <strong>LightFilter</strong>: 轻量过滤器组件
              </li>
              <li>
                <strong>ProFormDatePicker</strong>: 专业表单日期选择器组件
              </li>
              <li>
                <strong>菜单工具栏</strong>: 展示菜单工具栏功能
              </li>
            </ul>
            <h4>ProTable 配置:</h4>
            <ul>
              <li>
                <strong>columns</strong>: 列配置
              </li>
              <li>
                <strong>request</strong>: 请求函数
              </li>
              <li>
                <strong>toolbar</strong>: 工具栏配置
              </li>
              <li>
                <strong>rowKey</strong>: 行键
              </li>
              <li>
                <strong>search</strong>: 搜索配置
              </li>
            </ul>
            <h4>菜单工具栏特点:</h4>
            <ul>
              <li>
                <strong>标签菜单</strong>: 支持标签菜单
              </li>
              <li>
                <strong>搜索功能</strong>: 支持搜索功能
              </li>
              <li>
                <strong>过滤器</strong>: 支持过滤器
              </li>
              <li>
                <strong>操作按钮</strong>: 支持操作按钮
              </li>
              <li>
                <strong>菜单切换</strong>: 支持菜单切换
              </li>
            </ul>
            <h4>使用场景:</h4>
            <ul>
              <li>
                <strong>分类管理</strong>: 分类管理系统
              </li>
              <li>
                <strong>标签切换</strong>: 标签切换功能
              </li>
              <li>
                <strong>多视图展示</strong>: 多视图展示需求
              </li>
            </ul>
          </div>
        </>
      );
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );
    

    ProForm 内 EditableProTable(列校验)

    关联题库操作
    暂无数据
    暂无数据
    ProForm 内可编辑表格与列校验
    import type {
      ActionType,
      EditableFormInstance,
      ProColumns,
      ProFormInstance,
    } from '@ant-design/pro-components';
    import { EditableProTable, ProCard, ProForm } from '@ant-design/pro-components';
    import React, { useRef, useState } from 'react';
    
    type DataSourceType = {
      id: React.Key;
      associate?: string;
    };
    
    const defaultData: DataSourceType[] = [];
    
    const Demo = () => {
      const [editableKeys, setEditableRowKeys] = useState<React.Key[]>(() => []);
      const formRef = useRef<ProFormInstance<any>>();
      const actionRef = useRef<ActionType>();
      const editableFormRef = useRef<EditableFormInstance>();
      const columns: ProColumns<DataSourceType>[] = [
        {
          title: '关联题库',
          dataIndex: 'associate',
          valueType: 'text',
          ellipsis: true,
          formItemProps: {
            rules: [{ required: true, message: 'Required' }],
          },
        },
        {
          title: '操作',
          valueType: 'option',
          render: (_, row) => [
            <a
              key="delete"
              onClick={() => {
                const tableDataSource = formRef.current?.getFieldValue(
                  'table',
                ) as DataSourceType[];
                formRef.current?.setFieldsValue({
                  table: tableDataSource.filter((item) => item.id !== row?.id),
                });
              }}
            >
              移除
            </a>,
            <a
              key="edit"
              onClick={() => {
                actionRef.current?.startEditable(row.id);
              }}
            >
              编辑
            </a>,
          ],
        },
      ];
    
      return (
        <ProCard>
          <div
            style={{
              maxWidth: 800,
              margin: 'auto',
            }}
          >
            <ProForm<{
              table: DataSourceType[];
            }>
              formRef={formRef}
              initialValues={{
                table: defaultData,
              }}
            >
              <EditableProTable<DataSourceType>
                rowKey="id"
                scroll={{
                  x: true,
                }}
                editableFormRef={editableFormRef}
                controlled
                actionRef={actionRef}
                formItemProps={{
                  label: '题库编辑',
                }}
                maxLength={10}
                name="table"
                columns={columns}
                recordCreatorProps={{
                  record: (index) => {
                    return { id: index + 1 };
                  },
                }}
                editable={{
                  type: 'multiple',
                  editableKeys,
                  onChange: setEditableRowKeys,
                }}
              />
            </ProForm>
          </div>
        </ProCard>
      );
    
      <div
        style={{
          marginTop: '20px',
          padding: '20px',
          backgroundColor: '#f5f5f5',
          borderRadius: '6px',
        }}
      >
        <h4>EditableProTable 规则 Props 说明:</h4>
        <ul>
          <li>
            <strong>EditableProTable</strong>: 可编辑专业表格组件
          </li>
          <li>
            <strong>ProCard</strong>: 专业卡片组件
          </li>
          <li>
            <strong>ProForm</strong>: 专业表单组件
          </li>
          <li>
            <strong>编辑规则</strong>: 展示编辑规则功能
          </li>
        </ul>
        <h4>EditableProTable 配置:</h4>
        <ul>
          <li>
            <strong>rowKey</strong>: 行键
          </li>
          <li>
            <strong>scroll</strong>: 滚动配置
          </li>
          <li>
            <strong>editableFormRef</strong>: 可编辑表单引用
          </li>
          <li>
            <strong>controlled</strong>: 受控模式
          </li>
          <li>
            <strong>actionRef</strong>: 操作引用
          </li>
          <li>
            <strong>formItemProps</strong>: 表单项属性
          </li>
          <li>
            <strong>maxLength</strong>: 最大长度
          </li>
          <li>
            <strong>name</strong>: 字段名称
          </li>
          <li>
            <strong>columns</strong>: 列配置
          </li>
          <li>
            <strong>recordCreatorProps</strong>: 记录创建属性
          </li>
          <li>
            <strong>editable</strong>: 可编辑配置
          </li>
        </ul>
        <h4>编辑规则特点:</h4>
        <ul>
          <li>
            <strong>表单验证</strong>: 支持表单验证
          </li>
          <li>
            <strong>必填校验</strong>: 支持必填校验
          </li>
          <li>
            <strong>多行编辑</strong>: 支持多行编辑
          </li>
          <li>
            <strong>动态添加</strong>: 支持动态添加
          </li>
          <li>
            <strong>行内编辑</strong>: 支持行内编辑
          </li>
          <li>
            <strong>数据控制</strong>: 支持数据控制
          </li>
        </ul>
        <h4>使用场景:</h4>
        <ul>
          <li>
            <strong>数据编辑</strong>: 数据编辑需求
          </li>
          <li>
            <strong>表单管理</strong>: 表单管理系统
          </li>
          <li>
            <strong>配置管理</strong>: 配置管理功能
          </li>
        </ul>
      </div>;
    };
    
    export default () => (
      <div style={{ padding: 24 }}>
        <Demo />
      </div>
    );