uniapp微信小程序实现大文件上传 分片上传 进度条

这篇具有很好参考价值的文章主要介绍了uniapp微信小程序实现大文件上传 分片上传 进度条。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、安装  

npm i miniprogram-file-uploader

二、页面引入

    import Uploader from 'miniprogram-file-uploader'

 三、实现功能(重要)

        1.获取图片的路径

        2.设置分片的大小

        3.将数据放入

	let obj = this.uploadItem //图片路径或者视频路径 可以通过chooseMedia的api进行获取
				var tempFilePath = obj.tempFilePath
				var file = {//重点,分片要的参数 
					ext_file_name: '',
					index: 0,
					chunkSize: 1024 * 1024 * 0.5 //分片0.5M 根据自己的分片需求设置一片多大
				}
				file.ext_file_name = obj.tempFilePath
				file.index = Math.ceil(obj.size / file.chunkSize) //获取索引
				var opt = {
					fileName: file.ext_file_name,
					totalSize: obj.size,
					chunkSize: file.chunkSize,
					query: { //后端需要的参数
						activity_id: this.activity_id,
						file_type: this.file_type,
						total_size: obj.size,
						ext_file_name: file.ext_file_name
					},
					timeout: 180000, //请求超时时间,默认 10000 ms
					verifyUrl: 'https://xxxxxxx/upload/b2b3.0/digital_activity/?act=verify',//后端提供接口路径
					uploadUrl: 'https://xxxxxxx/upload/b2b3.0/digital_activity/?act=upload',//后端提供接口路径
					mergeUrl: `https://xxxxxxx/upload/b2b3.0/digital_activity/?act=merge&activity_id=${this.activity_id}&file_type=${this.file_type}&ext_file_name=${file.ext_file_name}`, //合并分块   //后端提供接口路径 参数自己传
					tempFilePath: tempFilePath //图片路径
				}
				const uploader = new Uploader(opt)//在这里扭一下

四、实现上传进度条

<view class="prompt_box" >
	<view class="prompt_top">
		<view class="prompt_title two_ti">正在提交</view>
		<view class="prompt_tow">
			<view class="">
				<progress :percent="upload.progress" stroke-width="4px" class="progress"
									:activeColor='theme_config.theme_color' show-info="true" font-size="15px"
									border-radius="4px"></progress>
			</view>
			<view class="">正在上传,请耐心等待</view>
		</view>
	</view>
	<view class="prompt_but two" @click="CancelSubmission">
		<view>取消提交</view>
		</view>
</view>
data(){
return{
	upload: { //上传进度
					// eq: -1,
					size: 0,
					progress: 0,
					uploadedSize: 0,
					averageSpeed: 0,
					timeRemaining: 0
				},
}

}





//js------

                const uploader = new Uploader(opt)//在这里扭一下
				uploader.on('complete', (res) => {})

				uploader.on('retry', (res) => {})
				uploader.on('success', (res) => {
					if (res.result.status_info.status_code == 100) {
						this.PostSubmitWork(res.result.build_info)
					}
				})
				uploader.on('fail', (res) => {
					this.isupload = false
				})

				uploader.on('progress', (res) => { //上传进度这里是进度条提供
					var tmp = {
						size: obj.size / 1024,
						progress: res.progress,
						uploadedSize: parseInt(res.uploadedSize / 1024),
						averageSpeed: parseInt(res.averageSpeed / 1024),
						timeRemaining: res.timeRemaining / 1000
					}
					this.upload = tmp//进度的所有数据
				})

全部函数js

	// 上传逻辑
			uploadOne() {
				let obj = this.uploadItem //图片路径或者视频路径 可以通过chooseMedia的api进行获取
				var tempFilePath = obj.tempFilePath
				var file = {//重点,分片要的参数 
					ext_file_name: '',
					index: 0,
					chunkSize: 1024 * 1024 * 0.5 //分片0.5M 根据自己的分片需求设置一片多大
				}
				file.ext_file_name = obj.tempFilePath
				file.index = Math.ceil(obj.size / file.chunkSize) //获取索引
				var opt = {
					fileName: file.ext_file_name,
					totalSize: obj.size,
					chunkSize: file.chunkSize,
					query: { //后端需要的参数
						activity_id: this.activity_id,
						file_type: this.file_type,
						total_size: obj.size,
						ext_file_name: file.ext_file_name
					},
					timeout: 180000, //请求超时时间,默认 10000 ms
					verifyUrl: 'https://xxxxxxx/upload/b2b3.0/digital_activity/?act=verify',//后端提供接口路径
					uploadUrl: 'https://xxxxxxx/upload/b2b3.0/digital_activity/?act=upload',//后端提供接口路径
					mergeUrl: `https://xxxxxxx/upload/b2b3.0/digital_activity/?act=merge&activity_id=${this.activity_id}&file_type=${this.file_type}&ext_file_name=${file.ext_file_name}`, //合并分块   //后端提供接口路径 参数自己传
					tempFilePath: tempFilePath //图片路径
				}
				const uploader = new Uploader(opt)//在这里扭一下

				// 成功或失败都会触发
				uploader.on('complete', (res) => {})

				uploader.on('retry', (res) => {})
				uploader.on('success', (res) => {
					if (res.result.status_info.status_code == 100) {
						this.PostSubmitWork(res.result.build_info)
					}
				})
				uploader.on('fail', (res) => {
					this.isupload = false
				})

				uploader.on('progress', (res) => { //上传进度这里是进度条提供
					var tmp = {
						size: obj.size / 1024,
						progress: res.progress,
						uploadedSize: parseInt(res.uploadedSize / 1024),
						averageSpeed: parseInt(res.averageSpeed / 1024),
						timeRemaining: res.timeRemaining / 1000
					}
					this.upload = tmp
				})
				uploader.upload()
				this.uploader = uploader
			},

五、修改npm的源码,处理请求源码中请求所携带的参数问题,以及报错处理(重要)

miniprogram-file-uploader,uni-app,微信小程序,小程序

miniprogram-file-uploader,uni-app,微信小程序,小程序

修改npm后的源码。可直接用(需修改请求参数)
 文章来源地址https://www.toymoban.com/news/detail-770992.html

/**
 * miniprogram-uploader 1.0.0
 * description: A JavaScript library supports miniprogram to upload large file.
 * author: sanfordsun
 * Released under the MIT License.
 */
import md5 from 'js-md5'
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window :
  typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};

function createCommonjsModule(fn, basedir, module) {
  return module = {
    path: basedir,
    exports: {},
    require: function(path, base) {
      return commonjsRequire(path, (base === undefined || base === null) ? module.path : base);
    }
  }, fn(module, module.exports), module.exports;
}

function commonjsRequire() {
  throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs');
}

