You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
4.7 KiB
178 lines
4.7 KiB
<template> |
|
<div class="flex justify-center items-center size-full"> |
|
<EdfsWrap title="固件上传" style="width: 50%; height: 50%"> |
|
<el-upload v-model:fileList="fileList" v-loading="loading" element-loading-text="上传中..." drag action="" |
|
accept=".tar.gz" :limit="1" :on-exceed="handleExceed" :auto-upload="false" ref="uploadRef" |
|
class="h-[calc(100%-30px)] w-full"> |
|
<div class="i-line-md:cloud-alt-upload-loop text-20px mx-auto"></div> |
|
<div class="text">拖拽文件或者 <em>点击上传</em></div> |
|
<template #tip v-if="!fileList.length"> |
|
<div class="el-upload__tip">上传限制一个文件,新文件会覆盖旧文件</div> |
|
</template> |
|
</el-upload> |
|
<div class="flex justify-center"> |
|
<el-button type="primary" @click="onSave" v-show="fileList.length && !loading">确定上传</el-button> |
|
<el-button type="info" v-show="loading" @click="onClone">取消上传</el-button> |
|
</div> |
|
</EdfsWrap> |
|
</div> |
|
</template> |
|
|
|
<script setup lang="ts"> |
|
import { uploadFirmwareFile } from '@/api/module/firmware' |
|
import { useMessage } from '@/composables/useMessage' |
|
import type { |
|
UploadInstance, |
|
UploadProps, |
|
UploadRawFile, |
|
UploadUserFile, |
|
} from 'element-plus' |
|
|
|
const message = useMessage() |
|
|
|
const fileList = ref<UploadUserFile[]>([]) |
|
|
|
const upload = ref<UploadInstance>() |
|
const handleExceed: UploadProps['onExceed'] = files => { |
|
upload.value!.clearFiles() |
|
const file = files[0] as UploadRawFile |
|
|
|
upload.value!.handleStart(file) |
|
} |
|
|
|
const uploadRef = ref<UploadInstance>() |
|
|
|
const beforeAvatarUpload: UploadProps['beforeUpload'] = rawFile => { |
|
const accept = ['.zip', '.tar', '.tar.gz'] |
|
const fileTypes = rawFile.name.substring(rawFile.name.indexOf('.')) |
|
|
|
if (!accept.includes(fileTypes)) { |
|
message.error('请上传 tar.gz 文件') |
|
uploadRef.value?.clearFiles?.() |
|
return false |
|
} |
|
return true |
|
} |
|
function validate() { |
|
if (!fileList.value.length) { |
|
message.error('请上传文件') |
|
return true |
|
} |
|
|
|
return beforeAvatarUpload(fileList.value[0].raw!) |
|
} |
|
const loading = ref(false) |
|
const abortController = ref<AbortController>() |
|
|
|
async function onSave() { |
|
if (loading.value) { |
|
message.error('文件正在上传中,请稍后') |
|
return |
|
} |
|
if (!validate()) return |
|
loading.value = true |
|
abortController.value = new AbortController() |
|
const data = new FormData() |
|
data.append('file', fileList.value[0].raw as File) |
|
const userFile = fileList.value[0] as UploadUserFile |
|
const res = await uploadFirmwareFile(data, abortController.value) |
|
if (res.code === 0) { |
|
message.success('上传成功') |
|
} else { |
|
message.error('上传失败') |
|
} |
|
// const file = userFile.raw as File |
|
// const fileName = userFile.name |
|
|
|
// const chunkList = await createChunksFromFileData(file, 1024) |
|
|
|
// try { |
|
// for (const chunk of chunkList) { |
|
// const { chunkData, offset } = chunk |
|
// const res = await uploadSftpFile( |
|
// { |
|
// fileName, |
|
// chunk: chunkData, |
|
// targetPath: props.curPath, |
|
// offset, |
|
// }, |
|
// abortController.value |
|
// ) |
|
|
|
// if (res.code === -777) { |
|
// return |
|
// } |
|
// if (![200, 0].includes(res.code)) { |
|
// // 如果是手动取消的请求,不提示错误 |
|
// message.error(`上传失败,${res.msg}`) |
|
// return |
|
// } |
|
// } |
|
// } catch (error) { |
|
// message.error('上传失败') |
|
// } |
|
abortController.value = undefined |
|
|
|
loading.value = false |
|
|
|
onClone() |
|
} |
|
|
|
async function readFileAsArrayBuffer(file: File): Promise<ArrayBuffer> { |
|
return new Promise((resolve, reject) => { |
|
const reader = new FileReader() |
|
reader.readAsArrayBuffer(file) |
|
reader.onload = () => resolve(reader.result as ArrayBuffer) |
|
reader.onerror = reject |
|
}) |
|
} |
|
|
|
async function createChunksFromFileData(file: File, chunkSize: number) { |
|
const fileData = await readFileAsArrayBuffer(file) |
|
|
|
const chunkList: { offset: number; chunkIndex: number; chunkData: Uint8Array }[] = [] |
|
let offset = 0 |
|
let chunkIndex = 0 |
|
|
|
while (offset < fileData.byteLength) { |
|
const chunkData = new Uint8Array(fileData.slice(offset, offset + chunkSize)) |
|
chunkList.push({ |
|
offset, |
|
chunkIndex, |
|
chunkData, |
|
}) |
|
|
|
offset += chunkSize |
|
chunkIndex++ |
|
} |
|
|
|
return chunkList |
|
} |
|
|
|
function clearData() { |
|
fileList.value = [] |
|
} |
|
function onClone() { |
|
if (loading.value) { |
|
abortController.value?.abort() |
|
loading.value = false |
|
} |
|
clearData() |
|
} |
|
</script> |
|
|
|
<style lang="scss" scoped> |
|
:deep(.el-upload) { |
|
height: calc(100% - 50px); |
|
width: 100%; |
|
} |
|
|
|
:deep(.el-upload-dragger) { |
|
height: 100%; |
|
width: 100%; |
|
display: flex; |
|
flex-direction: column; |
|
justify-content: center; |
|
align-items: center; |
|
} |
|
</style>
|
|
|