add 新增分片上传
This commit is contained in:
parent
c417c6debe
commit
0c62991f68
@ -33,3 +33,6 @@ VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
|
||||
|
||||
# websocket 开关
|
||||
VITE_APP_WEBSOCKET = true
|
||||
|
||||
# 文件上传分片大小 默认5M
|
||||
VITE_FILE_UPLOAD_PART_SIZE = 5242880
|
||||
|
@ -36,3 +36,6 @@ VITE_APP_CLIENT_ID = 'e5cd7e4891bf95d1d19206ce24a7b32e'
|
||||
|
||||
# websocket 开关
|
||||
VITE_APP_WEBSOCKET = true
|
||||
|
||||
# 文件上传分片大小 默认5M
|
||||
VITE_FILE_UPLOAD_PART_SIZE = 5242880
|
||||
|
@ -1,5 +1,5 @@
|
||||
import request from '@/utils/request';
|
||||
import { OssQuery, OssVO } from './types';
|
||||
import { OssPartUploadVo, OssQuery, OssVO } from './types';
|
||||
import { AxiosPromise } from 'axios';
|
||||
|
||||
// 查询OSS对象存储列表
|
||||
@ -26,3 +26,16 @@ export function delOss(ossId: string | number | Array<string | number>) {
|
||||
method: 'delete'
|
||||
});
|
||||
}
|
||||
|
||||
// 分片上传
|
||||
export function partUpload(formData: FormData): AxiosPromise<OssPartUploadVo> {
|
||||
return request({
|
||||
url: '/resource/oss/part/upload',
|
||||
method: 'post',
|
||||
headers: {
|
||||
// 关闭防重提交
|
||||
repeatSubmit: false
|
||||
},
|
||||
data: formData
|
||||
});
|
||||
}
|
||||
|
@ -20,3 +20,26 @@ export interface OssQuery extends PageQuery {
|
||||
export interface OssForm {
|
||||
file: undefined | string;
|
||||
}
|
||||
|
||||
export interface OssPartUploadForm {
|
||||
file: undefined | string;
|
||||
uploadId: undefined | string;
|
||||
fileName: undefined | string;
|
||||
fileSize: undefined | number;
|
||||
partNumber: undefined | number;
|
||||
partSize: undefined | number;
|
||||
totalParts: undefined | number;
|
||||
needMerge: undefined | boolean;
|
||||
}
|
||||
|
||||
export interface OssPartInfo {
|
||||
partNumber: undefined | number;
|
||||
eTag: undefined | string;
|
||||
}
|
||||
|
||||
export interface OssPartUploadVo {
|
||||
uploadId: undefined | string;
|
||||
url: undefined | string;
|
||||
partInfoList: undefined | Array<OssPartInfo>;
|
||||
mergeCompleted: undefined | boolean;
|
||||
}
|
||||
|
149
src/components/FilePartUpload/index.vue
Normal file
149
src/components/FilePartUpload/index.vue
Normal file
@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-upload
|
||||
class="upload-demo"
|
||||
action="#"
|
||||
drag
|
||||
multiple
|
||||
:auto-upload="false"
|
||||
:file-list="fileList"
|
||||
:show-file-list="true"
|
||||
:on-change="handleChange"
|
||||
:on-remove="handleRemove"
|
||||
>
|
||||
<el-icon class="el-icon--upload">
|
||||
<upload-filled />
|
||||
</el-icon>
|
||||
<div class="el-upload__text">
|
||||
将文件拖到此处,或<em>点击上传</em>
|
||||
</div>
|
||||
<!-- <template #tip>-->
|
||||
<!-- <div class="el-upload__tip">-->
|
||||
<!-- 请上传大小不超过 <b style="color: #f56c6c"> 500MB</b> 的文件-->
|
||||
<!-- </div>-->
|
||||
<!-- </template>-->
|
||||
</el-upload>
|
||||
<!-- 文件列表 -->
|
||||
<transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
|
||||
<li v-for="(file, index) in fileList" :key="file.uid" class="el-upload-list__item ele-upload-list__item-content">
|
||||
<el-link :href="`${file.url}`" :underline="false" target="_blank">
|
||||
<span class="el-icon-document"> {{ getFileName(file.name) }} </span>
|
||||
</el-link>
|
||||
<div class="ele-upload-list__item-content-action">
|
||||
<el-button type="danger" link @click="handleDelete(index)">删除</el-button>
|
||||
</div>
|
||||
</li>
|
||||
</transition-group>
|
||||
</div>
|
||||
<el-button type="success" @click="startUpload">开始上传</el-button>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { partUpload } from '@/api/system/oss';
|
||||
|
||||
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||||
|
||||
// 分片大小
|
||||
const partSize = Number(import.meta.env.VITE_FILE_UPLOAD_PART_SIZE);
|
||||
|
||||
const state = reactive({
|
||||
file: null, // 文件
|
||||
uploadId: null, // uploadId 上传ID 上传第一片不需要传递,后续需要,从第一次上传的响应中取得
|
||||
fileName: null, // 文件名(带后缀)
|
||||
fileSize: 0, // 文件(总)大小
|
||||
partNumber: 0, // 当前分片序号
|
||||
totalParts: 0, // 总片数
|
||||
fileParts: [] // 文件分片数组
|
||||
});
|
||||
|
||||
const fileList = ref([]);
|
||||
|
||||
// 开始上传分片
|
||||
const startUpload = () => {
|
||||
proxy?.$modal.loading('正在上传文件,请稍候...');
|
||||
uploadNextPart();
|
||||
proxy?.$modal.closeLoading();
|
||||
};
|
||||
|
||||
// 实际分片上传函数
|
||||
const uploadNextPart = () => {
|
||||
if (state.partNumber < state.totalParts) {
|
||||
const filePart = state.fileParts[state.partNumber];
|
||||
const partNumber = state.partNumber + 1;
|
||||
const formData = new FormData();
|
||||
formData.append('file', filePart);
|
||||
console.log('file:', filePart);
|
||||
// 上传第一片时,uploadId是不存在的
|
||||
if (state.uploadId) {
|
||||
formData.append('uploadId', state.uploadId);
|
||||
}
|
||||
formData.append('fileName', state.fileName);
|
||||
formData.append('fileSize', state.fileSize);
|
||||
formData.append('partNumber', partNumber);
|
||||
formData.append('partSize', partSize);
|
||||
formData.append('totalParts', state.totalParts);
|
||||
// 是否需要合并,如果已经是最后一片,则自动合并
|
||||
formData.append('needMerge', partNumber === state.totalParts);
|
||||
|
||||
partUpload(formData)
|
||||
.then((resp) => {
|
||||
state.partNumber++;
|
||||
if (resp.data.uploadId) {
|
||||
state.uploadId = resp.data.uploadId;
|
||||
}
|
||||
if (resp.data.mergeCompleted) {
|
||||
proxy?.$modal.msgSuccess('文件上传完成');
|
||||
} else {
|
||||
// 继续上传下一片
|
||||
// 如果需要做断点或者暂停上传,可以在这里做介入
|
||||
uploadNextPart();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
proxy?.$modal.msgError('上传文件失败');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 文件发生更改时
|
||||
const handleChange = (uploadFile, uploadFiles) => {
|
||||
stateReset();
|
||||
state.file = uploadFile;
|
||||
state.fileName = state.file.name;
|
||||
state.fileSize = state.file.size;
|
||||
const totalParts = Math.ceil(state.file.size / partSize);
|
||||
state.totalParts = totalParts;
|
||||
// 计算分片
|
||||
for (let i = 0; i < totalParts; i++) {
|
||||
const start = i * partSize;
|
||||
const end = start + partSize >= state.file.size ? state.file.size : start + partSize;
|
||||
const filePart = state.file.raw?.slice(start, end);
|
||||
state.fileParts.push(filePart);
|
||||
}
|
||||
};
|
||||
|
||||
// 文件移除时
|
||||
const handleRemove = (uploadFile, uploadFiles) => {
|
||||
stateReset();
|
||||
};
|
||||
|
||||
// 重置状态
|
||||
const stateReset = () => {
|
||||
state.file = null;
|
||||
state.fileParts = [];
|
||||
state.fileName = null;
|
||||
state.fileSize = 0;
|
||||
state.partNumber = 0;
|
||||
state.totalParts = 0;
|
||||
};
|
||||
|
||||
// 获取文件名称
|
||||
const getFileName = (name: string) => {
|
||||
// 如果是url那么取最后的名字 如果不是直接返回
|
||||
if (name.lastIndexOf('/') > -1) {
|
||||
return name.slice(name.lastIndexOf('/') + 1);
|
||||
} else {
|
||||
return name;
|
||||
}
|
||||
};
|
||||
</script>
|
@ -45,6 +45,9 @@
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPermi="['system:oss:upload']" type="primary" plain icon="Upload" @click="handleImage">上传图片</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPermi="['system:oss:upload']" type="primary" plain icon="Upload" @click="handlePartFile">分片上传</el-button>
|
||||
</el-col>
|
||||
<el-col :span="1.5">
|
||||
<el-button v-hasPermi="['system:oss:remove']" type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()">
|
||||
删除
|
||||
@ -118,6 +121,7 @@
|
||||
<el-form-item label="文件名">
|
||||
<fileUpload v-if="type === 0" v-model="form.file" />
|
||||
<imageUpload v-if="type === 1" v-model="form.file" />
|
||||
<filePartUpload v-if="type === 2" v-model="form.file" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
@ -295,6 +299,13 @@ const handleImage = () => {
|
||||
dialog.visible = true;
|
||||
dialog.title = '上传图片';
|
||||
};
|
||||
/** 分片上传按钮操作 */
|
||||
const handlePartFile = () => {
|
||||
reset();
|
||||
type.value = 2;
|
||||
dialog.visible = true;
|
||||
dialog.title = '分片上传';
|
||||
};
|
||||
/** 提交按钮 */
|
||||
const submitForm = () => {
|
||||
dialog.visible = false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user