✨ feat (rehab): implement rehab registration home component
This commit is contained in:
@@ -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[] = [
|
||||
|
||||
@@ -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>
|
||||
Reference in New Issue
Block a user