var logger = createCommonjsModule(function(module) {
  /*!
   * js-logger - http://github.com/jonnyreeves/js-logger
   * Jonny Reeves, http://jonnyreeves.co.uk/
   * js-logger may be freely distributed under the MIT license.
   */
  (function(global) {

    // Top level module for the global, static logger instance.
    var Logger = {};

    // For those that are at home that are keeping score.
    Logger.VERSION = "1.6.0";

    // Function which handles all incoming log messages.
    var logHandler;

    // Map of ContextualLogger instances by name; used by Logger.get() to return the same named instance.
    var contextualLoggersByNameMap = {};

    // Polyfill for ES5's Function.bind.
    var bind = function(scope, func) {
      return function() {
        return func.apply(scope, arguments);
      };
    };

    // Super exciting object merger-matron 9000 adding another 100 bytes to your download.
    var merge = function() {
      var args = arguments,
        target = args[0],
        key, i;
      for (i = 1; i < args.length; i++) {
        for (key in args[i]) {
          if (!(key in target) && args[i].hasOwnProperty(key)) {
            target[key] = args[i][key];
          }
        }
      }
      return target;
    };

    // Helper to define a logging level object; helps with optimisation.
    var defineLogLevel = function(value, name) {
      return {
        value: value,
        name: name
      };
    };

    // Predefined logging levels.
    Logger.TRACE = defineLogLevel(1, 'TRACE');
    Logger.DEBUG = defineLogLevel(2, 'DEBUG');
    Logger.INFO = defineLogLevel(3, 'INFO');
    Logger.TIME = defineLogLevel(4, 'TIME');
    Logger.WARN = defineLogLevel(5, 'WARN');
    Logger.ERROR = defineLogLevel(8, 'ERROR');
    Logger.OFF = defineLogLevel(99, 'OFF');

    // Inner class which performs the bulk of the work; ContextualLogger instances can be configured independently
    // of each other.
    var ContextualLogger = function(defaultContext) {
      this.context = defaultContext;
      this.setLevel(defaultContext.filterLevel);
      this.log = this.info; // Convenience alias.
    };

    ContextualLogger.prototype = {
      // Changes the current logging level for the logging instance.
      setLevel: function(newLevel) {
        // Ensure the supplied Level object looks valid.
        if (newLevel && "value" in newLevel) {
          this.context.filterLevel = newLevel;
        }
      },

      // Gets the current logging level for the logging instance
      getLevel: function() {
        return this.context.filterLevel;
      },

      // Is the logger configured to output messages at the supplied level?
      enabledFor: function(lvl) {
        var filterLevel = this.context.filterLevel;
        return lvl.value >= filterLevel.value;
      },

      trace: function() {
        this.invoke(Logger.TRACE, arguments);
      },

      debug: function() {
        this.invoke(Logger.DEBUG, arguments);
      },

      info: function() {
        this.invoke(Logger.INFO, arguments);
      },

      warn: function() {
        this.invoke(Logger.WARN, arguments);
      },

      error: function() {
        this.invoke(Logger.ERROR, arguments);
      },

      time: function(label) {
        if (typeof label === 'string' && label.length > 0) {
          this.invoke(Logger.TIME, [label, 'start']);
        }
      },

      timeEnd: function(label) {
        if (typeof label === 'string' && label.length > 0) {
          this.invoke(Logger.TIME, [label, 'end']);
        }
      },

      // Invokes the logger callback if it's not being filtered.
      invoke: function(level, msgArgs) {
        if (logHandler && this.enabledFor(level)) {
          logHandler(msgArgs, merge({
            level: level
          }, this.context));
        }
      }
    };

    // Protected instance which all calls to the to level `Logger` module will be routed through.
    var globalLogger = new ContextualLogger({
      filterLevel: Logger.OFF
    });

    // Configure the global Logger instance.
    (function() {
      // Shortcut for optimisers.
      var L = Logger;

      L.enabledFor = bind(globalLogger, globalLogger.enabledFor);
      L.trace = bind(globalLogger, globalLogger.trace);
      L.debug = bind(globalLogger, globalLogger.debug);
      L.time = bind(globalLogger, globalLogger.time);
      L.timeEnd = bind(globalLogger, globalLogger.timeEnd);
      L.info = bind(globalLogger, globalLogger.info);
      L.warn = bind(globalLogger, globalLogger.warn);
      L.error = bind(globalLogger, globalLogger.error);

      // Don't forget the convenience alias!
      L.log = L.info;
    }());

    // Set the global logging handler.  The supplied function should expect two arguments, the first being an arguments
    // object with the supplied log messages and the second being a context object which contains a hash of stateful
    // parameters which the logging function can consume.
    Logger.setHandler = function(func) {
      logHandler = func;
    };

    // Sets the global logging filter level which applies to *all* previously registered, and future Logger instances.
    // (note that named loggers (retrieved via `Logger.get`) can be configured independently if required).
    Logger.setLevel = function(level) {
      // Set the globalLogger's level.
      globalLogger.setLevel(level);

      // Apply this level to all registered contextual loggers.
      for (var key in contextualLoggersByNameMap) {
        if (contextualLoggersByNameMap.hasOwnProperty(key)) {
          contextualLoggersByNameMap[key].setLevel(level);
        }
      }
    };

    // Gets the global logging filter level
    Logger.getLevel = function() {
      return globalLogger.getLevel();
    };

    // Retrieve a ContextualLogger instance.  Note that named loggers automatically inherit the global logger's level,
    // default context and log handler.
    Logger.get = function(name) {
      // All logger instances are cached so they can be configured ahead of use.
      return contextualLoggersByNameMap[name] ||
        (contextualLoggersByNameMap[name] = new ContextualLogger(merge({
          name: name
        }, globalLogger.context)));
    };

    // CreateDefaultHandler returns a handler function which can be passed to `Logger.setHandler()` which will
    // write to the window's console object (if present); the optional options object can be used to customise the
    // formatter used to format each log message.
    Logger.createDefaultHandler = function(options) {
      options = options || {};

      options.formatter = options.formatter || function defaultMessageFormatter(messages, context) {
        // Prepend the logger's name to the log message for easy identification.
        if (context.name) {
          messages.unshift("[" + context.name + "]");
        }
      };

      // Map of timestamps by timer labels used to track `#time` and `#timeEnd()` invocations in environments
      // that don't offer a native console method.
      var timerStartTimeByLabelMap = {};

      // Support for IE8+ (and other, slightly more sane environments)
      var invokeConsoleMethod = function(hdlr, messages) {
        Function.prototype.apply.call(hdlr, console, messages);
      };

      // Check for the presence of a logger.
      if (typeof console === "undefined") {
        return function() {
          /* no console */
        };
      }

      return function(messages, context) {
        // Convert arguments object to Array.
        messages = Array.prototype.slice.call(messages);

        var hdlr = console.log;
        var timerLabel;

        if (context.level === Logger.TIME) {
          timerLabel = (context.name ? '[' + context.name + '] ' : '') + messages[0];

          if (messages[1] === 'start') {
            if (console.time) {
              console.time(timerLabel);
            } else {
              timerStartTimeByLabelMap[timerLabel] = new Date().getTime();
            }
          } else {
            if (console.timeEnd) {
              console.timeEnd(timerLabel);
            } else {
              invokeConsoleMethod(hdlr, [timerLabel + ': ' +
                (new Date().getTime() - timerStartTimeByLabelMap[timerLabel]) + 'ms'
              ]);
            }
          }
        } else {
          // Delegate through to custom warn/error loggers if present on the console.
          if (context.level === Logger.WARN && console.warn) {
            hdlr = console.warn;
          } else if (context.level === Logger.ERROR && console.error) {
            hdlr = console.error;
          } else if (context.level === Logger.INFO && console.info) {
            hdlr = console.info;
          } else if (context.level === Logger.DEBUG && console.debug) {
            hdlr = console.debug;
          } else if (context.level === Logger.TRACE && console.trace) {
            hdlr = console.trace;
          }

          options.formatter(messages, context);
          invokeConsoleMethod(hdlr, messages);
        }
      };
    };

    // Configure and example a Default implementation which writes to the `window.console` (if present).  The
    // `options` hash can be used to configure the default logLevel and provide a custom message formatter.
    Logger.useDefaults = function(options) {
      Logger.setLevel(options && options.defaultLevel || Logger.DEBUG);
      Logger.setHandler(Logger.createDefaultHandler(options));
    };

    // Export to popular environments boilerplate.
    if (module.exports) {
      module.exports = Logger;
    } else {
      Logger._prevLogger = global.Logger;

      Logger.noConflict = function() {
        global.Logger = Logger._prevLogger;
        return Logger;
      };

      global.Logger = Logger;
    }
  }(commonjsGlobal));
});

