Merge branch 'dev' of https://github.com/dikstub-rssa/simrs-fe into feat/rm-rajal-183
This commit is contained in:
No files matched your search
@@ -3,14 +3,14 @@
|
||||
import { Button } from '~/components/pub/ui/button'
|
||||
import AppEncounterEntryForm from '~/components/app/encounter/entry-form.vue'
|
||||
import AppViewPatient from '~/components/app/patient/view-patient.vue'
|
||||
import AppViewHistory from '~/components/app/sep/view-history.vue'
|
||||
|
||||
// Helpers
|
||||
import { refDebounced } from '@vueuse/core'
|
||||
|
||||
// Handlers
|
||||
import { getDetail as getDoctorDetail } from '~/services/doctor.service'
|
||||
import { useEncounterEntry } from '~/handlers/encounter-entry.handler'
|
||||
import { genDoctor, type Doctor } from '~/models/doctor'
|
||||
import { useIntegrationSepEntry } from '~/handlers/integration-sep-entry.handler'
|
||||
|
||||
// Props
|
||||
const props = defineProps<{
|
||||
@@ -34,54 +34,33 @@ const {
|
||||
isLoadingDetail,
|
||||
formObjects,
|
||||
openPatient,
|
||||
isMemberValid,
|
||||
isSepValid,
|
||||
isCheckingSep,
|
||||
isSaveDisabled,
|
||||
isSaving,
|
||||
isLoading,
|
||||
patients,
|
||||
selectedDoctor,
|
||||
selectedPatient,
|
||||
selectedPatientObject,
|
||||
paginationMeta,
|
||||
toNavigateSep,
|
||||
getListPath,
|
||||
handleInit,
|
||||
loadEncounterDetail,
|
||||
getFetchEncounterDetail,
|
||||
handleSaveEncounter,
|
||||
getPatientsList,
|
||||
getPatientCurrent,
|
||||
getPatientByIdentifierSearch,
|
||||
getIsSubspecialist,
|
||||
// getIsSubspecialist,
|
||||
getDoctorInfo,
|
||||
getValidateMember,
|
||||
getValidateSepNumber,
|
||||
handleFetchDoctors,
|
||||
} = useEncounterEntry(props)
|
||||
const { recSepId, openHistory, histories, getMonitoringHistoryMappers } = useIntegrationSepEntry()
|
||||
|
||||
const debouncedSepNumber = refDebounced(sepNumber, 500)
|
||||
const selectedDoctor = ref<Doctor>(genDoctor())
|
||||
|
||||
provide('rec_select_id', recSelectId)
|
||||
provide('table_data_loader', isLoading)
|
||||
|
||||
watch(debouncedSepNumber, async (newValue) => {
|
||||
await getValidateSepNumber(newValue)
|
||||
})
|
||||
|
||||
watch(
|
||||
() => formObjects.value?.paymentType,
|
||||
(newValue) => {
|
||||
isSepValid.value = false
|
||||
if (newValue !== 'jkn') {
|
||||
sepNumber.value = ''
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
onMounted(async () => {
|
||||
await handleInit()
|
||||
if (props.id > 0) {
|
||||
await loadEncounterDetail()
|
||||
}
|
||||
})
|
||||
|
||||
///// Functions
|
||||
function handleSavePatient() {
|
||||
@@ -116,12 +95,28 @@ async function handleEvent(menu: string, value?: any) {
|
||||
}
|
||||
toNavigateSep({
|
||||
isService: 'false',
|
||||
encounterId: props.id || null,
|
||||
sourcePath: route.path,
|
||||
resource: `${props.classCode}-${props.subClassCode}`,
|
||||
...value,
|
||||
})
|
||||
} else if (menu === 'sep-number-changed') {
|
||||
await getValidateSepNumber(String(value || ''))
|
||||
const sepNumberText = String(value || '').trim()
|
||||
if (sepNumberText.length > 5) {
|
||||
await getValidateSepNumber(sepNumberText)
|
||||
}
|
||||
} else if (menu === 'member-changed') {
|
||||
const memberText = String(value || '').trim()
|
||||
if (memberText.length > 5) {
|
||||
await getValidateMember(memberText)
|
||||
}
|
||||
} else if (menu === 'search-sep') {
|
||||
const memberText = String(value?.cardNumber || '').trim()
|
||||
if (memberText.length < 5) return
|
||||
getMonitoringHistoryMappers(memberText).then(() => {
|
||||
openHistory.value = true
|
||||
})
|
||||
return
|
||||
} else if (menu === 'save') {
|
||||
await handleSaveEncounter(value)
|
||||
} else if (menu === 'cancel') {
|
||||
@@ -129,13 +124,39 @@ async function handleEvent(menu: string, value?: any) {
|
||||
}
|
||||
}
|
||||
|
||||
async function getDoctorInfo(value: string) {
|
||||
const resp = await getDoctorDetail(value, { includes: 'unit,specialist,subspecialist'})
|
||||
if (resp.success) {
|
||||
selectedDoctor.value = resp.body.data
|
||||
// console.log(selectedDoctor.value)
|
||||
provide('rec_select_id', recSelectId)
|
||||
provide('rec_sep_id', recSepId)
|
||||
provide('table_data_loader', isLoading)
|
||||
|
||||
watch(debouncedSepNumber, async (newValue) => {
|
||||
await getValidateSepNumber(newValue)
|
||||
})
|
||||
|
||||
watch(
|
||||
() => formObjects.value?.paymentType,
|
||||
(newValue) => {
|
||||
isSepValid.value = false
|
||||
if (newValue !== 'jkn') {
|
||||
sepNumber.value = ''
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.id,
|
||||
async (newId) => {
|
||||
if (props.formType === 'edit' && newId > 0) {
|
||||
await getFetchEncounterDetail()
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
onMounted(async () => {
|
||||
await handleInit()
|
||||
if (props.formType === 'edit' && props.id > 0) {
|
||||
await getFetchEncounterDetail()
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -144,13 +165,15 @@ async function getDoctorInfo(value: string) {
|
||||
name="i-lucide-user"
|
||||
class="me-2"
|
||||
/>
|
||||
<span class="font-semibold">{{ props.formType }}</span>
|
||||
<span class="font-semibold">{{ props.formType === 'add' ? 'Tambah' : 'Ubah' }}</span>
|
||||
Kunjungan
|
||||
</div>
|
||||
|
||||
<AppEncounterEntryForm
|
||||
ref="formRef"
|
||||
:mode="props.formType"
|
||||
:is-loading="isLoadingDetail"
|
||||
:is-member-valid="isMemberValid"
|
||||
:is-sep-valid="isSepValid"
|
||||
:is-checking-sep="isCheckingSep"
|
||||
:payments="paymentsList"
|
||||
@@ -165,7 +188,6 @@ async function getDoctorInfo(value: string) {
|
||||
@event="handleEvent"
|
||||
@fetch="handleFetch"
|
||||
/>
|
||||
|
||||
<AppViewPatient
|
||||
v-model:open="openPatient"
|
||||
v-model:selected="selectedPatient"
|
||||
@@ -184,7 +206,11 @@ async function getDoctorInfo(value: string) {
|
||||
"
|
||||
@save="handleSavePatient"
|
||||
/>
|
||||
|
||||
<AppViewHistory
|
||||
v-model:open="openHistory"
|
||||
:is-action="true"
|
||||
:histories="histories"
|
||||
/>
|
||||
<!-- Footer Actions -->
|
||||
<div class="mt-6 flex justify-end gap-2 border-t border-t-slate-300 pt-4">
|
||||
<Button
|
||||
|
||||
@@ -13,7 +13,11 @@ import { useSidebar } from '~/components/pub/ui/sidebar/utils'
|
||||
import { getServicePosition } from '~/lib/roles' // previously getPositionAs
|
||||
|
||||
// Services
|
||||
import { getList as getEncounterList, remove as removeEncounter, cancel as cancelEncounter } from '~/services/encounter.service'
|
||||
import {
|
||||
getList as getEncounterList,
|
||||
remove as removeEncounter,
|
||||
cancel as cancelEncounter,
|
||||
} from '~/services/encounter.service'
|
||||
|
||||
// Apps
|
||||
import Content from '~/components/app/encounter/list.vue'
|
||||
@@ -34,8 +38,14 @@ const props = defineProps<{
|
||||
const { setOpen } = useSidebar()
|
||||
setOpen(true)
|
||||
|
||||
// Role reactivities
|
||||
const { getActiveRole } = useUserStore()
|
||||
|
||||
// Main data
|
||||
const data = ref([])
|
||||
const dataFiltered = ref([])
|
||||
const filterParams = ref<any>({})
|
||||
const activeServicePosition = ref(getServicePosition(getActiveRole()))
|
||||
const isLoading = reactive<DataTableLoader>({
|
||||
summary: false,
|
||||
isTableLoading: false,
|
||||
@@ -87,39 +97,38 @@ const filter = ref<{
|
||||
schema: {},
|
||||
})
|
||||
|
||||
// Role reactivities
|
||||
const { getActiveRole } = useUserStore()
|
||||
const activeServicePosition = ref(getServicePosition(getActiveRole()))
|
||||
provide('activeServicePosition', activeServicePosition)
|
||||
watch(getActiveRole, (role? : string) => {
|
||||
activeServicePosition.value = getServicePosition(role)
|
||||
})
|
||||
|
||||
// Recrod reactivities
|
||||
provide('activeServicePosition', activeServicePosition)
|
||||
provide('rec_id', recId)
|
||||
provide('rec_action', recAction)
|
||||
provide('rec_item', recItem)
|
||||
provide('table_data_loader', isLoading)
|
||||
watch(() => recAction.value, () => {
|
||||
const basePath = `/${props.classCode}/encounter`
|
||||
// console.log(`${basePath}/${recId.value}`, recAction.value)
|
||||
// return
|
||||
if (recAction.value === ActionEvents.showConfirmDelete) {
|
||||
isRecordConfirmationOpen.value = true
|
||||
} else if (recAction.value === ActionEvents.showCancel) {
|
||||
isRecordCancelOpen.value = true
|
||||
} else if (recAction.value === ActionEvents.showDetail) {
|
||||
navigateTo(`${basePath}/${recId.value}`)
|
||||
} else if (recAction.value === ActionEvents.showEdit) {
|
||||
navigateTo(`${basePath}/${recId.value}/edit`)
|
||||
} else if (recAction.value === ActionEvents.showProcess) {
|
||||
navigateTo(`${basePath}/${recId.value}/process`)
|
||||
} else if (recAction.value === ActionEvents.showConfirmDelete) {
|
||||
isRecordConfirmationOpen.value = true
|
||||
}
|
||||
recAction.value = '' // reset
|
||||
|
||||
watch(getActiveRole, (role?: string) => {
|
||||
activeServicePosition.value = getServicePosition(role)
|
||||
})
|
||||
|
||||
watch(
|
||||
() => recAction.value,
|
||||
() => {
|
||||
const basePath = `/${props.classCode}/encounter`
|
||||
if (recAction.value === ActionEvents.showConfirmDelete) {
|
||||
isRecordConfirmationOpen.value = true
|
||||
} else if (recAction.value === ActionEvents.showCancel) {
|
||||
isRecordCancelOpen.value = true
|
||||
} else if (recAction.value === ActionEvents.showDetail) {
|
||||
navigateTo(`${basePath}/${recId.value}/detail`)
|
||||
} else if (recAction.value === ActionEvents.showEdit) {
|
||||
navigateTo(`${basePath}/${recId.value}/edit`)
|
||||
} else if (recAction.value === ActionEvents.showProcess) {
|
||||
navigateTo(`${basePath}/${recId.value}/process`)
|
||||
} else if (recAction.value === ActionEvents.showConfirmDelete) {
|
||||
isRecordConfirmationOpen.value = true
|
||||
}
|
||||
recAction.value = '' // reset
|
||||
},
|
||||
)
|
||||
|
||||
onMounted(() => {
|
||||
getPatientList()
|
||||
})
|
||||
@@ -127,17 +136,21 @@ onMounted(() => {
|
||||
/////// Functions
|
||||
async function getPatientList() {
|
||||
isLoading.isTableLoading = true
|
||||
const includesParams =
|
||||
'patient,patient-person,patient-person-addresses,unit,Appointment_Doctor,Appointment_Doctor-employee,Appointment_Doctor-employee-person,Responsible_Doctor,Responsible_Doctor-employee,Responsible_Doctor-employee-person'
|
||||
data.value = []
|
||||
try {
|
||||
const params: any = { includes: 'patient,patient-person' }
|
||||
const params: any = { includes: includesParams, ...filterParams.value }
|
||||
if (props.classCode) {
|
||||
params['class-code'] = props.classCode
|
||||
params.class_code = props.classCode
|
||||
}
|
||||
if (props.subClassCode) {
|
||||
params['sub-class-code'] = props.subClassCode
|
||||
params.sub_class_code = props.subClassCode
|
||||
}
|
||||
const result = await getEncounterList(params)
|
||||
if (result.success) {
|
||||
data.value = result.body?.data || []
|
||||
dataFiltered.value = [...data.value]
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching encounter list:', error)
|
||||
@@ -146,6 +159,15 @@ async function getPatientList() {
|
||||
}
|
||||
}
|
||||
|
||||
function handleFilterApply(filters: { personName: string; startDate: string; endDate: string }) {
|
||||
filterParams.value = {
|
||||
'person-name': filters.personName,
|
||||
'start-date': filters.startDate,
|
||||
'end-date': filters.endDate,
|
||||
}
|
||||
getPatientList()
|
||||
}
|
||||
|
||||
// Handle confirmation result
|
||||
async function handleConfirmCancel(record: any, action: string) {
|
||||
if (action === 'deactivate' && record?.id) {
|
||||
@@ -240,7 +262,8 @@ function handleRemoveConfirmation() {
|
||||
<template>
|
||||
<CH.ContentHeader v-bind="hreaderPrep">
|
||||
<FilterNav
|
||||
@onFilterClick="() => isFilterFormDialogOpen = true"
|
||||
:active-positon="activeServicePosition"
|
||||
@apply="handleFilterApply"
|
||||
@onExportPdf="() => {}"
|
||||
@onExportExcel="() => {}"
|
||||
@nExportCsv="() => {}"
|
||||
@@ -256,11 +279,12 @@ function handleRemoveConfirmation() {
|
||||
size="lg"
|
||||
prevent-outside
|
||||
>
|
||||
<FilterForm v-bind="filter" />
|
||||
<FilterForm v-bind="filter" />
|
||||
</Dialog>
|
||||
|
||||
<!-- Batal -->
|
||||
<RecordConfirmation
|
||||
v-if="canDelete"
|
||||
v-model:open="isRecordCancelOpen"
|
||||
custom-title="Batalkan Kunjungan"
|
||||
custom-message="Apakah anda yakin ingin membatalkan kunjungan pasien berikut?"
|
||||
|
||||
@@ -26,6 +26,7 @@ import DocUploadList from '~/components/content/document-upload/list.vue'
|
||||
import GeneralConsentList from '~/components/content/general-consent/entry.vue'
|
||||
import ResumeList from '~/components/content/resume/list.vue'
|
||||
import ControlLetterList from '~/components/content/control-letter/list.vue'
|
||||
import VaccineDataList from '~/components/content/vaccine-data/list.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
@@ -96,6 +97,7 @@ const tabs: TabItem[] = [
|
||||
component: DocUploadList,
|
||||
props: { encounter: data },
|
||||
},
|
||||
{ value: 'vaccine-data', label: 'Data Vaksin', component: VaccineDataList, props: { encounter: data } },
|
||||
]
|
||||
</script>
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ import GeneralConsentList from '~/components/content/general-consent/entry.vue'
|
||||
import SummaryMedic from '~/components/content/summary-medic/entry.vue'
|
||||
import ResumeList from '~/components/content/resume/list.vue'
|
||||
import ControlLetterList from '~/components/content/control-letter/list.vue'
|
||||
import InitialNursingStudy from '~/components/content/initial-nursing/entry.vue'
|
||||
// App Components
|
||||
import EncounterPatientInfo from '~/components/app/encounter/quick-info.vue'
|
||||
import EncounterHistoryButtonMenu from '~/components/app/encounter/quick-shortcut.vue'
|
||||
@@ -43,6 +44,10 @@ import EncounterHistoryButtonMenu from '~/components/app/encounter/quick-shortcu
|
||||
const props = defineProps<{
|
||||
classCode: EncounterProps['classCode']
|
||||
subClassCode?: EncounterProps['subClassCode']
|
||||
canCreate?: boolean
|
||||
canRead?: boolean
|
||||
canUpdate?: boolean
|
||||
canDelete?: boolean
|
||||
}>()
|
||||
|
||||
// Common preparations
|
||||
@@ -104,6 +109,13 @@ const protocolRows = [
|
||||
{ value: 'device', label: 'Order Alkes' },
|
||||
{ value: 'mcu-radiology', label: 'Order Radiologi', component: Radiology, props: { encounter_id: data.id } },
|
||||
{ value: 'mcu-lab-cp', label: 'Order Lab PK', component: CpLabOrder, props: { encounter_id: data.id } },
|
||||
{ value: 'consent', label: 'General Consent', component: GeneralConsentList, props: { encounter: data } },
|
||||
{
|
||||
value: 'initial-nursing-study',
|
||||
label: 'Kajian Awal Keperawatan',
|
||||
component: InitialNursingStudy,
|
||||
props: { encounter: data },
|
||||
},
|
||||
{ value: 'mcu-lab-micro', label: 'Order Lab Mikro' },
|
||||
{ value: 'mcu-lab-pa', label: 'Order Lab PA' },
|
||||
{ value: 'medical-action', label: 'Order Ruang Tindakan' },
|
||||
@@ -149,7 +161,7 @@ onMounted(async () => {
|
||||
///// Functions
|
||||
function handleClick(type: string) {
|
||||
if (type === 'draft') {
|
||||
router.back()
|
||||
router.push(`/${props.classCode}/encounter`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,27 +188,13 @@ async function getData() {
|
||||
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<div class="bg-white p-4 dark:bg-slate-800 2xl:p-5">
|
||||
<div class="mb-4 flex">
|
||||
<div>
|
||||
<ContentNavBa
|
||||
label="Kembali"
|
||||
@click="handleClick"
|
||||
/>
|
||||
</div>
|
||||
<!-- <div class="ms-auto pe-3 pt-1 text-end text-xl 2xl:text-2xl font-semibold">
|
||||
Pasien: {{ data.patient.person.name }} --- No. RM: {{ data.patient.number }}
|
||||
</div> -->
|
||||
<div class="bg-white dark:bg-slate-800">
|
||||
<div class="p-3 2xl:p-4 border-b border-slate-300 dark:border-slate-700">
|
||||
<ContentNavBa label="Kembali Ke Daftar" @click="handleClick" />
|
||||
</div>
|
||||
<ContentSwitcher
|
||||
:active="1"
|
||||
:height="150"
|
||||
>
|
||||
<ContentSwitcher :active="1" class="h-[130px] 2xl:h-[160px]">
|
||||
<template v-slot:content1>
|
||||
<EncounterPatientInfo
|
||||
v-if="isShowPatient"
|
||||
:data="data"
|
||||
/>
|
||||
<EncounterPatientInfo v-if="isShowPatient" :data="data" />
|
||||
</template>
|
||||
<template v-slot:content2>
|
||||
<EncounterHistoryButtonMenu v-if="isShowPatient" />
|
||||
@@ -207,6 +205,10 @@ async function getData() {
|
||||
:data="menus"
|
||||
:initial-active-menu="activeMenu"
|
||||
@change-menu="activeMenu = $event"
|
||||
:can-create="canCreate"
|
||||
:can-read="canRead"
|
||||
:can-update="canUpdate"
|
||||
:can-delete="canDelete"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
@@ -5,6 +5,7 @@ import { getValueLabelList as getEmployeeValueLabelList } from '~/services/emplo
|
||||
import { getValueLabelList as getUnitValueLabelList } from '~/services/unit.service'
|
||||
import type { CheckInFormData, CheckOutFormData } from '~/schemas/encounter.schema'
|
||||
import { CheckInSchema, CheckOutSchema } from '~/schemas/encounter.schema'
|
||||
import { getEncounterData } from '~/handlers/encounter-process.handler'
|
||||
|
||||
//
|
||||
import Dialog from '~/components/pub/my-ui/modal/dialog.vue'
|
||||
@@ -18,10 +19,12 @@ import { checkIn } from '~/services/encounter.service'
|
||||
//
|
||||
const props = defineProps<{
|
||||
encounter: Encounter
|
||||
canUpdate?: boolean
|
||||
}>()
|
||||
|
||||
// doctors
|
||||
const doctors = await getDoctorValueLabelList({'includes': 'employee,employee-person'})
|
||||
const localEncounter = ref<Encounter>(props.encounter)
|
||||
const doctors = await getDoctorValueLabelList({'includes': 'employee,employee-person'}, true)
|
||||
const employees = await getEmployeeValueLabelList({'includes': 'person', 'position-code': 'reg'})
|
||||
const units = await getUnitValueLabelList()
|
||||
|
||||
@@ -32,7 +35,7 @@ const checkInValues = ref<any>({
|
||||
// registeredAt: '',
|
||||
})
|
||||
const checkInIsLoading = ref(false)
|
||||
const checkInIsReadonly = ref(false)
|
||||
const checkInIsReadonly = ref(props.canUpdate )
|
||||
const checkInDialogOpen = ref(false)
|
||||
|
||||
// check out
|
||||
@@ -49,8 +52,15 @@ function editCheckIn() {
|
||||
checkInDialogOpen.value = true
|
||||
}
|
||||
|
||||
function submitCheckIn(values: CheckInFormData) {
|
||||
checkIn(props.encounter.id, values)
|
||||
async function submitCheckIn(values: CheckInFormData) {
|
||||
const res = await checkIn(props.encounter.id, values)
|
||||
if (res.success) {
|
||||
checkInDialogOpen.value = false
|
||||
const resEnc = await getEncounterData(props.encounter.id)
|
||||
if (resEnc.success) {
|
||||
localEncounter.value = resEnc.body.data
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function editCheckOut() {
|
||||
@@ -67,9 +77,8 @@ function submitCheckOut(values: CheckOutFormData) {
|
||||
<div class="border-r lg:pe-4 xl:pe-5 mb-10">
|
||||
<div class="mb-4 xl:mb-5 text-base text-center font-semibold">Informasi Masuk</div>
|
||||
<CheckInView
|
||||
:encounter="encounter"
|
||||
:is-loading="checkInIsLoading"
|
||||
:is-readonly="checkInIsReadonly"
|
||||
:encounter="localEncounter"
|
||||
:can-update="canUpdate"
|
||||
@edit="editCheckIn"
|
||||
/>
|
||||
</div>
|
||||
@@ -77,9 +86,8 @@ function submitCheckOut(values: CheckOutFormData) {
|
||||
<Separator class="lg:hidden my-4 xl:my-5" />
|
||||
<div class="mb-4 xl:mb-5 text-base text-center font-semibold">Informasi Keluar</div>
|
||||
<CheckOutView
|
||||
:encounter="encounter"
|
||||
:is-loading="checkOutIsLoading"
|
||||
:is-readonly="checkOutIsReadonly"
|
||||
:encounter="localEncounter"
|
||||
:can-update="canUpdate"
|
||||
@edit="editCheckOut"
|
||||
/>
|
||||
</div>
|
||||
@@ -122,4 +130,4 @@ function submitCheckOut(values: CheckOutFormData) {
|
||||
@cancel="checkInDialogOpen = false"
|
||||
/>
|
||||
</Dialog>
|
||||
</template>
|
||||
</template>
|
||||
Reference in New Issue
Block a user