fix: update sub-class-code binding in encounter components and log user data

This commit is contained in:
riefive
2025-11-24 14:05:19 +07:00
parent 3d8378deac
commit 1053d794a0
4 changed files with 4 additions and 432 deletions
-431
View File
@@ -1,431 +0,0 @@
<script setup lang="ts">
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { getDetail } from '~/services/encounter.service'
import { getPositionAs } from '~/lib/roles'
import type { TabItem } from '~/components/pub/my-ui/comp-tab/type'
import EncounterPatientInfo from '~/components/app/encounter/collapsible-patient-info.vue'
import EncounterHistoryButtonMenu from '~/components/app/encounter/history-button-menu.vue'
import CompMenu from '~/components/pub/my-ui/comp-menu/comp-menu.vue'
import CompTab from '~/components/pub/my-ui/comp-tab/comp-tab.vue'
// PLASE ORDER BY TAB POSITION
import Status from '~/components/content/encounter/status.vue'
import AssesmentFunctionList from '~/components/content/assesment-function/list.vue'
import EarlyMedicalAssesmentList from '~/components/content/soapi/entry.vue'
import EarlyMedicalRehabList from '~/components/content/soapi/entry.vue'
import PrescriptionList from '~/components/content/prescription/list.vue'
import Consultation from '~/components/content/consultation/list.vue'
import ProtocolList from '~/components/app/chemotherapy/list.protocol.vue'
import MedicineProtocolList from '~/components/app/chemotherapy/list.medicine.vue'
import { listItems } from '~/handlers/encounter-process.handler'
const route = useRoute()
const router = useRouter()
const props = defineProps<{
display?: 'tab' | 'menu'
classCode?: 'ambulatory' | 'emergency' | 'inpatient' | 'outpatient'
subClassCode?: 'reg' | 'rehab' | 'chemo' | 'emg' | 'eon' | 'op' | 'icu' | 'hcu' | 'vk'
}>()
const { user, getActiveRole } = useUserStore()
const activeRole = getActiveRole()
const activePosition = ref(getPositionAs(activeRole))
const tabs = ref([] as any)
const currentDisplay = ref(props.display ?? 'tab')
console.log(JSON.stringify(user, null, 4))
console.log(listItems)
// activeTab selalu sinkron dengan query param
const activeMenu = computed({
get: () => (route.query?.menu && typeof route.query.menu === 'string' ? route.query.menu : 'status'),
set: (value: string) => {
router.replace({ path: route.path, query: { menu: value } })
},
})
const id = typeof route.params.id == 'string' ? parseInt(route.params.id) : 0
const data = ref<any>(null)
const isShowPatient = computed(() => data.value && data.value?.patient?.person)
if (activePosition.value === 'none') { // if user position is none, redirect to home page
router.push('/')
}
// Function to check if date is invalid (like "0001-01-01T00:00:00Z")
function isValidDate(dateString: string | null | undefined): boolean {
if (!dateString) return false
// Check for invalid date patterns
if (dateString.startsWith('0001-01-01')) return false
try {
const date = new Date(dateString)
return !isNaN(date.getTime())
} catch {
return false
}
}
// Function to map API response to Encounter structure
function mapApiResponseToEncounter(apiResponse: any): any {
if (!apiResponse) return null
// Check if patient and patient.person exist (minimal validation)
if (!apiResponse.patient || !apiResponse.patient.person) {
return null
}
const mapped: any = {
id: apiResponse.id || 0,
patient_id: apiResponse.patient_id || apiResponse.patient?.id || 0,
patient: {
id: apiResponse.patient?.id || 0,
number: apiResponse.patient?.number || '',
person: {
id: apiResponse.patient?.person?.id || 0,
name: apiResponse.patient?.person?.name || '',
birthDate: apiResponse.patient?.person?.birthDate || null,
gender_code: apiResponse.patient?.person?.gender_code || '',
residentIdentityNumber: apiResponse.patient?.person?.residentIdentityNumber || null,
frontTitle: apiResponse.patient?.person?.frontTitle || '',
endTitle: apiResponse.patient?.person?.endTitle || '',
addresses: apiResponse.patient?.person?.addresses || [],
},
},
registeredAt: apiResponse.registeredAt || apiResponse.patient?.registeredAt || null,
class_code: apiResponse.class_code || '',
unit_id: apiResponse.unit_id || 0,
unit: apiResponse.unit || null,
specialist_id: apiResponse.specialist_id || null,
subspecialist_id: apiResponse.subspecialist_id || null,
visitDate: isValidDate(apiResponse.visitDate) ? apiResponse.visitDate : (apiResponse.registeredAt || apiResponse.patient?.registeredAt || null),
adm_employee_id: apiResponse.adm_employee_id || 0,
appointment_doctor_id: apiResponse.appointment_doctor_id || null,
responsible_doctor_id: apiResponse.responsible_doctor_id || null,
appointment_doctor: apiResponse.appointment_doctor || null,
responsible_doctor: apiResponse.responsible_doctor || null,
refSource_name: apiResponse.refSource_name || null,
appointment_id: apiResponse.appointment_id || null,
earlyEducation: apiResponse.earlyEducation || null,
medicalDischargeEducation: apiResponse.medicalDischargeEducation || '',
admDischargeEducation: apiResponse.admDischargeEducation || null,
discharge_method_code: apiResponse.discharge_method_code || null,
discharge_reason: apiResponse.dischargeReason || apiResponse.discharge_reason || null,
discharge_date: apiResponse.discharge_date || null,
status_code: apiResponse.status_code || '',
// Payment related fields
paymentMethod_code: apiResponse.paymentMethod_code && apiResponse.paymentMethod_code.trim() !== ''
? apiResponse.paymentMethod_code
: null,
trx_number: apiResponse.trx_number || null,
member_number: apiResponse.member_number || null,
ref_number: apiResponse.ref_number || null,
}
return mapped
}
// Dummy rows for ProtocolList (matches keys expected by list-cfg.protocol)
const protocolRows = [
{
number: '1',
tanggal: new Date().toISOString().substring(0, 10),
siklus: 'I',
periode: 'Siklus I',
kehadiran: 'Hadir',
action: '',
},
{
number: '2',
tanggal: new Date().toISOString().substring(0, 10),
siklus: 'II',
periode: 'Siklus II',
kehadiran: 'Tidak Hadir',
action: '',
},
]
const paginationMeta = {
recordCount: protocolRows.length,
page: 1,
pageSize: 10,
totalPage: 1,
hasNext: false,
hasPrev: false,
}
const tabsRaws: TabItem[] = [
{
value: 'status',
label: 'Status Masuk/Keluar',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
component: Status,
props: { encounter: data },
},
{
value: 'early-medical-assessment',
label: 'Pengkajian Awal Medis',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
component: EarlyMedicalAssesmentList,
},
{
value: 'rehab-medical-assessment',
label: 'Pengkajian Awal Medis Rehabilitasi Medis',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
component: EarlyMedicalRehabList,
},
{
value: 'function-assessment',
label: 'Asesmen Fungsi',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
component: AssesmentFunctionList,
},
{
value: 'therapy-protocol',
groups: ['medical'],
classCode: ['ambulatory'],
subClassCode: ['rehab'],
label: 'Protokol Terapi',
},
{
value: 'chemotherapy-protocol',
label: 'Protokol Kemoterapi',
groups: ['medical', 'verificator'],
classCode: ['ambulatory'],
subClassCode: ['chemo'],
component: ProtocolList,
props: { data: protocolRows, paginationMeta },
},
{
value: 'chemotherapy-medicine',
label: 'Protokol Obat Kemoterapi',
groups: ['medical', 'verificator'],
classCode: ['ambulatory'],
subClassCode: ['chemo'],
component: MedicineProtocolList,
props: { data: protocolRows, paginationMeta },
},
{
value: 'report',
label: 'Laporan Tindakan',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'patient-note',
label: 'CPRJ',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'education-assessment',
label: 'Asesmen Kebutuhan Edukasi',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'consent',
label: 'General Consent',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'prescription',
label: 'Order Obat',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
component: PrescriptionList,
},
{
value: 'device',
label: 'Order Alkes',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'mcu-radiology',
label: 'Order Radiologi',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'mcu-lab-pc',
label: 'Order Lab PK',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'mcu-lab-micro',
label: 'Order Lab Mikro',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'mcu-lab-pa',
label: 'Order Lab PA',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'medical-action',
label: 'Order Ruang Tindakan',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'mcu-result',
label: 'Hasil Penunjang',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'consultation',
label: 'Konsultasi',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
component: Consultation,
props: { encounter: data },
},
{
value: 'resume',
label: 'Resume',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'control',
label: 'Surat Kontrol',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'screening',
label: 'Skrinning MPP',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
{
value: 'supporting-document',
label: 'Upload Dokumen Pendukung',
groups: ['medical'],
classCode: ['ambulatory'],
subClassCode: ['rehab'],
},
{
value: 'price-list',
label: 'Tarif Tindakan',
groups: ['medical'],
classCode: ['ambulatory', 'emergency', 'inpatient'],
subClassCode: ['reg', 'rehab', 'chemo', 'emg', 'eon', 'op', 'icu', 'hcu', 'vk'],
},
]
async function getData() {
try {
const dataRes = await getDetail(id, {
includes:
'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',
})
const dataResBody = dataRes.body ?? null
const result = dataResBody?.data ?? null
if (result) {
const mappedData = mapApiResponseToEncounter(result)
if (mappedData) {
data.value = mappedData
} else {
data.value = null
}
} else {
data.value = null
}
} catch (error) {
console.error('Error fetching encounter data:', error)
data.value = null
}
}
function getMenus() {
return tabsRaws
.filter((tab: TabItem) => (tab.groups ? tab.groups.some((group: string) => group === activePosition.value) : false))
.filter((tab: TabItem) => (tab.classCode && props.classCode ? tab.classCode.includes(props.classCode) : false))
.filter((tab: TabItem) =>
tab.subClassCode && props.subClassCode ? tab.subClassCode.includes(props.subClassCode) : false,
)
.map((tab: TabItem) => {
return { ...tab, props: { ...tab.props, encounter: data } }
})
}
function handleClick(type: string) {
if (type === 'draft') {
router.back()
}
}
watch(getActiveRole, () => {
const activeRole = getActiveRole()
activePosition.value = getPositionAs(activeRole)
tabs.value = getMenus()
})
onMounted(async () => {
await getData()
tabs.value = getMenus()
})
</script>
<template>
<div class="w-full">
<div class="mb-4">
<PubMyUiNavContentBa label="Kembali ke Daftar Kunjungan" @click="handleClick" />
</div>
<EncounterPatientInfo
v-if="isShowPatient"
:data="data"
/>
<EncounterHistoryButtonMenu
v-if="isShowPatient"
/>
<CompTab
v-if="currentDisplay === 'tab'"
:data="tabs"
:initial-active-tab="activeMenu"
@change-tab="activeMenu = $event"
/>
<CompMenu
v-else-if="currentDisplay === 'menu'"
:data="tabs"
:initial-active-menu="activeMenu"
@change-menu="activeMenu = $event"
/>
</div>
</template>
@@ -40,6 +40,8 @@ const id = typeof route.params.id == 'string' ? parseInt(route.params.id) : 0
const data = ref<any>(null)
const isShowPatient = computed(() => data.value && data.value?.patient?.person)
console.log(user)
if (activePosition.value === 'none') { // if user position is none, redirect to home page
router.push('/')
}
@@ -45,7 +45,7 @@ const subClassCode = user.unit_code == 'rehab' ? 'rehab' : 'reg'
<div v-if="canRead">
<Content
class-code="inpatient"
sub-class-code="reg"
:sub-class-code="subClassCode"
type="encounter"
/>
</div>
@@ -46,6 +46,7 @@ const subClassCode = user.unit_code == 'rehab' ? 'rehab' : 'reg'
<Content
class-code="ambulatory"
:sub-class-code="subClassCode"
type="encounter"
/>
</div>
<Error