当前位置: 首页 > news >正文

【图文并茂】ant design pro 如何优雅地把删除和批量删除功能合并到一起,并抽出来成为组件

在这里插入图片描述
在这里插入图片描述
如上图所示,其实批量删除和删除应该算是一个功能

只是删除一个或多个的区别

那么接口应该用的同一个

删除一个的时候呢,就传 一个对象_id 过去

删除多个的时候,就传 多个 对象 _id 的数组过去

后端

在这里插入图片描述

const deleteMultipleRoles = handleAsync(async (req: Request, res: Response) => {const { ids } = req.body;await Role.deleteMany({_id: { $in: ids },}).exec();res.json({success: true,message: `${ids.length} roles deleted successfully`,});
});export {getRoles,getRoleById,addRole,updateRole,deleteRole,deleteMultipleRoles,
};

后端用的同一个接口

前端

删除一个

在这里插入图片描述

  <DeleteLinkonOk={async () => {await handleRemove([record._id!]);setSelectedRows([]);actionRef.current?.reloadAndRest?.();}}/>

DeleteLink 的代码我封装好了

import { Modal } from 'antd';
import { useIntl } from '@umijs/max';interface DeleteLinkProps {onOk: () => Promise<void>;
}const DeleteLink: React.FC<DeleteLinkProps> = ({ onOk }) => {const intl = useIntl();return (<akey="delete"onClick={() => {return Modal.confirm({title: intl.formatMessage({ id: 'confirm_delete' }),onOk,content: intl.formatMessage({ id: 'confirm_delete_content' }),okText: intl.formatMessage({ id: 'confirm' }),cancelText: intl.formatMessage({ id: 'cancel' }),});}}>{intl.formatMessage({ id: 'delete' })}</a>);
};export default DeleteLink;

请求方法在下在面:

/***  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('/roles', {ids,});hide();message.success(<FormattedMessageid="delete_successful"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;}
};

还有

export async function removeItem(url: string, options?: { [key: string]: any }) {return request<Record<string, any>>(url, {method: 'DELETE',data: {...(options || {}),},});
}

删除多个

在这里插入图片描述

<FooterToolbarextra={<div><FormattedMessage id="pages.searchTable.chosen" defaultMessage="Chosen" />{' '}<a style={{ fontWeight: 600 }}>{selectedRowsState.length}</a>{' '}<FormattedMessage id="pages.searchTable.item" defaultMessage="项" /></div>}>{(access.canSuperAdmin || access.canDeleteRole) && (<DeleteButtononOk={async () => {await handleRemove(selectedRowsState?.map((item: any) => item._id!));setSelectedRows([]);actionRef.current?.reloadAndRest?.();}}/>)}</FooterToolbar>

DeleteButton 的代码也封装好的

import { Button, Modal } from 'antd';
import { FormattedMessage, useIntl } from '@umijs/max';interface DeleteButtonProps {onOk: () => Promise<void>;
}const DeleteButton: React.FC<DeleteButtonProps> = ({ onOk }) => {const intl = useIntl();return (<ButtondangeronClick={() => {return Modal.confirm({title: intl.formatMessage({ id: 'confirm_delete' }),onOk: onOk,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>);
};export default DeleteButton;

最后 index.tsx 完整代码:

import { useIntl } from '@umijs/max';
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, ProFormText, ProTable } from '@ant-design/pro-components';
import { FormattedMessage, useAccess } from '@umijs/max';
import { Button, message } 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 DeleteButton from '@/components/DeleteButton';
import DeleteLink from '@/components/DeleteLink';/*** @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('/roles', { ...fields });hide();message.success(<FormattedMessage id="add_successful" defaultMessage="Added successfully" />);return true;} catch (error: any) {hide();message.error(error?.response?.data?.message ?? (<FormattedMessage id="upload_failed" defaultMessage="Upload 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(`/roles/${fields._id}`, fields);hide();message.success(<FormattedMessage id="update_successful" defaultMessage="Update successful" />);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('/roles', {ids,});hide();message.success(<FormattedMessageid="delete_successful"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 [batchUploadPriceModalOpen, setBatchUploadPriceModalOpen] = useState<boolean>(false);const actionRef = useRef<ActionType>();const [currentRow, setCurrentRow] = useState<API.ItemData>();const [selectedRowsState, setSelectedRows] = useState<API.ItemData[]>([]);const [showDetail, setShowDetail] = useState<boolean>(false);const access = useAccess();/*** @en-US International configuration* @zh-CN 国际化配置* */// Define roles object with index signatureconst columns: ProColumns<API.ItemData>[] = [{title: intl.formatMessage({ id: 'name' }),dataIndex: 'name',copyable: true,renderFormItem: (item, { ...rest }) => {return <ProFormText {...rest} placeholder={intl.formatMessage({ id: 'enter_name' })} />;},render: (dom, entity) => {return (<aonClick={() => {setCurrentRow(entity);setShowDetail(true);}}>{dom}</a>);},},{title: intl.formatMessage({ id: 'permissions_list' }),dataIndex: 'permissions',hideInSearch: true,hideInTable: true,renderText: (val: { name: string }[]) => {return val.map((item) => item.name).join(', ');},},{title: <FormattedMessage id="pages.searchTable.titleOption" defaultMessage="Operating" />,dataIndex: 'option',valueType: 'option',render: (_, record) => [access.canSuperAdmin && (<akey="edit"onClick={() => {// Replace `handleUpdateModalOpen` and `setCurrentRow` with your actual functionshandleUpdateModalOpen(true);setCurrentRow(record);}}>{intl.formatMessage({ id: 'edit' })}</a>),access.canSuperAdmin && (<DeleteLinkonOk={async () => {await handleRemove([record._id!]);setSelectedRows([]);actionRef.current?.reloadAndRest?.();}}/>),],},];return (<PageContainer><ProTable<API.ItemData, API.PageParams>headerTitle={intl.formatMessage({ id: 'list' })}actionRef={actionRef}rowKey="_id"search={{labelWidth: 100,}}toolBarRender={() => [(access.canSuperAdmin || access.canUpdateRole) && (<Buttontype="primary"key="primary"onClick={() => {handleModalOpen(true);}}><PlusOutlined /> <FormattedMessage id="pages.searchTable.new" defaultMessage="New" /></Button>),]}request={async (params, sort, filter) => queryList('/roles', params, sort, filter)}columns={columns}rowSelection={access.canSuperAdmin && {onChange: (_, selectedRows) => {setSelectedRows(selectedRows);},}}/>{selectedRowsState?.length > 0 && (<FooterToolbarextra={<div><FormattedMessage id="pages.searchTable.chosen" defaultMessage="Chosen" />{' '}<a style={{ fontWeight: 600 }}>{selectedRowsState.length}</a>{' '}<FormattedMessage id="pages.searchTable.item" defaultMessage="项" /></div>}>{(access.canSuperAdmin || access.canDeleteRole) && (<DeleteButtononOk={async () => {await handleRemove(selectedRowsState?.map((item: any) => item._id!));setSelectedRows([]);actionRef.current?.reloadAndRest?.();}}/>)}</FooterToolbar>)}{(access.canSuperAdmin || access.canCreateRole) && (<Createopen={createModalOpen}onOpenChange={handleModalOpen}onFinish={async (value) => {const success = await handleAdd(value as API.ItemData);if (success) {handleModalOpen(false);if (actionRef.current) {actionRef.current.reload();}}}}/>)}{(access.canSuperAdmin || access.canUpdateRole) && (<UpdateonSubmit={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 || {}}/>)}<Showopen={showDetail}currentRow={currentRow as API.ItemData}columns={columns as ProDescriptionsItemProps<API.ItemData>[]}onClose={() => {setCurrentRow(undefined);setShowDetail(false);}}/></PageContainer>);
};export default TableList;

完结

  • 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 技巧之实现列表页多标签
  • 【图文并茂】ant design pro 如何对接登录接口
  • 【图文并茂】ant design pro 如何对接后端个人信息接口
  • 【图文并茂】ant design pro 如何给后端发送 json web token - 请求拦截器的使用
  • 【图文并茂】ant design pro 如何使用 refresh token 可续期 token 来提高用户体验
  • 【图文并茂】ant design pro 如何统一封装好 ProFormSelect 的查询请求
  • 【图文并茂】ant design pro 如何优雅地实现查询列表功能

获取 ant design pro & nodejs & typescript 多角色权限动态菜单管理系统源码
我正在做的程序员赚钱副业 - Shopify 真实案例技术赚钱营销课视频教程

相关文章:

【图文并茂】ant design pro 如何优雅地把删除和批量删除功能合并到一起,并抽出来成为组件

如上图所示&#xff0c;其实批量删除和删除应该算是一个功能 只是删除一个或多个的区别 那么接口应该用的同一个 删除一个的时候呢&#xff0c;就传 一个对象_id 过去 删除多个的时候&#xff0c;就传 多个 对象 _id 的数组过去 后端 const deleteMultipleRoles handleAs…...

