feat: add patient info components and update navigation for encounter details

This commit is contained in:
riefive
2025-11-25 14:59:59 +07:00
parent 59a84d948a
commit b01510707c
10 changed files with 190 additions and 12 deletions
@@ -29,7 +29,7 @@ const linkItems: LinkItem[] = [
icon: 'i-lucide-eye',
},
{
label: 'Edit',
label: 'Process',
value: 'edit',
onClick: () => {
edit()
@@ -13,18 +13,14 @@ const props = defineProps<{
<template>
<div class="w-full rounded-md border bg-white p-4 shadow-sm dark:bg-neutral-950">
<!-- Data Pasien -->
<Accordion
type="single"
defaultValue="item-patient"
collapsible
>
<!-- Data Pasien -->
<Accordion type="single" defaultValue="item-patient" collapsible>
<AccordionItem value="item-patient" class="border-none">
<AccordionTrigger class="focus:outline-none focus:ring-0">
<h2 class="mb-4 text-base font-semibold md:text-lg 2xl:text-xl">Data Pasien:</h2>
</AccordionTrigger>
<AccordionContent>
<EncounterQuickInfoFull :data="props.data" />
<EncounterQuickInfoFull :data="props.data" :is-grid="true" />
</AccordionContent>
</AccordionItem>
</Accordion>
@@ -0,0 +1,18 @@
<script setup lang="ts">
// Types
import type { Encounter } from '~/models/encounter'
// Components
import EncounterQuickInfoFull from '~/components/app/encounter/quick-info-full.vue'
const props = defineProps<{
data: Encounter
}>()
</script>
<template>
<div class="w-full rounded-md border bg-white p-4 shadow-sm dark:bg-neutral-950">
<h2 class="mb-4 text-base font-semibold md:text-lg 2xl:text-xl">Data Pasien:</h2>
<EncounterQuickInfoFull :data="props.data" :is-grid="false" />
</div>
</template>
@@ -3,6 +3,7 @@
import { format, parseISO } from 'date-fns'
import { id as localeID } from 'date-fns/locale'
import { getAge } from '~/lib/date'
import { cn } from "~/lib/utils"
// Types
import type { Encounter } from '~/models/encounter'
@@ -10,8 +11,11 @@ import { paymentTypes } from '~/lib/constants.vclaim'
const props = defineProps<{
data: Encounter
isGrid?: boolean
}>()
const isGrid = props.isGrid !== undefined ? props.isGrid : true
// Address
const address = computed(() => {
if (props.data.patient.person.addresses && props.data.patient.person.addresses.length > 0) {
@@ -139,7 +143,7 @@ const bedNumber = computed(() => {
<template>
<!-- 4 Column Grid Layout -->
<div class="grid grid-cols-1 gap-4 sm:grid-cols-4">
<div :class="cn('grid grid-cols-1 gap-4', isGrid && 'sm:grid-cols-4')">
<!-- No. RM -->
<div class="flex gap-1">
<label class="w-[150px] flex-none text-sm font-semibold text-gray-700 dark:text-gray-300">No. RM</label>
@@ -0,0 +1,43 @@
<script setup lang="ts">
import { computed, ref, onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
// Components
import EncounterPatientInfo from '~/components/app/encounter/patient-info.vue'
// Models
import { genEncounter } from '~/models/encounter'
// Handlers
import { getEncounterData } from '~/handlers/encounter-process.handler'
const route = useRoute()
const router = useRouter()
const id = typeof route.params.id == 'string' ? parseInt(route.params.id) : 0
const data = ref<any>(genEncounter())
const isShowPatient = computed(() => data.value && data.value?.patient?.person)
async function getData() {
data.value = await getEncounterData(id)
}
onMounted(async () => {
await getData()
})
function handleClick(type: string) {
if (type === 'draft') {
router.back()
}
}
</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" />
</div>
</template>
+2 -2
View File
@@ -228,9 +228,9 @@ watch(
if (props.type === 'encounter') {
if (recAction.value === 'showDetail') {
navigateTo(`${basePath}/${recId.value}/process`)
navigateTo(`${basePath}/${recId.value}/detail`)
} else if (recAction.value === 'showEdit') {
navigateTo(`${basePath}/${recId.value}/edit`)
navigateTo(`${basePath}/${recId.value}/process`)
} else if (recAction.value === 'showPrint') {
console.log('print')
} else {
@@ -3,7 +3,7 @@ import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
// Components
import EncounterPatientInfo from '~/components/app/encounter/collapsible-patient-info.vue'
import EncounterPatientInfo from '~/components/app/encounter/patient-info-collapsible.vue'
import EncounterHistoryButtonMenu from '~/components/app/encounter/history-button-menu.vue'
import SubMenu from '~/components/pub/my-ui/menus/submenu.vue'
@@ -0,0 +1,39 @@
<script setup lang="ts">
import type { Permission } from '~/models/role'
import { permissions } from '~/const/page-permission/emergency'
import Error from '~/components/pub/my-ui/error/error.vue'
import Content from '~/components/content/encounter/detail.vue'
definePageMeta({
middleware: ['rbac'],
roles: ['emp|doc', 'emp|nur', 'emp|reg', 'emp|pha', 'emp|pay', 'emp|mng'],
title: 'Detail Kunjungan',
contentFrame: 'cf-full-width',
})
// Preps role checking
const roleAccess: Record<string, Permission[]> = permissions['/emergency/encounter'] || {}
const { checkRole, hasReadAccess } = useRBAC()
// Check if user has access to this page
const hasAccess = checkRole(roleAccess)
if (!hasAccess) {
navigateTo('/403')
}
// Define permission-based computed properties
const canRead = hasReadAccess(roleAccess)
// Page needs
const route = useRoute()
useHead({
title: () => `${route.meta.title}`,
})
</script>
<template>
<div v-if="canRead">
<Content />
</div>
<Error v-else :status-code="403" />
</template>
@@ -0,0 +1,39 @@
<script setup lang="ts">
import type { Permission } from '~/models/role'
import { permissions } from '~/const/page-permission/inpatient'
import Error from '~/components/pub/my-ui/error/error.vue'
import Content from '~/components/content/encounter/detail.vue'
definePageMeta({
middleware: ['rbac'],
roles: ['emp|doc', 'emp|nur', 'emp|reg', 'emp|pha', 'emp|pay', 'emp|mng'],
title: 'Detail Kunjungan',
contentFrame: 'cf-full-width',
})
// Preps role checking
const roleAccess: Record<string, Permission[]> = permissions['/inpatient/encounter'] || {}
const { checkRole, hasReadAccess } = useRBAC()
// Check if user has access to this page
const hasAccess = checkRole(roleAccess)
if (!hasAccess) {
navigateTo('/403')
}
// Define permission-based computed properties
const canRead = hasReadAccess(roleAccess)
// Page needs
const route = useRoute()
useHead({
title: () => `${route.meta.title}`,
})
</script>
<template>
<div v-if="canRead">
<Content />
</div>
<Error v-else :status-code="403" />
</template>
@@ -0,0 +1,39 @@
<script setup lang="ts">
import type { Permission } from '~/models/role'
import { permissions } from '~/const/page-permission/outpatient'
import Error from '~/components/pub/my-ui/error/error.vue'
import Content from '~/components/content/encounter/detail.vue'
definePageMeta({
middleware: ['rbac'],
roles: ['emp|doc', 'emp|nur', 'emp|reg', 'emp|pha', 'emp|pay', 'emp|mng'],
title: 'Detail Kunjungan',
contentFrame: 'cf-full-width',
})
// Preps role checking
const roleAccess: Record<string, Permission[]> = permissions['/outpatient/encounter'] || {}
const { checkRole, hasReadAccess } = useRBAC()
// Check if user has access to this page
const hasAccess = checkRole(roleAccess)
if (!hasAccess) {
navigateTo('/403')
}
// Define permission-based computed properties
const canRead = hasReadAccess(roleAccess)
// Page needs
const route = useRoute()
useHead({
title: () => `${route.meta.title}`,
})
</script>
<template>
<div v-if="canRead">
<Content />
</div>
<Error v-else :status-code="403" />
</template>