var sparkMd5 = createCommonjsModule(function(module, exports) {
  (function(factory) {
    {
      // Node/CommonJS
      module.exports = factory();
    }
  }(function(undefined$1) {

    /*
     * Fastest md5 implementation around (JKM md5).
     * Credits: Joseph Myers
     *
     * @see http://www.myersdaily.org/joseph/javascript/md5-text.html
     * @see http://jsperf.com/md5-shootout/7
     */

    /* this function is much faster,
      so if possible we use it. Some IEs
      are the only ones I know of that
      need the idiotic second function,
      generated by an if clause.  */
    var hex_chr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];

    function md5cycle(x, k) {
      var a = x[0],
        b = x[1],
        c = x[2],
        d = x[3];

      a += (b & c | ~b & d) + k[0] - 680876936 | 0;
      a = (a << 7 | a >>> 25) + b | 0;
      d += (a & b | ~a & c) + k[1] - 389564586 | 0;
      d = (d << 12 | d >>> 20) + a | 0;
      c += (d & a | ~d & b) + k[2] + 606105819 | 0;
      c = (c << 17 | c >>> 15) + d | 0;
      b += (c & d | ~c & a) + k[3] - 1044525330 | 0;
      b = (b << 22 | b >>> 10) + c | 0;
      a += (b & c | ~b & d) + k[4] - 176418897 | 0;
      a = (a << 7 | a >>> 25) + b | 0;
      d += (a & b | ~a & c) + k[5] + 1200080426 | 0;
      d = (d << 12 | d >>> 20) + a | 0;
      c += (d & a | ~d & b) + k[6] - 1473231341 | 0;
      c = (c << 17 | c >>> 15) + d | 0;
      b += (c & d | ~c & a) + k[7] - 45705983 | 0;
      b = (b << 22 | b >>> 10) + c | 0;
      a += (b & c | ~b & d) + k[8] + 1770035416 | 0;
      a = (a << 7 | a >>> 25) + b | 0;
      d += (a & b | ~a & c) + k[9] - 1958414417 | 0;
      d = (d << 12 | d >>> 20) + a | 0;
      c += (d & a | ~d & b) + k[10] - 42063 | 0;
      c = (c << 17 | c >>> 15) + d | 0;
      b += (c & d | ~c & a) + k[11] - 1990404162 | 0;
      b = (b << 22 | b >>> 10) + c | 0;
      a += (b & c | ~b & d) + k[12] + 1804603682 | 0;
      a = (a << 7 | a >>> 25) + b | 0;
      d += (a & b | ~a & c) + k[13] - 40341101 | 0;
      d = (d << 12 | d >>> 20) + a | 0;
      c += (d & a | ~d & b) + k[14] - 1502002290 | 0;
      c = (c << 17 | c >>> 15) + d | 0;
      b += (c & d | ~c & a) + k[15] + 1236535329 | 0;
      b = (b << 22 | b >>> 10) + c | 0;

      a += (b & d | c & ~d) + k[1] - 165796510 | 0;
      a = (a << 5 | a >>> 27) + b | 0;
      d += (a & c | b & ~c) + k[6] - 1069501632 | 0;
      d = (d << 9 | d >>> 23) + a | 0;
      c += (d & b | a & ~b) + k[11] + 643717713 | 0;
      c = (c << 14 | c >>> 18) + d | 0;
      b += (c & a | d & ~a) + k[0] - 373897302 | 0;
      b = (b << 20 | b >>> 12) + c | 0;
      a += (b & d | c & ~d) + k[5] - 701558691 | 0;
      a = (a << 5 | a >>> 27) + b | 0;
      d += (a & c | b & ~c) + k[10] + 38016083 | 0;
      d = (d << 9 | d >>> 23) + a | 0;
      c += (d & b | a & ~b) + k[15] - 660478335 | 0;
      c = (c << 14 | c >>> 18) + d | 0;
      b += (c & a | d & ~a) + k[4] - 405537848 | 0;
      b = (b << 20 | b >>> 12) + c | 0;
      a += (b & d | c & ~d) + k[9] + 568446438 | 0;
      a = (a << 5 | a >>> 27) + b | 0;
      d += (a & c | b & ~c) + k[14] - 1019803690 | 0;
      d = (d << 9 | d >>> 23) + a | 0;
      c += (d & b | a & ~b) + k[3] - 187363961 | 0;
      c = (c << 14 | c >>> 18) + d | 0;
      b += (c & a | d & ~a) + k[8] + 1163531501 | 0;
      b = (b << 20 | b >>> 12) + c | 0;
      a += (b & d | c & ~d) + k[13] - 1444681467 | 0;
      a = (a << 5 | a >>> 27) + b | 0;
      d += (a & c | b & ~c) + k[2] - 51403784 | 0;
      d = (d << 9 | d >>> 23) + a | 0;
      c += (d & b | a & ~b) + k[7] + 1735328473 | 0;
      c = (c << 14 | c >>> 18) + d | 0;
      b += (c & a | d & ~a) + k[12] - 1926607734 | 0;
      b = (b << 20 | b >>> 12) + c | 0;

      a += (b ^ c ^ d) + k[5] - 378558 | 0;
      a = (a << 4 | a >>> 28) + b | 0;
      d += (a ^ b ^ c) + k[8] - 2022574463 | 0;
      d = (d << 11 | d >>> 21) + a | 0;
      c += (d ^ a ^ b) + k[11] + 1839030562 | 0;
      c = (c << 16 | c >>> 16) + d | 0;
      b += (c ^ d ^ a) + k[14] - 35309556 | 0;
      b = (b << 23 | b >>> 9) + c | 0;
      a += (b ^ c ^ d) + k[1] - 1530992060 | 0;
      a = (a << 4 | a >>> 28) + b | 0;
      d += (a ^ b ^ c) + k[4] + 1272893353 | 0;
      d = (d << 11 | d >>> 21) + a | 0;
      c += (d ^ a ^ b) + k[7] - 155497632 | 0;
      c = (c << 16 | c >>> 16) + d | 0;
      b += (c ^ d ^ a) + k[10] - 1094730640 | 0;
      b = (b << 23 | b >>> 9) + c | 0;
      a += (b ^ c ^ d) + k[13] + 681279174 | 0;
      a = (a << 4 | a >>> 28) + b | 0;
      d += (a ^ b ^ c) + k[0] - 358537222 | 0;
      d = (d << 11 | d >>> 21) + a | 0;
      c += (d ^ a ^ b) + k[3] - 722521979 | 0;
      c = (c << 16 | c >>> 16) + d | 0;
      b += (c ^ d ^ a) + k[6] + 76029189 | 0;
      b = (b << 23 | b >>> 9) + c | 0;
      a += (b ^ c ^ d) + k[9] - 640364487 | 0;
      a = (a << 4 | a >>> 28) + b | 0;
      d += (a ^ b ^ c) + k[12] - 421815835 | 0;
      d = (d << 11 | d >>> 21) + a | 0;
      c += (d ^ a ^ b) + k[15] + 530742520 | 0;
      c = (c << 16 | c >>> 16) + d | 0;
      b += (c ^ d ^ a) + k[2] - 995338651 | 0;
      b = (b << 23 | b >>> 9) + c | 0;

      a += (c ^ (b | ~d)) + k[0] - 198630844 | 0;
      a = (a << 6 | a >>> 26) + b | 0;
      d += (b ^ (a | ~c)) + k[7] + 1126891415 | 0;
      d = (d << 10 | d >>> 22) + a | 0;
      c += (a ^ (d | ~b)) + k[14] - 1416354905 | 0;
      c = (c << 15 | c >>> 17) + d | 0;
      b += (d ^ (c | ~a)) + k[5] - 57434055 | 0;
      b = (b << 21 | b >>> 11) + c | 0;
      a += (c ^ (b | ~d)) + k[12] + 1700485571 | 0;
      a = (a << 6 | a >>> 26) + b | 0;
      d += (b ^ (a | ~c)) + k[3] - 1894986606 | 0;
      d = (d << 10 | d >>> 22) + a | 0;
      c += (a ^ (d | ~b)) + k[10] - 1051523 | 0;
      c = (c << 15 | c >>> 17) + d | 0;
      b += (d ^ (c | ~a)) + k[1] - 2054922799 | 0;
      b = (b << 21 | b >>> 11) + c | 0;
      a += (c ^ (b | ~d)) + k[8] + 1873313359 | 0;
      a = (a << 6 | a >>> 26) + b | 0;
      d += (b ^ (a | ~c)) + k[15] - 30611744 | 0;
      d = (d << 10 | d >>> 22) + a | 0;
      c += (a ^ (d | ~b)) + k[6] - 1560198380 | 0;
      c = (c << 15 | c >>> 17) + d | 0;
      b += (d ^ (c | ~a)) + k[13] + 1309151649 | 0;
      b = (b << 21 | b >>> 11) + c | 0;
      a += (c ^ (b | ~d)) + k[4] - 145523070 | 0;
      a = (a << 6 | a >>> 26) + b | 0;
      d += (b ^ (a | ~c)) + k[11] - 1120210379 | 0;
      d = (d << 10 | d >>> 22) + a | 0;
      c += (a ^ (d | ~b)) + k[2] + 718787259 | 0;
      c = (c << 15 | c >>> 17) + d | 0;
      b += (d ^ (c | ~a)) + k[9] - 343485551 | 0;
      b = (b << 21 | b >>> 11) + c | 0;

      x[0] = a + x[0] | 0;
      x[1] = b + x[1] | 0;
      x[2] = c + x[2] | 0;
      x[3] = d + x[3] | 0;
    }

    function md5blk(s) {
      var md5blks = [],
        i; /* Andy King said do it this way. */

      for (i = 0; i < 64; i += 4) {
        md5blks[i >> 2] = s.charCodeAt(i) + (s.charCodeAt(i + 1) << 8) + (s.charCodeAt(i + 2) << 16) + (s
          .charCodeAt(i + 3) << 24);
      }
      return md5blks;
    }

    function md5blk_array(a) {
      var md5blks = [],
        i; /* Andy King said do it this way. */

      for (i = 0; i < 64; i += 4) {
        md5blks[i >> 2] = a[i] + (a[i + 1] << 8) + (a[i + 2] << 16) + (a[i + 3] << 24);
      }
      return md5blks;
    }

    function md51(s) {
      var n = s.length,
        state = [1732584193, -271733879, -1732584194, 271733878],
        i,
        length,
        tail,
        tmp,
        lo,
        hi;

      for (i = 64; i <= n; i += 64) {
        md5cycle(state, md5blk(s.substring(i - 64, i)));
      }
      s = s.substring(i - 64);
      length = s.length;
      tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
      for (i = 0; i < length; i += 1) {
        tail[i >> 2] |= s.charCodeAt(i) << ((i % 4) << 3);
      }
      tail[i >> 2] |= 0x80 << ((i % 4) << 3);
      if (i > 55) {
        md5cycle(state, tail);
        for (i = 0; i < 16; i += 1) {
          tail[i] = 0;
        }
      }

      // Beware that the final length might not fit in 32 bits so we take care of that
      tmp = n * 8;
      tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
      lo = parseInt(tmp[2], 16);
      hi = parseInt(tmp[1], 16) || 0;

      tail[14] = lo;
      tail[15] = hi;

      md5cycle(state, tail);
      return state;
    }

    function md51_array(a) {
      var n = a.length,
        state = [1732584193, -271733879, -1732584194, 271733878],
        i,
        length,
        tail,
        tmp,
        lo,
        hi;

      for (i = 64; i <= n; i += 64) {
        md5cycle(state, md5blk_array(a.subarray(i - 64, i)));
      }

      // Not sure if it is a bug, however IE10 will always produce a sub array of length 1
      // containing the last element of the parent array if the sub array specified starts
      // beyond the length of the parent array - weird.
      // https://connect.microsoft.com/IE/feedback/details/771452/typed-array-subarray-issue
      a = (i - 64) < n ? a.subarray(i - 64) : new Uint8Array(0);

      length = a.length;
      tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
      for (i = 0; i < length; i += 1) {
        tail[i >> 2] |= a[i] << ((i % 4) << 3);
      }

      tail[i >> 2] |= 0x80 << ((i % 4) << 3);
      if (i > 55) {
        md5cycle(state, tail);
        for (i = 0; i < 16; i += 1) {
          tail[i] = 0;
        }
      }

      // Beware that the final length might not fit in 32 bits so we take care of that
      tmp = n * 8;
      tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
      lo = parseInt(tmp[2], 16);
      hi = parseInt(tmp[1], 16) || 0;

      tail[14] = lo;
      tail[15] = hi;

      md5cycle(state, tail);

      return state;
    }

    function rhex(n) {
      var s = '',
        j;
      for (j = 0; j < 4; j += 1) {
        s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + hex_chr[(n >> (j * 8)) & 0x0F];
      }
      return s;
    }

    function hex(x) {
      var i;
      for (i = 0; i < x.length; i += 1) {
        x[i] = rhex(x[i]);
      }
      return x.join('');
    }

    // In some cases the fast add32 function cannot be used..
    if (hex(md51('hello')) !== '5d41402abc4b2a76b9719d911017c592');

    // ---------------------------------------------------

    /**
     * ArrayBuffer slice polyfill.
     *
     * @see https://github.com/ttaubert/node-arraybuffer-slice
     */

    if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
      (function() {
        function clamp(val, length) {
          val = (val | 0) || 0;

          if (val < 0) {
            return Math.max(val + length, 0);
          }

          return Math.min(val, length);
        }

        ArrayBuffer.prototype.slice = function(from, to) {
          var length = this.byteLength,
            begin = clamp(from, length),
            end = length,
            num,
            target,
            targetArray,
            sourceArray;

          if (to !== undefined$1) {
            end = clamp(to, length);
          }

          if (begin > end) {
            return new ArrayBuffer(0);
          }

          num = end - begin;
          target = new ArrayBuffer(num);
          targetArray = new Uint8Array(target);

          sourceArray = new Uint8Array(this, begin, num);
          targetArray.set(sourceArray);

          return target;
        };
      })();
    }

    // ---------------------------------------------------

    /**
     * Helpers.
     */

    function toUtf8(str) {
      if (/[\u0080-\uFFFF]/.test(str)) {
        str = unescape(encodeURIComponent(str));
      }

      return str;
    }

    function utf8Str2ArrayBuffer(str, returnUInt8Array) {
      var length = str.length,
        buff = new ArrayBuffer(length),
        arr = new Uint8Array(buff),
        i;

      for (i = 0; i < length; i += 1) {
        arr[i] = str.charCodeAt(i);
      }

      return returnUInt8Array ? arr : buff;
    }

    function arrayBuffer2Utf8Str(buff) {
      return String.fromCharCode.apply(null, new Uint8Array(buff));
    }

    function concatenateArrayBuffers(first, second, returnUInt8Array) {
      var result = new Uint8Array(first.byteLength + second.byteLength);

      result.set(new Uint8Array(first));
      result.set(new Uint8Array(second), first.byteLength);

      return returnUInt8Array ? result : result.buffer;
    }

    function hexToBinaryString(hex) {
      var bytes = [],
        length = hex.length,
        x;

      for (x = 0; x < length - 1; x += 2) {
        bytes.push(parseInt(hex.substr(x, 2), 16));
      }

      return String.fromCharCode.apply(String, bytes);
    }

    // ---------------------------------------------------

    /**
     * SparkMD5 OOP implementation.
     *
     * Use this class to perform an incremental md5, otherwise use the
     * static methods instead.
     */

    function SparkMD5() {
      // call reset to init the instance
      this.reset();
    }

    /**
     * Appends a string.
     * A conversion will be applied if an utf8 string is detected.
     *
     * @param {String} str The string to be appended
     *
     * @return {SparkMD5} The instance itself
     */
    SparkMD5.prototype.append = function(str) {
      // Converts the string to utf8 bytes if necessary
      // Then append as binary
      this.appendBinary(toUtf8(str));

      return this;
    };

    /**
     * Appends a binary string.
     *
     * @param {String} contents The binary string to be appended
     *
     * @return {SparkMD5} The instance itself
     */
    SparkMD5.prototype.appendBinary = function(contents) {
      this._buff += contents;
      this._length += contents.length;

      var length = this._buff.length,
        i;

      for (i = 64; i <= length; i += 64) {
        md5cycle(this._hash, md5blk(this._buff.substring(i - 64, i)));
      }

      this._buff = this._buff.substring(i - 64);

      return this;
    };

    /**
     * Finishes the incremental computation, reseting the internal state and
     * returning the result.
     *
     * @param {Boolean} raw True to get the raw string, false to get the hex string
     *
     * @return {String} The result
     */
    SparkMD5.prototype.end = function(raw) {
      var buff = this._buff,
        length = buff.length,
        i,
        tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        ret;

      for (i = 0; i < length; i += 1) {
        tail[i >> 2] |= buff.charCodeAt(i) << ((i % 4) << 3);
      }

      this._finish(tail, length);
      ret = hex(this._hash);

      if (raw) {
        ret = hexToBinaryString(ret);
      }

      this.reset();

      return ret;
    };

    /**
     * Resets the internal state of the computation.
     *
     * @return {SparkMD5} The instance itself
     */
    SparkMD5.prototype.reset = function() {
      this._buff = '';
      this._length = 0;
      this._hash = [1732584193, -271733879, -1732584194, 271733878];

      return this;
    };

    /**
     * Gets the internal state of the computation.
     *
     * @return {Object} The state
     */
    SparkMD5.prototype.getState = function() {
      return {
        buff: this._buff,
        length: this._length,
        hash: this._hash.slice()
      };
    };

    /**
     * Gets the internal state of the computation.
     *
     * @param {Object} state The state
     *
     * @return {SparkMD5} The instance itself
     */
    SparkMD5.prototype.setState = function(state) {
      this._buff = state.buff;
      this._length = state.length;
      this._hash = state.hash;

      return this;
    };

    /**
     * Releases memory used by the incremental buffer and other additional
     * resources. If you plan to use the instance again, use reset instead.
     */
    SparkMD5.prototype.destroy = function() {
      delete this._hash;
      delete this._buff;
      delete this._length;
    };

    /**
     * Finish the final calculation based on the tail.
     *
     * @param {Array}  tail   The tail (will be modified)
     * @param {Number} length The length of the remaining buffer
     */
    SparkMD5.prototype._finish = function(tail, length) {
      var i = length,
        tmp,
        lo,
        hi;

      tail[i >> 2] |= 0x80 << ((i % 4) << 3);
      if (i > 55) {
        md5cycle(this._hash, tail);
        for (i = 0; i < 16; i += 1) {
          tail[i] = 0;
        }
      }

      // Do the final computation based on the tail and length
      // Beware that the final length may not fit in 32 bits so we take care of that
      tmp = this._length * 8;
      tmp = tmp.toString(16).match(/(.*?)(.{0,8})$/);
      lo = parseInt(tmp[2], 16);
      hi = parseInt(tmp[1], 16) || 0;

      tail[14] = lo;
      tail[15] = hi;
      md5cycle(this._hash, tail);
    };

    /**
     * Performs the md5 hash on a string.
     * A conversion will be applied if utf8 string is detected.
     *
     * @param {String}  str The string
     * @param {Boolean} [raw] True to get the raw string, false to get the hex string
     *
     * @return {String} The result
     */
    SparkMD5.hash = function(str, raw) {
      // Converts the string to utf8 bytes if necessary
      // Then compute it using the binary function
      return SparkMD5.hashBinary(toUtf8(str), raw);
    };

    /**
     * Performs the md5 hash on a binary string.
     *
     * @param {String}  content The binary string
     * @param {Boolean} [raw]     True to get the raw string, false to get the hex string
     *
     * @return {String} The result
     */
    SparkMD5.hashBinary = function(content, raw) {
      var hash = md51(content),
        ret = hex(hash);

      return raw ? hexToBinaryString(ret) : ret;
    };

    // ---------------------------------------------------

    /**
     * SparkMD5 OOP implementation for array buffers.
     *
     * Use this class to perform an incremental md5 ONLY for array buffers.
     */
    SparkMD5.ArrayBuffer = function() {
      // call reset to init the instance
      this.reset();
    };

    /**
     * Appends an array buffer.
     *
     * @param {ArrayBuffer} arr The array to be appended
     *
     * @return {SparkMD5.ArrayBuffer} The instance itself
     */
    SparkMD5.ArrayBuffer.prototype.append = function(arr) {
      var buff = concatenateArrayBuffers(this._buff.buffer, arr, true),
        length = buff.length,
        i;

      this._length += arr.byteLength;

      for (i = 64; i <= length; i += 64) {
        md5cycle(this._hash, md5blk_array(buff.subarray(i - 64, i)));
      }

      this._buff = (i - 64) < length ? new Uint8Array(buff.buffer.slice(i - 64)) : new Uint8Array(0);

      return this;
    };

    /**
     * Finishes the incremental computation, reseting the internal state and
     * returning the result.
     *
     * @param {Boolean} raw True to get the raw string, false to get the hex string
     *
     * @return {String} The result
     */
    SparkMD5.ArrayBuffer.prototype.end = function(raw) {
      var buff = this._buff,
        length = buff.length,
        tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
        i,
        ret;

      for (i = 0; i < length; i += 1) {
        tail[i >> 2] |= buff[i] << ((i % 4) << 3);
      }

      this._finish(tail, length);
      ret = hex(this._hash);

      if (raw) {
        ret = hexToBinaryString(ret);
      }

      this.reset();

      return ret;
    };

    /**
     * Resets the internal state of the computation.
     *
     * @return {SparkMD5.ArrayBuffer} The instance itself
     */
    SparkMD5.ArrayBuffer.prototype.reset = function() {
      this._buff = new Uint8Array(0);
      this._length = 0;
      this._hash = [1732584193, -271733879, -1732584194, 271733878];

      return this;
    };

    /**
     * Gets the internal state of the computation.
     *
     * @return {Object} The state
     */
    SparkMD5.ArrayBuffer.prototype.getState = function() {
      var state = SparkMD5.prototype.getState.call(this);

      // Convert buffer to a string
      state.buff = arrayBuffer2Utf8Str(state.buff);

      return state;
    };

    /**
     * Gets the internal state of the computation.
     *
     * @param {Object} state The state
     *
     * @return {SparkMD5.ArrayBuffer} The instance itself
     */
    SparkMD5.ArrayBuffer.prototype.setState = function(state) {
      // Convert string to buffer
      state.buff = utf8Str2ArrayBuffer(state.buff, true);

      return SparkMD5.prototype.setState.call(this, state);
    };

    SparkMD5.ArrayBuffer.prototype.destroy = SparkMD5.prototype.destroy;

    SparkMD5.ArrayBuffer.prototype._finish = SparkMD5.prototype._finish;

    /**
     * Performs the md5 hash on an array buffer.
     *
     * @param {ArrayBuffer} arr The array buffer
     * @param {Boolean}     [raw] True to get the raw string, false to get the hex one
     *
     * @return {String} The result
     */
    SparkMD5.ArrayBuffer.hash = function(arr, raw) {
      var hash = md51_array(new Uint8Array(arr)),
        ret = hex(hash);

      return raw ? hexToBinaryString(ret) : ret;
    };

    return SparkMD5;
  }));
});

