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

news2024/11/15 15:51:09

在这里插入图片描述

  • ant design pro 如何去保存颜色
  • ant design pro v6 如何做好角色管理
  • ant design 的 tree 如何作为角色中的权限选择之一
  • ant design 的 tree 如何作为角色中的权限选择之二
  • ant design pro access.ts 是如何控制多角色的权限的
  • ant design pro 中用户的表单如何控制多个角色
  • ant design pro 如何实现动态菜单带上 icon 的
  • ant design pro 的表分层级如何处理
  • ant design pro 如何处理权限管理
  • ant design pro 技巧之自制复制到剪贴板组件

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

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这种多标签如何处理呢?

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

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

其实 ant design pro 是支持的。

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

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();
              }
            },
          },
        }}

完整代码是这样的:

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 外贸电商独立站建站

我的网站

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2056942.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

全国大学生数学建模比赛——时间序列(详细解读)

全国大学生数学建模比赛中&#xff0c;时间序列分析是一种重要的方法。以下是对时间序列在该比赛中的详细解读&#xff1a; 一、时间序列的概念 时间序列是按时间顺序排列的一组数据。在数学建模中&#xff0c;时间序列数据通常反映了某个现象随时间的变化情况。例如&#xf…

编程中数据字典介绍

目录 第一章、快速了解数据字典1.1&#xff09;数据字典介绍1.2&#xff09;主动数据字典1.2.1&#xff09;主动数据字典对表字段的描述1.2.2&#xff09;主动数据字典对表索引的描述1.2.3&#xff09;主动数据字典对表外键的描述1.3&#xff09;被动数据字典1.4&#xff09;数…

golang实现windows获取加密盘符的总大小

