瀏覽代碼

feat: file fast transfer

Casper Dai 2 年之前
父節點
當前提交
294fb74c62
共有 2 個文件被更改,包括 100 次插入31 次删除
  1. 11 5
      src/layout/components/Navbar/UploadDashboard/FileProgress.vue
  2. 89 26
      src/utils/upload.js

+ 11 - 5
src/layout/components/Navbar/UploadDashboard/FileProgress.vue

@@ -81,14 +81,14 @@ export default {
         type: AssetTypeInfo[options.type],
         name,
         valid,
-        percentage,
+        percentage: Math.min(percentage, 100),
         url: url ? `url("${url}")` : 'none',
         status: state === State.SUCCESS
           ? 'is-success'
-          : valid
-            ? 'is-processing'
-            : state === State.UPLOADING
-              ? 'is-exception'
+          : state === State.ABORT
+            ? 'is-exception'
+            : valid
+              ? 'is-processing'
               : 'is-warning'
       }
     },
@@ -150,6 +150,12 @@ export default {
       background-color: $warning;
     }
   }
+
+  .is-exception {
+    ::v-deep el-progress-bar__inner {
+      background-color: $error;
+    }
+  }
 }
 
 @keyframes move {

+ 89 - 26
src/utils/upload.js

@@ -19,6 +19,7 @@ export const State = {
   CHECK: 8,
   READY: 10,
   UPLOADING: 50,
+  COPY: 80,
   MERGING: 90,
   SUCCESS: 100,
   ABORT: 999
@@ -57,7 +58,7 @@ export function appendFile (file, options) {
     file,
     totalSize: size,
     uploaded: 0,
-    valid: 1,
+    valid: true,
     state: State.INIT,
     url: fileType === AssetType.IMAGE ? URL.createObjectURL(file) : null,
     options: {
@@ -159,6 +160,7 @@ export function removeFile (id) {
         console.log(`${obj.name}已取消`)
         files.splice(index, 1)
         obj.source?.cancel('abort')
+        obj.source = null
         setState(obj, State.ABORT)
         emitChange()
       })
@@ -180,6 +182,9 @@ export function retry (id) {
       case State.UPLOADING:
         startUpload(obj)
         break
+      case State.COPY:
+        startCopy(obj)
+        break
       case State.MERGING:
         startMerge(obj)
         break
@@ -259,6 +264,7 @@ function setInvalid (obj, message, stack) {
     message
   })
   obj.valid = false
+  obj.source = null
   emitChange()
 }
 
@@ -403,6 +409,7 @@ function calculateHashByWorker (obj, options = {}) {
     }
     worker.onmessageerror = worker.onerror = e => {
       obj.source?.cancel(e)
+      obj.source = null
     }
     worker.postMessage({ chunks })
   })
