index.tsx 3.56 KB
/*
 * @Date: 2021-01-05 14:24:23
 * @LastEditors: wangqiang@feewee.cn
 * @LastEditTime: 2021-03-11 12:55:38
 */
import React from "react";
import { message, Upload } from "antd";
import { UploadProps } from "antd/lib/upload";
import { RcFile, UploadFile } from "antd/lib/upload/interface";
import getFidFile from "@/utils/getFidFile";

interface Props extends UploadProps {
  isFid?: boolean; // 预览文件 路径是否为 fid 形式
  limitSize?: number; // 限制文件大小,单位MB
  limitUnit?: "kb" | "mb" | "KB" | "MB"; // 限制大小单位, 默认MB
  children?: React.ReactNode;
}

/**
 * @description: 自定义封装的Upload上传组件
 * @description: 目前主要有2个功能:
 * 1. 预览文件,通过isFid属性判断是否是fid链接,然后通过新生成的a标签,跳转新页面打开文件。
 * 2. 限制上传文件大小,通过传入limitSize和limitUnit属性,判断传入文件的大小是否符合条件。
 * 2.1. 这里有一点需要这里,
 * 为了解决在表单中使用,当超过限制后,原有filelist中的文件都被清空,
 * 需要在Form.Item 传入的getValueFromEvent回调函数中多添加2行判断函数:
 *if (e.file.status === 'size_limit') {
    return e.fileList.filter((file: any) => file.uid !== e.file.uid);
  }
 * @param {Props} props
 */
export default function FeeweeUpload({
  isFid = false,
  limitSize = undefined,
  limitUnit = "MB",
  children,
  ...props
}: Props) {
  const onPreview = (file: UploadFile) => {
    if (props.onPreview) {
      props.onPreview(file);
      return;
    }
    getFidFile(file.response.data, isFid);
  };

  const beforeUpload = (file: RcFile, filelist: RcFile[]) => {
    if (limitSize !== undefined && typeof limitSize === "number") {
      const limit = isExceededSize(file, limitSize, limitUnit);
      if (limit.success) {
        return true;
      } else {
        message.error(limit.msg);
        /**
         * 将文件状态status设置为 size_limit,
         * 当表单中使用时,可以在getValueFromEvent回调函数中多添加2行判断函数:
         * if (e.file.status === 'size_limit') {
         *    return e.fileList.filter((file: any) => file.uid !== e.file.uid);
         * }
         */
        // @ts-ignore
        file.status = "size_limit";
        return false;
      }
    }
    return props.beforeUpload ? props.beforeUpload(file, filelist) : true;
  };

  return (
    <>
      <Upload {...props} beforeUpload={beforeUpload} onPreview={onPreview}>
        {children}
      </Upload>
    </>
  );
}

/**
 * @description: 计算限制大小,统一返回限制大小转换为KB
 * @param {number} limitSize
 * @param {'kb' | 'mb' | 'KB' | 'MB'} limitUnit
 * @return {number}
 */
function getLimitSize(
  limitSize: number,
  limitUnit: "kb" | "mb" | "KB" | "MB"
): number {
  if (limitUnit === "kb" || limitUnit === "KB") {
    return limitSize;
  }
  if (limitUnit === "mb" || limitUnit === "MB") {
    return limitSize * 1024;
  }
  return 0;
}

/**
 * @description: 判断是否没超过限制大小
 * @param {RcFile} file
 * @param {number} limitSize
 * @param {*} limitUnit
 * @return {{ success: boolean, msg?: string }}
 */
function isExceededSize(
  file: RcFile,
  limitSize: number,
  limitUnit: "kb" | "mb" | "KB" | "MB"
): { success: boolean; msg?: string } {
  const _limitSize = getLimitSize(limitSize, limitUnit);

  const fileSizeToKB = file.size / 1024;
  if (fileSizeToKB <= _limitSize) {
    return { success: true };
  } else {
    return {
      success: false,
      msg: `文件【${file.name}】大小不能超过${limitSize}${limitUnit}`,
    };
  }
}