var config = {
  tempFilePath: '',
  totalSize: 0,
  fileName: '',
  verifyUrl: '',
  uploadUrl: '',
  mergeUrl: '',
  maxConcurrency: 5,
  generateIdentifier: null,
  chunkSize: 5 * 1024 * 1024,
  maxMemory: 100 * 1024 * 1024,
  query: '',
  header: {},
  testChunks: false,
  chunkRetryInterval: 0,
  maxChunkRetries: 0,
  timeout: 10000,
  successStatus: [200, 201, 202],
  failStatus: [404, 415, 500, 501],
  verbose: false
};

class EventEmitter {
  constructor() {
    this.events = {};
  }

  on(event, listener) {
    if (typeof this.events[event] !== 'object') {
      this.events[event] = [];
    }
    this.events[event].push(listener);
    return () => this.off(event, listener)
  }

  off(event, listener) {
    if (typeof this.events[event] === 'object') {
      const idx = this.events[event].indexOf(listener);
      if (idx > -1) {
        this.events[event].splice(idx, 1);
      }
    }
  }

  emit(event, ...args) {
    if (typeof this.events[event] === 'object') {
      this.events[event].forEach(listener => listener.apply(this, args));
    }
  }

  once(event, listener) {
    const remove = this.on(event, (...args) => {
      remove();
      listener.apply(this, args);
    });
  }
}

