2023西安数博会CIM演示-【前端】-Web
AdaKing88
2023-08-21 bc03b832caa49bbcd2674fe4cae3701b5059bf95
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
<template>
  <div id="app">
    <!-- 上传组件 -->
    <!-- :action="uploadUrl" -->
    <el-upload
      ref="upload"
      action
      :multiple="true"
      :show-file-list="true"
      :auto-upload="false"
      :http-request="uploadSectionFile"
      :on-error="onError"
      :on-change="changeFiles"
      name="file"
      :accept="acceptString"
    >
      <el-button class="button_box" slot="trigger" size="small" type="default"
        >选择数据</el-button
      ></el-upload
    >
    <!-- 进度显示 -->
    <!-- <div class="progress-box">
      <span>上传进度:{{ percent.toFixed() }}%</span>
      <el-button type="primary" size="mini" @click="handleClickBtn">{{
        upload | btnTextFilter
      }}</el-button>
    </div> -->
  </div>
</template>
 
<script>
import SparkMD5 from "spark-md5";
import axios from "axios";
 
export default {
  name: "App3",
  props: ["acceptString"],
  filters: {
    btnTextFilter(val) {
      return val ? "暂停" : "继续";
    },
  },
  data() {
    return {
      uploadFileList: [],
      uploadNum: 0,
      percent: 0,
      videoUrl: "",
      upload: true,
      percentCount: 0,
    };
  },
  methods: {
    submitUpload() {
      this.$refs.upload.submit();
    },
    cancelUpload() {
      this.$refs.upload.clearFiles();
      this.uploadNum = 0;
      this.uploadFileList = [];
    },
    uploadSectionFile(param) {
      let that = this;
      const file = param.file;
      let fsize = file.size / 1024 / 1024;
      if (fsize > 100) {
        //数据大于100M,执行分卷上传
        this.handleBigFileUpload(file);
      } else {
        //小文件直接上传
        const formData = new FormData();
        formData.append("chunk", file);
        formData.append("filename", file.name);
        //服务端上传接口,后期对接
        this.$axios({
          url: "/datainsert/upload",
          method: "post",
          headers: { "Content-Type": "multipart/form-data" },
          data: formData,
        }).then((res) => {
          alert("upload small file success!");
          that.uploadNum++;
          if (that.uploadNum === that.uploadFileList.length) {
            that.$refs.upload.clearFiles();
            that.uploadNum = 0;
            that.uploadFileList = [];
          }
        });
      }
    },
    changeFiles(file, fileList) {
      this.uploadFileList = fileList;
    },
    onError(err, file, fileList) {
      this.$alert("文件上传失败,请重试", "错误", {
        confirmButtonText: "确定",
      });
    },
    async handleBigFileUpload(file) {
      if (!file) return;
      let buffer;
      try {
        buffer = await this.fileToBuffer(file);
      } catch (e) {
        console.log(e);
      }
      // 将文件按固定大小(5M)进行切片,注意此处同时声明了多个常量
      const chunkSize = 50 * 1024 * 1024,
        chunkList = [], // 保存所有切片的数组
        chunkListLength = Math.ceil(file.size / chunkSize), // 计算总共多个切片
        suffix = /\.([0-9A-z]+)$/.exec(file.name)[1]; // 文件后缀名
 
      // 根据文件内容生成 hash 值
      const spark = new SparkMD5.ArrayBuffer();
      spark.append(buffer);
      const hash = spark.end();
 
      // 生成切片,这里后端要求传递的参数为字节数据块(chunk)和每个数据块的文件名(fileName)
      let curChunk = 0; // 切片时的初始位置
      for (let i = 0; i < chunkListLength; i++) {
        const item = {
          chunk: file.slice(curChunk, curChunk + chunkSize),
          fileName: `${hash}_${i}.${suffix}`, // 文件名规则按照 hash_1.jpg 命名
        };
        curChunk += chunkSize;
        chunkList.push(item);
      }
      this.chunkList = chunkList; // sendRequest 要用到
      this.hash = hash; // sendRequest 要用到
      this.sendRequest();
    },
    // 将 File 对象转为 ArrayBuffer
    fileToBuffer(file) {
      return new Promise((resolve, reject) => {
        const fr = new FileReader();
        fr.onload = (e) => {
          resolve(e.target.result);
        };
        fr.readAsArrayBuffer(file);
        fr.onerror = () => {
          reject(new Error("转换文件格式发生错误"));
        };
      });
    }, // 发送请求
    sendRequest() {
      let that = this;
      const requestList = []; // 请求集合
      this.chunkList.forEach((item, index) => {
        const fn = () => {
          const formData = new FormData();
          formData.append("chunk", item.chunk);
          formData.append("filename", item.fileName);
          return that
            .$axios({
              url: "/datainsert/upload",
              method: "post",
              headers: { "Content-Type": "multipart/form-data" },
              data: formData,
            })
            .then((res) => {
              alert("upload chunk :" + index + " success!");
              that.chunkList.splice(index, 1); // 一旦上传成功就删除这一个 chunk,方便断点续传
            });
        };
        requestList.push(fn);
      });
 
      let i = 0; // 记录发送的请求个数
      // 文件切片全部发送完毕后,需要请求 '/merge' 接口,把文件的 hash 传递给服务器
      //递归发送异步
      const send = async () => {
        if (i >= requestList.length) {
          that.uploadNum++;
          // 发送完毕
          that.completeUploadBigFile();
          return;
        }
        await requestList[i]();
        i++;
        send();
      };
      send(); // 发送请求
    },
    completeUploadBigFile() {
      let that = this;
      //服务端上传分卷完成后,将分卷合并还原文件接口,后期对接
      this.$axios({
        url: "/datainsert/merge",
        method: "post",
        data: { hash: this.hash },
      }).then((res) => {
        console.log(res);
        if (that.uploadNum === that.uploadFileList.length) {
          that.$refs.upload.clearFiles();
          that.uploadNum = 0;
          that.uploadFileList = [];
        }
      });
    },
  },
};
</script>
 
<style scoped>
.progress-box {
  box-sizing: border-box;
  width: 360px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 10px;
  padding: 8px 10px;
  background-color: #ecf5ff;
  font-size: 14px;
  border-radius: 4px;
}
</style>