From 44a3abe105e9b9b4d1a7173772fc9d18c9b59529 Mon Sep 17 00:00:00 2001
From: heyujie <516346543@qq.com>
Date: 星期六, 18 九月 2021 16:24:02 +0800
Subject: [PATCH] 应用中心ui改动

---
 src/pages/ai_c/index/App.vue                         |   15 
 src/pages/ai/FileUpload/uploader.vue                 |  168 ++
 src/pages/ai/FileUpload/common/mixins.js             |   14 
 src/pages/ai/FileUpload/file.vue                     |  471 ++++++
 src/pages/ai/FileUpload/unsupport.vue                |   30 
 public/apps.json                                     |    2 
 src/pages/ai/index/App.vue                           |  856 ++++++------
 src/pages/ai/index/detail.vue                        |  147 +
 src/pages/ai/FileUpload/btn.vue                      |   66 
 src/pages/ai/FileUpload/drop.vue                     |   64 
 src/components/subComponents/FileUpload/index.vue    |  173 +
 src/pages/ai/FileUpload/common/file-events.js        |    3 
 public/images/appCenter/Group-113.png                |    0 
 public/images/appCenter/app-banner.png               |    0 
 src/components/subComponents/FileUpload/uploader.vue |   12 
 src/pages/ai/FileUpload/common/uploader-simple.js    | 1612 +++++++++++++++++++++++
 src/pages/desktop/index/components/Desktop.vue       |   12 
 src/components/subComponents/FileUpload/file.vue     |    2 
 src/pages/ai/FileUpload/list.vue                     |   43 
 src/components/subComponents/FileUpload/btn.vue      |    4 
 public/images/appCenter/Group-112.png                |    0 
 src/pages/ai/FileUpload/index.vue                    |  302 ++++
 src/pages/ai/FileUpload/common/utils.js              |   28 
 src/pages/ai/FileUpload/files.vue                    |   42 
 src/pages/settings/views/generalSettings.vue         |    1 
 src/pages/ai/index/api.ts                            |    8 
 26 files changed, 3,523 insertions(+), 552 deletions(-)

diff --git a/public/apps.json b/public/apps.json
index 5736af4..cd5f077 100644
--- a/public/apps.json
+++ b/public/apps.json
@@ -54,7 +54,7 @@
       "type": "2",
       "url": "/view/ai/",
       "title": "搴旂敤涓績",
-      "width": 1243,
+      "width": 1024,
       "height": 742,
       "iconBlob": "",
       "icon": "../../images/app-mid/algorithm-store.png",
diff --git a/public/images/appCenter/Group-112.png b/public/images/appCenter/Group-112.png
new file mode 100644
index 0000000..25166fd
--- /dev/null
+++ b/public/images/appCenter/Group-112.png
Binary files differ
diff --git a/public/images/appCenter/Group-113.png b/public/images/appCenter/Group-113.png
new file mode 100644
index 0000000..f74ee8d
--- /dev/null
+++ b/public/images/appCenter/Group-113.png
Binary files differ
diff --git a/public/images/appCenter/app-banner.png b/public/images/appCenter/app-banner.png
new file mode 100644
index 0000000..008f99a
--- /dev/null
+++ b/public/images/appCenter/app-banner.png
Binary files differ
diff --git a/src/components/subComponents/FileUpload/btn.vue b/src/components/subComponents/FileUpload/btn.vue
index 9eccf99..0bffa02 100644
--- a/src/components/subComponents/FileUpload/btn.vue
+++ b/src/components/subComponents/FileUpload/btn.vue
@@ -34,8 +34,6 @@
  
   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';
@@ -63,6 +61,6 @@
   outline: none;
 }
 .uploader-btn:hover {
-  background-color: rgba(0, 0, 0, 0.08);
+  /* background-color: rgba(0, 0, 0, 0.08); */
 }
 </style>
diff --git a/src/components/subComponents/FileUpload/file.vue b/src/components/subComponents/FileUpload/file.vue
index 333a547..1d8c5c7 100644
--- a/src/components/subComponents/FileUpload/file.vue
+++ b/src/components/subComponents/FileUpload/file.vue
@@ -35,7 +35,7 @@
         <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>&nbsp;&nbsp;{{formatedTimeRemaining}}</i>