const isFunction = x => typeof x === 'function';

function promisify(func) {
  if (!isFunction(func)) return func
  return (args = {}) => new Promise((resolve, reject) => {
    func(
      Object.assign(args, {
        success: resolve,
        fail: reject
      })
    );
  })
}

function addParams(url = '', params = {}) {
  const parts = url.split('&');
  const query = Object.keys(params).map(key => `${key}=${params[key]}`).join('&');
  return query ? `${parts[0]}&${query}` : parts[0]
}

const awaitWrap = (promise) => promise
  .then(data => [null, data])
  .catch(err => [err, null]);

const compareVersion = (v1, v2) => {
  v1 = v1.split('.');
  v2 = v2.split('.');
  const len = Math.max(v1.length, v2.length);

  while (v1.length < len) {
    v1.push('0');
  }
  while (v2.length < len) {
    v2.push('0');
  }

  for (let i = 0; i < len; i++) {
    const num1 = parseInt(v1[i], 10);
    const num2 = parseInt(v2[i], 10);

    if (num1 > num2) {
      return 1
    } else if (num1 < num2) {
      return -1
    }
  }

  return 0
};

logger.useDefaults({
  defaultLevel: logger.OFF,
  formatter(messages) {
    const now = new Date();
    const time = `${now.getHours()}:${now.getMinutes()}:${now.getSeconds()}`;
    messages.unshift(time);
    messages.unshift('[Uploader]');
  }
});

