mcwl-pc/app/pages/test/index.vue

324 lines
9.0 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="upload-container">
<div class="fileUpload">
<div class="item-upload">
<span v-if="required" class="required">*</span>
<n-button type="success" onclick="document.getElementById('fpfileName').click()">
文件选择
</n-button>
<!-- <el-button type="primary" οnclick="document.getElementById('fpfileName').click()">文件选择</el-button> -->
<input
type="file"
id="fpfileName"
class="file2"
style="display: none"
@change="selectFile"
/>
</div>
<div v-if="showFileName" class="item-info">
{{ fileName }}
</div>
<div v-else class="item-info">支持{{ getAcceptType() }}文件格式</div>
<div v-if="progress > 0" class="item-cancel">
<n-button type="success" style="margin-top: 5px" @click="cancelUploadInfo">
X
</n-button>
</div>
</div>
<div class="item-process" v-if="progress > 0">
<n-progress
type="line"
:percentage="progress"
indicator-placement="inside"
processing
/>
<!-- <el-progress :text-inside="true" :stroke-width="20" :percentage="progress"/> -->
</div>
<div v-if="requiredValid" class="item-valid"></div>
</div>
</template>
<script>
// import { message } from 'element-plus';
// import { request } from "http";
import { defineComponent, onMounted, reactive, toRefs } from "vue";
export default defineComponent({
name: "file-upload",
props: {
//文件接受类型
accept: {
type: Array,
default: ["doc", "docx", "pdf", "safetensors", "ckpt"],
},
//是否必填
required: {
type: Boolean,
default: false,
},
//文件限制大小
fileSize: {
type: Number,
default: 2000,
},
},
setup(props) {
const data = reactive({
file: null,
fileName: "",
fileSize: 0,
progress: 0,
objectKey: "",
chunkSize: 5 * 1024 * 1024,
totalChunks: 0,
currentChunk: 1,
uploadId: "",
partArr: [],
showFileName: false,
bucketName: "",
objectKeyName: "",
required: props.required,
requiredValid: false,
});
const message = useMessage();
// 选择文件
const selectFile = async (event) => {
data.file = event.target.files[0];
event.target.value = "";
if (data?.file?.size) {
const fileSize = Math.round((data?.file?.size / 1024 / 1024) * 100) / 100;
if (fileSize > props.fileSize) {
message.warning("文件大小超过上限" + props.fileSize + "MB");
return;
}
data.fileSize = fileSize;
console.log(data.fileSize);
const fileName = data.file.name;
const index = fileName.lastIndexOf(".");
const fileType = fileName.substring(index + 1, fileName.length);
if (!props.accept.includes(fileType)) {
message.warning("文件类型不支持");
return;
}
data.progress = 0;
data.fileName = data.file.name;
data.showFileName = true;
data.totalChunks = Math.ceil(data.file.size / data.chunkSize);
data.objectKey = guid() + "." + fileType;
const res = await request.get("/file/getUploadId/" + data.objectKey);
data.uploadId = res.data;
data.progress = 1;
uploadFile();
// getUploadId(data.objectKey).then((res)=>{
// data.uploadId = res.data
// data.progress = 1;
// uploadFile();
// })
}
};
// 文件上传
const uploadFile = async () => {
const index = data.currentChunk - 1;
const start = index * data.chunkSize;
const end = Math.min((index + 1) * data.chunkSize, data.file.size);
const formData = new FormData();
formData.append("file", data.file.slice(start, end));
formData.append("chunk", data.currentChunk);
formData.append("objectKey", data.objectKey);
formData.append("uploadId", data.uploadId);
// 调用后端接口上传切片数据
try {
const res = await request.post("/file/chunk", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
});
data.partArr.push(res.data);
console.log(data.progress);
data.currentChunk++;
data.progress = Math.floor((data.currentChunk / data.totalChunks) * 100);
if (data.currentChunk <= data.totalChunks) {
uploadFile();
} else {
// 所有切片上传完成
data.progress = 99;
console.log(data.progress);
complete();
}
} catch (err) {
initParam();
console.error("切片上传失败:", error);
message.warning("文件上传异常或上传已取消");
}
// uploadFileInfo(formData).then((res) => {
// data.partArr.push(res.data)
// console.log(data.progress)
// data.currentChunk++;
// data.progress = Math.floor((data.currentChunk / data.totalChunks) * 100);
// if (data.currentChunk <= data.totalChunks) {
// uploadFile();
// } else {
// // 所有切片上传完成
// data.progress = 99;
// console.log(data.progress)
// complete();
// }
// }).catch((error) => {
// initParam()
// console.error('切片上传失败:', error);
// message.warning("文件上传异常或上传已取消")
// });
};
// 上传完成并合并分段上传
const complete = async () => {
try {
const res = await request.post(
`/file/completeUpload?objectKey=${data.objectKey}&uploadId=${data.uploadId}`,
data.partArr
);
console.log("文件上传完成");
console.log(res);
data.bucketName = res.data.bucketName;
data.objectKeyName = res.data.objectKey;
data.progress = 100;
initParam();
} catch (err) {
console.error("文件上传失败:", error);
message.warning('"文件上传失败"');
}
// completeUpload(data.partArr,data.objectKey,data.uploadId).then((res) => {
// console.log('文件上传完成');
// console.log(res);
// data.bucketName = res.data.bucketName
// data.objectKeyName = res.data.objectKey
// data.progress = 100;
// initParam()
// }).catch((error) => {
// console.error('文件上传失败:', error);
// message.error("文件上传失败")
// });
};
// 取消上传
const cancelUploadInfo = () => {
if (data.progress !== 100) {
cancelUpload(data.objectKey, data.uploadId).then(() => {
data.progress = 0;
data.showFileName = false;
initParam();
});
} else {
data.progress = 0;
data.showFileName = false;
initParam();
}
};
const getAcceptType = () => {
let str = "";
if (props.accept) {
for (let item of props.accept) {
str += item + ",";
}
}
return str.substr(0, str.length - 1);
};
// 构建uuid
const guid = () => {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
var r = (Math.random() * 16) | 0,
v = c == "x" ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
};
// 初始化参数
const initParam = () => {
data.file = null;
data.objectKey = "";
data.totalChunks = 0;
data.currentChunk = 1;
data.uploadId = "";
data.partArr = [];
data.requiredValid = false;
};
// 必传校验
const validRequired = () => {
if (data.bucketName && data.objectKeyName) {
data.requiredValid = false;
return true;
} else {
data.requiredValid = true;
return false;
}
};
// 返回上传结果 桶名称、文件名、文件大小
const getUploadInfo = () => {
return {
bucketName: data.bucketName,
fileName: data.objectKeyName,
fileSize: data.fileSize,
};
};
// 初始化
onMounted(() => {
data.progress = 0;
});
return {
...toRefs(data),
selectFile,
uploadFile,
getAcceptType,
validRequired,
getUploadInfo,
cancelUploadInfo,
};
},
});
</script>
<style scoped>
.upload-container {
.fileUpload {
display: flex;
flex-direction: row;
padding: 0px 8px;
.item-upload {
width: 100px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
.required {
color: red;
padding: 0px 5px;
}
}
.item-info {
flex: 1;
padding-top: 12px;
font-size: 13px;
}
.item-cancel {
width: 30px;
padding-right: 20px;
}
}
.item-process {
margin-top: 5px;
padding: 0px 23px;
box-sizing: border-box;
}
.item-valid {
color: red;
padding: 0px 10px;
font-size: 13px;
}
}
</style>