init doctor page

This commit is contained in:
Khafid Prayoga
2025-08-14 10:49:27 +07:00
parent bcfbc3af67
commit 616c843260
8 changed files with 109 additions and 73 deletions
+37
View File
@@ -0,0 +1,37 @@
<script setup lang="ts">
import Block from '~/components/pub/form/block.vue'
import FieldGroup from '~/components/pub/form/field-group.vue'
import Field from '~/components/pub/form/field.vue'
import Label from '~/components/pub/form/label.vue'
</script>
<template>
<form id="entry-form">
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
<Icon name="i-lucide-user" class="me-2" />
<span class="font-semibold">Tambah</span> Dokter
</div>
<div class="mb-5 border-b border-b-slate-300 pb-3 text-lg xl:text-xl">
<div>
<Block>
<FieldGroup :column="2">
<Label>Nama</Label>
<Field name="name">
<Input type="text" name="name" />
</Field>
</FieldGroup>
<FieldGroup :column="2">
<Label>Nomor RM</Label>
<Field name="name">
<Input type="text" name="name" />
</Field>
</FieldGroup>
</Block>
</div>
</div>
<div class="my-2 flex justify-end py-2">
<PubNavFooterCsd />
</div>
</form>
</template>
+1 -1
View File
@@ -2,5 +2,5 @@
</script>
<template>
<AppPatientEntryForm />
<AppDoctorEntryForm />
</template>
+3 -67
View File
@@ -1,7 +1,5 @@
<script setup lang="ts">
import type { Summary } from '~/components/pub/base/summary-card.type'
import type { HeaderPrep, RefSearchNav } from '~/components/pub/nav/types'
import { Calendar, Hospital, UserCheck, UsersRound } from 'lucide-vue-next'
const data = ref([])
@@ -18,70 +16,19 @@ const refSearchNav: RefSearchNav = {
},
}
// Loading state management
const isLoading = reactive({
summary: false,
table: false,
})
const recId = ref<number>(0)
const recAction = ref<string>('')
const recItem = ref<any>(null)
const hreaderPrep: HeaderPrep = {
title: 'Pasien',
title: 'Doctor',
icon: 'i-lucide-add',
addNav: {
label: 'Tambah',
onClick: () => navigateTo('/patient/add'),
onClick: () => navigateTo('/doctor/add'),
},
}
// Initial/default data structure
const summaryData: Summary[] = [
{
title: 'Total Pasien',
icon: UsersRound,
metric: 23,
trend: 15,
timeframe: 'daily',
},
{
title: 'Pasien Aktif',
icon: UserCheck,
metric: 100,
trend: 9,
timeframe: 'daily',
},
{
title: 'Kunjungan Hari Ini',
icon: Calendar,
metric: 52,
trend: 1,
timeframe: 'daily',
},
{
title: 'Peserta BPJS',
icon: Hospital,
metric: 71,
trend: -3,
timeframe: 'daily',
},
]
// API call function
async function getPatientSummary() {
try {
isLoading.summary = true
await new Promise((resolve) => setTimeout(resolve, 500))
} catch (error) {
console.error('Error fetching patient summary:', error)
// Keep default/existing data on error
} finally {
isLoading.summary = false
}
}
async function getPatientList() {
const resp = await xfetch('/api/v1/patient')
console.log('data patient', resp)
@@ -91,7 +38,6 @@ async function getPatientList() {
}
onMounted(() => {
getPatientSummary()
getPatientList()
})
@@ -102,15 +48,5 @@ provide('rec_item', recItem)
<template>
<PubNavHeaderPrep :prep="{ ...hreaderPrep }" :ref-search-nav="refSearchNav" />
<div class="flex flex-1 flex-col gap-4 md:gap-8">
<div class="grid gap-4 md:grid-cols-2 md:gap-8 lg:grid-cols-4">
<template v-if="isLoading.summary">
<PubBaseSummaryCard v-for="n in 4" :key="n" is-skeleton />
</template>
<template v-else>
<PubBaseSummaryCard v-for="card in summaryData" :key="card.title" :stat="card" />
</template>
</div>
<AppPatientList :data="data" />
</div>
<AppDoctorList :data="data" />
</template>
+8
View File
@@ -9,4 +9,12 @@ export const PAGE_PERMISSIONS = {
billing: ['R'],
management: ['R'],
},
'/doctor': {
doctor: ['C', 'R', 'U', 'D'],
nurse: ['R'],
admisi: ['R'],
pharmacy: ['R'],
billing: ['R'],
management: ['R'],
},
} as const satisfies Record<string, RoleAccess>
+2 -1
View File
@@ -1,3 +1,4 @@
import type { Pinia } from 'pinia'
import { PAGE_PERMISSIONS } from '~/lib/page-permission'
export default defineNuxtRouteMiddleware((to) => {
@@ -5,7 +6,7 @@ export default defineNuxtRouteMiddleware((to) => {
const { $pinia } = useNuxtApp()
if (import.meta.server) {
const authStore = useUserStore($pinia)
const authStore = useUserStore($pinia as Pinia)
// Check specific page permissions if defined in config
const pagePermissions = PAGE_PERMISSIONS[to.path as keyof typeof PAGE_PERMISSIONS]
if (pagePermissions) {
+27 -2
View File
@@ -1,9 +1,34 @@
<script setup lang="ts">
import type { PagePermission } from '~/models/role'
import { PAGE_PERMISSIONS } from '~/lib/page-permission'
definePageMeta({
roles: ['sys', 'doc'],
middleware: ['rbac'],
roles: ['doctor', 'nurse', 'admisi', 'pharmacy', 'billing', 'management'],
pageTitle: 'Doctor',
contentFrame: 'cf-full-width',
})
const roleAccess: PagePermission = PAGE_PERMISSIONS['/doctor']
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>add pasien</div>
<div v-if="canCreate">
<FlowDoctorAdd />
</div>
<PubBaseError v-else :status-code="403" />
</template>
+26 -2
View File
@@ -1,9 +1,33 @@
<script setup lang="ts">
import type { PagePermission } from '~/models/role'
import { PAGE_PERMISSIONS } from '~/lib/page-permission'
definePageMeta({
roles: ['sys', 'doc'],
middleware: ['rbac'],
roles: ['doctor', 'nurse', 'admisi', 'pharmacy', 'billing', 'management'],
pageTitle: 'Doctor',
contentFrame: 'cf-full-width',
})
const roleAccess: PagePermission = PAGE_PERMISSIONS['/doctor']
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)
</script>
<template>
<div>list pasien</div>
<div>
<div v-if="canRead">
<FlowDoctorList />
</div>
<PubBaseError v-else :status-code="403" />
</div>
</template>
+5
View File
@@ -30,6 +30,11 @@
}
]
},
{
"title": "Doctor",
"icon": "i-lucide-cross",
"link": "/doctor"
},
{
"title": "Pasien",
"icon": "i-lucide-users",