@@ -478,13 +485,15 @@ function createChunks (blob, chunkSize = CHUNK_SIZE) {
 
 function isExists (obj) {
   const { id, hash } = obj
-  const file = files.find(file => file.id !== id && file.hash === hash)
+  const { org } = obj.options
+  const file = files.find(file => file.id !== id && file.state !== State.ABORT && file.hash === hash && file.options.org === org)
   if (file) {
     return {
       result: true,
       type: 'warning',
       title: '文件上传',
-      message: obj.name === file.name ? `${obj.name}已在上传列表中` : `${obj.name}在上传列表中存在同内容文件${file.name}`
+      message: obj.name === file.name ? `${obj.name}已在上传列表中` : `${obj.name}在上传列表中存在同内容文件${file.name}`,
+      del: true
     }
   }
   console.log(`${obj.name}服务器校验`)
@@ -492,7 +501,10 @@ function isExists (obj) {
   return request({
     url: '/minio-data/integral/check',
     method: 'POST',
-    data: { identifier: hash },
+    data: addTenant({
+      identifier: hash,
+      org: obj.options.org
+    }),
     cancelToken: obj.source.token,
     custom: true,
     background: true
@@ -500,12 +512,11 @@ function isExists (obj) {
     obj.source = null
   }).then(
     ({ data }) => {
+      obj.keyName = data.keyName
+      obj.chunks = []
       return {
-        result: true,
-        type: 'warning',
-        title: '文件上传',
-        message: `${obj.name}已上传过,文件名为${data.originalName}`,
-        duration: 0
+        result: false,
+        chunks: []
       }
     },
     ({ errCode, data }) => {
@@ -515,6 +526,16 @@ function isExists (obj) {
           chunks: data
         }
       }
+      if (errCode === '667') {
+        return {
+          result: true,
+          type: 'warning',
+          title: '文件上传',
+          message: `${obj.name}已上传过,位于【${data.directoryName || '资源目录'}】,名称【${data.name}】`,
+          duration: 0,
+          del: true
+        }
+      }
       return Promise.reject()
     }
   )
@@ -541,7 +562,9 @@ async function startCheck (obj) {
     }
     return
   }
-  if (obj.chunks.length) {
+  if (obj.keyName) {
+    startCopy(obj)
+  } else if (obj.chunks.length) {
     setState(obj, State.READY)
     startUpload(obj)
   } else {
@@ -576,12 +599,16 @@ function idleTask () {
 }
 
 function finish (obj, options) {
-  Notification(options || {
-    type: 'success',
-    title: '文件上传',
-    message: `${obj.name}上传成功`
-  })
-  setState(obj, State.SUCCESS)
+  Notification(
+    options?.message
+      ? options
+      : {
+        type: 'success',
+        title: '文件上传',
+        message: `${obj.name}上传成功`
+      }
+  )
+  setState(obj, options?.del ? State.ABORT : State.SUCCESS)
   emit('uploaded', obj)
 }
 
@@ -650,7 +677,6 @@ function startChunkTask (obj) {
       if (chunk.error === 3) {
         chunk.error = 0
         obj.source?.cancel(e)
-        obj.source = null
         setInvalid(obj, `${name}上传失败`)
         idleTask()
       } else {
@@ -664,6 +690,9 @@ function startMerge (obj) {
   const { hash, name, totalSize, totalChunks, options } = obj
   console.log(`开始合并${name}`, options)
   setState(obj, State.MERGING)
+  if (!obj.source) {
+    obj.source = CancelToken.source()
+  }
   tenantRequest({
     url: '/minio-data/chunk/reduce',
     method: 'POST',
@@ -674,18 +703,52 @@ function startMerge (obj) {
       totalChunks,
       ...options
     }),
+    cancelToken: obj.source.token,
     timeout: 0,
     custom: true,
     background: true
-  }).then(({ data, errMessage }) => {
-    if (data) {
-      finish(obj)
-    } else {
-      setInvalid(obj, `${name}合并文件失败`, errMessage)
+  }).then(
+    ({ data, errMessage }) => {
+      if (data) {
+        console.log(name, '合并成功')
+        finish(obj)
+      } else {
+        setInvalid(obj, `${name}合并文件失败`, errMessage)
+      }
+    },
+    e => {
+      if (!isResolved(obj)) {
+        setInvalid(obj, `${name}合并文件失败`, e)
+      }
     }
-  }, e => {
-    if (!isResolved(obj)) {
-      setInvalid(obj, `${name}合并文件失败`, e)
+  )
+}
+
+function startCopy (obj) {
+  const { keyName, name, options } = obj
+  console.log(name, '开始拷贝')
+  obj.source = CancelToken.source()
+  return request({
+    url: '/minio-data/copy',
+    method: 'POST',
+    data: addTenant({
+      keyName,
+      filename: transformName(name),
+      ...options
+    }),
+    cancelToken: obj.source.token,
+    timeout: 0,
+    custom: true,
+    background: true
+  }).then(
+    () => {
+      console.log(name, '拷贝成功')
+      finish(obj)
+    },
+    e => {
+      if (!isResolved(obj)) {
+        setInvalid(obj, `${name}拷贝失败`, e)
+      }
     }
-  })
+  )
 }