[React]Antd Upload组件上传多个文件

前言

实现需求:上传多个文件。其实就是获取多个文件的绝对路径交给后端接口去处理。

Upload组件

首先,这里不能调用Upload的onChange函数,因为上传中、完成、失败都会调用这个函数,在多个文件的情况下会出现多次调用问题。改用beforeUpload和customRequest。

import React, { useRef, useState, useEffect } from 'react';
import { UploadOutlined } from '@ant-design/icons';
import type { UploadFile, UploadProps } from 'antd';
import { Button, Upload } from 'antd';
import { useTranslation } from 'react-i18next';
import Console from '../../../../util/Console';
import { UploadChangeParam } from 'antd/es/upload';
import { sendMsgToMain } from 'electron-prokit';type Props = {name?: string;onChangeFilePath: (path: string | null | unknown, info?: UploadChangeParam<UploadFile<any>>) => void;accept: Array<string>;headers?: any;progress?: any;buttonTitle?: string;rest?: UploadProps;action?: string | ((file: any) => Promise<string>);
};const FileMultiSelectButton: React.FC<Props> = ({name,onChangeFilePath,accept,headers,progress = null,buttonTitle,action,...rest
}) => {const { t } = useTranslation();const fileState: any = useRef();const [uploadFiles, setUploadFiles] = useState<UploadFile[]>([]);const updateFiles = (function () {let fileList: UploadFile[] | null = null;return function (list: UploadFile[], setState: React.Dispatch<React.SetStateAction<UploadFile[]>>) {if (!fileList) {fileList = list;setState && setState(list);}return {fileList,reset() {fileList = null;}};};})();const beforeUpload = (_: any, fileList: UploadFile[]) => {fileState.current = updateFiles(fileList, setUploadFiles);return false;}const customRequest = () => {if (uploadFiles.length > 0) {const path = uploadFiles.map(item => (item as any).path);// 这是electron的ipc处理函数,在node中复制文件sendMsgToMain({ key: 'fileMultiSelectPath', data: path }).then(filePath => {if (typeof onChangeFilePath === 'function') {onChangeFilePath(filePath);} else {Console.handleErrorMsg('onChangeFilePath is not a function');}});} else {Console.handleWarningMsg('no file uploaded');}}useEffect(() => {if (uploadFiles.length > 0) {customRequest();fileState.current.reset();}}, [uploadFiles]);return (<Uploadname={name || 'file'}accept={accept.join(',')}progress={progress}showUploadList={false}headers={headers}action={action}multiple={true}beforeUpload={beforeUpload}customRequest={customRequest}{...rest}><Button icon={<UploadOutlined />}> {buttonTitle || t('Select')} </Button></Upload>);
};export default FileMultiSelectButton;

在node中处理(不必须),这里主要因为electron需要兼容不同的平台,需要处理文件路径

function generateRandomString(length: number) {let result = '';const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';const charactersLength = characters.length;for (let i = 0; i < length; i++) {result += characters.charAt(Math.floor(Math.random() * charactersLength));}return result;
}
const fileSelectPath = (sourcePath: string) => {return new Promise((resolve, reject) => {const userDataPath = app.getPath('userData');// 获取用户数据目录,并在该目录下创建文件夹,用于保存用户数据,需要判断是否存在,如果存在则直接使用,否则创建,并返回该目录,用于后续操作,并需要兼容跨平台,比如windows和mac// 拼接出 files 目录的完整路径const filesDirPath = path.join(userDataPath, 'files');fs.mkdir(filesDirPath, { recursive: true }, err => {if (err) {// 如果目录创建失败,返回错误信息// 如果目录创建失败,处理错误console.error('Failed to create files directory:', err);}// 生成一个随机数const randomBytes = generateRandomString(8); // 生成8字节的随机数// 获取当前日期和时间const date = new Date();const formattedDate = date.toISOString().split('T')[0].replace(/-/g, ''); // 格式化为不含破折号的日期const formattedTime = date.toTimeString().split(' ')[0].replace(/:/g, ''); // 格式化为不含冒号的时间// 提取源文件名和扩展名const { name, ext } = path.parse(sourcePath);// 根据日期、时间和随机数生成一个新的文件名const newName = `${name}_${formattedDate}_${formattedTime}_${randomBytes}${ext}`;// 构造目标路径const destinationPath = path.join(filesDirPath, newName);// 使用fs模块的copy方法复制文件fs.copyFile(sourcePath, destinationPath, err => {if (err) {// 如果文件已存在或复制失败,返回错误信息reject(err);} else {// 复制成功,返回新的文件路径resolve(destinationPath);}});});});
};export const fileMultiSelectPath = (sourcePath: Array<string>) => {return Promise.all(sourcePath.map(async (sourcePath) => {return await fileSelectPath(sourcePath);}));
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java-多态

多态是 Java 面向对象三大特性&#xff08;封装、继承、多态&#xff09;中最灵活也最核心的概念之一。它允许我们用统一的方式处理不同的对象&#xff0c;大幅提升代码的扩展性和复用性。本文将结合实际案例&#xff0c;从概念、实现到应用&#xff0c;全面解析 Java 多态的核…

Redis常规指令及跳表

第一部分&#xff1a;Redis 常规指令Redis 是一个键值存储系统&#xff0c;其指令通常以 COMMAND KEY_NAME [ARGUMENTS...] 的形式存在。下面我们按照数据结构和功能来分类。1. 全局/键操作指令这些指令不特定于某一数据类型&#xff0c;适用于所有键。指令描述示例KEYS patter…

指纹云手机×Snapchat Spotlight:动态GPS+陀螺仪仿生方案

——基于时空坐标系重构与生物运动模拟的AR营销突破​​一、Snapchat Spotlight广告的技术困局​设备指纹关联风险​Snapchat通过陀螺仪基线值&#xff08;0.1误差&#xff09;和GPS坐标&#xff08;精度&#xff1c;5米&#xff09;构建设备指纹&#xff0c;相似度&#xff1e…

Java 编辑器与 IDE:开发者手中的利剑与盾牌

&#x1f525;个人主页&#xff1a;艾莉丝努力练剑 ❄专栏传送门&#xff1a;《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、洛谷刷题、C/C基础知识知识强化补充、C/C干货分享&学习过程记录 &#x1f349;学习方向&#xff1a;C/C方向学习者…

不再让Windows更新!Edge游戏助手卸载及关闭自动更新

文章目录Windows系统更新问题方法一&#xff1a;通过注册表手动设置1. 打开注册表编辑器2. 定位到目标路径3. 创建新的DWORD值4. 修改数值方法二&#xff1a;命令行设置1. 打开命令提示符2. 输入命令验证设置是否生效恢复更新Edge关闭游戏助手Edge关闭后台运行Edge关闭自动更新…

从Android到鸿蒙:一场本应无缝的转型-优雅草卓伊凡

从Android到鸿蒙&#xff1a;一场本应无缝的转型-优雅草卓伊凡看到Android开发者询问如何转向鸿蒙&#xff0c;卓伊凡不禁摇头&#xff1a;真正的Android工程师根本不需要“学习”鸿蒙&#xff0c;只需要简单查阅文档即可。近年来&#xff0c;随着鸿蒙系统的不断发展&#xff0…

Linux的线程概念与控制

目录 1、Linux的线程概念 1.1 什么是线程 1.2 分页式存储管理 1.3 线程的优点 1.4 线程的缺点 3、Linux的线程控制 3.1 POSIX线程库 3.2 线程创建 3.3 线程退出 3.4 线程等待 3.5 线程分离 1、Linux的线程概念 1.1 什么是线程 首先Linux内核不区分"进程"…

云原生俱乐部-RH294知识点归纳(3)

其实ansible还剩下使用角色和ansible内容集合来简化playbook、对ansible进行故障排除和自动执行Linux管理任务三部分。至于如何对ansible进行故障排除&#xff0c;只有在生产中碰到了故障才用得上&#xff0c;并且即使碰上的还是需要具体问题具体分析&#xff0c;但是可以该部分…

Flink 实时加购数据“维表补全”实战:从 Kafka 到 HBase 再到 Redis 的完整链路

一、业务背景 在电商实时运营场景中&#xff0c;加购行为&#xff08;AddShoppingCart&#xff09; 是最核心的用户行为之一&#xff0c;每秒钟可能产生数万条加购事件。以某头部电商平台为例&#xff0c;大促期间加购QPS可突破50万。 为了支持实时推荐、实时营销、实时大屏等业…

【数据结构】二叉树的顺序存储、堆的实现及其应用:堆排序与Top-K问题

二叉树的顺序存储、堆的实现及其应用&#xff1a;堆排序与Top-K问题 ✨前言&#xff1a;在上一节【树与二叉树】中&#xff0c;我们已经了解了二叉树的基本结构与存储方式。 本篇文章将更进一步&#xff0c;重点介绍 二叉树的顺序结构&#xff0c;并在此基础上引出一个重要的数…

SpringBoot 快速上手:从环境搭建到 HelloWorld 实战

在 Java 开发领域&#xff0c;Spring 框架占据着举足轻重的地位&#xff0c;但它复杂的配置曾让不少开发者望而却步。SpringBoot 的出现&#xff0c;如同为 Spring 框架装上了 “加速器”&#xff0c;以 “约定大于配置” 的理念简化了开发流程。本文将从环境准备、Maven 配置入…

一键部署开源 Coze Studio

文章目录一、简介1、什么是 Coze Studio2、参考地址二、安装部署1、安装docker2、安装git3、下载core4、配置公网可用5、登录成功一、简介 1、什么是 Coze Studio Coze Studio 是一站式 AI Agent 开发工具。提供各类最新大模型和工具、多种开发模式和框架&#xff0c;从开发到…