const fileManager = wx.getFileSystemManager();
const readFileAsync = promisify(fileManager.readFile);
const miniProgram = wx.getAccountInfoSync();
const systemInfo = wx.getSystemInfoSync();
const appId = miniProgram.appId;
const MB = 1024 * 1024;




// -----------------下面是请求的数据,可以删掉
let app_key = 'xxx';
let key = 'xxx';

// 随机32位数
function nonce() {
  let arr = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B',
    'C', 'D', 'E'
  ];
  let res = '';
  for (let i = 0; i < 32; i++) {
    let pos = Math.round(Math.random() * (arr.length - 1));
    res += arr[pos]
  }
  return res;
}

function signfn(action, postParam) {
  // 时间戳
  let ts = new Date().getTime().toString();
  let randomNum = nonce();

  let act = app_key; //请求带的url
  function getSign(params, app_key, key) {

    if (typeof params == "string") {
      return paramsStrSort(params);
    } else if (typeof params == "object") {
      let arr = [];
      for (let i in params) {
        arr.push((i + "=" + params[i]));
      }
      return paramsStrSort(arr.join(("&")))
    }
  }

  function paramsStrSort(paramsStr) {
    let url = paramsStr;
    let arr = [];
    let p = url.split("&");
    for (let i in p) {
      let temp_arr = p[i].split("=");
      arr.push((temp_arr[0].toLowerCase() + "=" + temp_arr[1]));
    }
    let urlStr = arr.sort().join("&");
    let newUrl = urlStr + '&key=' + key;
    return md5(newUrl);
  }

  var params = {
    act,
    'ts': ts,
    'nonce': randomNum,
    app_key
  };
  // 转成字符串
  let signstr = JSON.stringify(params);
  let sign = getSign(params, app_key, key);


  return {
    sign,
    ts,
    randomNum,
    app_key
  };

}
// -----------------上面是请求的数据,可以删掉  结束




class Uploader {
  constructor(option = {}) {
    if (option.verbose) logger.setLevel(logger.INFO);
    logger.debug('construct option ', option);
    this.config = Object.assign(config, option);
    this.emitter = new EventEmitter();
    this.totalSize = this.config.totalSize;
    this.chunkSize = this.config.chunkSize;
    this.tempFilePath = this.config.tempFilePath;
    this.totalChunks = Math.ceil(this.totalSize / this.chunkSize);
    this.maxLoadChunks = Math.floor(this.config.maxMemory / this.chunkSize);
    this._event();
  }

  static isSupport() {
    const version = systemInfo.SDKVersion;
    return compareVersion(version, '2.10.0') >= 0
  }

