From 7ddb14accc1fa640ab5a728fb8d7d0dbc1dce38f Mon Sep 17 00:00:00 2001 From: Munawwirul Jamal Date: Mon, 13 Oct 2025 16:38:23 +0700 Subject: [PATCH 1/5] dev: hotfix, added userQueryCRUD --- app/composables/useQueryCRUD.ts | 54 +++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 app/composables/useQueryCRUD.ts diff --git a/app/composables/useQueryCRUD.ts b/app/composables/useQueryCRUD.ts new file mode 100644 index 00000000..a5c532b7 --- /dev/null +++ b/app/composables/useQueryCRUD.ts @@ -0,0 +1,54 @@ +import { computed } from 'vue' +import { useRoute, useRouter } from 'vue-router' + +export function useQueryCRUDMode(key: string = 'mode') { + const route = useRoute() + const router = useRouter() + + type ModeType = 'list' | 'entry' + const mode = useState('route-query-' + key, () => 'list') + const modeSrc = computed({ + get: () => (route.query[key] && route.query[key] === 'entry' ? 'entry' : 'list'), + set: (val) => { + mode.value = val + router.push({ + path: route.path, + query: { + ...route.query, + [key]: val, + }, + }) + }, + }) + + const goToEntry = () => { + modeSrc.value = 'entry' + } + const backToList = () => { + modeSrc.value = 'list' + } + + return { mode, goToEntry, backToList } +} + +export function useQueryCRUDRecordId(key: string = 'record-id') { + const route = useRoute() + const router = useRouter() + + const recordId = useState('route-query-' + key, () => '') + computed({ + get: () => route.query[key], + set: (val: string) => { + recordId.value = val + router.replace({ + path: route.path, + query: { + ...route.query, + [key]: val, + }, + }) + }, + }) + + return { recordId } +} From 39af6052e729186ae9eae74d435352c178873110 Mon Sep 17 00:00:00 2001 From: Andrian Roshandy Date: Mon, 20 Oct 2025 11:22:54 +0700 Subject: [PATCH 2/5] feat/device-order-58: wip --- .../device-order-item/list-entry.config.ts | 36 +++++ .../app/device-order-item/list-entry.vue | 13 ++ .../app/device-order/entry-form.vue | 6 + .../app/device-order/list.config.ts | 42 +++++ app/components/app/device-order/list.vue | 35 +++++ app/components/content/device-order/entry.vue | 37 +++++ app/components/content/device-order/list.vue | 145 ++++++++++++++++++ app/components/content/device-order/main.vue | 12 ++ app/handlers/device-order-item.handler.ts | 24 +++ app/handlers/device-order.handler.ts | 24 +++ app/schemas/device-order.schema.ts | 12 ++ app/services/device-order-item.service.ts | 26 ++++ app/services/device-order.service.ts | 26 ++++ 13 files changed, 438 insertions(+) create mode 100644 app/components/app/device-order-item/list-entry.config.ts create mode 100644 app/components/app/device-order-item/list-entry.vue create mode 100644 app/components/app/device-order/entry-form.vue create mode 100644 app/components/app/device-order/list.config.ts create mode 100644 app/components/app/device-order/list.vue create mode 100644 app/components/content/device-order/entry.vue create mode 100644 app/components/content/device-order/list.vue create mode 100644 app/components/content/device-order/main.vue create mode 100644 app/handlers/device-order-item.handler.ts create mode 100644 app/handlers/device-order.handler.ts create mode 100644 app/schemas/device-order.schema.ts create mode 100644 app/services/device-order-item.service.ts create mode 100644 app/services/device-order.service.ts diff --git a/app/components/app/device-order-item/list-entry.config.ts b/app/components/app/device-order-item/list-entry.config.ts new file mode 100644 index 00000000..f2f3ef86 --- /dev/null +++ b/app/components/app/device-order-item/list-entry.config.ts @@ -0,0 +1,36 @@ +import { defineAsyncComponent } from 'vue' +import type { Config } from '~/components/pub/my-ui/data-table' + + +const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) + +export const config: Config = { + cols: [{}, {}, { width: 50 }], + headers: [[{ label: 'Nama' }, { label: 'Jumlah' }, { label: '' }]], + keys: ['name', 'count', 'action'], + delKeyNames: [ + { key: 'name', label: 'Nama' }, + { key: 'count', label: 'Jumlah' }, + ], + skeletonSize: 10 + // funcParsed: { + // parent: (rec: unknown): unknown => { + // const recX = rec as SmallDetailDto + // return recX.parent?.name || '-' + // }, + // }, + // funcComponent: { + // action(rec: object, idx: any) { + // const res: RecComponent = { + // idx, + // rec: rec as object, + // component: action, + // props: { + // size: 'sm', + // }, + // } + // return res + // }, + // } +} + diff --git a/app/components/app/device-order-item/list-entry.vue b/app/components/app/device-order-item/list-entry.vue new file mode 100644 index 00000000..26f6691d --- /dev/null +++ b/app/components/app/device-order-item/list-entry.vue @@ -0,0 +1,13 @@ + + + diff --git a/app/components/app/device-order/entry-form.vue b/app/components/app/device-order/entry-form.vue new file mode 100644 index 00000000..bea2b6eb --- /dev/null +++ b/app/components/app/device-order/entry-form.vue @@ -0,0 +1,6 @@ + + + diff --git a/app/components/app/device-order/list.config.ts b/app/components/app/device-order/list.config.ts new file mode 100644 index 00000000..7580c576 --- /dev/null +++ b/app/components/app/device-order/list.config.ts @@ -0,0 +1,42 @@ +import type { Config } from '~/components/pub/my-ui/data-table' +import type { DeviceOrder } from '~/models/device-order' +import { defineAsyncComponent } from 'vue' + +const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) + +export const config: Config = { + cols: [{ width: 120 }, { }, { }, { width: 50 }], + headers: [[{ label: 'Tanggal' }, { label: 'DPJP' }, { label: 'Alat Kesehatan' }, { label: '' }]], + keys: ['createdAt', 'encounter.doctor.person.name', 'items', 'action'], + delKeyNames: [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, + ], + skeletonSize: 10, + htmls: { + items: (rec: unknown): unknown => { + const recX = rec as DeviceOrder + return recX.items?.length || 0 + }, + } + // funcParsed: { + // parent: (rec: unknown): unknown => { + // const recX = rec as SmallDetailDto + // return recX.parent?.name || '-' + // }, + // }, + // funcComponent: { + // action(rec: object, idx: any) { + // const res: RecComponent = { + // idx, + // rec: rec as object, + // component: action, + // props: { + // size: 'sm', + // }, + // } + // return res + // }, + // } +} + diff --git a/app/components/app/device-order/list.vue b/app/components/app/device-order/list.vue new file mode 100644 index 00000000..37b24ea3 --- /dev/null +++ b/app/components/app/device-order/list.vue @@ -0,0 +1,35 @@ + + + diff --git a/app/components/content/device-order/entry.vue b/app/components/content/device-order/entry.vue new file mode 100644 index 00000000..6d76d685 --- /dev/null +++ b/app/components/content/device-order/entry.vue @@ -0,0 +1,37 @@ + + + diff --git a/app/components/content/device-order/list.vue b/app/components/content/device-order/list.vue new file mode 100644 index 00000000..e62a2fbd --- /dev/null +++ b/app/components/content/device-order/list.vue @@ -0,0 +1,145 @@ + + + diff --git a/app/components/content/device-order/main.vue b/app/components/content/device-order/main.vue new file mode 100644 index 00000000..ae5a9ca8 --- /dev/null +++ b/app/components/content/device-order/main.vue @@ -0,0 +1,12 @@ + + + diff --git a/app/handlers/device-order-item.handler.ts b/app/handlers/device-order-item.handler.ts new file mode 100644 index 00000000..b1df996b --- /dev/null +++ b/app/handlers/device-order-item.handler.ts @@ -0,0 +1,24 @@ +// Handlers +import { genCrudHandler } from '~/handlers/_handler' + +// Services +import { create, update, remove } from '~/services/device-order-item.service' + +export const { + recId, + recAction, + recItem, + isReadonly, + isProcessing, + isFormEntryDialogOpen, + isRecordConfirmationOpen, + onResetState, + handleActionSave, + handleActionEdit, + handleActionRemove, + handleCancelForm, +} = genCrudHandler({ + create, + update, + remove, +}) diff --git a/app/handlers/device-order.handler.ts b/app/handlers/device-order.handler.ts new file mode 100644 index 00000000..b1df996b --- /dev/null +++ b/app/handlers/device-order.handler.ts @@ -0,0 +1,24 @@ +// Handlers +import { genCrudHandler } from '~/handlers/_handler' + +// Services +import { create, update, remove } from '~/services/device-order-item.service' + +export const { + recId, + recAction, + recItem, + isReadonly, + isProcessing, + isFormEntryDialogOpen, + isRecordConfirmationOpen, + onResetState, + handleActionSave, + handleActionEdit, + handleActionRemove, + handleCancelForm, +} = genCrudHandler({ + create, + update, + remove, +}) diff --git a/app/schemas/device-order.schema.ts b/app/schemas/device-order.schema.ts new file mode 100644 index 00000000..b0c2a56c --- /dev/null +++ b/app/schemas/device-order.schema.ts @@ -0,0 +1,12 @@ +import { z } from 'zod' +import type { DeviceOrder } from '~/models/device-order' + +const DeviceOrderSchema = z.object({ + encounter_id: z.number({ required_error: 'Kode harus diisi' }), + doctor_id: z.number({ required_error: 'Kode harus diisi' }), +}) + +type DeviceOrderFormData = z.infer & Partial + +export { DeviceOrderSchema } +export type { DeviceOrderFormData } diff --git a/app/services/device-order-item.service.ts b/app/services/device-order-item.service.ts new file mode 100644 index 00000000..33b92b8c --- /dev/null +++ b/app/services/device-order-item.service.ts @@ -0,0 +1,26 @@ +// Base +import * as base from './_crud-base' + +const path = '/api/v1/device-order-item' +const name = 'device-order-item' + +export function create(data: any) { + console.log('service create', data) + return base.create(path, data, name) +} + +export function getList(params: any = null) { + return base.getList(path, params, name) +} + +export function getDetail(id: number | string) { + return base.getDetail(path, id, name) +} + +export function update(id: number | string, data: any) { + return base.update(path, id, data, name) +} + +export function remove(id: number | string) { + return base.remove(path, id, name) +} diff --git a/app/services/device-order.service.ts b/app/services/device-order.service.ts new file mode 100644 index 00000000..b8d5372c --- /dev/null +++ b/app/services/device-order.service.ts @@ -0,0 +1,26 @@ +// Base +import * as base from './_crud-base' + +const path = '/api/v1/device-order' +const name = 'device-order' + +export function create(data: any) { + console.log('service create', data) + return base.create(path, data, name) +} + +export function getList(params: any = null) { + return base.getList(path, params, name) +} + +export function getDetail(id: number | string) { + return base.getDetail(path, id, name) +} + +export function update(id: number | string, data: any) { + return base.update(path, id, data, name) +} + +export function remove(id: number | string) { + return base.remove(path, id, name) +} From 7f3fe813c547c6fdc58a0194827aca885d49a344 Mon Sep 17 00:00:00 2001 From: Andrian Roshandy Date: Thu, 23 Oct 2025 14:09:01 +0700 Subject: [PATCH 3/5] feat/device-order: wip --- app/components/content/device-order/list.vue | 24 ++++++++++++++------ app/components/content/encounter/process.vue | 3 ++- app/handlers/device-order.handler.ts | 5 ++-- app/services/device-order-item.service.ts | 1 - 4 files changed, 22 insertions(+), 11 deletions(-) diff --git a/app/components/content/device-order/list.vue b/app/components/content/device-order/list.vue index e62a2fbd..8c53f244 100644 --- a/app/components/content/device-order/list.vue +++ b/app/components/content/device-order/list.vue @@ -32,8 +32,15 @@ import { handleCancelForm, } from '~/handlers/device-order.handler' -// Services +// import { getList } from '~/services/device-order.service' +import type { Encounter } from '~/models/encounter' + +// Props +interface Props { + encounter: Encounter +} +const props = defineProps() const route = useRoute() const title = ref('') @@ -57,7 +64,7 @@ const { sort: 'createdAt:asc', 'page-number': params['page-number'] || 0, 'page-size': params['page-size'] || 10, - includes: 'parent,childrens', + includes: 'encounter', }) return { success: result.success || false, body: result.body || {} } }, @@ -82,11 +89,14 @@ const headerPrep: HeaderPrep = { label: 'Tambah', icon: 'i-lucide-plus', onClick: async () => { - recItem.value = null - recId.value = 0 - isReadonly.value = false - // await handleActionSave(recItem, getMyList, () => {}, () => {}) - goToEntry() + const data = { + encounter_id: props.encounter.id, + } + const dateResp = await handleActionSave(data, getMyList, () => {}, () => {}) + if (dateResp.success) { + const currentData = dateResp.body.data || [] + // goToEntry() + } }, }, } diff --git a/app/components/content/encounter/process.vue b/app/components/content/encounter/process.vue index 6fc620b5..d4279504 100644 --- a/app/components/content/encounter/process.vue +++ b/app/components/content/encounter/process.vue @@ -17,6 +17,7 @@ import EarlyMedicalAssesmentList from '~/components/content/soapi/entry.vue' // import AssesmentFunctionList from '~/components/content/assesment-function/list.vue' import PrescriptionList from '~/components/content/prescription/list.vue' import EarlyMedicalRehabList from '~/components/content/soapi/entry.vue' +import DeviceOrder from '~/components/content/device-order/main.vue' import Consultation from '~/components/content/consultation/list.vue' const route = useRoute() @@ -49,7 +50,7 @@ const tabs: TabItem[] = [ { value: 'consent', label: 'General Consent' }, { value: 'patient-note', label: 'CPRJ' }, { value: 'prescription', label: 'Order Obat', component: PrescriptionList }, - { value: 'device', label: 'Order Alkes' }, + { value: 'device-order', label: 'Order Alkes', component: DeviceOrder, props: { encounter: data } }, { value: 'mcu-radiology', label: 'Order Radiologi' }, { value: 'mcu-lab-pc', label: 'Order Lab PK' }, { value: 'mcu-lab-micro', label: 'Order Lab Mikro' }, diff --git a/app/handlers/device-order.handler.ts b/app/handlers/device-order.handler.ts index b1df996b..25529894 100644 --- a/app/handlers/device-order.handler.ts +++ b/app/handlers/device-order.handler.ts @@ -1,8 +1,9 @@ // Handlers import { genCrudHandler } from '~/handlers/_handler' +import type { DeviceOrder, CreateDto } from '~/models/device-order' // Services -import { create, update, remove } from '~/services/device-order-item.service' +import { create, update, remove } from '~/services/device-order.service' export const { recId, @@ -17,7 +18,7 @@ export const { handleActionEdit, handleActionRemove, handleCancelForm, -} = genCrudHandler({ +} = genCrudHandler({ create, update, remove, diff --git a/app/services/device-order-item.service.ts b/app/services/device-order-item.service.ts index 33b92b8c..b2eab0f4 100644 --- a/app/services/device-order-item.service.ts +++ b/app/services/device-order-item.service.ts @@ -5,7 +5,6 @@ const path = '/api/v1/device-order-item' const name = 'device-order-item' export function create(data: any) { - console.log('service create', data) return base.create(path, data, name) } From 7253272681411379b732340e1d84556c914d595d Mon Sep 17 00:00:00 2001 From: Andrian Roshandy Date: Sun, 16 Nov 2025 11:21:02 +0700 Subject: [PATCH 4/5] feat/device-order: adjustment wip --- .../app/device-order/list.config.ts | 35 ++++-- app/components/app/device-order/list.vue | 8 +- app/components/content/device-order/list.vue | 106 +++++++++++++----- app/models/device-order.ts | 3 + 4 files changed, 110 insertions(+), 42 deletions(-) diff --git a/app/components/app/device-order/list.config.ts b/app/components/app/device-order/list.config.ts index 7580c576..0e0d068d 100644 --- a/app/components/app/device-order/list.config.ts +++ b/app/components/app/device-order/list.config.ts @@ -1,13 +1,20 @@ import type { Config } from '~/components/pub/my-ui/data-table' import type { DeviceOrder } from '~/models/device-order' -import { defineAsyncComponent } from 'vue' +// import type {} from +// import { defineAsyncComponent } from 'vue' + +// const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) -const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) export const config: Config = { - cols: [{ width: 120 }, { }, { }, { width: 50 }], - headers: [[{ label: 'Tanggal' }, { label: 'DPJP' }, { label: 'Alat Kesehatan' }, { label: '' }]], - keys: ['createdAt', 'encounter.doctor.person.name', 'items', 'action'], + cols: [{ width: 120 }, { }, { }, { }, { width: 50 }], + headers: [[ + { label: 'Tanggal' }, + { label: 'DPJP' }, + { label: 'Alat Kesehatan' }, + { label: 'Status' }, + { label: '' }]], + keys: ['createdAt', 'doctor.employee.person.name', 'items', 'status_code', 'action'], delKeyNames: [ { key: 'code', label: 'Kode' }, { key: 'name', label: 'Nama' }, @@ -18,13 +25,17 @@ export const config: Config = { const recX = rec as DeviceOrder return recX.items?.length || 0 }, - } - // funcParsed: { - // parent: (rec: unknown): unknown => { - // const recX = rec as SmallDetailDto - // return recX.parent?.name || '-' - // }, - // }, + }, + parses: { + createdAt: (rec: unknown): unknown => { + const recX = rec as DeviceOrder + return recX.createdAt ? new Date(recX.createdAt).toLocaleDateString() : '-' + }, + // parent: (rec: unknown): unknown => { + // const recX = rec as SmallDetailDto + // return recX.parent?.name || '-' + // }, + }, // funcComponent: { // action(rec: object, idx: any) { // const res: RecComponent = { diff --git a/app/components/app/device-order/list.vue b/app/components/app/device-order/list.vue index 37b24ea3..83f57dd6 100644 --- a/app/components/app/device-order/list.vue +++ b/app/components/app/device-order/list.vue @@ -8,12 +8,10 @@ import type { PaginationMeta } from '~/components/pub/my-ui/pagination/paginatio // Configs import { config } from './list.config' -interface Props { +defineProps<{ data: any[] paginationMeta: PaginationMeta -} - -defineProps() +}>() const emit = defineEmits<{ pageChange: [page: number] @@ -28,7 +26,7 @@ function handlePageChange(page: number) {
diff --git a/app/components/content/device-order/list.vue b/app/components/content/device-order/list.vue index 1d0bd0fa..6c23cfc0 100644 --- a/app/components/content/device-order/list.vue +++ b/app/components/content/device-order/list.vue @@ -32,21 +32,18 @@ import { handleCancelForm, } from '~/handlers/device-order.handler' -// -import { getList } from '~/services/device-order.service' - -// Props -interface Props { - encounter_id: number -} -const props = defineProps() +// Services +import { getList, getDetail } from '~/services/device-order.service' const route = useRoute() -const title = ref('') +const { setQueryParams } = useQueryParam() + +const plainEid = route.params.id +const encounter_id = (plainEid && typeof plainEid == 'string') ? parseInt(plainEid) : 0 // const { mode, openForm, backToList } = useQueryMode() const { mode, goToEntry, backToList } = useQueryCRUDMode() -const { recordId } = useQueryCRUDRecordId() +// const { recordId } = useQueryCRUDRecordId() const { data, @@ -59,18 +56,18 @@ const { } = usePaginatedList({ fetchFn: async (params: any) => { const result = await getList({ + 'encounter-id': encounter_id, search: params.search, - sort: 'createdAt:asc', + includes: 'doctor,doctor-employee,doctor-employee-person,items', 'page-number': params['page-number'] || 0, 'page-size': params['page-size'] || 10, - // includes: 'encounter', - includes: 'parent,childrens', }) return { success: result.success || false, body: result.body || {} } }, entityName: 'device-order', }) +const voidFn = () => {} const headerPrep: HeaderPrep = { title: 'Order Alkes', icon: 'i-lucide-box', @@ -89,19 +86,18 @@ const headerPrep: HeaderPrep = { label: 'Tambah', icon: 'i-lucide-plus', onClick: async () => { - const data = { - encounter_id: props.encounter_id, - } - const dateResp = await handleActionSave(data, getMyList, () => {}, () => {}) - if (dateResp.success) { - const currentData = dateResp.body.data || [] - // goToEntry() - } recItem.value = null recId.value = 0 isReadonly.value = false + const saveResp = await handleActionSave({ encounter_id }, voidFn, voidFn, voidFn) + if (saveResp.success) { + setQueryParams({ + 'mode': 'entry', + 'id': saveResp.body?.data?.id.toString() + }) + } // await handleActionSave(recItem, getMyList, () => {}, () => {}) - goToEntry() + // goToEntry() }, }, } @@ -111,10 +107,66 @@ provide('rec_action', recAction) provide('rec_item', recItem) provide('table_data_loader', isLoading) -// Watch for row actions when recId or recAction changes -onMounted(async () => { - await getMyList() +watch([recId, recAction], () => { + switch (recAction.value) { + case ActionEvents.showDetail: + getMyDetail(recId.value) + isReadonly.value = true + break + case ActionEvents.showEdit: + getMyDetail(recId.value) + isReadonly.value = false + break + case ActionEvents.showConfirmDelete: + break + } }) + +// watch([isFormEntryDialogOpen], async () => { +// if (isFormEntryDialogOpen.value) { +// isFormEntryDialogOpen.value = false; +// const saveResp = await handleActionSave({ encounter_id }, getMyList, () =>{}, toast) +// if (saveResp.success) { +// setQueryParams({ +// 'mode': 'entry', +// 'id': saveResp.body?.data?.id.toString() +// }) +// } +// } +// }) + +// Watch for row actions when recId or recAction changes +// onMounted(async () => { +// await getMyList() +// }) + +// Functions +const getMyDetail = async (id: number | string) => { + const result = await getDetail(id) + if (result.success) { + const currentValue = result.body?.data || {} + recItem.value = currentValue + isFormEntryDialogOpen.value = true + } +} + +function cancel(data: DeviceOrder) { + recId.value = data.id + recItem.value = data + isRecordConfirmationOpen.value = true +} + +function edit(data: DeviceOrder) { + setQueryParams({ + 'mode': 'entry', + 'id': data.id.toString() + }) + recItem.value = data +} + +function submit(data: DeviceOrder) { +} +