diff --git a/src/components/subComponents/FileUpload/index.vue b/src/components/subComponents/FileUpload/index.vue
index 796d99f..2068da8 100644
--- a/src/components/subComponents/FileUpload/index.vue
+++ b/src/components/subComponents/FileUpload/index.vue
@@ -9,12 +9,46 @@
       @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"
+          >&#xe70b;</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">&#xe712;</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">&#xe712;</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 />
@@ -32,7 +66,7 @@
       @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 />
@@ -41,16 +75,18 @@
 </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: {
@@ -58,48 +94,47 @@
     },
     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() {
@@ -110,32 +145,37 @@
         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 = "鍑嗗涓婁紶,姝e湪妫�鏌ユ枃浠�"
+      this.statusText.paused = "鍑嗗涓婁紶,姝e湪妫�鏌ユ枃浠�";
       file.pause();
       loadNext();
-      fileReader.onload = (e => {
+      fileReader.onload = (e) => {
         spark.append(e.target.result);
         if (currentChunk < chunks) {
           currentChunk++;
@@ -145,16 +185,16 @@
           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));
       }
     },
@@ -163,32 +203,33 @@
       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">
@@ -237,6 +278,26 @@
         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>>
diff --git a/src/components/subComponents/FileUpload/uploader.vue b/src/components/subComponents/FileUpload/uploader.vue
index 6ada9f3..14735e4 100644
--- a/src/components/subComponents/FileUpload/uploader.vue
+++ b/src/components/subComponents/FileUpload/uploader.vue
@@ -3,11 +3,12 @@
     <!-- <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>
@@ -134,9 +135,9 @@
     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)
@@ -163,4 +164,5 @@
     cursor: pointer;
   }
 }
+
 </style>
