分片上传

69 阅读1分钟

import { DeleteOutlined, DownloadOutlined, LoadingOutlined, PaperClipOutlined, UploadOutlined, } from '@ant-design/icons'; import { Button, Form, message, Tooltip, Upload } from 'antd'; import cls from 'classnames'; import { useCallback, useEffect, useState } from 'react'; import { v4 as uuidv4 } from 'uuid';

import { HTTP_CODE } from '@/constant/httpCode'; import { filePartUpload } from '@/pages/adminicularEvidence/service'; // 上传文件的接口

import styles from './index.less';

const FragmentUpload = (props) => { const { uploadExtra, acceptType, isDownload, labelName, handleloading, handleClickDownload, uploadItemLayout, } = props;

const [uploading, setUploading] = useState(false); const [fileData, setFileData] = useState(false);

useEffect(() => { handleloading(uploading); }, [uploading]);

const beforeUpload = useCallback((info) => { const fileName = info.name.substring(info.name.lastIndexOf('.'));

if (!acceptType.includes(fileName)) {
  message.error('文件类型错误,请重新上传');
  return false;
}

}, []);

const onRemove = useCallback(() => { setFileData(false); }, []);

const handleChange = useCallback((info) => { if (info.file.status === 'uploading') { setUploading(true); } else { setUploading(false); } if (info.file.status === 'done' || info.file.status === 'error') { setFileData(true); } }, []);

const sliceFileChunk = useCallback((file) => { const fileList = []; for (let i = 0; i < file.size; i += 5 * 1024 * 1024) { const endSize = i + 5 * 1024 * 1024 > file.size ? file.size : i + 5 * 1024 * 1024; const curFile = file.slice(i, endSize > file.size ? file.size : endSize); fileList.push(curFile); } return fileList; }, []);

const uploadChunkFile = async ( curChunkIndex, fileId, chunkFileList, totalSize, fileName, onSuccess, onError, ) => { const chunkFile = chunkFileList[curChunkIndex - 1]; const formData = new FormData(); formData.append('fileTmpId', fileId); formData.append('file', chunkFile); formData.append('fileName', fileName); formData.append('totalPart', String(chunkFileList.length)); formData.append('currentPart', String(curChunkIndex)); try { const res = await filePartUpload(formData);

  if (curChunkIndex < chunkFileList.length) {
    uploadChunkFile(
      ++curChunkIndex,
      fileId,
      chunkFileList,
      totalSize,
      fileName,
      onSuccess,
      onError,
    );
  }

  if (
    curChunkIndex === chunkFileList.length &&
    res.code === HTTP_CODE.SUCCESS &&
    res.data
  ) {
    onSuccess(res);
  }
} catch (error) {
  onError(error);
}

};

const customRequest = async ({ data, file, filename, onSuccess, onError, }) => { const { size, name } = file; const formData = new FormData(); if (data) { Object.keys(data).forEach((keyData) => { formData.append(keyData, data[keyData]); }); } formData.append(filename, file); const fileId = uuidv4(); const chunkFileList = sliceFileChunk(file); uploadChunkFile(1, fileId, chunkFileList, size, name, onSuccess, onError); };

const itemRender = useCallback( (originNode, file, fileList, actions) => { return (

{file.status === 'uploading' ? ( <> {file.name} </> ) : null} {file.status === 'done' ? ( <> <span className={cls(styles.done, styles.fileName)}> {file.name}
{isDownload ? ( ) : null}

            <DeleteOutlined
              className={cls(styles.icon)}
              onClick={() => {
                actions.remove();
                setFileData(false);
              }}
            />
          </div>
        </>
      ) : null}
      {file.status === 'error' ? (
        <>
          <PaperClipOutlined className={styles.err} />
          <Tooltip placement="top" title={file?.error?.message}>
            <span className={cls(styles.fileName, styles.err)}>
              {file.name}
            </span>
          </Tooltip>

          <DeleteOutlined
            className={cls(styles.err, styles.icon)}
            onClick={() => {
              actions.remove();
              setFileData(false);
            }}
          />
        </>
      ) : null}
    </div>
  );
},
[uploading],

);

return ( <Form.Item {...uploadItemLayout} name="fileIdEn" valuePropName="file" extra={uploadExtra} label={labelName} rules={[ { required: true, message: '请上传' }, () => ({ validator(rule, value) { if (value.status !== 'error') { return Promise.resolve(); } return Promise.reject(new Error('上传失败')); }, }), ]} getValueFromEvent={(e) => { if (Array.isArray(e)) { return e; } return e?.file; }} > <Button disabled={uploading || fileData} loading={uploading} icon={} > {uploading ? '上传中' : '选择文件'} </Form.Item> ); };

export default FragmentUpload;