feat: Implement Fast Request feature with file upload and request management
This commit is contained in:
@@ -1,256 +1,37 @@
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
import { usePrimeVue } from 'primevue/config';
|
||||
import { useToast } from "primevue/usetoast";
|
||||
|
||||
const $primevue = usePrimeVue();
|
||||
const toast = useToast();
|
||||
|
||||
const totalSize = ref(0);
|
||||
const totalSizePercent = ref(0);
|
||||
const files = ref([]);
|
||||
|
||||
const fileUpload = ref(null)
|
||||
|
||||
const openFileDialog = () => {
|
||||
fileUpload.value.choose()
|
||||
}
|
||||
|
||||
const onRemoveTemplatingFile = (file, removeFileCallback, index) => {
|
||||
removeFileCallback(index);
|
||||
totalSize.value -= parseInt(formatSize(file.size));
|
||||
totalSizePercent.value = totalSize.value / 10;
|
||||
};
|
||||
|
||||
const onClearTemplatingUpload = (clear) => {
|
||||
clear();
|
||||
totalSize.value = 0;
|
||||
totalSizePercent.value = 0;
|
||||
};
|
||||
|
||||
const onSelectedFiles = (event) => {
|
||||
files.value = event.files;
|
||||
files.value.forEach((file) => {
|
||||
totalSize.value += parseInt(formatSize(file.size));
|
||||
});
|
||||
};
|
||||
|
||||
const uploadEvent = (callback) => {
|
||||
totalSizePercent.value = totalSize.value / 10;
|
||||
callback();
|
||||
};
|
||||
|
||||
const onTemplatedUpload = () => {
|
||||
toast.add({ severity: "info", summary: "Success", detail: "File Uploaded", life: 3000 });
|
||||
};
|
||||
|
||||
const formatSize = (bytes) => {
|
||||
const k = 1024;
|
||||
const dm = 3;
|
||||
const sizes = $primevue.config.locale.fileSizeTypes;
|
||||
|
||||
if (bytes === 0) {
|
||||
return `0 ${sizes[0]}`;
|
||||
}
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
const formattedSize = parseFloat((bytes / Math.pow(k, i)).toFixed(dm));
|
||||
|
||||
return `${formattedSize} ${sizes[i]}`;
|
||||
};
|
||||
import Select from 'primevue/select';
|
||||
import Textarea from 'primevue/textarea';
|
||||
import FileUploadBox from './FileUploadBox.vue';
|
||||
import { useFastRequestStore } from '../../../store/FastRequest';
|
||||
import { priorities, modalityTitle } from '../../../data/fastRequestOptions';
|
||||
|
||||
const fastRequestStore = useFastRequestStore();
|
||||
</script>
|
||||
|
||||
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<p class="text-[11px] font-[400] text-[#3E4C63] py-3">جزئیات درخواست و اطلاعات مورد نیاز را با دقت و حوصله وار نمایید.</p>
|
||||
<p class="text-[11px] font-[400] text-[#3E4C63] py-3">جزئیات درخواست و اطلاعات مورد نیاز را با دقت و حوصله وارد نمایید.</p>
|
||||
<div class="w-full grid grid-cols-2 gap-2 items-center justify-between">
|
||||
<Select
|
||||
:options="types"
|
||||
optionLabel="name"
|
||||
optionValue="code"
|
||||
placeholder="نوع درخواست"
|
||||
/>
|
||||
<span class="text-[11px] font-[400] text-[#7188AD]">زمان تخمینی ثبت گزارش: ۷۲ ساعت</span>
|
||||
<Select
|
||||
v-model="fastRequestStore.requestDetails.priority"
|
||||
:options="priorities"
|
||||
optionLabel="name"
|
||||
optionValue="code"
|
||||
placeholder="اولویت درخواست"
|
||||
/>
|
||||
<span class="text-[11px] font-[400] text-[#7188AD]">زمان تخمینی ثبت گزارش: ۷۲ ساعت</span>
|
||||
</div>
|
||||
<div class="w-full h-[118px] mt-3">
|
||||
<Textarea
|
||||
v-model="value1"
|
||||
size="small"
|
||||
placeholder="شرح درخواست و توضیحات"
|
||||
rows="3"
|
||||
class="w-full h-full" />
|
||||
|
||||
v-model="fastRequestStore.requestDetails.note"
|
||||
size="small"
|
||||
placeholder="شرح درخواست و توضیحات"
|
||||
rows="3"
|
||||
class="w-full h-full" />
|
||||
</div>
|
||||
<div class="w-full grid grid-cols-2 gap-2 items-center justify-between my-4">
|
||||
<FileUpload class="w-full !border-dashed !border-[#C1D0E8] !min-h-[100px] flex items-center justify-center" ref="fileUpload" name="files[]" :customUpload="true" :showUploadButton="false" :showCancelButton="false" :showChooseButton="false" url="/api/upload" @upload="onTemplatedUpload($event)" :multiple="true" accept="image/*" :maxFileSize="1000000" @select="onSelectedFiles">
|
||||
<template #content="{ files, uploadedFiles, removeUploadedFileCallback, removeFileCallback }">
|
||||
<div class="flex flex-col gap-8 pt-4">
|
||||
<div v-if="files.length > 0">
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<div v-for="(file, index) of files" :key="file.name + file.type + file.size" class="relative w-[5rem] h-[5rem] rounded-lg border border-gray-200 bg-amber-100 flex flex-col items-center gap-4 overflow-hidden">
|
||||
<div class="w-full h-full absolute top-0 left-0">
|
||||
<img role="presentation" :alt="file.name" :src="file.objectURL" class="w-full h-full object-cover"/>
|
||||
</div>
|
||||
<div class="w-full h-full flex flex-col items-center justify-center gap-2 absolute bottom-0 left-0">
|
||||
<span class="w-full px-2 text-xs font-[400] text-ellipsis whitespace-nowrap overflow-hidden">{{ file.name }}</span>
|
||||
<div>{{ formatSize(file.size) }}</div>
|
||||
<Badge value="Pending" severity="warn" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="uploadedFiles.length > 0">
|
||||
<h5>Completed</h5>
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<div v-for="(file, index) of uploadedFiles" :key="file.name + file.type + file.size" class="p-8 rounded-border flex flex-col border border-surface items-center gap-4">
|
||||
<div>
|
||||
<img role="presentation" :alt="file.name" :src="file.objectURL" width="100" height="50" />
|
||||
</div>
|
||||
<span class="font-semibold text-ellipsis max-w-60 whitespace-nowrap overflow-hidden">{{ file.name }}</span>
|
||||
<div>{{ formatSize(file.size) }}</div>
|
||||
<Badge value="Completed" class="mt-4" severity="success" />
|
||||
<Button icon="pi pi-times" @click="removeUploadedFileCallback(index)" variant="outlined" rounded severity="danger" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #empty>
|
||||
<div class="w-full flex items-center justify-center flex-col cursor-pointer" @click="openFileDialog">
|
||||
<Button
|
||||
icon="pi pi-images"
|
||||
rounded
|
||||
variant="outlined"
|
||||
severity="secondary"
|
||||
class="!hidden"
|
||||
@click.stop="openFileDialog"/>
|
||||
<p class="text-[11px] font-[600] text-[#365891]">سوابق پزشکی قبلی (اختیاری)</p>
|
||||
<p class="mt-1 mb-0 text-[11px] font-[400] text-[#365891]">
|
||||
جهت آپلود تصویر کلیک کنید و یا فایل خود کشیده و در این قسمت رها (Drag and Drup) کنید.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
</FileUpload>
|
||||
<FileUpload class="w-full !border-dashed !border-[#C1D0E8] !min-h-[100px] flex items-center justify-center" ref="fileUpload" name="files[]" :customUpload="true" :showUploadButton="false" :showCancelButton="false" :showChooseButton="false" url="/api/upload" @upload="onTemplatedUpload($event)" :multiple="true" accept="image/*" :maxFileSize="1000000" @select="onSelectedFiles">
|
||||
<template #content="{ files, uploadedFiles, removeUploadedFileCallback, removeFileCallback }">
|
||||
<div class="flex flex-col gap-8 pt-4">
|
||||
<div v-if="files.length > 0">
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<div v-for="(file, index) of files" :key="file.name + file.type + file.size" class="relative w-[5rem] h-[5rem] rounded-lg border border-gray-200 bg-amber-100 flex flex-col items-center gap-4 overflow-hidden">
|
||||
<div class="w-full h-full absolute top-0 left-0">
|
||||
<img role="presentation" :alt="file.name" :src="file.objectURL" class="w-full h-full object-cover"/>
|
||||
</div>
|
||||
<div class="w-full h-full flex flex-col items-center justify-center gap-2 absolute bottom-0 left-0">
|
||||
<span class="w-full px-2 text-xs font-[400] text-ellipsis whitespace-nowrap overflow-hidden">{{ file.name }}</span>
|
||||
<div>{{ formatSize(file.size) }}</div>
|
||||
<Badge value="Pending" severity="warn" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="uploadedFiles.length > 0">
|
||||
<h5>Completed</h5>
|
||||
<div class="flex flex-wrap gap-4">
|
||||
<div v-for="(file, index) of uploadedFiles" :key="file.name + file.type + file.size" class="p-8 rounded-border flex flex-col border border-surface items-center gap-4">
|
||||
<div>
|
||||
<img role="presentation" :alt="file.name" :src="file.objectURL" width="100" height="50" />
|
||||
</div>
|
||||
<span class="font-semibold text-ellipsis max-w-60 whitespace-nowrap overflow-hidden">{{ file.name }}</span>
|
||||
<div>{{ formatSize(file.size) }}</div>
|
||||
<Badge value="Completed" class="mt-4" severity="success" />
|
||||
<Button icon="pi pi-times" @click="removeUploadedFileCallback(index)" variant="outlined" rounded severity="danger" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #empty>
|
||||
<div class="w-full flex items-center justify-center flex-col cursor-pointer" @click="openFileDialog">
|
||||
<Button
|
||||
icon="pi pi-images"
|
||||
rounded
|
||||
variant="outlined"
|
||||
severity="secondary"
|
||||
class="!hidden"
|
||||
@click.stop="openFileDialog"/>
|
||||
<p class="text-[11px] font-[600] text-[#365891]">فایل «CT Scan»</p>
|
||||
<p class="mt-1 mb-0 text-[11px] font-[400] text-[#365891]">
|
||||
جهت آپلود تصویر کلیک کنید و یا فایل خود کشیده و در این قسمت رها (Drag and Drup) کنید.
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
</FileUpload>
|
||||
<div class="w-full grid grid-cols-2 gap-2 items-start justify-between my-4">
|
||||
<FileUploadBox v-model="fastRequestStore.historyFiles" title="سوابق پزشکی قبلی (اختیاری)" />
|
||||
<FileUploadBox v-model="fastRequestStore.scanFiles" :title="`فایل «${modalityTitle(fastRequestStore.requestType)}»`" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:deep(.p-select) {
|
||||
border: 1px solid #DEE3EB !important;
|
||||
border-radius: 8px !important;
|
||||
height: 37px !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
}
|
||||
|
||||
:deep(.p-select-label) {
|
||||
padding: 0 12px;
|
||||
line-height: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
:deep(.p-select-label.p-placeholder) {
|
||||
color: #6E91C9 !important;
|
||||
font-size: 11px !important;
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
|
||||
:deep(.p-textarea) {
|
||||
border: 1px solid #DEE3EB !important;
|
||||
border-radius: 8px !important;
|
||||
height: 100% !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
}
|
||||
|
||||
:deep(.p-textarea::placeholder) {
|
||||
color: #6E91C9 !important;
|
||||
font-size: 13px !important;
|
||||
font-weight: 400 !important;
|
||||
}
|
||||
|
||||
.p-fileupload-content {
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
:deep(.p-fileupload-choose-button) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:deep(.p-fileupload-header) {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
:deep(.p-fileupload) {
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
}
|
||||
|
||||
:deep(.p-fileupload-advanced) {
|
||||
border: none !important;
|
||||
border: 2px solid #C1D0E8 !important;
|
||||
border-style: dashed !important;
|
||||
border-radius: 6px !important;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user