golang实现windows获取加密盘符的总大小 package mainimport ("fmt""syscall""unsafe" )type PartitionStyle uint32const (IOCTL_DISK_GET_DRIVE_LAYOUT_EX 0x00070050FILE_DEVICE_MASS_STORAGE uint32 0x0000002dIOCTL_STOR…

【生物特征识别论文分享】基于深度学习的掌纹掌静脉识别

&#xff08;待更新&#xff09;基于深度学习的生物特征识别&#xff08;手掌静脉、手背静脉、手指静脉、掌纹、人脸等&#xff09;论文模型总结 。具体方法包括&#xff1a;基于特征表征、基于传统网络设计与优化、基于轻量级网络设计与优化、基于Transformer设计与优化、基于…

Isaac Sim仿真平台学习(2)基础知识

目录 0.前言 1.isaac sim的组建 1.Isaac Lab的资料 2.PhysX 3.RTX 4.Digital Twins 5.Replicator 6.Omnigraph 0.前言 难得更新阿&#xff0c;今天黑猴发布了没有去玩&#xff0c;跑来更新博客&#xff0c;本来想着按宇树的go2开发指南去试试RL的&#xff0c;但可惜没成…

39_WAF的概念、功能,ModSecurity部署配置、LAMP环境部署、Ubuntu搭建DVWA靶机测试、测试WAF防御、OWASP规则集的部署

一、WAF的概念 WAF&#xff08; Web Application Firewall &#xff09;&#xff0c;即Web应用防火墙 通过执行一系列HTTP/HTTPS&#xff08;应用层的协议&#xff09;的安全策略为Web应用提供保护的一种网络安全产品。增加攻击者的难度和成本&#xff0c;但不是100%安全。工…

XRAY~漏洞扫描工具

有人说&#xff1a;“所有的漏扫工具都是人写出来的&#xff0c;既然是工具&#xff0c;肯定没有人厉害&#xff0c;但是&#xff0c;漏扫可以大大减少你的工作量” 4、⭐ XRAY xray 是一款功能强大的安全评估工具&#xff0c;由多名经验丰富的一线安全从业者呕心打造而成&…

五、2 移位操作符赋值操作符

1、移位操作符 2、赋值操作符 “ ”赋值&#xff0c;“ ”判断是否相等 1&#xff09;连续赋值 2&#xff09;复合赋值符

关于栈(顺序栈)的知识讲解

1.1 什么是栈 栈是只能在一端进行插入和删除操作的线性表(又称为堆栈)&#xff0c;进行插入和删除操作的一端称为栈顶&#xff0c;另一端称为栈底。 特点&#xff1a;栈是先进后出FILO(First In Last Out) (LIFO(Last In First Out)) 1.2 顺序栈 1.2.1 特性 逻辑结构&#xff1…

推荐4款高效的视频剪辑神器。

很多人一开始&#xff0c;面对各种视频剪辑软件时会不知所措。不知道该选择哪一个&#xff0c;也知道如何使用。但是这几个软件&#xff0c;对于不太熟悉视频剪辑的朋友们来说简直就是神器&#xff0c;简单易上手&#xff0c;功能做的也非常的专业。 1、福昕剪辑软件 直达链接…

高性能 Web 服务器:让网页瞬间绽放的魔法引擎(下)

目录 一.Nginx 反向代理功能 1.缓存功能 2.http 反向代理负载均衡 二.实现 Nginx 四层负载均衡 三.实现 FastCGI 1.为什么会有FastCGI&#xff1f; 2.什么是PHP-FPM&#xff1f; 3.FastCGI配置指令 4.Nginx与php-fpm在同一服务器 5.Nginx配置转发 6. php的动态扩展模…

关于c++多线程中的互斥锁mutex

关于c多线程中的互斥锁mutex c中的多线程线程的基本概念C 标准库中的线程支持 多线程与主线程与join换一种方式理解线程互斥锁第一种第二种 子线程与互斥锁混合锁--看这个应该就明白了&#xff08;这个主要使用的是嵌套锁&#xff09;定义一个类创建线程 这个示例主要使用并列锁…

SAP负库存

业务示例 在系统中&#xff0c;对于一些物料而言&#xff0c;不能立即将收到的交货输入为收货。如果要使发货无论如何都是可以过帐的&#xff0c;则需要允许这些物料的负库存。 负库存 发货数量大于预订数量时&#xff0c;过帐该发货就会出现负库存。如果由于组织原因&#…

【人工智能】Transformers之Pipeline(十一):零样本图片分类(zero-shot-image-classification)

目录 一、引言 二、零样本图像分类&#xff08;zero-shot-image-classification&#xff09; 2.1 概述 2.2 技术原理 2.3 应用场景 2.4 pipeline参数 2.4.1 pipeline对象实例化参数 2.4.2 pipeline对象使用参数 2.4 pipeline实战 2.5 模型排名 三、总结 一、引言 …

嵌入式软件--PCB DAY 1

一、入门 1.什么是PCB 随着技术的进步&#xff0c;我们已经可以将一个电子设备的主要功能全部集成在一块单独的电路板上。这种电路板可以由相关的机械设备像印刷一样生产出来。因此我们现在的电路板可以被称为印刷电路板(Printed Circuit Board&#xff09;。 2.什么是PCBA …

洛谷B3981题解

题目描述 &#xff08;你不需要看懂这张图片&#xff1b;但如果你看懂了&#xff0c;会觉得它很有趣。&#xff09; JavaScript 是一种功能强大且灵活的编程语言&#xff0c;也是现代 Web 开发的三大支柱之一 (另外两个是 HTML 和 CSS)。灵活的 JavaScript 包含“自动类型转换…

C++实现——红黑树

目录 1.红黑树 1.1红黑树的概念 1.2红黑树的性质 1.3红黑树节点的定义 1.4红黑树的插入操作 1.5红黑树的验证 1.6红黑树的删除 1.7红黑树与AVL树的比较 1.8红黑树的应用 1.红黑树 1.1红黑树的概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存储位…

系统架构:分而治之

系统架构&#xff1a;分而治之 引言“分而治之”在架构中的应用模块化设计分层化架构微服务架构 分而治之的优势降低复杂性提高灵活性和可扩展性增强可维护性促进团队协作 分而治之的劣势复杂性转移性能开销开发和运维的复杂性数据一致性挑战 结论 引言 “分而治之”是一种分析…

修改Patroni ttl和retry_timeout

参数解释 修改 & 查看 https://www.cnblogs.com/linyouyi/p/15714010.html

58.区间和

58.区间和 //卡码网题号58.区间和 /* //如果我查询m次&#xff0c;每次查询的范围都是从0到n-1&#xff0c;那么该算法的时间复杂度是O(n*m)&#xff0c; //如果查询次数非常大的话&#xff0c;这个时间复杂度也是非常大的。 #include<iostream> #include<vector> …