feat (rehab): implement rehab registration home component

This commit is contained in:
Abizrh
2025-09-23 23:05:22 +07:00
parent 03697f9cea
commit 887db6f2a2
7 changed files with 287 additions and 42 deletions
+1 -1
View File
@@ -10,7 +10,7 @@ import { defineAsyncComponent } from 'vue'
type SmallDetailDto = any
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue'))
const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-pdud.vue'))
const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
export const cols: Col[] = [
+75
View File
@@ -0,0 +1,75 @@
<script setup lang="ts">
interface PatientData {
noRm: string
nama: string
alamat: string
tanggalKunjungan: string
klinik: string
tanggalLahir: string
jenisKelamin: string
jenisPembayaran: string
noBilling: string
dpjp: string
}
defineProps<{
data: PatientData
}>()
</script>
<template>
<div class="w-full rounded-md border bg-white p-4 shadow-sm">
<!-- Data Pasien -->
<h2 class="mb-2 text-base font-semibold">Data Pasien:</h2>
<div class="grid grid-cols-1 gap-y-2 text-sm md:grid-cols-2 lg:grid-cols-3">
<!-- col 1 -->
<div class="grid grid-cols-[140px_auto]">
<span class="font-medium">No. RM</span>
<span>: {{ data.noRm }}</span>
</div>
<div class="grid grid-cols-[140px_auto]">
<span class="font-medium">Tanggal Kunjungan</span>
<span>: {{ data.tanggalKunjungan }}</span>
</div>
<div class="grid grid-cols-[100px_auto]">
<span class="font-medium">Klinik</span>
<span>: {{ data.klinik }}</span>
</div>
<!-- col 2 -->
<div class="grid grid-cols-[140px_auto]">
<span class="font-medium">Nama Pasien</span>
<span>: {{ data.nama }}</span>
</div>
<div class="grid grid-cols-[140px_auto]">
<span class="font-medium">Tanggal Lahir</span>
<span>: {{ data.tanggalLahir }}</span>
</div>
<div class="grid grid-cols-[140px_auto]">
<span class="font-medium">Jenis Pembayaran</span>
<span>: {{ data.jenisPembayaran }}</span>
</div>
<!-- col 3 -->
<div class="grid grid-cols-[140px_auto]">
<span class="font-medium">Alamat</span>
<span>: {{ data.alamat }}</span>
</div>
<div class="grid grid-cols-[140px_auto]">
<span class="font-medium">Jenis Kelamin</span>
<span>: {{ data.jenisKelamin }}</span>
</div>
<div class="grid grid-cols-[140px_auto]">
<span class="font-medium">No. Billing</span>
<span>: {{ data.noBilling }}</span>
</div>
<!-- full row -->
<div class="grid grid-cols-[140px_auto] lg:col-span-3">
<span class="font-medium">DPJP</span>
<span>: {{ data.dpjp }}</span>
</div>
</div>
</div>
</template>
@@ -59,10 +59,13 @@ onMounted(() => {
watch(
() => recAction.value,
() => {
console.log('recAction.value', recAction.value)
if (recAction.value === 'showDetail') {
navigateTo(`/rehab/encounter/${recId.value}/detail`)
} else if (recAction.value === 'showEdit') {
navigateTo(`/rehab/encounter/${recId.value}/edit`)
} else if (recAction.value === 'showProcess') {
navigateTo(`/rehab/encounter/${recId.value}/process`)
} else {
// handle other actions
}
@@ -1,57 +1,86 @@
<script setup lang="ts">
import { ref } from 'vue'
import ListProsedur from './sep-prosedur/list.vue'
const tabs = [
{ value: 'sep-prosedur', label: 'Sep Prosedur', component: ListProsedur },
{ value: 'konsultasi', label: 'Konsultasi' },
{ value: 'surat', label: 'Surat Kontrol' },
{ value: 'catatan', label: 'Catatan Perkembangan Pasien' },
{ value: 'medis', label: 'Pengkajian Awal Medis & Asesmen Fungsi' },
{ value: 'keperawatan', label: 'Pengkajian Awal Keperawatan' },
interface TabItem {
value: string
label: string
component?: any
props?: Record<string, any>
}
const tabs: TabItem[] = [
{ value: 'status', label: 'Status Masuk/Keluar' },
{ value: 'medis', label: 'Pengkajian Awal Medis' },
{ value: 'rehab', label: 'Pengkajian Awal Medis Rehabilitasi Medis' },
{ value: 'fungsi', label: 'Asesmen Fungsi', component: ListProsedur },
{ value: 'protokol', label: 'Protokol Terapi' },
{ value: 'tindakan', label: 'Tindakan' },
{ value: 'edukasi', label: 'Asesmen Kebutuhan Edukasi' },
{ value: 'consent', label: 'General Consent' },
{ value: 'cprj', label: 'CPRJ' },
{ value: 'obat', label: 'Order Obat' },
{ value: 'bmhp', label: 'Order BMHP & Alkes' },
{ value: 'radiologi', label: 'Pemeriksaan Radiologi' },
{ value: 'labpk', label: 'Pemeriksaan Lab PK' },
{ value: 'alkes', label: 'Order Alkes' },
{ value: 'radiologi', label: 'Order Radiologi' },
{ value: 'labpk', label: 'Order Lab PK' },
{ value: 'labmikro', label: 'Order Lab Mikro' },
{ value: 'labpa', label: 'Order Lab PA' },
{ value: 'ambulance', label: 'Ambulance' },
{ value: 'ruangtindakan', label: 'Order Ruang Tindakan' },
{ value: 'hasil', label: 'Hasil Penunjang' },
{ value: 'konsultasi', label: 'Konsultasi' },
{ value: 'resume', label: 'Resume' },
{ value: 'kontrol', label: 'Surat Kontrol' },
{ value: 'skrining', label: 'Skrinning MPP' },
{ value: 'upload', label: 'Upload Dokumen Pendukung' },
]
const data = {
noRm: 'RM21123',
nama: 'Ahmad Sutanto',
alamat: 'Jl Jaksa Agung Suprapto No. 12, Jakarta',
tanggalKunjungan: '23 April 2024',
klinik: 'Bedah',
tanggalLahir: '23 April 1990 (25 Tahun)',
jenisKelamin: 'Laki-laki',
jenisPembayaran: 'JKN',
noBilling: '223332',
dpjp: 'dr. Syaifullah, Sp.OT(K)',
}
const activeTab = ref('fungsi')
</script>
<template>
<Tabs default-value="sep-prosedur" class="w-full">
<div class="scrollbar-hide overflow-x-auto">
<TabsList class="inline-flex gap-2 whitespace-nowrap bg-transparent p-2">
<TabsTrigger
v-for="tab in tabs"
:key="tab.value"
:value="tab.value"
class="flex-shrink-0 rounded-full px-4 py-2 text-sm font-medium data-[state=active]:bg-green-600 data-[state=inactive]:bg-gray-100 data-[state=active]:text-white data-[state=inactive]:text-gray-700"
>
{{ tab.label }}
</TabsTrigger>
</TabsList>
<div class="w-full">
<div class="mb-4">
<button
class="flex items-center gap-2 rounded-full border border-orange-400 bg-orange-50 px-3 py-1 text-sm font-medium text-orange-600 hover:bg-orange-100"
>
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
</svg>
Kembali ke Daftar Kunjungan
</button>
</div>
<div class="mt-4">
<TabsContent v-for="tab in tabs" :key="`content-${tab.value}`" :value="tab.value">
<div class="rounded-md border p-4">
<component :is="tab.component" v-bind="tab.props || {}" :label="tab.label" />
</div>
</TabsContent>
<AppPatientQuickInfo :data="data" />
<div class="mt-4 flex flex-wrap gap-2 rounded-md border bg-white p-4 shadow-sm">
<button
v-for="tab in tabs"
:key="tab.value"
:data-active="activeTab === tab.value"
class="flex-shrink-0 rounded-full px-4 py-2 text-sm font-medium transition data-[active=false]:bg-gray-100 data-[active=true]:bg-green-600 data-[active=false]:text-gray-700 data-[active=true]:text-white"
@click="activeTab = tab.value"
>
{{ tab.label }}
</button>
</div>
</Tabs>
<div class="mt-4 rounded-md border p-4">
<component
:is="tabs.find((t) => t.value === activeTab)?.component"
v-if="tabs.find((t) => t.value === activeTab)?.component"
v-bind="tabs.find((t) => t.value === activeTab)?.props || {}"
:label="tabs.find((t) => t.value === activeTab)?.label"
/>
</div>
</div>
</template>
<style>
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
</style>
@@ -0,0 +1,96 @@
<script setup lang="ts">
import type { LinkItem, ListItemDto } from './types'
import { ActionEvents } from './types'
const props = defineProps<{
rec: ListItemDto
}>()
const recId = inject<Ref<number>>('rec_id')!
const recAction = inject<Ref<string>>('rec_action')!
const recItem = inject<Ref<any>>('rec_item')!
function detail() {
recId.value = props.rec.id || 0
recAction.value = ActionEvents.showDetail
recItem.value = props.rec
}
function process() {
recId.value = props.rec.id || 0
recAction.value = ActionEvents.showProcess
recItem.value = props.rec
}
function edit() {
recId.value = props.rec.id || 0
recAction.value = ActionEvents.showEdit
recItem.value = props.rec
}
function del() {
recId.value = props.rec.id || 0
recAction.value = ActionEvents.showConfirmDelete
recItem.value = props.rec
}
const linkItems: LinkItem[] = [
{
label: 'Proses',
onClick: () => {
process()
},
icon: 'i-lucide-file',
},
{
label: 'Detail',
onClick: () => {
detail()
},
icon: 'i-lucide-eye',
},
{
label: 'Edit',
onClick: () => {
edit()
},
icon: 'i-lucide-pencil',
},
{
label: 'Hapus',
onClick: () => {
del()
},
icon: 'i-lucide-trash',
},
]
</script>
<template>
<div>
<DropdownMenu>
<DropdownMenuTrigger as-child>
<SidebarMenuButton
size="lg"
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white"
>
<Icon name="i-lucide-chevrons-up-down" class="ml-auto size-4" />
</SidebarMenuButton>
</DropdownMenuTrigger>
<DropdownMenuContent class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg bg-white" align="end">
<DropdownMenuGroup>
<DropdownMenuItem
v-for="item in linkItems"
:key="item.label"
v-slot="{ active }"
class="hover:bg-gray-100"
@click="item.onClick"
>
<Icon :name="item.icon" />
<span :class="active ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
</DropdownMenuItem>
</DropdownMenuGroup>
</DropdownMenuContent>
</DropdownMenu>
</div>
</template>
@@ -105,4 +105,5 @@ export const ActionEvents = {
showConfirmDelete: 'showConfirmDel',
showEdit: 'showEdit',
showDetail: 'showDetail',
showProcess: 'showProcess',
}
@@ -0,0 +1,41 @@
<script setup lang="ts">
import type { PagePermission } from '~/models/role'
import Error from '~/components/pub/base/error/error.vue'
import { PAGE_PERMISSIONS } from '~/lib/page-permission'
definePageMeta({
middleware: ['rbac'],
roles: ['doctor', 'nurse', 'admisi', 'pharmacy', 'billing', 'management'],
title: 'Tambah Kunjungan',
contentFrame: 'cf-full-width',
})
const route = useRoute()
useHead({
title: () => route.meta.title,
})
const roleAccess: PagePermission = PAGE_PERMISSIONS['/rehab/encounter']
const { checkRole, hasCreateAccess } = useRBAC()
// Check if user has access to this page
const hasAccess = checkRole(roleAccess)
if (!hasAccess) {
throw createError({
statusCode: 403,
statusMessage: 'Access denied',
})
}
// Define permission-based computed properties
const canCreate = hasCreateAccess(roleAccess)
</script>
<template>
<div v-if="canCreate">
<ContentRehabRegistrationHome />
</div>
<Error v-else :status-code="403" />
</template>