React+umi+antdesign实现上传文件组件(阿里云)

news/2024/7/15 17:20:13 标签: react.js, 阿里云, javascript

开始之前需要封装一个上传的方法fileUtils.ts

javascript">import { message } from 'antd';
import Base64 from 'crypto-js/enc-base64';
import Utf8 from 'crypto-js/enc-utf8';
import HmacSHA1 from 'crypto-js/hmac-sha1';
import { request } from 'umi';

const isDev = process.env.NODE_ENV === 'development';

export namespace FileUtil {
  const env = {
    timeout: 10000,
    uploadHost: 'https://hopeman.oss-cn-beijing.aliyuncs.com/',
  };

  const genPolicy = () => {
    const date = new Date();
    date.setHours(date.getHours() + env.timeout);
    const srcT = date.toISOString();
    const policyText = {
      expiration: srcT,
      conditions: [
        ['content-length-range', 0, 1 * 1024 * 1024 * 1024], // 设置上传文件的大小限制1G
      ],
    };
    const rawStr = JSON.stringify(policyText);
    const wordArray = Utf8.parse(rawStr);
    const policyBase64 = Base64.stringify(wordArray);
    return policyBase64;
  };

  const genSignature = (policyBase64: string, accessKey: string) => {
    const byte = HmacSHA1(policyBase64, accessKey);
    const signature = Base64.stringify(byte);
    return signature;
  };

  export const upload = async (options: any, dir?: string): Promise<string> => {
    const fileInfo = options.file;
    const { onError = () => {}, onSuccess = () => {}, fullHost = '', ext = false } = options;

    return new Promise(async (resolve) => {
      const res = await request('/common/ram/assumeRole', {
        method: 'POST',
      });

      if (res?.code === 200 && res?.data) {
        const {
          Credentials: { AccessKeyId, AccessKeySecret, SecurityToken },
        } = res.data;

        const fileNameSplit = fileInfo?.name.split('.') || [];
        const aliyunFileKey = `${dir ?? 'excel'}/event_${new Date().getTime()}${
          ext ? '.' + fileNameSplit[fileNameSplit?.length - 1] : ''
        }`; //文件命名

        const policyBase64 = genPolicy();
        const signature = genSignature(policyBase64, AccessKeySecret);

        const data = new FormData();
        data.append('key', aliyunFileKey);
        data.append('policy', policyBase64);
        data.append('OSSAccessKeyId', AccessKeyId);
        data.append('signature', signature);
        data.append('x-oss-security-token', SecurityToken);
        data.append('file', fileInfo);
        data.append('success_action_status', '200');

        try {
          await request(isDev ? '/upload' : UPLOAD_HOST, {
            method: 'POST',
            data,
          });
          const url = `${fullHost}${aliyunFileKey}`;
          onSuccess(url);
          resolve(url);
        } catch (e) {
          onError(options);
          resolve('');
        }
      } else {
        message.error('上传失败');
        onError(options);
        resolve('');
      }
    });
  };

  export const base64CoverFile = (dataUrl: string) => {
    /**
     * base64 转 File
     * @param data
     */
    const arr = dataUrl.split(','),
      mime = arr?.[0]?.match(/:(.*?);/)?.[1],
      bstr = atob(arr[1]);

    let n = bstr.length;
    const u8arr = new Uint8Array(n);
    while (n--) {
      u8arr[n] = bstr.charCodeAt(n);
    }
    const blob = new Blob([u8arr], { type: mime });
    // blob.lastModifiedDate = new Date(); // 文件最后的修改日期
    // blob.name = fileName; // 文件名
    return new File([blob], Date.now().toString(), { type: blob.type, lastModified: Date.now() });
  };
  // 浏览器本页下载文件
  export const downFileByUrl = (url: string) => {
    if (!url || url.length === 0) {
      message.error('url 不存在');
      return;
    }
    const a = document.createElement('a');
    a.setAttribute('href', url);
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
  };

  export const downMultipleFileByUrl = (urls: string[]) => {
    if (!urls || urls.length === 0) {
      message.error('url 不存在');
      return;
    }
    for (let i = 0; i < urls.length; i++) {
      const iframe = document.createElement('iframe');
      iframe.style.display = 'none'; // 防止影响页面
      // @ts-ignore
      iframe.style.height = 0; // 防止影响页面
      iframe.src = urls[i];
      document.body.appendChild(iframe);
      // 5分钟之后删除
      setTimeout(() => {
        iframe.remove();
      }, 5 * 60 * 1000);
    }
  };
}

