145 lines
4.2 KiB
Vue
145 lines
4.2 KiB
Vue
<script setup lang="ts">
|
|
// imports
|
|
|
|
import { useToast } from "~/composables/global/useToast";
|
|
|
|
// types
|
|
|
|
type Props = {
|
|
modelValue: File[];
|
|
};
|
|
|
|
type Emits = {
|
|
"update:modelValue": [value: any];
|
|
};
|
|
|
|
// props
|
|
|
|
const props = defineProps<Props>();
|
|
|
|
const { modelValue } = toRefs(props);
|
|
|
|
// emits
|
|
|
|
const emit = defineEmits<Emits>();
|
|
|
|
// state
|
|
|
|
const { addToast } = useToast();
|
|
|
|
const dropZoneRef = ref<HTMLDivElement>();
|
|
const fileLimit = 1024 * 1024 * 2;
|
|
|
|
// methods
|
|
|
|
const onDrop = (files: File[] | null) => {
|
|
if (modelValue.value.length < 3) {
|
|
files?.forEach((file, index) => {
|
|
if (file.size > fileLimit) {
|
|
files.splice(index, 1);
|
|
addToast({
|
|
message: "حداکثر حجم فایل 2 مگابایت می باشد",
|
|
options: {
|
|
status: "error",
|
|
},
|
|
});
|
|
}
|
|
});
|
|
if (files.length > 3) {
|
|
emit("update:modelValue", [...files.slice(0, 3)]);
|
|
} else {
|
|
if (modelValue.value.length + files.length <= 3) {
|
|
files?.forEach((item) => {
|
|
emit("update:modelValue", [...modelValue.value, item]);
|
|
});
|
|
} else {
|
|
addToast({
|
|
message: `مجاز به آپلود ${
|
|
3 - modelValue.value.length
|
|
} فایل دیگر هستید`,
|
|
options: {
|
|
status: "error",
|
|
},
|
|
});
|
|
}
|
|
}
|
|
} else {
|
|
addToast({
|
|
message: "محدودیت تعداد را رعایت کنید",
|
|
options: {
|
|
status: "error",
|
|
},
|
|
});
|
|
}
|
|
};
|
|
|
|
const { isOverDropZone } = useDropZone(dropZoneRef, {
|
|
onDrop,
|
|
dataTypes: ["image/jpeg", "image/png", "image/jpg"],
|
|
});
|
|
|
|
const { open: openDialog, onChange } = useFileDialog({
|
|
accept: "image/*",
|
|
directory: false,
|
|
});
|
|
|
|
onChange((files: any) => {
|
|
let arr: File[] = [];
|
|
Object.keys(files).forEach((item) => {
|
|
arr.push(files[item]);
|
|
});
|
|
onDrop(arr);
|
|
});
|
|
|
|
const deleteFile = (index: number) => {
|
|
const clone = [...modelValue.value];
|
|
clone.splice(index, 1);
|
|
emit("update:modelValue", clone);
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex flex-col w-full h-max gap-5 pt-8">
|
|
<div
|
|
ref="dropZoneRef"
|
|
@click="openDialog"
|
|
class="bg-slate-50 flex-col-center w-full transition-all text-black/50 gap-3 h-[20rem] border border-dashed rounded-xl cursor-pointer select-none"
|
|
:class="isOverDropZone ? 'border-black' : ' border-slate-300'"
|
|
>
|
|
<Icon name="bi:file-earmark-arrow-down" size="32" />
|
|
<p class="font-bold text-dynamic-primary text-sm lg:text-[1rem]">
|
|
برای آپلود کلیک کنید یا فایل خود را اینجا بیاندازید
|
|
</p>
|
|
<p class="text-xs font-semibold">فرمت مجاز : jpg, png, jpeg</p>
|
|
<p class="text-xs font-semibold">تعداد فایل مجاز : 3 عدد</p>
|
|
<p class="text-xs font-semibold">حداکثر حجم فایل : 2 مگابایت</p>
|
|
</div>
|
|
|
|
<ul
|
|
v-for="(item, index) in modelValue"
|
|
:key="index"
|
|
v-auto-animate
|
|
class="flex flex-row-reverse items-center justify-between w-full px-2 animate__animated animate__fadeIn"
|
|
>
|
|
<li class="w-full flex items-center">
|
|
<div class="flex justify-end w-9/12">
|
|
<p class="text-sm text-black">{{ item.name }}</p>
|
|
</div>
|
|
<div class="w-2/12">
|
|
<p class="text-sm text-black">
|
|
{{ (item.size / 1024).toFixed(2) }}KB
|
|
</p>
|
|
</div>
|
|
<div class="w-1/12">
|
|
<Icon
|
|
name="ci:close"
|
|
class="**:stroke-red-500 cursor-pointer pb-1"
|
|
@click="deleteFile(index)"
|
|
size="28"
|
|
/>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</template>
|