feat: enhance SEP entry and detail handling with new link mode and save functionality

This commit is contained in:
riefive
2025-11-28 16:02:11 +07:00
parent e9ed2a3715
commit 973931ec2f
9 changed files with 160 additions and 95 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ const recSepId = inject('rec_sep_id') as Ref<string>
function handleSelection() {
recSepId.value = record.sepNumber || ''
const pathUrl = `/integration/bpjs-vclaim/sep/${record.sepNumber || ''}/detail`
const pathUrl = `/integration/bpjs-vclaim/sep/${record.sepNumber || ''}/link`
router.push({ path: pathUrl })
}
</script>
+38
View File
@@ -47,6 +47,7 @@ const props = defineProps<{
cities: any[]
districts: any[]
specialists?: TreeItem[]
sepNumber?: string
objects?: any
values?: any
}>()
@@ -129,6 +130,14 @@ async function onFetchChildren(parentId: string): Promise<void> {
console.log('onFetchChildren', parentId)
}
const onBack = () => {
emit('event', 'back')
}
const onSaveNumber = () => {
emit('event', 'save-sep-number', { sepNumber: props.sepNumber})
}
// Submit handler
const onSubmit = handleSubmit((values) => {
console.log('✅ Validated form values:', JSON.stringify(values, null, 2))
@@ -966,6 +975,7 @@ onMounted(() => {
<!-- Actions -->
<div class="mt-6 flex justify-end gap-2">
<Button
v-if="props.mode === 'detail'"
variant="ghost"
type="button"
class="h-[40px] min-w-[120px] text-orange-400 hover:bg-green-50"
@@ -978,6 +988,7 @@ onMounted(() => {
Riwayat SEP
</Button>
<Button
v-if="props.mode === 'detail'"
variant="outline"
type="button"
class="h-[40px] min-w-[120px] rounded-md border-orange-400 text-orange-400 hover:bg-green-50 hover:text-orange-400"
@@ -989,6 +1000,7 @@ onMounted(() => {
Preview
</Button>
<Button
v-if="props.mode === 'add'"
type="button"
class="h-[40px] min-w-[120px] text-white"
:disabled="isLoading"
@@ -1000,6 +1012,32 @@ onMounted(() => {
/>
Simpan
</Button>
<Button
v-if="props.mode === 'detail'"
type="button"
class="h-[40px] min-w-[120px] text-white"
:disabled="isLoading"
@click="onBack"
>
<Icon
name="i-lucide-chevron-left"
class="h-5 w-5"
/>
Kembali
</Button>
<Button
v-if="props.mode === 'link'"
type="button"
class="h-[40px] min-w-[120px] text-white"
:disabled="isLoading"
@click="onSaveNumber"
>
<Icon
name="i-lucide-save"
class="h-5 w-5"
/>
Terapkan
</Button>
</div>
</form>
</div>
+13 -2
View File
@@ -9,6 +9,7 @@ import AppViewLetter from '~/components/app/sep/view-letter.vue'
// Handler
import { useIntegrationSepEntry } from '~/handlers/integration-sep-entry.handler'
import { useIntegrationSepDetail } from '~/handlers/integration-sep-detail.handler'
const {
histories,
@@ -55,8 +56,18 @@ const {
handleInit,
} = useIntegrationSepEntry()
const { valueObjects, getSepDetail } = useIntegrationSepDetail()
const props = defineProps<{
mode: 'add' | 'edit' | 'detail' | 'link'
}>()
onMounted(async () => {
await handleInit()
if (['detail', 'link'].includes(props.mode)) {
await getSepDetail()
selectedObjects.value = { ...selectedObjects.value, ...valueObjects.value }
}
})
</script>
@@ -66,10 +77,10 @@ onMounted(async () => {
name="i-lucide-panel-bottom"
class="me-2"
/>
<span class="font-semibold">Tambah</span>
SEP
<span class="font-semibold">{{ ['detail', 'link'].includes(props.mode) ? 'Detail' : 'Tambah' }} SEP</span>
</div>
<AppSepEntryForm
:mode="props.mode"
:is-save-loading="isSaveLoading"
:is-service="isServiceHidden"
:doctors="doctors"
+47 -59
View File
@@ -39,67 +39,55 @@ export function useIntegrationSepDetail() {
if (result.success && result.body?.response) {
const response = result.body.response
sepData.value = response
// Map response to form objects
// patientName.value = objects?.patientName || ''
// nationalIdentity.value = objects?.nationalIdentity || ''
// medicalRecordNumber.value = objects?.medicalRecordNumber || ''
// doctorId.value = objects?.doctorId || ''
// subSpecialistId.value = objects?.subSpecialistId || ''
// registerDate.value = objects?.registerDate || ''
// paymentType.value = objects?.paymentType || ''
// patientCategory.value = objects?.patientCategory || ''
// cardNumber.value = objects?.cardNumber || ''
// sepType.value = objects?.sepType || ''
// sepNumber.value = objects?.sepNumber || ''
// sepReference.value = objects?.sepReference || ''
// sepControlDate.value = objects?.sepControlDate || ''
// sepTrafficStatus.value = objects?.sepTrafficStatus || ''
// diagnosis.value = objects?.diagnosis || ''
// if (Object.keys(response).length > 0) {
// formObjects.value.patientName = response.peserta?.nama || '-'
// formObjects.value.medicalRecordNumber = response.peserta?.noMr || '-'
// formObjects.value.cardNumber = response.peserta?.noKartu || '-'
// formObjects.value.registerDate = response.tglSep || null
// formObjects.value.sepReference = response.noSep || '-'
// formObjects.value.sepControlDate = response.tglSep || null
// formObjects.value.sepTrafficStatus = response.nmstatusKecelakaan || '-'
// formObjects.value.diagnosis = response.diagnosa || '-'
// vclaimReference.value = {
// noSep: response.noSep || sepNumberValue.trim(),
// tglRujukan: response.tglSep ? new Date(response.tglSep).toISOString() : null,
// ppkDirujuk: response.noRujukan || 'rssa',
// jnsPelayanan:
// response.jnsPelayanan === 'Rawat Jalan' ? '2' : response.jnsPelayanan === 'Rawat Inap' ? '1' : null,
// catatan: response.catatan || '',
// diagRujukan: response.diagnosa || '',
// tipeRujukan: response.tujuanKunj?.kode ?? '0',
// poliRujukan: response.poli || '',
// user: userStore.user?.user_name || '',
// }
// }
valueObjects.value = {
noSep: response.noSep || noSep.value,
tglRujukan: response.tglSep ? new Date(response.tglSep).toISOString().split('T')[0] : '',
ppkDirujuk: response.noRujukan || '',
jnsPelayanan: mapServiceCodeToLabel(response.jnsPelayanan),
catatan: response.catatan || '',
diagRujukan: response.diagnosa || '',
tipeRujukan: response.tujuanKunj?.kode ?? '0',
poliRujukan: response.poli || '',
user: response.dpjp?.kdDPJP || response.dpjp?.nmDPJP || '',
// Additional fields dari response
patientName: response.peserta?.nama || '-',
medicalRecordNumber: response.peserta?.noMr || '-',
sepNumber: response.noSep || noSep.value,
eSep: response.eSEP === 'True' ? 'yes' : 'no',
serviceType: response.jnsPelayanan === 'Rawat Jalan' ? '2' : response.jnsPelayanan === 'Rawat Inap' ? '1' : null,
sepDate: response.tglSep ? new Date(response.tglSep).toISOString().split('T')[0] : '',
cardNumber: response.peserta?.noKartu || '-',
diagnosis: response.diagnosa || '-',
sepReference: response.noSep || '-',
sepControlDate: response.tglSep || null,
sepTrafficStatus: response.nmstatusKecelakaan || '-',
kelasRawat: response.kelasRawat || '-',
referralNumber: response.noRujukan || '-',
patientName: response.peserta?.nama || '-',
phoneNumber: response.peserta?.noTelp || '-',
medicalRecordNumber: response.peserta?.noMr || '-',
memberInsurance: response.peserta?.asuransi || '-',
memberClass: response.peserta?.hakKelas || '-',
memberGender: response.peserta?.kelamin || '-',
memberBirthDate: response.peserta?.tglLahir || '-',
memberType: response.peserta?.jnsPeserta || '-',
referralLetterNumber: response.noRujukan || '-',
initialDiagnosis: response.diagnosa || '-',
attendingDoctor: response.dpjp?.kdDPJP || '-',
attendingDoctorName: response.dpjp?.nmDPJP || '-',
polyName: response.poli || '-',
cob: response.cob === '1' ? 'yes' : 'no',
cataract: response.katarak === '1' ? 'yes' : 'no',
clinicExcecutive: response.poliEksekutif === '1' ? 'yes' : 'no',
procedureType: response.flagProcedure?.kode || '-',
procedureTypeName: response.flagProcedure?.nama || '-',
supportCode: response.kdPenunjang?.kode || '-',
supportCodeName: response.kdPenunjang?.nama || '-',
note: response.catatan || response.informasi || '-',
classLevel: response.kelasRawat || '-',
classLevelUpgrade: response.klsRawat?.klsRawatNaik || '-',
classPaySource: response.klsRawat?.pembiayaan || '-',
responsiblePerson: response.klsRawat?.penanggungJawab || response.penjamin || '-',
purposeOfVisit: response.tujuanKunj?.kode || '-',
purposeOfVisitName: response.tujuanKunj?.nama || '-',
serviceAssessment: response.assestmenPel?.kode || '-',
serviceAssessmentName: response.assestmenPel?.nama || '-',
trafficAccident: response.nmstatusKecelakaan || '',
trafficAccidentCode: response.kdStatusKecelakaan || '',
lpNumber: response.kontrol?.noSurat || '-',
accidentDate: response.lokasiKejadian?.tglKejadian || '-',
accidentNote: response.lokasiKejadian?.ketKejadian || '-',
accidentProvince: response.lokasiKejadian?.kdProp || '-',
accidentCity: response.lokasiKejadian?.kdKab || '-',
accidentDistrict: response.lokasiKejadian?.kdKec || '-',
accidentLocation: response.lokasiKejadian?.lokasi || '-',
suplesi: response.jnsPelayanan === 'Rawat Jalan' ? 'yes' : 'no',
suplesiNumber: response.jnsPelayanan === 'Rawat Jalan' ? response.noRujukan || '-' : '-',
controlLetterNumber: response.kontrol?.noSurat || '-',
controlLetterDoctor: response.kontrol?.kdDokter || '-',
controlLetterDoctorName: response.kontrol?.nmDokter || '-',
}
} else {
toast({
@@ -442,6 +442,9 @@ export function useIntegrationSepEntry() {
if (menu === 'back') {
navigateTo('/integration/bpjs-vclaim/sep')
}
if (menu === 'save-sep-number') {
navigateTo({ path: resourcePath.value, query: { 'sep-number': value.sepNumber || '' } })
}
if (menu === 'save-sep') {
isSaveLoading.value = true
@@ -0,0 +1,26 @@
<script setup lang="ts">
import Error from '~/components/pub/my-ui/error/error.vue'
import Content from '~/components/content/sep/entry.vue'
definePageMeta({
middleware: [],
roles: ['doctor', 'nurse', 'admisi', 'pharmacy', 'billing', 'management'],
title: 'Detail SEP',
contentFrame: 'cf-full-width',
})
const route = useRoute()
useHead({
title: () => route.meta.title as string,
})
const canCreate = true
</script>
<template>
<div v-if="canCreate">
<Content mode="detail" />
</div>
<Error v-else :status-code="403" />
</template>
@@ -0,0 +1,26 @@
<script setup lang="ts">
import Error from '~/components/pub/my-ui/error/error.vue'
import Content from '~/components/content/sep/entry.vue'
definePageMeta({
middleware: [],
roles: ['doctor', 'nurse', 'admisi', 'pharmacy', 'billing', 'management'],
title: 'Detail SEP',
contentFrame: 'cf-full-width',
})
const route = useRoute()
useHead({
title: () => route.meta.title as string,
})
const canCreate = true
</script>
<template>
<div v-if="canCreate">
<Content mode="link" />
</div>
<Error v-else :status-code="403" />
</template>
@@ -1,7 +1,6 @@
<script setup lang="ts">
import type { PagePermission } from '~/models/role'
import Error from '~/components/pub/my-ui/error/error.vue'
import { PAGE_PERMISSIONS } from '~/lib/page-permission'
import Content from '~/components/content/sep/entry.vue'
definePageMeta({
middleware: [],
@@ -16,26 +15,12 @@ useHead({
title: () => route.meta.title as string,
})
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 = true // hasCreateAccess(roleAccess)
const canCreate = true
</script>
<template>
<div v-if="canCreate">
<ContentSepEntry />
<Content mode="add" />
</div>
<Error v-else :status-code="403" />
</template>
@@ -1,7 +1,6 @@
<script setup lang="ts">
import type { PagePermission } from '~/models/role'
import Error from '~/components/pub/my-ui/error/error.vue'
import { PAGE_PERMISSIONS } from '~/lib/page-permission'
import Content from '~/components/content/sep/list.vue'
definePageMeta({
middleware: ['rbac'],
@@ -16,24 +15,13 @@ useHead({
title: () => route.meta.title as string,
})
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 = true // hasReadAccess(roleAccess)
const canRead = true
</script>
<template>
<div>
<div v-if="canRead">
<ContentSepList />
<Content />
</div>
<Error v-else :status-code="403" />
</div>