ant design pro 技巧之实现列表页多标签

像上图那样,我们经常给列表页做分类的,



这种多标签如何处理呢?

肯定是要得到动态数据对吧。

每次点击的时候要发请求,得到不同的数据。

其实 ant design pro 是支持的。

在 index.tsx 中的 protable 里加上这个就好。

javascript 复制代码
toolbar={{
          menu: {
            type: 'tab',
            activeKey: activeKey,
            items: [
              {
                label: <FormattedMessage id="platform.all" defaultMessage="All" />,
                key: '',
              },
              {
                label: <FormattedMessage id="platform.online" defaultMessage="Online" />,
                key: 'true',
              },
              {
                label: <FormattedMessage id="platform.offline" defaultMessage="Offline" />,
                key: 'false',
              },
            ],
            onChange: (key: any) => {
              setActiveKey(key);
              if (actionRef.current) {
                actionRef.current.reload();
              }
            },
          },
        }}

完整代码是这样的:

javascript 复制代码
import { addItem, queryList, removeItem, updateItem } from '@/services/ant-design-pro/api';
import { PlusOutlined } from '@ant-design/icons';
import type { ActionType, ProColumns, ProDescriptionsItemProps } from '@ant-design/pro-components';
import { FooterToolbar, PageContainer, ProTable } from '@ant-design/pro-components';
import { FormattedMessage, useAccess } from '@umijs/max';
import { Button, message, Modal, Switch, Tooltip } from 'antd';
import React, { useRef, useState } from 'react';
import type { FormValueType } from './components/Update';
import Update from './components/Update';
import Create from './components/Create';
import Show from './components/Show';
import { useIntl } from '@umijs/max';
import { carTypeMap } from '@/utils/constants';
import CopyToClipboard from '@/components/CopyToClipboard';
import ConfigureForm from './components/ConfigureForm';

/**
 * @en-US Add node
 * @zh-CN 添加节点
 * @param fields
 */
const handleAdd = async (fields: API.ItemData) => {
  const hide = message.loading(<FormattedMessage id="adding" defaultMessage="Adding..." />);
  try {
    await addItem('/platforms', { ...fields });
    hide();
    message.success(<FormattedMessage id="add.success" defaultMessage="Added successfully" />);
    return true;
  } catch (error: any) {
    hide();
    message.error(
      error?.response?.data?.message ?? (
        <FormattedMessage id="add.failed" defaultMessage="Adding failed, please try again!" />
      ),
    );
    return false;
  }
};

/**
 * @en-US Update node
 * @zh-CN 更新节点
 *
 * @param fields
 */
const handleUpdate = async (fields: FormValueType) => {
  const hide = message.loading(<FormattedMessage id="updating" defaultMessage="Updating..." />);
  try {
    await updateItem(`/platforms/${fields._id}`, fields);
    hide();

    message.success(<FormattedMessage id="update.success" defaultMessage="Updated successfully" />);
    return true;
  } catch (error: any) {
    hide();
    message.error(
      error?.response?.data?.message ?? (
        <FormattedMessage id="update.failed" defaultMessage="Update failed, please try again!" />
      ),
    );
    return false;
  }
};

/**
 *  Delete node
 * @zh-CN 删除节点
 *
 * @param selectedRows
 */
const handleRemove = async (ids: string[]) => {
  const hide = message.loading(<FormattedMessage id="deleting" defaultMessage="Deleting..." />);
  if (!ids) return true;
  try {
    await removeItem('/platforms', {
      ids,
    });
    hide();
    message.success(
      <FormattedMessage
        id="delete.success"
        defaultMessage="Deleted successfully and will refresh soon"
      />,
    );
    return true;
  } catch (error: any) {
    hide();
    message.error(
      error.response.data.message ?? (
        <FormattedMessage id="delete.failed" defaultMessage="Delete failed, please try again" />
      ),
    );
    return false;
  }
};

