complete design for submission flow

This commit is contained in:
2026-01-06 16:20:17 +03:30
parent f602ba68e3
commit 954947af77
12 changed files with 497 additions and 49 deletions
@@ -177,7 +177,6 @@ const handleSubmit = () => {
filter-placeholder="جستجو در شهرها..." filter-placeholder="جستجو در شهرها..."
:show-clear="false" :show-clear="false"
/> />
<UiInput <UiInput
prefix-start="آدرس" prefix-start="آدرس"
type="text" type="text"
@@ -10,11 +10,14 @@ import RequestCard from '../../components/dashboard/RequestCard.vue';
import { ref } from 'vue'; import { ref } from 'vue';
import { Link } from '@inertiajs/inertia-vue3'; import { Link } from '@inertiajs/inertia-vue3';
import FastRequestModal from '../../components/dashboard/FastRequestModal.vue'; import FastRequestModal from '../../components/dashboard/FastRequestModal.vue';
import { useFastRequestStore } from '../../store/FastRequest';
const fastRequestStore = useFastRequestStore();
const fastRequestModalVisible = ref(false); const fastRequestModalVisible = ref(false);
const openFastRequestModal = () => { const openFastRequestModal = (type) => {
fastRequestModalVisible.value = true; fastRequestModalVisible.value = true;
fastRequestStore.requestType = type;
} }
defineProps({ defineProps({
@@ -113,11 +116,11 @@ const columns = ref([
<UiCard title="ثبت آنی درخواست جدید" variant="default" class="mt-4"> <UiCard title="ثبت آنی درخواست جدید" variant="default" class="mt-4">
<p class="w-full flex items-center justify-start font-[400] text-[11px]">فقط چند قدم ساده برای ثبت درخواست کافیه.</p> <p class="w-full flex items-center justify-start font-[400] text-[11px]">فقط چند قدم ساده برای ثبت درخواست کافیه.</p>
<div class="w-full h-[179px] grid grid-cols-5 gap-3 justify-start pt-[10px]"> <div class="w-full h-[179px] grid grid-cols-5 gap-3 justify-start pt-[10px]">
<RequestCard title="CT Scan" icon="ct-scan" severity="primary" @click="openFastRequestModal"/> <RequestCard title="CT Scan" icon="ct-scan" severity="primary" @click="openFastRequestModal('ct-scan')"/>
<RequestCard title="MRI" icon="mri" severity="primary"/> <RequestCard title="MRI" icon="mri" severity="primary" @click="openFastRequestModal('mri')"/>
<RequestCard title="سونوگرافی" icon="sonography" severity="primary"/> <RequestCard title="سونوگرافی" icon="sonography" severity="primary" @click="openFastRequestModal('sonography')"/>
<RequestCard title="اکوکاردیوگرافی" icon="echo" severity="primary"/> <RequestCard title="اکوکاردیوگرافی" icon="echo" severity="primary" @click="openFastRequestModal('echo')"/>
<RequestCard title="رادیولوژی" icon="radiology" severity="primary"/> <RequestCard title="رادیولوژی" icon="radiology" severity="primary" @click="openFastRequestModal('radiology')"/>
</div> </div>
</UiCard> </UiCard>
<UiCard title="آخرین کیس‌های در انتظار بررسی" variant="default" class="mt-4"> <UiCard title="آخرین کیس‌های در انتظار بررسی" variant="default" class="mt-4">
@@ -1,21 +1,13 @@
<script setup> <script setup>
import { convertEnglishToPersian } from '../../utils/numberUtils';
import UiButton from '../../components/ui/UiButton.vue'; import UiButton from '../../components/ui/UiButton.vue';
import CtScanIcon from '../../components/svg/ctScanIcon.svg'; import { ref, computed } from 'vue';
import MriIcon from '../../components/svg/mriIcon.svg';
import SonographyIcon from '../../components/svg/sonographyIcon.svg';
import ECOIcon from '../../components/svg/ecoIcon.svg';
import RadiologyIcon from '../../components/svg/radiologyIcon.svg';
import { computed } from 'vue';
import Dialog from 'primevue/dialog'; import Dialog from 'primevue/dialog';
import { ref } from 'vue';
import ProgressBar from 'primevue/progressbar'; import ProgressBar from 'primevue/progressbar';
import RequestCard from './RequestCard.vue'; import RequestType from './fastRequest/RequestType.vue';
import RequestCase from './fastRequest/RequestCase.vue';
const value1 = ref(50); import RequestDetails from './fastRequest/RequestDetails.vue';
const value2 = ref(0); import RequestDoctor from './fastRequest/RequestDoctor.vue';
const value3 = ref(0); import RequestReview from './fastRequest/RequestReview.vue';
const value4 = ref(0);
const props = defineProps({ const props = defineProps({
title: { title: {
@@ -28,6 +20,25 @@
} }
}); });
const step = ref(1);
const stepRef = ref(null);
const steps = ref({
1: RequestType,
2: RequestCase,
3: RequestDetails,
4: RequestDoctor,
5: RequestReview,
});
const currentStepComponent = computed(() => {
return steps.value[step.value] || RequestType
});
const handleNext = () => {
step.value++;
}
</script> </script>
@@ -74,18 +85,10 @@
<span class="text-[10px] font-[600] text-[#7188AD]">مرور نهایی</span> <span class="text-[10px] font-[600] text-[#7188AD]">مرور نهایی</span>
</div> </div>
</div> </div>
<div class="w-full space-y-3 py-6"> <component :is="currentStepComponent" ref="stepRef" @validated="onValidated"/>
<p class="h-[17px] flex items-center justify-start text-[11px] font-[600] text-[#3E4C63]">نوع درخواست خود را مشخص کنید</p>
<div class="w-full h-[133px] grid grid-cols-5 gap-3 justify-start">
<RequestCard v-model="selectedCt" title="CT Scan" icon="ct-scan" severity="primary" :selectable="true"/>
<RequestCard v-model="selectedCt" title="MRI" icon="mri" severity="primary" :selectable="true"/>
<RequestCard v-model="selectedCt" title="سونوگرافی" icon="sonography" severity="primary" :selectable="true"/>
<RequestCard v-model="selectedCt" title="اکوکاردیوگرافی" icon="echo" severity="primary" :selectable="true"/>
<RequestCard v-model="selectedCt" title="رادیولوژی" icon="radiology" severity="primary" :selectable="true"/>
</div>
</div>
<div class="w-full pt-3 flex items-center justify-end border-t border-[#EBEBEB]"> <div class="w-full pt-3 flex items-center justify-end border-t border-[#EBEBEB]">
<ui-button label="تایید و مرحله بعد" severity="success" size="small" /> <ui-button label="تایید و مرحله بعد" severity="success" size="small" @click="handleNext" />
</div> </div>
</Dialog> </Dialog>
@@ -1,18 +1,23 @@
<script setup> <script setup>
import { convertEnglishToPersian } from '../../utils/numberUtils' import UiButton from '../../components/ui/UiButton.vue';
import UiButton from '../../components/ui/UiButton.vue' import CtScanIcon from '../../components/svg/ctScanIcon.svg';
import CtScanIcon from '../../components/svg/ctScanIcon.svg' import MriIcon from '../../components/svg/mriIcon.svg';
import MriIcon from '../../components/svg/mriIcon.svg' import SonographyIcon from '../../components/svg/sonographyIcon.svg';
import SonographyIcon from '../../components/svg/sonographyIcon.svg' import ECOIcon from '../../components/svg/ecoIcon.svg';
import ECOIcon from '../../components/svg/ecoIcon.svg' import RadiologyIcon from '../../components/svg/radiologyIcon.svg';
import RadiologyIcon from '../../components/svg/radiologyIcon.svg' import { computed } from 'vue';
import { computed } from 'vue' import { useFastRequestStore } from '../../store/FastRequest';
const fastRequestStore = useFastRequestStore();
const props = defineProps({ const props = defineProps({
title: { title: {
type: String, type: String,
required: true required: true
}, },
value: {
type: String,
required: true
},
icon: { icon: {
type: String, type: String,
required: true required: true
@@ -40,11 +45,14 @@
} }
}); });
const emit = defineEmits(['update:modelValue']);
const toggleSelect = () => { const toggleSelect = () => {
if (!props.selectable) return if (!props.selectable) return
emit('update:modelValue', !props.modelValue) fastRequestStore.requestType = props.value;
};
const submitRequest = () => {
fastRequestStore.requestType = props.value;
}; };
@@ -55,14 +63,12 @@
:class="[ :class="[
'w-full p-[12px] flex flex-col gap-1 items-center justify-center border rounded-[12px] transition-all', 'w-full p-[12px] flex flex-col gap-1 items-center justify-center border rounded-[12px] transition-all',
props.selectable && 'cursor-pointer', props.selectable && 'cursor-pointer',
props.modelValue fastRequestStore.requestType === props.value ? 'border-[#576989] border-2': 'border-[#DEE3EB]'
? 'border-[#576989]'
: 'border-[#DEE3EB]'
]"> ]">
<component :is="iconComponent" class="w-[87px] h-[80px]" /> <component :is="iconComponent" class="w-[87px] h-[80px]" />
<div class="w-full flex flex-col gap-1"> <div class="w-full flex flex-col gap-1">
<p class="w-full flex items-center justify-center font-[700] text-[14px]">{{ title }}</p> <p class="w-full flex items-center justify-center font-[700] text-[14px]">{{ title }}</p>
<ui-button v-if="!selectable" label="ثبت درخواست" severity="secondary" size="small" full-width="true"/> <ui-button v-if="!selectable" @click="submitRequest" label="ثبت درخواست" severity="secondary" size="small" full-width="true"/>
</div> </div>
</div> </div>
</template> </template>
@@ -0,0 +1,112 @@
<script setup>
import Dialog from 'primevue/dialog';
import UiButton from '../../ui/UiButton.vue';
import TableGeneric from '../../ui/TableGeneric.vue';
import { ref } from 'vue';
import CaseNumber from './CaseNumber.vue';
const isChooseCaseNumber = ref(false);
const showChooseCaseNumber = () => {
isChooseCaseNumber.value = true;
}
const data = ref([
{
id: 1,
case_number: '1234567890',
case_name: 'مایلو',
case_type: 'سگ',
},
{
id: 2,
case_number: '1234567891',
case_name: 'تدی',
case_type: 'گربه',
},
{
id: 3,
case_number: '1234567892',
case_name: 'پونی',
case_type: 'خرگوش',
},
{
id: 4,
case_number: '1234567893',
case_name: 'روبیک',
case_type: 'همستر',
},
{
id: 5,
case_number: '1234567894',
case_name: 'کولا',
case_type: 'خوکچه هندی',
}
]);
const columns = ref([
{
title: 'شناسه کیس',
key: 'case_number'
},
{
title: 'نام کیس',
key: 'case_name'
},
{
title: 'نوع(نژاد)',
key: 'case_type'
},
{
title: '',
key: 'actions',
width: 60,
style: 'grid grid-cols-1',
slot: true,
}
]);
</script>
<template>
<Dialog :modal="true" :closable="true" :dismissableMask="true" :maximizable="false" :style="{ width: '554px' , minHeight: '326px' }">
<template #header>
<h3>انتخاب کیس از آرشیو</h3>
</template>
<div class="w-full py-2 flex flex-col items-start justify-center border-t border-[#EBEBEB] text-[11px] font-[600]">
<p>لیست کیس‌های ثبت‌شده توسط شما در ادامه‌ نمایش داده می‌شود.</p>
<p>در صورتیکه شماره مرجع یک کیس را در اختیار داشته باشید می‌توانید درخواست را برای کیس مربوطه نیز ثبت کنید.</p>
</div>
<div class="h-[180px] overflow-y-scroll">
<TableGeneric
class="bg-white !rounded-2xl"
:data="data"
customStyle="!text-[11px] !font-normal"
:searchable="false"
:columns="columns"
:selectable="false"
:pagination="null"
:model-value="[]"
>
<template #column-actions="{ data }">
<div class="flex items-center justify-end">
<UiButton severity="secondary" size="small">
<template #icon>
</template>
</UiButton>
</div>
</template>
</TableGeneric>
</div>
<div class="w-full pt-3 flex items-center justify-end gap-2 border-t border-[#EBEBEB]">
<ui-button label="افزودن از طریق شناسه کیس" severity="secondary" @click="showChooseCaseNumber"/>
<ui-button label="تایید و انتخاب" severity="success" size="small" @click="handleNext" />
</div>
<case-number v-model:visible="isChooseCaseNumber"></case-number>
</Dialog>
</template>
<style scoped>
</style>
@@ -0,0 +1,45 @@
<script setup>
import Dialog from 'primevue/dialog';
import UiButton from '../../ui/UiButton.vue';
import { ref } from 'vue';
</script>
<template>
<Dialog :modal="true" :closable="true" :dismissableMask="true" :maximizable="false" :style="{ width: '408px' , minHeight: '210px' }">
<template #header>
<h3>افزودن کیس از طریق شناسه مرجع</h3>
</template>
<div class="w-full py-2 flex flex-col items-start justify-center border-t border-[#EBEBEB] text-[11px] font-[600]">
<p>لطفا شناسه کیس که از پزشک و یا سرپرست کیس دریافت کرده‌اید را وارد نمایید.</p>
</div>
<Form ref="formRef" v-slot="$form" class="p-4 grid grid-cols-1 !w-full">
<FormField v-slot="$field" name="name" initialValue="" class="flex flex-col">
<InputText
type="text"
placeholder="شناسه کیس"
size="large"/>
</FormField>
</Form>
<div class="w-full pt-3 flex items-center justify-end gap-2 border-t border-[#EBEBEB]">
<ui-button label="تایید و افزودن" severity="success" size="small"/>
</div>
</Dialog>
</template>
<style scoped>
:deep(.p-inputtext::placeholder) {
color: #6E91C9;
}
:deep(.p-inputtext) {
border: 1px solid #DEE3EB !important;
border-radius: 8px !important;
font-size: 13px !important;
font-weight: 400 !important;
}
</style>
@@ -0,0 +1,166 @@
<script setup>
import Select from 'primevue/select';
import { ref } from 'vue';
import ArchiveCase from './ArchiveCase.vue';
const isChooseArchive = ref(false);
const showChooseArchive = () => {
isChooseArchive.value = true;
}
const genders = ref([
{ name: 'نر', code: 'male' },
{ name: 'ماده', code: 'female' }
]);
const types = ref([
{ name: 'سگ', code: 'dog' },
{ name: 'گربه', code: 'cat' },
{ name: 'پرنده', code: 'bird' },
{ name: 'خرگوش', code: 'rabbit' },
{ name: 'همستر', code: 'hamster' },
{ name: 'خوکچه هندی', code: 'guinea_pig' },
{ name: 'لاک پشت', code: 'turtle' },
{ name: 'مار', code: 'snake' },
{ name: 'مارمولک', code: 'lizard' },
]);
const neuteredStatus = ref([
{ name: 'عقیم سازی شده', code: 'neutered' },
{ name: 'عقیم سازی نشده', code: 'not_neutered' }
]);
</script>
<template>
<div class="w-full space-y-2 py-6">
<div class="w-full h-[12px] flex items-center justify-between">
<p class="flex h-full items-center justify-start text-[11px] font-[600] text-[#3E4C63]">مشخصات کیس(حیوان) مورد نظر را وارد نمایید.</p>
<button @click="showChooseArchive" class="flex h-full items-center justify-end text-[11px] font-[400] text-[#7A1419] cursor-pointer">انتخاب از آرشیو</button>
</div>
<p class="flex items-center justify-start text-[11px] font-[600] text-[#576989]">
در صورتی که قبلا این کیس در پلتفرم رادیکال ثبت شده، برای بررسی سوابق قبلی از دکمه «انتخاب از آرشیو» استفاده نمایید.
</p>
<Form ref="formRef" v-slot="$form" class="p-4 grid grid-cols-2 gap-4 !w-full">
<FormField v-slot="$field" name="name" initialValue="" class="flex flex-col">
<InputText
type="text"
placeholder="نام"
size="large"/>
</FormField>
<FormField v-slot="$field" name="type" initialValue="" class="flex flex-col">
<Select
:options="types"
optionLabel="name"
optionValue="code"
placeholder="نوع"
/>
</FormField>
<FormField v-slot="$field" name="breed" initialValue="" class="flex flex-col">
<InputText
type="text"
placeholder="نژاد"
size="large"/>
</FormField>
<FormField v-slot="$field" name="gender" initialValue="" class="flex flex-col">
<Select :options="genders" optionLabel="name" optionValue="code" placeholder="جنسیت" size="small"/>
</FormField>
<FormField v-slot="$field" name="age" initialValue="" class="flex flex-col">
<InputText
type="text"
placeholder="سن"
size="large"
/>
</FormField>
<FormField v-slot="$field" name="birthday" initialValue="" class="flex flex-col">
<InputText
type="text"
placeholder="وزن"
size="large"
/>
</FormField>
<FormField v-slot="$field" name="sterilized" initialValue="" class="flex flex-col">
<Select
:options="neuteredStatus"
optionLabel="name"
optionValue="code"
placeholder="وضعیت عقیم سازی"
size="small"
/>
</FormField>
</Form>
<archive-case v-model:visible="isChooseArchive"></archive-case>
</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-inputtext) {
font-size: 11px !important;
font-weight: 400 !important;
border: 1px solid #DEE3EB !important;
border-radius: 8px !important;
}
:deep(.p-inputtext::placeholder) {
color: #6E91C9;
}
:deep(.vpd-main) {
border: 1px solid #DEE3EB !important;
border-radius: 8px !important;
overflow: hidden !important;
height: 45px !important;
}
:deep(.vpd-input-group) {
border: 0 !important;
font-size: 16px !important;
border-radius: 8px !important;
border: 0 !important;
font-weight: 400 !important;
height: 45px !important;
}
:deep(.vpd-input-group .vpd-placeholder) {
font-size: 13px !important;
font-weight: 400 !important;
color: #3E4C63 !important;
}
:deep(.vpd-input-group input) {
border: 0 !important;
}
:deep(.vpd-icon-btn) {
background: #576989 !important;
}
:deep(.vpd-content) {
border-radius: 12px !important;
overflow: hidden !important;
border: 0 !important;
}
:deep(.vpd-wrapper) {
background-color: rgba(0,0,0,.1) !important;
}
</style>
@@ -0,0 +1,50 @@
<script setup>
</script>
<template>
<div class="w-full">
<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>
</div>
<div class="w-full h-[118px]">
<p class="text-[11px] font-[400] text-[#6E91C9]">شرح درخواست و توضیحات</p>
</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;
}
</style>
@@ -0,0 +1,14 @@
<script setup>
</script>
<template>
</template>
<style scoped>
</style>
@@ -0,0 +1,14 @@
<script setup>
</script>
<template>
</template>
<style scoped>
</style>
@@ -0,0 +1,23 @@
<script setup>
import RequestCard from '../../../components/dashboard/RequestCard.vue';
</script>
<template>
<div class="w-full space-y-3 py-6">
<p class="h-[17px] flex items-center justify-start text-[11px] font-[600] text-[#3E4C63]">نوع درخواست خود را مشخص کنید</p>
<div class="w-full h-[133px] grid grid-cols-5 gap-3 justify-start">
<RequestCard value="ct-scan" title="CT Scan" icon="ct-scan" severity="primary" :selectable="true"/>
<RequestCard value="mri" title="MRI" icon="mri" severity="primary" :selectable="true"/>
<RequestCard value="sonography" title="سونوگرافی" icon="sonography" severity="primary" :selectable="true"/>
<RequestCard value="echo" title="اکوکاردیوگرافی" icon="echo" severity="primary" :selectable="true"/>
<RequestCard value="radiology" title="رادیولوژی" icon="radiology" severity="primary" :selectable="true"/>
</div>
</div>
</template>
<style scoped>
</style>
+14 -1
View File
@@ -1,7 +1,20 @@
import { step } from '@primeuix/themes/aura/stepper'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
export const useFastRequestStore = defineStore('FastRequestStore', { export const useFastRequestStore = defineStore('FastRequestStore', {
state: () => ({ state: () => ({
step: 1,
requestType: null,
requestCase: {
name: null,
species: null,
gender: null,
age: null,
weight: null,
neutered: null,
},
requestDetails: null,
requestDoctor: null,
requestReview: null,
}), }),
actions: { actions: {