javascript">//AliyunOssUpload 组件
import { FileUtil } from '**/fileUtils';
import { PlusOutlined, UploadOutlined } from '@ant-design/icons';
import type { UploadProps } from 'antd';
import { Button, Image, message, Upload } from 'antd';
import type { RcFile } from 'antd/lib/upload';
import type { UploadFile } from 'antd/lib/upload/interface';
import filesize from 'filesize';
import type { FC, ReactElement } from 'react';
import React, { Fragment, useState } from 'react';
import styles from './styles.less';

export type AliyunOssUploadProps = UploadProps & {
  value?: any;
  fullHost?: string | boolean; // 阿里云的Host,默认只返回目录,当 true 时,默认的是 UPLOAD_HOST
  limitSize?: number; // 文件大小限制单位 bytes(B) 默认是 2 * 1024 * 1024(2M) 0 表示不限制
  ext?: boolean; // 阿里云文件路径中是否包含文类后续名, 默认不包含文件类型后缀
  buttonRef?: any;
  readOnly?: boolean;
  uploadButtonRender?: ReactElement;
  maxCount?: number;
};

const UploadImageButton = React.forwardRef((props, ref: any) => {
  return (
    <div ref={ref} className={'aliyunUpBtn'}>
      <PlusOutlined className={'aliyunUpIcon'} />
      <div className={'aliyunUpTitle'} style={{ marginTop: 8 }}>
        上传图片
      </div>
    </div>
  );
});

const UploadNormalButton = React.forwardRef((props, ref: any) => (
  <Button ref={ref} icon={<UploadOutlined />}>
    点击上传
  </Button>
));

const AliyunOssUpload: FC<AliyunOssUploadProps> = (props) => {
  const [previewVisible, setPreviewVisible] = useState(false);
  const [previewSrc, setPreviewSrc] = useState('');
  let { fullHost = '' } = props;
  const {
    ext = false,
    disabled,
    buttonRef,
    readOnly = false,
    maxCount = 1,
    uploadButtonRender,
  } = props;

  fullHost = typeof fullHost === 'boolean' ? (fullHost ? UPLOAD_HOST : '') : fullHost;

  const uploadProps: UploadProps = {
    listType: 'picture-card',
    headers: {
      authorization: 'authorization-text',
    },
    maxCount: maxCount,
    customRequest: (options) => FileUtil.upload({ ...options, fullHost, ext }),
    onPreview: (file: UploadFile) => {
      const src = file?.response || file?.thumbUrl;
      if (src) {
        setPreviewSrc(src);
        setPreviewVisible(true);
      }
    },
    defaultFileList: props?.value?.fileList?.map((item: any) => ({
      uid: item?.uid,
      name: item?.url,
      url: item?.url,
      response: item?.url,
      thumbUrl: item?.url,
    })),
    beforeUpload: async (file: RcFile) => {
      const initAccept = props?.accept || 'image/png,image/jpg,image/jpeg';
      const accept = initAccept.split(',');

      const limitSize = props?.limitSize ?? 1024 * 1024 * 2;
      const isValidType = accept?.includes(file.type);
      const isValidSize = limitSize ? file.size < limitSize : true;
      if (!isValidType) {
        await message.error(`仅支持 ${initAccept} 格式`);
      }
      if (!isValidSize) {
        await message.error(
          `图片大小不能超过 ${filesize(limitSize, { base: 2, standard: 'jedec' })}`,
        );
      }
      return (isValidType && isValidSize) || Upload.LIST_IGNORE;
    },
    showUploadList: { showRemoveIcon: !readOnly },
    ...props,
  };

  const uploadButton = () => {
    if (readOnly || disabled) {
      return;
    }
    if (uploadProps?.maxCount) {
      if (props?.value?.fileList?.length >= uploadProps.maxCount) {
        return null;
      } else {
        if (uploadButtonRender) return uploadButtonRender;
        return props.listType === 'picture-card' || 'picture' ? (
          <UploadImageButton ref={buttonRef} />
        ) : (
          <UploadNormalButton ref={buttonRef} />
        );
      }
    } else {
      if (uploadButtonRender) return uploadButtonRender;
      return props.listType === 'picture-card' || 'picture' ? (
        <UploadImageButton ref={buttonRef} />
      ) : (
        <UploadNormalButton ref={buttonRef} />
      );
    }
  };

  if (!props.value?.fileList?.length && disabled) return <>-</>;

  return (
    <Fragment>
      <Upload className={styles.uploadBox} {...uploadProps}>
        {uploadButton()}
      </Upload>
      <div style={{ fontSize: 0, position: 'absolute' }}>
        <Image
          width={200}
          style={{ display: 'none' }}
          src={previewSrc}
          preview={{
            visible: previewVisible,
            src: previewSrc,
            onVisibleChange: (val) => {
              setPreviewVisible(val);
            },
          }}
        />
      </div>
    </Fragment>
  );
};

