index.tsx 4.3 KB
import React, { useState, useEffect } from 'react';
import { message, Upload, notification, Button } from 'antd';
import { uploadToken } from '@/services/upload';
import { UploadFile, UploadListType, UploadProps } from 'antd/lib/upload/interface';
import { UploadOutlined } from '@ant-design/icons';
import cx from 'classnames';

interface UploadFileProps {
  accept?: string;
  listType?: UploadListType;
  Callback?: (e: any) => void;
  num?: number;
  action?: string;
  name?: string | undefined;
  maxSize?: number;
  onChange?: (val: any) => void;
  value?: any;
  [prop: string]: any;
}

type Config = Record<
  | 'action'
  | 'OSSAccessKeyId'
  | 'key'
  | 'policy'
  | 'signature'
  | 'callback'
  | 'x:access_token'
  // | 'x-oss-security-token'
  | 'success_action_status',
  string
>;

// picture-card
const UploadFiles: React.FC<UploadFileProps> = (props) => {
  const {
    value,
    onChange,
    Callback,
    accept = '*.*',
    maxSize = 52428800,
    children,
    multiple,
    object_type,
  } = props;

  const [fileLists, setFileList] = useState<Array<UploadFile>>([]);
  const [config, setConfig] = useState<Config>();
  //解决Warning: Can‘t perform a React state update on an unmounted component.问题
  const [isFlag, setIsFlag] = useState(true);

  useEffect(() => {
    if (!isFlag) {
      return;
    }
    uploadToken({
      access_type: 'web_upload',
      object_type: object_type || 'recruit',
    }).then((res) => {
      if (res.errors) {
        notification.open({
          message: '错误',
          description: res.message,
          duration: 2,
        });
      } else {
        const data = {
          action: `https://${res.bucket}.${res.domain}/`,
          OSSAccessKeyId: res.access_key_id,
          key: res.object_path + '/' + '${filename}',
          policy: res.policy,
          signature: res.signature,
          callback: res.callback_body,
          'x:access_token': res.callback_token,
          // 测试环境不能使用
          // 'x-oss-security-token': res.security_token,
          success_action_status: '200',
        };

        setConfig(data);
      }
    });
    return () => setIsFlag(false);
  }, []);

  const onchange = ({ fileList }: { fileList: any }) => {
    if (fileList[fileList.length - 1].status === 'done') {
      // setFileList([...fileLists, fileList[fileList.length - 1]]);

      if (onChange) {
        onChange([...fileLists, fileList[fileList.length - 1]]);
      }
      if (Callback) Callback([...fileLists, fileList[fileList.length - 1]]);
    }
  };

  const onRemove = (file: UploadFile) => {
    const files = value.filter((v: { uid: string }) => v.uid !== file.uid);
    setFileList(files);
    if (onChange) {
      onChange(files);
    }
    if (Callback) Callback([...files]);
  };

  const onPreview = async (file: any) => {
    let src = file.url;
    if (!src) {
      src = await new Promise((resolve) => {
        const reader = new FileReader();

        reader.readAsDataURL(file.originFileObj);
        reader.onload = () => resolve(reader.result);
      });
    }
    const image = new Image();
    image.src = src;
    const imgWindow = window.open(src);
    imgWindow?.document.write(image.outerHTML);
  };

  const beforeUpload = (file: UploadFile) => {
    // 如果限制了上传类型
    if (accept !== '*.*') {
      const { name } = file;
      const accepts = accept.toLowerCase().split(',');
      const names = name.toLowerCase().split('.');
      const extName = names[names.length - 1];
      if (!accepts.includes(`.${extName}`)) {
        message.error('不支持的文件类型!');
        return false;
      }
    }
    // 如果限制了上传大小
    if (maxSize) {
      const { size = 0 } = file;

      if (size > maxSize) {
        message.error('文件太大了!');
        return false;
      }
    }
    return true;
  };

  const uploadProps: UploadProps = {
    accept: props.accept || '*.*',
    action: config?.action,
    name: 'file',
    data: config,
    showUploadList: false,
    multiple: multiple || false,
    beforeUpload: beforeUpload,
    onPreview: onPreview,
    onChange: onchange,
    onRemove: onRemove,
  };

  return (
    <div className={cx('global_upload')}>
      <Upload {...uploadProps}>
        {children || <Button icon={<UploadOutlined />}>上传文件</Button>}
      </Upload>
    </div>
  );
};

export default UploadFiles;