Browse Source

上传管理器

zhangyu 4 years ago
parent
commit
4d0e1359a7
6 changed files with 148 additions and 69 deletions
  1. 1 0
      public/index.html
  2. 3 11
      src/App.vue
  3. 17 3
      src/api/modelapi.ts
  4. 85 50
      src/components/GlobalUploader/index.vue
  5. 37 3
      src/styles/index.scss
  6. 5 2
      vue.config.js

+ 1 - 0
public/index.html

@@ -5,6 +5,7 @@
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width,initial-scale=1.0">
   <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+  <link rel="stylesheet" href="//at.alicdn.com/t/font_2327510_n21nvmc2c1p.css" />
   <title><%= htmlWebpackPlugin.options.title %></title>
 </head>
 <body>

+ 3 - 11
src/App.vue

@@ -19,16 +19,8 @@ import GlobalUploader from "@/components/GlobalUploader/index.vue";
 })
 export default class extends Vue {}
 </script>
-<style lang="scss">
-.el-scrollbar {
-    height: 100%;
-
-    .el-scrollbar__wrap {
-        overflow-x: auto;
-    }
-
-    .el-scrollbar__view {
-        height: 100%;
-    }
+<style lang="scss" scoped>
+::v-deep .el-scrollbar__wrap {
+    overflow-x: hidden;
 }
 </style>

+ 17 - 3
src/api/modelapi.ts

@@ -1,5 +1,5 @@
 /**
- * 数据中台通用接口文档
+ * 模型服务接口文档
  */
 import httputils from "@/api/httputils";
 const baseUrl = "/modelapi";
@@ -16,5 +16,19 @@ export function queryFloorList(postParams: any): any {
 
 // 准备分片上传模型文件接口
 export function modelFileUpload(postParams: any): any {
-    return httputils.postJson(`${baseUrl}/model-file/upload`, postParams)
-}
+    return httputils.postJson(`${baseUrl}/model-file/upload`, postParams);
+}
+
+// 准备分片上传模型文件接口
+export function mergeModelFile(postParams: any): any {
+    return httputils.postJson(`${baseUrl}/model-file/merge`, postParams);
+}
+
+// 删除模型文件
+export function deleteModelFileList(postParams: any): any {
+    const data = {
+        Id: postParams.Id,
+        Force: postParams.Force ? postParams.Force : false
+    };
+    return httputils.postJson(`${baseUrl}/model-file/merge`, data);
+}

+ 85 - 50
src/components/GlobalUploader/index.vue

@@ -61,13 +61,14 @@
 
 import { Vue, Component, Ref } from "vue-property-decorator";
 // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-//@ts-ignore
+// @ts-ignore
 import SparkMD5 from "spark-md5";
+import Bus from "@/utils/bus.ts";
 // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-//@ts-ignore
+// @ts-ignore
 import uploader from "vue-simple-uploader";
-import Bus from "@/utils/bus.ts";
 import { AppModule } from "@/store/modules/app";
+import { mergeModelFile, deleteModelFileList } from "@/api/modelapi";
 import { getUploadId, mergeMultipart } from "@/api/imageservice";
 
 // import request from "@/api/model/file.js";
@@ -76,7 +77,7 @@ import { getUploadId, mergeMultipart } from "@/api/imageservice";
     name: "GlobalUploader",
 })
 export default class extends Vue {
-    @Ref("uploader") readonly uploader!: uploader;
+    @Ref("uploader") readonly uploaderComponent!: uploader;
 
     // 中英文按钮映射
     private fileStatusText: any = {
@@ -114,13 +115,22 @@ export default class extends Vue {
         // accept: ACCEPT_CONFIG.getAll()
     };
 
-    private panelShow = false; // 选择文件后,展示上传panel
-    private collapse = false;
+    private panelShow = true; // 选择文件后,展示上传panel
+    private collapse = true;
+
+    // Uploader实例
+    get uploader() {
+        return this.uploaderComponent.uploader;
+    }
 
     get uploaderList(): any[] {
         return AppModule.uploaderList;
     }
 
+    private setUploaderList(list: any[]) {
+        AppModule.SetUploaderList(list);
+    }
+
     mounted() {
         // 刷新或关闭浏览器提示
         window.addEventListener("beforeunload", (e) => {
@@ -192,12 +202,18 @@ export default class extends Vue {
         Bus.$emit("fileAdded");
     }
 
+    /**
+     * 文件上传中监听回调
+     */
     private onFileProgress(rootFile: any, file: any, chunk: any) {
         console.log(`上传中 ${file.name},chunk:${chunk.startByte / 1024 / 1024} ~ ${chunk.endByte / 1024 / 1024}`);
     }
 
-    private onFileSuccess(rootFile: any, file: any, response: any, chunk: any) {
-        console.log(chunk);
+    /**
+     * 文件上传成功后的监听回调
+     * @info 每片上传成功后都会触发,检查所有分片是否都上传完成,完成后调用合并接口
+     */
+    private async onFileSuccess(rootFile: any, file: any, response: any) {
         let res = JSON.parse(response);
 
         // 服务器自定义的错误(即虽返回200,但是是错误的情况),这种错误是Uploader无法拦截的
@@ -214,51 +230,59 @@ export default class extends Vue {
             this.statusSet(file.id, "merging");
             if (file.file.modelId) {
                 //模型文件合并专用接口
-                request.mergeModelFile({ ModelId: file.file.modelId, UploadId: file.file.uploadId, Md5: file.file.md5 }, (res) => {
+                const res = await mergeModelFile({ ModelId: file.file.modelId, UploadId: file.file.uploadId, Md5: file.file.md5 });
+                // 文件合并成功
+                if (res.Result === "success") {
                     Bus.$emit("modelStatusChange");
-                    // 文件合并成功
                     Bus.$emit("fileSuccess");
                     this.statusRemove(file.id);
-                });
+                }
             } else {
-                mergeMultipart(
-                    {
-                        systemId: file.file.systemId ? file.file.systemId : "revit",
-                        secret: file.file.secret ? file.file.secret : "63afbef6906c342b",
-                        uploadId: file.file.uploadId,
-                    },
-                    (res) => {
-                        // 文件合并成功
-                        Bus.$emit("fileSuccess");
-                        this.statusRemove(file.id);
-                    }
-                );
+                const res = await mergeMultipart({
+                    systemId: file.file.systemId ? file.file.systemId : "revit",
+                    secret: file.file.secret ? file.file.secret : "63afbef6906c342b",
+                    uploadId: file.file.uploadId,
+                });
+                // 文件合并成功
+                if (res.Result === "success") {
+                    Bus.$emit("fileSuccess");
+                    this.statusRemove(file.id);
+                }
             }
-
-            // 不需要合并
         } else {
+            // 不需要合并
             Bus.$emit("fileSuccess");
             console.log("上传成功");
         }
     }
-    onFileError(rootFile, file, response, chunk) {
+
+    /**
+     * 文件上传失败回调
+     */
+    private onFileError(rootFile: any, file: any, response: any) {
         this.$message({
             message: response,
             type: "error",
         });
     }
-    onFileRemoved(file) {
+
+    /**
+     * 文件移除回调
+     */
+    private async onFileRemoved(file: any) {
         this.uploaderList.splice(
             this.uploaderList.findIndex((item) => {
                 return item.id == file.id;
             }, 1)
         );
         this.setUploaderList(this.uploaderList);
+        // 未上传完成的模型文件,调用模型删除回滚
         if (file.modelId && !file.isComplete()) {
-            request.deleteModelFileList({ Id: file.modelId, Force: true }, (res) => {
+            const res = await deleteModelFileList({ Id: file.modelId, Force: true });
+            if (res.Result === "success") {
                 console.log("删除错误模型:", file.modelId);
                 Bus.$emit("modelStatusChange");
-            });
+            }
         }
     }
 
@@ -266,9 +290,11 @@ export default class extends Vue {
      * 计算md5,实现断点续传及秒传
      * @param file
      */
-    computeMD5(file) {
+    private computeMD5(file: any) {
         let fileReader = new FileReader();
         let time = new Date().getTime();
+        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+        // @ts-ignore
         let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
         let currentChunk = 0;
         const chunkSize = 1 * 1024 * 1024;
@@ -281,7 +307,7 @@ export default class extends Vue {
 
         loadNext();
 
-        fileReader.onload = (e) => {
+        fileReader.onload = (e: any) => {
             spark.append(e.target.result);
 
             if (currentChunk < chunks) {
@@ -290,8 +316,8 @@ export default class extends Vue {
 
                 // 实时展示MD5的计算进度
                 this.$nextTick(() => {
-                    document.getElementsByClassName(`myStatus_${file.id}`)[0].innerText =
-                        "校验MD5 " + ((currentChunk / chunks) * 100).toFixed(0) + "%";
+                    let dom: HTMLElement = document.getElementsByClassName(`myStatus_${file.id}`)[0] as HTMLElement;
+                    dom.innerText = "校验MD5 " + ((currentChunk / chunks) * 100).toFixed(0) + "%";
                     // $(`.myStatus_${file.id}`).text('校验MD5 '+ ((currentChunk/chunks)*100).toFixed(0)+'%')
                 });
             } else {
@@ -302,7 +328,7 @@ export default class extends Vue {
             }
         };
 
-        fileReader.onerror = function () {
+        fileReader.onerror = () => {
             this.error(`文件${file.name}读取出错,请检查该文件`);
             file.cancel();
         };
@@ -315,7 +341,7 @@ export default class extends Vue {
         }
     }
 
-    computeMD5Success(md5, file) {
+    private computeMD5Success(md5: number, file: any) {
         // 将自定义参数直接加载uploader实例的opts上
         console.log(this.uploader);
         // Object.assign(this.uploader.opts, {
@@ -329,19 +355,25 @@ export default class extends Vue {
 
         // file.resume();//继续上传文件
         // 调用依赖中继续上传的方法达到状态刷新的目的(原生点击继续上传按钮)
-        document.querySelector(`.file_${file.id} .uploader-file-resume`).click();
+        let dom: HTMLElement | null = document.querySelector(`.file_${file.id} .uploader-file-resume`);
+        dom?.click();
         this.statusRemove(file.id);
     }
 
-    //获取文件参数
-    getFileQuery(file, chunk) {
+    /**
+     * 获取文件参数
+     */
+    private getFileQuery(file: any) {
         return {
             uploadId: file.file.uploadId,
             md5: file.file.md5,
         };
     }
 
-    fileListShow() {
+    /**
+     * 显示文件列表
+     */
+    private fileListShow() {
         this.collapse = this.collapse ? false : true;
 
         // let $list = $('#global-uploader .file-list');
@@ -359,7 +391,11 @@ export default class extends Vue {
         //   // this.collapse = false;
         // }
     }
-    close() {
+
+    /**
+     * 关闭文件上传器弹窗
+     */
+    private close() {
         if (this.uploader.isUploading()) {
             this.$alert("您有文件正在上传,关闭会中断上传,是否继续?", "提示", {
                 confirmButtonText: "确定",
@@ -371,7 +407,6 @@ export default class extends Vue {
                         this.uploader.files = [];
                         this.setUploaderList([]);
                         Bus.$emit("modelStatusChange");
-                    } else {
                     }
                 },
             });
@@ -386,8 +421,8 @@ export default class extends Vue {
      * @param id
      * @param status
      */
-    statusSet(id, status) {
-        let statusMap = {
+    private statusSet(id: string, status: string) {
+        let statusMap: any = {
             md5: {
                 text: "校验MD5",
                 bgc: "#fff",
@@ -414,7 +449,7 @@ export default class extends Vue {
             node.appendChild(text);
             node.setAttributeNode(att);
             node.style.backgroundColor = `${statusMap[status].bgc}`;
-            document.querySelector(`.file_${id} .uploader-file-status`).appendChild(node);
+            document.querySelector(`.file_${id} .uploader-file-status`)?.appendChild(node);
 
             // $(`<p class="myStatus_${id}"></p>`).appendTo(`.file_${id} .uploader-file-status`).css({
             //   'position': 'absolute',
@@ -427,14 +462,14 @@ export default class extends Vue {
             // }).text(statusMap[status].text);
         });
     }
-    statusRemove(id) {
+    private statusRemove(id: string) {
         this.$nextTick(() => {
-            let dom = document.getElementsByClassName(`myStatus_${id}`)[0];
-            dom.parentNode.removeChild(dom);
+            let dom: Node = document.getElementsByClassName(`myStatus_${id}`)[0];
+            dom.parentNode?.removeChild(dom);
         });
     }
 
-    error(msg) {
+    private error(msg: string) {
         this.$notify({
             title: "错误",
             message: msg,
@@ -450,7 +485,7 @@ export default class extends Vue {
     position: fixed;
     z-index: 101;
     top: auto;
-    right: 15px;
+    right: 10px;
     bottom: 0;
 
     .uploader-app {
@@ -496,7 +531,7 @@ export default class extends Vue {
             > li {
                 background-color: #fff;
             }
-            :v-deep .uploader-file-info i {
+            ::v-deep .uploader-file-info i {
                 display: none;
             }
             ::v-deep .status_style {

+ 37 - 3
src/styles/index.scss

@@ -9,7 +9,7 @@ body {
     height: 100%;
     -moz-osx-font-smoothing: grayscale;
     -webkit-font-smoothing: antialiased;
-    font-family: Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,SimSun,sans-serif,"\5FAE\8F6F\96C5\9ED1";
+    font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif, "\5FAE\8F6F\96C5\9ED1";
     font-size: 14px;
 }
 
@@ -24,10 +24,36 @@ body {
     box-sizing: border-box;
 }
 
+body,
+ul,
+ol,
+dl,
+dd,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+pre,
+form,
+fieldset,
+legend,
+input,
+button,
+textarea,
+p,
+blockquote,
+table,
+th,
+td,
+menu {
+    margin: 0;
+    padding: 0
+}
+
 ul {
     list-style-type: none;
-    margin: 0;
-    padding: 0;
 }
 
 a,
@@ -49,3 +75,11 @@ div:focus {
 .app-container {
     padding: 20px;
 }
+
+.el-scrollbar {
+    height: 100%;
+
+    .el-scrollbar__view {
+        height: 100%;
+    }
+}

+ 5 - 2
vue.config.js

@@ -26,8 +26,7 @@ module.exports = {
             },
             "/datacenter": {
                 target: "http://60.205.177.43:28888",
-                changeOrigin: true,
-                secure: false
+                changeOrigin: true
             },
             "/modelapi": {
                 target: "http://39.102.40.239:8080/",
@@ -35,6 +34,10 @@ module.exports = {
                 pathRewrite: {
                     "^/modelapi": "/revit-algorithm"
                 }
+            },
+            "/image-service": {
+                target: "http://39.97.179.199:8891",
+                changeOrigin: true
             }
         }
     },