  async upload() {
    this._reset();

    logger.info('start generateIdentifier');
    // step1: 计算 identifier
    try {
      logger.time('[Uploader] generateIdentifier');
      if (this.config.testChunks) {
        this.identifier = await this.computeMD5();
      } else {
        this.identifier = this.generateIdentifier();
      }
      logger.timeEnd('[Uploader] generateIdentifier');
      logger.debug('generateIdentifier ', this.identifier);
    } catch (error) {
      this.handleFail({
        errCode: 10002,
        errMsg: error.message
      });
      return
    }
    logger.info('generateIdentifier end');
    // step2: 获取已上传分片

    if (this.config.testChunks && this.config.verifyUrl) {
      logger.info('start verify uploaded chunks');
      logger.time('[Uploader] verifyRequest');
      const [verifyErr, verifyResp] = await awaitWrap(this.verifyRequest());
      logger.timeEnd('[Uploader] verifyRequest');
      logger.debug('verifyRequest', verifyErr, verifyResp);
      if (verifyErr) {
        this.handleFail({
          errCode: 20001,
          errMsg: verifyErr.errMsg
        });
        return
      }
      const {
        needUpload,
        uploadedChunks,
      } = verifyResp.data;
      logger.info('verify uploaded chunks end');
      // 秒传逻辑
      // 找不到合成的文件
      if (!needUpload) {
        this.progress = 100;
        this.timeRemaining = 0;
        this.dispatchProgress();
        this.emit('success', {
          errCode: 0,
          ...verifyResp.data
        });
        this.emit('complete', {
          errCode: 0,
          ...verifyResp.data
        });
        return
        // 分片齐全,但没有合并
      } else if (uploadedChunks.length === this.totalChunks) {
        this.progress = 100;
        this.timeRemaining = 0;
        this.dispatchProgress();
        this.emit('uploadDone');
        return
      } else {
        this.chunksIndexNeedRead = this.chunksIndexNeedRead.filter(v => !uploadedChunks.includes(v));
        this.chunksIndexNeedSend = this.chunksIndexNeedSend.filter(v => !uploadedChunks.includes(v));
        this.uploadedChunks = uploadedChunks.sort();
      }
    }

    this.chunksNeedSend = this.chunksIndexNeedSend.length;
    this.sizeNeedSend = this.chunksNeedSend * this.chunkSize;
    if (this.chunksIndexNeedSend.includes(this.totalChunks - 1)) {
      this.sizeNeedSend -= (this.totalChunks * this.chunkSize - this.totalSize);
    }
    logger.debug(`
      start upload
        uploadedChunks: ${this.uploadedChunks},
        chunksQueue: ${this.chunksQueue},
        chunksIndexNeedRead: ${this.chunksIndexNeedRead},
        chunksNeedSend: ${this.chunksIndexNeedSend},
        sizeNeedSend: ${this.sizeNeedSend}
    `);

    logger.info('start upload chunks');
    logger.time('[Uploader] uploadChunks');
    // step3: 开始上传
    this.isUploading = true;
    this._upload();
  }

  _requestAsync(args = {}, callback) {
    const {
      chunkRetryInterval,
      maxChunkRetries,
      successStatus,
      failStatus
    } = this.config;

    let retries = maxChunkRetries;

    // args.url||
    const signInfo = signfn(args.url)
    return new Promise((resolve, reject) => {
      let ts = new Date().getTime().toString();
      const doRequest = () => {
        const task = wx.request({
          ...args,
          header: {
            "Content-Type": "multipart/form-data",
            "auth-ts": signInfo.ts, //时间戳
            "auth-access-token": uni.getStorageSync('user_info').access_token || '',
            "auth-nonce": signInfo.randomNum, //随机字符串(32位)
            "auth-sign": signInfo.sign, //签名
            "auth-key": signInfo.app_key, //应用的APP_KEY
            "auth-platform": '1', //请求平台ID 1:web端 2:安卓 3:苹果
            "auth-appid": uni.getStorageSync('user_info').app_id || 0, //通过二维码进入携带的appid
            "auth-orgname": uni.getStorageSync('user_info').org_info.orgname || orgname || '', //用户机构
          },
          timeout: this.config.timeout,
          success: (res) => {
            let pages = getCurrentPages();
            if (res.data.result.status_info.status_code != 100) {
              let pagesitem = pages[2] || pages[1] || pages[0]
              if (pagesitem.route == "PackageA/pages/vote_work/video_upload") {
                pagesitem.$vm.$refs.sbp.close()
                pagesitem.$vm.isupload = false
                pagesitem.$vm.showMsk = false
              }
              uni.showToast({
                title: res.data.result.status_info.status_message,
                duration: 2000,
                icon: 'none'
              })
              this.cancel();
              return
            }
            const statusCode = res.statusCode;

            // 标示成功的返回码
            if (successStatus.includes(statusCode)) {
              resolve(res);
              // 标示失败的返回码
            } else if (failStatus.includes(statusCode)) {
              reject(res);
            } else if (retries > 0) {
              setTimeout(() => {
                this.emit('retry', {
                  statusCode,
                  url: args.url
                });
                --retries;
                doRequest();
              }, chunkRetryInterval);
            } else {
              reject(res);
            }
          },
          fail: (res) => {
            reject(res);
             let pageS = getCurrentPages();
            let pagesitem = pageS[2] || pageS[1] || pageS[0]
            if (pagesitem.route == "PackageA/pages/vote_work/video_upload") {
              console.log(pagesitem, 'pagesitem----');
              pagesitem.$vm.$refs.sbp.close()
              // pagesitem.$vm.imgvido_arr = []
              pagesitem.$vm.isupload = false
              pagesitem.$vm.showMsk = false
            }
            uni.showToast({
              title: res.data.result.status_info.status_message,
              duration: 2000,
              icon: 'none'
            })
            console.log(res, '请求失败');
            return
          }
        });
        if (isFunction(callback)) {

          callback(task);
        }
      };

      doRequest();
    })
  }

  handleFail(e) {
    if (this.isFail) return
    logger.error('upload file fail: ', e);
    this.isFail = true;
    this.cancel();
    this.emit('fail', e);
    this.emit('complete', e);
  }

  _event() { // step4: 发送合并请求
    // step4: 发送合并请求
    this.on('uploadDone', async () => {
      logger.timeEnd('[Uploader] uploadChunks');
      logger.info('upload chunks end');
      this.isUploading = false;
      logger.info('start merge reqeust');
      logger.time('[Uploader] mergeRequest');
      const [mergeErr, mergeResp] = await awaitWrap(this.mergeRequest());
      logger.timeEnd('[Uploader] mergeRequest');
      logger.info('merge reqeust end');
      logger.debug('mergeRequest', mergeErr, mergeResp);
      if (mergeErr) {
        this.handleFail({
          errCode: 20003,
          errrMsg: mergeErr.errMsg
        });
        return
      }
      logger.info('upload file success');
      this.emit('success', {
        errCode: 0,
        ...mergeResp.data
      });
      this.emit('complete', {
        errCode: 0,
        ...mergeResp.data
      });
    });
  }

  _upload() {
    this.startUploadTime = Date.now();
    this._uploadedSize = 0;

    if (this.chunksQueue.length) {
      const maxConcurrency = this.config.maxConcurrency;
      for (let i = 0; i < maxConcurrency; i++) {
        this.uploadChunk();
      }
    } else {
      this.readFileChunk();
    }
  }

