|
@@ -1,168 +0,0 @@
|
|
|
-<template>
|
|
|
- <div class="chunk-upload">
|
|
|
- <el-button type="primary" @click="handleClick" :disabled="uploading">
|
|
|
- {{ uploading ? '上传中...' : '选择并上传文件' }}
|
|
|
- </el-button>
|
|
|
- <div v-for="(progress, index) in uploadProgressList" :key="index" class="progress-item">
|
|
|
- <p>File {{ index + 1 }}: {{ progress.fileName }}</p>
|
|
|
- <el-progress :percentage="progress.percentage"></el-progress>
|
|
|
- </div>
|
|
|
- <input type="file" ref="fileInput" @change="handleFileChange" style="display: none;" multiple />
|
|
|
- </div>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script lang="ts">
|
|
|
-import { defineComponent, ref } from "vue";
|
|
|
-import { ElMessage } from "element-plus";
|
|
|
-import axios from "axios";
|
|
|
-import { v1 as uuidv1 } from "uuid";
|
|
|
-
|
|
|
-axios.defaults.baseURL = "http://10.181.7.236:9988";
|
|
|
-
|
|
|
-
|
|
|
-export default defineComponent({
|
|
|
- name: "ChunkUpload",
|
|
|
- props: {
|
|
|
- maxFileSize: {
|
|
|
- type: Number,
|
|
|
- default: 10 * 1024 * 1024, // 默认10MB
|
|
|
- },
|
|
|
- maxFiles: {
|
|
|
- type: Number,
|
|
|
- default: 3, // 默认最大上传3个文件
|
|
|
- },
|
|
|
- },
|
|
|
- setup(props) {
|
|
|
- const fileInput = ref<HTMLInputElement | null>(null);
|
|
|
- const uploading = ref(false);
|
|
|
- const uploadedFileNames = ref<string[]>([]);
|
|
|
- const uploadProgressList = ref<{ fileName: string; percentage: number }[]>([]);
|
|
|
- const CHUNK_SIZE = 1 * 1024 * 1024; // 每个分片的大小为 1MB
|
|
|
-
|
|
|
- const handleClick = () => {
|
|
|
- fileInput.value?.click();
|
|
|
- };
|
|
|
-
|
|
|
- const handleFileChange = async (event: Event) => {
|
|
|
- const files = (event.target as HTMLInputElement).files;
|
|
|
- if (!files || files.length === 0) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 检查文件数量
|
|
|
- if (files.length > props.maxFiles) {
|
|
|
- ElMessage.error(`最多只能上传 ${props.maxFiles} 个文件`);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- uploading.value = true;
|
|
|
- uploadProgressList.value = Array.from(files).map(file => ({
|
|
|
- fileName: file.name,
|
|
|
- percentage: 0,
|
|
|
- }));
|
|
|
-
|
|
|
- try {
|
|
|
- for (let i = 0; i < files.length; i++) {
|
|
|
- const file = files[i];
|
|
|
- if (file.size > props.maxFileSize) {
|
|
|
- ElMessage.error(`文件 ${file.name} 大小不能超过 ${props.maxFileSize / (1024 * 1024)} MB`);
|
|
|
- continue; // 跳过这个文件继续上传下一个
|
|
|
- }
|
|
|
-
|
|
|
- const totalChunks = Math.ceil(file.size / CHUNK_SIZE);
|
|
|
- const fileIdentifier = await generateFileIdentifier();
|
|
|
-
|
|
|
- for (let chunkIndex = 0; chunkIndex < totalChunks; chunkIndex++) {
|
|
|
- const start = chunkIndex * CHUNK_SIZE;
|
|
|
- const chunk = file.slice(start, start + CHUNK_SIZE);
|
|
|
- await uploadChunk(chunk, chunkIndex, totalChunks, fileIdentifier);
|
|
|
- uploadProgressList.value[i].percentage = Math.round(((chunkIndex + 1) / totalChunks) * 100);
|
|
|
- }
|
|
|
-
|
|
|
- // 文件分片上传完成后,调用合并接口
|
|
|
- const uuidFilename = await mergeChunks(fileIdentifier, file.name);
|
|
|
- uploadedFileNames.value.push(uuidFilename); // 保存上传成功的文件名
|
|
|
- }
|
|
|
-
|
|
|
- ElMessage.success("文件上传完成!");
|
|
|
- } catch (error) {
|
|
|
- ElMessage.error("文件上传失败!");
|
|
|
- console.error("Upload error:", error);
|
|
|
- } finally {
|
|
|
- uploading.value = false;
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- const uploadChunk = async (
|
|
|
- chunk: Blob,
|
|
|
- chunkNumber: number,
|
|
|
- totalChunks: number,
|
|
|
- fileIdentifier: string
|
|
|
- ) => {
|
|
|
- const formData = new FormData();
|
|
|
- formData.append("file", chunk);
|
|
|
-
|
|
|
- try {
|
|
|
- await axios.post(`/file/upload/uploadfile`, formData, {
|
|
|
- params: {
|
|
|
- chunknumber: chunkNumber,
|
|
|
- identifier: fileIdentifier,
|
|
|
- },
|
|
|
- headers: {
|
|
|
- "Content-Type": "multipart/form-data",
|
|
|
- },
|
|
|
- });
|
|
|
- } catch (error) {
|
|
|
- throw new Error(`上传分片 ${chunkNumber} 失败`);
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- // 合并文件分片
|
|
|
- const mergeChunks = async (identifier: string, filename: string) => {
|
|
|
- try {
|
|
|
- const response = await axios.post("/file/upload/mergefile", null, {
|
|
|
- params: {
|
|
|
- identifier: identifier,
|
|
|
- filename: filename,
|
|
|
- chunkstar: 0, // 假设所有分片的开始序号为0
|
|
|
- },
|
|
|
- });
|
|
|
-
|
|
|
- if (response.status !== 200) {
|
|
|
- throw new Error("文件合并失败");
|
|
|
- }
|
|
|
- return response.data.uuidFilename;
|
|
|
- } catch (error) {
|
|
|
- throw new Error("合并请求失败");
|
|
|
- }
|
|
|
- };
|
|
|
-
|
|
|
- const generateFileIdentifier = async (): Promise<string> => {
|
|
|
- return uuidv1(); // 生成一个固定的 UUID1
|
|
|
- };
|
|
|
-
|
|
|
- // 获取已上传的文件名
|
|
|
- const getUploadedFileNames = () => {
|
|
|
- return uploadedFileNames.value;
|
|
|
- };
|
|
|
-
|
|
|
- return {
|
|
|
- fileInput,
|
|
|
- uploading,
|
|
|
- uploadProgressList,
|
|
|
- handleClick,
|
|
|
- handleFileChange,
|
|
|
- getUploadedFileNames,
|
|
|
- };
|
|
|
- },
|
|
|
-});
|
|
|
-</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
-.chunk-upload {
|
|
|
- padding: 20px;
|
|
|
-}
|
|
|
-.progress-item {
|
|
|
- margin-top: 10px;
|
|
|
-}
|
|
|
-</style>
|