Files
radicall/resources/js/Client/Pages/Dashboard/Cases/show.vue
T

229 lines
14 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script setup>
import { computed, onMounted, onUnmounted, ref } from 'vue';
import { useForm } from '@inertiajs/inertia-vue3';
import { Inertia } from '@inertiajs/inertia';
import Dialog from 'primevue/dialog';
import { toast } from 'vue3-toastify';
import ClientLayout from '../../../layouts/ClientLayout.vue';
import UiButton from '../../../components/ui/UiButton.vue';
import CaseSpecsCard from '../../../components/dashboard/cases/CaseSpecsCard.vue';
import ReportSectionCard from '../../../components/dashboard/cases/ReportSectionCard.vue';
import FileUploadBox from '../../../components/dashboard/fastRequest/FileUploadBox.vue';
import { modalityTitle } from '../../../data/fastRequestOptions';
import { convertEnglishToPersian } from '../../../utils/numberUtils';
import { downloadFiles } from '../../../utils/fileUtils';
const props = defineProps({
case: {
type: Object,
required: true
},
canReport: {
type: Boolean,
required: true
}
});
const petRows = computed(() => [
{ label: 'نام', value: props.case.pet?.name },
{ label: 'نوع', value: props.case.pet?.type },
{ label: 'جنسیت', value: props.case.pet?.gender },
{ label: 'نژاد', value: props.case.pet?.breed },
{ label: 'سن', value: props.case.pet?.age !== null && props.case.pet?.age !== undefined ? `${convertEnglishToPersian(props.case.pet.age)} سال` : null },
{ label: 'وزن', value: props.case.pet?.weight ? `${convertEnglishToPersian(props.case.pet.weight)} کیلو گرم` : null },
{ label: 'وضعیت عقیم‌سازی', value: props.case.pet?.sterilized === null ? null : (props.case.pet?.sterilized ? 'عقیم شده' : 'عقیم نشده') },
]);
const requesterRows = computed(() => {
const requester = props.case.requester || {};
return [
{ label: 'نوع', value: requester.level },
{ label: 'نام و نام خانوادگی', value: requester.fullname },
{ label: 'شماره موبایل', value: requester.phone ? convertEnglishToPersian(requester.phone) : null },
{ label: 'تخصص', value: requester.specialty },
{ label: 'کلینیک', value: requester.clinic_name },
{ label: 'تلفن کلینیک', value: requester.clinic_phone ? convertEnglishToPersian(requester.clinic_phone) : null },
{ label: 'محل اقامت', value: [requester.province, requester.city].filter(Boolean).join('، ') || null },
].filter((row) => row.value);
});
const remainingLabel = ref(null);
let timerId = null;
const updateRemaining = () => {
if (!props.case.processing_deadline) {
remainingLabel.value = null;
return;
}
const diff = Math.floor((new Date(props.case.processing_deadline).getTime() - Date.now()) / 1000);
if (diff <= 0) {
remainingLabel.value = 'اتمام فرصت رسیدگی';
return;
}
const pad = (value) => String(value).padStart(2, '0');
remainingLabel.value = convertEnglishToPersian(`${pad(Math.floor(diff / 3600))}:${pad(Math.floor((diff % 3600) / 60))}:${pad(diff % 60)}`) + ' تا پایان زمان ثبت گزارش';
};
onMounted(() => {
updateRemaining();
timerId = setInterval(updateRemaining, 1000);
});
onUnmounted(() => clearInterval(timerId));
const reportForm = useForm({
document_id: props.case.id,
technique: props.case.report?.technique || '',
finding: props.case.report?.finding || '',
diagnose: props.case.report?.diagnose || '',
recommendation: props.case.report?.recommendation || '',
files: [],
});
const submitReport = () => {
reportForm.post('/dashboard/reports', {
forceFormData: true,
onError: () => toast.error('لطفا موارد مشخص‌شده را بررسی و اصلاح کنید.'),
});
};
const rejectModalVisible = ref(false);
const rejectReason = ref('');
const rejecting = ref(false);
const submitReject = () => {
if (!rejectReason.value.trim()) {
toast.error('لطفا دلیل رد درخواست را وارد کنید.');
return;
}
rejecting.value = true;
Inertia.post(`/dashboard/cases/${props.case.id}/reject`, { reason: rejectReason.value }, {
onFinish: () => {
rejecting.value = false;
rejectModalVisible.value = false;
},
});
};
</script>
<template>
<ClientLayout>
<div class="flex flex-col gap-4">
<header class="bg-white border border-complement-50 rounded-2xl px-4 py-3 flex items-center justify-between flex-wrap gap-2">
<h1 class="text-[13px] font-bold text-[#3E4C63]">پرونده شماره {{ convertEnglishToPersian(props.case.code) }}</h1>
<div class="flex items-center gap-3 text-[11px]">
<span v-if="canReport && remainingLabel" class="font-semibold text-[#7A1419]">{{ remainingLabel }}</span>
<span v-else class="font-normal text-[#576989]">وضعیت فعلی</span>
<span class="font-semibold text-[#3E4C63] border-r border-[#DEE3EB] pr-3">{{ props.case.status }}</span>
</div>
</header>
<div class="grid grid-cols-[16rem_1fr] max-lg:grid-cols-1 gap-4 items-start">
<aside class="flex flex-col gap-4">
<CaseSpecsCard title="مشخصات کیس" :rows="petRows" />
<CaseSpecsCard v-if="canReport && requesterRows.length" title="مشخصات درخواست‌دهنده" :rows="requesterRows" />
</aside>
<div class="flex flex-col gap-4">
<section class="bg-white border border-complement-50 rounded-2xl p-4 flex flex-col gap-3">
<h2 class="flex items-center gap-2 text-[12px] font-bold text-[#3E4C63]">
<span class="w-1.5 h-1.5 rounded-full bg-[#7A1419]"></span>
جزئیات درخواست
</h2>
<div class="flex items-center gap-3 flex-wrap text-[11px]">
<p><span class="font-normal text-[#576989]">گزارش درخواست‌شده:</span> <span class="font-semibold text-[#7A1419]">{{ modalityTitle(props.case.modality) }}</span></p>
<span class="text-[#DEE3EB]">|</span>
<p><span class="font-normal text-[#576989]">نوع درخواست:</span> <span class="font-semibold text-[#7A1419]">{{ props.case.priority }}</span></p>
<span class="text-[#DEE3EB]">|</span>
<p><span class="font-normal text-[#576989]">زمان درخواست:</span> <span class="font-semibold text-[#3E4C63]">{{ props.case.submitted_at ? convertEnglishToPersian(props.case.submitted_at) : '-' }}</span></p>
</div>
<div class="text-[12px] leading-6">
<p class="font-normal text-[#576989]">تاریخچه بیماری:</p>
<p class="font-normal text-[#3E4C63] whitespace-pre-line">{{ props.case.note || 'توضیحی ثبت نشده است.' }}</p>
</div>
<div class="flex items-center gap-3 flex-wrap pt-2 border-t border-[#EBEBEB]">
<UiButton label="دانلود فایل درخواست" severity="secondary" size="small" :disabled="!props.case.primary_files.length" @click="downloadFiles(props.case.primary_files)" />
<UiButton label="دانلود سوابق پزشکی قبلی" severity="secondary" size="small" :disabled="!props.case.history_files.length" @click="downloadFiles(props.case.history_files)" />
<UiButton v-if="!canReport && props.case.report" label="دانلود فایل گزارش" severity="secondary" size="small" :disabled="!props.case.report.attachments.length" @click="downloadFiles(props.case.report.attachments)" />
</div>
</section>
<p v-if="props.case.rejection_reason" class="bg-[#F8E9EA] border border-[#E7C3C5] rounded-2xl p-4 text-[12px] font-normal text-[#7A1419] leading-6">
دلیل رد درخواست: {{ props.case.rejection_reason }}
</p>
<template v-if="canReport">
<ReportSectionCard v-model="reportForm.technique" title="تکنیک (Technique)" editable placeholder="شرح تکنیک را وارد کنید" :error="reportForm.errors.technique" />
<ReportSectionCard v-model="reportForm.finding" title="یافته‌ها (Finding)" editable placeholder="یافته‌ها را وارد کنید" :error="reportForm.errors.finding" />
<ReportSectionCard v-model="reportForm.diagnose" title="تشخیص (Diagnose)" editable placeholder="تشخیص را وارد کنید" :error="reportForm.errors.diagnose" />
<ReportSectionCard v-model="reportForm.recommendation" title="پیشنهادات (Recommendation)" editable placeholder="پیشنهادات را وارد کنید" :error="reportForm.errors.recommendation" />
<section class="bg-white border border-complement-50 rounded-2xl p-4 flex flex-col gap-3">
<h2 class="flex items-center gap-2 text-[12px] font-bold text-[#3E4C63]">
<span class="w-1.5 h-1.5 rounded-full bg-[#7A1419]"></span>
آپلود فایل و مستندات
</h2>
<FileUploadBox v-model="reportForm.files" title="آپلود فایل و مستندات گزارش" />
</section>
<footer class="bg-white border border-complement-50 rounded-2xl p-4 flex items-center justify-between flex-wrap gap-3">
<p class="text-[11px] font-normal text-[#576989]">با تایید گزارش و یا رد درخواست دیگر امکان ویرایش آن را نخواهید داشت.</p>
<div class="flex items-center gap-3">
<button type="button" class="text-[11px] font-semibold text-[#7A1419]" @click="rejectModalVisible = true">رد درخواست</button>
<UiButton label="تایید و ثبت گزارش" severity="success" size="small" :loading="reportForm.processing" :disabled="reportForm.processing" @click="submitReport" />
</div>
</footer>
</template>
<template v-else>
<ReportSectionCard :model-value="props.case.report?.technique || ''" title="تکنیک (Technique)" />
<ReportSectionCard :model-value="props.case.report?.finding || ''" title="یافته‌ها (Finding)" />
<ReportSectionCard :model-value="props.case.report?.diagnose || ''" title="تشخیص (Diagnose)" />
<ReportSectionCard :model-value="props.case.report?.recommendation || ''" title="پیشنهادات (Recommendation)" />
<section class="bg-white border border-complement-50 rounded-2xl p-4 flex flex-col gap-3">
<h2 class="flex items-center gap-2 text-[12px] font-bold text-[#3E4C63]">
<span class="w-1.5 h-1.5 rounded-full bg-[#7A1419]"></span>
آپلود فایل و مستندات
</h2>
<div v-if="props.case.report?.attachments?.length" class="flex flex-wrap gap-4">
<a v-for="file in props.case.report.attachments" :key="file.id" :href="file.url" target="_blank" class="relative w-[5rem] h-[5rem] rounded-lg border border-gray-200 overflow-hidden">
<img :alt="file.filename" :src="file.url" class="absolute top-0 left-0 w-full h-full object-cover" />
</a>
</div>
<p v-else class="w-full min-h-[5rem] bg-[#F8FAFC] border border-[#DEE3EB] rounded-xl p-4 text-[12px] font-normal text-[#576989] leading-6 flex items-center justify-center text-center">
عکسی برای این پرونده آپلود نشده است.
</p>
</section>
</template>
</div>
</div>
</div>
<Dialog v-model:visible="rejectModalVisible" :modal="true" :closable="true" :dismissableMask="false" :style="{ width: '480px' }" class="fast-request-dialog" :pt="{ header: '!bg-client-primaryBlue' }">
<template #header>
<div class="w-full flex items-center justify-start">
<h2 class="text-[14px] font-[700] text-[#576989]">رد درخواست</h2>
</div>
</template>
<div class="w-full flex flex-col gap-3 border-t border-[#EBEBEB] pt-4">
<p class="text-[12px] font-normal text-[#3E4C63] leading-6">پس از رد درخواست، مبلغ فاکتور به کیف پول درخواست‌کننده بازگردانده می‌شود.</p>
<textarea
v-model="rejectReason"
rows="4"
placeholder="دلیل رد درخواست را وارد کنید"
class="w-full bg-[#F8FAFC] border border-[#DEE3EB] rounded-xl p-4 text-[12px] font-normal text-[#3E4C63] leading-6 outline-none focus:border-[#C1D0E8] resize-y"
></textarea>
</div>
<div class="w-full pt-3 flex items-center justify-start gap-2 border-t border-[#EBEBEB]">
<UiButton label="رد درخواست" severity="danger" size="small" :loading="rejecting" :disabled="rejecting" @click="submitReject" />
<UiButton label="انصراف" severity="secondary" size="small" :disabled="rejecting" @click="rejectModalVisible = false" />
</div>
</Dialog>
</ClientLayout>
</template>