137 lines
3.5 KiB
Vue
137 lines
3.5 KiB
Vue
<template>
|
|
<div class="flex flex-col bg-base-100 justify-center items-center">
|
|
<!-- Title -->
|
|
<h1 class="font-bold text-2xl">上传比特流文件</h1>
|
|
|
|
<!-- Input File -->
|
|
<fieldset class="fieldset w-full">
|
|
<legend class="fieldset-legend text-sm">选择或拖拽上传文件</legend>
|
|
<input type="file" ref="fileInput" class="file-input w-full" @change="handleFileChange" />
|
|
<label class="fieldset-label">文件最大容量: {{ maxMemory }}MB</label>
|
|
</fieldset>
|
|
|
|
<!-- Upload Button -->
|
|
<div class="card-actions w-full">
|
|
<button @click="handleClick" class="btn btn-primary grow" :disabled="isUploading">
|
|
<div v-if="isUploading">
|
|
<span class="loading loading-spinner"></span>
|
|
下载中...
|
|
</div>
|
|
<div v-else>
|
|
{{ buttonText }}
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { computed, ref, useTemplateRef, onMounted } from "vue";
|
|
import { useDialogStore } from "@/stores/dialog";
|
|
import { isNull, isUndefined } from "lodash";
|
|
|
|
interface Props {
|
|
uploadEvent?: (file: File) => Promise<boolean>;
|
|
downloadEvent?: () => Promise<boolean>;
|
|
maxMemory?: number;
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
maxMemory: 4,
|
|
});
|
|
|
|
const emits = defineEmits<{
|
|
finishedUpload: [file: File];
|
|
}>();
|
|
|
|
const dialog = useDialogStore();
|
|
|
|
const isUploading = ref(false);
|
|
const buttonText = computed(() => {
|
|
return isUndefined(props.downloadEvent) ? "上传" : "上传并下载";
|
|
});
|
|
|
|
const fileInput = useTemplateRef("fileInput");
|
|
const bitstream = defineModel("bitstreamFile", {
|
|
type: File,
|
|
default: undefined,
|
|
});
|
|
onMounted(() => {
|
|
if (!isUndefined(bitstream.value) && !isNull(fileInput.value)) {
|
|
let fileList = new DataTransfer();
|
|
fileList.items.add(bitstream.value);
|
|
fileInput.value.files = fileList.files;
|
|
}
|
|
});
|
|
|
|
function handleFileChange(event: Event): void {
|
|
const target = event.target as HTMLInputElement;
|
|
const file = target.files?.[0]; // 获取选中的第一个文件
|
|
|
|
if (!file) {
|
|
return;
|
|
}
|
|
|
|
bitstream.value = file;
|
|
}
|
|
|
|
function checkFile(file: File): boolean {
|
|
const maxBytes = props.maxMemory! * 1024 * 1024; // 将最大容量从 MB 转换为字节
|
|
if (file.size > maxBytes) {
|
|
dialog.error(`文件大小超过最大限制: ${props.maxMemory}MB`);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
async function handleClick(event: Event): Promise<void> {
|
|
if (isNull(bitstream.value) || isUndefined(bitstream.value)) {
|
|
dialog.error(`未选择文件`);
|
|
return;
|
|
}
|
|
|
|
if (!checkFile(bitstream.value)) return;
|
|
if (isUndefined(props.uploadEvent)) {
|
|
dialog.error("无法上传");
|
|
return;
|
|
}
|
|
|
|
isUploading.value = true;
|
|
try {
|
|
const ret = await props.uploadEvent(bitstream.value);
|
|
console.debug(`After upload bistream: ${bitstream.value}, result: ${ret}`);
|
|
if (isUndefined(props.downloadEvent)) {
|
|
if (ret) {
|
|
dialog.info("上传成功");
|
|
emits("finishedUpload", bitstream.value);
|
|
} else dialog.error("上传失败");
|
|
return;
|
|
}
|
|
if (!ret) {
|
|
isUploading.value = false;
|
|
return;
|
|
}
|
|
} catch (e) {
|
|
dialog.error("上传失败");
|
|
console.error(e);
|
|
return;
|
|
}
|
|
|
|
// Download
|
|
try {
|
|
const ret = await props.downloadEvent();
|
|
if (ret) dialog.info("下载成功");
|
|
else dialog.error("下载失败");
|
|
} catch (e) {
|
|
dialog.error("下载失败");
|
|
console.error(e);
|
|
}
|
|
|
|
isUploading.value = false;
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="postcss">
|
|
@import "../assets/main.css";
|
|
</style>
|