监控篇之利用dcgm-exporter监控GPU指标并集成grafana大盘

一、应用场景 当环境中包含GPU节点时&#xff0c;需要了解GPU应用使用节点GPU资源的情况&#xff0c;例如GPU利用率、显存使用量、GPU运行的温度、GPU的功率等。 在获取GPU监控指标后&#xff0c;用户可根据应用的GPU指标配置弹性伸缩策略&#xff0c;或者根据GPU指标设置告警…...

获取当前路由器的外网IP(WAN IP)

GPT-4o (OpenAI) 获取当前路由器的外网IP&#xff08;WAN IP&#xff09;可以通过以下几种方法&#xff1a; 1. 访问路由器管理页面&#xff1a; - 通常路由器的管理页面可以通过在浏览器中输入路由器的IP地址来访问&#xff08;例如&#xff0c;192.168.0.1 或 192.168.1…...

QT Creator UI中文输入跳出英文

笔者用的是QQ拼音输入&#xff0c;发现只要在UI中加入了QTableWidget&#xff0c;输入多几次中文&#xff0c;就会跳入英文。 后面改用搜狗拼音稍微好一些&#xff0c;但是偶尔还是插入了空格。...

Java基础核心知识学习笔记

方法重载 请记住下面重载的条件 方法名称必须相同。参数列表必须不同&#xff08;个数不同、或类型不同、参数类型排列顺序不同等&#xff09;。方法的返回类型可以相同也可以不相同。仅仅返回类型不同不足以成为方法的重载。重载是发生在编译时的&#xff0c;因为编译器可以根…...

Leetcode 237.19.83.82 删除链表重复结点 C++实现

Leetcode 237. 删除链表中的节点 问题&#xff1a;有一个单链表的head&#xff0c;我们想删除它其中的一个节点node。给你一个需要删除的节点 node 。你将 无法访问 第一个节点head。链表的所有值都是唯一的&#xff0c;并且保证给定的节点 node不是链表中的最后一个节点。删除…...

Spring OAuth2.0资源服务源码解析

主要分析spring-security-oauth2-resource-server的源码&#xff0c;介绍OAuth2.0授权码模式下Spring Boot OAuth2资源服务的运行流程&#xff0c;分析其是如何对令牌进行认证的&#xff0c;并展示资源服务配置 代码版本信息 Spring Boot 2.7.10 spring-security-oauth2-resou…...

JavaScript 原型与原型链

原型与原型链 要讨论原型与原型链&#xff0c;就要先了解什么是 构造函数 &#xff0c;构造函数与普通函数没有太大的区别&#xff0c;使用 new关键字 创建实例对象的函数&#xff0c;就叫做构造函数。 在js中&#xff0c;每一个函数类型的数据都有一个 .prototype 的属性&am…...

Spring Boot实现简单的Oracle数据库操作

使用到的技术&#xff1a; 1. Spring Boot&#xff1a;用于简化Spring应用的开发。 2. Dynamic DataSource&#xff1a;实现动态多数据源的访问和切换 3. Oracle JDBC Driver&#xff1a;与Oracle数据库进行连接和交互。 4. Mybatis-Plus&#xff1a;简化SQL映射和数据库访问。…...

微软发布 Phi-3.5 系列模型,涵盖端侧、多模态、MOE;字节 Seed-ASR:自动识别多语言丨 RTE 开发者日报

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE&#xff08;Real-Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…...

笔记:Echarts柱状图 实现滚轮条 数据太多

效果&#x1f447;&#x1f447;&#x1f447; 配置&#xff1a;&#x1f447; let option {dataZoom: [{type: "slider",show: true,zoomLock: true,start: 0,end: 20,bottom: 60,height: 10,textStyle: {color: "transparent",fontSize: 9,},fillerColo…...

嵌入式学习day17(数据结构)

大纲 数据结构、算法数据结构&#xff1a; 1. 线性表&#xff1a;顺序表、链表&#xff08;单向链表&#xff0c;单向循环链表&#xff0c;双向链表&#xff0c;双向循环链表&#xff09;、栈&#xff08;顺序栈&#xff0c;链式栈&#xff09;、队列&#xff08;循…...

网站怎么做敏感词过滤,敏感词过滤的思路和实践