const TableList: React.FC = () => {
  const intl = useIntl();
  /**
   * @en-US Pop-up window of new window
   * @zh-CN 新建窗口的弹窗
   *  */
  const [createModalOpen, handleModalOpen] = useState<boolean>(false);
  /**2024fc.xyz
   * @en-US The pop-up window of the distribution update window
   * @zh-CN 分布更新窗口的弹窗
   * */
  const [updateModalOpen, handleUpdateModalOpen] = useState<boolean>(false);

  const [showDetail, setShowDetail] = useState<boolean>(false);

  const actionRef = useRef<ActionType>();
  const [currentRow, setCurrentRow] = useState<API.ItemData>();
  const [selectedRowsState, setSelectedRows] = useState<API.ItemData[]>([]);
  const access = useAccess();
  const [activeKey, setActiveKey] = useState<string | undefined>('');
  const [configureModalVisible, setConfigureModalVisible] = useState<boolean>(false);

  /**
   * @en-US International configuration
   * @zh-CN 国际化配置
   * */

  const columns: ProColumns<API.ItemData>[] = [
    {
      title: intl.formatMessage({ id: 'platform.name' }),
      dataIndex: 'name',
      width: 150,
      copyable: true,
      render: (dom, entity) => {
        return (
          <a
            onClick={() => {
              setCurrentRow(entity);
              setShowDetail(true);
            }}
          >
            {dom}
          </a>
        );
      },
    },
    {
      title: intl.formatMessage({ id: 'platform.image' }),
      dataIndex: 'image',
      width: 100,
      hideInSearch: true,
      valueType: 'image',
    },
    {
      title: intl.formatMessage({ id: 'platform.region' }),
      dataIndex: 'region',
      width: 200,
      render: (_, record: any) =>
        record.region && (
          <>
            {record.region.name} <CopyToClipboard text={record.region.name} />
          </>
        ),
    },
    {
      title: intl.formatMessage({ id: 'platform.price' }),
      dataIndex: 'price',
      width: 150,
      hideInSearch: true,
      render: (text, record: any) => (
        <Tooltip title={`€ ${record.priceInEuro}`}>
          <strong>$ {text}</strong>/{carTypeMap[record.carType as keyof typeof carTypeMap]}
        </Tooltip>
      ),
    },
    {
      title: intl.formatMessage({ id: 'platform.tips' }),
      ellipsis: true,
      width: 150,
      hideInTable: true,
      hideInSearch: true,
      dataIndex: 'tips',
    },
    {
      title: intl.formatMessage({ id: 'platform.boardingMethod' }),
      dataIndex: 'boardingMethod',
      width: 150,
      hideInSearch: true,
      hideInTable: true,
      valueEnum: {
        '': { text: intl.formatMessage({ id: 'all' }), status: 'Default' },
        fullCar: { text: intl.formatMessage({ id: 'platform.fullCar' }) },
        batchCar: { text: intl.formatMessage({ id: 'platform.batchCar' }) },
      },
    },
    {
      title: intl.formatMessage({ id: 'platform.deliveryMethod' }),
      dataIndex: 'deliveryMethod',
      width: 150,
      hideInSearch: true,
      hideInTable: true,
      valueEnum: {
        '': { text: intl.formatMessage({ id: 'all' }), status: 'Default' },
        autoDelivery: { text: intl.formatMessage({ id: 'platform.autoDelivery' }) },
        inviteLink: { text: intl.formatMessage({ id: 'platform.inviteLink' }) },
      },
    },
    {
      title: intl.formatMessage({ id: 'platform.status' }),
      dataIndex: 'isOnline',
      width: 150,
      hideInSearch: true,
      render: (_, record: any) => (
        <Switch
          checkedChildren={intl.formatMessage({ id: 'platform.online' })}
          unCheckedChildren={intl.formatMessage({ id: 'platform.offline' })}
          checked={record.isOnline}
          onChange={async () => {
            await handleUpdate({ _id: record._id, isOnline: !record.isOnline });
            if (actionRef.current) {
              actionRef.current.reload();
            }
          }}
        />
      ),
    },
    {
      title: intl.formatMessage({ id: 'platform.remark' }),
      ellipsis: true,
      width: 150,
      hideInSearch: true,
      dataIndex: 'remark',
    },
    {
      title: intl.formatMessage({ id: 'platform.userCount' }),
      hideInSearch: true,
      width: 150,
      hideInTable: true,
      dataIndex: 'userCount',
    },
    {
      title: intl.formatMessage({ id: 'platform.user' }),
      hideInSearch: true,
      width: 150,
      dataIndex: 'user',
      render: (_, record) => record.user && record.user.name,
    },
    {
      title: <FormattedMessage id="creation_time" defaultMessage="Creation Time" />,
      width: 250,
      dataIndex: 'createdAt',
      valueType: 'dateTime',
      hideInSearch: true,
    },
    {
      title: <FormattedMessage id="platform.description" defaultMessage="platform.description" />,
      width: 250,
      dataIndex: 'descriptions',
      hideInSearch: true,
      hideInTable: true,
      render: (text) => (Array.isArray(text) ? text.join(', ') : text),
    },
    {
      title: <FormattedMessage id="pages.searchTable.titleOption" defaultMessage="Operating" />,
      dataIndex: 'option',
      valueType: 'option',
      fixed: 'right',
      render: (_, record) => [
        <a
          key="update"
          onClick={() => {
            handleUpdateModalOpen(true);
            setCurrentRow(record);
          }}
        >
          <FormattedMessage id="edit" defaultMessage="Edit" />
        </a>,
        access.canSuperAdmin && (
          <a
            key="delete"
            onClick={() => {
              return Modal.confirm({
                title: intl.formatMessage({ id: 'confirm.delete' }),
                onOk: async () => {
                  await handleRemove([record._id!]);
                  setSelectedRows([]);
                  actionRef.current?.reloadAndRest?.();
                },
                content: intl.formatMessage({ id: 'confirm.delete.content' }),
                okText: intl.formatMessage({ id: 'confirm' }),
                cancelText: intl.formatMessage({ id: 'cancel' }),
              });
            }}
          >
            <FormattedMessage id="delete" defaultMessage="Delete" />
          </a>
        ),
        <a
          key="configure"
          onClick={() => {
            setConfigureModalVisible(true);
            setCurrentRow(record);
          }}
        >
          {intl.formatMessage({
            id: 'configure',
            defaultMessage: 'Configure',
          })}
        </a>,
      ],
    },
  ];

  return (
    <PageContainer>
      <ProTable<API.ItemData, API.PageParams>
        headerTitle={intl.formatMessage({ id: 'list' })}
        actionRef={actionRef}
        rowKey="_id"
        scroll={{ x: 1200 }}
        search={{
          labelWidth: 120,
          collapsed: false,
        }}
        toolBarRender={() => [
          <Button
            type="primary"
            key="primary"
            onClick={() => {
              handleModalOpen(true);
            }}
          >
            <PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="New" />
          </Button>,
          selectedRowsState?.length > 0 && access.canSuperAdmin && (
            <Button
              danger
              onClick={() => {
                return Modal.confirm({
                  title: intl.formatMessage({ id: 'confirm.delete' }),
                  onOk: async () => {
                    await handleRemove(selectedRowsState?.map((item) => item._id!));
                    setSelectedRows([]);
                    actionRef.current?.reloadAndRest?.();
                  },
                  content: intl.formatMessage({ id: 'confirm.delete.content' }),
                  okText: intl.formatMessage({ id: 'confirm' }),
                  cancelText: intl.formatMessage({ id: 'cancel' }),
                });
              }}
            >
              <FormattedMessage
                id="pages.searchTable.batchDeletion"
                defaultMessage="Batch deletion"
              />
            </Button>
          ),
        ]}
        toolbar={{
          menu: {
            type: 'tab',
            activeKey: activeKey,
            items: [
              {
                label: <FormattedMessage id="platform.all" defaultMessage="All" />,
                key: '',
              },
              {
                label: <FormattedMessage id="platform.online" defaultMessage="Online" />,
                key: 'true',
              },
              {
                label: <FormattedMessage id="platform.offline" defaultMessage="Offline" />,
                key: 'false',
              },
            ],
            onChange: (key: any) => {
              setActiveKey(key);
              if (actionRef.current) {
                actionRef.current.reload();
              }
            },
          },
        }}
        request={async (params, sort, filter) =>
          queryList('/platforms', { ...params, isOnline: activeKey }, sort, filter)
        }
        columns={columns}
        rowSelection={{
          onChange: (_, selectedRows) => {
            setSelectedRows(selectedRows);
          },
        }}
      />
      {selectedRowsState?.length > 0 && (
        <FooterToolbar
          extra={
            <div>
              <FormattedMessage id="pages.searchTable.chosen" defaultMessage="Chosen" />{' '}
              <a style={{ fontWeight: 600 }}>{selectedRowsState.length}</a>{' '}
              <FormattedMessage id="pages_searchTable_item" defaultMessage="items" />
            </div>
          }
        ></FooterToolbar>
      )}
      <Create
        open={createModalOpen}
        onOpenChange={handleModalOpen}
        onFinish={async (value) => {
          const success = await handleAdd(value as API.ItemData);
          if (success) {
            handleModalOpen(false);
            if (actionRef.current) {
              actionRef.current.reload();
            }
          }
        }}
      />
      <Update
        onSubmit={async (value) => {
          const success = await handleUpdate(value);
          if (success) {
            handleUpdateModalOpen(false);
            setCurrentRow(undefined);
            if (actionRef.current) {
              actionRef.current.reload();
            }
          }
        }}
        onCancel={handleUpdateModalOpen}
        updateModalOpen={updateModalOpen}
        values={currentRow || {}}
      />

      <ConfigureForm
        onSubmit={async (value) => {
          const success = await handleUpdate(value);
          if (success) {
            setConfigureModalVisible(false);
            setCurrentRow(undefined);
            if (actionRef.current) {
              actionRef.current.reload();
            }
          }
        }}
        onCancel={setConfigureModalVisible}
        updateModalOpen={configureModalVisible}
        values={currentRow || {}}
      />

      <Show
        open={showDetail}
        currentRow={currentRow as API.ItemData}
        columns={columns as ProDescriptionsItemProps<API.ItemData>[]}
        onClose={() => {
          setCurrentRow(undefined);
          setShowDetail(false);
        }}
      />
    </PageContainer>
  );
};

