From e78521793b49419e4d1ffd97db44f62c0ada1489 Mon Sep 17 00:00:00 2001 From: riefive Date: Fri, 26 Sep 2025 11:23:05 +0700 Subject: [PATCH 1/9] feat(medicine-method): integrate + refactor entry --- .../app/medicine-method/entry-form.vue | 107 +++++++--- .../content/medicine-method/list.vue | 182 +++++++++++++----- 2 files changed, 211 insertions(+), 78 deletions(-) diff --git a/app/components/app/medicine-method/entry-form.vue b/app/components/app/medicine-method/entry-form.vue index e4f0b60a..043b1e4c 100644 --- a/app/components/app/medicine-method/entry-form.vue +++ b/app/components/app/medicine-method/entry-form.vue @@ -1,37 +1,90 @@ + diff --git a/app/components/content/medicine-method/list.vue b/app/components/content/medicine-method/list.vue index 43d7a03f..46ce2680 100644 --- a/app/components/content/medicine-method/list.vue +++ b/app/components/content/medicine-method/list.vue @@ -1,74 +1,154 @@ + From 457b927c4fd1e818eace02016c25e6cb052a47e9 Mon Sep 17 00:00:00 2001 From: riefive Date: Fri, 26 Sep 2025 12:37:47 +0700 Subject: [PATCH 2/9] chore: restucture list and entry form --- app/components/app/equipment/entry-form.vue | 16 +++++++++------- app/components/app/tools/entry-form.vue | 16 +++++++++------- app/components/content/employee/entry.vue | 2 +- app/components/content/equipment/list.vue | 9 +++++---- app/components/content/material/entry.vue | 4 ++-- app/components/content/medicine-method/list.vue | 14 ++++++++++++-- .../content/specialist-intern/entry.vue | 2 +- app/components/content/tools/list.vue | 9 +++++---- app/models/medicine.ts | 5 +++++ app/schemas/{device.ts => device.schema.ts} | 0 app/schemas/{material.ts => material.schema.ts} | 0 app/schemas/medicine.schema.ts | 12 ++++++++++++ 12 files changed, 61 insertions(+), 28 deletions(-) rename app/schemas/{device.ts => device.schema.ts} (100%) rename app/schemas/{material.ts => material.schema.ts} (100%) create mode 100644 app/schemas/medicine.schema.ts diff --git a/app/components/app/equipment/entry-form.vue b/app/components/app/equipment/entry-form.vue index bb2b0545..5820a495 100644 --- a/app/components/app/equipment/entry-form.vue +++ b/app/components/app/equipment/entry-form.vue @@ -1,16 +1,18 @@ \ No newline at end of file diff --git a/app/components/app/tools/entry-form.vue b/app/components/app/tools/entry-form.vue index 98e0414e..f888c518 100644 --- a/app/components/app/tools/entry-form.vue +++ b/app/components/app/tools/entry-form.vue @@ -73,7 +73,7 @@ function onCancelForm() { diff --git a/app/components/app/medicine-group/list.vue b/app/components/app/medicine-group/list.vue index 5b8778d9..d44aa4d8 100644 --- a/app/components/app/medicine-group/list.vue +++ b/app/components/app/medicine-group/list.vue @@ -1,19 +1,35 @@ diff --git a/app/components/app/medicine-method/list.vue b/app/components/app/medicine-method/list.vue index 5b8778d9..d44aa4d8 100644 --- a/app/components/app/medicine-method/list.vue +++ b/app/components/app/medicine-method/list.vue @@ -1,19 +1,35 @@ diff --git a/app/components/app/tools/list.vue b/app/components/app/tools/list.vue index 076f0f41..d44aa4d8 100644 --- a/app/components/app/tools/list.vue +++ b/app/components/app/tools/list.vue @@ -22,10 +22,14 @@ function handlePageChange(page: number) { diff --git a/app/components/content/medicine-group/list.vue b/app/components/content/medicine-group/list.vue index d437b0c5..34e8d628 100644 --- a/app/components/content/medicine-group/list.vue +++ b/app/components/content/medicine-group/list.vue @@ -2,8 +2,7 @@ // Components import Dialog from '~/components/pub/base/modal/dialog.vue' import Header from '~/components/pub/custom-ui/nav-header/prep.vue' -import AppMedicineMethodEntryForm from '~/components/app/medicine-method/entry-form.vue' -import AppMedicineMethodList from '~/components/app/medicine-method/list.vue' +import AppMedicineGroupEntryForm from '~/components/app/medicine-group/entry-form.vue' import RecordConfirmation from '~/components/pub/custom-ui/confirmation/record-confirmation.vue' // Helpers @@ -27,7 +26,7 @@ import { handleActionEdit, handleActionRemove, handleCancelForm, -} from '~/handlers/medicine-method.handler' +} from '~/handlers/medicine-group.handler' // Services import { getMedicineGroups, getMedicineGroupDetail } from '~/services/medicine-group.service' @@ -47,7 +46,7 @@ const { const result = await getMedicineGroups({ search, page }) return { success: result.success || false, body: result.body || {} } }, - entityName: 'medicine-method', + entityName: 'medicine-group', }) const headerPrep: HeaderPrep = { @@ -93,12 +92,12 @@ watch([recId, recAction], () => { switch (recAction.value) { case ActionEvents.showDetail: getCurrentMedicineGroupDetail(recId.value) - title.value = 'Detail Metode Obat' + title.value = 'Detail Kelompok Obat' isReadonly.value = true break case ActionEvents.showEdit: getCurrentMedicineGroupDetail(recId.value) - title.value = 'Edit Metode Obat' + title.value = 'Edit Kelompok Obat' isReadonly.value = false break case ActionEvents.showConfirmDelete: @@ -121,7 +120,7 @@ onMounted(async () => { diff --git a/app/components/content/medicine-method/list.vue b/app/components/content/medicine-method/list.vue index 9a400c05..fee2e16f 100644 --- a/app/components/content/medicine-method/list.vue +++ b/app/components/content/medicine-method/list.vue @@ -3,7 +3,6 @@ import Dialog from '~/components/pub/base/modal/dialog.vue' import Header from '~/components/pub/custom-ui/nav-header/prep.vue' import AppMedicineMethodEntryForm from '~/components/app/medicine-method/entry-form.vue' -import AppMedicineMethodList from '~/components/app/medicine-method/list.vue' import RecordConfirmation from '~/components/pub/custom-ui/confirmation/record-confirmation.vue' // Helpers From 34a4fc11d0cfd5eacb92a67059f1d43356300fc3 Mon Sep 17 00:00:00 2001 From: riefive Date: Fri, 26 Sep 2025 13:18:32 +0700 Subject: [PATCH 6/9] feat(menu): change menu --- public/side-menu-items/sys.json | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/public/side-menu-items/sys.json b/public/side-menu-items/sys.json index d89634e4..de88cf31 100644 --- a/public/side-menu-items/sys.json +++ b/public/side-menu-items/sys.json @@ -287,11 +287,6 @@ } ] }, - { - "title": "Item & Item Price", - "icon": "i-lucide-shopping-basket", - "link": "/item-src/item" - }, { "title": "Organisasi", "icon": "i-lucide-network", @@ -322,6 +317,22 @@ "link": "/org-src/subspecialist" } ] + }, + { + "title": "Umum", + "icon": "i-lucide-airplay", + "children": [ + { + "title": "Item & Pricing", + "icon": "i-lucide-airplay", + "link": "/common/item" + }, + { + "title": "Uom", + "icon": "i-lucide-airplay", + "link": "/common/uom" + } + ] } ] } From 5d41e4e60d8234c41c5d882009db83e0c94fa4af Mon Sep 17 00:00:00 2001 From: riefive Date: Fri, 26 Sep 2025 14:03:44 +0700 Subject: [PATCH 7/9] chore: modify service and hanler --- app/components/content/equipment/list.vue | 10 ++-- app/components/content/tools/list.vue | 10 ++-- app/handlers/device.handler.ts | 8 +-- app/handlers/material.handler.ts | 8 +-- app/services/device.service.ts | 14 ++--- app/services/material.service.ts | 28 +++++----- app/services/medicine-group.service.ts | 18 +++---- app/services/medicine-method.service.ts | 18 +++---- app/services/uom.service.ts | 64 +++++++++++++++++++++-- 9 files changed, 116 insertions(+), 62 deletions(-) diff --git a/app/components/content/equipment/list.vue b/app/components/content/equipment/list.vue index 2a5b0cab..497b9bd1 100644 --- a/app/components/content/equipment/list.vue +++ b/app/components/content/equipment/list.vue @@ -30,8 +30,8 @@ import { } from '~/handlers/material.handler' // Services -import { getSourceMaterials, getSourceMaterialDetail } from '~/services/material.service' -import { getSourceUoms } from '~/services/uom.service' +import { getMaterials, getMaterialDetail } from '~/services/material.service' +import { getUoms } from '~/services/uom.service' const uoms = ref<{ value: string; label: string }[]>([]) const title = ref('') @@ -46,7 +46,7 @@ const { fetchData: getEquipmentList, } = usePaginatedList({ fetchFn: async ({ page }) => { - const result = await getSourceMaterials({ search: searchInput.value, page }) + const result = await getMaterials({ search: searchInput.value, page }) return { success: result.success || false, body: result.body || {} } }, entityName: 'equipment', @@ -88,7 +88,7 @@ provide('rec_item', recItem) provide('table_data_loader', isLoading) const getCurrentMaterialDetail = async (id: number | string) => { - const result = await getSourceMaterialDetail(id) + const result = await getMaterialDetail(id) if (result.success) { const currentMaterial = result.body?.data || {} recItem.value = currentMaterial @@ -97,7 +97,7 @@ const getCurrentMaterialDetail = async (id: number | string) => { } const getUomList = async () => { - const result = await getSourceUoms() + const result = await getUoms() if (result.success) { const currentUoms = result.body?.data || [] uoms.value = currentUoms.map((uom: Uom) => ({ value: uom.code || uom.erp_id, label: uom.name })) diff --git a/app/components/content/tools/list.vue b/app/components/content/tools/list.vue index 334a927a..31cdc2cb 100644 --- a/app/components/content/tools/list.vue +++ b/app/components/content/tools/list.vue @@ -30,8 +30,8 @@ import { } from '~/handlers/device.handler' // Services -import { getSourceDevices, getSourceDeviceDetail } from '~/services/device.service' -import { getSourceUoms } from '~/services/uom.service' +import { getDevices, getDeviceDetail } from '~/services/device.service' +import { getUoms } from '~/services/uom.service' const uoms = ref<{ value: string; label: string }[]>([]) const title = ref('') @@ -46,7 +46,7 @@ const { fetchData: getToolsList, } = usePaginatedList({ fetchFn: async ({ page }) => { - const result = await getSourceDevices({ search: searchInput.value, page }) + const result = await getDevices({ search: searchInput.value, page }) return { success: result.success || false, body: result.body || {} } }, entityName: 'device', @@ -88,7 +88,7 @@ provide('rec_item', recItem) provide('table_data_loader', isLoading) const getCurrentToolsDetail = async (id: number | string) => { - const result = await getSourceDeviceDetail(id) + const result = await getDeviceDetail(id) if (result.success) { const currentDevice = result.body?.data || {} recItem.value = currentDevice @@ -96,7 +96,7 @@ const getCurrentToolsDetail = async (id: number | string) => { } const getUomList = async () => { - const result = await getSourceUoms() + const result = await getUoms() if (result.success) { const currentUoms = result.body?.data || [] uoms.value = currentUoms.map((uom: Uom) => ({ value: uom.code || uom.erp_id, label: uom.name })) diff --git a/app/handlers/device.handler.ts b/app/handlers/device.handler.ts index f64ca226..e269f61b 100644 --- a/app/handlers/device.handler.ts +++ b/app/handlers/device.handler.ts @@ -4,7 +4,7 @@ import { ref } from 'vue' import { type ToastFn, handleAsyncAction } from '~/handlers/_handler' // Services -import { postSourceDevice, patchSourceDevice, removeSourceDevice } from '~/services/device.service' +import { postDevice, patchDevice, removeDevice } from '~/services/device.service' const recId = ref(0) const recAction = ref('') @@ -28,7 +28,7 @@ export async function handleActionSave( ) { isProcessing.value = true; await handleAsyncAction<[any], any>({ - action: postSourceDevice, + action: postDevice, args: [values], toast, successMessage: 'Data berhasil disimpan', @@ -53,7 +53,7 @@ export async function handleActionEdit( ) { isProcessing.value = true; await handleAsyncAction<[number | string, any], any>({ - action: patchSourceDevice, + action: patchDevice, args: [id, values], toast, successMessage: 'Data berhasil diubah', @@ -76,7 +76,7 @@ export async function handleActionRemove( ) { isProcessing.value = true; await handleAsyncAction<[number | string], any>({ - action: removeSourceDevice, + action: removeDevice, args: [id], toast, successMessage: 'Data berhasil dihapus', diff --git a/app/handlers/material.handler.ts b/app/handlers/material.handler.ts index e09ae59e..d61e5f01 100644 --- a/app/handlers/material.handler.ts +++ b/app/handlers/material.handler.ts @@ -4,7 +4,7 @@ import { ref } from 'vue' import { type ToastFn, handleAsyncAction } from '~/handlers/_handler' // Services -import { postSourceMaterial, patchSourceMaterial, removeSourceMaterial } from '~/services/material.service' +import { postMaterial, patchMaterial, removeMaterial } from '~/services/material.service' const recId = ref(0) const recAction = ref('') @@ -23,7 +23,7 @@ function onResetState() { export async function handleActionSave(values: any, refresh: () => void, reset: () => void, toast: ToastFn) { isProcessing.value = true await handleAsyncAction<[any], any>({ - action: postSourceMaterial, + action: postMaterial, args: [values], toast, successMessage: 'Data berhasil disimpan', @@ -48,7 +48,7 @@ export async function handleActionEdit( ) { isProcessing.value = true await handleAsyncAction<[number | string, any], any>({ - action: patchSourceMaterial, + action: patchMaterial, args: [id, values], toast, successMessage: 'Data berhasil diubah', @@ -67,7 +67,7 @@ export async function handleActionEdit( export async function handleActionRemove(id: number | string, refresh: () => void, toast: ToastFn) { isProcessing.value = true await handleAsyncAction<[number | string], any>({ - action: removeSourceMaterial, + action: removeMaterial, args: [id], toast, successMessage: 'Data berhasil dihapus', diff --git a/app/services/device.service.ts b/app/services/device.service.ts index b979ce87..44f7d1b9 100644 --- a/app/services/device.service.ts +++ b/app/services/device.service.ts @@ -2,7 +2,7 @@ import { xfetch } from '~/composables/useXfetch' const mainUrl = '/api/v1/device' -export async function getSourceDevices(params: any = null) { +export async function getDevices(params: any = null) { try { let url = mainUrl if (params && typeof params === 'object' && Object.keys(params).length > 0) { @@ -21,12 +21,12 @@ export async function getSourceDevices(params: any = null) { result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error fetching source devices:', error) - throw new Error('Failed to fetch source devices') + console.error('Error fetching devices:', error) + throw new Error('Failed to fetch devices') } } -export async function getSourceDeviceDetail(id: string | number) { +export async function getDeviceDetail(id: string | number) { try { const resp = await xfetch(`${mainUrl}/${id}`, 'GET') const result: any = {} @@ -39,7 +39,7 @@ export async function getSourceDeviceDetail(id: string | number) { } } -export async function postSourceDevice(data: any) { +export async function postDevice(data: any) { try { const resp = await xfetch(mainUrl, 'POST', data) const result: any = {} @@ -52,7 +52,7 @@ export async function postSourceDevice(data: any) { } } -export async function patchSourceDevice(id: string | number, data: any) { +export async function patchDevice(id: string | number, data: any) { try { const resp = await xfetch(`${mainUrl}/${id}`, 'PATCH', data) const result: any = {} @@ -65,7 +65,7 @@ export async function patchSourceDevice(id: string | number, data: any) { } } -export async function removeSourceDevice(id: string | number) { +export async function removeDevice(id: string | number) { try { const resp = await xfetch(`${mainUrl}/${id}`, 'DELETE') const result: any = {} diff --git a/app/services/material.service.ts b/app/services/material.service.ts index b4723f4c..098612e0 100644 --- a/app/services/material.service.ts +++ b/app/services/material.service.ts @@ -2,7 +2,7 @@ import { xfetch } from '~/composables/useXfetch' const mainUrl = '/api/v1/material' -export async function getSourceMaterials(params: any = null) { +export async function getMaterials(params: any = null) { try { let url = mainUrl if (params && typeof params === 'object' && Object.keys(params).length > 0) { @@ -21,12 +21,12 @@ export async function getSourceMaterials(params: any = null) { result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error fetching source materials:', error) - throw new Error('Failed to fetch source materials') + console.error('Error fetching materials:', error) + throw new Error('Failed to fetch materials') } } -export async function getSourceMaterialDetail(id: number | string) { +export async function getMaterialDetail(id: number | string) { try { const resp = await xfetch(`${mainUrl}/${id}`, 'GET') const result: any = {} @@ -34,12 +34,12 @@ export async function getSourceMaterialDetail(id: number | string) { result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error fetching source material detail:', error) - throw new Error('Failed to get source material detail') + console.error('Error fetching material detail:', error) + throw new Error('Failed to get material detail') } } -export async function postSourceMaterial(record: any) { +export async function postMaterial(record: any) { try { const resp = await xfetch(mainUrl, 'POST', record) const result: any = {} @@ -47,12 +47,12 @@ export async function postSourceMaterial(record: any) { result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error posting source material:', error) - throw new Error('Failed to post source material') + console.error('Error posting material:', error) + throw new Error('Failed to post material') } } -export async function patchSourceMaterial(id: number | string, record: any) { +export async function patchMaterial(id: number | string, record: any) { try { const resp = await xfetch(`${mainUrl}/${id}`, 'PATCH', record) const result: any = {} @@ -60,12 +60,12 @@ export async function patchSourceMaterial(id: number | string, record: any) { result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error putting source material:', error) - throw new Error('Failed to put source material') + console.error('Error putting material:', error) + throw new Error('Failed to put material') } } -export async function removeSourceMaterial(id: number | string) { +export async function removeMaterial(id: number | string) { try { const resp = await xfetch(`${mainUrl}/${id}`, 'DELETE') const result: any = {} @@ -74,6 +74,6 @@ export async function removeSourceMaterial(id: number | string) { return result } catch (error) { console.error('Error deleting record:', error) - throw new Error('Failed to delete source material') + throw new Error('Failed to delete material') } } diff --git a/app/services/medicine-group.service.ts b/app/services/medicine-group.service.ts index ce16449b..e1f06863 100644 --- a/app/services/medicine-group.service.ts +++ b/app/services/medicine-group.service.ts @@ -21,8 +21,8 @@ export async function getMedicineGroups(params: any = null) { result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error fetching source materials:', error) - throw new Error('Failed to fetch source materials') + console.error('Error fetching medicine groups:', error) + throw new Error('Failed to fetch medicine groups') } } @@ -34,8 +34,8 @@ export async function getMedicineGroupDetail(id: number | string) { result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error fetching source material detail:', error) - throw new Error('Failed to get source material detail') + console.error('Error fetching medicine group detail:', error) + throw new Error('Failed to get medicine group detail') } } @@ -47,8 +47,8 @@ export async function postMedicineGroup(record: any) { result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error posting source material:', error) - throw new Error('Failed to post source material') + console.error('Error posting medicine group:', error) + throw new Error('Failed to post medicine group') } } @@ -60,8 +60,8 @@ export async function patchMedicineGroup(id: number | string, record: any) { result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error putting source material:', error) - throw new Error('Failed to put source material') + console.error('Error putting medicine group:', error) + throw new Error('Failed to put medicine group') } } @@ -74,6 +74,6 @@ export async function removeMedicineGroup(id: number | string) { return result } catch (error) { console.error('Error deleting record:', error) - throw new Error('Failed to delete source material') + throw new Error('Failed to delete medicine group') } } \ No newline at end of file diff --git a/app/services/medicine-method.service.ts b/app/services/medicine-method.service.ts index 319d2c85..3050671c 100644 --- a/app/services/medicine-method.service.ts +++ b/app/services/medicine-method.service.ts @@ -29,8 +29,8 @@ export async function getMedicineMethods(params: any = null) { result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error fetching source materials:', error) - throw new Error('Failed to fetch source materials') + console.error('Error fetching medicine methods:', error) + throw new Error('Failed to fetch medicine methods') } } @@ -42,8 +42,8 @@ export async function getMedicineMethodDetail(id: number | string) { result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error fetching source material detail:', error) - throw new Error('Failed to get source material detail') + console.error('Error fetching medicine method detail:', error) + throw new Error('Failed to get medicine method detail') } } @@ -55,8 +55,8 @@ export async function postMedicineMethod(record: any) { result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error posting source material:', error) - throw new Error('Failed to post source material') + console.error('Error posting medicine method:', error) + throw new Error('Failed to post medicine method') } } @@ -68,8 +68,8 @@ export async function patchMedicineMethod(id: number | string, record: any) { result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error putting source material:', error) - throw new Error('Failed to put source material') + console.error('Error putting medicine method:', error) + throw new Error('Failed to put medicine method') } } @@ -82,6 +82,6 @@ export async function removeMedicineMethod(id: number | string) { return result } catch (error) { console.error('Error deleting record:', error) - throw new Error('Failed to delete source material') + throw new Error('Failed to delete medicine method') } } diff --git a/app/services/uom.service.ts b/app/services/uom.service.ts index 18564f33..f7b2eec1 100644 --- a/app/services/uom.service.ts +++ b/app/services/uom.service.ts @@ -1,8 +1,10 @@ import { xfetch } from '~/composables/useXfetch' -export async function getSourceUoms(params: any = null) { +const mainUrl = '/api/v1/uom' + +export async function getUoms(params: any = null) { try { - let url = '/api/v1/uom' + let url = mainUrl if (params && typeof params === 'object' && Object.keys(params).length > 0) { const searchParams = new URLSearchParams() for (const key in params) { @@ -13,13 +15,65 @@ export async function getSourceUoms(params: any = null) { const queryString = searchParams.toString() if (queryString) url += `?${queryString}` } - const resp = await xfetch(url, 'GET') + const resp = await xfetch(mainUrl, 'GET') const result: any = {} result.success = resp.success result.body = (resp.body as Record) || {} return result } catch (error) { - console.error('Error fetching source uoms:', error) - throw new Error('Failed to fetch source uoms') + console.error('Error fetching uoms:', error) + throw new Error('Failed to fetch uoms') } } + +export async function getUomDetail(id: number | string) { + try { + const resp = await xfetch(`${mainUrl}/${id}`, 'GET') + const result: any = {} + result.success = resp.success + result.body = (resp.body as Record) || {} + return result + } catch (error) { + console.error('Error fetching uom detail:', error) + throw new Error('Failed to get uom detail') + } +} + +export async function postUom(record: any) { + try { + const resp = await xfetch(mainUrl, 'POST', record) + const result: any = {} + result.success = resp.success + result.body = (resp.body as Record) || {} + return result + } catch (error) { + console.error('Error posting uom:', error) + throw new Error('Failed to post uom') + } +} + +export async function patchUom(id: number | string, record: any) { + try { + const resp = await xfetch(`${mainUrl}/${id}`, 'PATCH', record) + const result: any = {} + result.success = resp.success + result.body = (resp.body as Record) || {} + return result + } catch (error) { + console.error('Error putting uom:', error) + throw new Error('Failed to put uom') + } +} + +export async function removeUom(id: number | string) { + try { + const resp = await xfetch(`${mainUrl}/${id}`, 'DELETE') + const result: any = {} + result.success = resp.success + result.body = (resp.body as Record) || {} + return result + } catch (error) { + console.error('Error deleting record:', error) + throw new Error('Failed to delete uom') + } +} \ No newline at end of file From 867f93af31e793112adb649e63cf9ad773c1afbf Mon Sep 17 00:00:00 2001 From: riefive Date: Fri, 26 Sep 2025 15:46:22 +0700 Subject: [PATCH 8/9] feat(uom): integrate api for uom --- app/components/app/medicine-group/picker.vue | 0 app/components/app/medicine-group/search.vue | 0 .../app/medicine-group/status-badge.vue | 29 ---- app/components/app/medicine-method/picker.vue | 0 app/components/app/medicine-method/search.vue | 0 app/components/app/uom/entry-form.vue | 96 +++++++++++ app/components/app/uom/list-cfg.ts | 46 +++++ app/components/app/uom/list.vue | 35 ++++ app/components/content/equipment/list.vue | 4 +- .../content/medicine-group/list.vue | 6 +- .../content/medicine-method/list.vue | 4 +- app/components/content/tools/list.vue | 4 +- app/components/content/uom/list.vue | 162 ++++++++++++++++++ app/handlers/uom.handler.ts | 92 ++++++++++ app/models/_model.ts | 21 ++- app/schemas/base.schema.ts | 12 ++ app/schemas/uom.schema.ts | 4 + 17 files changed, 469 insertions(+), 46 deletions(-) delete mode 100644 app/components/app/medicine-group/picker.vue delete mode 100644 app/components/app/medicine-group/search.vue delete mode 100644 app/components/app/medicine-group/status-badge.vue delete mode 100644 app/components/app/medicine-method/picker.vue delete mode 100644 app/components/app/medicine-method/search.vue create mode 100644 app/components/app/uom/entry-form.vue create mode 100644 app/components/app/uom/list-cfg.ts create mode 100644 app/components/app/uom/list.vue create mode 100644 app/components/content/uom/list.vue create mode 100644 app/handlers/uom.handler.ts create mode 100644 app/schemas/base.schema.ts create mode 100644 app/schemas/uom.schema.ts diff --git a/app/components/app/medicine-group/picker.vue b/app/components/app/medicine-group/picker.vue deleted file mode 100644 index e69de29b..00000000 diff --git a/app/components/app/medicine-group/search.vue b/app/components/app/medicine-group/search.vue deleted file mode 100644 index e69de29b..00000000 diff --git a/app/components/app/medicine-group/status-badge.vue b/app/components/app/medicine-group/status-badge.vue deleted file mode 100644 index 32cdfbca..00000000 --- a/app/components/app/medicine-group/status-badge.vue +++ /dev/null @@ -1,29 +0,0 @@ - - - diff --git a/app/components/app/medicine-method/picker.vue b/app/components/app/medicine-method/picker.vue deleted file mode 100644 index e69de29b..00000000 diff --git a/app/components/app/medicine-method/search.vue b/app/components/app/medicine-method/search.vue deleted file mode 100644 index e69de29b..00000000 diff --git a/app/components/app/uom/entry-form.vue b/app/components/app/uom/entry-form.vue new file mode 100644 index 00000000..3bf95352 --- /dev/null +++ b/app/components/app/uom/entry-form.vue @@ -0,0 +1,96 @@ + + + + diff --git a/app/components/app/uom/list-cfg.ts b/app/components/app/uom/list-cfg.ts new file mode 100644 index 00000000..e2c72f9c --- /dev/null +++ b/app/components/app/uom/list-cfg.ts @@ -0,0 +1,46 @@ +import type { + Col, + KeyLabel, + RecComponent, + RecStrFuncComponent, + RecStrFuncUnknown, + Th, +} from '~/components/pub/custom-ui/data/types' +import { defineAsyncComponent } from 'vue' + +const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue')) + +const _doctorStatus = { + 0: 'Tidak Aktif', + 1: 'Aktif', +} + +export const cols: Col[] = [{}, {}, { width: 50 }] + +export const header: Th[][] = [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Aksi' }]] + +export const keys = ['code', 'name', 'action'] + +export const delKeyNames: KeyLabel[] = [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, +] + +export const funcParsed: RecStrFuncUnknown = {} + +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/uom/list.vue b/app/components/app/uom/list.vue new file mode 100644 index 00000000..d44aa4d8 --- /dev/null +++ b/app/components/app/uom/list.vue @@ -0,0 +1,35 @@ + + + diff --git a/app/components/content/equipment/list.vue b/app/components/content/equipment/list.vue index 497b9bd1..40f5417b 100644 --- a/app/components/content/equipment/list.vue +++ b/app/components/content/equipment/list.vue @@ -90,8 +90,8 @@ provide('table_data_loader', isLoading) const getCurrentMaterialDetail = async (id: number | string) => { const result = await getMaterialDetail(id) if (result.success) { - const currentMaterial = result.body?.data || {} - recItem.value = currentMaterial + const currentValue = result.body?.data || {} + recItem.value = currentValue isFormEntryDialogOpen.value = true } } diff --git a/app/components/content/medicine-group/list.vue b/app/components/content/medicine-group/list.vue index 34e8d628..5dd89f9c 100644 --- a/app/components/content/medicine-group/list.vue +++ b/app/components/content/medicine-group/list.vue @@ -81,8 +81,8 @@ provide('table_data_loader', isLoading) const getCurrentMedicineGroupDetail = async (id: number | string) => { const result = await getMedicineGroupDetail(id) if (result.success) { - const currentMaterial = result.body?.data || {} - recItem.value = currentMaterial + const currentValue = result.body?.data || {} + recItem.value = currentValue isFormEntryDialogOpen.value = true } } @@ -115,7 +115,7 @@ onMounted(async () => {
- +
{ const result = await getMedicineMethodDetail(id) if (result.success) { - const currentMaterial = result.body?.data || {} - recItem.value = currentMaterial + const currentValue = result.body?.data || {} + recItem.value = currentValue isFormEntryDialogOpen.value = true } } diff --git a/app/components/content/tools/list.vue b/app/components/content/tools/list.vue index 31cdc2cb..613df671 100644 --- a/app/components/content/tools/list.vue +++ b/app/components/content/tools/list.vue @@ -90,8 +90,8 @@ provide('table_data_loader', isLoading) const getCurrentToolsDetail = async (id: number | string) => { const result = await getDeviceDetail(id) if (result.success) { - const currentDevice = result.body?.data || {} - recItem.value = currentDevice + const currentValue = result.body?.data || {} + recItem.value = currentValue } } diff --git a/app/components/content/uom/list.vue b/app/components/content/uom/list.vue new file mode 100644 index 00000000..fee2e16f --- /dev/null +++ b/app/components/content/uom/list.vue @@ -0,0 +1,162 @@ + + + diff --git a/app/handlers/uom.handler.ts b/app/handlers/uom.handler.ts new file mode 100644 index 00000000..e24fbcfa --- /dev/null +++ b/app/handlers/uom.handler.ts @@ -0,0 +1,92 @@ +import { ref } from 'vue' + +// Handlers +import { type ToastFn, handleAsyncAction } from '~/handlers/_handler' + +// Services +import { postUom, patchUom, removeUom } from '~/services/uom.service' + +const recId = ref(0) +const recAction = ref('') +const recItem = ref(null) +const isReadonly = ref(false) +const isProcessing = ref(false) +const isFormEntryDialogOpen = ref(false) +const isRecordConfirmationOpen = ref(false) + +function onResetState() { + recId.value = 0 + recAction.value = '' + recItem.value = null +} + +export async function handleActionSave(values: any, refresh: () => void, reset: () => void, toast: ToastFn) { + isProcessing.value = true + await handleAsyncAction<[any], any>({ + action: postUom, + args: [values], + toast, + successMessage: 'Data berhasil disimpan', + errorMessage: 'Gagal menyimpan data', + onSuccess: () => { + isFormEntryDialogOpen.value = false + if (refresh) refresh() + }, + onFinally: (isSuccess: boolean) => { + if (isSuccess) setTimeout(reset, 500) + isProcessing.value = false + }, + }) +} + +export async function handleActionEdit( + id: number | string, + values: any, + refresh: () => void, + reset: () => void, + toast: ToastFn, +) { + isProcessing.value = true + await handleAsyncAction<[number | string, any], any>({ + action: patchUom, + args: [id, values], + toast, + successMessage: 'Data berhasil diubah', + errorMessage: 'Gagal mengubah data', + onSuccess: () => { + isFormEntryDialogOpen.value = false + if (refresh) refresh() + }, + onFinally: (isSuccess: boolean) => { + if (isSuccess) setTimeout(reset, 500) + isProcessing.value = false + }, + }) +} + +export async function handleActionRemove(id: number | string, refresh: () => void, toast: ToastFn) { + isProcessing.value = true + await handleAsyncAction<[number | string], any>({ + action: removeUom, + args: [id], + toast, + successMessage: 'Data berhasil dihapus', + errorMessage: 'Gagal menghapus data', + onSuccess: () => { + if (refresh) refresh() + }, + onFinally: () => { + onResetState() + isProcessing.value = false + }, + }) +} + +export function handleCancelForm(reset: () => void) { + isFormEntryDialogOpen.value = false + setTimeout(() => { + reset() + }, 500) +} + +export { recId, recAction, recItem, isReadonly, isProcessing, isFormEntryDialogOpen, isRecordConfirmationOpen } diff --git a/app/models/_model.ts b/app/models/_model.ts index 64e4a972..b5f09a71 100644 --- a/app/models/_model.ts +++ b/app/models/_model.ts @@ -1,15 +1,20 @@ // Default item meta model for entities export interface ItemMeta { - id: number; - createdAt: string | null; - deletedAt: string | null; - updatedAt: string | null; + id: number + createdAt: string | null + deletedAt: string | null + updatedAt: string | null } // Pagination meta model for API responses export interface PaginationMeta { - page_number: string; - page_size: string; - record_totalCount: string; - source: string; + page_number: string + page_size: string + record_totalCount: string + source: string +} + +export interface Base { + name: string + code: string } diff --git a/app/schemas/base.schema.ts b/app/schemas/base.schema.ts new file mode 100644 index 00000000..b46857ac --- /dev/null +++ b/app/schemas/base.schema.ts @@ -0,0 +1,12 @@ +import { z } from 'zod' +import type { Base } from '~/models/_model' + +const BaseSchema = z.object({ + code: z.string({ required_error: 'Kode harus diisi' }).min(1, 'Kode minimum 1 karakter'), + name: z.string({ required_error: 'Nama harus diisi' }).min(1, 'Nama minimum 1 karakter'), +}) + +type BaseFormData = z.infer & Base + +export { BaseSchema } +export type { BaseFormData } diff --git a/app/schemas/uom.schema.ts b/app/schemas/uom.schema.ts new file mode 100644 index 00000000..4229e420 --- /dev/null +++ b/app/schemas/uom.schema.ts @@ -0,0 +1,4 @@ +import { BaseSchema, type BaseFormData } from './base.schema' + +export { BaseSchema as UomSchema } +export type { BaseFormData as UomFormData } From ca1b0f4cb769edf2c4d3c0ba466e66011ec02e56 Mon Sep 17 00:00:00 2001 From: riefive Date: Fri, 26 Sep 2025 16:04:19 +0700 Subject: [PATCH 9/9] feat(uom): crate form, list and integrate --- app/components/content/uom/list.vue | 52 +++++++++---------- .../device/add.vue => common/uom/index.vue} | 19 ++++--- .../tools-equipment-src/equipment/add.vue | 41 --------------- 3 files changed, 35 insertions(+), 77 deletions(-) rename app/pages/(features)/{tools-equipment-src/device/add.vue => common/uom/index.vue} (70%) delete mode 100644 app/pages/(features)/tools-equipment-src/equipment/add.vue diff --git a/app/components/content/uom/list.vue b/app/components/content/uom/list.vue index fee2e16f..bcb01444 100644 --- a/app/components/content/uom/list.vue +++ b/app/components/content/uom/list.vue @@ -2,7 +2,7 @@ // Components import Dialog from '~/components/pub/base/modal/dialog.vue' import Header from '~/components/pub/custom-ui/nav-header/prep.vue' -import AppMedicineMethodEntryForm from '~/components/app/medicine-method/entry-form.vue' +import AppUomEntryForm from '~/components/app/uom/entry-form.vue' import RecordConfirmation from '~/components/pub/custom-ui/confirmation/record-confirmation.vue' // Helpers @@ -11,7 +11,7 @@ import { toast } from '~/components/pub/ui/toast' // Types import { ActionEvents, type HeaderPrep } from '~/components/pub/custom-ui/data/types' -import { MedicineBaseSchema, type MedicineBaseFormData } from '~/schemas/medicine.schema' +import { UomSchema, type UomFormData } from '~/schemas/uom.schema' // Handlers import { @@ -26,10 +26,10 @@ import { handleActionEdit, handleActionRemove, handleCancelForm, -} from '~/handlers/medicine-method.handler' +} from '~/handlers/uom.handler' // Services -import { getMedicineMethods, getMedicineMethodDetail } from '~/services/medicine-method.service' +import { getUoms, getUomDetail } from '~/services/uom.service' const title = ref('') @@ -40,18 +40,18 @@ const { searchInput, handlePageChange, handleSearch, - fetchData: getMedicineMethodList, + fetchData: getUomList, } = usePaginatedList({ fetchFn: async ({ page, search }) => { - const result = await getMedicineMethods({ search, page }) + const result = await getUoms({ search, page }) return { success: result.success || false, body: result.body || {} } }, - entityName: 'medicine-method', + entityName: 'uom', }) const headerPrep: HeaderPrep = { - title: 'Metode Obat', - icon: 'i-lucide-medicine-bottle', + title: 'Uom', + icon: 'i-lucide-layout-dashboard', refSearchNav: { placeholder: 'Cari (min. 3 karakter)...', minLength: 3, @@ -78,11 +78,11 @@ provide('rec_action', recAction) provide('rec_item', recItem) provide('table_data_loader', isLoading) -const getCurrentMedicineMethodDetail = async (id: number | string) => { - const result = await getMedicineMethodDetail(id) +const getCurrentUomDetail = async (id: number | string) => { + const result = await getUomDetail(id) if (result.success) { - const currentMaterial = result.body?.data || {} - recItem.value = currentMaterial + const currentValue = result.body?.data || {} + recItem.value = currentValue isFormEntryDialogOpen.value = true } } @@ -91,13 +91,13 @@ const getCurrentMedicineMethodDetail = async (id: number | string) => { watch([recId, recAction], () => { switch (recAction.value) { case ActionEvents.showDetail: - getCurrentMedicineMethodDetail(recId.value) - title.value = 'Detail Metode Obat' + getCurrentUomDetail(recId.value) + title.value = 'Detail Uom' isReadonly.value = true break case ActionEvents.showEdit: - getCurrentMedicineMethodDetail(recId.value) - title.value = 'Edit Metode Obat' + getCurrentUomDetail(recId.value) + title.value = 'Edit Uom' isReadonly.value = false break case ActionEvents.showConfirmDelete: @@ -107,7 +107,7 @@ watch([recId, recAction], () => { }) onMounted(async () => { - await getMedicineMethodList() + await getUomList() }) @@ -115,27 +115,27 @@ onMounted(async () => {
- +
- { v-model:open="isRecordConfirmationOpen" action="delete" :record="recItem" - @confirm="() => handleActionRemove(recId, getMedicineMethodList, toast)" + @confirm="() => handleActionRemove(recId, getUomList, toast)" @cancel="" >