<template>
<div>
<el-upload
accept=".mp3, .m4a, .aac, .mp4, .m4v"
:before-upload="beforeUpload"
:http-request="upload"
:show-file-list="false"
:disabled="disabled"
style="display: inline-block"
class="m-x-12"
>
<el-tooltip placement="bottom">
<template #content>
可上传本地录音录像,支持上传的
<br />音频格式为:mp3、m4a、aac
<br />
视频格式为:mp4、m4v
</template>
<el-button type="primary" style="font-size: 12px" :disabled="disabled">
上传录音录像
</el-button>
</el-tooltip>
</el-upload>
<div
v-if="props.modelValue && props.isShow"
style="margin-top: 10px; width: 100%"
>
<input
disabled="false"
v-model="props.modelValue"
placeholder-class="input-placeholder"
style="width: 80%; padding: 10px; margin-right: 10px"
id="myInput"
/>
</div>
<br />
<el-dialog
v-model="dialogVisible"
:fullscreen="true"
:show-close="false"
custom-class="dispute-upload-dialog"
>
<div class="center">
<div class="fz-18 ellipsis">正在上传:{{ fileData.name }}</div>
<el-progress
:text-inside="true"
:stroke-width="16"
:percentage="percentage"
/>
<el-button style="margin-top: 10px" @click="cancel">取消上传</el-button>
</div>
</el-dialog>
</div>
</template>
<script setup>
import { getToken } from "@/utils/auth";
import axios from "axios";
const { proxy } = getCurrentInstance();
const emit = defineEmits();
const baseUrl = import.meta.env.VITE_APP_BASE_API;
const props = defineProps({
modelValue: [String, Object, Array],
// 是否显示删除
isShow: {
type: Boolean,
default: true,
},
});
const beforeUpload = (file) => {
const mimeTypes = [
"audio/mpeg",
"audio/x-m4a",
"audio/aac",
"video/mp4",
"video/x-m4v",
];
if (!mimeTypes.includes(file.type)) {
proxy.$modal.msgError({
type: "error",
message: "只能上传 MP3、M4A、AAC、MP4、M4V 格式的文件",
duration: 6000,
});
return false;
}
if (file.size / 1024 / 1024 / 1024 > 1.5) {
proxy.$modal.msgError("文件大小不能超过 1.5G");
proxy.$modal.msgError({
type: "error",
message: "文件大小不能超过 1.5G",
duration: 6000,
});
return false;
}
return true;
};
const dialogVisible = ref(false); //上传的进度条弹框
const cancelUpload = ref(false); //是否继续循环调上传接口
let controller = null;
const chunkSize = 5 * 1024 * 1024; // 切片大小5M
const percentage = ref(0); //进度条的数字
const fileData = ref({
name: "",
size: 0,
type: "",
suffix: "",
md5: "",
});
const cancel = () => {
const formData = new FormData();
formData.append("name", fileData.value.name);
formData.append("md5", fileData.value.md5);
dialogVisible.value = false;
cancelUpload.value = true;
controller?.abort();
axios
.post(baseUrl + "/system/oss/endUpload", formData, {
headers: {
"Content-Type": "multipart/form-data",
Authorization: "Bearer " + getToken(),
},
})
.then(() => {
proxy.$modal.msgSuccess("取消上传");
});
};
let counter = 0;
const getFileMd5 = () => {
let guid = (+new Date()).toString(32);
for (let i = 0; i < 5; i++) {
guid += Math.floor(Math.random() * 65535).toString(32);
}
return "wu_" + guid + (counter++).toString(32);
};
const updateUrl = (fileUrl) => {
axios.post("saveUrl", {
fileName: fileData.value.name,
fileUrl,
});
};
// 上传切片
const uploadChunkFile = async (i, fileObj, chunkCount) => {
const start = i * chunkSize;
const end = Math.min(fileData.value.size, start + chunkSize);
const chunkFile = fileObj.slice(start, end);
const formData = new FormData();
formData.append("encrypt", "true");
formData.append("name", fileData.value.name);
formData.append("md5", fileData.value.md5);
formData.append("file", chunkFile, String(i + 1));
formData.append("size", fileObj.size);
formData.append("chunk", i);
formData.append("chunks", chunkCount);
controller = new AbortController();
return await axios
.post(baseUrl + "/system/oss/uploadBigFile", formData, {
headers: {
"Content-Type": "multipart/form-data",
Authorization: "Bearer " + getToken(),
},
onUploadProgress: (data) => {
percentage.value = Number(
(
(Math.min(fileData.value.size, start + data.loaded) /
fileData.value.size) *
100
).toFixed(2)
);
},
signal: controller.signal,
})
.then((res) => {
if (res.data.code === 200) {
return res;
} else {
// 关闭弹框
dialogVisible.value = false;
// 结束循环
cancelUpload.value = true;
proxy.$modal.msgError({
message: `${fileData.value.name}上传失败`,
title: "提示",
});
}
// updateUrl(res.data);
})
.catch((err) => {
// 关闭弹框
dialogVisible.value = false;
// 结束循环
cancelUpload.value = true;
proxy.$modal.msgError({
message: `${fileData.value.name}上传失败`,
title: "提示",
});
});
};
// 计算切片数量
const batchUpload = async (fileObj) => {
percentage.value = 0;
dialogVisible.value = true;
cancelUpload.value = false;
const chunkCount = Math.ceil(fileData.value.size / chunkSize); // 切片数量
fileData.value.md5 = getFileMd5(); // 文件唯一标识
for (let i = 0; i < chunkCount; i++) {
if (cancelUpload.value) return;
const res = await uploadChunkFile(i, fileObj, chunkCount);
if (res && res.data.code === 200 && res.data.data.url) {
proxy.$modal.msgSuccess({
message: `${fileData.value.name}上传成功`,
title: "提示",
});
dialogVisible.value = false;
emit("videoUrl", res.data.data.url);
} else if (res && res.data.code !== 200) {
dialogVisible.value = false;
proxy.$modal.msgError({
message: `${fileData.value.name}上传失败`,
title: "提示",
});
}
// if (i === chunkCount - 1) {
// console.log("循环上传");
// return;
// setTimeout(() => {
// dialogVisible.value = false;
// proxy.$modal.msgSuccess({
// message: `${fileData.value.name}上传成功`,
// title: "提示",
// });
// axios
// .post("/system/oss/uploadTest", {
// folder: fileData.value.md5,
// })
// .then((res) => {
// console.log(res);
// return;
// updateUrl(res.data);
// });
// }, 500);
// }
}
};
// 选择文件
const disabled = ref(false);
const upload = async (file) => {
const fileObj = file.file;
const formData = new FormData();
formData.append("file", file.file);
const nameList = fileObj.name.split(".");
fileData.value.name = fileObj.name;
fileData.value.size = fileObj.size;
fileData.value.type = fileObj.type;
fileData.value.suffix = nameList[nameList.length - 1];
if (chunkSize > fileData.value.size) {
proxy.$modal.loading("正在上传文件,请稍候...");
// 说明是小文件只有1M
disabled.value = true;
axios
.post(baseUrl + "/system/oss/upload", formData, {
headers: {
"Content-Type": "multipart/form-data",
Authorization: "Bearer " + getToken(),
},
})
.then((res) => {
proxy.$modal.msgSuccess({
message: `${fileData.value.name}上传成功`,
title: "提示",
});
proxy.$modal.closeLoading();
emit("update:modelValue", res.data.data.url);
emit("videoUrl", res.data.data.url);
})
.catch(() => {
proxy.$modal.msgError({
message: `${fileData.value.name}上传失败`,
title: "提示",
});
proxy.$modal.closeLoading();
})
.finally(() => (disabled.value = false));
return;
}
batchUpload(fileObj);
};
</script>
<style lang="scss">
.dispute-upload-dialog {
background: none;
}
</style>
<style lang="scss" scoped>
.center {
color: #fff;
width: 50%;
text-align: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>
06-04
322
03-08
206