feat: 前端增加提交功能
This commit is contained in:
117
src/components/UploadModal.vue
Normal file
117
src/components/UploadModal.vue
Normal file
@@ -0,0 +1,117 @@
|
||||
<script setup lang="ts">
|
||||
import { templateRef } from "@vueuse/core";
|
||||
import { File, UploadIcon, XIcon } from "lucide-vue-next";
|
||||
import { isNull } from "mathjs";
|
||||
import { useSlots } from "vue";
|
||||
|
||||
const slots = useSlots();
|
||||
|
||||
interface Props {
|
||||
autoUpload?: boolean;
|
||||
closeAfterUpload?: boolean;
|
||||
callback: (files: File[]) => void;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
autoUpload: false,
|
||||
closeAfterUpload: false,
|
||||
});
|
||||
|
||||
const inputFiles = defineModel<File[] | null>("inputFiles", { default: null });
|
||||
const isShowModal = defineModel<boolean>("isShowModal", { default: false });
|
||||
|
||||
const fileInputRef = templateRef("fileInputRef");
|
||||
|
||||
function handleFileChange(event: Event) {
|
||||
const files = (event.target as HTMLInputElement).files;
|
||||
if (!files) return;
|
||||
inputFiles.value = Array.from(files);
|
||||
|
||||
if (props.autoUpload) handleUpload();
|
||||
}
|
||||
|
||||
function handleFileDrop(event: DragEvent) {
|
||||
const files = event.dataTransfer?.files;
|
||||
if (!files) return;
|
||||
inputFiles.value = Array.from(files);
|
||||
|
||||
if (props.autoUpload) handleUpload();
|
||||
}
|
||||
|
||||
function handleUpload() {
|
||||
if (!inputFiles.value) return;
|
||||
props.callback(inputFiles.value);
|
||||
if (props.closeAfterUpload) close();
|
||||
}
|
||||
|
||||
function show() {
|
||||
isShowModal.value = true;
|
||||
}
|
||||
|
||||
function close() {
|
||||
isShowModal.value = false;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
show,
|
||||
close,
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div v-if="isShowModal" class="modal modal-open overflow-hidden">
|
||||
<div class="modal-box overflow-hidden flex flex-col gap-3">
|
||||
<div
|
||||
class="flex justify-between items-center pb-3 border-b border-base-300"
|
||||
>
|
||||
<h2 class="text-2xl font-bold text-base-content">文件上传</h2>
|
||||
<button @click="close" class="btn btn-sm btn-circle btn-ghost">
|
||||
<XIcon class="w-6 h-6" />
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
class="border-2 border-dashed border-base-300 rounded-lg text-center cursor-pointer hover:border-primary hover:bg-primary/5 transition-colors aspect-4/2 flex items-center justify-center"
|
||||
@click="fileInputRef.click()"
|
||||
@dragover.prevent
|
||||
@dragenter.prevent
|
||||
@drop.prevent="handleFileDrop"
|
||||
>
|
||||
<div v-if="slots.content">
|
||||
<slot name="content"></slot>
|
||||
</div>
|
||||
<div v-else class="flex flex-col items-center gap-3">
|
||||
<File class="w-12 h-12 text-base-content opacity-40" />
|
||||
<div class="text-sm text-base-content/70 text-center">
|
||||
<div class="font-medium mb-1">点击或拖拽上传</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="flex flex-col items-center gap-2">
|
||||
<File class="w-8 h-8 text-success" />
|
||||
<div class="text-xs font-medium text-success text-center">
|
||||
{{ inputFiles?.[0]?.name }}
|
||||
</div>
|
||||
<div class="text-xs text-base-content/50">点击重新选择</div>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
type="file"
|
||||
ref="fileInputRef"
|
||||
@change="handleFileChange"
|
||||
accept=""
|
||||
class="hidden"
|
||||
/>
|
||||
<button
|
||||
v-if="!autoUpload"
|
||||
class="btn btn-primary btn-sm w-full h-10"
|
||||
@click="handleUpload"
|
||||
:disabled="isNull(inputFiles) || inputFiles.length === 0"
|
||||
>
|
||||
<UploadIcon class="w-6 h-6" />
|
||||
上传
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-backdrop" @click="close"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="postcss" scoped></style>
|
||||
Reference in New Issue
Block a user