import { ref } from 'vue' import { useRoute } from 'vue-router' // Components import { toast } from '~/components/pub/ui/toast' // Types import type { SepHistoryData } from '~/components/app/sep/list-cfg.history' import type { TreeItem } from '~/components/pub/my-ui/select-tree/type' // Constants import { serviceTypes, serviceAssessments, registerMethods, trafficAccidents, supportCodes, procedureTypes, purposeOfVisits, classLevels, classLevelUpgrades, classPaySources, } from '~/lib/constants.vclaim' // Services import { getList as getSpecialistList, getValueTreeItems as getSpecialistTreeItems, } from '~/services/specialist.service' import { getValueLabelList as getProvinceList } from '~/services/vclaim-region-province.service' import { getValueLabelList as getCityList } from '~/services/vclaim-region-city.service' import { getValueLabelList as getDistrictList } from '~/services/vclaim-region-district.service' import { getValueLabelList as getDoctorLabelList } from '~/services/vclaim-doctor.service' import { getValueLabelList as getHealthFacilityLabelList } from '~/services/vclaim-healthcare.service' import { getValueLabelList as getDiagnoseLabelList } from '~/services/vclaim-diagnose.service' import { getList as getMemberList } from '~/services/vclaim-member.service' import { getList as getHospitalLetterList } from '~/services/vclaim-reference-hospital-letter.service' import { getList as getControlLetterList } from '~/services/vclaim-control-letter.service' import { getList as getMonitoringHistoryList } from '~/services/vclaim-monitoring-history.service' import { create as createSep, makeSepData } from '~/services/vclaim-sep.service' // Handlers import { patients, selectedPatient, selectedPatientObject, paginationMeta, getPatientsList, getPatientCurrent, getPatientByIdentifierSearch, } from '~/handlers/patient.handler' export function useIntegrationSepEntry() { const userStore = useUserStore() const route = useRoute() const recSepId = ref(null) const openPatient = ref(false) const openLetter = ref(false) const openHistory = ref(false) const selectedLetter = ref('') const selectedObjects = ref({}) const selectedServiceType = ref('') const selectedAdmissionType = ref('') const histories = ref>([]) const letters = ref>([]) const doctors = ref>([]) const diagnoses = ref>([]) const facilitiesFrom = ref>([]) const facilitiesTo = ref>([]) const supportCodesList = ref>([]) const serviceTypesList = ref>([]) const registerMethodsList = ref>([]) const accidentsList = ref>([]) const purposeOfVisitsList = ref>([]) const proceduresList = ref>([]) const assessmentsList = ref>([]) const provincesList = ref>([]) const citiesList = ref>([]) const districtsList = ref>([]) const classLevelsList = ref>([]) const classLevelUpgradesList = ref>([]) const classPaySourcesList = ref>([]) const isServiceHidden = ref(false) const isSaveLoading = ref(false) const isLetterReadonly = ref(false) const isLoadingPatient = ref(false) const specialistsTree = ref([]) const resourceType = ref('') const resourcePath = ref('') const encounterId = ref(null) /** * Map letter data to form fields for save-sep * Maps data from letters.value[0].information to selectedObjects and form values */ function mapLetterDataToForm(formValues: any): any { if (selectedAdmissionType.value === '3' || letters.value.length === 0) { return formValues } const letterData = letters.value[0] const info = letterData.information || {} // Map data to selectedObjects for form population if (info.cardNumber) { selectedObjects.value['cardNumber'] = info.cardNumber } if (info.medicalRecordNumber) { selectedObjects.value['medicalRecordNumber'] = info.medicalRecordNumber } if (info.patientPhone) { selectedObjects.value['phoneNumber'] = info.patientPhone } if (info.classLevel) { selectedObjects.value['classLevel'] = info.classLevel } // Map data to formValues for makeSepData const mappedValues = { ...formValues } // response.rujukan.peserta.noKartu → cardNumber (noKartu) if (info.cardNumber) { mappedValues.cardNumber = info.cardNumber } // response.rujukan.tglKunjungan → referralLetterDate (rujukan.tglRujukan) if (letterData.plannedDate) { mappedValues.referralLetterDate = letterData.plannedDate } // response.rujukan.noKunjungan → referralLetterNumber (rujukan.noRujukan) if (letterData.letterNumber) { mappedValues.referralLetterNumber = letterData.letterNumber } // response.rujukan.provPerujuk.kode → fromClinic (rujukan.ppkRujukan) if (info.destination) { mappedValues.referralTo = info.destination } // response.rujukan.poliRujukan.kode → polyCode if (info.poly) { mappedValues.polyCode = info.poly } // response.asalFaskes → asalRujukan (1 = Faskes 1, 2 = Faskes RS) // Map facility to referralFrom (asalRujukan) if (info.facility) { mappedValues.referralFrom = info.facility } // response.rujukan.diagnosa.kode → initialDiagnosis (diagAwal) if (info.diagnoses) { mappedValues.initialDiagnosis = info.diagnoses } // response.rujukan.poliRujukan.kode → destinationClinic (poli.tujuan) if (info.poly) { mappedValues.destinationClinic = info.poly } // response.rujukan.peserta.hakKelas.kode → classLevel (klsRawat.klsRawatHak) if (info.classLevel) { mappedValues.classLevel = info.classLevel } // response.rujukan.peserta.mr.noMR → medicalRecordNumber (noMR) if (info.medicalRecordNumber) { mappedValues.medicalRecordNumber = info.medicalRecordNumber } // response.rujukan.peserta.mr.noTelepon → phoneNumber (noTelp) if (info.patientPhone) { mappedValues.phoneNumber = info.patientPhone } return mappedValues } async function getMonitoringHistoryMappers(number: string | null = null) { histories.value = [] const dateFirst = new Date() const dateLast = new Date() dateLast.setMonth(dateFirst.getMonth() - 2) // max 90 days const cardNumber = selectedPatientObject.value?.person?.residentIdentityNumber || selectedPatientObject.value?.number || number || '' const result = await getMonitoringHistoryList({ cardNumber: cardNumber, startDate: dateLast.toISOString().substring(0, 10), endDate: dateFirst.toISOString().substring(0, 10), }) if (result && result.success && result.body) { const historiesRaw = result.body?.response?.histori || [] if (!historiesRaw) return historiesRaw.forEach((result: any) => { histories.value.push({ sepNumber: result.noSep, sepDate: result.tglSep, referralNumber: result.noRujukan, diagnosis: result.diagnosa && typeof result.diagnosa === 'string' && result.diagnosa.length > 20 ? result.diagnosa.toString().substring(0, 17) + '...' : '-', serviceType: !result.jnsPelayanan ? '-' : result.jnsPelayanan === '1' ? 'Rawat Jalan' : 'Rawat Inap', careClass: result.kelasRawat, }) }) } } async function getLetterMappers(admissionType: string, search: string) { letters.value = [] let result = null if (admissionType !== '3') { result = await getHospitalLetterList({ letterNumber: search, }) } else { result = await getControlLetterList({ letterNumber: search, mode: 'by-control', }) if (result && result.success && result.body) { const lettersRaw = result.body?.response || null if (!lettersRaw) { result = await getControlLetterList({ letterNumber: search, mode: 'by-card', }) } } if (result && result.success && result.body) { const lettersRaw = result.body?.response || null if (!lettersRaw) { result = await getControlLetterList({ letterNumber: search, mode: 'by-sep', }) } } } if (result && result.success && result.body) { const lettersRaw = result.body?.response || null if (!lettersRaw) return if (admissionType === '3') { letters.value = [ { letterNumber: lettersRaw.noSuratKontrol || '', plannedDate: lettersRaw.tglRencanaKontrol || '', sepNumber: lettersRaw.sep.noSep || '', patientName: lettersRaw.sep.peserta.nama || '', bpjsCardNo: lettersRaw.sep.peserta.noKartu, clinic: lettersRaw.sep.poli || '', doctor: lettersRaw.sep.namaDokter || '', }, ] } else { const destA = lettersRaw?.rujukan?.provPerujuk?.Kode const destB = lettersRaw?.rujukan?.provPerujuk?.kode letters.value = [ { letterNumber: lettersRaw?.rujukan?.noKunjungan || '', plannedDate: lettersRaw?.rujukan?.tglKunjungan || '', sepNumber: lettersRaw?.rujukan?.informasi?.eSEP || '-', patientName: lettersRaw?.rujukan?.peserta.nama || '', bpjsCardNo: lettersRaw?.rujukan?.peserta.noKartu || '', clinic: lettersRaw?.rujukan?.poliRujukan.nama || '', doctor: '', information: { facility: lettersRaw?.asalFaskes || '', diagnose: lettersRaw?.rujukan?.diagnosa?.kode || '', serviceType: lettersRaw?.rujukan?.pelayanan?.kode || '', classLevel: lettersRaw?.rujukan?.peserta?.hakKelas?.kode || '', poly: lettersRaw?.rujukan?.poliRujukan?.kode || '', cardNumber: lettersRaw?.rujukan?.peserta?.noKartu || '', identity: lettersRaw?.rujukan?.peserta?.nik || '', patientName: lettersRaw?.rujukan?.peserta?.nama || '', patientPhone: lettersRaw?.rujukan?.peserta?.mr?.noTelepon || '', medicalRecordNumber: lettersRaw?.rujukan?.peserta?.mr?.noMR || '', destination: destA || destB || '', }, }, ] } } } async function getPatientInternalMappers(id: string) { try { await getPatientCurrent(id) if (selectedPatientObject.value) { const patient = selectedPatientObject.value selectedObjects.value['cardNumber'] = '-' selectedObjects.value['nationalIdentity'] = patient?.person?.residentIdentityNumber || '-' selectedObjects.value['medicalRecordNumber'] = patient?.number || '-' selectedObjects.value['patientName'] = patient?.person?.name || '-' selectedObjects.value['phoneNumber'] = patient?.person?.contacts?.[0]?.value || '-' } } catch (err) { console.error('Failed to load patient from query params:', err) } } async function getPatientExternalMappers(id: string, type: string) { try { isLoadingPatient.value = true const result = await getMemberList({ mode: type, number: id, date: new Date().toISOString().substring(0, 10), }) if (result && result.success && result.body) { const memberRaws = result.body?.response || null selectedObjects.value['cardNumber'] = memberRaws?.peserta?.noKartu || '' selectedObjects.value['nationalIdentity'] = memberRaws?.peserta?.nik || '' selectedObjects.value['medicalRecordNumber'] = memberRaws?.peserta?.mr?.noMR || '' selectedObjects.value['patientName'] = memberRaws?.peserta?.nama || '' selectedObjects.value['phoneNumber'] = memberRaws?.peserta?.mr?.noTelepon || '' selectedObjects.value['classLevel'] = memberRaws?.peserta?.hakKelas?.kode || '' selectedObjects.value['status'] = memberRaws?.statusPeserta?.kode || '' } isLoadingPatient.value = false } catch (err) { console.error('Failed to load patient from query params:', err) isLoadingPatient.value = false } } function handleSaveLetter() { // Find the selected letter and get its plannedDate const selectedLetterData = letters.value.find((letter) => letter.letterNumber === selectedLetter.value) if (selectedLetterData && selectedLetterData.plannedDate) { selectedObjects.value['letterDate'] = selectedLetterData.plannedDate } } async function handleSavePatient() { selectedPatientObject.value = null await getPatientInternalMappers(selectedPatient.value) } async function handleEvent(menu: string, value: any) { if (menu === 'admission-type') { selectedAdmissionType.value = value return } if (menu === 'service-type') { selectedServiceType.value = value doctors.value = await getDoctorLabelList({ serviceType: selectedServiceType.value || '2', serviceDate: new Date().toISOString().substring(0, 10), specialistCode: 0, }) } if (menu === 'search-patient') { getPatientsList({ 'page-size': 10, includes: 'person' }).then(() => { openPatient.value = true }) return } if (menu === 'search-patient-by-identifier') { if (isLoadingPatient.value) return const text = value.text const type = value.type const prevCardNumber = selectedObjects.value['cardNumber'] || '' const prevNationalIdentity = selectedObjects.value['nationalIdentity'] || '' if (type === 'indentity' && text !== prevNationalIdentity) { await getPatientByIdentifierSearch(text) await getPatientExternalMappers(text, 'by-identity') } if (type === 'cardNumber' && text !== prevCardNumber) { await getPatientExternalMappers(text, 'by-card') } return } if (menu === 'search-letter') { isLetterReadonly.value = false getLetterMappers(value.admissionType, value.search).then(async () => { if (letters.value.length > 0) { const copyObjects = { ...selectedObjects.value } const letter = letters.value[0] selectedObjects.value = {} selectedLetter.value = letter.letterNumber isLetterReadonly.value = true if (letter.information || letter.clinic) { const poly = value.admissionType === '3' ? letter.clinic : letter.information?.poly if (poly) { const resultControl = await getControlLetterList({ mode: 'by-schedule', controlDate: letter.plannedDate, controlType: selectedServiceType.value, polyCode: poly, }) if (resultControl && resultControl.success && resultControl.body) { const resultData = resultControl.body?.response?.list || [] const resultUnique = [...new Map(resultData.map((item: any) => [item.kodeDokter, item])).values()] const controlLetters = resultUnique.map((item: any) => ({ value: item.kodeDokter ? String(item.kodeDokter) : '', label: `${item.kodeDokter} - ${item.namaDokter} - ${item.jadwalPraktek} (${item.kapasitas})`, })) doctors.value = controlLetters } } } setTimeout(async () => { selectedObjects.value = copyObjects selectedObjects.value['letterDate'] = letter.plannedDate selectedObjects.value['cardNumber'] = letter.information?.cardNumber || '' selectedObjects.value['nationalIdentity'] = letter.information?.identity || '' selectedObjects.value['medicalRecordNumber'] = letter.information?.medicalRecordNumber || '' selectedObjects.value['patientName'] = letter.information?.patientName || '' selectedObjects.value['phoneNumber'] = letter.information?.patientPhone || '' selectedObjects.value['facility'] = letter.information?.facility || '' selectedObjects.value['diagnose'] = letter.information?.diagnose || '' selectedObjects.value['serviceType'] = letter.information?.serviceType || '' selectedObjects.value['classLevel'] = letter.information?.classLevel || '' selectedObjects.value['poly'] = letter.information?.poly || '' selectedObjects.value['destination'] = letter.information?.destination || '' if (!!selectedObjects.value['diagnose']) { const diagnoseRes: any = await getDiagnoseLabelList({ diagnosa: selectedObjects.value['diagnose'] }) diagnoses.value = diagnoseRes if (diagnoseRes && diagnoseRes.length > 0) { selectedObjects.value['diagnoseLabel'] = diagnoseRes[0].value } } }, 250) } }) return } if (menu === 'open-letter') { openLetter.value = true return } if (menu === 'history-sep') { getMonitoringHistoryMappers().then(() => { openHistory.value = true }) return } if (menu === 'sep-number-changed') { // Update sepNumber when it changes in form (only if different to prevent loop) } if (menu === 'back') { navigateTo('/integration/bpjs-vclaim/sep') } if (menu === 'save-sep-number') { const sourcePath = route.query['source-path'] || ('' as any) navigateTo({ path: sourcePath, query: { 'sep-number': value.sepNumber || '' } }) } if (menu === 'save-sep') { isSaveLoading.value = true // Map letter data to form if admissionType !== '3' and letters.value has data let mappedValues = value if (selectedAdmissionType.value !== '3') { if (letters.value.length > 0) { // Map data from letters.value to form values mappedValues = mapLetterDataToForm(value) } else { // Fallback: use getPatientExternalMappers if letters.value is empty // Get card number from form values or selectedObjects const cardNumberToSearch = value.cardNumber || selectedObjects.value['cardNumber'] || '' if (cardNumberToSearch && cardNumberToSearch !== '-') { await getPatientExternalMappers(cardNumberToSearch, 'by-card') // Update mappedValues with data from getPatientExternalMappers if (selectedObjects.value['cardNumber']) { mappedValues.cardNumber = selectedObjects.value['cardNumber'] } if (selectedObjects.value['medicalRecordNumber']) { mappedValues.medicalRecordNumber = selectedObjects.value['medicalRecordNumber'] } if (selectedObjects.value['phoneNumber']) { mappedValues.phoneNumber = selectedObjects.value['phoneNumber'] } if (selectedObjects.value['classLevel']) { mappedValues.classLevel = selectedObjects.value['classLevel'] } } } } if (!value.destinationClinic) { mappedValues.referralTo = selectedObjects.value['destination'] || '' } if (!value.clinicExcecutive) { mappedValues.clinicExcecutive = 'no' } mappedValues.userName = userStore.user?.user_name || '' const payload = { ...makeSepData(mappedValues), encounterId: encounterId.value || null } createSep(payload) .then((res) => { const success = res?.success if (success) { const body = res?.body const code = body?.metaData?.code const message = body?.metaData?.message if (code && code !== '200') { toast({ title: 'Gagal', description: message || 'Gagal membuat SEP', variant: 'destructive' }) return } toast({ title: 'Berhasil', description: 'SEP berhasil dibuat', variant: 'default' }) if (!!resourcePath.value) { navigateTo({ path: resourcePath.value, query: { 'sep-number': body?.response?.sep?.noSep || '-' } }) return } navigateTo('/integration/bpjs-vclaim/sep') return } const error = res?.error if (error) { const errorMessage = error?.message ? `${error?.message}` : 'Sep gagal dibuat' toast({ title: 'Gagal', description: errorMessage, variant: 'destructive' }) return } }) .catch((err) => { console.error('Failed to save SEP:', err) toast({ title: 'Gagal', description: err?.message || 'Gagal membuat SEP', variant: 'destructive' }) }) .finally(() => { isSaveLoading.value = false }) } } async function handleFetch(params: any) { const menu = params.menu || '' const value = params.value || '' if (menu === 'diagnosis') { diagnoses.value = await getDiagnoseLabelList({ diagnosa: value }) } if (menu === 'clinic-from') { facilitiesFrom.value = await getHealthFacilityLabelList({ healthcare: value, healthcareType: selectedServiceType.value || 2, }) } if (menu === 'clinic-to') { facilitiesTo.value = await getHealthFacilityLabelList({ healthcare: value, healthcareType: selectedServiceType.value || 2, }) } if (menu === 'province') { citiesList.value = await getCityList({ province: value }) districtsList.value = [] } if (menu === 'city') { districtsList.value = await getDistrictList({ city: value }) } } async function handleFetchSpecialists() { try { const specialistsResult = await getSpecialistList({ 'page-size': 100, includes: 'subspecialists' }) if (specialistsResult.success) { const specialists = specialistsResult.body?.data || [] specialistsTree.value = getSpecialistTreeItems(specialists) } } catch (error) { console.error('Error fetching specialist-subspecialist tree:', error) } } async function handleInit() { selectedServiceType.value = '2' const facilities = await getHealthFacilityLabelList({ healthcare: 'Puskesmas', healthcareType: selectedLetter.value || 1, }) diagnoses.value = await getDiagnoseLabelList({ diagnosa: 'paru' }) facilitiesFrom.value = facilities facilitiesTo.value = facilities doctors.value = await getDoctorLabelList({ serviceType: selectedServiceType.value || '2', serviceDate: new Date().toISOString().substring(0, 10), specialistCode: 0, }) provincesList.value = await getProvinceList() serviceTypesList.value = Object.keys(serviceTypes).map((item) => ({ value: item.toString(), label: serviceTypes[item], })) as any registerMethodsList.value = Object.keys(registerMethods) .filter((item) => ![''].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 classLevelsList.value = Object.keys(classLevels).map((item) => ({ value: item.toString(), label: classLevels[item], })) as any classLevelUpgradesList.value = Object.keys(classLevelUpgrades).map((item) => ({ value: item.toString(), label: classLevelUpgrades[item], })) as any classPaySourcesList.value = Object.keys(classPaySources).map((item) => ({ value: item.toString(), label: classPaySources[item], })) as any await handleFetchSpecialists() if (route.query) { const queries = route.query as any isServiceHidden.value = queries['is-service'] === 'true' selectedObjects.value = {} if (queries['encounter-id']) encounterId.value = queries['encounter-id'] if (queries['resource']) resourceType.value = queries['resource'] if (queries['source-path']) resourcePath.value = queries['source-path'] if (queries['doctor-code']) selectedObjects.value['doctorCode'] = queries['doctor-code'] if (queries['specialist-code']) selectedObjects.value['subSpecialistCode'] = queries['specialist-code'] if (queries['sub-specialist-code']) selectedObjects.value['subSpecialistCode'] = queries['sub-specialist-code'] if (queries['card-number']) selectedObjects.value['cardNumber'] = queries['card-number'] if (queries['register-date']) selectedObjects.value['registerDate'] = queries['register-date'] if (queries['sep-type']) selectedObjects.value['sepType'] = queries['sep-type'] if (queries['sep-number']) selectedObjects.value['sepNumber'] = queries['sep-number'] if (queries['register-date']) selectedObjects.value['registerDate'] = queries['register-date'] if (queries['payment-type']) selectedObjects.value['paymentType'] = queries['payment-type'] if (queries['patient-id']) { await getPatientInternalMappers(queries['patient-id']) } if (queries['card-number']) { await getMemberList({ mode: 'by-card', number: queries['card-number'], date: new Date().toISOString().substring(0, 10), }) } delete selectedObjects.value['is-service'] } } return { recSepId, openPatient, openLetter, openHistory, selectedLetter, selectedObjects, selectedServiceType, selectedAdmissionType, histories, letters, doctors, diagnoses, facilitiesFrom, facilitiesTo, supportCodesList, serviceTypesList, registerMethodsList, accidentsList, purposeOfVisitsList, proceduresList, assessmentsList, provincesList, citiesList, districtsList, classLevelsList, classLevelUpgradesList, classPaySourcesList, isServiceHidden, isSaveLoading, isLetterReadonly, isLoadingPatient, specialistsTree, resourceType, resourcePath, encounterId, patients, selectedPatient, paginationMeta, getMonitoringHistoryMappers, getLetterMappers, getPatientInternalMappers, getPatientExternalMappers, getPatientsList, getPatientByIdentifierSearch, handleSaveLetter, mapLetterDataToForm, handleSavePatient, handleEvent, handleFetch, handleFetchSpecialists, handleInit, } }