敏感词过滤是一种在网站、应用程序或平台中实现内容审查的技术&#xff0c;用于阻止用户发布包含不适当、非法或不符合政策的内容。我们在实际的网站运营过程中&#xff0c;往往需要担心某些用户发布的内容中包含敏感词汇&#xff0c;这些词汇往往会导致我们的网站被用户举报&a…...

【峟思】如何使用投入式水位计才能确保测量准确性

在水利、环保、工业监测等众多领域&#xff0c;水位测量是一项至关重要的任务&#xff0c;它不仅直接关系到水资源的合理利用与保护&#xff0c;还影响到防洪、供水、排水等多个方面的安全与效率。投入式水位计作为一种常见的水位测量工具&#xff0c;以其结构简单、测量准确、…...

供应链管理系统(SCM) —— 企业物流的智能枢纽

SAP 供应链管理系统以打造数字化和集成化的供应链管理平台为使命&#xff0c;将传统的仓储管理系统、制造执行系统、产品管理系统等软件进行升级和上云管理&#xff0c;为企业提供面向客户、合作伙伴及员工的数字化SCM系统平台。 SAP SCM系统从设计到运维&#xff0c;全面优化供…...

计算机视觉(CV)技术的优势和挑战。

计算机视觉&#xff08;CV&#xff09;技术在许多领域中具有广泛的应用&#xff0c;并且具有一些优势和挑战。 优势&#xff1a; 1. 高效性&#xff1a;CV技术能够快速处理大量的图像和视频数据&#xff0c;以实现实时的分析和决策。 2. 自动化&#xff1a;CV技术可以自动化地…...

数据库MySQL多表设计、查询

目录 1.概述 2.一对多 3.一对一 4.多对多 5.多表查询 5.1内连接 5.2外连接 5.3子查询 1.概述 项目开发中,在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结构&#xff0c;由于业务之间相互关联&#xff0c;所以各个…...

基于vue框架的北城招聘管理平台题目7lly3(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;用户,企业,企业信息,职位类型,职位信息,简历信息,职位应聘,求职意愿,面试信息,录取信息,实习信息,冻结信息,解冻信息 开题报告内容 基于Vue框架的北城招聘管理平台 开题报告 一、引言 随着互联网的飞速发展和企业对人才需求的不断增…...

详讲C#中如何存储当前项目的设置-超级简单省事

我们在编写软件的时候总有一些配置数据需要保存&#xff0c;比如用户选择的偏好设置&#xff0c;又如软件所用到的数据库文件等。我们有很多中方式都可以保存&#xff0c;比如直接保存在某个文本文件&#xff0c;或者ini文件中&#xff0c;其实最简单的办法是保存在项目的资源文…...

【QT文件操作】---xml文件读取

XML&#xff08;可扩展标记语言&#xff0c;eXtensible Markup Language&#xff09;是一种用于存储和传输数据的文本格式&#xff0c;广泛用于配置文件、数据交换和文档表示。XML 文件具有明确的结构和标记&#xff0c;这使得它能够描述复杂的层次结构和数据关系。 xml和html…...

基于FPGA的PID算法学习———实现PID比例控制算法

基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容&#xff1a;参考网站&#xff1a; PID算法控制 PID即&#xff1a;Proportional&#xff08;比例&#xff09;、Integral&#xff08;积分&…...

VB.net复制Ntag213卡写入UID

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?ftt&id615391857885 一、读取旧Ntag卡的UID和数据 Private Sub Button15_Click(sender As Object, e As EventArgs) Handles Button15.Click轻松读卡技术支持:网站:Dim i, j As IntegerDim cardidhex, …...

多场景 OkHttpClient 管理器 - Android 网络通信解决方案

下面是一个完整的 Android 实现&#xff0c;展示如何创建和管理多个 OkHttpClient 实例&#xff0c;分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...

【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具

第2章 虚拟机性能监控&#xff0c;故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令&#xff1a;jps [options] [hostid] 功能&#xff1a;本地虚拟机进程显示进程ID&#xff08;与ps相同&#xff09;&#xff0c;可同时显示主类&#x…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

HDFS分布式存储 zookeeper

hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架&#xff0c;允许使用简单的变成模型跨计算机对大型集群进行分布式处理&#xff08;1.海量的数据存储 2.海量数据的计算&#xff09;Hadoop核心组件 hdfs&#xff08;分布式文件存储系统&#xff09;&a…...

springboot整合VUE之在线教育管理系统简介

可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生&#xff0c;小白用户&#xff0c;想学习知识的 有点基础&#xff0c;想要通过项…...

Linux nano命令的基本使用

参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时&#xff0c;显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...