import React from "react"; import { Table, Divider, Space, Tag, Progress, Button, Row, Col, Modal, Steps } from 'antd'; import { PauseOutlined, DeleteOutlined, CaretRightOutlined, ExclamationCircleOutlined } from '@ant-design/icons'; import Resumablejs from "./resumable"; import './style.css'; /** * 大文件上传组件 */ export default class ReactResumableJs extends React.Component { constructor(props) { super(props); this.state = { fileList: [],// 任务队列 isPaused: false,// 暂停上传 isUploading: false,// 正在上传 isSupported: false,// 浏览器支持H5分片接口 task: {// 当前执行的任务 id: 0,// 任务id prograss: 0,// 任务进度 }, timer: 0,// 计时器 }; this.resumable = null; this.timerInterval; } componentDidMount = () => { // 实例化上传组件( 用的是开源组件 resumablejs ) let _resumableField = this.__createResumbleObj(); // 当前浏览器是否支持 H5 Api this.setState({ isSupported: _resumableField.support }); // 绑定上传组件, 拖拽组件 _resumableField.assignBrowse(this.uploader); _resumableField.assignDrop(this.dropZone); /* 注册新增文件通知 */ _resumableField.on('fileAdded', this.__fileAddedListener.bind(this)); /* 注册上传处理中文件通知 */ _resumableField.on('fileProgress', this.__fileProgressListener.bind(this)); /** 文件上传完成 */ _resumableField.on('fileSuccess', this.__fileSuccessListener.bind(this)); /** 文件上传失败 */ _resumableField.on('fileError', this.__fileErrorListener.bind(this)); this.resumable = _resumableField; }; render() { // AntDesign Step组件, 用于指示业务运行阶段 const { Step } = Steps; const columns = [ { title: '描述', dataIndex: 'filename', key: 'filename', render: text => {text}, }, { title: '进度', dataIndex: 'prograss', key: 'prograss', width: '40%', responsive: ['lg'], render: (val, record) => , }, { title: '动作', dataIndex: 'action', key: 'action', width: '20%', responsive: ['md'], render: (text, record) => { if (record.uploading) { return ( ); } }, }, ]; return ( <>
this.dropZone = node} style={{ display: this.state.fileList.length === 0 ? '' : 'none' }}>
Your browser, unfortunately, is not supported by Resumable.js. The library requires support for the HTML5 File API along with file slicing.
文件拖拽到该区域或者 { this.uploader = node; this.dropZone = node; }} type="file" id={this.props.uploaderID} className='btn' name={this.props.uploaderID + '-upload'} accept={this.props.fileAccept || '*'} disabled={this.props.disableInput || false}>点击链接添加文件

总体作业已用时

{(() => { let _timer = this.state.timer; let _hour = parseInt(_timer / 3600); let _minute = parseInt(_timer % 3600 / 60); let _second = parseInt(_timer % 3600 % 60); return this.__format(_hour) + ":" + this.__format(_minute) + ":" + this.__format(_second); })()}

); } /** * 格式化计时器 * @param {*} value */ __format(value) { if (value < 10) { return '0' + value; } return value; } /** * 实例化上传组件 */ __createResumbleObj() { return new Resumablejs({ target: this.props.service, query: this.props.query,// 自定义参数 forceChunkSize: true,// 是否严格执行分片 fileType: this.props.filetypes, maxFiles: this.props.maxFiles, maxFileSize: this.props.maxFileSize, headers: this.props.headerObject || {}, chunkSize: this.props.chunkSize, testChunks: false,// 不启用测试块 simultaneousUploads: this.props.simultaneousUploads, fileParameterName: this.props.fileParameterName, forceChunkSize: true,// 是否严格执行分片 maxChunkRetries: 10,// 最大重试次数 chunkRetryInterval: 1000,// 重试间隔时间 10 秒 throttleProgressCallbacks: 1,// 上传进度播报周期 (1秒) forceChunkSize: this.props.forceChunkSize }); } /** * 添加文件时的监听 * * @param {*} file */ __fileAddedListener(file) { // 更新文件队列表单 let _cache = this.state.fileList; _cache.length = 0; _cache.push({ key: _cache.length + 1, filename: file.fileName, uploading: true, prograss: Math.floor(file.progress() * 100), }); // 更新组件状态,进行组件重绘 this.setState({ fileList: _cache }); if (typeof this.props.onFileAdded === "function") { this.props.onFileAdded(file, this.resumable); } else { this.resumable.upload(); } this.timerInterval = setInterval(() => { this.setState({ timer: this.state.timer + 1 }); }, 1000); } /** * 文件上传进度播报 * @param {*} file */ __fileProgressListener(file) { // 更新文件队列表单 let _cache = this.state.fileList; let matchedObj = _cache.find((obj) => obj.filename === file.fileName); if (matchedObj) { matchedObj.prograss = Math.floor(file.progress() * 100); // 更新组件状态,进行组件重绘 this.setState({ fileList: _cache, task: { id: 0, process: matchedObj.prograss } }); } } /** * 文件上传完成 * @param {*} file */ __fileSuccessListener(file) { let _cache = this.state.fileList; let matchedObj = _cache.find((obj) => obj.filename === file.fileName); if (matchedObj) { matchedObj.complete = true; this.setState({ fileList: _cache });// 更新组件状态,进行组件重绘 } if (typeof this.props.onUploadSuccess === "function") { _cache.length = 0;// 清空已完成的任务条目 this.props.onUploadSuccess(file, _cache, (index, description, percent) => { let obj = _cache[index]; if (obj) { obj.prograss = Math.floor(percent); obj.filename = description; this.setState({ fileList: _cache, task: { id: 1, prograss: obj.prograss } }); } // console.log(obj.prograss) // alert(obj.prograss) // 确认是否所有任务都已完成 if (obj.prograss >= 100) { // this.setState({ fileList: [], task: { id: 2, prograss: 100 } }); this.setState({ fileList: [], task: { id: 0, prograss: 0 } }); this.setState({ timer: 0 }); clearInterval(this.timerInterval); } else if (obj.prograss == 2) { this.setState({ fileList: [], task: { id: 0, prograss: 0 } }); this.setState({ timer: 0 }); clearInterval(this.timerInterval); } else { this.setState({ fileList: _cache, task: { id: 1, prograss: obj.prograss } }); } }); } } /** * 文件上传失败 * @param {*} file */ __fileErrorListener(file) { // 更新文件队列表单 let _cache = this.state.fileList; let matchedObj = _cache.find((obj) => obj.filename === file.fileName); if (matchedObj) { matchedObj.error = true; // 更新组件状态,进行组件重绘 this.setState({ fileList: _cache }); } if (typeof this.props.onUploadError === "function") { this.props.onUploadError(file, this.resumable); } } /** * 移除上传列表中的文件 */ __removeFile(filename) { /** 查询当前文件 */ const file = this.resumable.files.find(obj => obj.file.name === filename); const selfRef = this; if (!file.isComplete()) { const { confirm } = Modal; confirm({ title: '确定要移除当前任务吗?', icon: , content: '当前上传任务尚未完成,移除后将无法恢复,确定要执行该操作吗?', okText: '确定', okType: 'danger', cancelText: '取消', onOk() {// 取消选中文件的上传操作 file.cancel(); selfRef.__handleRemoveFile(filename); }, }); } else { selfRef.__handleRemoveFile(filename); } } __handleRemoveFile(filename) { // 更新文件队列表单 let _cache = this.state.fileList; // 移除指定的元素 _cache.splice(_cache.findIndex((obj) => obj.filename === filename), 1) // 修改上传列表状态 this.setState({ fileList: _cache }); } /** * 暂停上传 */ __uploadPause(filename) { // 取消选中文件的上传操作 this.resumable.files.find(obj => obj.file.name === filename)._pause = true; // 更新文件队列表单 let _cache = this.state.fileList; let matchedObj = _cache.find((obj) => obj.filename === filename); if (matchedObj) { matchedObj.pause = true; // 更新组件状态,进行组件重绘 this.setState({ fileList: _cache }); } } /** * 恢复上传 */ __uploadResum(filename) { let file = this.resumable.files.find(obj => obj.file.name === filename); // 取消暂停状态 file._pause = false; // 取消选中文件的上传操作 file.upload(); // 更新文件队列表单 let _cache = this.state.fileList; let matchedObj = _cache.find((obj) => obj.filename === filename); if (matchedObj) { delete matchedObj.pause; // 更新组件状态,进行组件重绘 this.setState({ fileList: _cache }); } } } /** * 对外暴露的属性值 */ ReactResumableJs.defaultProps = { maxFiles: 10,// 添加最大文件数 uploaderID: 'default-resumable-uploader', dropTargetID: 'dropTarget', query: {}, fileAccept: "*",// 文件头类型 maxFileSize: 1204 * 1024 * 1024 * 1024,// max size 1T onUploadErrorCallback: (file, errorCount) => { }, onFileRemoved: file => file, onCancelUpload: () => true, onPauseUpload: () => true, onResumeUpload: () => true, onStartUpload: () => true, onUploadSuccess: () => true, onUploadError: () => true, disableDragAndDrop: false,// 允许拖拽操作 chunkSize: 5 * 1024 * 1024,// 每个分批那的尺寸 5M simultaneousUploads: 5,// 同步上传的分片数 fileParameterName: 'file', generateUniqueIdentifier: null, maxFilesErrorCallback: null, cancelButton: false, pause: false, startButton: null, pauseButton: null, previousText: "", headerObject: {}, forceChunkSize: false };