init specialist feature

This commit is contained in:
Khafid Prayoga
2025-09-11 14:46:50 +07:00
parent 26b0cf12e3
commit 865bbbdce9
5 changed files with 28 additions and 93 deletions
+4 -33
View File
@@ -6,30 +6,20 @@ import Field from '~/components/pub/custom-ui/form/field.vue'
import Label from '~/components/pub/custom-ui/form/label.vue'
import Select from '~/components/pub/custom-ui/form/select.vue'
interface InstallationFormData {
interface SpecialistFormData {
name: string
code: string
encounterClassCode: string
}
const props = defineProps<{
installation: {
msg: {
placeholder: string
}
items: {
value: string
label: string
code: string
}[]
}
schema: any
initialValues?: Partial<InstallationFormData>
initialValues?: Partial<SpecialistFormData>
errors?: FormErrors
}>()
const emit = defineEmits<{
'submit': [values: InstallationFormData, resetForm: () => void]
'submit': [values: SpecialistFormData, resetForm: () => void]
'cancel': [resetForm: () => void]
}>()
@@ -37,7 +27,7 @@ const formSchema = toTypedSchema(props.schema)
// Form submission handler
function onSubmitForm(values: any, { resetForm }: { resetForm: () => void }) {
const formData: InstallationFormData = {
const formData: SpecialistFormData = {
name: values.name || '',
code: values.code || '',
encounterClassCode: values.encounterClassCode || '',
@@ -89,25 +79,6 @@ function onCancelForm({ resetForm }: { resetForm: () => void }) {
</FormField>
</Field>
</FieldGroup>
<FieldGroup>
<Label label-for="parentId">Encounter Class</Label>
<Field id="encounterClassCode" :errors="errors">
<FormField v-slot="{ componentField }" name="encounterClassCode">
<FormItem>
<FormControl>
<Select
v-bind="componentField"
:items="installation.items"
:placeholder="installation.msg.placeholder"
/>
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</Field>
</FieldGroup>
</div>
</div>
+1 -19
View File
@@ -15,7 +15,7 @@ const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/dat
export const cols: Col[] = [{ width: 100 }, {}, {}, {}, { width: 50 }]
export const header: Th[][] = [
[{ label: 'Id' }, { label: 'Nama' }, { label: 'Kode' }, { label: 'Encounter Class' }, { label: '' }],
[{ label: 'Id' }, { label: 'Name' }, { label: 'Code' }, { label: 'Unit' }, { label: '' }],
]
export const keys = ['id', 'name', 'cellphone', 'religion_code', 'action']
@@ -30,21 +30,6 @@ export const funcParsed: RecStrFuncUnknown = {
const recX = rec as SmallDetailDto
return `${recX.firstName} ${recX.lastName || ''}`.trim()
},
identity_number: (rec: unknown): unknown => {
const recX = rec as SmallDetailDto
if (recX.identity_number?.substring(0, 5) === 'BLANK') {
return '(TANPA NIK)'
}
return recX.identity_number
},
inPatient_itemPrice: (rec: unknown): unknown => {
const recX = rec as SmallDetailDto
return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID')
},
outPatient_itemPrice: (rec: unknown): unknown => {
const recX = rec as SmallDetailDto
return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID')
},
}
export const funcComponent: RecStrFuncComponent = {
@@ -62,7 +47,4 @@ export const funcComponent: RecStrFuncComponent = {
}
export const funcHtml: RecStrFuncUnknown = {
patient_address(_rec) {
return '-'
},
}
+7 -23
View File
@@ -1,37 +1,21 @@
import * as z from 'zod'
export const installationConf = {
msg: {
placeholder: '---pilih encounter class (fhir7)',
},
items: [
{ value: '1', label: 'Ambulatory', code: 'AMB' },
{ value: '2', label: 'Inpatient', code: 'IMP' },
{ value: '3', label: 'Emergency', code: 'EMER' },
{ value: '4', label: 'Observation', code: 'OBSENC' },
{ value: '5', label: 'Pre-admission', code: 'PRENC' },
{ value: '6', label: 'Short Stay', code: 'SS' },
{ value: '7', label: 'Virtual', code: 'VR' },
{ value: '8', label: 'Home Health', code: 'HH' },
],
}
export const schemaConf = z.object({
name: z
.string({
required_error: 'Nama instalasi harus diisi',
required_error: 'Nama spesialisasi harus diisi',
})
.min(3, 'Nama instalasi minimal 3 karakter'),
.min(3, 'Nama spesialisasi minimal 3 karakter'),
code: z
.string({
required_error: 'Kode instalasi harus diisi',
required_error: 'Kode spesialisasi harus diisi',
})
.min(3, 'Kode instalasi minimal 3 karakter'),
.min(3, 'Kode spesialisasi minimal 3 karakter'),
encounterClassCode: z
unitId: z
.string({
required_error: 'Kelompok encounter class harus dipilih',
required_error: 'Unit harus dipilih',
})
.min(1, 'Kelompok encounter class harus dipilih'),
.min(1, 'Unit harus dipilih'),
})
+14 -16
View File
@@ -1,12 +1,12 @@
<script setup lang="ts">
import type { HeaderPrep } from '~/components/pub/custom-ui/data/types'
import AppInstallationEntryForm from '~/components/app/installation/entry-form.vue'
import AppSpecialistEntryForm from '~/components/app/specialist/entry-form.vue'
import Dialog from '~/components/pub/base/modal/dialog.vue'
import RecordConfirmation from '~/components/pub/custom-ui/confirmation/record-confirmation.vue'
import { ActionEvents } from '~/components/pub/custom-ui/data/types'
import Header from '~/components/pub/custom-ui/nav-header/header.vue'
import { usePaginatedList } from '~/composables/usePaginatedList'
import { installationConf, schemaConf } from './entry'
import { schemaConf } from './entry'
// #region State & Computed
// Dialog state
@@ -18,7 +18,7 @@ const recId = ref<number>(0)
const recAction = ref<string>('')
const recItem = ref<any>(null)
async function fetchInstallationData(params: any) {
async function fetchSpecialistData(params: any) {
const endpoint = transform('/api/v1/patient', params)
return await xfetch(endpoint)
}
@@ -31,14 +31,14 @@ const {
searchInput,
handlePageChange,
handleSearch,
fetchData: getInstallationList,
fetchData: getSpecialistList,
} = usePaginatedList({
fetchFn: fetchInstallationData,
entityName: 'installation',
fetchFn: fetchSpecialistData,
entityName: 'specialist',
})
const headerPrep: HeaderPrep = {
title: 'Instalasi',
title: 'Specialist',
icon: 'i-lucide-box',
refSearchNav: {
placeholder: 'Cari (min. 3 karakter)...',
@@ -56,7 +56,7 @@ const headerPrep: HeaderPrep = {
},
},
addNav: {
label: 'Tambah Instalasi',
label: 'Tambah Specialist',
icon: 'i-lucide-send',
onClick: () => {
isFormEntryDialogOpen.value = true
@@ -83,7 +83,7 @@ async function handleDeleteRow(record: any) {
// })
// Refresh data setelah berhasil delete
await getInstallationList()
await getSpecialistList()
// TODO: Show success message
console.log('Record deleted successfully')
@@ -126,7 +126,7 @@ async function onSubmitForm(values: any, resetForm: () => void) {
isSuccess = true
// Refresh data after successful submission
await getInstallationList()
await getSpecialistList()
// TODO: Show success message
console.log('Installation created successfully')
@@ -179,15 +179,13 @@ function handleCancelConfirmation() {
<template>
<div class="rounded-md border p-4">
<Header v-model="searchInput" :prep="headerPrep" @search="handleSearch" />
<AppInstallationList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
<AppSpecialistList :data="data" :pagination-meta="paginationMeta" @page-change="handlePageChange" />
<Dialog v-model:open="isFormEntryDialogOpen" title="Tambah Instalasi" size="lg" prevent-outside>
<AppInstallationEntryForm :installation="installationConf" :schema="schemaConf"
:initial-values="{ name: '', code: '', encounterClassCode: '' }" @submit="onSubmitForm"
@cancel="onCancelForm" />
<Dialog v-model:open="isFormEntryDialogOpen" :title="headerPrep.addNav?.label!" size="lg" prevent-outside>
<AppSpecialistEntryForm :schema="schemaConf" :initial-values="{ name: '', code: '', encounterClassCode: '' }"
@submit="onSubmitForm" @cancel="onCancelForm" />
</Dialog>
<!-- Record Confirmation Modal -->
<RecordConfirmation v-model:open="isRecordConfirmationOpen" action="delete" :record="recItem"
@confirm="handleConfirmDelete" @cancel="handleCancelConfirmation">
<template #default="{ record }">
@@ -6,7 +6,7 @@ import Error from '~/components/pub/base/error/error.vue'
definePageMeta({
// middleware: ['rbac'],
roles: ['doctor', 'nurse', 'admisi', 'pharmacy', 'billing', 'management'],
title: 'List Unit',
title: 'List Specialist',
contentFrame: 'cf-full-width',
})
@@ -34,7 +34,7 @@ const canRead = true
<template>
<div>
<div v-if="canRead">
<ContentUnitList />
<ContentSpecialistList />
</div>
<Error v-else :status-code="403" />
</div>