export default AliyunOssUpload;

在页面中使用 时

javascript"><AliyunOssUpload
	accept={'image/png,image/jpg,image/jpeg'}
	fullHost
	maxCount={5} //根据业务需求填写
	listType={'picture-card'}
	limitSize={1024 * 1024 * 5} //根据业务需求填写
 />

http://www.niftyadmin.cn/n/5287391.html

相关文章

k8s:kubernets

自动部署、自动扩展和管理的容器化部署的应用程序的一个开源系统 k8s负责自动化运维管理多个容器化程序的集群&#xff0c;是一个功能强大的容器编排工具 可以以分布式和集群化的方式进行容器管理 1.18版本&#xff0c;目前最多的是1.20版本&#xff0c;最新的是1.29版本&am…

序列化与作用

一.概念 当我们谈论序列化时&#xff0c;实际上是在讨论如何把一个对象转换成一种持久化或可传输的形式。这个过程需要把对象的状态信息写入某种能够存储或传输的方式&#xff0c;以后能够重新创建这个对象 对于解析JSON字符串也有序列化和反序列化&#xff1a; 反序列化&am…

2024深入评测CleanMyMac X4.14.6破解版新的功能

随着时间的推移&#xff0c;我们的Mac电脑往往会变得越来越慢&#xff0c;存储空间变得越来越紧张&#xff0c;这时候一个优秀的清理工具就显得尤为重要。作为一款备受好评的Mac清理工具&#xff0c;它能够为你的Mac带来全方位的清理和优化。在本文中&#xff0c;我们将深入评测…

【Arthas】Arthas线上trace匿名函数/Lambda表达式/函数式接口

目录 前言阅读对象先说结论RT问题解决思路&#xff08;拓展&#xff0c;不感兴趣可以跳过&#xff09;解决办法步骤一&#xff1a;安装字节码查看插件步骤二&#xff1a;查看字节码文件步骤三&#xff1a;trace匿名函数 感谢 前言 Arthas是一个非常牛B的东西&#xff0c;我非常…

本机ping不通虚拟机

windows下finall shell连不上虚拟机了&#xff0c;之前是可以的&#xff0c;然后ping虚拟机&#xff0c;发现也ping不通&#xff0c;随后到处找问题。 在本地部分&#xff0c;控制面板 ——>网络和Internet——>网络连接 &#xff0c; 可以看到 VMnet1和Vmnet8虽然都是已…

【软件工程】可执行文件和数据分离

一、概述 可执行文件和数据分离是一种软件设计策略&#xff0c;旨在将程序代码和程序使用的数据分离存储。这种方法通常用于提高软件的模块化程度和灵活性&#xff0c;以及方便软件的管理和维护。 在可执行文件和数据分离中&#xff0c;程序代码通常以可执行文件的形式存储&a…

TensorFlow层次结构中的三种计算图

三种计算图 所谓计算图&#xff0c;计算图由节点&#xff08;nodes&#xff09;和线&#xff08;edges&#xff09;组成。节点表示操作符 Operator&#xff0c;或者称之为算子&#xff0c;线表示计算间的依赖。实线表示有数据传递依赖&#xff0c;传递的数据即张量。虚线通常可…

html动态加载script

<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <title>动态添加JavaScript代码</title> </head> <body> <h1>Hello, World!</h1> <button onclick"add…