diff --git a/src/pages/ai/FileUpload/btn.vue b/src/pages/ai/FileUpload/btn.vue
new file mode 100644
index 0000000..0bffa02
--- /dev/null
+++ b/src/pages/ai/FileUpload/btn.vue
@@ -0,0 +1,66 @@
+<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>
diff --git a/src/pages/ai/FileUpload/common/file-events.js b/src/pages/ai/FileUpload/common/file-events.js
new file mode 100644
index 0000000..2aba807
--- /dev/null
+++ b/src/pages/ai/FileUpload/common/file-events.js
@@ -0,0 +1,3 @@
+const events = ['fileProgress', 'fileSuccess', 'fileComplete', 'fileError']
+
+export default events
diff --git a/src/pages/ai/FileUpload/common/mixins.js b/src/pages/ai/FileUpload/common/mixins.js
new file mode 100644
index 0000000..efab3b0
--- /dev/null
+++ b/src/pages/ai/FileUpload/common/mixins.js
@@ -0,0 +1,14 @@
+export const uploaderMixin = {
+  inject: ['uploader']
+}
+
+export const supportMixin = {
+  data () {
+    return {
+      support: true
+    }
+  },
+  mounted () {
+    this.support = this.uploader.uploader.support
+  }
+}
diff --git a/src/pages/ai/FileUpload/common/uploader-simple.js b/src/pages/ai/FileUpload/common/uploader-simple.js
new file mode 100644
index 0000000..b0a0d16
--- /dev/null
+++ b/src/pages/ai/FileUpload/common/uploader-simple.js
@@ -0,0 +1,1612 @@
+/*!
+ * 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 = {}
+        }
+    
+        // 濡傛灉鍙湁涓�涓弬鏁帮紝閭d箞鏂版垚鍛樻坊鍔犱簬 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)
+    });
\ No newline at end of file
diff --git a/src/pages/ai/FileUpload/common/utils.js b/src/pages/ai/FileUpload/common/utils.js
new file mode 100644
index 0000000..92c775a
--- /dev/null
+++ b/src/pages/ai/FileUpload/common/utils.js
@@ -0,0 +1,28 @@
+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()}`)
+}
diff --git a/src/pages/ai/FileUpload/drop.vue b/src/pages/ai/FileUpload/drop.vue
new file mode 100644
index 0000000..9c88666
--- /dev/null
+++ b/src/pages/ai/FileUpload/drop.vue
@@ -0,0 +1,64 @@
+<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>
diff --git a/src/pages/ai/FileUpload/file.vue b/src/pages/ai/FileUpload/file.vue
new file mode 100644
index 0000000..fca3993
--- /dev/null
+++ b/src/pages/ai/FileUpload/file.vue
@@ -0,0 +1,471 @@
+<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>&nbsp;&nbsp;{{ 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>
diff --git a/src/pages/ai/FileUpload/files.vue b/src/pages/ai/FileUpload/files.vue
new file mode 100644
index 0000000..1380ba9
--- /dev/null
+++ b/src/pages/ai/FileUpload/files.vue
@@ -0,0 +1,42 @@
+<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>
diff --git a/src/pages/ai/FileUpload/index.vue b/src/pages/ai/FileUpload/index.vue
new file mode 100644
index 0000000..2a8ccf2
--- /dev/null
+++ b/src/pages/ai/FileUpload/index.vue
@@ -0,0 +1,302 @@
+<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"
+          >&#xe70b;</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">&#xe712;</span>
+            </div>
+          </el-tooltip>
+        </uploader-btn>
+        <!-- <div class="open-file-btn">
+          <span class="icon iconfont">&#xe712;</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 = "鍑嗗涓婁紶,姝e湪妫�鏌ユ枃浠�";
+      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瀹炰緥鐨刼pts涓�
+      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>>
diff --git a/src/pages/ai/FileUpload/list.vue b/src/pages/ai/FileUpload/list.vue
new file mode 100644
index 0000000..9951595
--- /dev/null
+++ b/src/pages/ai/FileUpload/list.vue
@@ -0,0 +1,43 @@
+<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>
diff --git a/src/pages/ai/FileUpload/unsupport.vue b/src/pages/ai/FileUpload/unsupport.vue
new file mode 100644
index 0000000..59626ee
--- /dev/null
+++ b/src/pages/ai/FileUpload/unsupport.vue
@@ -0,0 +1,30 @@
+<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>
diff --git a/src/pages/ai/FileUpload/uploader.vue b/src/pages/ai/FileUpload/uploader.vue
new file mode 100644
index 0000000..14735e4
--- /dev/null
+++ b/src/pages/ai/FileUpload/uploader.vue
@@ -0,0 +1,168 @@
+<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>
diff --git a/src/pages/ai/index/App.vue b/src/pages/ai/index/App.vue
index 324e7a1..a4ea71c 100644
--- a/src/pages/ai/index/App.vue
+++ b/src/pages/ai/index/App.vue
@@ -19,15 +19,11 @@
                   @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">&#xe703;</span>
                 <el-input
                   placeholder="鎼滅储"
                   v-model="input3"
@@ -37,53 +33,71 @@
                   <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">&#xe713;</span>
+                      <span>閾佽矾鍦烘櫙</span>
+                    </el-option>
+                    <el-option label="瀹夊叏鍦烘櫙" value="2">
+                      <span class="icon iconfont">&#xe702;</span>
+                      <span>瀹夊叏鍦烘櫙</span>
+                    </el-option>
+                    <el-option label="閫氱敤鍦烘櫙" value="3">
+                      <span class="icon iconfont">&#xe70d;</span>
+                      <span>閫氱敤鍦烘櫙</span>
+                    </el-option>
+                    <el-option label="鏍″洯鍥尯" value="4">
+                      <span class="icon iconfont">&#xe70e;</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">&#xe6b0;</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"
+                      >&#xe719;</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">&#xe71a;</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">
@@ -119,7 +133,10 @@
                   >
                 </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"
@@ -127,6 +144,9 @@
                   @click="checkDetail(item)"
                 >
                   <div class="icon-img">
+                    <span class="icon iconfont" v-if="item.isUpgrade"
+                      >&#xe719;</span
+                    >
                     <img
                       v-if="item.iconBlob"
                       :src="
@@ -146,6 +166,7 @@
                     <el-button
                       size="small"
                       type="primary"
+                      class="other-btn"
                       round
                       @click="checkDetail(item)"
                       v-if="activeName == '搴旂敤涓績'"
@@ -154,19 +175,23 @@
                     <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 == '宸叉縺娲�' &&
@@ -179,6 +204,7 @@
                     <el-button
                       size="small"
                       type="primary"
+                      class="other-btn"
                       round
                       v-if="
                         activeName == '宸叉縺娲�' &&
@@ -188,6 +214,58 @@
                       "
                       >鍗囩骇</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
+                      "
+                      >&#xe70c;</span
+                    >
+                    <span
+                      class="icon iconfont rocket-icon"
+                      v-if="
+                        activeName == '鏇存柊' &&
+                        item.isUpgrade &&
+                        item.upgradeLoading &&
+                        !rocketIf
+                      "
+                      >&#xe717;</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>
 
@@ -195,6 +273,7 @@
                   class="front-page-item item-dimmed"
                   v-for="(item, index) in tempDarkList"
                   :key="index"
+                  @click="checkDetail(item, 'activeNotInstall')"
                 >
                   <div class="icon-img">
                     <img
@@ -216,31 +295,55 @@
                     <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"
+                        >&#xe70a;</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">&#xe754;</span>
                     <span class="txt">涓婁紶瀹夎杞欢</span>
                   </div>
-                  <div class="right">
-                    <span class="icon iconfont">&#xe711;</span>
-                    <span class="icon iconfont">&#xe712;</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>
 
@@ -253,6 +356,53 @@
         </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>
@@ -262,6 +412,7 @@
   installSdk,
   getInstallInfo,
   removeSdk,
+  uploadSDK,
 } from "./api";
 import {
   getApps,
@@ -274,7 +425,7 @@
   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",
@@ -296,22 +447,17 @@
       }
       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") || [],
@@ -359,6 +505,7 @@
       backStack: [],
       toUpdateArr1: [],
       forwardStack: [],
+      rocketIf: false,
       backDisable: true,
       forwardDisable: true,
       showInputCode: false,
@@ -407,7 +554,7 @@
     },
     batchUpdateSDK() {
       this.hasNewVersionSdk.forEach((sdk) => {
-        this.donwload(sdk, 0);
+        this.donwloadSDK(sdk);
       });
     },
     batchUpdateApp() {
@@ -458,6 +605,7 @@
           this.activeTab == "sdk"
             ? this.hasNewVersionSdk
             : this.hasNewVersionApp;
+
         this.tempDarkList = [];
       }
     },
@@ -474,12 +622,6 @@
       } 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]);
@@ -553,66 +695,44 @@
         .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;
     },
@@ -630,17 +750,17 @@
             { 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);
@@ -664,12 +784,7 @@
                 app.unloadLoading = false;
                 _this.getAllApps();
                 window.parent.postMessage({ msg: "AppUpdate" }, "*");
-
-                _this.$notify({
-                  title: "鎴愬姛",
-                  message: "鍗歌浇搴旂敤鎴愬姛",
-                  type: "success",
-                });
+                _this.$notify.success("鍗歌浇搴旂敤鎴愬姛");
               }
             })
             .catch((e) => {
@@ -704,6 +819,21 @@
       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;
         }
       });
@@ -820,9 +950,12 @@
             { unloadLoading: false, upgradeLoading: false },
             item
           );
-          if (obj.progressMsg !== "" && obj.progressMsg !== "宸插畨瑁�") {
+          if (
+            obj.progressMsg !== "" &&
+            obj.progressMsg !== "宸插畨瑁�" &&
+            obj.progressMsg !== "100%"
+          ) {
             obj.upgradeLoading = true;
-
             this.sdkUpgreading = true;
           }
 
@@ -875,64 +1008,17 @@
         })
         .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" }, "*");
@@ -944,9 +1030,6 @@
         });
       // 寮�鍚嚜鍔ㄥ埛鏂�
       this.sdkUpgreading = true;
-    },
-    inputBlur(item) {
-      this.$set(item, "isEdit", false);
     },
     autoRefreshAppAndSdkState() {
       // 鍏抽棴鍚庨��鍑�
@@ -973,31 +1056,6 @@
   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 {
@@ -1067,12 +1125,14 @@
             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 {
@@ -1084,12 +1144,20 @@
             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;
@@ -1099,17 +1167,19 @@
               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,
@@ -1122,7 +1192,7 @@
               border-left: 0;
               border: none;
               border-radius: 20px;
-              width: 64px;
+              width: 52px;
               background: linear-gradient(
                 180deg,
                 #ecfcfe 0%,
@@ -1138,11 +1208,38 @@
                   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 {
@@ -1163,8 +1260,8 @@
           position: absolute;
           z-index: 1;
           right: 0;
-          top: 70px;
-          height: 200px;
+          top: 41px;
+          height: 229px;
           img {
             height: 100%;
           }
@@ -1185,16 +1282,26 @@
         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;
@@ -1219,11 +1326,17 @@
             }
           }
           .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 {
@@ -1236,7 +1349,7 @@
         }
       }
       .main-content {
-        padding: 35px 60px;
+        padding: 35px 82px;
         z-index: 99;
         .main-title {
           line-height: 25px;
@@ -1250,7 +1363,7 @@
           .group-left {
             display: flex;
             .tab {
-              font-size: 15px;
+              font-size: 14px;
               margin-right: 25px;
               line-height: 28px;
               cursor: pointer;
@@ -1279,30 +1392,43 @@
           }
         }
         .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;
@@ -1320,26 +1446,66 @@
               }
             }
             .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;
@@ -1353,29 +1519,53 @@
           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;
           }
         }
       }
@@ -1415,148 +1605,11 @@
       }
     }
 
-    .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 {
@@ -1567,39 +1620,6 @@
       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;
-      }
     }
   }
 }
diff --git a/src/pages/ai/index/api.ts b/src/pages/ai/index/api.ts
index 7232d34..88b586b 100644
--- a/src/pages/ai/index/api.ts
+++ b/src/pages/ai/index/api.ts
@@ -142,6 +142,14 @@
     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({
diff --git a/src/pages/ai/index/detail.vue b/src/pages/ai/index/detail.vue
index aaa1c11..c8fa510 100644
--- a/src/pages/ai/index/detail.vue
+++ b/src/pages/ai/index/detail.vue
@@ -16,6 +16,7 @@
             <el-button
               size="mini"
               round
+              class="update-btn"
               @click="upgradeSDKinWin"
               v-if="productDetail.isUpgrade"
               >鏇存柊</el-button
@@ -34,10 +35,20 @@
               @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"
             >
@@ -50,17 +61,17 @@
               @click="actived"
               >婵�娲�</el-button
             >
-            <span
+            <!-- <span
               class="icon iconfont"
               v-if="!isActive && !showInstallNotActive"
               @click="activeCode = ''"
               >&#xe6cb;</span
-            >
+            > -->
           </div>
         </div>
         <div class="back-btn" @click="goback">
           <span class="icon iconfont">&#xe680;</span>
-          <span class="back-text">杩斿洖涓婇〉</span>
+          <span class="back-text">杩斿洖</span>
         </div>
       </div>
       <div class="text-area">
@@ -161,6 +172,43 @@
         </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>
@@ -182,11 +230,8 @@
   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;
@@ -207,7 +252,6 @@
     return {
       installedList: [],
       hasNewVersionSdk: [],
-      activeTab: 0,
       hasNewVersionApp: [],
       notInstalledList: [],
       buttonAuthority: sessionStorage.getItem("buttonAuthoritys") || [],
@@ -258,8 +302,6 @@
       showInputCode: false,
       needToUpgradeInWin: false,
       showInstallNotActive: false,
-      activeIndex: 0,
-      menuArr: ["搴旂敤涓績", "宸叉縺娲�", "绂荤嚎鍗囩骇/瀹夎", "鏇存柊"],
     };
   },
   props: {
@@ -334,7 +376,7 @@
         this.actId = this.productDetail.productBaseId;
         this.isSDKDetail = this.productDetail.productTypeName == "SDK";
         this.isDefaultApp = this.productDetail.productBaseId.length < 10;
-    
+
         this.otherProducts = res.data.randoms;
       });
     },
@@ -613,7 +655,8 @@
     },
     checkMyAlgorith() {
       this.showActivateSuccess = false;
-      this.activeName = "myAlgorithm";
+      this.goback();
+      this.activeName = "宸叉縺娲�";
     },
     onFileUpload(file) {
       this.patchFile = { ...file };
@@ -720,18 +763,9 @@
             .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) => {
@@ -781,17 +815,11 @@
         .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;
         });
@@ -849,14 +877,12 @@
 .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;
@@ -866,7 +892,7 @@
         position: absolute;
         right: 0;
         top: 0;
-        width: 80px;
+        width: 51px;
         height: 20px;
         line-height: 20px;
         display: flex;
@@ -874,12 +900,12 @@
         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 {
@@ -915,6 +941,19 @@
         .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;
@@ -922,7 +961,8 @@
           }
           .el-input {
             margin-right: 12px;
-            width: 220px;
+            width: 224px;
+            font-size: 12px;
             .el-input__inner {
               border: 1px solid #bdbdbd;
               border-radius: 20px;
@@ -938,19 +978,23 @@
             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;
           }
@@ -961,8 +1005,6 @@
       .text-line {
         line-height: 17px;
         height: 25px;
-
-        // margin-top: 6px;
         .icon {
           font-size: 14px;
           margin-right: 2px;
@@ -1046,7 +1088,7 @@
       font-weight: bold;
       letter-spacing: 0.5px;
       line-height: 26px;
-          margin-bottom: 20px;
+      margin-bottom: 20px;
     }
   }
   .rec-items {
@@ -1054,7 +1096,7 @@
       float: left;
       display: flex;
       margin: 0 15px;
-         margin-bottom: 30px;
+      margin-bottom: 30px;
       padding: 2px 0;
       height: 62px;
       box-sizing: border-box;
@@ -1086,7 +1128,6 @@
         }
       }
       .right-btn {
-        // width: 20px;
         padding: 5px 0;
         .el-button {
           padding: 3px 12px;
@@ -1094,10 +1135,6 @@
           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;
diff --git a/src/pages/ai_c/index/App.vue b/src/pages/ai_c/index/App.vue
index 2a13830..fa975eb 100644
--- a/src/pages/ai_c/index/App.vue
+++ b/src/pages/ai_c/index/App.vue
@@ -336,7 +336,7 @@
               >
                 <div class="tab-content">
                   <div class="action-bar">
-                    <file-uploader
+                    <FileUploader
                       single
                       tip
                       tipWords="涓婁紶绠楁硶"
@@ -440,7 +440,6 @@
                       <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"
@@ -1191,7 +1190,7 @@
         this.showInstallNotActive = false;
         this.isActive = true;
       } else if (type == "activeNotInstall") {
-        debugger
+        debugger;
         this.showInputCode = false;
         this.isActive = false;
         this.showInstallNotActive = true;
@@ -1296,7 +1295,7 @@
             this.isInstall = false;
             this.$message({
               type: "success",
-              message: '瀹夎鎴愬姛,灏嗚烦杞嚦鈥滃凡婵�娲烩�濅腑鏌ョ湅',
+              message: "瀹夎鎴愬姛,灏嗚烦杞嚦鈥滃凡婵�娲烩�濅腑鏌ョ湅",
             });
             setTimeout(() => {
               this.getAllSdk();
@@ -1553,11 +1552,11 @@
                 installContent: res.data.sdks[0].installContent,
               };
             }
-          }else{
+          } else {
             this.$message({
               type: "error",
               message: res.msg,
-          });
+            });
           }
         })
         .catch((e) => {
@@ -1657,7 +1656,7 @@
       this.isUpgrading = !this.isUpgrading;
       let _this = this;
       if (this.productDetail.productTypeName == "搴旂敤") {
-        debugger
+        debugger;
         installApp({ path: this.productDetail.productBaseId })
           .then((res) => {
             if (res && res.success) {
@@ -1683,7 +1682,7 @@
         // 寮�鍚嚜鍔ㄥ埛鏂�
         this.appUpgreading = true;
       } else {
-        debugger
+        debugger;
         downloadSdk({ path: this.productDetail.productBaseId })
           .then((res) => {
             this.needToUpgradeInWin = false;
diff --git a/src/pages/desktop/index/components/Desktop.vue b/src/pages/desktop/index/components/Desktop.vue
index c14e20e..7e4e343 100644
--- a/src/pages/desktop/index/components/Desktop.vue
+++ b/src/pages/desktop/index/components/Desktop.vue
@@ -46,7 +46,6 @@
       <div class="ask">
         濡傛灉浣犲叿鏈塖martAI鎻愪緵鐨勪骇鍝佸瘑閽ワ紝璇峰湪姝ゅ杈撳叆婵�娲籗martAI銆�
       </div>
-
       <div class="validate">
         <form id="myForm">
           <el-input
@@ -138,15 +137,20 @@
       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);
         }
       );
     },
diff --git a/src/pages/settings/views/generalSettings.vue b/src/pages/settings/views/generalSettings.vue
index 62220d2..ba74441 100644
--- a/src/pages/settings/views/generalSettings.vue
+++ b/src/pages/settings/views/generalSettings.vue
@@ -632,7 +632,6 @@
         transition: all 0.5s;
         position: absolute;
         bottom: -40px;
-
         left: calc(50% - 145px);
         .el-upload-dragger {
           width: 290px;

--
Gitblit v1.8.0