feat(sep): add form support code

This commit is contained in:
riefive
2025-10-22 13:38:17 +07:00
parent d11b22dc05
commit baad005522
5 changed files with 263 additions and 110 deletions

No files matched your search

+159 -55
View File
@@ -19,6 +19,7 @@ import type { PatientEntity } from '~/models/patient'
// Helpers
import { toTypedSchema } from '@vee-validate/zod'
import { useForm } from 'vee-validate'
import { se } from "date-fns/locale"
const props = defineProps<{
isLoading?: boolean
@@ -26,6 +27,12 @@ const props = defineProps<{
doctors: any[]
diagnoses: any[]
facilities: any[]
serviceTypes: any[]
registerMethods: any[]
accidents: any[]
purposes: any[]
procedures: any[]
assessments: any[]
supportCodes: any[]
patient?: PatientEntity | null | undefined
values?: any
@@ -39,11 +46,6 @@ const emit = defineEmits<{
const isLoading = props.isLoading !== undefined ? props.isLoading : false
const isReadonly = props.isReadonly !== undefined ? props.isReadonly : false
const admissionTypes = [
{ value: '1', label: 'Kontrol' },
{ value: '2', label: 'Rujukan' },
]
// Validation schema (moved to shared file)
const { handleSubmit, errors, defineField, meta } = useForm<IntegrationBpjsFormData>({
validationSchema: toTypedSchema(IntegrationBpjsSchema),
@@ -51,6 +53,7 @@ const { handleSubmit, errors, defineField, meta } = useForm<IntegrationBpjsFormD
// Bind fields and extract attrs for consistent Field pattern
const [sepDate, sepDateAttrs] = defineField('sepDate')
const [serviceType, serviceTypeAttrs] = defineField('serviceType')
const [admissionType, admissionTypeAttrs] = defineField('admissionType')
const [bpjsNumber, bpjsNumberAttrs] = defineField('bpjsNumber')
const [nationalId, nationalIdAttrs] = defineField('nationalId')
@@ -59,6 +62,7 @@ const [patientName, patientNameAttrs] = defineField('patientName')
const [phoneNumber, phoneNumberAttrs] = defineField('phoneNumber')
const [referralLetterNumber, referralLetterNumberAttrs] = defineField('referralLetterNumber')
const [referralLetterDate, referralLetterDateAttrs] = defineField('referralLetterDate')
const [fromClinic, fromClinicAttrs] = defineField('fromClinic')
const [destinationClinic, destinationClinicAttrs] = defineField('destinationClinic')
const [attendingDoctor, attendingDoctorAttrs] = defineField('attendingDoctor')
const [initialDiagnosis, initialDiagnosisAttrs] = defineField('initialDiagnosis')
@@ -68,6 +72,13 @@ const [clinicExcecutive, clinicExcecutiveAttrs] = defineField('clinicExcecutive'
const [procedureType, procedureTypeAttrs] = defineField('procedureType')
const [supportCode, supportCodeAttrs] = defineField('supportCode')
const [note, noteAttrs] = defineField('note')
const [accident, accidentAttrs] = defineField('trafficAccident')
const [purposeOfVisit, purposeOfVisitAttrs] = defineField('purposeOfVisit')
const [serviceAssessment, serviceAssessmentAttrs] = defineField('serviceAssessment')
const titleLetterNumber = computed(() => (admissionType.value === '3' ? 'Surat Kontrol' : 'Surat Rujukan'))
const titleLetterDate = computed(() =>
admissionType.value === '3' ? 'Tanggal Surat Kontrol' : 'Tanggal Surat Rujukan',
)
// Submit handler
const onSubmit = handleSubmit((values) => {
@@ -115,6 +126,23 @@ watch(props, (value) => {
/>
</Field>
</Cell>
<Cell>
<Label height="compact">Pelayanan</Label>
<Field :errMessage="errors.serviceType">
<Select
id="serviceType"
icon-name="i-lucide-chevron-down"
v-model="serviceType"
v-bind="serviceTypeAttrs"
:items="serviceTypes"
:disabled="isLoading || isReadonly"
placeholder="Pilih Pelayanan"
@change="emit('event', 'service-type', $event)"
/>
</Field>
</Cell>
<Cell>
<Label height="compact">Jalur</Label>
<Field :errMessage="errors.admissionType">
@@ -123,7 +151,7 @@ watch(props, (value) => {
icon-name="i-lucide-chevron-down"
v-model="admissionType"
v-bind="admissionTypeAttrs"
:items="admissionTypes"
:items="registerMethods"
:disabled="isLoading || isReadonly"
placeholder="Pilih jalur"
@change="emit('event', 'admission-type', $event)"
@@ -171,6 +199,7 @@ watch(props, (value) => {
/>
</Field>
</Cell>
<Cell>
<Label height="compact">
No. KTP
@@ -185,6 +214,7 @@ watch(props, (value) => {
/>
</Field>
</Cell>
<Cell>
<Label height="compact">
No. RM
@@ -199,6 +229,7 @@ watch(props, (value) => {
/>
</Field>
</Cell>
<Cell>
<Label height="compact">
Nama Pasien
@@ -213,6 +244,7 @@ watch(props, (value) => {
/>
</Field>
</Cell>
<Cell>
<Label height="compact">
No. Telepon
@@ -241,7 +273,7 @@ watch(props, (value) => {
>
<Cell>
<Label height="compact">
No. Surat Kontrol
{{ titleLetterNumber }}
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.referralLetterNumber">
@@ -268,9 +300,10 @@ watch(props, (value) => {
</div>
</Field>
</Cell>
<Cell>
<Label height="compact">
Tanggal Surat Kontrol
{{ titleLetterDate }}
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.referralLetterDate">
@@ -278,30 +311,11 @@ watch(props, (value) => {
id="referralLetterDate"
v-model="referralLetterDate"
v-bind="referralLetterDateAttrs"
:disabled="isLoading || isReadonly"
:disabled="true"
placeholder="Pilih tanggal surat kontrol"
/>
</Field>
</Cell>
<Cell>
<Label height="compact">
Klinik Tujuan
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.destinationClinic">
<Combobox
id="destinationClinic"
v-model="destinationClinic"
v-bind="destinationClinicAttrs"
:items="facilities"
:is-disabled="isLoading || isReadonly"
placeholder="Pilih Klinik"
search-placeholder="Cari Klinik"
empty-message="Item tidak ditemukan"
@update:searchText="emit('fetch', { menu: 'destinationClinic', value: $event })"
/>
</Field>
</Cell>
<Cell>
<Label height="compact">
@@ -332,6 +346,46 @@ watch(props, (value) => {
</Field>
</Cell>
<Cell>
<Label height="compact">
Faskes Asal
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.fromClinic">
<Combobox
id="fromClinic"
v-model="fromClinic"
v-bind="fromClinicAttrs"
:items="facilities"
:is-disabled="isLoading || isReadonly"
placeholder="Pilih Asal"
search-placeholder="Cari Asal"
empty-message="Item tidak ditemukan"
@update:searchText="emit('fetch', { menu: 'clinic', value: $event })"
/>
</Field>
</Cell>
<Cell>
<Label height="compact">
Klinik Tujuan
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.destinationClinic">
<Combobox
id="destinationClinic"
v-model="destinationClinic"
v-bind="destinationClinicAttrs"
:items="facilities"
:is-disabled="isLoading || isReadonly"
placeholder="Pilih Klinik"
search-placeholder="Cari Klinik"
empty-message="Item tidak ditemukan"
@update:searchText="emit('fetch', { menu: 'clinic', value: $event })"
/>
</Field>
</Cell>
<Cell>
<Label height="compact">
DPJP
@@ -347,7 +401,7 @@ watch(props, (value) => {
placeholder="Pilih DPJP"
search-placeholder="Cari DPJP"
empty-message="Item tidak ditemukan"
@update:searchText="emit('fetch', { menu: 'attendingDoctor', value: $event })"
@update:searchText="emit('fetch', { menu: 'doctor', value: $event })"
/>
</Field>
</Cell>
@@ -367,13 +421,13 @@ watch(props, (value) => {
placeholder="Pilih Diagnosa Awal"
search-placeholder="Cari Diagnosa Awal"
empty-message="Item tidak ditemukan"
@update:searchText="emit('fetch', { menu: 'initialDiagnosis', value: $event })"
@update:searchText="emit('fetch', { menu: 'diagnosis', value: $event })"
/>
</Field>
</Cell>
</Block>
<Block
<Block
labelSize="thin"
class="!pt-0"
:colCount="1"
@@ -392,12 +446,12 @@ watch(props, (value) => {
/>
</Field>
</Cell>
</Block>
</Block>
<Block
labelSize="thin"
class="!pt-0"
:colCount="2"
:colCount="3"
:cellFlex="false"
>
<Cell>
@@ -457,33 +511,29 @@ watch(props, (value) => {
</RadioGroup>
</Field>
</Cell>
</Block>
<Block
labelSize="thin"
class="!pt-0"
:colCount="3"
:cellFlex="false"
>
<Cell>
<Label height="compact">
Jenis Prosedur
Status Kecelakaan
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.procedureType">
<RadioGroup
v-model="procedureType"
class="flex items-center gap-2"
v-bind="procedureTypeAttrs"
>
<div class="flex items-center space-x-2">
<RadioGroupItem
value="0"
id="procedure-one"
/>
<Label for="procedure-one">Prosedur tidak berkelanjutan</Label>
</div>
<div class="flex items-center space-x-2">
<RadioGroupItem
value="1"
id="procedure-two"
/>
<Label for="procedure-two">Prosedur dan terapi berkelanjutan</Label>
</div>
</RadioGroup>
<Field :errMessage="errors.trafficAccident">
<Select
id="accident"
icon-name="i-lucide-chevron-down"
v-model="accident"
v-bind="accidentAttrs"
:items="accidents"
:disabled="isLoading || isReadonly"
placeholder="Pilih Status Kecelakaan"
/>
</Field>
</Cell>
</Block>
@@ -495,6 +545,60 @@ watch(props, (value) => {
:cellFlex="false"
>
<Cell>
<Label height="compact">
Tujuan Kunjungan
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.purposeOfVisit">
<Select
id="purposeOfVisit"
icon-name="i-lucide-chevron-down"
v-model="purposeOfVisit"
v-bind="purposeOfVisitAttrs"
:items="purposes"
:disabled="isLoading || isReadonly"
placeholder="Pilih Tujuan Kunjungan"
/>
</Field>
</Cell>
<Cell v-if="purposeOfVisit === '1'">
<Label height="compact">
Jenis Prosedur
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.procedureType">
<Select
id="procedureType"
icon-name="i-lucide-chevron-down"
v-model="procedureType"
v-bind="procedureTypeAttrs"
:items="procedures"
:disabled="isLoading || isReadonly"
placeholder="Pilih Jenis Prosedur"
/>
</Field>
</Cell>
<Cell v-if="purposeOfVisit === '2'">
<Label height="compact">
Assemen Pelayanan
<span class="text-red-500">*</span>
</Label>
<Field :errMessage="errors.serviceAssessment">
<Select
id="serviceAssessment"
icon-name="i-lucide-chevron-down"
v-model="serviceAssessment"
v-bind="serviceAssessmentAttrs"
:items="assessments"
:disabled="isLoading || isReadonly"
placeholder="Pilih Assemen Pelayanan"
/>
</Field>
</Cell>
<Cell v-if="purposeOfVisit === '1'">
<Label height="compact">
Kode Penunjang
<span class="text-red-500">*</span>
+54 -8
View File
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRoute } from "vue-router"
import { useRoute } from 'vue-router'
// Components
import AppViewHistory from '~/components/app/sep/view-history.vue'
@@ -12,7 +12,7 @@ import type { SepHistoryData } from '~/components/app/sep/list-cfg.history'
import type { SepVisitData } from '~/components/app/sep/list-cfg.visit'
// Constants
import { supportCodes } from '~/lib/constants'
import { serviceTypes, serviceAssessments, registerMethods, trafficAccidents, supportCodes, procedureTypes, purposeOfVisits } from '~/lib/constants.vclaim'
// Services
import { getPatientDetail, getPatients } from '~/services/patient.service'
@@ -35,6 +35,7 @@ const selectedPatient = ref('')
const selectedPatientObject = ref<PatientEntity | null>(null)
const selectedLetter = ref('SK22334442')
const selectedObjects = ref<any>({})
const selectedServiceType = ref<string>('')
const histories = ref<Array<SepHistoryData>>([])
const visits = ref<Array<SepVisitData>>([])
const patients = ref<Array<{ id: string; identity: string; number: string; bpjs: string; name: string }>>([])
@@ -42,6 +43,12 @@ const doctors = ref<Array<{ value: string | number; label: string }>>([])
const diagnoses = ref<Array<{ value: string | number; label: string }>>([])
const facilities = ref<Array<{ value: string | number; label: string }>>([])
const supportCodesList = ref<Array<{ value: string; label: string }>>([])
const serviceTypesList = ref<Array<{ value: string; label: string }>>([])
const registerMethodsList = ref<Array<{ value: string; label: string }>>([])
const accidentsList = ref<Array<{ value: string; label: string }>>([])
const purposeOfVisitsList = ref<Array<{ value: string; label: string }>>([])
const proceduresList = ref<Array<{ value: string; label: string }>>([])
const assessmentsList = ref<Array<{ value: string; label: string }>>([])
const isPatientsLoading = ref(false)
const paginationMeta = ref<PaginationMeta>({
recordCount: 0,
@@ -246,18 +253,18 @@ function handleEvent(menu: string, value: any) {
async function handleFetch(params: any) {
const menu = params.menu || ''
const value = params.value || ''
if (menu === 'initialDiagnosis') {
if (menu === 'diagnosis') {
diagnoses.value = await getDiagnoseLabelList({ diagnosa: value })
}
if (menu === 'attendingDoctor') {
if (menu === 'doctor') {
console.log('value:', value)
}
if (menu === 'destinationClinic') {
if (menu === 'clinic') {
facilities.value = await getHealthFacilityLabelList({ faskes: value, 'jenis-faskes': 1 })
}
}
onMounted(async () => {
async function handleInit() {
diagnoses.value = await getDiagnoseLabelList({ diagnosa: 'paru' })
facilities.value = await getHealthFacilityLabelList({ faskes: 'Puskesmas', 'jenis-faskes': 1 })
doctors.value = await getDoctorLabelList({
@@ -265,6 +272,40 @@ onMounted(async () => {
'tgl-pelayanan': new Date().toISOString().substring(0, 10),
'kode-spesialis': 0,
})
serviceTypesList.value = Object.keys(serviceTypes).map((item) => ({
value: item.toString(),
label: serviceTypes[item],
})) as any
registerMethodsList.value = Object.keys(registerMethods)
.filter((item) => !['2', '4'].includes(item))
.map((item) => ({
value: item.toString(),
label: registerMethods[item],
})) as any
accidentsList.value = Object.keys(trafficAccidents).map((item) => ({
value: item.toString(),
label: trafficAccidents[item],
})) as any
purposeOfVisitsList.value = Object.keys(purposeOfVisits).map((item) => ({
value: item.toString(),
label: purposeOfVisits[item],
})) as any
proceduresList.value = Object.keys(procedureTypes).map((item) => ({
value: item.toString(),
label: procedureTypes[item],
})) as any
assessmentsList.value = Object.keys(serviceAssessments).map((item) => ({
value: item.toString(),
label: `${item.toString()} - ${serviceAssessments[item]}`,
})) as any
supportCodesList.value = Object.keys(supportCodes).map((item) => ({
value: item.toString(),
label: `${item.toString()} - ${supportCodes[item]}`,
})) as any
}
onMounted(async () => {
await handleInit()
getProvinceList().then((value) => {
console.log('value:', value)
})
@@ -277,7 +318,6 @@ onMounted(async () => {
getDiagnoseReferralList().then((value) => {
console.log('value:', value)
})
supportCodesList.value = Object.keys(supportCodes).map((item) => ({ value: item.toString(), label: supportCodes[item] })) as any
if (route.query) {
selectedObjects.value = { ...route.query }
}
@@ -298,8 +338,14 @@ onMounted(async () => {
:doctors="doctors"
:diagnoses="diagnoses"
:facilities="facilities"
:patient="selectedPatientObject"
:service-types="serviceTypesList"
:register-methods="registerMethodsList"
:accidents="accidentsList"
:purposes="purposeOfVisitsList"
:procedures="proceduresList"
:assessments="assessmentsList"
:support-codes="supportCodesList"
:patient="selectedPatientObject"
@fetch="handleFetch"
@event="handleEvent"
/>