feat/encounter: wip

This commit is contained in:
2025-10-17 02:19:12 +07:00
parent 61a3e8597b
commit 53a1b7d4ae
9 changed files with 164 additions and 140 deletions
-127
View File
@@ -1,127 +0,0 @@
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
import { defineAsyncComponent } from 'vue'
type SmallDetailDto = any
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-pdud.vue'))
const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
export const config: Config = {
cols: [
{},
{},
{},
{ width: 100 },
{ width: 120 },
{},
{},
{},
{ width: 100 },
{ width: 100 },
{},
{ width: 50 },
],
headers: [
[
{ label: 'Nama' },
{ label: 'Rekam Medis' },
{ label: 'KTP' },
{ label: 'Tgl Lahir' },
{ label: 'Umur' },
{ label: 'JK' },
{ label: 'Pendidikan' },
{ label: 'Status' },
{ label: '' },
],
],
keys: [
'name',
'medicalRecord_number',
'identity_number',
'birth_date',
'patient_age',
'gender',
'education',
'status',
'action',
],
delKeyNames: [
{ key: 'code', label: 'Kode' },
{ key: 'name', label: 'Nama' },
],
parses: {
name: (rec: unknown): unknown => {
const recX = rec as SmallDetailDto
return `${recX.firstName} ${recX.middleName || ''} ${recX.lastName || ''}`
},
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
},
birth_date: (rec: unknown): unknown => {
const recX = rec as SmallDetailDto
if (typeof recX.birth_date == 'object' && recX.birth_date) {
return (recX.birth_date as Date).toLocaleDateString()
} else if (typeof recX.birth_date == 'string') {
return (recX.birth_date as string).substring(0, 10)
}
return recX.birth_date
},
patient_age: (rec: unknown): unknown => {
const recX = rec as SmallDetailDto
return recX.birth_date?.split('T')[0]
},
gender: (rec: unknown): unknown => {
const recX = rec as SmallDetailDto
if (typeof recX?.gender_code !== 'number' && recX?.gender_code !== '') {
return 'Tidak Diketahui'
}
return recX.gender_code
},
education: (rec: unknown): unknown => {
const recX = rec as SmallDetailDto
if (typeof recX.education_code == 'number' && recX.education_code >= 0) {
return recX.education_code
} else if (typeof recX.education_code) {
return recX.education_code
}
return '-'
},
},
components: {
action(rec, idx) {
const res: RecComponent = {
idx,
rec: rec as object,
component: action,
}
return res
},
status(rec, idx) {
const recX = rec as SmallDetailDto
if (recX.status_code === null) {
recX.status_code = 0
}
const res: RecComponent = {
idx,
rec: rec as object,
component: statusBadge,
}
return res
},
},
htmls: {
patient_address(_rec) {
return '-'
},
},
}
+104
View File
@@ -0,0 +1,104 @@
import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
import { defineAsyncComponent } from 'vue'
import type { Encounter } from '~/models/encounter'
import { educationCodes, genderCodes } from '~/lib/constants'
import { getAge } from '~/lib/date'
type SmallDetailDto = Encounter
const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-pdud.vue'))
const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
export const config: Config = {
cols: [
{},
{},
{},
{ width: 160 },
{},
{ width: 70 },
{ },
{ width: 50 },
],
headers: [
[
{ label: 'Nama' },
{ label: 'Rekam Medis' },
{ label: 'KTP' },
{ label: 'Tgl Lahir / Umur' },
{ label: 'JK' },
{ label: 'Pendidikan' },
{ label: 'Status', classVal: '!text-center' },
{ label: '' },
],
],
keys: [
'patient.person.name',
'patient.number',
'patient.person.residentIdentityNumber',
'birth_date',
'gender',
'education',
'status',
'action',
],
delKeyNames: [
{ key: 'code', label: 'Kode' },
{ key: 'name', label: 'Nama' },
],
parses: {
gender: (rec: unknown): unknown => {
const recX = rec as Encounter
if (recX.patient?.person?.gender_code) {
return genderCodes[recX.patient.person.gender_code]
}
return '-'
},
education: (rec: unknown): unknown => {
const recX = rec as SmallDetailDto
if (recX.patient?.person?.education_code) {
return educationCodes[recX.patient.person.education_code]
}
return '-'
},
},
components: {
action(rec, idx) {
const res: RecComponent = {
idx,
rec: rec as object,
component: action,
}
return res
},
status(rec, idx) {
const recX = rec as Encounter
if (!recX.status_code) {
recX.status_code = 'new'
}
const res: RecComponent = {
idx,
rec: recX,
component: statusBadge,
}
return res
},
},
htmls: {
birth_date: (rec: unknown): unknown => {
const recX = rec as Encounter
if (recX.patient?.person?.birthDate) {
return '' +
'<div>' + (recX.patient.person.birthDate as string).substring(0, 10) + ' / </div>' +
getAge(recX.patient.person.birthDate as string).extFormat
}
return '-'
},
},
}
+2 -2
View File
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { config } from './list-cfg'
import { config } from './list.cfg'
defineProps<{
const props = defineProps<{
data: any[]
}>()
</script>
+12 -6
View File
@@ -1,22 +1,28 @@
<script setup lang="ts">
import { Badge } from '~/components/pub/ui/badge'
import { type Variants, Badge } from '~/components/pub/ui/badge'
import { dataStatusCodes } from '~/lib/constants';
const props = defineProps<{
rec: any
idx?: number
}>()
const doctorStatus = {
0: 'Tidak Aktif',
1: 'Aktif',
const statusCodeColors: Record<string, Variants> = {
new: 'warning',
review: 'fresh',
process: 'fresh',
done: 'positive',
canceled: 'destructive',
rejected: 'destructive',
skiped: 'negative',
}
const statusText = computed(() => {
return doctorStatus[props.rec.status_code as keyof typeof doctorStatus]
return dataStatusCodes[props.rec.status_code as keyof typeof dataStatusCodes]
})
const badgeVariant = computed(() => {
return props.rec.status_code === 1 ? 'default' : 'destructive'
return (statusCodeColors[props.rec.status_code as keyof typeof statusCodeColors] || 'default')
})
</script>
+1 -1
View File
@@ -49,7 +49,7 @@ const refSearchNav: RefSearchNav = {
async function getPatientList() {
isLoading.isTableLoading = true
const resp = await xfetch('/api/v1/encounter')
const resp = await xfetch('/api/v1/encounter?includes=patient,patient-person')
if (resp.success) {
data.value = (resp.body as Record<string, any>).data
}
+4 -2
View File
@@ -29,7 +29,9 @@ const activeTab = computed({
})
const id = typeof route.params.id == 'string' ? parseInt(route.params.id) : 0
const encounter = ref<Encounter>((await getDetail(id)) as Encounter)
const encounterRes = await getDetail(id)
const encounterResBody = encounterRes.body ?? null
const encounter = encounterResBody?.data ?? null
const data = {
noRm: 'RM21123',
@@ -45,7 +47,7 @@ const data = {
}
const tabs: TabItem[] = [
{ value: 'status', label: 'Status Masuk/Keluar', component: Status },
{ value: 'status', label: 'Status Masuk/Keluar', component: Status, props: { encounter } },
{ value: 'early-medical-assessment', label: 'Pengkajian Awal Medis', component: EarlyMedicalAssesmentList },
{
value: 'rehab-medical-assessment',
+10
View File
@@ -1,14 +1,22 @@
import { type Doctor, genDoctor } from "./doctor"
import { genEmployee, type Employee } from "./employee"
import { type Patient, genPatient } from "./patient"
import type { Specialist } from "./specialist"
import type { Subspecialist } from "./subspecialist"
import { genUnit, type Unit } from "./unit"
export interface Encounter {
id: number
patient_id: number
patient: Patient
registeredAt: string
class_code: string
unit_id: number
unit: Unit
specialist_id?: number
specilist?: Specialist
subspecialist_id?: number
subspecialist?: Subspecialist
visitdate: string
adm_employee_id: number
adm_employee: Employee
@@ -30,9 +38,11 @@ export function genEncounter(): Encounter {
return {
id: 0,
patient_id: 0,
patient: genPatient(),
registeredAt: '',
class_code: '',
unit_id: 0,
unit: genUnit(),
visitdate: '',
adm_employee_id: 0,
adm_employee: genEmployee(),
+25 -2
View File
@@ -6,7 +6,7 @@ import type { PersonFamiliesFormData } from '~/schemas/person-family.schema'
import type { PersonContactFormData } from '~/schemas/person-contact.schema'
import type { PersonRelativeFormData } from '~/schemas/person-relative.schema'
import type { Person } from './person'
import { genPerson, type Person } from './person'
import type { PersonAddress } from './person-address'
import type { PersonContact } from './person-contact'
import type { PersonRelative } from './person-relative'
@@ -37,7 +37,7 @@ export interface genPatientProps {
responsible: PersonRelativeFormData
}
export function genPatient(props: genPatientProps): PatientEntity {
export function genPatientEntity(props: genPatientProps): PatientEntity {
const { patient, residentAddress, cardAddress, familyData, contacts, responsible } = props
const addresses: PersonAddress[] = [{ ...genBase(), person_id: 0, locationType: '', ...residentAddress }]
@@ -135,3 +135,26 @@ export function genPatient(props: genPatientProps): PatientEntity {
deletedAt: null,
}
}
// New model
export interface Patient extends Base {
person_id?: number
person: Person
newBornStatus?: boolean
registeredAt?: Date | string | null
status_code?: string
number?: string
}
export function genPatient(): Patient {
return {
...genBase(),
person_id: 0,
registeredAt: '',
status_code: '',
number: '',
newBornStatus: false,
person: genPerson(),
}
}
+6
View File
@@ -1,4 +1,7 @@
import { type Base, genBase } from "./_base"
import type { PersonAddress } from "./person-address"
import type { PersonContact } from "./person-contact"
import type { PersonRelative } from "./person-relative"
export interface Person extends Base {
// todo: awaiting approve from stake holder: buat field sapaan
@@ -26,6 +29,9 @@ export interface Person extends Base {
passportFileUrl?: string
drivingLicenseFileUrl?: string
familyIdentityFileUrl?: string
addresses?: PersonAddress[]
contacts?: PersonContact[]
relatives?: PersonRelative[]
}
export function genPerson(): Person {