| | |
| | | "type": "2", |
| | | "url": "/view/ai/", |
| | | "title": "应用中心", |
| | | "width": 1243, |
| | | "width": 1024, |
| | | "height": 742, |
| | | "iconBlob": "", |
| | | "icon": "../../images/app-mid/algorithm-store.png", |
| | |
| | | |
| | | mounted() { |
| | | this.$nextTick(() => { |
| | | console.log('btn attrs', this.attrs) |
| | | console.log("btn sourceType", this.sourceType) |
| | | let props = {accept:''}; |
| | | if(this.sourceType == 1){ |
| | | props.accept = '.mp4'; |
| | |
| | | outline: none; |
| | | } |
| | | .uploader-btn:hover { |
| | | background-color: rgba(0, 0, 0, 0.08); |
| | | /* background-color: rgba(0, 0, 0, 0.08); */ |
| | | } |
| | | </style> |
| | |
| | | <div class="uploader-file-status"> |
| | | <span v-show="status !== 'uploading'">{{statusText}}</span> |
| | | <span v-show="status === 'uploading'"> |
| | | <!-- <span>{{progressStyle.progress}}</span> --> |
| | | <span>{{progressStyle.progress}}</span> |
| | | <em>{{formatedAverageSpeed}}</em> |
| | | |
| | | <i> {{formatedTimeRemaining}}</i> |
| | |
| | | @file-added="onFileAdded"
|
| | | @complete="onComplete"
|
| | | >
|
| | | <el-input :placeholder="uploadPlaceholder" size="small" :readonly="true" v-model="fileName">
|
| | | <!-- <uploader-drop v-if="isDrag == true">
|
| | | <div class="drag-txt">拖拽文件到这里</div>
|
| | | <span class="icon iconfont" @click.stop="showUpload = false"
|
| | | ></span
|
| | | >
|
| | | <uploader-btn>选择文件</uploader-btn>
|
| | | </uploader-drop> -->
|
| | |
|
| | | <div class="up-bar" v-if="isDrag == true">
|
| | | <div class="name">{{ fileName || uploadPlaceholder }}</div>
|
| | | <uploader-btn slot="suffix">
|
| | | <el-tooltip :content="tipWords" placement="top" v-if="tip">
|
| | | <i class="el-icon-upload2" style="font-size:18px; color:#0088ff"></i>
|
| | | <div class="open-file-btn">
|
| | | <span class="icon iconfont"></span>
|
| | | </div>
|
| | | </el-tooltip>
|
| | | <i v-else class="el-icon-upload2" style="font-size:18px; color:#0088ff"></i>
|
| | | </uploader-btn>
|
| | | <!-- <div class="open-file-btn">
|
| | | <span class="icon iconfont"></span>
|
| | | </div> -->
|
| | | </div>
|
| | | <el-input
|
| | | :placeholder="uploadPlaceholder"
|
| | | v-if="isDrag == false"
|
| | | size="small"
|
| | | :readonly="true"
|
| | | v-model="fileName"
|
| | | >
|
| | | <uploader-btn slot="suffix">
|
| | | <el-tooltip :content="tipWords" placement="top" v-if="tip">
|
| | | <i
|
| | | class="el-icon-upload2"
|
| | | style="font-size: 18px; color: #0088ff"
|
| | | ></i>
|
| | | </el-tooltip>
|
| | | <i
|
| | | v-else
|
| | | class="el-icon-upload2"
|
| | | style="font-size: 18px; color: #0088ff"
|
| | | ></i>
|
| | | </uploader-btn>
|
| | | </el-input>
|
| | | <uploader-list />
|
| | |
| | | @close="closeHandle"
|
| | | >
|
| | | <uploader-btn ref="button" :sourceType="sourceType">
|
| | | <i class="el-icon-upload2" style="font-size:18px; color:#0088ff"></i>
|
| | | <i class="el-icon-upload2" style="font-size: 18px; color: #0088ff"></i>
|
| | | 上传
|
| | | </uploader-btn>
|
| | | <uploader-list />
|
| | |
| | | </template>
|
| | |
|
| | | <script>
|
| | | import uploader from "./uploader"
|
| | | import SparkMD5 from 'spark-md5';
|
| | | import UploaderBtn from "./btn"
|
| | | import UploaderList from "./list"
|
| | | import uploader from "./uploader";
|
| | | import SparkMD5 from "spark-md5";
|
| | | import UploaderBtn from "./btn";
|
| | | import UploaderList from "./list";
|
| | | import UploaderDrop from "./drop";
|
| | |
|
| | | export default {
|
| | | components: {
|
| | | uploader,
|
| | | UploaderBtn,
|
| | | UploaderList
|
| | | UploaderList,
|
| | | UploaderDrop,
|
| | | },
|
| | | props: {
|
| | | sourceType: {
|
| | |
| | | },
|
| | | tip: {
|
| | | type: Boolean,
|
| | | default: false
|
| | | default: false,
|
| | | },
|
| | | tipWords: {
|
| | | type: String,
|
| | | default: ''
|
| | | default: "",
|
| | | },
|
| | | single: {
|
| | | type: Boolean,
|
| | | default: false
|
| | | default: false,
|
| | | },
|
| | | uploadPlaceholder: {
|
| | | type: String,
|
| | | default: ''
|
| | | default: "",
|
| | | },
|
| | | isDrag: {
|
| | | type: Boolean,
|
| | | default: false,
|
| | | },
|
| | | url: {
|
| | | type: String,
|
| | | default: "/data/api-f/file/upload" //"//192.168.20.10:3000/upload"
|
| | | default: "/data/api-f/file/upload",
|
| | | },
|
| | | attrs: {
|
| | | type: Object,
|
| | | default () {
|
| | | return {
|
| | |
|
| | | }
|
| | | }
|
| | | }
|
| | | default() {
|
| | | return {};
|
| | | },
|
| | | },
|
| | | },
|
| | | data() {
|
| | | return {
|
| | | fileName: "",
|
| | | fileMd5: "",
|
| | | // attrs: {
|
| | | // accept: 'image/*'
|
| | | // },
|
| | | statusText: {
|
| | | success: '上传成功',
|
| | | error: '上传失败',
|
| | | uploading: '上传中',
|
| | | paused: '暂停中',
|
| | | waiting: '等待中'
|
| | | }
|
| | | }
|
| | | success: "上传成功",
|
| | | error: "上传失败",
|
| | | uploading: "上传中",
|
| | | paused: "暂停中",
|
| | | waiting: "等待中",
|
| | | },
|
| | | };
|
| | | },
|
| | | computed: {
|
| | | uploader() {
|
| | |
| | | target: this.url,
|
| | | testChunks: true,
|
| | | headers: {
|
| | | Authorization: sessionStorage.getItem('loginedInfo') && JSON.parse(sessionStorage.getItem('loginedInfo')).access_token
|
| | | }
|
| | | }
|
| | | }
|
| | | Authorization:
|
| | | sessionStorage.getItem("loginedInfo") &&
|
| | | JSON.parse(sessionStorage.getItem("loginedInfo")).access_token,
|
| | | },
|
| | | };
|
| | | },
|
| | | },
|
| | | methods: {
|
| | | onFileAdded(file) {
|
| | | if (this.single) {
|
| | | this.uploader.fileList = this.uploader.fileList.slice([-1]);
|
| | | this.$emit("file-added")
|
| | | this.$emit("file-added");
|
| | | }
|
| | | this.computeMD5(file);
|
| | | },
|
| | | computeMD5(file) {
|
| | | let fileReader = new FileReader();
|
| | | let time = new Date().getTime();
|
| | | let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
|
| | | let blobSlice =
|
| | | File.prototype.slice ||
|
| | | File.prototype.mozSlice ||
|
| | | File.prototype.webkitSlice;
|
| | | let currentChunk = 0;
|
| | | const chunkSize = 10 * 1024 * 1000;
|
| | | let chunks = Math.ceil(file.size / chunkSize);
|
| | | let spark = new SparkMD5.ArrayBuffer();
|
| | | // 文件状态设为"计算MD5"
|
| | | this.statusText.paused = "准备上传,正在检查文件"
|
| | | this.statusText.paused = "准备上传,正在检查文件";
|
| | | file.pause();
|
| | | loadNext();
|
| | | fileReader.onload = (e => {
|
| | | fileReader.onload = (e) => {
|
| | | spark.append(e.target.result);
|
| | | if (currentChunk < chunks) {
|
| | | currentChunk++;
|
| | |
| | | this.computeMD5Success(md5, file);
|
| | | this.fileName = file.name;
|
| | | this.fileMd5 = md5;
|
| | | // console.log(`MD5计算完毕:${file.name} \nMD5:${md5} \n分片:${chunks} 大小:${file.size} 用时:${new Date().getTime() - time} ms`);
|
| | | }
|
| | | });
|
| | | };
|
| | | fileReader.onerror = function () {
|
| | | this.error(`文件${file.name}读取出错,请检查该文件`)
|
| | | this.error(`文件${file.name}读取出错,请检查该文件`);
|
| | | file.cancel();
|
| | | };
|
| | | function loadNext() {
|
| | | let start = currentChunk * chunkSize;
|
| | | let end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
|
| | | let end =
|
| | | start + chunkSize >= file.size ? file.size : start + chunkSize;
|
| | | fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
|
| | | }
|
| | | },
|
| | |
| | | if (location.href.indexOf("dataStack") >= 0) {
|
| | | Object.assign(this.uploader.opts, {
|
| | | query: {
|
| | | stackId: this.DataStackPool.selectedDir.id
|
| | | stackId: this.DataStackPool.selectedDir.id,
|
| | | // ...this.params,
|
| | | }
|
| | | })
|
| | | },
|
| | | });
|
| | | }
|
| | | file.uniqueIdentifier = md5;
|
| | | file.resume();
|
| | | this.statusText.paused = "暂停中";
|
| | | },
|
| | | onComplete() {
|
| | | this.$emit("complete", { filename: this.fileName, identifier: this.fileMd5 });
|
| | | this.$emit("complete", {
|
| | | filename: this.fileName,
|
| | | identifier: this.fileMd5,
|
| | | });
|
| | | },
|
| | | fileComplete() {
|
| | | // console.log('file complete', arguments)
|
| | | },
|
| | | fileComplete() {},
|
| | | closeHandle() {
|
| | | this.$emit("close")
|
| | | }
|
| | | this.$emit("close");
|
| | | },
|
| | | },
|
| | | mounted() {
|
| | | this.isDrag;
|
| | | this.$nextTick(() => {
|
| | | console.log(this.sourceType)
|
| | | window.uploader = this.$refs.uploader.uploader
|
| | | })
|
| | | }
|
| | | }
|
| | | window.uploader = this.$refs.uploader.uploader;
|
| | | });
|
| | | },
|
| | | };
|
| | | </script>
|
| | |
|
| | | <style lang="scss">
|
| | |
| | | display: none;
|
| | | }
|
| | | }
|
| | |
|
| | | .up-bar {
|
| | | height: 30px;
|
| | | margin: 25px;
|
| | | background: #f2f2f7;
|
| | | border-radius: 2px;
|
| | | display: flex;
|
| | | align-items: center;
|
| | | justify-content: space-between;
|
| | | box-sizing: border-box;
|
| | | padding: 0 20px;
|
| | | .iconfont {
|
| | | font-size: 16px;
|
| | | color: #333;
|
| | | }
|
| | | .name {
|
| | | color: #bdbdbd;
|
| | | font-size: 14px;
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | | </style>>
|
| | |
| | | <!-- <div class="close" @click="closeHandle">x</div> --> |
| | | <slot :files="files" :file-list="fileList" :started="started"> |
| | | <uploader-unsupport></uploader-unsupport> |
| | | <uploader-drop> |
| | | <!-- <p>拖动文件到该区域上传</p> --> |
| | | <UploaderDrop> |
| | | <p>拖动文件到该区域上传</p> |
| | | |
| | | <uploader-btn >选择文件</uploader-btn> |
| | | <uploader-btn :directory="true" >选择文件夹</uploader-btn> |
| | | </uploader-drop> |
| | | </UploaderDrop> |
| | | <uploader-list></uploader-list> |
| | | </slot> |
| | | </div> |
| | |
| | | uploader.on('fileRemoved', this.fileRemoved) |
| | | uploader.on('filesSubmitted', this.filesSubmitted) |
| | | }, |
| | | |
| | | mounted() { |
| | | }, |
| | | destroyed() { |
| | | //this.unBindUploader(); |
| | | const uploader = this.uploader |
| | | uploader.off('catchAll', this.allEvent) |
| | | uploader.off(FILE_ADDED_EVENT, this.fileAdded) |
| | |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <label class="uploader-btn" ref="btn" v-show="support"> |
| | | <slot></slot> |
| | | </label> |
| | | </template> |
| | | |
| | | <script> |
| | | import { uploaderMixin, supportMixin } from './common/mixins' |
| | | |
| | | const COMPONENT_NAME = 'uploader-btn' |
| | | |
| | | export default { |
| | | name: COMPONENT_NAME, |
| | | mixins: [uploaderMixin, supportMixin], |
| | | props: { |
| | | directory: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | single: { |
| | | type: Boolean, |
| | | default: false |
| | | }, |
| | | attrs: { |
| | | type: Object, |
| | | default() { |
| | | return {} |
| | | } |
| | | }, |
| | | sourceType: { |
| | | type: Number, |
| | | } |
| | | }, |
| | | |
| | | mounted() { |
| | | this.$nextTick(() => { |
| | | let props = {accept:''}; |
| | | if(this.sourceType == 1){ |
| | | props.accept = '.mp4'; |
| | | }else if(this.sourceType == 2){ |
| | | props.accept = '.jpg,.jpeg,.png'; |
| | | } |
| | | this.uploader.uploader.assignBrowse(this.$refs.btn, this.directory, this.single, props) |
| | | }) |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style> |
| | | .uploader-btn { |
| | | display: inline-block; |
| | | position: relative; |
| | | padding: 4px 8px; |
| | | font-size: 100%; |
| | | line-height: 1.4; |
| | | color: #666; |
| | | border: 1px solid #666; |
| | | cursor: pointer; |
| | | border-radius: 2px; |
| | | background: none; |
| | | outline: none; |
| | | } |
| | | .uploader-btn:hover { |
| | | /* background-color: rgba(0, 0, 0, 0.08); */ |
| | | } |
| | | </style> |
New file |
| | |
| | | const events = ['fileProgress', 'fileSuccess', 'fileComplete', 'fileError'] |
| | | |
| | | export default events |
New file |
| | |
| | | export const uploaderMixin = { |
| | | inject: ['uploader'] |
| | | } |
| | | |
| | | export const supportMixin = { |
| | | data () { |
| | | return { |
| | | support: true |
| | | } |
| | | }, |
| | | mounted () { |
| | | this.support = this.uploader.uploader.support |
| | | } |
| | | } |
New file |
| | |
| | | /*! |
| | | * Uploader - Uploader library implements html5 file upload and provides multiple simultaneous, stable, fault tolerant and resumable uploads |
| | | * @version v0.5.4 |
| | | * @author dolymood <dolymood@gmail.com> |
| | | * @link https://github.com/simple-uploader/Uploader |
| | | * @license MIT |
| | | */ |
| | | !function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.Uploader=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ |
| | | var utils = _dereq_('./utils') |
| | | |
| | | function Chunk (uploader, file, offset) { |
| | | utils.defineNonEnumerable(this, 'uploader', uploader) |
| | | utils.defineNonEnumerable(this, 'file', file) |
| | | utils.defineNonEnumerable(this, 'bytes', null) |
| | | this.offset = offset |
| | | this.tested = false |
| | | this.retries = 0 |
| | | this.pendingRetry = false |
| | | this.preprocessState = 0 |
| | | this.readState = 0 |
| | | this.loaded = 0 |
| | | this.total = 0 |
| | | this.chunkSize = this.uploader.opts.chunkSize |
| | | this.startByte = this.offset * this.chunkSize |
| | | this.endByte = this.computeEndByte() |
| | | this.xhr = null |
| | | } |
| | | |
| | | var STATUS = Chunk.STATUS = { |
| | | PENDING: 'pending', |
| | | UPLOADING: 'uploading', |
| | | READING: 'reading', |
| | | SUCCESS: 'success', |
| | | ERROR: 'error', |
| | | COMPLETE: 'complete', |
| | | PROGRESS: 'progress', |
| | | RETRY: 'retry' |
| | | } |
| | | |
| | | utils.extend(Chunk.prototype, { |
| | | |
| | | _event: function (evt, args) { |
| | | args = utils.toArray(arguments) |
| | | args.unshift(this) |
| | | this.file._chunkEvent.apply(this.file, args) |
| | | }, |
| | | |
| | | computeEndByte: function () { |
| | | var endByte = Math.min(this.file.size, (this.offset + 1) * this.chunkSize) |
| | | if (this.file.size - endByte < this.chunkSize && !this.uploader.opts.forceChunkSize) { |
| | | // The last chunk will be bigger than the chunk size, |
| | | // but less than 2 * this.chunkSize |
| | | endByte = this.file.size |
| | | } |
| | | return endByte |
| | | }, |
| | | |
| | | getParams: function () { |
| | | return { |
| | | chunkNumber: this.offset + 1, |
| | | chunkSize: this.uploader.opts.chunkSize, |
| | | currentChunkSize: this.endByte - this.startByte, |
| | | totalSize: this.file.size, |
| | | identifier: this.file.uniqueIdentifier, |
| | | filename: this.file.name, |
| | | relativePath: this.file.relativePath, |
| | | totalChunks: this.file.chunks.length |
| | | } |
| | | }, |
| | | |
| | | getTarget: function (target, params) { |
| | | if (!params.length) { |
| | | return target |
| | | } |
| | | if (target.indexOf('?') < 0) { |
| | | target += '?' |
| | | } else { |
| | | target += '&' |
| | | } |
| | | return target + params.join('&') |
| | | }, |
| | | |
| | | test: function () { |
| | | this.xhr = new XMLHttpRequest() |
| | | this.xhr.addEventListener('load', testHandler, false) |
| | | this.xhr.addEventListener('error', testHandler, false) |
| | | var testMethod = utils.evalOpts(this.uploader.opts.testMethod, this.file, this) |
| | | var data = this.prepareXhrRequest(testMethod, true) |
| | | this.xhr.send(data) |
| | | |
| | | var $ = this |
| | | function testHandler (event) { |
| | | var status = $.status(true) |
| | | if (status === STATUS.ERROR) { |
| | | $._event(status, $.message()) |
| | | $.uploader.uploadNextChunk() |
| | | } else if (status === STATUS.SUCCESS) { |
| | | $._event(status, $.message()) |
| | | $.tested = true |
| | | } else if (!$.file.paused) { |
| | | // Error might be caused by file pause method |
| | | // Chunks does not exist on the server side |
| | | $.tested = true |
| | | $.send() |
| | | } |
| | | } |
| | | }, |
| | | |
| | | preprocessFinished: function () { |
| | | // Compute the endByte after the preprocess function to allow an |
| | | // implementer of preprocess to set the fileObj size |
| | | this.endByte = this.computeEndByte() |
| | | this.preprocessState = 2 |
| | | this.send() |
| | | }, |
| | | |
| | | readFinished: function (bytes) { |
| | | this.readState = 2 |
| | | this.bytes = bytes |
| | | this.send() |
| | | }, |
| | | |
| | | send: function () { |
| | | var preprocess = this.uploader.opts.preprocess |
| | | var read = this.uploader.opts.readFileFn |
| | | if (utils.isFunction(preprocess)) { |
| | | switch (this.preprocessState) { |
| | | case 0: |
| | | this.preprocessState = 1 |
| | | preprocess(this) |
| | | return |
| | | case 1: |
| | | return |
| | | } |
| | | } |
| | | switch (this.readState) { |
| | | case 0: |
| | | this.readState = 1 |
| | | read(this.file, this.file.fileType, this.startByte, this.endByte, this) |
| | | return |
| | | case 1: |
| | | return |
| | | } |
| | | if (this.uploader.opts.testChunks && !this.tested) { |
| | | this.test() |
| | | return |
| | | } |
| | | |
| | | this.loaded = 0 |
| | | this.total = 0 |
| | | this.pendingRetry = false |
| | | |
| | | // Set up request and listen for event |
| | | this.xhr = new XMLHttpRequest() |
| | | this.xhr.upload.addEventListener('progress', progressHandler, false) |
| | | this.xhr.addEventListener('load', doneHandler, false) |
| | | this.xhr.addEventListener('error', doneHandler, false) |
| | | |
| | | var uploadMethod = utils.evalOpts(this.uploader.opts.uploadMethod, this.file, this) |
| | | var data = this.prepareXhrRequest(uploadMethod, false, this.uploader.opts.method, this.bytes) |
| | | this.xhr.send(data) |
| | | |
| | | var $ = this |
| | | function progressHandler (event) { |
| | | if (event.lengthComputable) { |
| | | $.loaded = event.loaded |
| | | $.total = event.total |
| | | } |
| | | $._event(STATUS.PROGRESS, event) |
| | | } |
| | | |
| | | function doneHandler (event) { |
| | | var msg = $.message() |
| | | $.processingResponse = true |
| | | $.uploader.opts.processResponse(msg, function (err, res) { |
| | | $.processingResponse = false |
| | | if (!$.xhr) { |
| | | return |
| | | } |
| | | $.processedState = { |
| | | err: err, |
| | | res: res |
| | | } |
| | | var status = $.status() |
| | | if (status === STATUS.SUCCESS || status === STATUS.ERROR) { |
| | | delete this.data |
| | | $._event(status, res) |
| | | status === STATUS.ERROR && $.uploader.uploadNextChunk() |
| | | } else { |
| | | $._event(STATUS.RETRY, res) |
| | | $.pendingRetry = true |
| | | $.abort() |
| | | $.retries++ |
| | | var retryInterval = $.uploader.opts.chunkRetryInterval |
| | | if (retryInterval !== null) { |
| | | setTimeout(function () { |
| | | $.send() |
| | | }, retryInterval) |
| | | } else { |
| | | $.send() |
| | | } |
| | | } |
| | | }, $.file, $) |
| | | } |
| | | }, |
| | | |
| | | abort: function () { |
| | | var xhr = this.xhr |
| | | this.xhr = null |
| | | this.processingResponse = false |
| | | this.processedState = null |
| | | if (xhr) { |
| | | xhr.abort() |
| | | } |
| | | }, |
| | | |
| | | status: function (isTest) { |
| | | if (this.readState === 1) { |
| | | return STATUS.READING |
| | | } else if (this.pendingRetry || this.preprocessState === 1) { |
| | | // if pending retry then that's effectively the same as actively uploading, |
| | | // there might just be a slight delay before the retry starts |
| | | return STATUS.UPLOADING |
| | | } else if (!this.xhr) { |
| | | return STATUS.PENDING |
| | | } else if (this.xhr.readyState < 4 || this.processingResponse) { |
| | | // Status is really 'OPENED', 'HEADERS_RECEIVED' |
| | | // or 'LOADING' - meaning that stuff is happening |
| | | return STATUS.UPLOADING |
| | | } else { |
| | | var _status |
| | | if (this.uploader.opts.successStatuses.indexOf(this.xhr.status) > -1) { |
| | | // HTTP 200, perfect |
| | | // HTTP 202 Accepted - The request has been accepted for processing, but the processing has not been completed. |
| | | _status = STATUS.SUCCESS |
| | | } else if (this.uploader.opts.permanentErrors.indexOf(this.xhr.status) > -1 || |
| | | !isTest && this.retries >= this.uploader.opts.maxChunkRetries) { |
| | | // HTTP 415/500/501, permanent error |
| | | _status = STATUS.ERROR |
| | | } else { |
| | | // this should never happen, but we'll reset and queue a retry |
| | | // a likely case for this would be 503 service unavailable |
| | | this.abort() |
| | | _status = STATUS.PENDING |
| | | } |
| | | var processedState = this.processedState |
| | | if (processedState && processedState.err) { |
| | | _status = STATUS.ERROR |
| | | } |
| | | return _status |
| | | } |
| | | }, |
| | | |
| | | message: function () { |
| | | return this.xhr ? this.xhr.responseText : '' |
| | | }, |
| | | |
| | | progress: function () { |
| | | if (this.pendingRetry) { |
| | | return 0 |
| | | } |
| | | var s = this.status() |
| | | if (s === STATUS.SUCCESS || s === STATUS.ERROR) { |
| | | return 1 |
| | | } else if (s === STATUS.PENDING) { |
| | | return 0 |
| | | } else { |
| | | return this.total > 0 ? this.loaded / this.total : 0 |
| | | } |
| | | }, |
| | | |
| | | sizeUploaded: function () { |
| | | var size = this.endByte - this.startByte |
| | | // can't return only chunk.loaded value, because it is bigger than chunk size |
| | | if (this.status() !== STATUS.SUCCESS) { |
| | | size = this.progress() * size |
| | | } |
| | | return size |
| | | }, |
| | | |
| | | prepareXhrRequest: function (method, isTest, paramsMethod, blob) { |
| | | // Add data from the query options |
| | | var query = utils.evalOpts(this.uploader.opts.query, this.file, this, isTest) |
| | | query = utils.extend(this.getParams(), query) |
| | | |
| | | // processParams |
| | | query = this.uploader.opts.processParams(query, this.file, this, isTest) |
| | | |
| | | var target = utils.evalOpts(this.uploader.opts.target, this.file, this, isTest) |
| | | var data = null |
| | | if (method === 'GET' || paramsMethod === 'octet') { |
| | | // Add data from the query options |
| | | var params = [] |
| | | utils.each(query, function (v, k) { |
| | | params.push([encodeURIComponent(k), encodeURIComponent(v)].join('=')) |
| | | }) |
| | | target = this.getTarget(target, params) |
| | | data = blob || null |
| | | } else { |
| | | // Add data from the query options |
| | | data = new FormData() |
| | | utils.each(query, function (v, k) { |
| | | data.append(k, v) |
| | | }) |
| | | if (typeof blob !== 'undefined') { |
| | | data.append(this.uploader.opts.fileParameterName, blob, this.file.name) |
| | | } |
| | | } |
| | | |
| | | this.xhr.open(method, target, true) |
| | | this.xhr.withCredentials = this.uploader.opts.withCredentials |
| | | |
| | | // Add data from header options |
| | | utils.each(utils.evalOpts(this.uploader.opts.headers, this.file, this, isTest), function (v, k) { |
| | | this.xhr.setRequestHeader(k, v) |
| | | }, this) |
| | | |
| | | return data |
| | | } |
| | | |
| | | }) |
| | | |
| | | module.exports = Chunk |
| | | |
| | | },{"./utils":5}],2:[function(_dereq_,module,exports){ |
| | | var each = _dereq_('./utils').each |
| | | |
| | | var event = { |
| | | |
| | | _eventData: null, |
| | | |
| | | on: function (name, func) { |
| | | if (!this._eventData) this._eventData = {} |
| | | if (!this._eventData[name]) this._eventData[name] = [] |
| | | var listened = false |
| | | each(this._eventData[name], function (fuc) { |
| | | if (fuc === func) { |
| | | listened = true |
| | | return false |
| | | } |
| | | }) |
| | | if (!listened) { |
| | | this._eventData[name].push(func) |
| | | } |
| | | }, |
| | | |
| | | off: function (name, func) { |
| | | if (!this._eventData) this._eventData = {} |
| | | if (!this._eventData[name] || !this._eventData[name].length) return |
| | | if (func) { |
| | | each(this._eventData[name], function (fuc, i) { |
| | | if (fuc === func) { |
| | | this._eventData[name].splice(i, 1) |
| | | return false |
| | | } |
| | | }, this) |
| | | } else { |
| | | this._eventData[name] = [] |
| | | } |
| | | }, |
| | | |
| | | trigger: function (name) { |
| | | if (!this._eventData) this._eventData = {} |
| | | if (!this._eventData[name]) return true |
| | | var args = this._eventData[name].slice.call(arguments, 1) |
| | | var preventDefault = false |
| | | each(this._eventData[name], function (fuc) { |
| | | preventDefault = fuc.apply(this, args) === false || preventDefault |
| | | }, this) |
| | | return !preventDefault |
| | | } |
| | | } |
| | | |
| | | module.exports = event |
| | | |
| | | },{"./utils":5}],3:[function(_dereq_,module,exports){ |
| | | var utils = _dereq_('./utils') |
| | | var event = _dereq_('./event') |
| | | var File = _dereq_('./file') |
| | | var Chunk = _dereq_('./chunk') |
| | | |
| | | var version = '0.5.4' |
| | | |
| | | var isServer = typeof window === 'undefined' |
| | | |
| | | // ie10+ |
| | | var ie10plus = isServer ? false : window.navigator.msPointerEnabled |
| | | var support = (function () { |
| | | if (isServer) { |
| | | return false |
| | | } |
| | | var sliceName = 'slice' |
| | | var _support = utils.isDefined(window.File) && utils.isDefined(window.Blob) && |
| | | utils.isDefined(window.FileList) |
| | | var bproto = null |
| | | if (_support) { |
| | | bproto = window.Blob.prototype |
| | | utils.each(['slice', 'webkitSlice', 'mozSlice'], function (n) { |
| | | if (bproto[n]) { |
| | | sliceName = n |
| | | return false |
| | | } |
| | | }) |
| | | _support = !!bproto[sliceName] |
| | | } |
| | | if (_support) Uploader.sliceName = sliceName |
| | | bproto = null |
| | | return _support |
| | | })() |
| | | |
| | | var supportDirectory = (function () { |
| | | if (isServer) { |
| | | return false |
| | | } |
| | | var input = window.document.createElement('input') |
| | | input.type = 'file' |
| | | var sd = 'webkitdirectory' in input || 'directory' in input |
| | | input = null |
| | | return sd |
| | | })() |
| | | |
| | | function Uploader (opts) { |
| | | this.support = support |
| | | /* istanbul ignore if */ |
| | | if (!this.support) { |
| | | return |
| | | } |
| | | this.supportDirectory = supportDirectory |
| | | utils.defineNonEnumerable(this, 'filePaths', {}) |
| | | this.opts = utils.extend({}, Uploader.defaults, opts || {}) |
| | | |
| | | this.preventEvent = utils.bind(this._preventEvent, this) |
| | | |
| | | File.call(this, this) |
| | | } |
| | | |
| | | /** |
| | | * Default read function using the webAPI |
| | | * |
| | | * @function webAPIFileRead(fileObj, fileType, startByte, endByte, chunk) |
| | | * |
| | | */ |
| | | var webAPIFileRead = function (fileObj, fileType, startByte, endByte, chunk) { |
| | | chunk.readFinished(fileObj.file[Uploader.sliceName](startByte, endByte, fileType)) |
| | | } |
| | | |
| | | Uploader.version = version |
| | | |
| | | Uploader.defaults = { |
| | | chunkSize: 1024 * 1024, |
| | | forceChunkSize: false, |
| | | simultaneousUploads: 3, |
| | | singleFile: false, |
| | | fileParameterName: 'file', |
| | | progressCallbacksInterval: 500, |
| | | speedSmoothingFactor: 0.1, |
| | | query: {}, |
| | | headers: {}, |
| | | withCredentials: false, |
| | | preprocess: null, |
| | | method: 'multipart', |
| | | testMethod: 'GET', |
| | | uploadMethod: 'POST', |
| | | prioritizeFirstAndLastChunk: false, |
| | | allowDuplicateUploads: false, |
| | | target: '/', |
| | | testChunks: true, |
| | | generateUniqueIdentifier: null, |
| | | maxChunkRetries: 0, |
| | | chunkRetryInterval: null, |
| | | permanentErrors: [404, 415, 500, 501], |
| | | successStatuses: [200, 201, 202], |
| | | onDropStopPropagation: false, |
| | | initFileFn: null, |
| | | readFileFn: webAPIFileRead, |
| | | checkChunkUploadedByResponse: null, |
| | | initialPaused: false, |
| | | processResponse: function (response, cb) { |
| | | cb(null, response) |
| | | }, |
| | | processParams: function (params) { |
| | | return params |
| | | } |
| | | } |
| | | |
| | | Uploader.utils = utils |
| | | Uploader.event = event |
| | | Uploader.File = File |
| | | Uploader.Chunk = Chunk |
| | | |
| | | // inherit file |
| | | Uploader.prototype = utils.extend({}, File.prototype) |
| | | // inherit event |
| | | utils.extend(Uploader.prototype, event) |
| | | utils.extend(Uploader.prototype, { |
| | | |
| | | constructor: Uploader, |
| | | |
| | | _trigger: function (name) { |
| | | var args = utils.toArray(arguments) |
| | | var preventDefault = !this.trigger.apply(this, arguments) |
| | | if (name !== 'catchAll') { |
| | | args.unshift('catchAll') |
| | | preventDefault = !this.trigger.apply(this, args) || preventDefault |
| | | } |
| | | return !preventDefault |
| | | }, |
| | | |
| | | _triggerAsync: function () { |
| | | var args = arguments |
| | | utils.nextTick(function () { |
| | | this._trigger.apply(this, args) |
| | | }, this) |
| | | }, |
| | | |
| | | addFiles: function (files, evt) { |
| | | var _files = [] |
| | | var oldFileListLen = this.fileList.length |
| | | utils.each(files, function (file) { |
| | | // Uploading empty file IE10/IE11 hangs indefinitely |
| | | // Directories have size `0` and name `.` |
| | | // Ignore already added files if opts.allowDuplicateUploads is set to false |
| | | if ((!ie10plus || ie10plus && file.size > 0) && !(file.size % 4096 === 0 && (file.name === '.' || file.fileName === '.'))) { |
| | | var uniqueIdentifier = this.generateUniqueIdentifier(file) |
| | | if (this.opts.allowDuplicateUploads || !this.getFromUniqueIdentifier(uniqueIdentifier)) { |
| | | var _file = new File(this, file, this) |
| | | _file.uniqueIdentifier = uniqueIdentifier |
| | | if (this._trigger('fileAdded', _file, evt)) { |
| | | _files.push(_file) |
| | | } else { |
| | | File.prototype.removeFile.call(this, _file) |
| | | } |
| | | } |
| | | } |
| | | }, this) |
| | | // get new fileList |
| | | var newFileList = this.fileList.slice(oldFileListLen) |
| | | if (this._trigger('filesAdded', _files, newFileList, evt)) { |
| | | utils.each(_files, function (file) { |
| | | if (this.opts.singleFile && this.files.length > 0) { |
| | | this.removeFile(this.files[0]) |
| | | } |
| | | this.files.push(file) |
| | | }, this) |
| | | this._trigger('filesSubmitted', _files, newFileList, evt) |
| | | } else { |
| | | utils.each(newFileList, function (file) { |
| | | File.prototype.removeFile.call(this, file) |
| | | }, this) |
| | | } |
| | | }, |
| | | |
| | | addFile: function (file, evt) { |
| | | this.addFiles([file], evt) |
| | | }, |
| | | |
| | | cancel: function () { |
| | | for (var i = this.fileList.length - 1; i >= 0; i--) { |
| | | this.fileList[i].cancel() |
| | | } |
| | | }, |
| | | |
| | | removeFile: function (file) { |
| | | File.prototype.removeFile.call(this, file) |
| | | this._trigger('fileRemoved', file) |
| | | }, |
| | | |
| | | generateUniqueIdentifier: function (file) { |
| | | var custom = this.opts.generateUniqueIdentifier |
| | | if (utils.isFunction(custom)) { |
| | | return custom(file) |
| | | } |
| | | /* istanbul ignore next */ |
| | | // Some confusion in different versions of Firefox |
| | | var relativePath = file.relativePath || file.webkitRelativePath || file.fileName || file.name |
| | | /* istanbul ignore next */ |
| | | return file.size + '-' + relativePath.replace(/[^0-9a-zA-Z_-]/img, '') |
| | | }, |
| | | |
| | | getFromUniqueIdentifier: function (uniqueIdentifier) { |
| | | var ret = false |
| | | utils.each(this.files, function (file) { |
| | | if (file.uniqueIdentifier === uniqueIdentifier) { |
| | | ret = file |
| | | return false |
| | | } |
| | | }) |
| | | return ret |
| | | }, |
| | | |
| | | uploadNextChunk: function (preventEvents) { |
| | | var found = false |
| | | var pendingStatus = Chunk.STATUS.PENDING |
| | | var checkChunkUploaded = this.uploader.opts.checkChunkUploadedByResponse |
| | | if (this.opts.prioritizeFirstAndLastChunk) { |
| | | utils.each(this.files, function (file) { |
| | | if (file.paused) { |
| | | return |
| | | } |
| | | if (checkChunkUploaded && !file._firstResponse && file.isUploading()) { |
| | | // waiting for current file's first chunk response |
| | | return |
| | | } |
| | | if (file.chunks.length && file.chunks[0].status() === pendingStatus) { |
| | | file.chunks[0].send() |
| | | found = true |
| | | return false |
| | | } |
| | | if (file.chunks.length > 1 && file.chunks[file.chunks.length - 1].status() === pendingStatus) { |
| | | file.chunks[file.chunks.length - 1].send() |
| | | found = true |
| | | return false |
| | | } |
| | | }) |
| | | if (found) { |
| | | return found |
| | | } |
| | | } |
| | | |
| | | // Now, simply look for the next, best thing to upload |
| | | utils.each(this.files, function (file) { |
| | | if (!file.paused) { |
| | | if (checkChunkUploaded && !file._firstResponse && file.isUploading()) { |
| | | // waiting for current file's first chunk response |
| | | return |
| | | } |
| | | utils.each(file.chunks, function (chunk) { |
| | | if (chunk.status() === pendingStatus) { |
| | | chunk.send() |
| | | found = true |
| | | return false |
| | | } |
| | | }) |
| | | } |
| | | if (found) { |
| | | return false |
| | | } |
| | | }) |
| | | if (found) { |
| | | return true |
| | | } |
| | | |
| | | // The are no more outstanding chunks to upload, check is everything is done |
| | | var outstanding = false |
| | | utils.each(this.files, function (file) { |
| | | if (!file.isComplete()) { |
| | | outstanding = true |
| | | return false |
| | | } |
| | | }) |
| | | // should check files now |
| | | // if now files in list |
| | | // should not trigger complete event |
| | | if (!outstanding && !preventEvents && this.files.length) { |
| | | // All chunks have been uploaded, complete |
| | | this._triggerAsync('complete') |
| | | } |
| | | return outstanding |
| | | }, |
| | | |
| | | upload: function (preventEvents) { |
| | | // Make sure we don't start too many uploads at once |
| | | var ret = this._shouldUploadNext() |
| | | if (ret === false) { |
| | | return |
| | | } |
| | | !preventEvents && this._trigger('uploadStart') |
| | | var started = false |
| | | for (var num = 1; num <= this.opts.simultaneousUploads - ret; num++) { |
| | | started = this.uploadNextChunk(!preventEvents) || started |
| | | if (!started && preventEvents) { |
| | | // completed |
| | | break |
| | | } |
| | | } |
| | | if (!started && !preventEvents) { |
| | | this._triggerAsync('complete') |
| | | } |
| | | }, |
| | | |
| | | /** |
| | | * should upload next chunk |
| | | * @function |
| | | * @returns {Boolean|Number} |
| | | */ |
| | | _shouldUploadNext: function () { |
| | | var num = 0 |
| | | var should = true |
| | | var simultaneousUploads = this.opts.simultaneousUploads |
| | | var uploadingStatus = Chunk.STATUS.UPLOADING |
| | | utils.each(this.files, function (file) { |
| | | utils.each(file.chunks, function (chunk) { |
| | | if (chunk.status() === uploadingStatus) { |
| | | num++ |
| | | if (num >= simultaneousUploads) { |
| | | should = false |
| | | return false |
| | | } |
| | | } |
| | | }) |
| | | return should |
| | | }) |
| | | // if should is true then return uploading chunks's length |
| | | return should && num |
| | | }, |
| | | |
| | | /** |
| | | * Assign a browse action to one or more DOM nodes. |
| | | * @function |
| | | * @param {Element|Array.<Element>} domNodes |
| | | * @param {boolean} isDirectory Pass in true to allow directories to |
| | | * @param {boolean} singleFile prevent multi file upload |
| | | * @param {Object} attributes set custom attributes: |
| | | * http://www.w3.org/TR/html-markup/input.file.html#input.file-attributes |
| | | * eg: accept: 'image/*' |
| | | * be selected (Chrome only). |
| | | */ |
| | | assignBrowse: function (domNodes, isDirectory, singleFile, attributes) { |
| | | if (typeof domNodes.length === 'undefined') { |
| | | domNodes = [domNodes] |
| | | } |
| | | |
| | | utils.each(domNodes, function (domNode) { |
| | | var input |
| | | if (domNode.tagName === 'INPUT' && domNode.type === 'file') { |
| | | input = domNode |
| | | } else { |
| | | input = document.createElement('input') |
| | | input.setAttribute('type', 'file') |
| | | // display:none - not working in opera 12 |
| | | utils.extend(input.style, { |
| | | visibility: 'hidden', |
| | | position: 'absolute', |
| | | width: '1px', |
| | | height: '1px' |
| | | }) |
| | | // for opera 12 browser, input must be assigned to a document |
| | | Array.from(domNode.children).forEach(function(child){ |
| | | if(child.type=='file'){ |
| | | console.log(child) |
| | | domNode.removeChild(child) |
| | | } |
| | | }) |
| | | domNode.appendChild(input) |
| | | // https://developer.mozilla.org/en/using_files_from_web_applications) |
| | | // event listener is executed two times |
| | | // first one - original mouse click event |
| | | // second - input.click(), input is inside domNode |
| | | domNode.addEventListener('click', function (e) { |
| | | if (domNode.tagName.toLowerCase() === 'label') { |
| | | return |
| | | } |
| | | input.click() |
| | | }, false) |
| | | } |
| | | if (!this.opts.singleFile && !singleFile) { |
| | | input.setAttribute('multiple', 'multiple') |
| | | } |
| | | if (isDirectory) { |
| | | input.setAttribute('webkitdirectory', 'webkitdirectory') |
| | | } |
| | | attributes && utils.each(attributes, function (value, key) { |
| | | input.setAttribute(key, value) |
| | | }) |
| | | // When new files are added, simply append them to the overall list |
| | | var that = this |
| | | input.addEventListener('change', function (e) { |
| | | that._trigger(e.type, e) |
| | | if (e.target.value) { |
| | | that.addFiles(e.target.files, e) |
| | | e.target.value = '' |
| | | } |
| | | }, false) |
| | | }, this) |
| | | }, |
| | | |
| | | onDrop: function (evt) { |
| | | this._trigger(evt.type, evt) |
| | | if (this.opts.onDropStopPropagation) { |
| | | evt.stopPropagation() |
| | | } |
| | | evt.preventDefault() |
| | | this._parseDataTransfer(evt.dataTransfer, evt) |
| | | }, |
| | | |
| | | _parseDataTransfer: function (dataTransfer, evt) { |
| | | if (dataTransfer.items && dataTransfer.items[0] && |
| | | dataTransfer.items[0].webkitGetAsEntry) { |
| | | this.webkitReadDataTransfer(dataTransfer, evt) |
| | | } else { |
| | | this.addFiles(dataTransfer.files, evt) |
| | | } |
| | | }, |
| | | |
| | | webkitReadDataTransfer: function (dataTransfer, evt) { |
| | | var self = this |
| | | var queue = dataTransfer.items.length |
| | | var files = [] |
| | | utils.each(dataTransfer.items, function (item) { |
| | | var entry = item.webkitGetAsEntry() |
| | | if (!entry) { |
| | | decrement() |
| | | return |
| | | } |
| | | if (entry.isFile) { |
| | | // due to a bug in Chrome's File System API impl - #149735 |
| | | fileReadSuccess(item.getAsFile(), entry.fullPath) |
| | | } else { |
| | | readDirectory(entry.createReader()) |
| | | } |
| | | }) |
| | | function readDirectory (reader) { |
| | | reader.readEntries(function (entries) { |
| | | if (entries.length) { |
| | | queue += entries.length |
| | | utils.each(entries, function (entry) { |
| | | if (entry.isFile) { |
| | | var fullPath = entry.fullPath |
| | | entry.file(function (file) { |
| | | fileReadSuccess(file, fullPath) |
| | | }, readError) |
| | | } else if (entry.isDirectory) { |
| | | readDirectory(entry.createReader()) |
| | | } |
| | | }) |
| | | readDirectory(reader) |
| | | } else { |
| | | decrement() |
| | | } |
| | | }, readError) |
| | | } |
| | | function fileReadSuccess (file, fullPath) { |
| | | // relative path should not start with "/" |
| | | file.relativePath = fullPath.substring(1) |
| | | files.push(file) |
| | | decrement() |
| | | } |
| | | function readError (fileError) { |
| | | throw fileError |
| | | } |
| | | function decrement () { |
| | | if (--queue === 0) { |
| | | self.addFiles(files, evt) |
| | | } |
| | | } |
| | | }, |
| | | |
| | | _assignHelper: function (domNodes, handles, remove) { |
| | | if (typeof domNodes.length === 'undefined') { |
| | | domNodes = [domNodes] |
| | | } |
| | | var evtMethod = remove ? 'removeEventListener' : 'addEventListener' |
| | | utils.each(domNodes, function (domNode) { |
| | | utils.each(handles, function (handler, name) { |
| | | domNode[evtMethod](name, handler, false) |
| | | }, this) |
| | | }, this) |
| | | }, |
| | | |
| | | _preventEvent: function (e) { |
| | | utils.preventEvent(e) |
| | | this._trigger(e.type, e) |
| | | }, |
| | | |
| | | /** |
| | | * Assign one or more DOM nodes as a drop target. |
| | | * @function |
| | | * @param {Element|Array.<Element>} domNodes |
| | | */ |
| | | assignDrop: function (domNodes) { |
| | | this._onDrop = utils.bind(this.onDrop, this) |
| | | this._assignHelper(domNodes, { |
| | | dragover: this.preventEvent, |
| | | dragenter: this.preventEvent, |
| | | dragleave: this.preventEvent, |
| | | drop: this._onDrop |
| | | }) |
| | | }, |
| | | |
| | | /** |
| | | * Un-assign drop event from DOM nodes |
| | | * @function |
| | | * @param domNodes |
| | | */ |
| | | unAssignDrop: function (domNodes) { |
| | | this._assignHelper(domNodes, { |
| | | dragover: this.preventEvent, |
| | | dragenter: this.preventEvent, |
| | | dragleave: this.preventEvent, |
| | | drop: this._onDrop |
| | | }, true) |
| | | this._onDrop = null |
| | | } |
| | | }) |
| | | |
| | | module.exports = Uploader |
| | | |
| | | },{"./chunk":1,"./event":2,"./file":4,"./utils":5}],4:[function(_dereq_,module,exports){ |
| | | var utils = _dereq_('./utils') |
| | | var Chunk = _dereq_('./chunk') |
| | | |
| | | function File (uploader, file, parent) { |
| | | utils.defineNonEnumerable(this, 'uploader', uploader) |
| | | this.isRoot = this.isFolder = uploader === this |
| | | utils.defineNonEnumerable(this, 'parent', parent || null) |
| | | utils.defineNonEnumerable(this, 'files', []) |
| | | utils.defineNonEnumerable(this, 'fileList', []) |
| | | utils.defineNonEnumerable(this, 'chunks', []) |
| | | utils.defineNonEnumerable(this, '_errorFiles', []) |
| | | utils.defineNonEnumerable(this, 'file', null) |
| | | this.id = utils.uid() |
| | | |
| | | if (this.isRoot || !file) { |
| | | this.file = null |
| | | } else { |
| | | if (utils.isString(file)) { |
| | | // folder |
| | | this.isFolder = true |
| | | this.file = null |
| | | this.path = file |
| | | if (this.parent.path) { |
| | | file = file.substr(this.parent.path.length) |
| | | } |
| | | this.name = file.charAt(file.length - 1) === '/' ? file.substr(0, file.length - 1) : file |
| | | } else { |
| | | this.file = file |
| | | this.fileType = this.file.type |
| | | this.name = file.fileName || file.name |
| | | this.size = file.size |
| | | this.relativePath = file.relativePath || file.webkitRelativePath || this.name |
| | | this._parseFile() |
| | | } |
| | | } |
| | | |
| | | this.paused = uploader.opts.initialPaused |
| | | this.error = false |
| | | this.allError = false |
| | | this.aborted = false |
| | | this.completed = false |
| | | this.averageSpeed = 0 |
| | | this.currentSpeed = 0 |
| | | this._lastProgressCallback = Date.now() |
| | | this._prevUploadedSize = 0 |
| | | this._prevProgress = 0 |
| | | |
| | | this.bootstrap() |
| | | } |
| | | |
| | | utils.extend(File.prototype, { |
| | | |
| | | _parseFile: function () { |
| | | var ppaths = parsePaths(this.relativePath) |
| | | if (ppaths.length) { |
| | | var filePaths = this.uploader.filePaths |
| | | utils.each(ppaths, function (path, i) { |
| | | var folderFile = filePaths[path] |
| | | if (!folderFile) { |
| | | folderFile = new File(this.uploader, path, this.parent) |
| | | filePaths[path] = folderFile |
| | | this._updateParentFileList(folderFile) |
| | | } |
| | | this.parent = folderFile |
| | | folderFile.files.push(this) |
| | | if (!ppaths[i + 1]) { |
| | | folderFile.fileList.push(this) |
| | | } |
| | | }, this) |
| | | } else { |
| | | this._updateParentFileList() |
| | | } |
| | | }, |
| | | |
| | | _updateParentFileList: function (file) { |
| | | if (!file) { |
| | | file = this |
| | | } |
| | | var p = this.parent |
| | | if (p) { |
| | | p.fileList.push(file) |
| | | } |
| | | }, |
| | | |
| | | _eachAccess: function (eachFn, fileFn) { |
| | | if (this.isFolder) { |
| | | utils.each(this.files, function (f, i) { |
| | | return eachFn.call(this, f, i) |
| | | }, this) |
| | | return |
| | | } |
| | | fileFn.call(this, this) |
| | | }, |
| | | |
| | | bootstrap: function () { |
| | | if (this.isFolder) return |
| | | var opts = this.uploader.opts |
| | | if (utils.isFunction(opts.initFileFn)) { |
| | | opts.initFileFn.call(this, this) |
| | | } |
| | | |
| | | this.abort(true) |
| | | this._resetError() |
| | | // Rebuild stack of chunks from file |
| | | this._prevProgress = 0 |
| | | var round = opts.forceChunkSize ? Math.ceil : Math.floor |
| | | var chunks = Math.max(round(this.size / opts.chunkSize), 1) |
| | | for (var offset = 0; offset < chunks; offset++) { |
| | | this.chunks.push(new Chunk(this.uploader, this, offset)) |
| | | } |
| | | }, |
| | | |
| | | _measureSpeed: function () { |
| | | var smoothingFactor = this.uploader.opts.speedSmoothingFactor |
| | | var timeSpan = Date.now() - this._lastProgressCallback |
| | | if (!timeSpan) { |
| | | return |
| | | } |
| | | var uploaded = this.sizeUploaded() |
| | | // Prevent negative upload speed after file upload resume |
| | | this.currentSpeed = Math.max((uploaded - this._prevUploadedSize) / timeSpan * 1000, 0) |
| | | this.averageSpeed = smoothingFactor * this.currentSpeed + (1 - smoothingFactor) * this.averageSpeed |
| | | this._prevUploadedSize = uploaded |
| | | if (this.parent && this.parent._checkProgress()) { |
| | | this.parent._measureSpeed() |
| | | } |
| | | }, |
| | | |
| | | _checkProgress: function (file) { |
| | | return Date.now() - this._lastProgressCallback >= this.uploader.opts.progressCallbacksInterval |
| | | }, |
| | | |
| | | _chunkEvent: function (chunk, evt, message) { |
| | | var uploader = this.uploader |
| | | var STATUS = Chunk.STATUS |
| | | var that = this |
| | | var rootFile = this.getRoot() |
| | | var triggerProgress = function () { |
| | | that._measureSpeed() |
| | | uploader._trigger('fileProgress', rootFile, that, chunk) |
| | | that._lastProgressCallback = Date.now() |
| | | } |
| | | switch (evt) { |
| | | case STATUS.PROGRESS: |
| | | if (this._checkProgress()) { |
| | | triggerProgress() |
| | | } |
| | | break |
| | | case STATUS.ERROR: |
| | | this._error() |
| | | this.abort(true) |
| | | uploader._trigger('fileError', rootFile, this, message, chunk) |
| | | break |
| | | case STATUS.SUCCESS: |
| | | this._updateUploadedChunks(message, chunk) |
| | | if (this.error) { |
| | | return |
| | | } |
| | | clearTimeout(this._progeressId) |
| | | this._progeressId = 0 |
| | | var timeDiff = Date.now() - this._lastProgressCallback |
| | | if (timeDiff < uploader.opts.progressCallbacksInterval) { |
| | | this._progeressId = setTimeout(triggerProgress, uploader.opts.progressCallbacksInterval - timeDiff) |
| | | } |
| | | if (this.isComplete()) { |
| | | clearTimeout(this._progeressId) |
| | | triggerProgress() |
| | | this.currentSpeed = 0 |
| | | this.averageSpeed = 0 |
| | | uploader._trigger('fileSuccess', rootFile, this, message, chunk) |
| | | if (rootFile.isComplete()) { |
| | | uploader._trigger('fileComplete', rootFile, this) |
| | | } |
| | | } else if (!this._progeressId) { |
| | | triggerProgress() |
| | | } |
| | | break |
| | | case STATUS.RETRY: |
| | | uploader._trigger('fileRetry', rootFile, this, chunk) |
| | | break |
| | | } |
| | | }, |
| | | |
| | | _updateUploadedChunks: function (message, chunk) { |
| | | var checkChunkUploaded = this.uploader.opts.checkChunkUploadedByResponse |
| | | if (checkChunkUploaded) { |
| | | var xhr = chunk.xhr |
| | | utils.each(this.chunks, function (_chunk) { |
| | | if (!_chunk.tested) { |
| | | var uploaded = checkChunkUploaded.call(this, _chunk, message) |
| | | if (_chunk === chunk && !uploaded) { |
| | | // fix the first chunk xhr status |
| | | // treated as success but checkChunkUploaded is false |
| | | // so the current chunk should be uploaded again |
| | | _chunk.xhr = null |
| | | } |
| | | if (uploaded) { |
| | | // first success and other chunks are uploaded |
| | | // then set xhr, so the uploaded chunks |
| | | // will be treated as success too |
| | | _chunk.xhr = xhr |
| | | } |
| | | _chunk.tested = true |
| | | } |
| | | }, this) |
| | | if (!this._firstResponse) { |
| | | this._firstResponse = true |
| | | this.uploader.upload(true) |
| | | } else { |
| | | this.uploader.uploadNextChunk() |
| | | } |
| | | } else { |
| | | this.uploader.uploadNextChunk() |
| | | } |
| | | }, |
| | | |
| | | _error: function () { |
| | | this.error = this.allError = true |
| | | var parent = this.parent |
| | | while (parent && parent !== this.uploader) { |
| | | parent._errorFiles.push(this) |
| | | parent.error = true |
| | | if (parent._errorFiles.length === parent.files.length) { |
| | | parent.allError = true |
| | | } |
| | | parent = parent.parent |
| | | } |
| | | }, |
| | | |
| | | _resetError: function () { |
| | | this.error = this.allError = false |
| | | var parent = this.parent |
| | | var index = -1 |
| | | while (parent && parent !== this.uploader) { |
| | | index = parent._errorFiles.indexOf(this) |
| | | parent._errorFiles.splice(index, 1) |
| | | parent.allError = false |
| | | if (!parent._errorFiles.length) { |
| | | parent.error = false |
| | | } |
| | | parent = parent.parent |
| | | } |
| | | }, |
| | | |
| | | isComplete: function () { |
| | | if (!this.completed) { |
| | | var outstanding = false |
| | | this._eachAccess(function (file) { |
| | | if (!file.isComplete()) { |
| | | outstanding = true |
| | | return false |
| | | } |
| | | }, function () { |
| | | var STATUS = Chunk.STATUS |
| | | utils.each(this.chunks, function (chunk) { |
| | | var status = chunk.status() |
| | | if (status === STATUS.PENDING || status === STATUS.UPLOADING || status === STATUS.READING || chunk.preprocessState === 1 || chunk.readState === 1) { |
| | | outstanding = true |
| | | return false |
| | | } |
| | | }) |
| | | }) |
| | | this.completed = !outstanding |
| | | } |
| | | return this.completed |
| | | }, |
| | | |
| | | isUploading: function () { |
| | | var uploading = false |
| | | this._eachAccess(function (file) { |
| | | if (file.isUploading()) { |
| | | uploading = true |
| | | return false |
| | | } |
| | | }, function () { |
| | | var uploadingStatus = Chunk.STATUS.UPLOADING |
| | | utils.each(this.chunks, function (chunk) { |
| | | if (chunk.status() === uploadingStatus) { |
| | | uploading = true |
| | | return false |
| | | } |
| | | }) |
| | | }) |
| | | return uploading |
| | | }, |
| | | |
| | | resume: function () { |
| | | this._eachAccess(function (f) { |
| | | f.resume() |
| | | }, function () { |
| | | this.paused = false |
| | | this.aborted = false |
| | | this.uploader.upload() |
| | | }) |
| | | this.paused = false |
| | | this.aborted = false |
| | | }, |
| | | |
| | | pause: function () { |
| | | this._eachAccess(function (f) { |
| | | f.pause() |
| | | }, function () { |
| | | this.paused = true |
| | | this.abort() |
| | | }) |
| | | this.paused = true |
| | | }, |
| | | |
| | | cancel: function () { |
| | | this.uploader.removeFile(this) |
| | | }, |
| | | |
| | | retry: function (file) { |
| | | var fileRetry = function (file) { |
| | | if (file.error) { |
| | | file.bootstrap() |
| | | } |
| | | } |
| | | if (file) { |
| | | file.bootstrap() |
| | | } else { |
| | | this._eachAccess(fileRetry, function () { |
| | | this.bootstrap() |
| | | }) |
| | | } |
| | | this.uploader.upload() |
| | | }, |
| | | |
| | | abort: function (reset) { |
| | | if (this.aborted) { |
| | | return |
| | | } |
| | | this.currentSpeed = 0 |
| | | this.averageSpeed = 0 |
| | | this.aborted = !reset |
| | | var chunks = this.chunks |
| | | if (reset) { |
| | | this.chunks = [] |
| | | } |
| | | var uploadingStatus = Chunk.STATUS.UPLOADING |
| | | utils.each(chunks, function (c) { |
| | | if (c.status() === uploadingStatus) { |
| | | c.abort() |
| | | this.uploader.uploadNextChunk() |
| | | } |
| | | }, this) |
| | | }, |
| | | |
| | | progress: function () { |
| | | var totalDone = 0 |
| | | var totalSize = 0 |
| | | var ret = 0 |
| | | this._eachAccess(function (file, index) { |
| | | totalDone += file.progress() * file.size |
| | | totalSize += file.size |
| | | if (index === this.files.length - 1) { |
| | | ret = totalSize > 0 ? totalDone / totalSize : this.isComplete() ? 1 : 0 |
| | | } |
| | | }, function () { |
| | | if (this.error) { |
| | | ret = 1 |
| | | return |
| | | } |
| | | if (this.chunks.length === 1) { |
| | | this._prevProgress = Math.max(this._prevProgress, this.chunks[0].progress()) |
| | | ret = this._prevProgress |
| | | return |
| | | } |
| | | // Sum up progress across everything |
| | | var bytesLoaded = 0 |
| | | utils.each(this.chunks, function (c) { |
| | | // get chunk progress relative to entire file |
| | | bytesLoaded += c.progress() * (c.endByte - c.startByte) |
| | | }) |
| | | var percent = bytesLoaded / this.size |
| | | // We don't want to lose percentages when an upload is paused |
| | | this._prevProgress = Math.max(this._prevProgress, percent > 0.9999 ? 1 : percent) |
| | | ret = this._prevProgress |
| | | }) |
| | | return ret |
| | | }, |
| | | |
| | | getSize: function () { |
| | | var size = 0 |
| | | this._eachAccess(function (file) { |
| | | size += file.size |
| | | }, function () { |
| | | size += this.size |
| | | }) |
| | | return size |
| | | }, |
| | | |
| | | getFormatSize: function () { |
| | | var size = this.getSize() |
| | | return utils.formatSize(size) |
| | | }, |
| | | |
| | | getRoot: function () { |
| | | if (this.isRoot) { |
| | | return this |
| | | } |
| | | var parent = this.parent |
| | | while (parent) { |
| | | if (parent.parent === this.uploader) { |
| | | // find it |
| | | return parent |
| | | } |
| | | parent = parent.parent |
| | | } |
| | | return this |
| | | }, |
| | | |
| | | sizeUploaded: function () { |
| | | var size = 0 |
| | | this._eachAccess(function (file) { |
| | | size += file.sizeUploaded() |
| | | }, function () { |
| | | utils.each(this.chunks, function (chunk) { |
| | | size += chunk.sizeUploaded() |
| | | }) |
| | | }) |
| | | return size |
| | | }, |
| | | |
| | | timeRemaining: function () { |
| | | var ret = 0 |
| | | var sizeDelta = 0 |
| | | var averageSpeed = 0 |
| | | this._eachAccess(function (file, i) { |
| | | if (!file.paused && !file.error) { |
| | | sizeDelta += file.size - file.sizeUploaded() |
| | | averageSpeed += file.averageSpeed |
| | | } |
| | | if (i === this.files.length - 1) { |
| | | ret = calRet(sizeDelta, averageSpeed) |
| | | } |
| | | }, function () { |
| | | if (this.paused || this.error) { |
| | | ret = 0 |
| | | return |
| | | } |
| | | var delta = this.size - this.sizeUploaded() |
| | | ret = calRet(delta, this.averageSpeed) |
| | | }) |
| | | return ret |
| | | function calRet (delta, averageSpeed) { |
| | | if (delta && !averageSpeed) { |
| | | return Number.POSITIVE_INFINITY |
| | | } |
| | | if (!delta && !averageSpeed) { |
| | | return 0 |
| | | } |
| | | return Math.floor(delta / averageSpeed) |
| | | } |
| | | }, |
| | | |
| | | removeFile: function (file) { |
| | | if (file.isFolder) { |
| | | while (file.files.length) { |
| | | var f = file.files[file.files.length - 1] |
| | | this._removeFile(f) |
| | | } |
| | | } |
| | | this._removeFile(file) |
| | | }, |
| | | |
| | | _delFilePath: function (file) { |
| | | if (file.path && this.filePaths) { |
| | | delete this.filePaths[file.path] |
| | | } |
| | | utils.each(file.fileList, function (file) { |
| | | this._delFilePath(file) |
| | | }, this) |
| | | }, |
| | | |
| | | _removeFile: function (file) { |
| | | if (!file.isFolder) { |
| | | utils.each(this.files, function (f, i) { |
| | | if (f === file) { |
| | | this.files.splice(i, 1) |
| | | return false |
| | | } |
| | | }, this) |
| | | file.abort() |
| | | var parent = file.parent |
| | | var newParent |
| | | while (parent && parent !== this) { |
| | | newParent = parent.parent |
| | | parent._removeFile(file) |
| | | parent = newParent |
| | | } |
| | | } |
| | | file.parent === this && utils.each(this.fileList, function (f, i) { |
| | | if (f === file) { |
| | | this.fileList.splice(i, 1) |
| | | return false |
| | | } |
| | | }, this) |
| | | if (!this.isRoot && this.isFolder && !this.files.length) { |
| | | this.parent._removeFile(this) |
| | | this.uploader._delFilePath(this) |
| | | } |
| | | file.parent = null |
| | | }, |
| | | |
| | | getType: function () { |
| | | if (this.isFolder) { |
| | | return 'folder' |
| | | } |
| | | return this.file.type && this.file.type.split('/')[1] |
| | | }, |
| | | |
| | | getExtension: function () { |
| | | if (this.isFolder) { |
| | | return '' |
| | | } |
| | | return this.name.substr((~-this.name.lastIndexOf('.') >>> 0) + 2).toLowerCase() |
| | | } |
| | | |
| | | }) |
| | | |
| | | module.exports = File |
| | | |
| | | function parsePaths (path) { |
| | | var ret = [] |
| | | var paths = path.split('/') |
| | | var len = paths.length |
| | | var i = 1 |
| | | paths.splice(len - 1, 1) |
| | | len-- |
| | | if (paths.length) { |
| | | while (i <= len) { |
| | | ret.push(paths.slice(0, i++).join('/') + '/') |
| | | } |
| | | } |
| | | return ret |
| | | } |
| | | |
| | | },{"./chunk":1,"./utils":5}],5:[function(_dereq_,module,exports){ |
| | | var oproto = Object.prototype |
| | | var aproto = Array.prototype |
| | | var serialize = oproto.toString |
| | | |
| | | var isFunction = function (fn) { |
| | | return serialize.call(fn) === '[object Function]' |
| | | } |
| | | |
| | | var isArray = Array.isArray || /* istanbul ignore next */ function (ary) { |
| | | return serialize.call(ary) === '[object Array]' |
| | | } |
| | | |
| | | var isPlainObject = function (obj) { |
| | | return serialize.call(obj) === '[object Object]' && Object.getPrototypeOf(obj) === oproto |
| | | } |
| | | |
| | | var i = 0 |
| | | var utils = { |
| | | uid: function () { |
| | | return ++i |
| | | }, |
| | | noop: function () {}, |
| | | bind: function (fn, context) { |
| | | return function () { |
| | | return fn.apply(context, arguments) |
| | | } |
| | | }, |
| | | preventEvent: function (evt) { |
| | | evt.preventDefault() |
| | | }, |
| | | stop: function (evt) { |
| | | evt.preventDefault() |
| | | evt.stopPropagation() |
| | | }, |
| | | nextTick: function (fn, context) { |
| | | setTimeout(utils.bind(fn, context), 0) |
| | | }, |
| | | toArray: function (ary, start, end) { |
| | | if (start === undefined) start = 0 |
| | | if (end === undefined) end = ary.length |
| | | return aproto.slice.call(ary, start, end) |
| | | }, |
| | | |
| | | isPlainObject: isPlainObject, |
| | | isFunction: isFunction, |
| | | isArray: isArray, |
| | | isObject: function (obj) { |
| | | return Object(obj) === obj |
| | | }, |
| | | isString: function (s) { |
| | | return typeof s === 'string' |
| | | }, |
| | | isUndefined: function (a) { |
| | | return typeof a === 'undefined' |
| | | }, |
| | | isDefined: function (a) { |
| | | return typeof a !== 'undefined' |
| | | }, |
| | | |
| | | each: function (ary, func, context) { |
| | | if (utils.isDefined(ary.length)) { |
| | | for (var i = 0, len = ary.length; i < len; i++) { |
| | | if (func.call(context, ary[i], i, ary) === false) { |
| | | break |
| | | } |
| | | } |
| | | } else { |
| | | for (var k in ary) { |
| | | if (func.call(context, ary[k], k, ary) === false) { |
| | | break |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | |
| | | /** |
| | | * If option is a function, evaluate it with given params |
| | | * @param {*} data |
| | | * @param {...} args arguments of a callback |
| | | * @returns {*} |
| | | */ |
| | | evalOpts: function (data, args) { |
| | | if (utils.isFunction(data)) { |
| | | // `arguments` is an object, not array, in FF, so: |
| | | args = utils.toArray(arguments) |
| | | data = data.apply(null, args.slice(1)) |
| | | } |
| | | return data |
| | | }, |
| | | |
| | | extend: function () { |
| | | var options |
| | | var name |
| | | var src |
| | | var copy |
| | | var copyIsArray |
| | | var clone |
| | | var target = arguments[0] || {} |
| | | var i = 1 |
| | | var length = arguments.length |
| | | var force = false |
| | | |
| | | // 如果第一个参数为布尔,判定是否深拷贝 |
| | | if (typeof target === 'boolean') { |
| | | force = target |
| | | target = arguments[1] || {} |
| | | i++ |
| | | } |
| | | |
| | | // 确保接受方为一个复杂的数据类型 |
| | | if (typeof target !== 'object' && !isFunction(target)) { |
| | | target = {} |
| | | } |
| | | |
| | | // 如果只有一个参数,那么新成员添加于 extend 所在的对象上 |
| | | if (i === length) { |
| | | target = this |
| | | i-- |
| | | } |
| | | |
| | | for (; i < length; i++) { |
| | | // 只处理非空参数 |
| | | if ((options = arguments[i]) != null) { |
| | | for (name in options) { |
| | | src = target[name] |
| | | copy = options[name] |
| | | |
| | | // 防止环引用 |
| | | if (target === copy) { |
| | | continue |
| | | } |
| | | if (force && copy && (isPlainObject(copy) || (copyIsArray = isArray(copy)))) { |
| | | if (copyIsArray) { |
| | | copyIsArray = false |
| | | clone = src && isArray(src) ? src : [] |
| | | } else { |
| | | clone = src && isPlainObject(src) ? src : {} |
| | | } |
| | | target[name] = utils.extend(force, clone, copy) |
| | | } else if (copy !== undefined) { |
| | | target[name] = copy |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return target |
| | | }, |
| | | |
| | | formatSize: function (size) { |
| | | if (size < 1024) { |
| | | return size.toFixed(0) + ' bytes' |
| | | } else if (size < 1024 * 1024) { |
| | | return (size / 1024.0).toFixed(0) + ' KB' |
| | | } else if (size < 1024 * 1024 * 1024) { |
| | | return (size / 1024.0 / 1024.0).toFixed(1) + ' MB' |
| | | } else { |
| | | return (size / 1024.0 / 1024.0 / 1024.0).toFixed(1) + ' GB' |
| | | } |
| | | }, |
| | | |
| | | defineNonEnumerable: function (target, key, value) { |
| | | Object.defineProperty(target, key, { |
| | | enumerable: false, |
| | | configurable: true, |
| | | writable: true, |
| | | value: value |
| | | }) |
| | | } |
| | | } |
| | | |
| | | module.exports = utils |
| | | |
| | | },{}]},{},[3]) |
| | | (3) |
| | | }); |
New file |
| | |
| | | export function secondsToStr(temp) { |
| | | const years = Math.floor(temp / 31536000) |
| | | if (years) { |
| | | return years + ' 年' + numberEnding(years) |
| | | } |
| | | const days = Math.floor((temp %= 31536000) / 86400) |
| | | if (days) { |
| | | return days + ' 天' + numberEnding(days) |
| | | } |
| | | const hours = Math.floor((temp %= 86400) / 3600) |
| | | if (hours) { |
| | | return hours + ' 小时' + numberEnding(hours) |
| | | } |
| | | const minutes = Math.floor((temp %= 3600) / 60) |
| | | if (minutes) { |
| | | return minutes + ' 分' + numberEnding(minutes) |
| | | } |
| | | const seconds = temp % 60 |
| | | return seconds + ' 秒' + numberEnding(seconds) |
| | | function numberEnding(number) { |
| | | // return (number > 1) ? 's' : '' |
| | | return '' |
| | | } |
| | | } |
| | | |
| | | export function kebabCase(s) { |
| | | return s.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`) |
| | | } |
New file |
| | |
| | | <template> |
| | | <div class="uploader-drop" :class="dropClass" ref="drop" v-show="support"> |
| | | <slot></slot> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { uploaderMixin, supportMixin } from './common/mixins' |
| | | |
| | | const COMPONENT_NAME = 'uploader-drop' |
| | | |
| | | export default { |
| | | name: COMPONENT_NAME, |
| | | mixins: [uploaderMixin, supportMixin], |
| | | data() { |
| | | return { |
| | | dropClass: '' |
| | | } |
| | | }, |
| | | methods: { |
| | | onDragEnter() { |
| | | this.dropClass = 'uploader-dragover' |
| | | }, |
| | | onDragLeave() { |
| | | this.dropClass = '' |
| | | }, |
| | | onDrop() { |
| | | this.dropClass = 'uploader-droped' |
| | | } |
| | | }, |
| | | mounted() { |
| | | this.$nextTick(() => { |
| | | const dropEle = this.$refs.drop |
| | | const uploader = this.uploader.uploader |
| | | uploader.assignDrop(dropEle) |
| | | uploader.on('dragenter', this.onDragEnter) |
| | | uploader.on('dragleave', this.onDragLeave) |
| | | uploader.on('drop', this.onDrop) |
| | | }) |
| | | }, |
| | | beforeDestroy() { |
| | | const dropEle = this.$refs.drop |
| | | const uploader = this.uploader.uploader |
| | | uploader.off('dragenter', this.onDragEnter) |
| | | uploader.off('dragleave', this.onDragLeave) |
| | | uploader.off('drop', this.onDrop) |
| | | uploader.unAssignDrop(dropEle) |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style> |
| | | .uploader-drop { |
| | | position: relative; |
| | | padding: 10px; |
| | | overflow: hidden; |
| | | border: 1px dashed #ccc; |
| | | background-color: #f5f5f5; |
| | | } |
| | | .uploader-dragover { |
| | | border-color: #999; |
| | | background-color: #f7f7f7; |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="uploader-file" :status="status"> |
| | | <slot |
| | | :file="file" |
| | | :list="list" |
| | | :status="status" |
| | | :paused="paused" |
| | | :error="error" |
| | | :response="response" |
| | | :average-speed="averageSpeed" |
| | | :formated-average-speed="formatedAverageSpeed" |
| | | :current-speed="currentSpeed" |
| | | :is-complete="isComplete" |
| | | :is-uploading="isUploading" |
| | | :size="size" |
| | | :formated-size="formatedSize" |
| | | :uploaded-size="uploadedSize" |
| | | :progress="progress" |
| | | :progress-style="progressStyle" |
| | | :progressing-class="progressingClass" |
| | | :time-remaining="timeRemaining" |
| | | :formated-time-remaining="formatedTimeRemaining" |
| | | :type="type" |
| | | :extension="extension" |
| | | :file-category="fileCategory" |
| | | > |
| | | <div |
| | | class="uploader-file-progress" |
| | | :class="progressingClass" |
| | | :style="progressStyle" |
| | | ></div> |
| | | <div class="uploader-file-info"> |
| | | <div class="uploader-file-name"> |
| | | <i class="uploader-file-icon" :icon="fileCategory"></i> |
| | | {{ file.name }} |
| | | </div> |
| | | <div class="uploader-file-size">{{ formatedSize }}</div> |
| | | <div class="uploader-file-meta"></div> |
| | | <div class="uploader-file-status"> |
| | | <span v-show="status !== 'uploading'">{{ statusText }}</span> |
| | | <span v-show="status === 'uploading'"> |
| | | <span>{{ progressStyle.progress }}</span> |
| | | <em>{{ formatedAverageSpeed }}</em> |
| | | |
| | | <i> {{ formatedTimeRemaining }}</i> |
| | | </span> |
| | | </div> |
| | | <div class="uploader-file-actions"> |
| | | <span class="uploader-file-pause" @click="pause"></span> |
| | | <span class="uploader-file-resume" @click="resume">️</span> |
| | | <span class="uploader-file-retry" @click="retry"></span> |
| | | <span class="uploader-file-remove" @click="remove"></span> |
| | | </div> |
| | | </div> |
| | | </slot> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import Uploader from "simple-uploader.js"; |
| | | import events from "./common/file-events"; |
| | | import { secondsToStr } from "./common/utils"; |
| | | |
| | | const COMPONENT_NAME = "uploader-file"; |
| | | |
| | | export default { |
| | | name: COMPONENT_NAME, |
| | | props: { |
| | | file: { |
| | | type: Object, |
| | | default() { |
| | | return {}; |
| | | }, |
| | | }, |
| | | list: { |
| | | type: Boolean, |
| | | default: false, |
| | | }, |
| | | }, |
| | | data() { |
| | | return { |
| | | response: null, |
| | | paused: false, |
| | | error: false, |
| | | averageSpeed: 0, |
| | | currentSpeed: 0, |
| | | isComplete: false, |
| | | isUploading: false, |
| | | size: 0, |
| | | formatedSize: "", |
| | | uploadedSize: 0, |
| | | progress: 0, |
| | | timeRemaining: 0, |
| | | type: "", |
| | | extension: "", |
| | | progressingClass: "", |
| | | }; |
| | | }, |
| | | computed: { |
| | | fileCategory() { |
| | | const extension = this.extension; |
| | | const isFolder = this.file.isFolder; |
| | | let type = isFolder ? "folder" : "unknown"; |
| | | const categoryMap = this.file.uploader.opts.categoryMap; |
| | | const typeMap = categoryMap || { |
| | | image: ["gif", "jpg", "jpeg", "png", "bmp", "webp"], |
| | | video: ["mp4", "m3u8", "rmvb", "avi", "swf", "3gp", "mkv", "flv"], |
| | | audio: ["mp3", "wav", "wma", "ogg", "aac", "flac"], |
| | | document: [ |
| | | "doc", |
| | | "txt", |
| | | "docx", |
| | | "pages", |
| | | "epub", |
| | | "pdf", |
| | | "numbers", |
| | | "csv", |
| | | "xls", |
| | | "xlsx", |
| | | "keynote", |
| | | "ppt", |
| | | "pptx", |
| | | ], |
| | | }; |
| | | Object.keys(typeMap).forEach((_type) => { |
| | | const extensions = typeMap[_type]; |
| | | if (extensions.indexOf(extension) > -1) { |
| | | type = _type; |
| | | } |
| | | }); |
| | | return type; |
| | | }, |
| | | progressStyle() { |
| | | const progress = Math.floor(this.progress * 100); |
| | | const style = `translateX(${Math.floor(progress - 100)}%)`; |
| | | return { |
| | | progress: `${progress}%`, |
| | | webkitTransform: style, |
| | | mozTransform: style, |
| | | msTransform: style, |
| | | transform: style, |
| | | }; |
| | | }, |
| | | formatedAverageSpeed() { |
| | | return `${Uploader.utils.formatSize(this.averageSpeed)} / s`; |
| | | }, |
| | | status() { |
| | | const isUploading = this.isUploading; |
| | | const isComplete = this.isComplete; |
| | | const isError = this.error; |
| | | const paused = this.paused; |
| | | if (isComplete) { |
| | | return "success"; |
| | | } else if (isError) { |
| | | return "error"; |
| | | } else if (isUploading) { |
| | | return "uploading"; |
| | | } else if (paused) { |
| | | return "paused"; |
| | | } else { |
| | | return "waiting"; |
| | | } |
| | | }, |
| | | statusText() { |
| | | const status = this.status; |
| | | const fileStatusText = this.file.uploader.fileStatusText; |
| | | let txt = status; |
| | | if (typeof fileStatusText === "function") { |
| | | txt = fileStatusText(status, this.response); |
| | | } else { |
| | | txt = fileStatusText[status]; |
| | | } |
| | | return txt || status; |
| | | }, |
| | | formatedTimeRemaining() { |
| | | const timeRemaining = this.timeRemaining; |
| | | const file = this.file; |
| | | if (timeRemaining === Number.POSITIVE_INFINITY || timeRemaining === 0) { |
| | | return ""; |
| | | } |
| | | let parsedTimeRemaining = secondsToStr(timeRemaining); |
| | | const parseTimeRemaining = file.uploader.opts.parseTimeRemaining; |
| | | if (parseTimeRemaining) { |
| | | parsedTimeRemaining = parseTimeRemaining( |
| | | timeRemaining, |
| | | parsedTimeRemaining |
| | | ); |
| | | } |
| | | return parsedTimeRemaining; |
| | | }, |
| | | }, |
| | | watch: { |
| | | status(newStatus, oldStatus) { |
| | | if (oldStatus && newStatus === "uploading" && oldStatus !== "uploading") { |
| | | this.tid = setTimeout(() => { |
| | | this.progressingClass = "uploader-file-progressing"; |
| | | }, 200); |
| | | } else { |
| | | clearTimeout(this.tid); |
| | | this.progressingClass = ""; |
| | | } |
| | | }, |
| | | }, |
| | | methods: { |
| | | _actionCheck() { |
| | | this.paused = this.file.paused; |
| | | this.error = this.file.error; |
| | | this.isUploading = this.file.isUploading(); |
| | | }, |
| | | pause() { |
| | | this.file.pause(); |
| | | this._actionCheck(); |
| | | this._fileProgress(); |
| | | }, |
| | | resume() { |
| | | this.file.resume(); |
| | | this._actionCheck(); |
| | | }, |
| | | remove() { |
| | | this.file.cancel(); |
| | | }, |
| | | retry() { |
| | | this.file.retry(); |
| | | this._actionCheck(); |
| | | }, |
| | | processResponse(message) { |
| | | let res = message; |
| | | try { |
| | | res = JSON.parse(message); |
| | | } catch (e) {} |
| | | this.response = res; |
| | | }, |
| | | fileEventsHandler(event, args) { |
| | | const rootFile = args[0]; |
| | | const file = args[1]; |
| | | const target = this.list ? rootFile : file; |
| | | if (this.file === target) { |
| | | if (this.list && event === "fileSuccess") { |
| | | this.processResponse(args[2]); |
| | | return; |
| | | } |
| | | this[`_${event}`].apply(this, args); |
| | | } |
| | | }, |
| | | _fileProgress() { |
| | | this.progress = this.file.progress(); |
| | | this.averageSpeed = this.file.averageSpeed; |
| | | this.currentSpeed = this.file.currentSpeed; |
| | | this.timeRemaining = this.file.timeRemaining(); |
| | | this.uploadedSize = this.file.sizeUploaded(); |
| | | this._actionCheck(); |
| | | }, |
| | | _fileSuccess(rootFile, file, message) { |
| | | if (rootFile) { |
| | | this.processResponse(message); |
| | | } |
| | | this._fileProgress(); |
| | | this.error = false; |
| | | this.isComplete = true; |
| | | this.isUploading = false; |
| | | console.log("rootFile, file, message", rootFile, file, message); |
| | | }, |
| | | _fileComplete() { |
| | | this._fileSuccess(); |
| | | }, |
| | | _fileError(rootFile, file, message) { |
| | | this._fileProgress(); |
| | | console.log("rootFile, file, message", rootFile, file, message); |
| | | this.processResponse(message); |
| | | this.error = true; |
| | | this.isComplete = false; |
| | | this.isUploading = false; |
| | | }, |
| | | }, |
| | | mounted() { |
| | | const staticProps = ["paused", "error", "averageSpeed", "currentSpeed"]; |
| | | const fnProps = [ |
| | | "isComplete", |
| | | "isUploading", |
| | | { |
| | | key: "size", |
| | | fn: "getSize", |
| | | }, |
| | | { |
| | | key: "formatedSize", |
| | | fn: "getFormatSize", |
| | | }, |
| | | { |
| | | key: "uploadedSize", |
| | | fn: "sizeUploaded", |
| | | }, |
| | | "progress", |
| | | "timeRemaining", |
| | | { |
| | | key: "type", |
| | | fn: "getType", |
| | | }, |
| | | { |
| | | key: "extension", |
| | | fn: "getExtension", |
| | | }, |
| | | ]; |
| | | staticProps.forEach((prop) => { |
| | | this[prop] = this.file[prop]; |
| | | }); |
| | | fnProps.forEach((fnProp) => { |
| | | if (typeof fnProp === "string") { |
| | | this[fnProp] = this.file[fnProp](); |
| | | } else { |
| | | this[fnProp.key] = this.file[fnProp.fn](); |
| | | } |
| | | }); |
| | | |
| | | const handlers = (this._handlers = {}); |
| | | const eventHandler = (event) => { |
| | | handlers[event] = (...args) => { |
| | | this.fileEventsHandler(event, args); |
| | | }; |
| | | return handlers[event]; |
| | | }; |
| | | events.forEach((event) => { |
| | | this.file.uploader.on(event, eventHandler(event)); |
| | | }); |
| | | }, |
| | | destroyed() { |
| | | events.forEach((event) => { |
| | | this.file.uploader.off(event, this._handlers[event]); |
| | | }); |
| | | this._handlers = null; |
| | | }, |
| | | }; |
| | | </script> |
| | | |
| | | <style> |
| | | .uploader-file { |
| | | position: relative; |
| | | height: 49px; |
| | | line-height: 49px; |
| | | overflow: hidden; |
| | | } |
| | | .uploader-file[status="waiting"] .uploader-file-pause, |
| | | .uploader-file[status="uploading"] .uploader-file-pause { |
| | | display: block; |
| | | } |
| | | .uploader-file[status="paused"] .uploader-file-resume { |
| | | display: block; |
| | | } |
| | | .uploader-file[status="error"] .uploader-file-retry { |
| | | display: block; |
| | | } |
| | | .uploader-file[status="success"] .uploader-file-remove { |
| | | display: none; |
| | | } |
| | | .uploader-file[status="error"] .uploader-file-progress { |
| | | background: #ffe0e0; |
| | | } |
| | | .uploader-file-progress { |
| | | position: absolute; |
| | | width: 100%; |
| | | height: 4px; |
| | | border-radius: 4px; |
| | | background: #1dd4ec; |
| | | transform: translateX(-100%); |
| | | } |
| | | .uploader-file-progressing { |
| | | transition: all 0.4s linear; |
| | | } |
| | | .uploader-file-info { |
| | | position: relative; |
| | | z-index: 1; |
| | | height: 100%; |
| | | overflow: hidden; |
| | | font-size: 13px; |
| | | } |
| | | .uploader-file-info:hover { |
| | | background-color: rgba(240, 240, 240, 0.2); |
| | | } |
| | | .uploader-file-info i, |
| | | .uploader-file-info em { |
| | | font-style: normal; |
| | | } |
| | | .uploader-file-name, |
| | | .uploader-file-size, |
| | | .uploader-file-meta, |
| | | .uploader-file-status, |
| | | .uploader-file-actions { |
| | | float: left; |
| | | position: relative; |
| | | height: 100%; |
| | | } |
| | | .uploader-file-name { |
| | | width: 50%; |
| | | overflow: hidden; |
| | | white-space: nowrap; |
| | | text-overflow: ellipsis; |
| | | text-indent: 14px; |
| | | text-align: left; |
| | | } |
| | | .uploader-file-icon { |
| | | width: 24px; |
| | | height: 24px; |
| | | display: inline-block; |
| | | vertical-align: top; |
| | | margin-top: 13px; |
| | | margin-right: 8px; |
| | | } |
| | | .uploader-file-icon::before { |
| | | content: "📋"; |
| | | display: block; |
| | | /* height: 49px; */ |
| | | font-size: 18px; |
| | | line-height: 26px; |
| | | text-indent: 0; |
| | | } |
| | | .uploader-file-icon[icon="folder"]::before { |
| | | content: "📂"; |
| | | } |
| | | .uploader-file-icon[icon="image"]::before { |
| | | content: "🌆"; |
| | | } |
| | | .uploader-file-icon[icon="video"]::before { |
| | | content: "🎬"; |
| | | } |
| | | .uploader-file-icon[icon="audio"]::before { |
| | | content: "🎵"; |
| | | } |
| | | .uploader-file-icon[icon="document"]::before { |
| | | content: "📋"; |
| | | } |
| | | .uploader-file-size { |
| | | width: 11%; |
| | | text-indent: 10px; |
| | | } |
| | | .uploader-file-meta { |
| | | width: 8%; |
| | | } |
| | | .uploader-file-status { |
| | | width: 24%; |
| | | text-indent: 20px; |
| | | } |
| | | .uploader-file-actions { |
| | | width: 6%; |
| | | } |
| | | .uploader-file-actions > span { |
| | | display: none; |
| | | float: left; |
| | | width: 16px; |
| | | height: 16px; |
| | | margin-top: 16px; |
| | | margin-right: 10px; |
| | | cursor: pointer; |
| | | background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAABkCAYAAAD0ZHJ6AAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAAJcEhZcwAACxMAAAsTAQCanBgAAARkSURBVGje7ZnfS1NRHMAH4ptPkvQSuAdBkCxD8FUQJMEULUgzy1KyyPVQ4JMiiP4Bvg6EwUQQfMmwhwRDshwaKUjDVCgoSdDNHkzTJZ6+Z37Purve8+PeTb2TM/ggu+ew89l33x8H9BBCPG7GowXTJej3+wnDvEm0JuLC04+EYWftVAUv+fiCvDUdQR1BHUEdQR3BTIygvixoQS14XgTtthLVdpNWwXRLqvQ724LplFRtyrYF0yVpFLQrKRVMh6RZ0I6kkmCqklaCqpKZH0FX56Crq9jVfdDVk0RfFrSgFsxkQVmLcdKCVrKySCrryhPEyYShhzOcrFtG0EoilfHHk1CRU5rF6ZjNZhlVOW6RnMSVyyilKies4pO41diVy8wIujoHXV3FGdMHXTtJKLFYTLhZtq4vC1rwXApCZTIqgR6g1PBMCO9DL3bMMSqBHqDU8EyISDAHiGKvWwcCQG2KgjlAFCDAOhAAap0K5gKLphk8mqJgLrCIgoxRJ4J5wKpJ7gAoMkn5EBXBPGDVJHcAFJmkfIhQcAql1oBpTvTol9gG9pm4RHAKpdaAaU706JfYBvaZuJVgPQrt4sFlnOh5MC/p3lmJYD0K7eLBZZzoeTAv6d5ZnuAYHjpgEOnk5F0ufhG6v1ggOIaHDhhEOjl5l4tfhO4vthLcwAMrFNvLJO5vEwhu4IEViu1lEve3WQmyoihQFBzG/V0CQVYUBYqCw7i/SxTBcpsRbFeIYLnNCLZbCY5b5KAnxRwct8hBj9McZFVMW0ihRNBuFdMWUigRlFaxuQ9WWYjRMTiIe5z0wSoLMToGB3GPsA9aTZIJoB+nRgBnM1tzOkkmgH6cGgGczWzNpzqLx3n/aULJJgezeNw07oxQySbVywKjBOgFRnDs+VEsx8FlgVEC9AIjOPb8KJYjvSzoG7UW1IJaUAtqQS14toLNM5fN5APdwBJA8G83Pk/aK/rgzVvXzeQD3cASQPBvNz5P2ssTzAaGUIrHEO6zI5gNDKEUjyHcxxWkh4Ylcowwk1QQpIeGJXKMMJO0EgwqyjGCioJBJvDrxRMSuVOTJEXfbz1/bHwWtBL0yoQehK6RucgE+bGzanzulQh6E3IgQV+xpc8kcrfuSO7eTfJ3ZYmQw0Oy9azVKOk1C/bJ5D5F38YPeLfx0rjWJxHsS0SqsSYuxySjj5qO5Oj7xQWy2VBtFOwzCy6ryH3YfE3uh64Y1xckgstJPydEjkkeHv07Iy4Xaao15+KCWTBx6M/db+T9xivSErqaJDdzXI6yLRE8Vgg0coex/SPJvT0SbWu0KpZtbgSpCH3NRt7I5OxHkObc6heU+/M/J5vrpBFM5GBLqCQux14COXs5CNXK5OjPGm1tSMrJSOMNYQ4mVTGV/L6zTL7+DovkbFUxbSW0Wo05l8hJWsU+cRWfSh+Mt5Lb1ck/J1TvVsdDaR/MiEni+llsdZuZp62EViu+96bpNjNPWwmtVnzvFd5m9IVVC54x/wA7gNvqFG9vXQAAAABJRU5ErkJggg==") |
| | | no-repeat 0 0; |
| | | } |
| | | .uploader-file-actions > span:hover { |
| | | background-position-x: -21px; |
| | | } |
| | | .uploader-file-actions .uploader-file-pause { |
| | | background-position-y: 0; |
| | | } |
| | | .uploader-file-actions .uploader-file-resume { |
| | | background-position-y: -17px; |
| | | } |
| | | .uploader-file-actions .uploader-file-retry { |
| | | background-position-y: -53px; |
| | | } |
| | | .uploader-file-actions .uploader-file-remove { |
| | | display: block; |
| | | background-position-y: -34px; |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="uploader-files"> |
| | | <slot :files="files"> |
| | | <ul> |
| | | <li v-for="file in files" :key="file.id"> |
| | | <uploader-file :file="file"></uploader-file> |
| | | </li> |
| | | </ul> |
| | | </slot> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { uploaderMixin } from './common/mixins' |
| | | import UploaderFile from './file.vue' |
| | | |
| | | const COMPONENT_NAME = 'uploader-files' |
| | | |
| | | export default { |
| | | name: COMPONENT_NAME, |
| | | mixins: [uploaderMixin], |
| | | computed: { |
| | | files() { |
| | | return this.uploader.files |
| | | } |
| | | }, |
| | | components: { |
| | | UploaderFile |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style> |
| | | .uploader-files { |
| | | position: relative; |
| | | } |
| | | .uploader-files > ul { |
| | | list-style: none; |
| | | margin: 0; |
| | | padding: 0; |
| | | } |
| | | </style> |
New file |
| | |
| | | <template>
|
| | | <div class="file-uploader">
|
| | | <uploader
|
| | | v-if="single"
|
| | | ref="uploader"
|
| | | :options="options"
|
| | | :file-status-text="statusText"
|
| | | class="uploader-single"
|
| | | @file-added="onFileAdded"
|
| | | @complete="onComplete"
|
| | | >
|
| | | <!-- <uploader-drop v-if="isDrag == true">
|
| | | <div class="drag-txt">拖拽文件到这里</div>
|
| | | <span class="icon iconfont" @click.stop="showUpload = false"
|
| | | ></span
|
| | | >
|
| | | <uploader-btn>选择文件</uploader-btn>
|
| | | </uploader-drop> -->
|
| | |
|
| | | <div class="up-bar" v-if="isDrag == true">
|
| | | <div class="name">{{ fileName || uploadPlaceholder }}</div>
|
| | | <uploader-btn slot="suffix">
|
| | | <el-tooltip :content="tipWords" placement="top" v-if="tip">
|
| | | <div class="open-file-btn">
|
| | | <span class="icon iconfont"></span>
|
| | | </div>
|
| | | </el-tooltip>
|
| | | </uploader-btn>
|
| | | <!-- <div class="open-file-btn">
|
| | | <span class="icon iconfont"></span>
|
| | | </div> -->
|
| | | </div>
|
| | | <el-input
|
| | | :placeholder="uploadPlaceholder"
|
| | | v-if="isDrag == false"
|
| | | size="small"
|
| | | :readonly="true"
|
| | | v-model="fileName"
|
| | | >
|
| | | <uploader-btn slot="suffix">
|
| | | <el-tooltip :content="tipWords" placement="top" v-if="tip">
|
| | | <i
|
| | | class="el-icon-upload2"
|
| | | style="font-size: 18px; color: #0088ff"
|
| | | ></i>
|
| | | </el-tooltip>
|
| | | <i
|
| | | v-else
|
| | | class="el-icon-upload2"
|
| | | style="font-size: 18px; color: #0088ff"
|
| | | ></i>
|
| | | </uploader-btn>
|
| | | </el-input>
|
| | | <uploader-list />
|
| | | </uploader>
|
| | |
|
| | | <uploader
|
| | | v-else
|
| | | ref="uploader"
|
| | | :options="options"
|
| | | :file-status-text="statusText"
|
| | | class="uploader-example"
|
| | | @file-added="onFileAdded"
|
| | | @file-complete="fileComplete"
|
| | | @complete="onComplete"
|
| | | @close="closeHandle"
|
| | | >
|
| | | <uploader-btn ref="button" :sourceType="sourceType">
|
| | | <i class="el-icon-upload2" style="font-size: 18px; color: #0088ff"></i>
|
| | | 上传
|
| | | </uploader-btn>
|
| | | <uploader-list />
|
| | | </uploader>
|
| | | </div>
|
| | | </template>
|
| | |
|
| | | <script>
|
| | | import uploader from "./uploader";
|
| | | import SparkMD5 from "spark-md5";
|
| | | import UploaderBtn from "./btn";
|
| | | import UploaderList from "./list";
|
| | | import UploaderDrop from "./drop";
|
| | |
|
| | | export default {
|
| | | components: {
|
| | | uploader,
|
| | | UploaderBtn,
|
| | | UploaderList,
|
| | | UploaderDrop,
|
| | | },
|
| | | props: {
|
| | | sourceType: {
|
| | | type: Number,
|
| | | },
|
| | | tip: {
|
| | | type: Boolean,
|
| | | default: false,
|
| | | },
|
| | | tipWords: {
|
| | | type: String,
|
| | | default: "",
|
| | | },
|
| | | single: {
|
| | | type: Boolean,
|
| | | default: false,
|
| | | },
|
| | | uploadPlaceholder: {
|
| | | type: String,
|
| | | default: "",
|
| | | },
|
| | | isDrag: {
|
| | | type: Boolean,
|
| | | default: false,
|
| | | },
|
| | | url: {
|
| | | type: String,
|
| | | default: "/data/api-f/file/upload",
|
| | | },
|
| | | attrs: {
|
| | | type: Object,
|
| | | default() {
|
| | | return {};
|
| | | },
|
| | | },
|
| | | },
|
| | | data() {
|
| | | return {
|
| | | fileName: "",
|
| | | fileMd5: "",
|
| | | statusText: {
|
| | | success: "上传成功",
|
| | | error: "上传失败",
|
| | | uploading: "上传中",
|
| | | paused: "暂停中",
|
| | | waiting: "等待中",
|
| | | },
|
| | | };
|
| | | },
|
| | | computed: {
|
| | | uploader() {
|
| | | return this.$refs.uploader.uploader;
|
| | | },
|
| | | options() {
|
| | | return {
|
| | | target: this.url,
|
| | | testChunks: true,
|
| | | headers: {
|
| | | Authorization:
|
| | | sessionStorage.getItem("loginedInfo") &&
|
| | | JSON.parse(sessionStorage.getItem("loginedInfo")).access_token,
|
| | | },
|
| | | };
|
| | | },
|
| | | },
|
| | | methods: {
|
| | | onFileAdded(file) {
|
| | | if (this.single) {
|
| | | this.uploader.fileList = this.uploader.fileList.slice([-1]);
|
| | | this.$emit("file-added");
|
| | | }
|
| | | this.computeMD5(file);
|
| | | },
|
| | | computeMD5(file) {
|
| | | let fileReader = new FileReader();
|
| | | let time = new Date().getTime();
|
| | | let blobSlice =
|
| | | File.prototype.slice ||
|
| | | File.prototype.mozSlice ||
|
| | | File.prototype.webkitSlice;
|
| | | let currentChunk = 0;
|
| | | const chunkSize = 10 * 1024 * 1000;
|
| | | let chunks = Math.ceil(file.size / chunkSize);
|
| | | let spark = new SparkMD5.ArrayBuffer();
|
| | | // 文件状态设为"计算MD5"
|
| | | this.statusText.paused = "准备上传,正在检查文件";
|
| | | file.pause();
|
| | | loadNext();
|
| | | fileReader.onload = (e) => {
|
| | | spark.append(e.target.result);
|
| | | if (currentChunk < chunks) {
|
| | | currentChunk++;
|
| | | loadNext();
|
| | | } else {
|
| | | let md5 = spark.end();
|
| | | this.computeMD5Success(md5, file);
|
| | | this.fileName = file.name;
|
| | | this.fileMd5 = md5;
|
| | | }
|
| | | };
|
| | | fileReader.onerror = function () {
|
| | | this.error(`文件${file.name}读取出错,请检查该文件`);
|
| | | file.cancel();
|
| | | };
|
| | | function loadNext() {
|
| | | let start = currentChunk * chunkSize;
|
| | | let end =
|
| | | start + chunkSize >= file.size ? file.size : start + chunkSize;
|
| | | fileReader.readAsArrayBuffer(blobSlice.call(file.file, start, end));
|
| | | }
|
| | | },
|
| | | computeMD5Success(md5, file) {
|
| | | //将自定义参数直接加载uploader实例的opts上
|
| | | if (location.href.indexOf("dataStack") >= 0) {
|
| | | Object.assign(this.uploader.opts, {
|
| | | query: {
|
| | | stackId: this.DataStackPool.selectedDir.id,
|
| | | // ...this.params,
|
| | | },
|
| | | });
|
| | | }
|
| | | file.uniqueIdentifier = md5;
|
| | | file.resume();
|
| | | this.statusText.paused = "暂停中";
|
| | | },
|
| | | onComplete() {
|
| | | this.$emit("complete", {
|
| | | filename: this.fileName,
|
| | | identifier: this.fileMd5,
|
| | | });
|
| | | },
|
| | | fileComplete() {},
|
| | | closeHandle() {
|
| | | this.$emit("close");
|
| | | },
|
| | | },
|
| | | mounted() {
|
| | | this.isDrag;
|
| | | this.$nextTick(() => {
|
| | | window.uploader = this.$refs.uploader.uploader;
|
| | | });
|
| | | },
|
| | | };
|
| | | </script>
|
| | |
|
| | | <style lang="scss">
|
| | | .file-uploader {
|
| | | .el-input__suffix,
|
| | | .el-input__suffix-inner {
|
| | | outline: none !important;
|
| | | }
|
| | | .el-tooltip.focusing {
|
| | | outline: none;
|
| | | }
|
| | | .uploader-example {
|
| | | width: 99%;
|
| | | // padding: 15px;
|
| | | // margin: 40px auto 0;
|
| | | font-size: 12px;
|
| | | // box-shadow: 0 0 10px rgba(0, 0, 0, 0.4);
|
| | | background-color: #fff;
|
| | | }
|
| | | .uploader-example .uploader-btn {
|
| | | position: relative;
|
| | | display: none;
|
| | | // float: right;
|
| | | // top: -45px;
|
| | | }
|
| | | .uploader-example .uploader-list {
|
| | | max-height: 440px;
|
| | | overflow: auto;
|
| | | overflow-x: hidden;
|
| | | overflow-y: auto;
|
| | | }
|
| | | .uploader-single {
|
| | | position: unset;
|
| | | .close {
|
| | | display: none;
|
| | | }
|
| | | .uploader-btn {
|
| | | border: 0px;
|
| | | }
|
| | | .uploader-file {
|
| | | // height: 2px;
|
| | | .uploader-file-progress {
|
| | | // background: #3d68e1;
|
| | | }
|
| | | .uploader-file-info {
|
| | | // display: none;
|
| | | }
|
| | | }
|
| | |
|
| | | .up-bar {
|
| | | height: 30px;
|
| | | background: #f2f2f7;
|
| | | border-radius: 2px;
|
| | | display: flex;
|
| | | align-items: center;
|
| | | justify-content: space-between;
|
| | | box-sizing: border-box;
|
| | | padding: 0 20px;
|
| | | .iconfont {
|
| | | font-size: 16px;
|
| | | color: #333;
|
| | | }
|
| | | .name {
|
| | | color: #bdbdbd;
|
| | | font-size: 14px;
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | | </style>>
|
New file |
| | |
| | | <template> |
| | | <div class="uploader-list"> |
| | | <slot :file-list="fileList"> |
| | | <ul> |
| | | <li v-for="file in fileList" :key="file.id"> |
| | | <uploader-file :file="file" :list="true"></uploader-file> |
| | | </li> |
| | | </ul> |
| | | </slot> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { uploaderMixin } from './common/mixins' |
| | | import UploaderFile from './file.vue' |
| | | |
| | | const COMPONENT_NAME = 'uploader-list' |
| | | |
| | | export default { |
| | | name: COMPONENT_NAME, |
| | | mixins: [uploaderMixin], |
| | | computed: { |
| | | fileList() { |
| | | return this.uploader.fileList |
| | | } |
| | | }, |
| | | components: { |
| | | UploaderFile |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style> |
| | | .uploader-list { |
| | | position: relative; margin-top: 12px; |
| | | |
| | | } |
| | | .uploader-list > ul { |
| | | list-style: none; |
| | | margin: 0; |
| | | padding: 0; |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="uploader-unsupport" v-show="!support"> |
| | | <slot> |
| | | <p> |
| | | Your browser, unfortunately, is not supported by Uploader.js. The library requires support for |
| | | <a href="http://www.w3.org/TR/FileAPI/">the HTML5 File API</a> along with |
| | | <a href="http://www.w3.org/TR/FileAPI/#normalization-of-params">file slicing</a>. |
| | | </p> |
| | | </slot> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import { uploaderMixin, supportMixin } from './common/mixins' |
| | | |
| | | const COMPONENT_NAME = 'uploader-unsupport' |
| | | |
| | | export default { |
| | | name: COMPONENT_NAME, |
| | | mixins: [uploaderMixin, supportMixin] |
| | | } |
| | | </script> |
| | | |
| | | <style> |
| | | .uploader-unsupport { |
| | | position: relative; |
| | | z-index: 10; |
| | | overflow: hidden; |
| | | } |
| | | </style> |
New file |
| | |
| | | <template> |
| | | <div class="uploader"> |
| | | <!-- <div class="close" @click="closeHandle">x</div> --> |
| | | <slot :files="files" :file-list="fileList" :started="started"> |
| | | <uploader-unsupport></uploader-unsupport> |
| | | <UploaderDrop> |
| | | <p>拖动文件到该区域上传</p> |
| | | |
| | | <uploader-btn >选择文件</uploader-btn> |
| | | <uploader-btn :directory="true" >选择文件夹</uploader-btn> |
| | | </UploaderDrop> |
| | | <uploader-list></uploader-list> |
| | | </slot> |
| | | </div> |
| | | </template> |
| | | |
| | | <script> |
| | | import Uploader from 'simple-uploader.js' |
| | | import { kebabCase } from './common/utils' |
| | | import UploaderBtn from './btn.vue' |
| | | import UploaderDrop from './drop.vue' |
| | | import UploaderUnsupport from './unsupport.vue' |
| | | import UploaderList from './list.vue' |
| | | |
| | | const COMPONENT_NAME = 'uploader' |
| | | const FILE_ADDED_EVENT = 'fileAdded' |
| | | const FILES_ADDED_EVENT = 'filesAdded' |
| | | const UPLOAD_START_EVENT = 'uploadStart' |
| | | |
| | | export default { |
| | | name: COMPONENT_NAME, |
| | | provide() { |
| | | return { |
| | | uploader: this |
| | | } |
| | | }, |
| | | props: { |
| | | attrs: { |
| | | type: Object, |
| | | default() { |
| | | return {} |
| | | } |
| | | }, |
| | | options: { |
| | | type: Object, |
| | | default() { |
| | | return {} |
| | | } |
| | | }, |
| | | autoStart: { |
| | | type: Boolean, |
| | | default: true |
| | | }, |
| | | fileStatusText: { |
| | | type: [Object, Function], |
| | | default() { |
| | | return { |
| | | success: 'success', |
| | | error: 'error', |
| | | uploading: 'uploading', |
| | | paused: 'paused', |
| | | waiting: 'waiting' |
| | | } |
| | | } |
| | | } |
| | | }, |
| | | data() { |
| | | return { |
| | | started: false, |
| | | files: [], |
| | | fileList: [] |
| | | } |
| | | }, |
| | | methods: { |
| | | uploadStart() { |
| | | this.started = true |
| | | }, |
| | | fileAdded(file) { |
| | | this.$emit(kebabCase(FILE_ADDED_EVENT), file) |
| | | if (file.ignored) { |
| | | // is ignored, filter it |
| | | return false |
| | | } |
| | | }, |
| | | filesAdded(files, fileList) { |
| | | this.$emit(kebabCase(FILES_ADDED_EVENT), files, fileList) |
| | | if (files.ignored || fileList.ignored) { |
| | | // is ignored, filter it |
| | | return false |
| | | } |
| | | }, |
| | | fileRemoved(file) { |
| | | this.files = this.uploader.files |
| | | this.fileList = this.uploader.fileList |
| | | }, |
| | | filesSubmitted(files, fileList) { |
| | | this.files = this.uploader.files |
| | | this.fileList = this.uploader.fileList |
| | | if (this.autoStart) { |
| | | this.uploader.upload() |
| | | } |
| | | }, |
| | | allEvent(...args) { |
| | | console.log(args) |
| | | const name = args[0] |
| | | const EVENTSMAP = { |
| | | [FILE_ADDED_EVENT]: true, |
| | | [FILES_ADDED_EVENT]: true, |
| | | [UPLOAD_START_EVENT]: 'uploadStart' |
| | | } |
| | | const handler = EVENTSMAP[name] |
| | | if (handler) { |
| | | if (handler === true) { |
| | | return |
| | | } |
| | | this[handler].apply(this, args.slice(1)) |
| | | } |
| | | args[0] = kebabCase(name) |
| | | this.$emit.apply(this, args) |
| | | }, |
| | | closeHandle() { |
| | | this.$emit("close") |
| | | } |
| | | }, |
| | | created() { |
| | | // console.log('uploader attrs',this.attrs); |
| | | // this.bindUploader(); |
| | | this.options.initialPaused = !this.autoStart |
| | | const uploader = new Uploader(this.options) |
| | | this.uploader = uploader |
| | | this.uploader.fileStatusText = this.fileStatusText |
| | | uploader.on('catchAll', this.allEvent) |
| | | uploader.on(FILE_ADDED_EVENT, this.fileAdded) |
| | | uploader.on(FILES_ADDED_EVENT, this.filesAdded) |
| | | uploader.on('fileRemoved', this.fileRemoved) |
| | | uploader.on('filesSubmitted', this.filesSubmitted) |
| | | }, |
| | | mounted() { |
| | | }, |
| | | destroyed() { |
| | | const uploader = this.uploader |
| | | uploader.off('catchAll', this.allEvent) |
| | | uploader.off(FILE_ADDED_EVENT, this.fileAdded) |
| | | uploader.off(FILES_ADDED_EVENT, this.filesAdded) |
| | | uploader.off('fileRemoved', this.fileRemoved) |
| | | uploader.off('filesSubmitted', this.filesSubmitted) |
| | | this.uploader = null |
| | | }, |
| | | components: { |
| | | UploaderBtn, |
| | | UploaderDrop, |
| | | UploaderUnsupport, |
| | | UploaderList |
| | | } |
| | | } |
| | | </script> |
| | | |
| | | <style lang="scss"> |
| | | .uploader { |
| | | .close { |
| | | position: absolute; |
| | | right: 5px; |
| | | top: 3px; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | |
| | | </style> |
| | |
| | | @click="pickMenu(name)"
|
| | | >
|
| | | {{ name }}
|
| | | <el-badge
|
| | | v-if="index == 3"
|
| | | class="update-badge"
|
| | | :value="updateNum"
|
| | | :hidden="updateNum == 0"
|
| | | ></el-badge>
|
| | | <sup v-if="index == 3 && updateNum != 0">{{ updateNum }}</sup>
|
| | | </div>
|
| | | </div>
|
| | | <div class="nav-box-search">
|
| | | <span class="icon iconfont all-scene"></span>
|
| | | <el-input
|
| | | placeholder="搜索"
|
| | | v-model="input3"
|
| | |
| | | <el-select
|
| | | v-model="select"
|
| | | slot="append"
|
| | | placeholder="所有场景"
|
| | | placeholder="选择场景"
|
| | | :popper-append-to-body="false"
|
| | | >
|
| | | <el-option label="铁路场景" value="1"></el-option>
|
| | | <el-option label="安全场景" value="2"></el-option>
|
| | | <el-option label="通用场景" value="3"></el-option>
|
| | | <el-option label="校园园区" value="4"></el-option>
|
| | | <el-option label="铁路场景" value="1">
|
| | | <span class="icon iconfont"></span>
|
| | | <span>铁路场景</span>
|
| | | </el-option>
|
| | | <el-option label="安全场景" value="2">
|
| | | <span class="icon iconfont"></span>
|
| | | <span>安全场景</span>
|
| | | </el-option>
|
| | | <el-option label="通用场景" value="3">
|
| | | <span class="icon iconfont"></span>
|
| | | <span>通用场景</span>
|
| | | </el-option>
|
| | | <el-option label="校园园区" value="4">
|
| | | <span class="icon iconfont"></span>
|
| | | <span>校园园区</span>
|
| | | </el-option>
|
| | | </el-select>
|
| | | </el-input>
|
| | | </div>
|
| | |
|
| | | <div class="bg-img-wrap">
|
| | | <img src="/images/appCenter/app-banner.jpg" alt="" />
|
| | | <img src="/images/appCenter/Group-112.png" alt="" />
|
| | | </div>
|
| | | </div>
|
| | | <div class="quick-path" v-if="showQuickPath">
|
| | | <div
|
| | | class="quick-item"
|
| | | v-for="(item, index) in recomandUpdateList"
|
| | | :key="index"
|
| | | @click="checkDetail(item, 'active')"
|
| | | >
|
| | | <div class="icon-img">
|
| | | <img
|
| | | v-if="item.iconBlob"
|
| | | :src="
|
| | | item.iconBlob.indexOf(',') > 0
|
| | | ? item.iconBlob
|
| | | : `data:image/png;base64,${item.iconBlob}`
|
| | | "
|
| | | alt
|
| | | />
|
| | | <img v-else :src="item.icon" alt />
|
| | | </div>
|
| | | <div class="desc">
|
| | | <div class="desc-1">{{ item.sdk_name || item.name }}</div>
|
| | | <div class="desc-2">版本 {{ item.version }}</div>
|
| | | </div>
|
| | | <div class="right-icon">
|
| | | <span class="icon iconfont"></span>
|
| | | <div class="left-items">
|
| | | <div
|
| | | class="quick-item"
|
| | | v-for="(item, index) in recomandUpdateList"
|
| | | :key="index"
|
| | | @click="checkDetail(item, 'inactive')"
|
| | | >
|
| | | <div class="icon-img">
|
| | | <span class="icon iconfont" v-if="item.isUpgrade"
|
| | | ></span
|
| | | >
|
| | | <img
|
| | | v-if="item.iconBlob"
|
| | | :src="
|
| | | item.iconBlob.indexOf(',') > 0
|
| | | ? item.iconBlob
|
| | | : `data:image/png;base64,${item.iconBlob}`
|
| | | "
|
| | | alt
|
| | | />
|
| | | <img v-else :src="item.icon" alt />
|
| | | </div>
|
| | | <div class="desc">
|
| | | <div class="desc-1">{{ item.sdk_name || item.name }}</div>
|
| | | <div class="desc-2">版本 {{ item.version }}</div>
|
| | | </div>
|
| | | <div class="right-icon">
|
| | | <span class="icon iconfont"></span>
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | |
|
| | | <div class="down-all-btn">
|
| | | <!-- <div class="down-all-btn">
|
| | | <el-button plain size="small" @click="batchUpdate('both')" round
|
| | | >全部更新</el-button
|
| | | >
|
| | | </div>
|
| | | </div> -->
|
| | | </div>
|
| | |
|
| | | <div class="main-content">
|
| | |
| | | >
|
| | | </div>
|
| | | </div>
|
| | | <div class="front-page-items" v-if="activeName != '离线升级/安装'">
|
| | | <div
|
| | | class="front-page-items"
|
| | | v-if="activeName != '离线升级/安装'"
|
| | | >
|
| | | <div
|
| | | class="front-page-item"
|
| | | v-for="(item, index) in tempList"
|
| | |
| | | @click="checkDetail(item)"
|
| | | >
|
| | | <div class="icon-img">
|
| | | <span class="icon iconfont" v-if="item.isUpgrade"
|
| | | ></span
|
| | | >
|
| | | <img
|
| | | v-if="item.iconBlob"
|
| | | :src="
|
| | |
| | | <el-button
|
| | | size="small"
|
| | | type="primary"
|
| | | class="other-btn"
|
| | | round
|
| | | @click="checkDetail(item)"
|
| | | v-if="activeName == '应用中心'"
|
| | |
| | | <el-button
|
| | | size="small"
|
| | | type="primary"
|
| | | class="check-btn"
|
| | | round
|
| | | v-if="
|
| | | activeName == '已激活' &&
|
| | | (activeTab == 'sdk' ||
|
| | | (activeTab == 'app' && !item.isDefault))
|
| | | ((activeTab == 'sdk' && !item.isUpgrade) ||
|
| | | (activeTab == 'app' &&
|
| | | !item.isUpgrade &&
|
| | | !item.isDefault))
|
| | | "
|
| | | @click.stop="unLoadSdkOrApp(item)"
|
| | | >卸载</el-button
|
| | | >查看</el-button
|
| | | >
|
| | | <!-- @click.stop="unLoadSdkOrApp(item)" -->
|
| | |
|
| | | <el-button
|
| | | size="small"
|
| | | type="primary"
|
| | | class="check-btn"
|
| | | round
|
| | | v-if="
|
| | | activeName == '已激活' &&
|
| | |
| | | <el-button
|
| | | size="small"
|
| | | type="primary"
|
| | | class="other-btn"
|
| | | round
|
| | | v-if="
|
| | | activeName == '已激活' &&
|
| | |
| | | "
|
| | | >升级</el-button
|
| | | >
|
| | | <el-button
|
| | | size="small"
|
| | | type="primary"
|
| | | class="update-btn"
|
| | | round
|
| | | @click.stop="donwloadSDK(item)"
|
| | | v-if="
|
| | | (activeName == '更新' || activeName == '已激活') &&
|
| | | activeTab == 'sdk' &&
|
| | | item.isUpgrade &&
|
| | | !item.upgradeLoading
|
| | | "
|
| | | >更新</el-button
|
| | | >
|
| | | <span
|
| | | class="icon iconfont rocket-icon"
|
| | | v-if="
|
| | | activeName == '更新' &&
|
| | | item.isUpgrade &&
|
| | | item.upgradeLoading &&
|
| | | rocketIf
|
| | | "
|
| | | ></span
|
| | | >
|
| | | <span
|
| | | class="icon iconfont rocket-icon"
|
| | | v-if="
|
| | | activeName == '更新' &&
|
| | | item.isUpgrade &&
|
| | | item.upgradeLoading &&
|
| | | !rocketIf
|
| | | "
|
| | | ></span
|
| | | >
|
| | | <el-button
|
| | | size="small"
|
| | | type="primary"
|
| | | class="update-btn"
|
| | | round
|
| | | @click.stop="downloadApp(item, 'upgrade')"
|
| | | v-if="
|
| | | (activeName == '更新' || activeName == '已激活') &&
|
| | | activeTab == 'app' &&
|
| | | item.isUpgrade &&
|
| | | !item.upgradeLoading
|
| | | "
|
| | | >更新</el-button
|
| | | >
|
| | |
|
| | | <div class="status">
|
| | | {{ item.progressMsg }}
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | |
|
| | |
| | | class="front-page-item item-dimmed"
|
| | | v-for="(item, index) in tempDarkList"
|
| | | :key="index"
|
| | | @click="checkDetail(item, 'activeNotInstall')"
|
| | | >
|
| | | <div class="icon-img">
|
| | | <img
|
| | |
| | | <el-button
|
| | | size="small"
|
| | | type="primary"
|
| | | class="other-btn"
|
| | | round
|
| | | @click="donwload(item)"
|
| | | v-if="activeTab == 'sdk' && !item.upgradeLoading"
|
| | | @click.stop="donwloadSDK(item)"
|
| | | >安装</el-button
|
| | | >
|
| | | <el-button
|
| | | size="small"
|
| | | type="primary"
|
| | | class="other-btn"
|
| | | round
|
| | | v-if="activeTab == 'app' && !item.upgradeLoading"
|
| | | @click.stop="downloadApp(item)"
|
| | | >安装</el-button
|
| | | >
|
| | | <div class="spin-icon">
|
| | | <span
|
| | | class="icon iconfont anz-font"
|
| | | v-if="item.upgradeLoading"
|
| | | ></span
|
| | | >
|
| | | </div>
|
| | | <div class="status">
|
| | | {{ item.progressMsg }}
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | |
|
| | | <div class="upload-pkg">
|
| | |
|
| | | <div class="upload-pkg" v-if="activeName == '离线升级/安装'">
|
| | | <div class="upload-head">
|
| | | <div class="left">
|
| | | <span class="icon iconfont"></span>
|
| | | <span class="txt">上传安装软件</span>
|
| | | </div>
|
| | | <div class="right">
|
| | | <span class="icon iconfont"></span>
|
| | | <span class="icon iconfont"></span>
|
| | | </div>
|
| | |
|
| | | </div>
|
| | |
|
| | |
|
| | | <FileUploader
|
| | | class="upload-demo"
|
| | | single
|
| | | tip
|
| | | :isDrag="true"
|
| | | tipWords="点击上传"
|
| | | uploadPlaceholder="算法软件"
|
| | | url="/data/api-v/sdk/upload"
|
| | | @complete="onFileUpload"
|
| | | @file-added="onFileAdded"
|
| | | />
|
| | | </div>
|
| | |
|
| | | </div>
|
| | | </div>
|
| | |
|
| | |
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | |
|
| | | <el-dialog
|
| | | title="安装包信息"
|
| | | :visible.sync="installDialogVisible"
|
| | | width="40%"
|
| | | :close-on-click-modal="false"
|
| | | >
|
| | | <div class="installInfo">
|
| | | <template v-if="installAppPackage != null">
|
| | | <div>
|
| | | <div>
|
| | | <span>安装包名称:</span>
|
| | | <span>{{ installAppPackage.productName }}</span>
|
| | | </div>
|
| | | <div>
|
| | | <span>安装版本:</span>
|
| | | <span>{{ installAppPackage.version }}</span>
|
| | | </div>
|
| | | <div>
|
| | | <span>更新内容:</span>
|
| | | <span>{{ installAppPackage.installContent }}</span>
|
| | | </div>
|
| | | </div>
|
| | | </template>
|
| | | <template v-if="installSdkPackage != null">
|
| | | <div>
|
| | | <div>
|
| | | <span>安装包名称:</span>
|
| | | <span>{{ installSdkPackage.productName }}</span>
|
| | | </div>
|
| | | <div>
|
| | | <span>安装版本:</span>
|
| | | <span>{{ installSdkPackage.version }}</span>
|
| | | </div>
|
| | | <div>
|
| | | <span>更新内容:</span>
|
| | | <span>{{ installSdkPackage.installContent }}</span>
|
| | | </div>
|
| | | </div>
|
| | | </template>
|
| | | <p>确定安装?</p>
|
| | | </div>
|
| | | <div slot="footer" class="dialog-footer">
|
| | | <el-button @click="installDialogVisible = false">取 消</el-button>
|
| | | <el-button type="primary" @click="offlineInstall">安 装</el-button>
|
| | | </div>
|
| | | </el-dialog>
|
| | | </div>
|
| | | </template>
|
| | | <script>
|
| | |
| | | installSdk,
|
| | | getInstallInfo,
|
| | | removeSdk,
|
| | | uploadSDK,
|
| | | } from "./api";
|
| | | import {
|
| | | getApps,
|
| | |
| | | actApp,
|
| | | } from "@/api/app";
|
| | | import { getUrlKey } from "@/api/utils";
|
| | | import FileUploader from "@/components/subComponents/FileUpload/index";
|
| | | import FileUploader from "../FileUpload/index";
|
| | | import detailPage from "./detail";
|
| | | export default {
|
| | | name: "algorithmManage",
|
| | |
| | | }
|
| | | return false;
|
| | | },
|
| | | recomandUpdateList() {
|
| | | if (this.activeTab == "sdk") {
|
| | | return this.hasNewVersionSdk.slice(0, 3);
|
| | | } else {
|
| | | return this.hasNewVersionApp.slice(0, 3);
|
| | | }
|
| | | },
|
| | | },
|
| | | data() {
|
| | | return {
|
| | | installedList: [],
|
| | | recomandUpdateList: [],
|
| | | hasNewVersionSdk: [],
|
| | | activeTab: "sdk",
|
| | | hasNewVersionApp: [],
|
| | | tempDarkList: [],
|
| | | notInstalledList: [],
|
| | | showUpload: false,
|
| | | detailType: "",
|
| | | detailProductID: "",
|
| | | buttonAuthority: sessionStorage.getItem("buttonAuthoritys") || [],
|
| | |
| | | backStack: [],
|
| | | toUpdateArr1: [],
|
| | | forwardStack: [],
|
| | | rocketIf: false,
|
| | | backDisable: true,
|
| | | forwardDisable: true,
|
| | | showInputCode: false,
|
| | |
| | | },
|
| | | batchUpdateSDK() {
|
| | | this.hasNewVersionSdk.forEach((sdk) => {
|
| | | this.donwload(sdk, 0);
|
| | | this.donwloadSDK(sdk);
|
| | | });
|
| | | },
|
| | | batchUpdateApp() {
|
| | |
| | | this.activeTab == "sdk"
|
| | | ? this.hasNewVersionSdk
|
| | | : this.hasNewVersionApp;
|
| | |
|
| | | this.tempDarkList = [];
|
| | | }
|
| | | },
|
| | |
| | | } else {
|
| | | this.detailType = this.activeName == "应用中心" ? "inactive" : "active";
|
| | | }
|
| | | },
|
| | | resetStack() {
|
| | | this.forwardStack = [];
|
| | | this.backStack = [];
|
| | | this.backDisable = true;
|
| | | this.forwardDisable = true;
|
| | | },
|
| | | checkInWindow(item) {
|
| | | this.backStack.push([this.productDetail, this.otherProducts]);
|
| | |
| | | .then((res) => {
|
| | | if (res.success) {
|
| | | this.isInstall = false;
|
| | | this.$message({
|
| | | type: "success",
|
| | | message: '安装成功,将跳转至"已激活"中查看',
|
| | | });
|
| | | this.$message.success('安装成功,将跳转至"已激活"中查看');
|
| | | setTimeout(() => {
|
| | | this.getAllSdk();
|
| | | window.parent.postMessage({ msg: "AppUpdate" }, "*");
|
| | |
|
| | | this.activeName = "已激活";
|
| | | }, 3000);
|
| | | }
|
| | | })
|
| | | .catch((e) => {
|
| | | this.isInstall = false;
|
| | | this.$message({
|
| | | type: "error",
|
| | | message: e.data,
|
| | | });
|
| | | this.$message.error(e.data);
|
| | | });
|
| | | },
|
| | | downloadApp(app, action) {
|
| | | if (action == "upgrade") {
|
| | | app.upgradeLoading = true;
|
| | | } else {
|
| | | app.installLoading = true;
|
| | | }
|
| | | let _this = this;
|
| | | let timer = null;
|
| | | app.upgradeLoading = true;
|
| | | timer = setInterval(() => {
|
| | | this.rocketIf = !this.rocketIf;
|
| | | }, 350);
|
| | |
|
| | | let _this = this;
|
| | | installApp({ path: app.id })
|
| | | .then((res) => {
|
| | | if (res && res.success) {
|
| | | _this.$notify({
|
| | | title: "成功",
|
| | | message: "安装应用成功",
|
| | | type: "success",
|
| | | });
|
| | | _this.$notify.success("安装应用成功");
|
| | | clearInterval(timer);
|
| | | app.upgradeLoading = false;
|
| | | setTimeout(() => {
|
| | | if (action == "upgrade") {
|
| | | app.upgradeLoading = false;
|
| | | } else {
|
| | | app.installLoading = false;
|
| | | }
|
| | | window.parent.postMessage({ msg: "AppUpdate" }, "*");
|
| | | }, 3000);
|
| | | } else {
|
| | | }
|
| | | })
|
| | | .catch((e) => {
|
| | | _this.$notify({
|
| | | title: "安装失败",
|
| | | message: e.data,
|
| | | type: "warning",
|
| | | });
|
| | | if (action == "upgrade") {
|
| | | app.upgradeLoading = false;
|
| | | } else {
|
| | | app.installLoading = false;
|
| | | }
|
| | | _this.$notify.warning(e.data);
|
| | | clearInterval(timer);
|
| | | app.upgradeLoading = false;
|
| | | });
|
| | |
|
| | | // 开启自动刷新
|
| | | this.appUpgreading = true;
|
| | | },
|
| | |
| | | { unloadLoading: false, upgradeLoading: false },
|
| | | item
|
| | | );
|
| | | if (obj.progressMsg !== "" && obj.progressMsg !== "已安装") {
|
| | | if (
|
| | | obj.progressMsg !== "" &&
|
| | | obj.progressMsg !== "已安装" &&
|
| | | obj.progressMsg != "100%"
|
| | | ) {
|
| | | obj.upgradeLoading = true;
|
| | |
|
| | | this.appUpgreading = true;
|
| | | }
|
| | |
|
| | | if (obj.upgradeDone) {
|
| | | this.$notify({
|
| | | type: "success",
|
| | | message: 1 ? "算法安装成功" : "算法升级成功",
|
| | | });
|
| | | this.$notify.success(1 ? "算法安装成功" : "算法升级成功");
|
| | | }
|
| | |
|
| | | item.installed ? iArry.push(obj) : sArry.push(obj);
|
| | |
| | | app.unloadLoading = false;
|
| | | _this.getAllApps();
|
| | | window.parent.postMessage({ msg: "AppUpdate" }, "*");
|
| | |
|
| | | _this.$notify({
|
| | | title: "成功",
|
| | | message: "卸载应用成功",
|
| | | type: "success",
|
| | | });
|
| | | _this.$notify.success("卸载应用成功");
|
| | | }
|
| | | })
|
| | | .catch((e) => {
|
| | |
| | | getUnActivedSdk().then((res) => {
|
| | | if (res.code == 200) {
|
| | | this.unActivedSDKList = res.data;
|
| | | const len = this.unActivedSDKList.length;
|
| | | const set = new Set();
|
| | | if (len <= 3) {
|
| | | this.recomandUpdateList = [...this.unActivedSDKList];
|
| | | } else {
|
| | | for (let i = 0; i < 3; i++) {
|
| | | const pickI = Math.floor(Math.random() * len);
|
| | | if (set.has(pickI)) {
|
| | | i--;
|
| | | continue;
|
| | | }
|
| | | set.add(pickI);
|
| | | this.recomandUpdateList.push(this.unActivedSDKList[pickI]);
|
| | | }
|
| | | }
|
| | | v == 1 ? (this.tempList = res.data) : null;
|
| | | }
|
| | | });
|
| | |
| | | { unloadLoading: false, upgradeLoading: false },
|
| | | item
|
| | | );
|
| | | if (obj.progressMsg !== "" && obj.progressMsg !== "已安装") {
|
| | | if (
|
| | | obj.progressMsg !== "" &&
|
| | | obj.progressMsg !== "已安装" &&
|
| | | obj.progressMsg !== "100%"
|
| | | ) {
|
| | | obj.upgradeLoading = true;
|
| | |
|
| | | this.sdkUpgreading = true;
|
| | | }
|
| | |
|
| | |
| | | })
|
| | | .catch((e) => {});
|
| | | },
|
| | | upgradeSDKinWin() {
|
| | | this.isUpgrading = !this.isUpgrading;
|
| | | let _this = this;
|
| | | if (this.productDetail.productTypeName == "应用") {
|
| | | installApp({ path: this.productDetail.productBaseId })
|
| | | .then((res) => {
|
| | | if (res && res.success) {
|
| | | this.$notify.success("升级完成");
|
| | | this.needToUpgradeInWin = false;
|
| | | this.productDetail.isUpgrade = false;
|
| | | this.isUpgrading = !this.isUpgrading;
|
| | | }
|
| | | })
|
| | | .catch((e) => {
|
| | | this.$notify.warning("升级失败");
|
| | | this.isUpgrading = !this.isUpgrading;
|
| | | });
|
| | |
|
| | | // 开启自动刷新
|
| | | this.appUpgreading = true;
|
| | | } else {
|
| | | downloadSdk({ path: this.productDetail.productBaseId })
|
| | | .then((res) => {
|
| | | this.needToUpgradeInWin = false;
|
| | | this.productDetail.isUpgrade = false;
|
| | | this.isUpgrading = !this.isUpgrading;
|
| | | this.$notify.success("升级完成");
|
| | | })
|
| | | .catch((err) => {
|
| | | this.$notify.warning("升级失败");
|
| | | this.isUpgrading = !this.isUpgrading;
|
| | | });
|
| | | this.sdkUpgreading = true;
|
| | | }
|
| | | },
|
| | | downloadSdkInSide() {
|
| | | this.downloadItem = this.productDetail.productBaseId;
|
| | | this.isUpgrading = true;
|
| | | downloadSdk({ path: this.productDetail.productBaseId })
|
| | | .then((rsp) => {
|
| | | this.productDetailVisible = false;
|
| | | this.downloadItem = "";
|
| | | this.$notify.success("算法已安装");
|
| | | this.isUpgrading = false;
|
| | | })
|
| | | .catch((err) => {
|
| | | this.$notify.warning(err.data);
|
| | | this.downloadItem = "";
|
| | | this.isUpgrading = false;
|
| | | });
|
| | | // 开启自动刷新
|
| | | this.sdkUpgreading = true;
|
| | | },
|
| | | donwload(item) {
|
| | | donwloadSDK(item) {
|
| | | let timer = null;
|
| | | item.upgradeLoading = true;
|
| | | timer = setInterval(() => {
|
| | | this.rocketIf = !this.rocketIf;
|
| | | }, 350);
|
| | | this.downloadItem = item.id;
|
| | | downloadSdk({ path: item.id })
|
| | | .then((rsp) => {
|
| | | clearInterval(timer);
|
| | | item.upgradeLoading = false;
|
| | | this.downloadItem = "";
|
| | | window.parent.postMessage({ msg: "AppUpdate" }, "*");
|
| | |
| | | });
|
| | | // 开启自动刷新
|
| | | this.sdkUpgreading = true;
|
| | | },
|
| | | inputBlur(item) {
|
| | | this.$set(item, "isEdit", false);
|
| | | },
|
| | | autoRefreshAppAndSdkState() {
|
| | | // 关闭后退出
|
| | |
| | | height: 100%;
|
| | | box-sizing: border-box;
|
| | | text-align: left;
|
| | | min-width: 1106px;
|
| | | }
|
| | | .el-loading-mask .el-loading-spinner {
|
| | | top: 40px !important;
|
| | | }
|
| | | .el-loading-mask .el-loading-spinner svg {
|
| | | transform: none !important;
|
| | | top: 20px !important;
|
| | | left: 40% !important;
|
| | | }
|
| | | .el-loading-mask .el-loading-spinner p.el-loading-text {
|
| | | display: block !important;
|
| | | text-align: center !important;
|
| | | bottom: 10px !important;
|
| | | top: 80px !important;
|
| | | right: 0 !important;
|
| | | color: #78adf7;
|
| | | }
|
| | | .el-loading-mask .el-loading-spinner .path {
|
| | | stroke: #78adf7;
|
| | | }
|
| | |
|
| | | .update-badge .el-badge__content.is-fixed {
|
| | | top: 10px;
|
| | | right: 4px;
|
| | | }
|
| | |
|
| | | .task-manage {
|
| | |
| | | border-left: 3px solid #f3f6fc;
|
| | | cursor: pointer;
|
| | | caret-color: transparent;
|
| | | .el-badge__content {
|
| | | border-radius: 50%;
|
| | | sup {
|
| | | background-color: #f52323;
|
| | | font-size: 12px;
|
| | | height: 14px;
|
| | | line-height: 14px;
|
| | | padding: 0px 3px;
|
| | | color: #fff;
|
| | | height: 18px;
|
| | | line-height: 18px;
|
| | | padding: 0 3.5px;
|
| | | border-radius: 50%;
|
| | | }
|
| | | }
|
| | | .menu-item:hover {
|
| | |
| | | border-left: 3px solid #23d7ee;
|
| | | font-weight: 700;
|
| | | font-size: 16px;
|
| | | // transition: transform .3s cubic-bezier(.645,.045,.355,1);
|
| | | color: #333;
|
| | | }
|
| | | }
|
| | | .nav-box-search {
|
| | | z-index: 99;
|
| | | position: relative;
|
| | | .all-scene {
|
| | | position: absolute;
|
| | | z-index: 100;
|
| | | right: 64px;
|
| | |
|
| | | top: 10px;
|
| | | font-size: 12px;
|
| | | }
|
| | | .el-input {
|
| | | position: relative;
|
| | | font-size: 12px;
|
| | |
| | | border: none;
|
| | | height: 30px;
|
| | | line-height: 30px;
|
| | | padding: 0 12px;
|
| | | }
|
| | | .el-input-group__prepend {
|
| | | border-right: 0;
|
| | | border: none;
|
| | | border-radius: 20px;
|
| | | background: #fff;
|
| | | padding: 0 25px;
|
| | | padding: 0 0 0 15px;
|
| | |
|
| | | i {
|
| | | font-weight: 600;
|
| | | color: #333;
|
| | | font-size: 19px;
|
| | | font-size: 16px;
|
| | | }
|
| | | }
|
| | | .el-input-group--append .el-input__inner,
|
| | |
| | | border-left: 0;
|
| | | border: none;
|
| | | border-radius: 20px;
|
| | | width: 64px;
|
| | | width: 52px;
|
| | | background: linear-gradient(
|
| | | 180deg,
|
| | | #ecfcfe 0%,
|
| | |
| | | font-size: 12px;
|
| | | font-weight: bold;
|
| | | letter-spacing: 0.5px;
|
| | | padding: 0 0px 0 30px;
|
| | | color: #474747;
|
| | | }
|
| | | .el-input__suffix {
|
| | | display: none;
|
| | | }
|
| | | }
|
| | | .el-input__inner::placeholder {
|
| | | color: rgb(71, 71, 71);
|
| | | // font-weight: 600;
|
| | | }
|
| | | .el-select-dropdown {
|
| | | min-width: 120px !important;
|
| | | left: -26px !important;
|
| | | background: rgba(236, 245, 253, 0.6);
|
| | | border-radius: 2px;
|
| | | border: none;
|
| | | .el-select-dropdown__item {
|
| | | height: 22px;
|
| | | line-height: 22px;
|
| | | font-size: 12px;
|
| | | letter-spacing: 0.4px;
|
| | | color: #333333;
|
| | | .icon {
|
| | | margin-right: 5px;
|
| | | font-size: 15px;
|
| | | }
|
| | | }
|
| | | .el-select-dropdown__item.hover,
|
| | | .el-select-dropdown__item:hover {
|
| | | background-color: #ebf4fd;
|
| | | font-weight: 600;
|
| | | }
|
| | | }
|
| | | }
|
| | | .el-input-group__prepend .el-select {
|
| | |
| | | position: absolute;
|
| | | z-index: 1;
|
| | | right: 0;
|
| | | top: 70px;
|
| | | height: 200px;
|
| | | top: 41px;
|
| | | height: 229px;
|
| | | img {
|
| | | height: 100%;
|
| | | }
|
| | |
| | | height: 75px;
|
| | | display: flex;
|
| | | align-items: center;
|
| | | .left-items {
|
| | | display: flex;
|
| | | }
|
| | | .quick-item {
|
| | | display: flex;
|
| | | cursor: pointer;
|
| | | padding: 2px 20px;
|
| | | height: 52px;
|
| | | box-sizing: border-box;
|
| | | border-right: 1px solid #e0e0e0;
|
| | |
|
| | | .icon-img {
|
| | | width: 48px;
|
| | | height: 48px;
|
| | | position: relative;
|
| | | .icon {
|
| | | position: absolute;
|
| | | right: -7px;
|
| | | top: -7px;
|
| | | font-size: 13px;
|
| | | }
|
| | | img {
|
| | | width: 48px;
|
| | | height: 48px;
|
| | |
| | | }
|
| | | }
|
| | | .right-icon {
|
| | | padding: 5px 0;
|
| | | padding: 2px 0;
|
| | |
|
| | | .icon {
|
| | | font-size: 21px;
|
| | | }
|
| | | }
|
| | | }
|
| | | .quick-item:not(:last-child) {
|
| | | border-right: 1px solid #e0e0e0;
|
| | | }
|
| | | .down-all-btn {
|
| | | // margin-left: 25px;
|
| | | position: absolute;
|
| | | right: 30px;
|
| | | .el-button {
|
| | |
| | | }
|
| | | }
|
| | | .main-content {
|
| | | padding: 35px 60px;
|
| | | padding: 35px 82px;
|
| | | z-index: 99;
|
| | | .main-title {
|
| | | line-height: 25px;
|
| | |
| | | .group-left {
|
| | | display: flex;
|
| | | .tab {
|
| | | font-size: 15px;
|
| | | font-size: 14px;
|
| | | margin-right: 25px;
|
| | | line-height: 28px;
|
| | | cursor: pointer;
|
| | |
| | | }
|
| | | }
|
| | | .front-page-items {
|
| | | padding-top: 30px;
|
| | | padding-top: 25px;
|
| | | .front-page-item {
|
| | | float: left;
|
| | | display: flex;
|
| | | margin-bottom: 30px;
|
| | | padding: 2px 0;
|
| | | height: 60px;
|
| | | margin: 0 5px;
|
| | | margin-bottom: 15px;
|
| | | box-sizing: border-box;
|
| | | width: 278px;
|
| | | width: 274px;
|
| | |
|
| | | justify-content: center;
|
| | | cursor: pointer;
|
| | | border-radius: 6px;
|
| | |
|
| | | padding: 10px 0;
|
| | | height: 76px;
|
| | | border-radius: 4px;
|
| | |
|
| | | .icon-img {
|
| | | width: 58px;
|
| | | height: 58px;
|
| | | position: relative;
|
| | | .icon {
|
| | | position: absolute;
|
| | | right: -9px;
|
| | | top: -9px;
|
| | | font-size: 16px;
|
| | | }
|
| | | img {
|
| | | width: 58px;
|
| | | height: 58px;
|
| | | border-radius: 10px;
|
| | | }
|
| | | }
|
| | | .desc {
|
| | | box-sizing: border-box;
|
| | | padding: 0 12px;
|
| | | width: 140px;
|
| | | width: 147px;
|
| | |
|
| | | .desc-1 {
|
| | | font-size: 14px;
|
| | | font-weight: bold;
|
| | |
| | | }
|
| | | }
|
| | | .right-btn {
|
| | | padding: 5px 0;
|
| | | .el-button {
|
| | | padding: 3px 12px;
|
| | | padding: 2px 0;
|
| | | width: 50px;
|
| | | text-align: center;
|
| | | position: relative;
|
| | | .check-btn {
|
| | | background-color: #f2f2f7 !important;
|
| | | border-color: #f2f2f7 !important;
|
| | | color: #4f4f4f;
|
| | | }
|
| | | .update-btn {
|
| | | border-color: #23d7ee !important;
|
| | | background-color: rgba(29, 212, 236, 0.1) !important;
|
| | | color: #4f4f4f;
|
| | | }
|
| | | .other-btn {
|
| | | background-color: #1dd4ec !important;
|
| | | border-color: #1dd4ec !important;
|
| | | border-radius: 22px;
|
| | | color: #ffffff;
|
| | | }
|
| | | .el-button--primary:hover {
|
| | | background: #089fb3 !important;
|
| | | border-color: #089fb3 !important;
|
| | | @keyframes spin {
|
| | | from {
|
| | | transform: rotate(0deg);
|
| | | }
|
| | | to {
|
| | | transform: rotate(360deg);
|
| | | }
|
| | | }
|
| | | .anz-font {
|
| | | font-size: 28px;
|
| | | color: #333;
|
| | | }
|
| | |
|
| | | .spin-icon {
|
| | | animation: spin 0.8s linear infinite;
|
| | | }
|
| | | .status {
|
| | | font-size: 12px;
|
| | | color: #828282;
|
| | | white-space: nowrap;
|
| | | overflow: hidden;
|
| | | text-overflow: ellipsis;
|
| | | min-width: 100px;
|
| | | text-align: end;
|
| | | position: absolute;
|
| | | right: 0;
|
| | | margin-top: 2px;
|
| | | }
|
| | | .rocket-icon {
|
| | | font-size: 20px;
|
| | | }
|
| | | .el-button {
|
| | | padding: 3px 12px;
|
| | | border-radius: 22px;
|
| | | font-weight: bold;
|
| | | letter-spacing: 0.5px;
|
| | | }
|
| | | }
|
| | | }
|
| | | .front-page-item:hover {
|
| | | background: linear-gradient(
|
| | | 180deg,
|
| | | #ecfcfe 0%,
|
| | | #ebf4fd 47.92%,
|
| | | #f4f4fe 100%
|
| | | );
|
| | | // background-color: #f2f2f7;
|
| | | }
|
| | | .item-dimmed {
|
| | | color: gray;
|
| | |
| | | clear: both;
|
| | | visibility: hidden;
|
| | | }
|
| | | .upload-pkg{
|
| | | .upload-head{
|
| | | .upload-pkg {
|
| | | .upload-head {
|
| | | display: flex;
|
| | | justify-content: space-between;
|
| | | align-items: center;
|
| | | .left{
|
| | | justify-content: space-between;
|
| | | align-items: center;
|
| | | .left {
|
| | | display: flex;
|
| | | align-items: center;
|
| | | .iconfont{
|
| | | .iconfont {
|
| | | font-size: 18px;
|
| | | margin-right: 6px;
|
| | | }
|
| | | .txt{
|
| | | font-size: 16px;
|
| | |
|
| | | .txt {
|
| | | font-size: 16px;
|
| | | }
|
| | | }
|
| | | .right{
|
| | | .icon{
|
| | | margin-right: 10px;
|
| | | .right {
|
| | | .icon {
|
| | | margin-right: 11px;
|
| | | font-size: 17px;
|
| | | cursor: pointer;
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | | .upload-demo {
|
| | | margin: 30px 0px;
|
| | | .drag-txt {
|
| | | width: 340px;
|
| | | height: 45px;
|
| | | border: 1px dashed #bdbdbd;
|
| | | display: flex;
|
| | | margin-top: 30px;
|
| | | align-items: center;
|
| | | justify-content: center;
|
| | | color: #828282;
|
| | | font-size: 14px;
|
| | | }
|
| | | .txt-btn {
|
| | | width: 78px;
|
| | | margin-top: 18px;
|
| | | height: 19px;
|
| | | background: #23d7ee;
|
| | | border-radius: 22px;
|
| | | color: #ffffff;
|
| | | font-weight: bold;
|
| | | font-size: 12px;
|
| | | }
|
| | | }
|
| | | }
|
| | |
| | | }
|
| | | }
|
| | |
|
| | | .list-choose-item {
|
| | | cursor: pointer;
|
| | | position: relative;
|
| | | font-size: 14px;
|
| | | display: inline-block;
|
| | | @media screen and(min-width: 1640px) {
|
| | | margin: 30px 20px 20px 20px;
|
| | | }
|
| | | @media screen and(min-width: 1460px) and(max-width: 1640px) {
|
| | | margin: 30px 20px 20px 10px;
|
| | | }
|
| | | @media screen and(max-width: 1460px) {
|
| | | margin: 30px 10px 20px 10px;
|
| | | }
|
| | | min-width: 126px;
|
| | | height: 120px;
|
| | | transition: all 1s;
|
| | | background: #fff;
|
| | | border: 1px solid #e2e2e2;
|
| | | box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07);
|
| | | border-radius: 4px;
|
| | | }
|
| | | .list-choose-item:hover {
|
| | | .mask {
|
| | | display: block;
|
| | | }
|
| | | }
|
| | |
|
| | | .list-choose-item-left {
|
| | | cursor: pointer;
|
| | | position: relative;
|
| | | font-size: 14px;
|
| | |
|
| | | transition: all 1s;
|
| | | border-radius: 4px;
|
| | | p {
|
| | | display: none;
|
| | | text-align: right;
|
| | | width: 100%;
|
| | | position: absolute;
|
| | | right: 10px;
|
| | | top: 5px;
|
| | | }
|
| | | .click-download {
|
| | | position: absolute;
|
| | | left: 80%;
|
| | | top: 5%;
|
| | | }
|
| | | }
|
| | | .list-choose-item-left:hover {
|
| | | .mask {
|
| | | display: flex;
|
| | | align-items: flex-end;
|
| | | flex-wrap: wrap;
|
| | | justify-content: center;
|
| | | top: 0;
|
| | |
|
| | | .bot-btn {
|
| | | flex: 1;
|
| | | }
|
| | | &.flex-center {
|
| | | align-items: center;
|
| | | justify-content: center;
|
| | | }
|
| | | }
|
| | | }
|
| | | .list-choose-item-left-uninstal {
|
| | | color: gray;
|
| | | filter: grayscale(100%);
|
| | | }
|
| | | .list-complete-item.sortable-chosen {
|
| | | background: #4ab7bd;
|
| | | }
|
| | | .list-choose-item.sortable-ghost {
|
| | | background: #30b08f;
|
| | | }
|
| | |
|
| | | .list-choose-header {
|
| | | position: relative;
|
| | | width: 74px;
|
| | | height: 74px;
|
| | | background-image: linear-gradient(-137deg, #7076f2 0%, #3d63e1 100%);
|
| | | box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07);
|
| | | border-radius: 37px;
|
| | | margin: 10px 25px;
|
| | | }
|
| | |
|
| | | .b-top {
|
| | | width: 100%;
|
| | | padding-top: 10px;
|
| | | }
|
| | | .b-bottom {
|
| | | width: 100%;
|
| | | border-bottom: 1px solid rgba(24, 28, 33, 0.5);
|
| | | }
|
| | | .i-set-right {
|
| | | position: absolute;
|
| | | left: 80px;
|
| | | top: -11px;
|
| | | font-size: 24px;
|
| | | }
|
| | | .i-remove-right {
|
| | | position: absolute;
|
| | | right: -1px;
|
| | | top: -11px;
|
| | | font-size: 24px;
|
| | | color: red;
|
| | | }
|
| | | .alg-t {
|
| | | line-height: 31px;
|
| | | font-family: PingFangSC-Medium;
|
| | | font-size: 14px;
|
| | | color: #222222;
|
| | | }
|
| | | .alg-name {
|
| | | line-height: 20px;
|
| | | font-family: PingFangSC-Regular;
|
| | | font-size: 14px;
|
| | | letter-spacing: 0.05em;
|
| | | color: #333;
|
| | | .el-input {
|
| | | position: relative;
|
| | | font-size: 14px;
|
| | | display: inline-block;
|
| | | width: 100%;
|
| | | }
|
| | | }
|
| | |
|
| | | .el-input {
|
| | | position: relative;
|
| | | font-size: 14px;
|
| | | // display: inline-block;
|
| | | // width: 80%;
|
| | | }
|
| | |
|
| | | .drag-info {
|
| | | min-width: 126px;
|
| | | height: 120px;
|
| | | border: 1px dashed #3d68e1;
|
| | | box-shadow: 0 5px 12px 0 rgba(0, 0, 0, 0.07);
|
| | | border-radius: 4px;
|
| | | margin: 30px 10px 20px 10px;
|
| | | }
|
| | |
|
| | | .el-button--cancle {
|
| | |
| | | font-size: 13px;
|
| | | color: #222222;
|
| | | margin-right: 12px;
|
| | | }
|
| | |
|
| | | .task-name-google {
|
| | | position: relative;
|
| | | top: 30px;
|
| | | width: 126px;
|
| | | height: 120px;
|
| | | border: 1px solid #fff;
|
| | | background: #fff;
|
| | | border-radius: 4px;
|
| | | cursor: pointer;
|
| | | .set-task {
|
| | | display: none;
|
| | | cursor: pointer;
|
| | | }
|
| | |
|
| | | .el-switch__core {
|
| | | width: 27px !important;
|
| | | height: 14px;
|
| | | }
|
| | | .el-switch__core:after {
|
| | | width: 10px;
|
| | | height: 10px;
|
| | | }
|
| | | .el-switch.is-checked .el-switch__core::after {
|
| | | left: 100%;
|
| | | margin-left: -11px;
|
| | | }
|
| | | }
|
| | | .task-name-google:hover {
|
| | | .mask {
|
| | | display: block;
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | |
| | | params: data
|
| | | })
|
| | | }
|
| | | export const uploadSDK = (data: any) => {
|
| | | return request({
|
| | | url: "/data/api-v/sdk/upload",
|
| | | method: "post",
|
| | | data
|
| | | })
|
| | | }
|
| | |
|
| | | //安装已上传的算法接口
|
| | | export const installSdk = (file: any) => {
|
| | | return request({
|
| | |
| | | <el-button
|
| | | size="mini"
|
| | | round
|
| | | class="update-btn"
|
| | | @click="upgradeSDKinWin"
|
| | | v-if="productDetail.isUpgrade"
|
| | | >更新</el-button
|
| | |
| | | @click="unloadSDKinWin"
|
| | | >卸载</el-button
|
| | | >
|
| | |
|
| | | <el-button
|
| | | size="mini"
|
| | | round
|
| | | v-if="!isActive && showInstallNotActive"
|
| | | @click="downloadSdkInSide"
|
| | | >安装</el-button
|
| | | >
|
| | | <!-- suffix-icon="iconfont iconchushaixuanxiang" -->
|
| | | <el-input
|
| | | class="activeInput"
|
| | | placeholder="请输入激活码"
|
| | | size="mini"
|
| | | clearable
|
| | | :autofocus="true"
|
| | | v-model="activeCode"
|
| | | v-if="!isActive && !showInstallNotActive"
|
| | | >
|
| | |
| | | @click="actived"
|
| | | >激活</el-button
|
| | | >
|
| | | <span
|
| | | <!-- <span
|
| | | class="icon iconfont"
|
| | | v-if="!isActive && !showInstallNotActive"
|
| | | @click="activeCode = ''"
|
| | | ></span
|
| | | >
|
| | | > -->
|
| | | </div>
|
| | | </div>
|
| | | <div class="back-btn" @click="goback">
|
| | | <span class="icon iconfont"></span>
|
| | | <span class="back-text">返回上页</span>
|
| | | <span class="back-text">返回</span>
|
| | | </div>
|
| | | </div>
|
| | | <div class="text-area">
|
| | |
| | | </div>
|
| | | </div>
|
| | | </div>
|
| | |
|
| | | <el-dialog
|
| | | :visible.sync="showActivateSuccess"
|
| | | title="激活成功!"
|
| | | width="30%"
|
| | | class="active-Dial"
|
| | | :before-close="handleClose"
|
| | | >
|
| | | <div class="dialog-active">
|
| | | <ul class="desc">
|
| | | <li>
|
| | | <label>激活码:</label>
|
| | | <span>{{ activedSdkOrApp.activateCode }}</span>
|
| | | </li>
|
| | | <li>
|
| | | <label>产品名称:</label>
|
| | | <span>{{ activedSdkOrApp.productName }}</span>
|
| | | </li>
|
| | | <li>
|
| | | <label>配置详情:</label>
|
| | | <span>{{ activedSdkOrApp.setting }}</span>
|
| | | </li>
|
| | | <li>
|
| | | <label>服务到期日:</label>
|
| | | <span>{{ activedSdkOrApp.expireTime }}</span>
|
| | | </li>
|
| | | <li>
|
| | | <label>许可证:</label>
|
| | | <span>{{ activedSdkOrApp.licence }}</span>
|
| | | </li>
|
| | | </ul>
|
| | | <div class="text-right">
|
| | | <el-button type="primary" @click="checkMyAlgorith">确定</el-button>
|
| | | <p class="tip">提示:请在“已激活”中查看并安装算法</p>
|
| | | </div>
|
| | | </div>
|
| | | </el-dialog>
|
| | | </div>
|
| | | </template>
|
| | | <script>
|
| | |
| | | actApp,
|
| | | } from "@/api/app";
|
| | | import { getUrlKey } from "@/api/utils";
|
| | | // import FileUploader from "@/components/subComponents/FileUpload/index";
|
| | | export default {
|
| | | components: {
|
| | | // FileUploader,
|
| | | },
|
| | | components: {},
|
| | | computed: {
|
| | | updateNum() {
|
| | | return this.hasNewVersionApp.length + this.hasNewVersionSdk.length;
|
| | |
| | | return {
|
| | | installedList: [],
|
| | | hasNewVersionSdk: [],
|
| | | activeTab: 0,
|
| | | hasNewVersionApp: [],
|
| | | notInstalledList: [],
|
| | | buttonAuthority: sessionStorage.getItem("buttonAuthoritys") || [],
|
| | |
| | | showInputCode: false,
|
| | | needToUpgradeInWin: false,
|
| | | showInstallNotActive: false,
|
| | | activeIndex: 0,
|
| | | menuArr: ["应用中心", "已激活", "离线升级/安装", "更新"],
|
| | | };
|
| | | },
|
| | | props: {
|
| | |
| | | this.actId = this.productDetail.productBaseId;
|
| | | this.isSDKDetail = this.productDetail.productTypeName == "SDK";
|
| | | this.isDefaultApp = this.productDetail.productBaseId.length < 10;
|
| | | |
| | |
|
| | | this.otherProducts = res.data.randoms;
|
| | | });
|
| | | },
|
| | |
| | | },
|
| | | checkMyAlgorith() {
|
| | | this.showActivateSuccess = false;
|
| | | this.activeName = "myAlgorithm";
|
| | | this.goback();
|
| | | this.activeName = "已激活";
|
| | | },
|
| | | onFileUpload(file) {
|
| | | this.patchFile = { ...file };
|
| | |
| | | .then((res) => {
|
| | | if (res && res.success) {
|
| | | sdk.unloadLoading = false;
|
| | | this.$notify({
|
| | | title: "成功",
|
| | | message: "卸载完成",
|
| | | type: "success",
|
| | | });
|
| | | this.$notify.success("卸载完成");
|
| | | _this.getAllSdk();
|
| | | window.parent.postMessage(
|
| | | {
|
| | | msg: "AppUpdate",
|
| | | },
|
| | | "*"
|
| | | );
|
| | | window.parent.postMessage({ msg: "AppUpdate" }, "*");
|
| | | }
|
| | | })
|
| | | .catch((e) => {
|
| | |
| | | .then((rsp) => {
|
| | | this.productDetailVisible = false;
|
| | | this.downloadItem = "";
|
| | | this.$notify({
|
| | | type: "success",
|
| | | message: "算法已安装",
|
| | | });
|
| | | this.$notify.success("算法已安装");
|
| | | this.isUpgrading = false;
|
| | | })
|
| | | .catch((err) => {
|
| | | this.$notify({
|
| | | type: "warning",
|
| | | message: err.data,
|
| | | });
|
| | | this.$notify.warning(err.data);
|
| | | this.downloadItem = "";
|
| | | this.isUpgrading = false;
|
| | | });
|
| | |
| | | .detail-page {
|
| | | width: 100% !important;
|
| | | height: 100%;
|
| | | // background-color: cornsilk;
|
| | | box-sizing: border-box;
|
| | | text-align: left;
|
| | | // min-width: 1106px;
|
| | | .detail-top {
|
| | | padding: 35px 60px;
|
| | | padding-bottom: 20px;
|
| | | // margin-bottom: 40px;
|
| | | border-bottom: 3px solid #f2f2f2;
|
| | | .title-area {
|
| | | display: flex;
|
| | |
| | | position: absolute;
|
| | | right: 0;
|
| | | top: 0;
|
| | | width: 80px;
|
| | | width: 51px;
|
| | | height: 20px;
|
| | | line-height: 20px;
|
| | | display: flex;
|
| | |
| | | align-items: center;
|
| | | cursor: pointer;
|
| | | .icon {
|
| | | margin-right: 2px;
|
| | | margin-right: 3px;
|
| | | font-size: 18px;
|
| | | }
|
| | | .back-text {
|
| | | font-size: 14px;
|
| | | letter-spacing: 0.1px;
|
| | | letter-spacing: 0.5px;
|
| | | }
|
| | | }
|
| | | .icon-img {
|
| | |
| | | .right-info-2 {
|
| | | display: flex;
|
| | | align-items: center;
|
| | | .activeInput {
|
| | | .el-input__suffix {
|
| | | display: flex;
|
| | | align-items: center;
|
| | | .el-input__suffix-inner {
|
| | | border-color: none;
|
| | | .el-icon-circle-close:before {
|
| | | content: "\e79d" !important;
|
| | | font-size: 14px;
|
| | | }
|
| | | }
|
| | | }
|
| | | }
|
| | | .iconfont {
|
| | | margin-left: 10px;
|
| | | font-size: 15px;
|
| | |
| | | }
|
| | | .el-input {
|
| | | margin-right: 12px;
|
| | | width: 220px;
|
| | | width: 224px;
|
| | | font-size: 12px;
|
| | | .el-input__inner {
|
| | | border: 1px solid #bdbdbd;
|
| | | border-radius: 20px;
|
| | |
| | | background: #f2f2f7;
|
| | | border: 1px solid #f2f2f7;
|
| | | }
|
| | | .update-btn {
|
| | | border-color: #23d7ee;
|
| | | background-color: rgba(29, 212, 236, 0.1);
|
| | | }
|
| | | .act-btn {
|
| | | background: #23d7ee;
|
| | | border: 1px solid #23d7ee;
|
| | | color: #f2f2f2;
|
| | | }
|
| | | .act-btn:hover {
|
| | | background: #089fb3 !important;
|
| | | border-color: #089fb3 !important;
|
| | | }
|
| | | .el-button:hover {
|
| | | border-color: #23d7ee;
|
| | | background-color: rgba(29, 212, 236, 0.1);
|
| | | }
|
| | | // .act-btn:hover {
|
| | | // background: #089fb3 !important;
|
| | | // border-color: #089fb3 !important;
|
| | | // }
|
| | | // .el-button:hover {
|
| | | // border-color: #23d7ee;
|
| | | // background-color: rgba(29, 212, 236, 0.1);
|
| | | // }
|
| | | .el-button + .el-button {
|
| | | margin-left: 12px;
|
| | | }
|
| | |
| | | .text-line {
|
| | | line-height: 17px;
|
| | | height: 25px;
|
| | |
|
| | | // margin-top: 6px;
|
| | | .icon {
|
| | | font-size: 14px;
|
| | | margin-right: 2px;
|
| | |
| | | font-weight: bold;
|
| | | letter-spacing: 0.5px;
|
| | | line-height: 26px;
|
| | | margin-bottom: 20px;
|
| | | margin-bottom: 20px;
|
| | | }
|
| | | }
|
| | | .rec-items {
|
| | |
| | | float: left;
|
| | | display: flex;
|
| | | margin: 0 15px;
|
| | | margin-bottom: 30px;
|
| | | margin-bottom: 30px;
|
| | | padding: 2px 0;
|
| | | height: 62px;
|
| | | box-sizing: border-box;
|
| | |
| | | }
|
| | | }
|
| | | .right-btn {
|
| | | // width: 20px;
|
| | | padding: 5px 0;
|
| | | .el-button {
|
| | | padding: 3px 12px;
|
| | |
| | | border-color: #1dd4ec !important;
|
| | | border-radius: 22px;
|
| | | }
|
| | | // .el-button--primary:focus {
|
| | | // background: #0cabc0 !important;
|
| | | // border-color: #0cabc0 !important;
|
| | | // }
|
| | | .el-button--primary:hover {
|
| | | background: #089fb3 !important;
|
| | | border-color: #089fb3 !important;
|
| | |
| | | >
|
| | | <div class="tab-content">
|
| | | <div class="action-bar">
|
| | | <file-uploader
|
| | | <FileUploader
|
| | | single
|
| | | tip
|
| | | tipWords="上传算法"
|
| | |
| | | <div class="list-choose-item-left">
|
| | | <div class="list-complete-item-handle">
|
| | | <div class="alg-icon svg-wrap">
|
| | | |
| | | <div
|
| | | class="mask"
|
| | | v-if="!item.isDefault || item.isUpgrade"
|
| | |
| | | this.showInstallNotActive = false;
|
| | | this.isActive = true;
|
| | | } else if (type == "activeNotInstall") {
|
| | | debugger
|
| | | debugger;
|
| | | this.showInputCode = false;
|
| | | this.isActive = false;
|
| | | this.showInstallNotActive = true;
|
| | |
| | | this.isInstall = false;
|
| | | this.$message({
|
| | | type: "success",
|
| | | message: '安装成功,将跳转至“已激活”中查看',
|
| | | message: "安装成功,将跳转至“已激活”中查看",
|
| | | });
|
| | | setTimeout(() => {
|
| | | this.getAllSdk();
|
| | |
| | | installContent: res.data.sdks[0].installContent,
|
| | | };
|
| | | }
|
| | | }else{
|
| | | } else {
|
| | | this.$message({
|
| | | type: "error",
|
| | | message: res.msg,
|
| | | });
|
| | | });
|
| | | }
|
| | | })
|
| | | .catch((e) => {
|
| | |
| | | this.isUpgrading = !this.isUpgrading;
|
| | | let _this = this;
|
| | | if (this.productDetail.productTypeName == "应用") {
|
| | | debugger
|
| | | debugger;
|
| | | installApp({ path: this.productDetail.productBaseId })
|
| | | .then((res) => {
|
| | | if (res && res.success) {
|
| | |
| | | // 开启自动刷新
|
| | | this.appUpgreading = true;
|
| | | } else {
|
| | | debugger
|
| | | debugger;
|
| | | downloadSdk({ path: this.productDetail.productBaseId })
|
| | | .then((res) => {
|
| | | this.needToUpgradeInWin = false;
|
| | |
| | | <div class="ask"> |
| | | 如果你具有SmartAI提供的产品密钥,请在此处输入激活SmartAI。 |
| | | </div> |
| | | |
| | | <div class="validate"> |
| | | <form id="myForm"> |
| | | <el-input |
| | |
| | | this.dialogVisible = true; |
| | | }, |
| | | uploadKey(params) { |
| | | debugger |
| | | let param = new FormData(); |
| | | param.append("code", params.file); |
| | | uploadKey(param).then( |
| | | (res) => { |
| | | this.$message.success("导入成功"); |
| | | this.secrectKey = res.data; |
| | | if (res.code == 200) { |
| | | this.$message.success("导入成功"); |
| | | this.secrectKey = res.data; |
| | | } else { |
| | | this.$message.error(res.msg); |
| | | } |
| | | }, |
| | | (err) => { |
| | | this.$message.error("导入失败"); |
| | | this.$message.error(err.msg); |
| | | } |
| | | ); |
| | | }, |
| | |
| | | transition: all 0.5s;
|
| | | position: absolute;
|
| | | bottom: -40px;
|
| | |
|
| | | left: calc(50% - 145px);
|
| | | .el-upload-dragger {
|
| | | width: 290px;
|