-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ {{ props.title || 'Kontak Pasien' }}
+
+
+
+
+
+
+
+
Penanggung Jawab {{ idx + 1 }}
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
+
+
+
+
diff --git a/app/components/app/person/_common/radio-parents-input.vue b/app/components/app/person/_common/radio-parents-input.vue
new file mode 100644
index 00000000..bd8b6f15
--- /dev/null
+++ b/app/components/app/person/_common/radio-parents-input.vue
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ option.label }}
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/person/entry-form.vue b/app/components/app/person/entry-form.vue
index 24705de4..a9a9c6cf 100644
--- a/app/components/app/person/entry-form.vue
+++ b/app/components/app/person/entry-form.vue
@@ -1,5 +1,6 @@
+
+
+
+
diff --git a/app/components/app/room/entry-form.vue b/app/components/app/room/entry-form.vue
new file mode 100644
index 00000000..6f4e7708
--- /dev/null
+++ b/app/components/app/room/entry-form.vue
@@ -0,0 +1,195 @@
+
+
+
+
+
diff --git a/app/components/app/room/list-cfg.ts b/app/components/app/room/list-cfg.ts
new file mode 100644
index 00000000..98e7eb50
--- /dev/null
+++ b/app/components/app/room/list-cfg.ts
@@ -0,0 +1,61 @@
+import type {
+ Col,
+ KeyLabel,
+ RecComponent,
+ RecStrFuncComponent,
+ RecStrFuncUnknown,
+ Th,
+} from '~/components/pub/my-ui/data/types'
+import { defineAsyncComponent } from 'vue'
+
+type SmallDetailDto = any
+
+const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
+
+export const cols: Col[] = [{}, {}, {}, {}, {}, { width: 50 }]
+
+export const header: Th[][] = [
+ [
+ { label: 'Kode' },
+ { label: 'Nama' },
+ { label: 'Spesialis' },
+ { label: 'Sub Spesialis' },
+ { label: 'Unit' },
+ { label: '' },
+ ],
+]
+
+export const keys = ['code', 'name', 'specialist', 'subspecialist', 'unit', 'action']
+
+export const delKeyNames: KeyLabel[] = [
+ { key: 'code', label: 'Kode' },
+ { key: 'name', label: 'Nama' },
+]
+
+export const funcParsed: RecStrFuncUnknown = {
+ specialist: (rec: unknown): unknown => {
+ const recX = rec as SmallDetailDto
+ return recX.specialist?.name || '-'
+ },
+ subspecialist: (rec: unknown): unknown => {
+ const recX = rec as SmallDetailDto
+ return recX.subspecialist?.name || '-'
+ },
+ unit: (rec: unknown): unknown => {
+ const recX = rec as SmallDetailDto
+ return recX.unit?.name || '-'
+ },
+}
+
+export const funcComponent: RecStrFuncComponent = {
+ action(rec, idx) {
+ const res: RecComponent = {
+ idx,
+ rec: rec as object,
+ component: action,
+ }
+ return res
+ },
+}
+
+export const funcHtml: RecStrFuncUnknown = {}
diff --git a/app/components/app/room/list.vue b/app/components/app/room/list.vue
new file mode 100644
index 00000000..e1b056ce
--- /dev/null
+++ b/app/components/app/room/list.vue
@@ -0,0 +1,41 @@
+
+
+
+
+
diff --git a/app/components/app/sep/entry-form.vue b/app/components/app/sep/entry-form.vue
index 9ff4c8cd..9aea7c31 100644
--- a/app/components/app/sep/entry-form.vue
+++ b/app/components/app/sep/entry-form.vue
@@ -7,7 +7,7 @@ import * as z from 'zod'
import { Button } from '~/components/pub/ui/button'
import { Input } from '~/components/pub/ui/input'
import { Label } from '~/components/pub/ui/label'
-import { Select } from '~/components/pub/ui/select'
+import Select from '~/components/pub/ui/select/Select.vue'
import { RadioGroup, RadioGroupItem } from '~/components/pub/ui/radio-group'
import { Textarea } from '~/components/pub/ui/textarea'
import DatepickerSingle from '~/components/pub/my-ui/form/datepicker-single.vue'
diff --git a/app/components/app/soapi/early-entry.vue b/app/components/app/soapi/early-entry.vue
new file mode 100644
index 00000000..c5697a7a
--- /dev/null
+++ b/app/components/app/soapi/early-entry.vue
@@ -0,0 +1,222 @@
+
+
+
+
+
diff --git a/app/components/app/soapi/early-rehab-entry.vue b/app/components/app/soapi/early-rehab-entry.vue
new file mode 100644
index 00000000..991a7c73
--- /dev/null
+++ b/app/components/app/soapi/early-rehab-entry.vue
@@ -0,0 +1,101 @@
+
+
+
+
+
+ |
+
+
+
+
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+ |
+
+
diff --git a/app/components/app/soapi/entry.vue b/app/components/app/soapi/entry.vue
new file mode 100644
index 00000000..ced3e3d8
--- /dev/null
+++ b/app/components/app/soapi/entry.vue
@@ -0,0 +1,28 @@
+
+
+
+
+
diff --git a/app/components/app/soapi/function-entry.vue b/app/components/app/soapi/function-entry.vue
new file mode 100644
index 00000000..a2fad36a
--- /dev/null
+++ b/app/components/app/soapi/function-entry.vue
@@ -0,0 +1,172 @@
+
+
+
+
+
diff --git a/app/components/app/soapi/list-cfg.ts b/app/components/app/soapi/list-cfg.ts
new file mode 100644
index 00000000..460cacd9
--- /dev/null
+++ b/app/components/app/soapi/list-cfg.ts
@@ -0,0 +1,119 @@
+import type {
+ Col,
+ KeyLabel,
+ RecComponent,
+ RecStrFuncComponent,
+ RecStrFuncUnknown,
+ Th,
+} from '~/components/pub/my-ui/data/types'
+import { defineAsyncComponent } from 'vue'
+
+type SmallDetailDto = any
+
+const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
+
+export const cols: Col[] = [
+ {},
+ {},
+ {},
+ { width: 100 },
+ { width: 120 },
+ {},
+ {},
+ {},
+ { width: 100 },
+ { width: 100 },
+ {},
+ { width: 50 },
+]
+
+export const header: Th[][] = [
+ [
+ { label: 'Nama' },
+ { label: 'Rekam Medis' },
+ { label: 'KTP' },
+ { label: 'Tgl Lahir' },
+ { label: 'Umur' },
+ { label: 'JK' },
+ { label: 'Pendidikan' },
+ { label: 'Status' },
+ { label: '' },
+ ],
+]
+
+export const keys = [
+ 'name',
+ 'medicalRecord_number',
+ 'identity_number',
+ 'birth_date',
+ 'patient_age',
+ 'gender',
+ 'education',
+ 'status',
+ 'action',
+]
+
+export const delKeyNames: KeyLabel[] = [
+ { key: 'code', label: 'Kode' },
+ { key: 'name', label: 'Nama' },
+]
+
+export const funcParsed: RecStrFuncUnknown = {
+ 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 '-'
+ },
+}
+
+export const funcComponent: RecStrFuncComponent = {
+ action(rec, idx) {
+ const res: RecComponent = {
+ idx,
+ rec: rec as object,
+ component: action,
+ }
+ return res
+ },
+}
+
+export const funcHtml: RecStrFuncUnknown = {
+ patient_address(_rec) {
+ return '-'
+ },
+}
diff --git a/app/components/app/soapi/list.vue b/app/components/app/soapi/list.vue
new file mode 100644
index 00000000..b9a74929
--- /dev/null
+++ b/app/components/app/soapi/list.vue
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/app/components/app/soapi/picker.vue b/app/components/app/soapi/picker.vue
new file mode 100644
index 00000000..e69de29b
diff --git a/app/components/app/soapi/search.vue b/app/components/app/soapi/search.vue
new file mode 100644
index 00000000..e69de29b
diff --git a/app/components/app/specialist/entry-form.vue b/app/components/app/specialist/entry-form.vue
index 0d055a1d..eb77f1df 100644
--- a/app/components/app/specialist/entry-form.vue
+++ b/app/components/app/specialist/entry-form.vue
@@ -47,7 +47,7 @@ const [unit, unitAttrs] = defineField('unit_id')
if (props.values) {
if (props.values.code !== undefined) code.value = props.values.code
if (props.values.name !== undefined) name.value = props.values.name
- if (props.values.unit_id !== undefined) unit.value = props.values.unit_id
+ if (props.values.unit_id !== undefined) unit.value = props.values.unit_id ? String(props.values.unit_id) : null
}
const resetForm = () => {
@@ -61,7 +61,7 @@ function onSubmitForm(values: any) {
const formData: SpecialistFormData = {
name: name.value || '',
code: code.value || '',
- unit_id: unit.value || '',
+ unit_id: unit.value ? Number(unit.value) : null,
}
emit('submit', formData, resetForm)
}
@@ -73,18 +73,35 @@ function onCancelForm() {
-
diff --git a/app/components/content/floor/list.vue b/app/components/content/floor/list.vue
new file mode 100644
index 00000000..5124b456
--- /dev/null
+++ b/app/components/content/floor/list.vue
@@ -0,0 +1,166 @@
+
+
+
+
+
+
+
+
+ handleActionRemove(recId, getItemList, toast)"
+ @cancel=""
+ >
+
+
+
ID: {{ record?.id }}
+
Nama: {{ record.name }}
+
Kode: {{ record.code }}
+
+
+
+
diff --git a/app/components/content/medicine-group/list.vue b/app/components/content/medicine-group/list.vue
index 8d45843f..c0a85b00 100644
--- a/app/components/content/medicine-group/list.vue
+++ b/app/components/content/medicine-group/list.vue
@@ -12,7 +12,7 @@ import { toast } from '~/components/pub/ui/toast'
// Types
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
-import { BaseSchema, type BaseFormData } from '~/schemas/base.schema'
+import { BaseSchema, type BaseFormData } from '~/schemas/my-ui.schema'
// Handlers
import {
diff --git a/app/components/content/medicine-method/list.vue b/app/components/content/medicine-method/list.vue
index f6ddf86b..5f555dba 100644
--- a/app/components/content/medicine-method/list.vue
+++ b/app/components/content/medicine-method/list.vue
@@ -12,7 +12,7 @@ import { toast } from '~/components/pub/ui/toast'
// Types
import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types'
-import { BaseSchema, type BaseFormData } from '~/schemas/base.schema'
+import { BaseSchema, type BaseFormData } from '~/schemas/my-ui.schema'
// Handlers
import {
diff --git a/app/components/content/patient/detail.vue b/app/components/content/patient/detail.vue
new file mode 100644
index 00000000..0ca4cd0d
--- /dev/null
+++ b/app/components/content/patient/detail.vue
@@ -0,0 +1,83 @@
+
+
+
+
+
+
diff --git a/app/components/content/patient/entry.vue b/app/components/content/patient/entry.vue
new file mode 100644
index 00000000..b0b5569e
--- /dev/null
+++ b/app/components/content/patient/entry.vue
@@ -0,0 +1,180 @@
+
+
+
+ Tambah Pasien
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/content/patient/list.vue b/app/components/content/patient/list.vue
index 7d3c3c79..2b73ca08 100644
--- a/app/components/content/patient/list.vue
+++ b/app/components/content/patient/list.vue
@@ -1,46 +1,54 @@
-
+
+
+
+
+
+
+ ID:
+ {{ record?.id }}
+
+
+ Nama:
+ {{ record.firstName }}
+
+
+ Kode:
+ {{ record.cellphone }}
+
+
+
+
diff --git a/app/components/content/room/list.vue b/app/components/content/room/list.vue
new file mode 100644
index 00000000..bd716240
--- /dev/null
+++ b/app/components/content/room/list.vue
@@ -0,0 +1,200 @@
+
+
+
+
+
+
+
+
+ handleActionRemove(recId, getItemList, toast)"
+ @cancel=""
+ >
+
+
+
ID: {{ record?.id }}
+
Nama: {{ record.name }}
+
Kode: {{ record.code }}
+
+
+
+
diff --git a/app/components/content/soapi/entry.vue b/app/components/content/soapi/entry.vue
new file mode 100644
index 00000000..05c25ec7
--- /dev/null
+++ b/app/components/content/soapi/entry.vue
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
diff --git a/app/components/content/soapi/form.vue b/app/components/content/soapi/form.vue
new file mode 100644
index 00000000..916f22d6
--- /dev/null
+++ b/app/components/content/soapi/form.vue
@@ -0,0 +1,36 @@
+
+
+
+
+
diff --git a/app/components/content/soapi/list.vue b/app/components/content/soapi/list.vue
new file mode 100644
index 00000000..e1d8373a
--- /dev/null
+++ b/app/components/content/soapi/list.vue
@@ -0,0 +1,66 @@
+
+
+
+
+
+
diff --git a/app/components/content/specialist/list.vue b/app/components/content/specialist/list.vue
index 71d573b4..5e869f3b 100644
--- a/app/components/content/specialist/list.vue
+++ b/app/components/content/specialist/list.vue
@@ -58,7 +58,7 @@ const {
})
const headerPrep: HeaderPrep = {
- title: 'Specialist',
+ title: 'Spesialis',
icon: 'i-lucide-box',
refSearchNav: {
placeholder: 'Cari (min. 3 karakter)...',
diff --git a/app/components/content/subspecialist/list.vue b/app/components/content/subspecialist/list.vue
index bf60598e..2e5b7e44 100644
--- a/app/components/content/subspecialist/list.vue
+++ b/app/components/content/subspecialist/list.vue
@@ -58,7 +58,7 @@ const {
})
const headerPrep: HeaderPrep = {
- title: 'SubSpecialist',
+ title: 'Sub Spesialis',
icon: 'i-lucide-box',
refSearchNav: {
placeholder: 'Cari (min. 3 karakter)...',
diff --git a/app/components/content/warehouse/list.vue b/app/components/content/warehouse/list.vue
new file mode 100644
index 00000000..88b7c2b6
--- /dev/null
+++ b/app/components/content/warehouse/list.vue
@@ -0,0 +1,8 @@
+
+
+
+ ...existing code...
+
+
diff --git a/app/components/pub/my-ui/form/block.vue b/app/components/pub/my-ui/form/block.vue
index 27015f7a..ee19d116 100644
--- a/app/components/pub/my-ui/form/block.vue
+++ b/app/components/pub/my-ui/form/block.vue
@@ -5,7 +5,7 @@ defineProps<{
-
+
diff --git a/app/components/pub/my-ui/form/combobox.vue b/app/components/pub/my-ui/form/combobox.vue
index de51600e..f48947f3 100644
--- a/app/components/pub/my-ui/form/combobox.vue
+++ b/app/components/pub/my-ui/form/combobox.vue
@@ -5,6 +5,7 @@ interface Item {
value: string
label: string
code?: string
+ priority?: number
}
const props = defineProps<{
@@ -15,7 +16,7 @@ const props = defineProps<{
searchPlaceholder?: string
emptyMessage?: string
class?: string
- disabled?: boolean
+ isDisabled?: boolean
}>()
const emit = defineEmits<{
@@ -24,31 +25,32 @@ const emit = defineEmits<{
const open = ref(false)
-const selectedItem = computed(() =>
- props.items.find(item => item.value === props.modelValue),
-)
+const selectedItem = computed(() => props.items.find((item) => item.value === props.modelValue))
-const displayText = computed(() =>
- selectedItem.value?.label || props.placeholder || '---pilih item',
-)
+const displayText = computed(() => {
+ if (selectedItem.value?.label) {
+ return selectedItem.value.label
+ }
+ return props.placeholder || 'Pilih item'
+})
-// Create searchable items with combined code and label for better search
-// Sort by:
-// 1. Selected item first (highest priority)
-// 2. Then by label alphabetically
const searchableItems = computed(() => {
- const itemsWithSearch = props.items.map(item => ({
+ const itemsWithSearch = props.items.map((item) => ({
...item,
searchValue: `${item.code || ''} ${item.label}`.trim(),
isSelected: item.value === props.modelValue,
}))
return itemsWithSearch.sort((a, b) => {
- // Selected item always comes first
+ const aPriority = a.priority ?? 0
+ const bPriority = b.priority ?? 0
+ if (aPriority !== bPriority) {
+ return bPriority - aPriority
+ }
+
if (a.isSelected && !b.isSelected) return -1
if (!a.isSelected && b.isSelected) return 1
- // If neither or both are selected, sort by label alphabetically
return a.label.localeCompare(b.label)
})
})
@@ -63,45 +65,78 @@ function onSelect(item: Item) {
-
-
+
+
- {{ emptyMessage || 'Item tidak ditemukan.' }}
-
+
+ {{ emptyMessage || 'Item tidak ditemukan.' }}
+
+
-
-
+
+
{{ item.label }}
- {{ item.code }}
+
+ {{ item.code }}
+
diff --git a/app/components/pub/my-ui/form/datepicker-single.vue b/app/components/pub/my-ui/form/datepicker-single.vue
index 7e628404..5a13117f 100644
--- a/app/components/pub/my-ui/form/datepicker-single.vue
+++ b/app/components/pub/my-ui/form/datepicker-single.vue
@@ -1,9 +1,10 @@
diff --git a/app/components/pub/my-ui/form/field.vue b/app/components/pub/my-ui/form/field.vue
index 96497be5..48e3bc3d 100644
--- a/app/components/pub/my-ui/form/field.vue
+++ b/app/components/pub/my-ui/form/field.vue
@@ -10,8 +10,9 @@ defineProps<{
-
- {{ errors[id]?.message }}
+
+
+ {{ (id && errors?.[id]) ? errors[id]?.message : '' }}
diff --git a/app/components/pub/my-ui/form/input-base.vue b/app/components/pub/my-ui/form/input-base.vue
new file mode 100644
index 00000000..baa4b261
--- /dev/null
+++ b/app/components/pub/my-ui/form/input-base.vue
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/pub/my-ui/form/label.vue b/app/components/pub/my-ui/form/label.vue
index 4186d880..74312222 100644
--- a/app/components/pub/my-ui/form/label.vue
+++ b/app/components/pub/my-ui/form/label.vue
@@ -2,16 +2,18 @@
const props = withDefaults(
defineProps<{
labelFor?: string
- size?: 'default' | 'narrow' | 'wide'
+ size?: 'default' | 'narrow' | 'wide' | 'fit'
height?: 'default' | 'compact'
position?: 'default' | 'dynamic'
stacked?: boolean
+ isRequired?: boolean
}>(),
{
size: 'default',
height: 'default',
position: 'default',
- stacked: false,
+ stacked: true,
+ isRequired: false,
},
)
@@ -19,6 +21,7 @@ const sizeMap = {
default: 'w-28 2xl:w-36',
narrow: 'w-24 2xl:w-28',
wide: 'w-44 2xl:w-48',
+ fit: 'w-fit',
} as const
const heightMap = {
@@ -43,13 +46,23 @@ const wrapperClass = computed(() => [
props.stacked ? '' : positionWrapMap[props.position],
])
-const labelClass = computed(() => [props.stacked ? 'block mb-1 text-sm font-medium' : positionChildMap[props.position]])
+const labelClass = computed(() => [props.stacked ? 'block mb-1 text-sm font-normal' : positionChildMap[props.position]])
-
diff --git a/app/components/pub/my-ui/form/select.vue b/app/components/pub/my-ui/form/select.vue
index ec5f882c..189f112a 100644
--- a/app/components/pub/my-ui/form/select.vue
+++ b/app/components/pub/my-ui/form/select.vue
@@ -1,20 +1,20 @@
-
-
-
+
+
+
@@ -66,10 +147,18 @@ function onValueChange(value: string) {
{{ label }}
-
-
+
+
{{ item.label }}
-
+
{{ item.code }}
diff --git a/app/components/pub/my-ui/form/view/detail-row.vue b/app/components/pub/my-ui/form/view/detail-row.vue
new file mode 100644
index 00000000..2b2b8f6f
--- /dev/null
+++ b/app/components/pub/my-ui/form/view/detail-row.vue
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ {{ label }}
+
+
+
+
+ :
+
+
+
+
diff --git a/app/components/pub/my-ui/form/view/detail-section.vue b/app/components/pub/my-ui/form/view/detail-section.vue
new file mode 100644
index 00000000..50eebbe1
--- /dev/null
+++ b/app/components/pub/my-ui/form/view/detail-section.vue
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
diff --git a/app/components/pub/my-ui/modal/dialog.vue b/app/components/pub/my-ui/modal/dialog.vue
index 548af287..822991d4 100644
--- a/app/components/pub/my-ui/modal/dialog.vue
+++ b/app/components/pub/my-ui/modal/dialog.vue
@@ -41,11 +41,12 @@ const isOpen = computed({