export default TableList;

主要是上面的 menu 的选项处理,还有

const activeKey, setActiveKey = useState<string | undefined>('');

然后是请求列表里比较重要,

要把 activeKey 传给后端

复制代码
    request={async (params, sort, filter) =>
      queryList('/platforms', { ...params, isOnline: activeKey }, sort, filter)
    }

后端的参数是叫 isOnline ,要对上 key 和 value

其它的都没啥的问题。

我们拥有 12 年建站编程经验

  1. 虚拟产品交易平台定制开发
  2. WordPress 外贸电商独立站建站

我的网站

相关推荐
前端snow7 小时前
ai agent --- 文件存储
前端
Frag0ut7 小时前
Chrome四大版本获取及共存指南:Stable/Beta/Dev/Canary
前端·chrome·浏览器·dev·beta·canary·共存版
IT_陈寒8 小时前
SpringBoot自动配置坑了我一把,原来是这样绕过去的
前端·人工智能·后端
广州华水科技8 小时前
单北斗GNSS变形监测在大坝安全监测中的应用与优势
前端
zeng不错8 小时前
B站 173 个投稿活动看到眼瞎?我写了个扩展,主打一个精准打击
前端
Latchh8 小时前
前端导出的JPEG红字发糊,质量要拉到100才清楚
前端·图像处理·人工智能·计算机视觉
默_笙9 小时前
🚦 请三个 AI 考官给 RAG 打分:量化评估实战(下)
前端·javascript
阿坨9 小时前
灵感闪存卡:一款 Tampermonkey用户脚本
javascript·tampermonkey
Joy T9 小时前
聊天系统中五大ID的演进与实战解析
java·前端·人工智能·spring·agent入门
Seraphina3611 小时前
DVWA(SQL注入-low,medium,XSS反射-low)
前端·数据库·笔记·sql·网络安全·web·xss