diff --git a/app/components/app/division-position/entry.vue b/app/components/app/division-position/entry.vue new file mode 100644 index 00000000..da4782c0 --- /dev/null +++ b/app/components/app/division-position/entry.vue @@ -0,0 +1,192 @@ + + + + + + + Kode Jabatan + + + + + + Nama Jabatan + + + + + + Pengisi Jabatan + + + + + + Status Kepala + + + + + Ya + + + + Tidak + + + + + + + + Kembali + + + Simpan + + + + diff --git a/app/components/app/division-position/list-cfg.ts b/app/components/app/division-position/list-cfg.ts index e35627d2..cc153cc5 100644 --- a/app/components/app/division-position/list-cfg.ts +++ b/app/components/app/division-position/list-cfg.ts @@ -1,5 +1,6 @@ import type { Config, RecComponent } from '~/components/pub/my-ui/data-table' import { defineAsyncComponent } from 'vue' +import type { DivisionPosition } from '~/models/division-position' type SmallDetailDto = any @@ -10,9 +11,9 @@ export const config: Config = { headers: [ [ - { label: 'Kode' }, - { label: 'Nama' }, - { label: 'Divisi Induk' }, + { label: 'Kode Posisi' }, + { label: 'Nama Posisi' }, + { label: 'Nama Divisi ' }, { label: 'Karyawan' }, { label: 'Status Kepala' }, { label: '' }, @@ -32,8 +33,13 @@ export const config: Config = { return recX.division?.name || '-' }, employee: (rec: unknown): unknown => { - const recX = rec as SmallDetailDto - return recX.employee?.name || '-' + const recX = rec as DivisionPosition + const fullName = [recX.employee?.person.frontTitle, recX.employee?.person.name, recX.employee?.person.endTitle] + .filter(Boolean) + .join(' ') + .trim() + + return fullName || '-' }, head: (rec: unknown): unknown => { const recX = rec as SmallDetailDto diff --git a/app/components/app/division/detail/index.vue b/app/components/app/division/detail/index.vue new file mode 100644 index 00000000..dd5a4c59 --- /dev/null +++ b/app/components/app/division/detail/index.vue @@ -0,0 +1,34 @@ + + + + {{ division.code || '-' }} + {{ division.name || '-' }} + + + diff --git a/app/components/app/division/detail/list-cfg.ts b/app/components/app/division/detail/list-cfg.ts new file mode 100644 index 00000000..76c3b9c8 --- /dev/null +++ b/app/components/app/division/detail/list-cfg.ts @@ -0,0 +1,65 @@ +import type { Config, RecComponent } from '~/components/pub/my-ui/data-table' +import { defineAsyncComponent } from 'vue' +import type { DivisionPosition } from '~/models/division-position' + +type SmallDetailDto = any + +const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) + +export const config: Config = { + cols: [{}, {}, {}, {}, {}, { width: 50 }], + + headers: [ + [ + { label: '#' }, + { label: 'Kode Jabatan' }, + { label: 'Nama Jabatan' }, + { label: 'Pengisi Jabatan' }, + { label: 'Status Kepala' }, + { label: '' }, + ], + ], + + keys: ['index', 'code', 'name', 'employee', 'head', 'action'], + + delKeyNames: [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, + ], + + parses: { + division: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return recX.division?.name || '-' + }, + employee: (rec: unknown): unknown => { + const recX = rec as DivisionPosition + const fullName = [recX.employee?.person.frontTitle, recX.employee?.person.name, recX.employee?.person.endTitle] + .filter(Boolean) + .join(' ') + .trim() + + return fullName || '-' + }, + head: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return recX.headStatus ? 'Ya' : 'Tidak' + }, + }, + + components: { + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + props: { + size: 'sm', + }, + } + return res + }, + }, + + htmls: {}, +} diff --git a/app/components/app/division/detail/list.vue b/app/components/app/division/detail/list.vue new file mode 100644 index 00000000..4bbebb57 --- /dev/null +++ b/app/components/app/division/detail/list.vue @@ -0,0 +1,45 @@ + + + + + + + + + + + diff --git a/app/components/app/division/list-cfg.ts b/app/components/app/division/list-cfg.ts index 54ed06a6..2d7f93ba 100644 --- a/app/components/app/division/list-cfg.ts +++ b/app/components/app/division/list-cfg.ts @@ -3,17 +3,12 @@ import { defineAsyncComponent } from 'vue' type SmallDetailDto = any -const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) +const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue')) export const config: Config = { cols: [{}, {}, {}, { width: 50 }], - headers: [[ - { label: 'Kode' }, - { label: 'Nama' }, - { label: 'Divisi Induk' }, - { label: '' }, - ]], + headers: [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Divisi Induk' }, { label: '' }]], keys: ['code', 'name', 'parent', 'action'], @@ -44,4 +39,4 @@ export const config: Config = { }, htmls: {}, -} \ No newline at end of file +} diff --git a/app/components/app/installation-position/entry-detail.vue b/app/components/app/installation-position/entry-detail.vue new file mode 100644 index 00000000..a6bfd113 --- /dev/null +++ b/app/components/app/installation-position/entry-detail.vue @@ -0,0 +1,192 @@ + + + + + + + Kode Jabatan + + + + + + Nama Jabatan + + + + + + Pengisi Jabatan + + + + + + Status Kepala + + + + + Ya + + + + Tidak + + + + + + + + Kembali + + + Simpan + + + + diff --git a/app/components/app/installation-position/entry-form.vue b/app/components/app/installation-position/entry-form.vue new file mode 100644 index 00000000..4f7885a1 --- /dev/null +++ b/app/components/app/installation-position/entry-form.vue @@ -0,0 +1,207 @@ + + + + + + + Kode + + + + + + Nama Posisi + + + + + + Instalasi + + + + + + Karyawan + + + + + + Status Kepala + + + + + Ya + + + + Tidak + + + + + + + + Kembali + + + Simpan + + + + diff --git a/app/components/app/installation-position/list.cfg.ts b/app/components/app/installation-position/list.cfg.ts new file mode 100644 index 00000000..fe3f6c9c --- /dev/null +++ b/app/components/app/installation-position/list.cfg.ts @@ -0,0 +1,65 @@ +import type { Config, RecComponent } from '~/components/pub/my-ui/data-table' +import { defineAsyncComponent } from 'vue' +import type { DivisionPosition } from '~/models/division-position' + +type SmallDetailDto = any + +const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) + +export const config: Config = { + cols: [{}, {}, {}, {}, {}, { width: 50 }], + + headers: [ + [ + { label: 'Kode Posisi' }, + { label: 'Nama Posisi' }, + { label: 'Nama Instalasi ' }, + { label: 'Karyawan' }, + { label: 'Status Kepala' }, + { label: '' }, + ], + ], + + keys: ['code', 'name', 'installation.name', 'employee', 'head', 'action'], + + delKeyNames: [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, + ], + + parses: { + division: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return recX.division?.name || '-' + }, + employee: (rec: unknown): unknown => { + const recX = rec as DivisionPosition + const fullName = [recX.employee?.person.frontTitle, recX.employee?.person.name, recX.employee?.person.endTitle] + .filter(Boolean) + .join(' ') + .trim() + + return fullName || '-' + }, + head: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return recX.headStatus ? 'Ya' : 'Tidak' + }, + }, + + components: { + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + props: { + size: 'sm', + }, + } + return res + }, + }, + + htmls: {}, +} diff --git a/app/components/app/installation-position/list.vue b/app/components/app/installation-position/list.vue new file mode 100644 index 00000000..6ad7dd81 --- /dev/null +++ b/app/components/app/installation-position/list.vue @@ -0,0 +1,39 @@ + + + + + + + + diff --git a/app/components/app/installation/detail/index.vue b/app/components/app/installation/detail/index.vue new file mode 100644 index 00000000..8a668d1c --- /dev/null +++ b/app/components/app/installation/detail/index.vue @@ -0,0 +1,34 @@ + + + + {{ installation.code || '-' }} + {{ installation.name || '-' }} + + + diff --git a/app/components/app/installation/detail/list.cfg.ts b/app/components/app/installation/detail/list.cfg.ts new file mode 100644 index 00000000..bf341ff9 --- /dev/null +++ b/app/components/app/installation/detail/list.cfg.ts @@ -0,0 +1,65 @@ +import type { Config, RecComponent } from '~/components/pub/my-ui/data-table' +import { defineAsyncComponent } from 'vue' +import type { DivisionPosition } from '~/models/division-position' + +type SmallDetailDto = any + +const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) + +export const config: Config = { + cols: [{}, {}, {}, {}, {}, { width: 50 }], + + headers: [ + [ + { label: '#' }, + { label: 'Kode Posisi' }, + { label: 'Nama Posisi' }, + { label: 'Karyawan' }, + { label: 'Status Kepala' }, + { label: '' }, + ], + ], + + keys: ['index', 'code', 'name', 'employee', 'head', 'action'], + + delKeyNames: [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, + ], + + parses: { + division: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return recX.division?.name || '-' + }, + employee: (rec: unknown): unknown => { + const recX = rec as DivisionPosition + const fullName = [recX.employee?.person.frontTitle, recX.employee?.person.name, recX.employee?.person.endTitle] + .filter(Boolean) + .join(' ') + .trim() + + return fullName || '-' + }, + head: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return recX.headStatus ? 'Ya' : 'Tidak' + }, + }, + + components: { + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + props: { + size: 'sm', + }, + } + return res + }, + }, + + htmls: {}, +} diff --git a/app/components/app/installation/detail/list.vue b/app/components/app/installation/detail/list.vue new file mode 100644 index 00000000..b5884cfd --- /dev/null +++ b/app/components/app/installation/detail/list.vue @@ -0,0 +1,45 @@ + + + + + + + + + + + diff --git a/app/components/app/installation/list-cfg.ts b/app/components/app/installation/list.cfg.ts similarity index 83% rename from app/components/app/installation/list-cfg.ts rename to app/components/app/installation/list.cfg.ts index f64ecea8..e2a39d80 100644 --- a/app/components/app/installation/list-cfg.ts +++ b/app/components/app/installation/list.cfg.ts @@ -3,19 +3,12 @@ import { defineAsyncComponent } from 'vue' type SmallDetailDto = any -const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) +const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue')) export const config: Config = { cols: [{}, {}, {}, { width: 50 }], - headers: [ - [ - { label: 'Kode' }, - { label: 'Nama' }, - { label: 'Encounter Class' }, - { label: '' }, - ], - ], + headers: [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Encounter Class' }, { label: '' }]], keys: ['code', 'name', 'encounterClass_code', 'action'], diff --git a/app/components/app/installation/list.vue b/app/components/app/installation/list.vue index 1be60a60..6ad7dd81 100644 --- a/app/components/app/installation/list.vue +++ b/app/components/app/installation/list.vue @@ -6,7 +6,7 @@ import PaginationView from '~/components/pub/my-ui/pagination/pagination-view.vu import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type' // Configs -import { config } from './list-cfg' +import { config } from './list.cfg' interface Props { data: any[] @@ -31,6 +31,9 @@ function handlePageChange(page: number) { :rows="data" :skeleton-size="paginationMeta?.pageSize" /> - + diff --git a/app/components/app/specialist-position/entry-detail.vue b/app/components/app/specialist-position/entry-detail.vue new file mode 100644 index 00000000..f21ff65f --- /dev/null +++ b/app/components/app/specialist-position/entry-detail.vue @@ -0,0 +1,192 @@ + + + + + + + Kode Jabatan + + + + + + Nama Jabatan + + + + + + Pengisi Jabatan + + + + + + Status Kepala + + + + + Ya + + + + Tidak + + + + + + + + Kembali + + + Simpan + + + + diff --git a/app/components/app/specialist-position/entry-form.vue b/app/components/app/specialist-position/entry-form.vue new file mode 100644 index 00000000..be031219 --- /dev/null +++ b/app/components/app/specialist-position/entry-form.vue @@ -0,0 +1,207 @@ + + + + + + + Kode + + + + + + Nama Posisi + + + + + + Spesialis + + + + + + Karyawan + + + + + + Status Kepala + + + + + Ya + + + + Tidak + + + + + + + + Kembali + + + Simpan + + + + diff --git a/app/components/app/specialist-position/list.cfg.ts b/app/components/app/specialist-position/list.cfg.ts new file mode 100644 index 00000000..35f49c20 --- /dev/null +++ b/app/components/app/specialist-position/list.cfg.ts @@ -0,0 +1,61 @@ +import type { Config, RecComponent } from '~/components/pub/my-ui/data-table' +import { defineAsyncComponent } from 'vue' +import type { DivisionPosition } from '~/models/division-position' + +type SmallDetailDto = any + +const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) + +export const config: Config = { + cols: [{}, {}, {}, {}, {}, { width: 50 }], + + headers: [ + [ + { label: 'Kode Posisi' }, + { label: 'Nama Posisi' }, + { label: 'Nama Spesialis ' }, + { label: 'Karyawan' }, + { label: 'Status Kepala' }, + { label: '' }, + ], + ], + + keys: ['code', 'name', 'specialist.name', 'employee', 'head', 'action'], + + delKeyNames: [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, + ], + + parses: { + employee: (rec: unknown): unknown => { + const recX = rec as DivisionPosition + const fullName = [recX.employee?.person.frontTitle, recX.employee?.person.name, recX.employee?.person.endTitle] + .filter(Boolean) + .join(' ') + .trim() + + return fullName || '-' + }, + head: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return recX.headStatus ? 'Ya' : 'Tidak' + }, + }, + + components: { + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + props: { + size: 'sm', + }, + } + return res + }, + }, + + htmls: {}, +} diff --git a/app/components/app/specialist-position/list.vue b/app/components/app/specialist-position/list.vue new file mode 100644 index 00000000..6ad7dd81 --- /dev/null +++ b/app/components/app/specialist-position/list.vue @@ -0,0 +1,39 @@ + + + + + + + + diff --git a/app/components/app/specialist/detail/index.vue b/app/components/app/specialist/detail/index.vue new file mode 100644 index 00000000..3f32a78f --- /dev/null +++ b/app/components/app/specialist/detail/index.vue @@ -0,0 +1,37 @@ + + + + {{ specialist.code || '-' }} + {{ specialist.name || '-' }} + + {{ [specialist.unit?.code, specialist.unit?.name].filter(Boolean).join(' / ') || '-' }} + + + + diff --git a/app/components/app/specialist/detail/list.cfg.ts b/app/components/app/specialist/detail/list.cfg.ts new file mode 100644 index 00000000..8faf9e61 --- /dev/null +++ b/app/components/app/specialist/detail/list.cfg.ts @@ -0,0 +1,61 @@ +import type { Config, RecComponent } from '~/components/pub/my-ui/data-table' +import { defineAsyncComponent } from 'vue' +import type { UnitPosition } from '~/models/unit-position' + +type SmallDetailDto = any + +const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) + +export const config: Config = { + cols: [{}, {}, {}, {}, {}, { width: 50 }], + + headers: [ + [ + { label: '#' }, + { label: 'Kode Posisi' }, + { label: 'Nama Posisi' }, + { label: 'Karyawan' }, + { label: 'Status Kepala' }, + { label: '' }, + ], + ], + + keys: ['index', 'code', 'name', 'employee', 'head', 'action'], + + delKeyNames: [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, + ], + + parses: { + employee: (rec: unknown): unknown => { + const recX = rec as UnitPosition + const fullName = [recX.employee?.person.frontTitle, recX.employee?.person.name, recX.employee?.person.endTitle] + .filter(Boolean) + .join(' ') + .trim() + + return fullName || '-' + }, + head: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return recX.headStatus ? 'Ya' : 'Tidak' + }, + }, + + components: { + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + props: { + size: 'sm', + }, + } + return res + }, + }, + + htmls: {}, +} diff --git a/app/components/app/specialist/detail/list.vue b/app/components/app/specialist/detail/list.vue new file mode 100644 index 00000000..da83e7ca --- /dev/null +++ b/app/components/app/specialist/detail/list.vue @@ -0,0 +1,45 @@ + + + + + + + + + + + diff --git a/app/components/app/specialist/list-cfg.ts b/app/components/app/specialist/list-cfg.ts index 8ed75f28..010358c4 100644 --- a/app/components/app/specialist/list-cfg.ts +++ b/app/components/app/specialist/list-cfg.ts @@ -8,16 +8,9 @@ const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dr export const config: Config = { cols: [{}, {}, {}, { width: 50 }], - headers: [ - [ - { label: 'Kode' }, - { label: 'Nama' }, - { label: 'Unit' }, - { label: '' }, - ], - ], + headers: [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Nama Unit' }, { label: '' }]], - keys: ['code', 'name', 'unit', 'action'], + keys: ['code', 'name', 'unit.name', 'action'], delKeyNames: [ { key: 'code', label: 'Kode' }, @@ -29,10 +22,6 @@ export const config: Config = { const recX = rec as SmallDetailDto return `${recX.name}`.trim() }, - unit: (rec: unknown): unknown => { - const recX = rec as SmallDetailDto - return recX.unit_id || '-' - }, }, components: { diff --git a/app/components/app/subspecialist-position/entry-detail.vue b/app/components/app/subspecialist-position/entry-detail.vue new file mode 100644 index 00000000..fd3f91b7 --- /dev/null +++ b/app/components/app/subspecialist-position/entry-detail.vue @@ -0,0 +1,192 @@ + + + + + + + Kode Jabatan + + + + + + Nama Jabatan + + + + + + Pengisi Jabatan + + + + + + Status Kepala + + + + + Ya + + + + Tidak + + + + + + + + Kembali + + + Simpan + + + + diff --git a/app/components/app/subspecialist-position/entry-form.vue b/app/components/app/subspecialist-position/entry-form.vue new file mode 100644 index 00000000..c897b2f5 --- /dev/null +++ b/app/components/app/subspecialist-position/entry-form.vue @@ -0,0 +1,207 @@ + + + + + + + Kode + + + + + + Nama Posisi + + + + + + Sub Spesialis + + + + + + Karyawan + + + + + + Status Kepala + + + + + Ya + + + + Tidak + + + + + + + + Kembali + + + Simpan + + + + diff --git a/app/components/app/subspecialist-position/list.cfg.ts b/app/components/app/subspecialist-position/list.cfg.ts new file mode 100644 index 00000000..028bc7bf --- /dev/null +++ b/app/components/app/subspecialist-position/list.cfg.ts @@ -0,0 +1,65 @@ +import type { Config, RecComponent } from '~/components/pub/my-ui/data-table' +import { defineAsyncComponent } from 'vue' +import type { SubSpecialistPosition } from '~/models/subspecialist-position' + +type SmallDetailDto = any + +const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) + +export const config: Config = { + cols: [{}, {}, {}, {}, {}, { width: 50 }], + + headers: [ + [ + { label: 'Kode Posisi' }, + { label: 'Nama Posisi' }, + { label: 'Nama Sub Spesialis ' }, + { label: 'Karyawan' }, + { label: 'Status Kepala' }, + { label: '' }, + ], + ], + + keys: ['code', 'name', 'subspecialist', 'employee', 'head', 'action'], + + delKeyNames: [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, + ], + + parses: { + subspecialist: (rec: unknown): unknown => { + const recX = rec as SubSpecialistPosition + return recX.subspecialist?.name || '-' + }, + employee: (rec: unknown): unknown => { + const recX = rec as SubSpecialistPosition + const fullName = [recX.employee?.person.frontTitle, recX.employee?.person.name, recX.employee?.person.endTitle] + .filter(Boolean) + .join(' ') + .trim() + + return fullName || '-' + }, + head: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return recX.headStatus ? 'Ya' : 'Tidak' + }, + }, + + components: { + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + props: { + size: 'sm', + }, + } + return res + }, + }, + + htmls: {}, +} diff --git a/app/components/app/subspecialist-position/list.vue b/app/components/app/subspecialist-position/list.vue new file mode 100644 index 00000000..6ad7dd81 --- /dev/null +++ b/app/components/app/subspecialist-position/list.vue @@ -0,0 +1,39 @@ + + + + + + + + diff --git a/app/components/app/subspecialist/detail/index.vue b/app/components/app/subspecialist/detail/index.vue new file mode 100644 index 00000000..154acf75 --- /dev/null +++ b/app/components/app/subspecialist/detail/index.vue @@ -0,0 +1,49 @@ + + + + {{ subspecialist.code || '-' }} + {{ subspecialist.name || '-' }} + + {{ [subspecialist.specialist?.code, subspecialist.specialist?.name].filter(Boolean).join(' / ') || '-' }} + + + {{ + [subspecialist.specialist?.unit?.code, subspecialist.specialist?.unit?.name].filter(Boolean).join(' / ') || '-' + }} + + + {{ + [subspecialist.specialist?.unit?.installation?.code, subspecialist.specialist?.unit?.installation?.name] + .filter(Boolean) + .join(' / ') || '-' + }} + + + + diff --git a/app/components/app/subspecialist/detail/list.cfg.ts b/app/components/app/subspecialist/detail/list.cfg.ts new file mode 100644 index 00000000..8faf9e61 --- /dev/null +++ b/app/components/app/subspecialist/detail/list.cfg.ts @@ -0,0 +1,61 @@ +import type { Config, RecComponent } from '~/components/pub/my-ui/data-table' +import { defineAsyncComponent } from 'vue' +import type { UnitPosition } from '~/models/unit-position' + +type SmallDetailDto = any + +const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) + +export const config: Config = { + cols: [{}, {}, {}, {}, {}, { width: 50 }], + + headers: [ + [ + { label: '#' }, + { label: 'Kode Posisi' }, + { label: 'Nama Posisi' }, + { label: 'Karyawan' }, + { label: 'Status Kepala' }, + { label: '' }, + ], + ], + + keys: ['index', 'code', 'name', 'employee', 'head', 'action'], + + delKeyNames: [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, + ], + + parses: { + employee: (rec: unknown): unknown => { + const recX = rec as UnitPosition + const fullName = [recX.employee?.person.frontTitle, recX.employee?.person.name, recX.employee?.person.endTitle] + .filter(Boolean) + .join(' ') + .trim() + + return fullName || '-' + }, + head: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return recX.headStatus ? 'Ya' : 'Tidak' + }, + }, + + components: { + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + props: { + size: 'sm', + }, + } + return res + }, + }, + + htmls: {}, +} diff --git a/app/components/app/subspecialist/detail/list.vue b/app/components/app/subspecialist/detail/list.vue new file mode 100644 index 00000000..11431e25 --- /dev/null +++ b/app/components/app/subspecialist/detail/list.vue @@ -0,0 +1,45 @@ + + + + + + + + + + + diff --git a/app/components/app/subspecialist/list-cfg.ts b/app/components/app/subspecialist/list-cfg.ts index 7e9e7b79..99d34169 100644 --- a/app/components/app/subspecialist/list-cfg.ts +++ b/app/components/app/subspecialist/list-cfg.ts @@ -8,16 +8,9 @@ const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dr export const config: Config = { cols: [{}, {}, {}, { width: 50 }], - headers: [ - [ - { label: 'Kode' }, - { label: 'Nama' }, - { label: 'Specialis' }, - { label: '' }, - ], - ], + headers: [[{ label: 'Kode' }, { label: 'Nama' }, { label: 'Specialis' }, { label: '' }]], - keys: ['code', 'name', 'specialist', 'action'], + keys: ['code', 'name', 'specialist.name', 'action'], delKeyNames: [ { key: 'code', label: 'Kode' }, diff --git a/app/components/app/subspecialist/list.vue b/app/components/app/subspecialist/list.vue index 1be60a60..2f7908cb 100644 --- a/app/components/app/subspecialist/list.vue +++ b/app/components/app/subspecialist/list.vue @@ -31,6 +31,9 @@ function handlePageChange(page: number) { :rows="data" :skeleton-size="paginationMeta?.pageSize" /> - + diff --git a/app/components/app/unit-position/entry-detail.vue b/app/components/app/unit-position/entry-detail.vue new file mode 100644 index 00000000..fb84e41a --- /dev/null +++ b/app/components/app/unit-position/entry-detail.vue @@ -0,0 +1,192 @@ + + + + + + + Kode Jabatan + + + + + + Nama Jabatan + + + + + + Pengisi Jabatan + + + + + + Status Kepala + + + + + Ya + + + + Tidak + + + + + + + + Kembali + + + Simpan + + + + diff --git a/app/components/app/unit-position/entry-form.vue b/app/components/app/unit-position/entry-form.vue new file mode 100644 index 00000000..b6ab8609 --- /dev/null +++ b/app/components/app/unit-position/entry-form.vue @@ -0,0 +1,206 @@ + + + + + + + Kode + + + + + + Nama Posisi + + + + + + Unit + + + + + + Karyawan + + + + + + Status Kepala + + + + + Ya + + + + Tidak + + + + + + + + Kembali + + + Simpan + + + + diff --git a/app/components/app/unit-position/list.cfg.ts b/app/components/app/unit-position/list.cfg.ts new file mode 100644 index 00000000..fb5e319b --- /dev/null +++ b/app/components/app/unit-position/list.cfg.ts @@ -0,0 +1,61 @@ +import type { Config, RecComponent } from '~/components/pub/my-ui/data-table' +import { defineAsyncComponent } from 'vue' +import type { UnitPosition } from '~/models/unit-position' + +type SmallDetailDto = any + +const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) + +export const config: Config = { + cols: [{}, {}, {}, {}, {}, { width: 50 }], + + headers: [ + [ + { label: 'Kode Posisi' }, + { label: 'Nama Posisi' }, + { label: 'Nama Unit ' }, + { label: 'Karyawan' }, + { label: 'Status Kepala' }, + { label: '' }, + ], + ], + + keys: ['code', 'name', 'unit.name', 'employee', 'head', 'action'], + + delKeyNames: [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, + ], + + parses: { + employee: (rec: unknown): unknown => { + const recX = rec as UnitPosition + const fullName = [recX.employee?.person.frontTitle, recX.employee?.person.name, recX.employee?.person.endTitle] + .filter(Boolean) + .join(' ') + .trim() + + return fullName || '-' + }, + head: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return recX.headStatus ? 'Ya' : 'Tidak' + }, + }, + + components: { + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + props: { + size: 'sm', + }, + } + return res + }, + }, + + htmls: {}, +} diff --git a/app/components/app/unit-position/list.vue b/app/components/app/unit-position/list.vue new file mode 100644 index 00000000..6ad7dd81 --- /dev/null +++ b/app/components/app/unit-position/list.vue @@ -0,0 +1,39 @@ + + + + + + + + diff --git a/app/components/app/unit/detail/index.vue b/app/components/app/unit/detail/index.vue new file mode 100644 index 00000000..9b38aa2b --- /dev/null +++ b/app/components/app/unit/detail/index.vue @@ -0,0 +1,35 @@ + + + + {{ unit.code || '-' }} + {{ unit.name || '-' }} + + + + diff --git a/app/components/app/unit/detail/list.cfg.ts b/app/components/app/unit/detail/list.cfg.ts new file mode 100644 index 00000000..8faf9e61 --- /dev/null +++ b/app/components/app/unit/detail/list.cfg.ts @@ -0,0 +1,61 @@ +import type { Config, RecComponent } from '~/components/pub/my-ui/data-table' +import { defineAsyncComponent } from 'vue' +import type { UnitPosition } from '~/models/unit-position' + +type SmallDetailDto = any + +const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue')) + +export const config: Config = { + cols: [{}, {}, {}, {}, {}, { width: 50 }], + + headers: [ + [ + { label: '#' }, + { label: 'Kode Posisi' }, + { label: 'Nama Posisi' }, + { label: 'Karyawan' }, + { label: 'Status Kepala' }, + { label: '' }, + ], + ], + + keys: ['index', 'code', 'name', 'employee', 'head', 'action'], + + delKeyNames: [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, + ], + + parses: { + employee: (rec: unknown): unknown => { + const recX = rec as UnitPosition + const fullName = [recX.employee?.person.frontTitle, recX.employee?.person.name, recX.employee?.person.endTitle] + .filter(Boolean) + .join(' ') + .trim() + + return fullName || '-' + }, + head: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return recX.headStatus ? 'Ya' : 'Tidak' + }, + }, + + components: { + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + props: { + size: 'sm', + }, + } + return res + }, + }, + + htmls: {}, +} diff --git a/app/components/app/unit/detail/list.vue b/app/components/app/unit/detail/list.vue new file mode 100644 index 00000000..f878d14c --- /dev/null +++ b/app/components/app/unit/detail/list.vue @@ -0,0 +1,45 @@ + + + + + + + + + + + diff --git a/app/components/content/division-position/list.vue b/app/components/content/division-position/list.vue index 019e64a9..4fa8605d 100644 --- a/app/components/content/division-position/list.vue +++ b/app/components/content/division-position/list.vue @@ -54,6 +54,7 @@ const { sort: 'createdAt:asc', 'page-number': params['page-number'] || 0, 'page-size': params['page-size'] || 10, + includes: 'division,Employee.Person', }) return { success: result.success || false, body: result.body || {} } }, @@ -61,7 +62,7 @@ const { }) const headerPrep: HeaderPrep = { - title: 'Divisi', + title: 'Divisi - Posisi', icon: 'i-lucide-box', refSearchNav: { placeholder: 'Cari (min. 3 karakter)...', @@ -105,12 +106,12 @@ watch([recId, recAction], () => { switch (recAction.value) { case ActionEvents.showDetail: getCurrentDivisionDetail(recId.value) - title.value = 'Detail Divisi' + title.value = 'Detail Divisi Position' isReadonly.value = true break case ActionEvents.showEdit: getCurrentDivisionDetail(recId.value) - title.value = 'Edit Divisi' + title.value = 'Edit Divisi Position' isReadonly.value = false break case ActionEvents.showConfirmDelete: @@ -120,9 +121,19 @@ watch([recId, recAction], () => { }) onMounted(async () => { - divisions.value = await getDivisionLabelList({ sort: 'createdAt:asc', 'page-size': 100 }) - employees.value = await getEmployeeLabelList({ sort: 'createdAt:asc', 'page-size': 100 }) - await getDivisionList() + try { + divisions.value = await getDivisionLabelList({ sort: 'createdAt:asc', 'page-size': 100 }) + employees.value = await getEmployeeLabelList({ sort: 'createdAt:asc', 'page-size': 100, includes: 'person' }) + await getDivisionList() + } catch (err) { + console.log(err) + // show toast + toast({ + title: 'Terjadi Kesalahan', + description: 'Terjadi kesalahan saat memuat data', + variant: 'destructive', + }) + } }) @@ -142,7 +153,7 @@ onMounted(async () => { +import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types' +import RecordConfirmation from '~/components/pub/my-ui/confirmation/record-confirmation.vue' + +// Components +import Header from '~/components/pub/my-ui/nav-header/prep.vue' + +// Service +import type { Division } from '~/models/division' +import { getDetail as getDetailDivision } from '~/services/division.service' + +// #region division positions +import { config } from '~/components/app/division/detail/list-cfg' + +// Helpers +import { usePaginatedList } from '~/composables/usePaginatedList' +import { toast } from '~/components/pub/ui/toast' + +import Dialog from '~/components/pub/my-ui/modal/dialog.vue' +// Types +import { DivisionPositionSchema, type DivisionPositionFormData } from '~/schemas/division-position.schema' + +// Handlers +import { + recId, + recAction, + recItem, + isReadonly, + isProcessing, + isFormEntryDialogOpen, + isRecordConfirmationOpen, + onResetState, + handleActionSave, + handleActionEdit, + handleActionRemove, + handleCancelForm, +} from '~/handlers/division-position.handler' + +// Services +import { getList, getDetail as getDetailDivisionPosition } from '~/services/division-position.service' +import { getValueLabelList as getEmployeeLabelList } from '~/services/employee.service' + +const employees = ref<{ value: string | number; label: string }[]>([]) + +const title = ref('') +// #endregion + +// #region Props & Emits +const props = defineProps<{ + divisionId: number +}>() +const division = ref({} as Division) +// #endregion + +// #region State & Computed +const { + data, + isLoading, + paginationMeta, + searchInput, + handlePageChange, + handleSearch, + fetchData: getDivisionPositionList, +} = usePaginatedList({ + fetchFn: async (params: any) => { + const result = await getList({ + 'division-id': props.divisionId, + includes: 'Employee.Person', + search: params.search, + sort: 'createdAt:asc', + 'page-number': params['page-number'] || 0, + 'page-size': params['page-size'] || 10, + 'page-no-limit': true, + }) + return { success: result.success || false, body: result.body || {} } + }, + entityName: 'division-position', +}) + +const dataMap = computed(() => { + return data.value.map((v, i) => { + return { + ...v, + index: i + 1, + } + }) +}) +const headerPrep: HeaderPrep = { + title: 'Detail Divisi', + icon: 'i-lucide-user', + refSearchNav: { + placeholder: 'Cari (min. 3 karakter)...', + minLength: 3, + debounceMs: 500, + showValidationFeedback: true, + onInput: (value: string) => { + searchInput.value = value + }, + onClick: () => {}, + onClear: () => {}, + }, + addNav: { + label: 'Tambah Jabatan', + icon: 'i-lucide-plus', + onClick: () => { + recItem.value = null + recId.value = 0 + isFormEntryDialogOpen.value = true + isReadonly.value = false + }, + }, +} + +// #endregion + +// #region Lifecycle Hooks +onMounted(async () => { + try { + const result = await getDetailDivision(props.divisionId) + if (result.success) { + division.value = result.body.data || {} + } + + const res = await getEmployeeLabelList({ sort: 'createdAt:asc', 'page-size': 100, includes: 'person' }) + employees.value = res + } catch (err) { + // show toast + toast({ + title: 'Terjadi Kesalahan', + description: 'Terjadi kesalahan saat memuat data', + variant: 'destructive', + }) + } +}) +// #endregion + +// #region Functions +// #endregion region + +// #region Utilities & event handlers +// #endregion + +// #region Watchers +// #endregion +provide('rec_id', recId) +provide('rec_action', recAction) +provide('rec_item', recItem) +provide('table_data_loader', isLoading) + +// Watch for row actions when recId or recAction changes +watch([recId, recAction], () => { + console.log(recId, recAction) + switch (recAction.value) { + case ActionEvents.showEdit: + getDetailDivisionPosition(recId.value) + title.value = 'Edit Jabatan' + isReadonly.value = false + isFormEntryDialogOpen.value = true + break + case ActionEvents.showConfirmDelete: + isRecordConfirmationOpen.value = true + break + } +}) + + + + + + + + + + + { + onResetState() + isFormEntryDialogOpen = value + } + " + > + , resetForm: () => void) => { + console.log(values) + if (recId > 0) { + handleActionEdit(recId, values, getDivisionPositionList, onResetState, toast) + return + } + handleActionSave(values, getDivisionPositionList, onResetState, toast) + } + " + @cancel="handleCancelForm" + /> + + handleActionRemove(recId, getDivisionPositionList, toast)" + @cancel="" + > + + + + {{ field.label }}: + {{ record[field.key] }} + + + + + diff --git a/app/components/content/division/list.vue b/app/components/content/division/list.vue index 9ccefc56..0456891b 100644 --- a/app/components/content/division/list.vue +++ b/app/components/content/division/list.vue @@ -13,7 +13,7 @@ import { toast } from '~/components/pub/ui/toast' // Types import { ActionEvents, type HeaderPrep } from '~/components/pub/my-ui/data/types' import { DivisionSchema, type DivisionFormData } from '~/schemas/division.schema' -import type { Division } from "~/models/division" +import type { Division } from '~/models/division' import type { TreeItem } from '~/models/_base' // Handlers @@ -78,6 +78,7 @@ const headerPrep: HeaderPrep = { label: 'Tambah', icon: 'i-lucide-plus', onClick: () => { + recAction.value = '' recItem.value = null recId.value = 0 isFormEntryDialogOpen.value = true @@ -104,9 +105,23 @@ const getCurrentDivisionDetail = async (id: number | string) => { watch([recId, recAction], () => { switch (recAction.value) { case ActionEvents.showDetail: - getCurrentDivisionDetail(recId.value) - title.value = 'Detail Divisi' - isReadonly.value = true + if (Number(recId.value) > 0) { + const id = Number(recId.value) + + recAction.value = '' + recItem.value = null + recId.value = 0 + isFormEntryDialogOpen.value = false + isReadonly.value = false + + navigateTo({ + name: 'org-src-division-id', + params: { + id, + }, + }) + } + break case ActionEvents.showEdit: getCurrentDivisionDetail(recId.value) diff --git a/app/components/content/installation-position/list.vue b/app/components/content/installation-position/list.vue new file mode 100644 index 00000000..ea60ee04 --- /dev/null +++ b/app/components/content/installation-position/list.vue @@ -0,0 +1,208 @@ + + + + + + + + { + onResetState() + isFormEntryDialogOpen = value + } + " + > + , resetForm: () => void) => { + if (recId > 0) { + handleActionEdit(recId, values, getInstallationPositionList, resetForm, toast) + return + } + handleActionSave(values, getInstallationPositionList, resetForm, toast) + } + " + @cancel="handleCancelForm" + /> + + + + handleActionRemove(recId, getInstallationPositionList, toast)" + @cancel="" + > + + + + ID: + {{ record?.id }} + + + Nama: + {{ record.name }} + + + Kode: + {{ record.code }} + + + + + diff --git a/app/components/content/installation/detail.vue b/app/components/content/installation/detail.vue new file mode 100644 index 00000000..0f12ad8c --- /dev/null +++ b/app/components/content/installation/detail.vue @@ -0,0 +1,235 @@ + + + + + + + + + + + { + onResetState() + isFormEntryDialogOpen = value + } + " + > + , resetForm: () => void) => { + console.log(values) + if (recId > 0) { + handleActionEdit(recId, values, getInstallationPositionList, onResetState, toast) + return + } + handleActionSave(values, getInstallationPositionList, onResetState, toast) + } + " + @cancel="handleCancelForm" + /> + + handleActionRemove(recId, getInstallationPositionList, toast)" + @cancel="" + > + + + + {{ field.label }}: + {{ record[field.key] }} + + + + + diff --git a/app/components/content/installation/entry.ts b/app/components/content/installation/entry.ts deleted file mode 100644 index c003a029..00000000 --- a/app/components/content/installation/entry.ts +++ /dev/null @@ -1,37 +0,0 @@ -import * as z from 'zod' - -export const installationConf = { - msg: { - placeholder: '---pilih encounter class (fhir7)', - }, - items: [ - { value: '1', label: 'Ambulatory', code: 'AMB' }, - { value: '2', label: 'Inpatient', code: 'IMP' }, - { value: '3', label: 'Emergency', code: 'EMER' }, - { value: '4', label: 'Observation', code: 'OBSENC' }, - { value: '5', label: 'Pre-admission', code: 'PRENC' }, - { value: '6', label: 'Short Stay', code: 'SS' }, - { value: '7', label: 'Virtual', code: 'VR' }, - { value: '8', label: 'Home Health', code: 'HH' }, - ], -} - -export const schemaConf = z.object({ - name: z - .string({ - required_error: 'Nama instalasi harus diisi', - }) - .min(3, 'Nama instalasi minimal 3 karakter'), - - code: z - .string({ - required_error: 'Kode instalasi harus diisi', - }) - .min(3, 'Kode instalasi minimal 3 karakter'), - - encounterClassCode: z - .string({ - required_error: 'Kelompok encounter class harus dipilih', - }) - .min(1, 'Kelompok encounter class harus dipilih'), -}) diff --git a/app/components/content/installation/list.vue b/app/components/content/installation/list.vue index 31486097..553d7ebb 100644 --- a/app/components/content/installation/list.vue +++ b/app/components/content/installation/list.vue @@ -102,9 +102,23 @@ const getCurrentInstallationDetail = async (id: number | string) => { watch([recId, recAction], () => { switch (recAction.value) { case ActionEvents.showDetail: - getCurrentInstallationDetail(recId.value) - title.value = 'Detail Instalasi' - isReadonly.value = true + if (Number(recId.value) > 0) { + const id = Number(recId.value) + + recAction.value = '' + recItem.value = null + recId.value = 0 + isFormEntryDialogOpen.value = false + isReadonly.value = false + + navigateTo({ + name: 'org-src-installation-id', + params: { + id, + }, + }) + } + break case ActionEvents.showEdit: getCurrentInstallationDetail(recId.value) diff --git a/app/components/content/specialist-position/list.vue b/app/components/content/specialist-position/list.vue new file mode 100644 index 00000000..1ebf697e --- /dev/null +++ b/app/components/content/specialist-position/list.vue @@ -0,0 +1,203 @@ + + + + + + { + onResetState() + isFormEntryDialogOpen = value + } + " + > + , resetForm: () => void) => { + if (recId > 0) { + handleActionEdit(recId, values, getSpecialistList, resetForm, toast) + return + } + handleActionSave(values, getSpecialistList, resetForm, toast) + } + " + @cancel="handleCancelForm" + /> + + + handleActionRemove(recId, getSpecialistList, toast)" + @cancel="" + > + + + + {{ field.label }}: + {{ record[field.key] }} + + + + + diff --git a/app/components/content/specialist/detail.vue b/app/components/content/specialist/detail.vue new file mode 100644 index 00000000..df4e79b6 --- /dev/null +++ b/app/components/content/specialist/detail.vue @@ -0,0 +1,236 @@ + + + + + + + + + + + { + onResetState() + isFormEntryDialogOpen = value + } + " + > + , resetForm: () => void) => { + console.log(values) + if (recId > 0) { + handleActionEdit(recId, values, getPositionList, onResetState, toast) + return + } + handleActionSave(values, getPositionList, onResetState, toast) + } + " + @cancel="handleCancelForm" + /> + + handleActionRemove(recId, getPositionList, toast)" + @cancel="" + > + + + + {{ field.label }}: + {{ record[field.key] }} + + + + + diff --git a/app/components/content/specialist/entry.ts b/app/components/content/specialist/entry.ts deleted file mode 100644 index c89302c2..00000000 --- a/app/components/content/specialist/entry.ts +++ /dev/null @@ -1,95 +0,0 @@ -import * as z from 'zod' - -export const schemaConf = z.object({ - name: z - .string({ - required_error: 'Nama spesialisasi harus diisi', - }) - .min(3, 'Nama spesialisasi minimal 3 karakter'), - - code: z - .string({ - required_error: 'Kode spesialisasi harus diisi', - }) - .min(3, 'Kode spesialisasi minimal 3 karakter'), - - installationId: z - .string({ - required_error: 'Instalasi harus dipilih', - }) - .min(1, 'Instalasi harus dipilih'), - - unitId: z - .string({ - required_error: 'Unit harus dipilih', - }) - .min(1, 'Unit harus dipilih'), -}) - -// Unit mapping berdasarkan installation -export const installationUnitMapping: Record = { - '1': ['1', '3', '5'], - '2': ['2', '4', '6'], - '3': ['7', '8', '9', '10', '11'], -} - -export const unitConf = { - msg: { - placeholder: '---pilih unit', - search: 'kode, nama unit', - empty: 'unit tidak ditemukan', - }, - items: [ - { value: '1', label: 'Instalasi Medis', code: 'MED' }, - { value: '2', label: 'Instalasi Keperawatan', code: 'NUR' }, - { value: '3', label: 'Instalasi Administrasi', code: 'ADM' }, - { value: '4', label: 'Instalasi Penunjang Non-Medis', code: 'SUP' }, - { value: '5', label: 'Instalasi Pendidikan & Pelatihan', code: 'EDU' }, - { value: '6', label: 'Instalasi Farmasi', code: 'PHA' }, - { value: '7', label: 'Instalasi Radiologi', code: 'RAD' }, - { value: '8', label: 'Instalasi Laboratorium', code: 'LAB' }, - { value: '9', label: 'Instalasi Keuangan', code: 'FIN' }, - { value: '10', label: 'Instalasi SDM', code: 'HR' }, - { value: '11', label: 'Instalasi Teknologi Informasi', code: 'ITS' }, - { value: '12', label: 'Instalasi Pemeliharaan & Sarana', code: 'MNT' }, - { value: '13', label: 'Instalasi Gizi / Catering', code: 'CAT' }, - { value: '14', label: 'Instalasi Keamanan', code: 'SEC' }, - { value: '15', label: 'Instalasi Gawat Darurat', code: 'EMR' }, - { value: '16', label: 'Instalasi Bedah Sentral', code: 'SUR' }, - { value: '17', label: 'Instalasi Rawat Jalan', code: 'OUT' }, - { value: '18', label: 'Instalasi Rawat Inap', code: 'INP' }, - { value: '19', label: 'Instalasi Rehabilitasi Medik', code: 'REB' }, - { value: '20', label: 'Instalasi Penelitian & Pengembangan', code: 'RSH' }, - ], -} - -export const installationConf = { - msg: { - placeholder: '---pilih instalasi', - search: 'kode, nama instalasi', - empty: 'instalasi tidak ditemukan', - }, - items: [ - { value: '1', label: 'Ambulatory', code: 'AMB' }, - { value: '2', label: 'Inpatient', code: 'IMP' }, - { value: '3', label: 'Emergency', code: 'EMER' }, - ], -} - -// Helper function untuk filter unit berdasarkan installation -export function getFilteredUnits(installationId: string) { - if (!installationId || !installationUnitMapping[installationId]) { - return [] - } - - const allowedUnitIds = installationUnitMapping[installationId] - return unitConf.items.filter((unit) => allowedUnitIds.includes(unit.value)) -} - -// Helper function untuk membuat unit config yang ter-filter -export function createFilteredUnitConf(installationId: string) { - return { - ...unitConf, - items: getFilteredUnits(installationId), - } -} diff --git a/app/components/content/specialist/list.vue b/app/components/content/specialist/list.vue index 9bbf755f..ca293026 100644 --- a/app/components/content/specialist/list.vue +++ b/app/components/content/specialist/list.vue @@ -103,9 +103,23 @@ const getCurrentSpecialistDetail = async (id: number | string) => { watch([recId, recAction], () => { switch (recAction.value) { case ActionEvents.showDetail: - getCurrentSpecialistDetail(recId.value) - title.value = 'Detail Spesialis' - isReadonly.value = true + if (Number(recId.value) > 0) { + const id = Number(recId.value) + + recAction.value = '' + recItem.value = null + recId.value = 0 + isFormEntryDialogOpen.value = false + isReadonly.value = false + + navigateTo({ + name: 'org-src-specialist-id', + params: { + id, + }, + }) + } + break case ActionEvents.showEdit: getCurrentSpecialistDetail(recId.value) diff --git a/app/components/content/subspecialist-position/list.vue b/app/components/content/subspecialist-position/list.vue new file mode 100644 index 00000000..4c833ce2 --- /dev/null +++ b/app/components/content/subspecialist-position/list.vue @@ -0,0 +1,211 @@ + + + + + + + + { + onResetState() + isFormEntryDialogOpen = value + } + " + > + , resetForm: () => void) => { + if (recId > 0) { + handleActionEdit(recId, values, getSubSpecialistList, onResetState, toast) + return + } + handleActionSave(values, getSubSpecialistList, onResetState, toast) + } + " + @cancel="handleCancelForm" + /> + + + + handleActionRemove(recId, getSubSpecialistList, toast)" + @cancel="" + > + + + + {{ field.label }}: + {{ record[field.key] }} + + + + + diff --git a/app/components/content/subspecialist/detail.vue b/app/components/content/subspecialist/detail.vue new file mode 100644 index 00000000..d432eb22 --- /dev/null +++ b/app/components/content/subspecialist/detail.vue @@ -0,0 +1,239 @@ + + + + + + + + + + + { + onResetState() + isFormEntryDialogOpen = value + } + " + > + , resetForm: () => void) => { + console.log(values) + if (recId > 0) { + handleActionEdit(recId, values, getPositionList, onResetState, toast) + return + } + handleActionSave(values, getPositionList, onResetState, toast) + } + " + @cancel="handleCancelForm" + /> + + handleActionRemove(recId, getPositionList, toast)" + @cancel="" + > + + + + {{ field.label }}: + {{ record[field.key] }} + + + + + diff --git a/app/components/content/subspecialist/entry.ts b/app/components/content/subspecialist/entry.ts deleted file mode 100644 index 5a93847d..00000000 --- a/app/components/content/subspecialist/entry.ts +++ /dev/null @@ -1,98 +0,0 @@ -import * as z from 'zod' - -export const schemaConf = z.object({ - name: z - .string({ - required_error: 'Nama spesialisasi harus diisi', - }) - .min(3, 'Nama spesialisasi minimal 3 karakter'), - - code: z - .string({ - required_error: 'Kode spesialisasi harus diisi', - }) - .min(3, 'Kode spesialisasi minimal 3 karakter'), - - installationId: z - .string({ - required_error: 'Instalasi harus dipilih', - }) - .min(1, 'Instalasi harus dipilih'), - - unitId: z - .string({ - required_error: 'Unit harus dipilih', - }) - .min(1, 'Unit harus dipilih'), - specialistId: z - .string({ - required_error: 'Specialist harus dipilih', - }) - .min(1, 'Specialist harus dipilih'), -}) - -// Unit mapping berdasarkan installation -export const installationUnitMapping: Record = { - '1': ['1', '3'], - '2': ['2', '3'], - '3': ['1', '2', '3'], -} - -export const unitConf = { - msg: { - placeholder: '---pilih unit', - search: 'kode, nama unit', - empty: 'unit tidak ditemukan', - }, - items: [ - { value: '1', label: 'Instalasi Medis', code: 'MED' }, - { value: '2', label: 'Instalasi Keperawatan', code: 'NUR' }, - { value: '3', label: 'Instalasi Administrasi', code: 'ADM' }, - ], -} - -export const specialistConf = { - msg: { - placeholder: '---pilih specialist', - search: 'kode, nama specialist', - empty: 'specialist tidak ditemukan', - }, - items: [ - { value: '1', label: 'Spesialis Jantung', code: 'CARD' }, - { value: '2', label: 'Spesialis Mata', code: 'OPHT' }, - { value: '3', label: 'Spesialis Bedah', code: 'SURG' }, - { value: '4', label: 'Spesialis Anak', code: 'PEDI' }, - { value: '5', label: 'Spesialis Kandungan', code: 'OBGY' }, - ], -} - -export const installationConf = { - msg: { - placeholder: '---pilih instalasi', - search: 'kode, nama instalasi', - empty: 'instalasi tidak ditemukan', - }, - items: [ - { value: '1', label: 'Ambulatory', code: 'AMB' }, - { value: '2', label: 'Inpatient', code: 'IMP' }, - { value: '3', label: 'Emergency', code: 'EMER' }, - ], -} - -// Helper function untuk filter unit berdasarkan installation -export function getFilteredUnits(installationId: string) { - if (!installationId || !installationUnitMapping[installationId]) { - return [] - } - - const allowedUnitIds = installationUnitMapping[installationId] - return unitConf.items.filter((unit) => allowedUnitIds.includes(unit.value)) -} - -// Helper function untuk membuat unit config yang ter-filter -export function createFilteredUnitConf(installationId: string) { - return { - ...unitConf, - items: getFilteredUnits(installationId), - } -} diff --git a/app/components/content/subspecialist/list.vue b/app/components/content/subspecialist/list.vue index e2c6db52..bb1b63f5 100644 --- a/app/components/content/subspecialist/list.vue +++ b/app/components/content/subspecialist/list.vue @@ -103,9 +103,23 @@ const getCurrentSubSpecialistDetail = async (id: number | string) => { watch([recId, recAction], () => { switch (recAction.value) { case ActionEvents.showDetail: - getCurrentSubSpecialistDetail(recId.value) - title.value = 'Detail Sub Spesialis' - isReadonly.value = true + if (Number(recId.value) > 0) { + const id = Number(recId.value) + + recAction.value = '' + recItem.value = null + recId.value = 0 + isFormEntryDialogOpen.value = false + isReadonly.value = false + + navigateTo({ + name: 'org-src-subspecialist-id', + params: { + id, + }, + }) + } + break case ActionEvents.showEdit: getCurrentSubSpecialistDetail(recId.value) diff --git a/app/components/content/unit-position/list.vue b/app/components/content/unit-position/list.vue new file mode 100644 index 00000000..55ab3f29 --- /dev/null +++ b/app/components/content/unit-position/list.vue @@ -0,0 +1,206 @@ + + + + + + + + { + onResetState() + isFormEntryDialogOpen = value + } + " + > + , resetForm: () => void) => { + if (recId > 0) { + handleActionEdit(recId, values, getListUnit, resetForm, toast) + return + } + handleActionSave(values, getListUnit, resetForm, toast) + } + " + @cancel="handleCancelForm" + /> + + + handleActionRemove(recId, getListUnit, toast)" + @cancel="" + > + + + + {{ field.label }}: + {{ record[field.key] }} + + + + + diff --git a/app/components/content/unit/detail.vue b/app/components/content/unit/detail.vue new file mode 100644 index 00000000..6c51624f --- /dev/null +++ b/app/components/content/unit/detail.vue @@ -0,0 +1,234 @@ + + + + + + + + + + + { + onResetState() + isFormEntryDialogOpen = value + } + " + > + , resetForm: () => void) => { + console.log(values) + if (recId > 0) { + handleActionEdit(recId, values, getPositionList, onResetState, toast) + return + } + handleActionSave(values, getPositionList, onResetState, toast) + } + " + @cancel="handleCancelForm" + /> + + handleActionRemove(recId, getPositionList, toast)" + @cancel="" + > + + + + {{ field.label }}: + {{ record[field.key] }} + + + + + diff --git a/app/components/content/unit/entry.ts b/app/components/content/unit/entry.ts deleted file mode 100644 index bf85a0ed..00000000 --- a/app/components/content/unit/entry.ts +++ /dev/null @@ -1,63 +0,0 @@ -import * as z from 'zod' - -export const unitConf = { - msg: { - placeholder: '--- pilih instalasi', - search: 'kode, nama instalasi', - empty: 'instalasi tidak ditemukan', - }, - items: [ - { value: '1', label: 'Instalasi Medis', code: 'MED' }, - { value: '2', label: 'Instalasi Keperawatan', code: 'NUR' }, - { value: '3', label: 'Instalasi Administrasi', code: 'ADM' }, - { value: '4', label: 'Instalasi Penunjang Non-Medis', code: 'SUP' }, - { value: '5', label: 'Instalasi Pendidikan & Pelatihan', code: 'EDU' }, - { value: '6', label: 'Instalasi Farmasi', code: 'PHA' }, - { value: '7', label: 'Instalasi Radiologi', code: 'RAD' }, - { value: '8', label: 'Instalasi Laboratorium', code: 'LAB' }, - { value: '9', label: 'Instalasi Keuangan', code: 'FIN' }, - { value: '10', label: 'Instalasi SDM', code: 'HR' }, - { value: '11', label: 'Instalasi Teknologi Informasi', code: 'ITS' }, - { value: '12', label: 'Instalasi Pemeliharaan & Sarana', code: 'MNT' }, - { value: '13', label: 'Instalasi Gizi / Catering', code: 'CAT' }, - { value: '14', label: 'Instalasi Keamanan', code: 'SEC' }, - { value: '15', label: 'Instalasi Gawat Darurat', code: 'EMR' }, - { value: '16', label: 'Instalasi Bedah Sentral', code: 'SUR' }, - { value: '17', label: 'Instalasi Rawat Jalan', code: 'OUT' }, - { value: '18', label: 'Instalasi Rawat Inap', code: 'INP' }, - { value: '19', label: 'Instalasi Rehabilitasi Medik', code: 'REB' }, - { value: '20', label: 'Instalasi Penelitian & Pengembangan', code: 'RSH' }, - ], -} - -export const schemaConf = z.object({ - name: z - .string({ - required_error: 'Nama unit harus diisi', - }) - .min(1, 'Nama unit harus diisi'), - - code: z - .string({ - required_error: 'Kode unit harus diisi', - }) - .min(1, 'Kode unit harus diisi'), - parentId: z.preprocess( - (input: unknown) => { - if (typeof input === 'string') { - // Handle empty string case - if (input.trim() === '') { - return 0 - } - return Number(input) - } - - return input - }, - z - .number({ - required_error: 'Instalasi induk harus dipilih', - }) - .refine((num) => num > 0, 'Instalasi induk harus dipilih'), - ), -}) diff --git a/app/components/content/unit/list.vue b/app/components/content/unit/list.vue index 03edd231..34b647ef 100644 --- a/app/components/content/unit/list.vue +++ b/app/components/content/unit/list.vue @@ -103,9 +103,23 @@ const getCurrentUnitDetail = async (id: number | string) => { watch([recId, recAction], () => { switch (recAction.value) { case ActionEvents.showDetail: - getCurrentUnitDetail(recId.value) - title.value = 'Detail Unit' - isReadonly.value = true + if (Number(recId.value) > 0) { + const id = Number(recId.value) + + recAction.value = '' + recItem.value = null + recId.value = 0 + isFormEntryDialogOpen.value = false + isReadonly.value = false + + navigateTo({ + name: 'org-src-unit-id', + params: { + id, + }, + }) + } + break case ActionEvents.showEdit: getCurrentUnitDetail(recId.value) diff --git a/app/components/pub/my-ui/data/dropdown-action-dud.vue b/app/components/pub/my-ui/data/dropdown-action-dud.vue index 71979c7c..dfcf1ada 100644 --- a/app/components/pub/my-ui/data/dropdown-action-dud.vue +++ b/app/components/pub/my-ui/data/dropdown-action-dud.vue @@ -2,9 +2,14 @@ import type { LinkItem, ListItemDto } from './types' import { ActionEvents } from './types' -const props = defineProps<{ +interface Props { rec: ListItemDto -}>() + size?: 'default' | 'sm' | 'lg' +} + +const props = withDefaults(defineProps(), { + size: 'lg', +}) const recId = inject>('rec_id')! const recAction = inject>('rec_action')! @@ -58,7 +63,7 @@ function del() { +const emit = defineEmits<{ + (e: 'click'): void +}>() + +function onClick() { + emit('click') +} + + + + + + + Back + + + diff --git a/app/components/pub/my-ui/pagination/pagination-view.vue b/app/components/pub/my-ui/pagination/pagination-view.vue index 149d425e..8a2271b4 100644 --- a/app/components/pub/my-ui/pagination/pagination-view.vue +++ b/app/components/pub/my-ui/pagination/pagination-view.vue @@ -4,6 +4,10 @@ import Pagination from './pagination.vue' const props = defineProps<{ paginationMeta: PaginationMeta + conf?: { + showInfo: boolean + showControl: boolean + } }>() const emit = defineEmits<{ @@ -17,8 +21,10 @@ function handlePageChange(page: number) { diff --git a/app/components/pub/my-ui/pagination/pagination.vue b/app/components/pub/my-ui/pagination/pagination.vue index 4ba0da5f..9b1618c3 100644 --- a/app/components/pub/my-ui/pagination/pagination.vue +++ b/app/components/pub/my-ui/pagination/pagination.vue @@ -15,11 +15,13 @@ interface Props { paginationMeta: PaginationMeta onPageChange?: (page: number) => void showInfo?: boolean + showControl?: boolean } const props = withDefaults(defineProps(), { onPageChange: undefined, showInfo: true, + showControl: true, }) const emit = defineEmits<{ @@ -65,7 +67,7 @@ const formattedRecordCount = computed(() => { }) const startRecord = computed(() => { - const start = ((props.paginationMeta.page - 1) * props.paginationMeta.pageSize) + 1 + const start = (props.paginationMeta.page - 1) * props.paginationMeta.pageSize + 1 return Number(start).toLocaleString('id-ID') }) @@ -77,53 +79,95 @@ const endRecord = computed(() => { function getButtonClass(pageNumber: number) { const digits = pageNumber.toString().length - if (digits >= 4) { // 1000+ (1k+) + if (digits >= 4) { + // 1000+ (1k+) return 'h-9 px-4 min-w-12' - } else if (digits === 3) { // 100-999 + } else if (digits === 3) { + // 100-999 return 'h-9 px-3 min-w-10' - } else { // 1-99 + } else { + // 1-99 return 'w-9 h-9 p-0' } } - + - - Menampilkan {{ startRecord }} - hingga {{ Number(endRecord).toLocaleString('id-ID') }} - dari {{ formattedRecordCount }} data + + Menampilkan {{ startRecord }} hingga {{ Number(endRecord).toLocaleString('id-ID') }} dari + {{ formattedRecordCount }} data + + + - - - - + - + - - - + v-slot="{ page }" + :total="paginationMeta.recordCount" + :sibling-count="1" + :page="paginationMeta.page" + :items-per-page="paginationMeta.pageSize" + show-edges + > + + + - + > + {{ item.value }} - + - - + + diff --git a/app/handlers/installation-position.handler.ts b/app/handlers/installation-position.handler.ts new file mode 100644 index 00000000..e3cfcf38 --- /dev/null +++ b/app/handlers/installation-position.handler.ts @@ -0,0 +1,24 @@ +// Handlers +import { genCrudHandler } from '~/handlers/_handler' + +// Services +import { create, update, remove } from '~/services/installation-position.service' + +export const { + recId, + recAction, + recItem, + isReadonly, + isProcessing, + isFormEntryDialogOpen, + isRecordConfirmationOpen, + onResetState, + handleActionSave, + handleActionEdit, + handleActionRemove, + handleCancelForm, +} = genCrudHandler({ + create, + update, + remove, +}) diff --git a/app/handlers/specialist-position.handler.ts b/app/handlers/specialist-position.handler.ts new file mode 100644 index 00000000..859070ba --- /dev/null +++ b/app/handlers/specialist-position.handler.ts @@ -0,0 +1,24 @@ +// Handlers +import { genCrudHandler } from '~/handlers/_handler' + +// Services +import { create, update, remove } from '~/services/specialist-position.service' + +export const { + recId, + recAction, + recItem, + isReadonly, + isProcessing, + isFormEntryDialogOpen, + isRecordConfirmationOpen, + onResetState, + handleActionSave, + handleActionEdit, + handleActionRemove, + handleCancelForm, +} = genCrudHandler({ + create, + update, + remove, +}) diff --git a/app/handlers/subspecialist-position.handler.ts b/app/handlers/subspecialist-position.handler.ts new file mode 100644 index 00000000..42473f86 --- /dev/null +++ b/app/handlers/subspecialist-position.handler.ts @@ -0,0 +1,24 @@ +// Handlers +import { genCrudHandler } from '~/handlers/_handler' + +// Services +import { create, update, remove } from '~/services/subspecialist-position.service' + +export const { + recId, + recAction, + recItem, + isReadonly, + isProcessing, + isFormEntryDialogOpen, + isRecordConfirmationOpen, + onResetState, + handleActionSave, + handleActionEdit, + handleActionRemove, + handleCancelForm, +} = genCrudHandler({ + create, + update, + remove, +}) diff --git a/app/handlers/unit-position.handler.ts b/app/handlers/unit-position.handler.ts new file mode 100644 index 00000000..1cf4994b --- /dev/null +++ b/app/handlers/unit-position.handler.ts @@ -0,0 +1,24 @@ +// Handlers +import { genCrudHandler } from '~/handlers/_handler' + +// Services +import { create, update, remove } from '~/services/unit-position.service' + +export const { + recId, + recAction, + recItem, + isReadonly, + isProcessing, + isFormEntryDialogOpen, + isRecordConfirmationOpen, + onResetState, + handleActionSave, + handleActionEdit, + handleActionRemove, + handleCancelForm, +} = genCrudHandler({ + create, + update, + remove, +}) diff --git a/app/models/division-position.ts b/app/models/division-position.ts index 3bd5e63a..dc263ada 100644 --- a/app/models/division-position.ts +++ b/app/models/division-position.ts @@ -1,11 +1,13 @@ import { type Base, genBase } from './_base' - +import type { Employee } from './employee' export interface DivisionPosition extends Base { code: string name: string headStatus?: boolean division_id: number employee_id?: number + + employee?: Employee | null } export function genDivisionPosition(): DivisionPosition { diff --git a/app/models/division.ts b/app/models/division.ts index 0f6d9185..c54a0e24 100644 --- a/app/models/division.ts +++ b/app/models/division.ts @@ -1,10 +1,13 @@ -import { type Base, genBase } from "./_base" - +import { type Base, genBase } from './_base' +import type { DivisionPosition } from './division-position' export interface Division extends Base { code: string name: string parent_id?: number | null childrens?: Division[] | null + + // preload + divisionPosition?: DivisionPosition[] | null } export function genDivision(): Division { diff --git a/app/models/installation-position.ts b/app/models/installation-position.ts new file mode 100644 index 00000000..199038d7 --- /dev/null +++ b/app/models/installation-position.ts @@ -0,0 +1,23 @@ +import { type Base, genBase } from './_base' +import type { Employee } from './employee' + +export interface InstallationPosition extends Base { + installation_id: number + code: string + name: string + headStatus?: boolean + employee_id?: number + + employee?: Employee | null +} + +export function genInstallationPosition(): InstallationPosition { + return { + ...genBase(), + installation_id: 0, + code: '', + name: '', + headStatus: false, + employee_id: 0, + } +} diff --git a/app/models/specialist-position.ts b/app/models/specialist-position.ts new file mode 100644 index 00000000..727e8374 --- /dev/null +++ b/app/models/specialist-position.ts @@ -0,0 +1,22 @@ +import { type Base, genBase } from './_base' +import type { Employee } from './employee' + +export interface SpecialistPosition extends Base { + specialist_id: number + code: string + name: string + headStatus?: boolean + employee_id?: number + employee?: Employee | null +} + +export function genSpecialistPosition(): SpecialistPosition { + return { + ...genBase(), + specialist_id: 0, + code: '', + name: '', + headStatus: false, + employee_id: 0, + } +} diff --git a/app/models/specialist.ts b/app/models/specialist.ts index 1959673d..d3180a73 100644 --- a/app/models/specialist.ts +++ b/app/models/specialist.ts @@ -1,10 +1,11 @@ -import { type Base, genBase } from "./_base" +import { type Base, genBase } from './_base' +import type { Unit } from './unit' import type { Subspecialist } from "./subspecialist" export interface Specialist extends Base { code: string name: string - unit_id?: number | string | null + unit?: Unit | null subspecialists?: Subspecialist[] } @@ -13,6 +14,6 @@ export function genSpecialist(): Specialist { ...genBase(), code: '', name: '', - unit_id: 0 + unit_id: 0, } } diff --git a/app/models/subspecialist-position.ts b/app/models/subspecialist-position.ts new file mode 100644 index 00000000..28ea2287 --- /dev/null +++ b/app/models/subspecialist-position.ts @@ -0,0 +1,25 @@ +import { type Base, genBase } from './_base' +import type { Employee } from './employee' +import type { Subspecialist } from './subspecialist' + +export interface SubSpecialistPosition extends Base { + subspecialist_id: number + code: string + name: string + headStatus?: boolean + employee_id?: number + + subspecialist?: Subspecialist | null + employee?: Employee | null +} + +export function genSubSpecialistPosition(): SubSpecialistPosition { + return { + ...genBase(), + subspecialist_id: 0, + code: '', + name: '', + headStatus: false, + employee_id: 0, + } +} diff --git a/app/models/subspecialist.ts b/app/models/subspecialist.ts index 6343b847..e67333e9 100644 --- a/app/models/subspecialist.ts +++ b/app/models/subspecialist.ts @@ -1,9 +1,11 @@ -import { type Base, genBase } from "./_base" - +import { type Base, genBase } from './_base' +import { type Specialist } from './specialist' export interface Subspecialist extends Base { code: string name: string specialist_id?: number | string | null + + specialist?: Specialist | null } export function genSubspecialist(): Subspecialist { @@ -11,6 +13,6 @@ export function genSubspecialist(): Subspecialist { ...genBase(), code: '', name: '', - specialist_id: 0 + specialist_id: 0, } } diff --git a/app/models/unit-position.ts b/app/models/unit-position.ts new file mode 100644 index 00000000..11e97806 --- /dev/null +++ b/app/models/unit-position.ts @@ -0,0 +1,23 @@ +import { type Base, genBase } from './_base' +import type { Employee } from './employee' + +export interface UnitPosition extends Base { + unit_id: number + code: string + name: string + headStatus?: boolean + employee_id?: number + + employee?: Employee | null +} + +export function genUnitPosition(): UnitPosition { + return { + ...genBase(), + unit_id: 0, + code: '', + name: '', + headStatus: false, + employee_id: 0, + } +} diff --git a/app/models/unit.ts b/app/models/unit.ts index 142f0570..ba8ba5a1 100644 --- a/app/models/unit.ts +++ b/app/models/unit.ts @@ -1,9 +1,11 @@ -import { type Base, genBase } from "./_base" - +import { type Base, genBase } from './_base' +import { type Installation } from '~/models/installation' export interface Unit extends Base { code: string name: string installation_id?: number | string | null + + installation?: Installation | null } export function genUnit(): Unit { diff --git a/app/pages/(features)/org-src/division-position/index.vue b/app/pages/(features)/org-src/division-position/index.vue new file mode 100644 index 00000000..53551b48 --- /dev/null +++ b/app/pages/(features)/org-src/division-position/index.vue @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/app/pages/(features)/org-src/division/[id]/index.vue b/app/pages/(features)/org-src/division/[id]/index.vue new file mode 100644 index 00000000..658652d9 --- /dev/null +++ b/app/pages/(features)/org-src/division/[id]/index.vue @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/app/pages/(features)/org-src/installation-position/index.vue b/app/pages/(features)/org-src/installation-position/index.vue new file mode 100644 index 00000000..0b525098 --- /dev/null +++ b/app/pages/(features)/org-src/installation-position/index.vue @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/app/pages/(features)/org-src/installation/[id]/index.vue b/app/pages/(features)/org-src/installation/[id]/index.vue new file mode 100644 index 00000000..0264dd65 --- /dev/null +++ b/app/pages/(features)/org-src/installation/[id]/index.vue @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/app/pages/(features)/org-src/specialist-position/index.vue b/app/pages/(features)/org-src/specialist-position/index.vue new file mode 100644 index 00000000..a2e29428 --- /dev/null +++ b/app/pages/(features)/org-src/specialist-position/index.vue @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/app/pages/(features)/org-src/specialist/[id]/index.vue b/app/pages/(features)/org-src/specialist/[id]/index.vue new file mode 100644 index 00000000..c5554a71 --- /dev/null +++ b/app/pages/(features)/org-src/specialist/[id]/index.vue @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/app/pages/(features)/org-src/subspecialist-position/index.vue b/app/pages/(features)/org-src/subspecialist-position/index.vue new file mode 100644 index 00000000..650ae9ee --- /dev/null +++ b/app/pages/(features)/org-src/subspecialist-position/index.vue @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/app/pages/(features)/org-src/subspecialist/[id]/index.vue b/app/pages/(features)/org-src/subspecialist/[id]/index.vue new file mode 100644 index 00000000..7bd0b8ee --- /dev/null +++ b/app/pages/(features)/org-src/subspecialist/[id]/index.vue @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/app/pages/(features)/org-src/unit-position/index.vue b/app/pages/(features)/org-src/unit-position/index.vue new file mode 100644 index 00000000..c40a0654 --- /dev/null +++ b/app/pages/(features)/org-src/unit-position/index.vue @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/app/pages/(features)/org-src/unit/[id]/index.vue b/app/pages/(features)/org-src/unit/[id]/index.vue new file mode 100644 index 00000000..1230b57c --- /dev/null +++ b/app/pages/(features)/org-src/unit/[id]/index.vue @@ -0,0 +1,42 @@ + + + + + + + + diff --git a/app/schemas/installation-position.schema.ts b/app/schemas/installation-position.schema.ts new file mode 100644 index 00000000..5990fc6c --- /dev/null +++ b/app/schemas/installation-position.schema.ts @@ -0,0 +1,20 @@ +import { z } from 'zod' +import type { InstallationPosition } from '~/models/installation-position' + +const InstallationPositionSchema = 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'), + headStatus: z.boolean().optional().nullable(), + installation_id: z.union([ + z.string({ required_error: 'Instalasi Induk harus diisi' }), + z.number({ required_error: 'Instalasi Induk harus diisi' }), + ]), + employee_id: z + .union([z.string({ required_error: 'Karyawan harus diisi' }), z.number({ required_error: 'Karyawan harus diisi' })]) + .optional() + .nullable(), +}) +type InstallationPositionFormData = z.infer & Partial + +export { InstallationPositionSchema } +export type { InstallationPositionFormData } diff --git a/app/schemas/specialist-position.schema.ts b/app/schemas/specialist-position.schema.ts new file mode 100644 index 00000000..7aacef37 --- /dev/null +++ b/app/schemas/specialist-position.schema.ts @@ -0,0 +1,24 @@ +import { z } from 'zod' +import type { SpecialistPosition } from '~/models/specialist-position' + +const SpecialistPositionSchema = 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'), + headStatus: z.boolean().optional().nullable(), + specialist_id: z + .union([ + z.string({ required_error: 'Spesialis harus diisi' }), + z.number({ required_error: 'Spesialis harus diisi' }), + ]) + .optional() + .nullable(), + employee_id: z + .union([z.string({ required_error: 'Karyawan harus diisi' }), z.number({ required_error: 'Karyawan harus diisi' })]) + .optional() + .nullable(), +}) + +type SpecialistPositionFormData = z.infer & Partial + +export { SpecialistPositionSchema } +export type { SpecialistPositionFormData } diff --git a/app/schemas/subspecialist-position.schema.ts b/app/schemas/subspecialist-position.schema.ts new file mode 100644 index 00000000..7f458e7b --- /dev/null +++ b/app/schemas/subspecialist-position.schema.ts @@ -0,0 +1,24 @@ +import { z } from 'zod' +import type { SubSpecialistPosition } from '~/models/subspecialist-position' + +const SubSpecialistPositionSchema = 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'), + headStatus: z.boolean().optional().nullable(), + subspecialist_id: z + .union([ + z.string({ required_error: 'Spesialis harus diisi' }), + z.number({ required_error: 'Spesialis harus diisi' }), + ]) + .optional() + .nullable(), + employee_id: z + .union([z.string({ required_error: 'Karyawan harus diisi' }), z.number({ required_error: 'Karyawan harus diisi' })]) + .optional() + .nullable(), +}) + +type SubSpecialistPositionFormData = z.infer & Partial + +export { SubSpecialistPositionSchema } +export type { SubSpecialistPositionFormData } diff --git a/app/schemas/unit-position.schema.ts b/app/schemas/unit-position.schema.ts new file mode 100644 index 00000000..2422b9a1 --- /dev/null +++ b/app/schemas/unit-position.schema.ts @@ -0,0 +1,24 @@ +import { z } from 'zod' +import type { UnitPosition } from '~/models/unit-position' + +const UnitPositionSchema = 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'), + headStatus: z.boolean().optional().nullable(), + unit_id: z + .union([ + z.string({ required_error: 'Unit Induk harus diisi' }), + z.number({ required_error: 'Unit Induk harus diisi' }), + ]) + .optional() + .nullable(), + employee_id: z + .union([z.string({ required_error: 'Karyawan harus diisi' }), z.number({ required_error: 'Karyawan harus diisi' })]) + .optional() + .nullable(), +}) + +type UnitPositionFormData = z.infer & Partial + +export { UnitPositionSchema } +export type { UnitPositionFormData } diff --git a/app/services/employee.service.ts b/app/services/employee.service.ts index 366ef71e..3121e7a2 100644 --- a/app/services/employee.service.ts +++ b/app/services/employee.service.ts @@ -1,4 +1,5 @@ // Base +import type { Employee } from '~/models/employee' import * as base from './_crud-base' const path = '/api/v1/employee' @@ -29,9 +30,9 @@ export async function getValueLabelList(params: any = null): Promise<{ value: st const result = await getList(params) if (result.success) { const resultData = result.body?.data || [] - data = resultData.map((item: any) => ({ - value: item.id ? Number(item.id) : item.code, - label: item.person.name, + data = resultData.map((item: Employee) => ({ + value: item.id, + label: `${item.person.frontTitle} ${item.person.name} ${item.person.endTitle}`.trim(), })) } return data diff --git a/app/services/installation-position.service.ts b/app/services/installation-position.service.ts new file mode 100644 index 00000000..13d5e914 --- /dev/null +++ b/app/services/installation-position.service.ts @@ -0,0 +1,41 @@ +// Base +import * as base from './_crud-base' + +// Types +import type { Installation } from '~/models/installation' + +const path = '/api/v1/installation-position' +const name = 'installation' + +export function create(data: any) { + 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) +} + +export async function getValueLabelList(params: any = null): Promise<{ value: string; label: string }[]> { + let data: { value: string; label: string }[] = [] + const result = await getList(params) + if (result.success) { + const resultData = result.body?.data || [] + data = resultData.map((item: Installation) => ({ + value: item.id ? Number(item.id) : item.code, + label: item.name, + })) + } + return data +} diff --git a/app/services/specialist-position.service.ts b/app/services/specialist-position.service.ts new file mode 100644 index 00000000..6966ca60 --- /dev/null +++ b/app/services/specialist-position.service.ts @@ -0,0 +1,25 @@ +// Base +import * as base from './_crud-base' + +const path = '/api/v1/specialist-position' +const name = 'specialist-position' + +export function create(data: any) { + 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/specialist.service.ts b/app/services/specialist.service.ts index 1e3be79c..b18eac34 100644 --- a/app/services/specialist.service.ts +++ b/app/services/specialist.service.ts @@ -16,8 +16,8 @@ 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 getDetail(id: number | string, params?: any) { + return base.getDetail(path, id, name, params) } export function update(id: number | string, data: any) { diff --git a/app/services/subspecialist-position.service.ts b/app/services/subspecialist-position.service.ts new file mode 100644 index 00000000..9653100b --- /dev/null +++ b/app/services/subspecialist-position.service.ts @@ -0,0 +1,25 @@ +// Base +import * as base from './_crud-base' + +const path = '/api/v1/subspecialist-position' +const name = 'subspecialist-position' + +export function create(data: any) { + 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/subspecialist.service.ts b/app/services/subspecialist.service.ts index 94e70a09..e384f059 100644 --- a/app/services/subspecialist.service.ts +++ b/app/services/subspecialist.service.ts @@ -15,8 +15,8 @@ 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 getDetail(id: number | string, params?: any) { + return base.getDetail(path, id, name, params) } export function update(id: number | string, data: any) { diff --git a/app/services/unit-position.service.ts b/app/services/unit-position.service.ts new file mode 100644 index 00000000..ee9cf89c --- /dev/null +++ b/app/services/unit-position.service.ts @@ -0,0 +1,25 @@ +// Base +import * as base from './_crud-base' + +const path = '/api/v1/unit-position' +const name = 'unit-position' + +export function create(data: any) { + 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/unit.service.ts b/app/services/unit.service.ts index 438625f1..ec1ccec0 100644 --- a/app/services/unit.service.ts +++ b/app/services/unit.service.ts @@ -2,7 +2,7 @@ import * as base from './_crud-base' // Types -import type { Unit } from "~/models/unit"; +import type { Unit } from '~/models/unit' const path = '/api/v1/unit' const name = 'unit' diff --git a/public/side-menu-items/sys.json b/public/side-menu-items/sys.json index 19491069..b69127e7 100644 --- a/public/side-menu-items/sys.json +++ b/public/side-menu-items/sys.json @@ -320,21 +320,41 @@ "title": "Divisi", "link": "/org-src/division" }, + { + "title": "Divisi - Posisi", + "link": "/org-src/division-position" + }, { "title": "Instalasi", "link": "/org-src/installation" }, + { + "title": "Instalasi - Posisi", + "link": "/org-src/installation-position" + }, { "title": "Unit", "link": "/org-src/unit" }, + { + "title": "Unit - Posisi", + "link": "/org-src/unit-position" + }, { "title": "Spesialis", "link": "/org-src/specialist" }, + { + "title": "Spesialis - Posisi", + "link": "/org-src/specialist-position" + }, { "title": "Sub Spesialis", "link": "/org-src/subspecialist" + }, + { + "title": "Sub Spesialis - Posisi", + "link": "/org-src/subspecialist-position" } ] },
+ {{ field.label }}: + {{ record[field.key] }} +
+ ID: + {{ record?.id }} +
+ Nama: + {{ record.name }} +
+ Kode: + {{ record.code }} +