  updateUploadSize(currUploadSize) {
    this.uploadedSize += currUploadSize; // 总体上传大小,暂停后累计
    this._uploadedSize += currUploadSize; // 上传大小,暂停后清空
    const time = Date.now() - this.startUploadTime; // 当前耗时
    const averageSpeed = this._uploadedSize / time; // B/ms
    const sizeWaitSend = this.sizeNeedSend - this.uploadedSize; // 剩余需要发送的大小
    this.timeRemaining = parseInt(sizeWaitSend / averageSpeed, 10); // 剩余时间
    this.averageSpeed = parseInt(averageSpeed, 10) * 1000; // 平均速度 B/s
    this.progress = parseInt(((this.uploadedSize * 100) / this.sizeNeedSend), 10);
    this.dispatchProgress();
  }

  dispatchProgress() {
    this.emit('progress', {
      totalSize: this.totalSize,
      progress: this.progress,
      uploadedSize: this.uploadedSize,
      averageSpeed: this.averageSpeed,
      timeRemaining: this.timeRemaining
    });
  }

  pause() {
    logger.info('** pause **');
    this.isUploading = false;
    const abortIndex = Object.keys(this.uploadTasks).map(v => v * 1);
    abortIndex.forEach(index => {
      this.chunksIndexNeedRead.push(index);
      this.uploadTasks[index].abort();
    });
    this.uploadTasks = {};
  }

  resume() {
    logger.info('** resume **');
    this.isUploading = true;
    this._upload();
  }

  cancel() {
    logger.info('** cancel **');
    this.pause();
    this._reset();
  }

  _reset() {
    this.chunksIndexNeedRead = Array.from(Array(this.totalChunks).keys());
    this.chunksIndexNeedSend = Array.from(Array(this.totalChunks).keys());
    this.chunksNeedSend = this.totalChunks;
    this.sizeNeedSend = this.totalSize;
    this.identifier = '';
    this.chunksSend = 0;
    this.chunksQueue = [];
    this.uploadTasks = {};
    this.pUploadList = [];
    this.uploadedChunks = [];
    this.isUploading = false;
    this.isFail = false;
    this.progress = 0;
    this.uploadedSize = 0;
    this.averageSpeed = 0;
    this.timeRemaining = Number.POSITIVE_INFINITY;
    this.dispatchProgress();
  }

  readFileChunk() {
    const {
      tempFilePath,
      chunkSize,
      maxLoadChunks,
      chunksQueue,
      chunksIndexNeedRead,
      totalSize
    } = this;
    const chunks = Math.min(chunksIndexNeedRead.length, maxLoadChunks - chunksQueue.length);
    // 异步读取
    logger.debug(`readFileChunk chunks: ${chunks}, chunksIndexNeedRead`, this.chunksIndexNeedRead);
    for (let i = 0; i < chunks; i++) {
      const index = chunksIndexNeedRead.shift();
      const position = index * chunkSize;
      const length = Math.min(totalSize - position, chunkSize);
      if (this.isFail) break

      readFileAsync({
        filePath: tempFilePath,
        position,
        length
      }).then(res => {
        const chunk = res.data;
        this.chunksQueue.push({
          chunk,
          length,
          index
        });
        this.uploadChunk();
        return null
      }).catch(e => {
        this.handleFail({
          errCode: 10001,
          errMsg: e.errMsg
        });
      });
    }
  }

  uploadChunk() { //暂停 / 继续 /取消
    // 暂停中
    if (!this.isUploading || this.isFail) return
    // 没有更多数据了
    if (!this.chunksQueue.length) return
    // 达到最大并发度
    if (Object.keys(this.uploadTasks).length === this.config.maxConcurrency) return

    const {
      chunk,
      index,
      length
    } = this.chunksQueue.shift();

    // 跳过已发送的分块
    if (this.uploadedChunks.includes(index)) {
      this.uploadChunk();
      return
    }
    const {
      uploadUrl,
      query,
      header
    } = this.config;
    const identifier = this.identifier;
    const url = addParams(uploadUrl, {
      ...query,
      identifier,
      index,
      chunkSize: length,
      fileName: this.config.fileName,
      totalChunks: this.totalChunks,
      totalSize: this.totalSize
    });
    logger.debug(`uploadChunk index: ${index}, lenght ${length}`);
    logger.time(`[Uploader] uploadChunk index-${index}`);
    this._requestAsync({
      url,
      data: chunk,
      header: {
        ...header,
        'content-type': 'application/octet-stream'
      },
      method: 'POST',
    }, (task) => {
      this.uploadTasks[index] = task;
    }).then((res) => {
      if (res.data.result.status_info.status_code != 100) {
        this.cancel();
        return
      }
      this.chunksSend++;
      delete this.uploadTasks[index];
      this.updateUploadSize(length);
      logger.debug(`uploadChunk success chunksSend: ${this.chunksSend}`);
      logger.timeEnd(`[Uploader] uploadChunk index-${index}`);
      // 尝试继续加载文件
      this.readFileChunk();
      // 尝试继续发送下一条
      this.uploadChunk();
      // 所有分片发送完毕
      if (this.chunksSend === this.chunksNeedSend) {
        this.emit('uploadDone');
      }
      return null
    }).catch(res => {
      if (res.errMsg.includes('request:fail abort')) {
        logger.info(`chunk index-${index} will be aborted`);
      } else {
        this.handleFail({
          errCode: 20002,
          errMsg: res.errMsg
        });
      }
    });
  }

  emit(event, data) {
    this.emitter.emit(event, data);
  }

  on(event, listenr) {
    this.emitter.on(event, listenr);
  }

  off(event, listenr) {
    this.emitter.off(event, listenr);
  }

  generateIdentifier() {
    let identifier = '';
    const generator = this.config.generateIdentifier;
    if (isFunction(generator)) {
      identifier = generator();
    } else {
      const uuid = `${appId}-${Date.now()}-${Math.random()}`;
      identifier = sparkMd5.hash(uuid);
    }
    return identifier
  }

  async computeMD5() {
    const {
      tempFilePath,
      totalSize,
      chunkSize
    } = this;

    // 文件比内存限制小时,保存分片
    const isltMaxMemory = totalSize < this.config.maxMemory;
    const sliceSize = isltMaxMemory ? chunkSize : 10 * MB;
    const sliceNum = Math.ceil(totalSize / sliceSize);
    const spark = new sparkMd5.ArrayBuffer();
    for (let i = 0; i < sliceNum; i++) {
      const position = i * sliceSize;
      const length = Math.min(totalSize - position, sliceSize);
      // eslint-disable-next-line no-await-in-loop
      const [readFileErr, readFileResp] = await awaitWrap(readFileAsync({
        filePath: tempFilePath,
        position,
        length
      }));

      if (readFileErr) {
        spark.destroy();
        throw (new Error(readFileErr.errMsg))
      }

      const chunk = readFileResp.data;
      if (isltMaxMemory) {
        this.chunksQueue.push({
          chunk,
          length,
          index: i
        });
      }
      spark.append(chunk);
    }
    this.chunksIndexNeedRead = [];
    const identifier = spark.end();
    spark.destroy();
    return identifier
  }

  async verifyRequest() {
    const {
      verifyUrl,
      fileName
    } = this.config;
    const verifyResp = await this._requestAsync({
      url: verifyUrl,
      data: {
        fileName,
        identifier: this.identifier
      }
    });
    return verifyResp
  }

  async mergeRequest() {
    const {
      mergeUrl,
      fileName
    } = this.config;
    const mergeResp = await this._requestAsync({
      url: mergeUrl,
      data: {
        fileName,
        identifier: this.identifier
      }
    });
    return mergeResp
  }
}

export default Uploader;
//# sourceMappingURL=uploader.js.map

到了这里,关于uniapp微信小程序实现大文件上传 分片上传 进度条的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包