diff --git a/app/assets/svg/wavey-fingerprint.svg b/app/assets/svg/wavey-fingerprint.svg
new file mode 100644
index 00000000..b281297f
--- /dev/null
+++ b/app/assets/svg/wavey-fingerprint.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/app/components/app/bpjs/control-letter/_common/dropdown-action.vue b/app/components/app/bpjs/control-letter/_common/dropdown-action.vue
new file mode 100644
index 00000000..9086c883
--- /dev/null
+++ b/app/components/app/bpjs/control-letter/_common/dropdown-action.vue
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/bpjs/control-letter/_common/history-dialog.vue b/app/components/app/bpjs/control-letter/_common/history-dialog.vue
new file mode 100644
index 00000000..00d7b32f
--- /dev/null
+++ b/app/components/app/bpjs/control-letter/_common/history-dialog.vue
@@ -0,0 +1,49 @@
+
+
+
+
+ -
+
+
+
+
+
+
+
{{ item.description }}
+
+
+
+
+
\ No newline at end of file
diff --git a/app/components/app/bpjs/control-letter/_common/select-date-range.vue b/app/components/app/bpjs/control-letter/_common/select-date-range.vue
new file mode 100644
index 00000000..114f8542
--- /dev/null
+++ b/app/components/app/bpjs/control-letter/_common/select-date-range.vue
@@ -0,0 +1,104 @@
+
+
+
+
+
+ {{ label }}
+
+
+
+
+
+
+
+
+
+
+ (value.start = startDate)"
+ />
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/bpjs/control-letter/_common/select-destination-polyclinic.vue b/app/components/app/bpjs/control-letter/_common/select-destination-polyclinic.vue
new file mode 100644
index 00000000..0852195b
--- /dev/null
+++ b/app/components/app/bpjs/control-letter/_common/select-destination-polyclinic.vue
@@ -0,0 +1,70 @@
+
+
+
+
+
+ {{ label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/bpjs/control-letter/_common/select-origin-polyclinic.vue b/app/components/app/bpjs/control-letter/_common/select-origin-polyclinic.vue
new file mode 100644
index 00000000..0852195b
--- /dev/null
+++ b/app/components/app/bpjs/control-letter/_common/select-origin-polyclinic.vue
@@ -0,0 +1,70 @@
+
+
+
+
+
+ {{ label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/bpjs/control-letter/filter.vue b/app/components/app/bpjs/control-letter/filter.vue
new file mode 100644
index 00000000..50005069
--- /dev/null
+++ b/app/components/app/bpjs/control-letter/filter.vue
@@ -0,0 +1,128 @@
+
+
+
+
+
+
diff --git a/app/components/app/bpjs/control-letter/list.cfg.ts b/app/components/app/bpjs/control-letter/list.cfg.ts
new file mode 100644
index 00000000..8eb7e5f4
--- /dev/null
+++ b/app/components/app/bpjs/control-letter/list.cfg.ts
@@ -0,0 +1,108 @@
+import type { Config } from '~/components/pub/my-ui/data-table'
+import type { Patient } from '~/models/patient'
+import { defineAsyncComponent } from 'vue'
+import { educationCodes, genderCodes } from '~/lib/constants'
+import { calculateAge } from '~/lib/utils'
+
+const action = defineAsyncComponent(() => import('./_common/dropdown-action.vue'))
+const statusBadge = defineAsyncComponent(() => import('~/components/pub/my-ui/badge/status-badge.vue'))
+
+export const config: Config = {
+ cols: [{}, {}, {}, {},{}, {}, {}, {}, {}, {width: 90},{width: 10},],
+
+ headers: [
+ [
+ { label: 'No Surat' },
+ { label: 'No MR' },
+ { label: 'Nama' },
+ { label: 'Tgl Rencana Kontrol' },
+ { label: 'Tgl Penerbitan' },
+ { label: 'Klinik Asal' },
+ { label: 'Klinik Tujuan' },
+ { label: 'DPJP' },
+ { label: 'No SEP Asal' },
+ { label: 'Status' },
+ { label: 'Action' },
+ ],
+ ],
+
+ keys: ['birth_date', 'number', 'person.name', 'birth_date', 'birth_date',
+ 'birth_date', 'number', 'person.name', 'birth_date', 'status', 'action'],
+
+ delKeyNames: [
+ { key: 'code', label: 'Kode' },
+ { key: 'name', label: 'Nama' },
+ ],
+
+ parses: {
+ patientId: (rec: unknown): unknown => {
+ const patient = rec as Patient
+ return patient.number
+ },
+ identity_number: (rec: unknown): unknown => {
+ const { person } = rec as Patient
+
+ if (person.nationality == 'WNA') {
+ return person.passportNumber
+ }
+
+ return person.residentIdentityNumber || '-'
+ },
+ birth_date: (rec: unknown): unknown => {
+ const { person } = rec as Patient
+
+ if (typeof person.birthDate == 'object' && person.birthDate) {
+ return (person.birthDate as Date).toLocaleDateString('id-ID')
+ } else if (typeof person.birthDate == 'string') {
+ return (person.birthDate as string).substring(0, 10)
+ }
+ return person.birthDate
+ },
+ patient_age: (rec: unknown): unknown => {
+ const { person } = rec as Patient
+ return calculateAge(person.birthDate)
+ },
+ gender: (rec: unknown): unknown => {
+ const { person } = rec as Patient
+
+ if (typeof person.gender_code == 'number' && person.gender_code >= 0) {
+ return person.gender_code
+ } else if (typeof person.gender_code === 'string' && person.gender_code) {
+ return genderCodes[person.gender_code] || '-'
+ }
+ return '-'
+ },
+ education: (rec: unknown): unknown => {
+ const { person } = rec as Patient
+ if (typeof person.education_code == 'number' && person.education_code >= 0) {
+ return person.education_code
+ } else if (typeof person.education_code === 'string' && person.education_code) {
+ return educationCodes[person.education_code] || '-'
+ }
+ return '-'
+ },
+ },
+
+ components: {
+ action(rec, idx) {
+ return {
+ idx,
+ rec: rec as object,
+ component: action,
+ }
+ },
+ status(rec, idx) {
+ return {
+ idx,
+ rec: rec as object,
+ component: statusBadge,
+ }
+ },
+ },
+
+ htmls: {
+ patient_address(_rec) {
+ return '-'
+ },
+ },
+}
diff --git a/app/components/app/bpjs/control-letter/list.vue b/app/components/app/bpjs/control-letter/list.vue
new file mode 100644
index 00000000..8274e752
--- /dev/null
+++ b/app/components/app/bpjs/control-letter/list.vue
@@ -0,0 +1,31 @@
+
+
+
+
+
diff --git a/app/components/app/chemotherapy/action-proses.vue b/app/components/app/chemotherapy/action-proses.vue
new file mode 100644
index 00000000..4e2efeb3
--- /dev/null
+++ b/app/components/app/chemotherapy/action-proses.vue
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
diff --git a/app/components/app/chemotherapy/dialog-verification.vue b/app/components/app/chemotherapy/dialog-verification.vue
new file mode 100644
index 00000000..2d617445
--- /dev/null
+++ b/app/components/app/chemotherapy/dialog-verification.vue
@@ -0,0 +1,164 @@
+
+
+
+
+
+
diff --git a/app/components/app/chemotherapy/dropdown-action-process.vue b/app/components/app/chemotherapy/dropdown-action-process.vue
new file mode 100644
index 00000000..56e14886
--- /dev/null
+++ b/app/components/app/chemotherapy/dropdown-action-process.vue
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/chemotherapy/entry-form.vue b/app/components/app/chemotherapy/entry-form.vue
new file mode 100644
index 00000000..39113d63
--- /dev/null
+++ b/app/components/app/chemotherapy/entry-form.vue
@@ -0,0 +1,302 @@
+
+
+
+
+
diff --git a/app/components/app/chemotherapy/list-admin.vue b/app/components/app/chemotherapy/list-admin.vue
new file mode 100644
index 00000000..a201f2a1
--- /dev/null
+++ b/app/components/app/chemotherapy/list-admin.vue
@@ -0,0 +1,37 @@
+
+
+
+
+
+
diff --git a/app/components/app/chemotherapy/list-cfg.admin.ts b/app/components/app/chemotherapy/list-cfg.admin.ts
new file mode 100644
index 00000000..38d77121
--- /dev/null
+++ b/app/components/app/chemotherapy/list-cfg.admin.ts
@@ -0,0 +1,80 @@
+import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
+import { defineAsyncComponent } from 'vue'
+
+type SmallDetailDto = any
+
+const action = defineAsyncComponent(() => import('./dropdown-action-process.vue'))
+
+export const config: Config = {
+ cols: [
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 50 },
+ ],
+
+ headers: [
+ [
+ { label: 'TANGGAL' },
+ { label: 'NO. RM' },
+ { label: 'NO. BILL' },
+ { label: 'JK' },
+ { label: 'ALAMAT' },
+ { label: 'KLINIK ASAL' },
+ { label: 'NAMA DOKTER' },
+ { label: 'CARA BAYAR' },
+ { label: 'RUJUKAN' },
+ { label: 'KET. RUJUKAN' },
+ { label: 'ASAL' },
+ { label: '' },
+ ],
+ ],
+
+ keys: [
+ 'tanggal',
+ 'noRm',
+ 'noBill',
+ 'jk',
+ 'alamat',
+ 'klinik',
+ 'dokter',
+ 'caraBayar',
+ 'rujukan',
+ 'ketRujukan',
+ 'asal',
+ 'action',
+ ],
+
+ delKeyNames: [
+ { key: 'code', label: 'Kode' },
+ { key: 'name', label: 'Nama' },
+ ],
+
+ parses: {
+ parent: (rec: unknown): unknown => {
+ const recX = rec as SmallDetailDto
+ return recX.parent?.name || '-'
+ },
+ },
+
+ components: {
+ action(rec, idx) {
+ const res: RecComponent = {
+ idx,
+ rec: rec as object,
+ component: action,
+ }
+ return res
+ },
+ },
+
+ htmls: {},
+}
diff --git a/app/components/app/chemotherapy/list-cfg.medicine.ts b/app/components/app/chemotherapy/list-cfg.medicine.ts
new file mode 100644
index 00000000..103452f5
--- /dev/null
+++ b/app/components/app/chemotherapy/list-cfg.medicine.ts
@@ -0,0 +1,69 @@
+import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
+import { defineAsyncComponent } from 'vue'
+
+type SmallDetailDto = any
+
+const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
+
+export const config: Config = {
+ cols: [
+ { width: 60 },
+ { width: 200 },
+ { width: 100 },
+ { width: 100 },
+ { width: 150 },
+ { width: 80 },
+ { width: 200 },
+ { width: 120 },
+ ],
+
+ headers: [
+ [
+ { label: 'NO.' },
+ { label: 'NAMA OBAT' },
+ { label: 'DOSIS' },
+ { label: 'SATUAN' },
+ { label: 'RUTE PEMBERIAN' },
+ { label: 'HARI' },
+ { label: 'CATATAN' },
+ { label: '' },
+ ],
+ ],
+
+ keys: [
+ 'number',
+ 'namaObat',
+ 'dosis',
+ 'satuan',
+ 'rute',
+ 'hari',
+ 'catatan',
+ 'action',
+ ],
+
+ delKeyNames: [
+ { key: 'code', label: 'Kode' },
+ { key: 'name', label: 'Nama' },
+ ],
+
+ parses: {
+ parent: (rec: unknown): unknown => {
+ const recX = rec as SmallDetailDto
+ return recX.parent?.name || '-'
+ },
+ },
+
+ components: {
+ action(rec, idx) {
+ const res: RecComponent = {
+ idx,
+ rec: rec as object,
+ component: action,
+ }
+ return res
+ },
+ },
+
+ htmls: {},
+}
+
diff --git a/app/components/app/chemotherapy/list-cfg.protocol.ts b/app/components/app/chemotherapy/list-cfg.protocol.ts
new file mode 100644
index 00000000..da678c0f
--- /dev/null
+++ b/app/components/app/chemotherapy/list-cfg.protocol.ts
@@ -0,0 +1,62 @@
+import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
+import { defineAsyncComponent } from 'vue'
+
+type SmallDetailDto = any
+
+const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
+
+export const config: Config = {
+ cols: [
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 50 },
+ ],
+
+ headers: [
+ [
+ { label: 'NO.' },
+ { label: 'TANGGAL' },
+ { label: 'SIKLUS' },
+ { label: 'PERIODE KEMOTERAPI' },
+ { label: 'KEHADIRAN' },
+ { label: '' },
+ ],
+ ],
+
+ keys: [
+ 'number',
+ 'tanggal',
+ 'siklus',
+ 'periode',
+ 'kehadiran',
+ 'action',
+ ],
+
+ delKeyNames: [
+ { key: 'code', label: 'Kode' },
+ { key: 'name', label: 'Nama' },
+ ],
+
+ parses: {
+ parent: (rec: unknown): unknown => {
+ const recX = rec as SmallDetailDto
+ return recX.parent?.name || '-'
+ },
+ },
+
+ components: {
+ action(rec, idx) {
+ const res: RecComponent = {
+ idx,
+ rec: rec as object,
+ component: action,
+ }
+ return res
+ },
+ },
+
+ htmls: {},
+}
diff --git a/app/components/app/chemotherapy/list-cfg.ts b/app/components/app/chemotherapy/list-cfg.ts
new file mode 100644
index 00000000..29c24e6f
--- /dev/null
+++ b/app/components/app/chemotherapy/list-cfg.ts
@@ -0,0 +1,80 @@
+import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
+import { defineAsyncComponent } from 'vue'
+
+type SmallDetailDto = any
+
+const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
+
+export const config: Config = {
+ cols: [
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 120 },
+ { width: 50 },
+ ],
+
+ headers: [
+ [
+ { label: 'TANGGAL' },
+ { label: 'NO. RM' },
+ { label: 'NO. BILL' },
+ { label: 'JK' },
+ { label: 'ALAMAT' },
+ { label: 'KLINIK ASAL' },
+ { label: 'NAMA DOKTER' },
+ { label: 'CARA BAYAR' },
+ { label: 'RUJUKAN' },
+ { label: 'KET. RUJUKAN' },
+ { label: 'ASAL' },
+ { label: '' },
+ ],
+ ],
+
+ keys: [
+ 'tanggal',
+ 'noRm',
+ 'noBill',
+ 'jk',
+ 'alamat',
+ 'klinik',
+ 'dokter',
+ 'caraBayar',
+ 'rujukan',
+ 'ketRujukan',
+ 'asal',
+ 'action',
+ ],
+
+ delKeyNames: [
+ { key: 'code', label: 'Kode' },
+ { key: 'name', label: 'Nama' },
+ ],
+
+ parses: {
+ parent: (rec: unknown): unknown => {
+ const recX = rec as SmallDetailDto
+ return recX.parent?.name || '-'
+ },
+ },
+
+ components: {
+ action(rec, idx) {
+ const res: RecComponent = {
+ idx,
+ rec: rec as object,
+ component: action,
+ }
+ return res
+ },
+ },
+
+ htmls: {},
+}
diff --git a/app/components/app/chemotherapy/list-cfg.verification.ts b/app/components/app/chemotherapy/list-cfg.verification.ts
new file mode 100644
index 00000000..e75aa615
--- /dev/null
+++ b/app/components/app/chemotherapy/list-cfg.verification.ts
@@ -0,0 +1,78 @@
+import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
+import { defineAsyncComponent } from 'vue'
+
+type SmallDetailDto = any
+
+const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
+const verifyButton = defineAsyncComponent(() => import('./verify-button.vue'))
+
+export const config: Config = {
+ cols: [
+ { width: 120 },
+ { width: 150 },
+ { width: 150 },
+ { width: 150 },
+ { width: 150 },
+ { width: 180 },
+ { width: 150 },
+ { width: 100 },
+ ],
+
+ headers: [
+ [
+ { label: 'TANGGAL MASUK' },
+ { label: 'PJ BERKAS RM' },
+ { label: 'DOKTER' },
+ { label: 'JENIS RUANGAN' },
+ { label: 'JENIS TINDAKAN' },
+ { label: 'TANGGAL JADWAL TINDAKAN' },
+ { label: 'STATUS' },
+ { label: 'AKSI' },
+ ],
+ ],
+
+ keys: [
+ 'tanggalMasuk',
+ 'pjBerkasRm',
+ 'dokter',
+ 'jenisRuangan',
+ 'jenisTindakan',
+ 'tanggalJadwalTindakan',
+ 'status',
+ 'action',
+ ],
+
+ delKeyNames: [
+ { key: 'code', label: 'Kode' },
+ { key: 'name', label: 'Nama' },
+ ],
+
+ parses: {
+ parent: (rec: unknown): unknown => {
+ const recX = rec as SmallDetailDto
+ return recX.parent?.name || '-'
+ },
+ },
+
+ components: {
+ status(rec, idx) {
+ const res: RecComponent = {
+ idx,
+ rec: rec as object,
+ component: statusBadge,
+ }
+ return res
+ },
+ action(rec, idx) {
+ const res: RecComponent = {
+ idx,
+ rec: rec as object,
+ component: verifyButton,
+ }
+ return res
+ },
+ },
+
+ htmls: {},
+}
+
diff --git a/app/components/app/chemotherapy/list-cfg.visit.ts b/app/components/app/chemotherapy/list-cfg.visit.ts
new file mode 100644
index 00000000..cb242d62
--- /dev/null
+++ b/app/components/app/chemotherapy/list-cfg.visit.ts
@@ -0,0 +1,99 @@
+import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
+import { defineAsyncComponent } from 'vue'
+import { format, parseISO } from 'date-fns'
+import { id as localeID } from 'date-fns/locale'
+
+type VisitDto = any
+
+const statusBadge = defineAsyncComponent(() => import('./status-badge.vue'))
+const verifyButton = defineAsyncComponent(() => import('./verify-button.vue'))
+
+export const config: Config = {
+ cols: [
+ { width: 150 }, // TANGGAL MASUK
+ { width: 180 }, // PJ BERKAS RM
+ { width: 200 }, // DOKTER
+ { width: 150 }, // JENIS RUANGAN
+ { width: 150 }, // JENIS TINDAKAN
+ { width: 180 }, // TANGGAL JADWAL TINDAKAN
+ { width: 150 }, // STATUS
+ { width: 120 }, // AKSI
+ ],
+
+ headers: [
+ [
+ { label: 'TANGGAL MASUK' },
+ { label: 'PJ BERKAS RM' },
+ { label: 'DOKTER' },
+ { label: 'JENIS RUANGAN' },
+ { label: 'JENIS TINDAKAN' },
+ { label: 'TANGGAL JADWAL TINDAKAN' },
+ { label: 'STATUS' },
+ { label: 'AKSI' },
+ ],
+ ],
+
+ keys: [
+ 'tanggal_masuk',
+ 'pj_berkas_rm',
+ 'dokter',
+ 'jenis_ruangan',
+ 'jenis_tindakan',
+ 'tanggal_jadwal_tindakan',
+ 'status',
+ 'action',
+ ],
+
+ delKeyNames: [
+ { key: 'id', label: 'ID' },
+ { key: 'nama', label: 'Nama' },
+ ],
+
+ parses: {
+ tanggal_masuk: (rec: unknown): string => {
+ const recX = rec as VisitDto
+ if (!recX.tanggal_masuk) return '-'
+ try {
+ const date = typeof recX.tanggal_masuk === 'string' ? parseISO(recX.tanggal_masuk) : recX.tanggal_masuk
+ return format(date, 'dd MMMM yyyy', { locale: localeID })
+ } catch {
+ return recX.tanggal_masuk.toString()
+ }
+ },
+ tanggal_jadwal_tindakan: (rec: unknown): string => {
+ const recX = rec as VisitDto
+ if (!recX.tanggal_jadwal_tindakan) return '-'
+ try {
+ const date =
+ typeof recX.tanggal_jadwal_tindakan === 'string'
+ ? parseISO(recX.tanggal_jadwal_tindakan)
+ : recX.tanggal_jadwal_tindakan
+ return format(date, 'dd MMMM yyyy', { locale: localeID })
+ } catch {
+ return recX.tanggal_jadwal_tindakan.toString()
+ }
+ },
+ },
+
+ components: {
+ status(rec, idx) {
+ const res: RecComponent = {
+ idx,
+ rec: rec as object,
+ component: statusBadge,
+ }
+ return res
+ },
+ action(rec, idx) {
+ const res: RecComponent = {
+ idx,
+ rec: rec as object,
+ component: verifyButton,
+ }
+ return res
+ },
+ },
+
+ htmls: {},
+}
+
diff --git a/app/components/app/chemotherapy/list-verification.vue b/app/components/app/chemotherapy/list-verification.vue
new file mode 100644
index 00000000..93120f69
--- /dev/null
+++ b/app/components/app/chemotherapy/list-verification.vue
@@ -0,0 +1,37 @@
+
+
+
+
+
+
diff --git a/app/components/app/chemotherapy/list.medicine.vue b/app/components/app/chemotherapy/list.medicine.vue
new file mode 100644
index 00000000..748c8cb9
--- /dev/null
+++ b/app/components/app/chemotherapy/list.medicine.vue
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
Protokol Obat Kemoterapi
+
Daftar obat-obatan yang digunakan dalam protokol kemoterapi.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/chemotherapy/list.protocol.vue b/app/components/app/chemotherapy/list.protocol.vue
new file mode 100644
index 00000000..7b5c3234
--- /dev/null
+++ b/app/components/app/chemotherapy/list.protocol.vue
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
Protokol Kemoterapi
+
Rangkaian prosedur kemoterapi yang terintegrasi dan konsisten.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/chemotherapy/list.register.vue b/app/components/app/chemotherapy/list.register.vue
new file mode 100644
index 00000000..131afc04
--- /dev/null
+++ b/app/components/app/chemotherapy/list.register.vue
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
Daftar Kunjungan Rawat Jalan Kemoterapi
+
Manajemen pendaftaran serta monitoring terapi pasien tindakan rawat jalan.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/chemotherapy/list.visit.vue b/app/components/app/chemotherapy/list.visit.vue
new file mode 100644
index 00000000..de451f31
--- /dev/null
+++ b/app/components/app/chemotherapy/list.visit.vue
@@ -0,0 +1,45 @@
+
+
+
+
+
+
diff --git a/app/components/app/chemotherapy/list.vue b/app/components/app/chemotherapy/list.vue
new file mode 100644
index 00000000..19642581
--- /dev/null
+++ b/app/components/app/chemotherapy/list.vue
@@ -0,0 +1,36 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/components/app/chemotherapy/sample.ts b/app/components/app/chemotherapy/sample.ts
new file mode 100644
index 00000000..082cde66
--- /dev/null
+++ b/app/components/app/chemotherapy/sample.ts
@@ -0,0 +1,49 @@
+export type ChemotherapyData = {
+ id: number
+ tanggal: string
+ noRm: string
+ noBill: string
+ nama: string
+ jk: string
+ alamat: string
+ klinik: string
+ dokter: string
+ caraBayar: string
+ rujukan: string
+ ketRujukan: string
+ asal: string
+}
+
+export const sampleRows: ChemotherapyData[] = [
+ {
+ id: 1,
+ tanggal: '12 Agustus 2025',
+ noRm: 'RM23311224',
+ noBill: '-',
+ nama: 'Ahmad Baidowi',
+ jk: 'L',
+ alamat: 'Jl Jaksa Agung S. No. 9',
+ klinik: 'Penyakit dalam',
+ dokter: 'Dr. Andreas Sutaji',
+ caraBayar: 'JKN',
+ rujukan: 'Faskes BPJS',
+ ketRujukan: 'RUMAH SAKIT - RS Lawang Medika - Malang',
+ asal: 'Rawat Jalan Reguler',
+ },
+ {
+ id: 2,
+ tanggal: '11 Agustus 2025',
+ noRm: 'RM23455667',
+ noBill: '-',
+ nama: 'Abraham Sulaiman',
+ jk: 'L',
+ alamat: 'Purwantoro, Blimbing',
+ klinik: 'Penyakit dalam',
+ dokter: 'Dr. Andreas Sutaji',
+ caraBayar: 'JKN',
+ rujukan: 'Faskes BPJS',
+ ketRujukan: 'RUMAH SAKIT - RS Lawang Medika - Malang',
+ asal: 'Rawat Jalan Reguler',
+ },
+ // tambahkan lebih banyak baris contoh jika perlu
+]
diff --git a/app/components/app/chemotherapy/status-badge.vue b/app/components/app/chemotherapy/status-badge.vue
new file mode 100644
index 00000000..1a7d94ca
--- /dev/null
+++ b/app/components/app/chemotherapy/status-badge.vue
@@ -0,0 +1,28 @@
+
+
+
+
+
+ {{ statusInfo.text }}
+
+
+
+
diff --git a/app/components/app/chemotherapy/verify-button.vue b/app/components/app/chemotherapy/verify-button.vue
new file mode 100644
index 00000000..1d9c2d3a
--- /dev/null
+++ b/app/components/app/chemotherapy/verify-button.vue
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
diff --git a/app/components/app/control-letter/_common/select-date.vue b/app/components/app/control-letter/_common/select-date.vue
new file mode 100644
index 00000000..057d0a63
--- /dev/null
+++ b/app/components/app/control-letter/_common/select-date.vue
@@ -0,0 +1,116 @@
+
+
+
+
+
+ {{ label }}
+
+
+
+
+
+ {
+ const dateStr = typeof value === 'number' ? String(value) : value
+ patientAge = calculateAge(dateStr)
+ }
+ "
+ />
+
+
+
+
+
+
+
diff --git a/app/components/app/control-letter/_common/select-dpjp.vue b/app/components/app/control-letter/_common/select-dpjp.vue
new file mode 100644
index 00000000..2053ebdb
--- /dev/null
+++ b/app/components/app/control-letter/_common/select-dpjp.vue
@@ -0,0 +1,98 @@
+
+
+
+
+
+ {{ label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/control-letter/_common/select-specialist.vue b/app/components/app/control-letter/_common/select-specialist.vue
new file mode 100644
index 00000000..cd5ee923
--- /dev/null
+++ b/app/components/app/control-letter/_common/select-specialist.vue
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+ Spesialis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/control-letter/_common/select-subspecialist.vue b/app/components/app/control-letter/_common/select-subspecialist.vue
new file mode 100644
index 00000000..61567c0c
--- /dev/null
+++ b/app/components/app/control-letter/_common/select-subspecialist.vue
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+ Sub Spesialis
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/control-letter/_common/select-unit.vue b/app/components/app/control-letter/_common/select-unit.vue
new file mode 100644
index 00000000..afe0ca0a
--- /dev/null
+++ b/app/components/app/control-letter/_common/select-unit.vue
@@ -0,0 +1,85 @@
+
+
+
+
+
+ {{ label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/control-letter/entry-form.vue b/app/components/app/control-letter/entry-form.vue
new file mode 100644
index 00000000..2517e8b1
--- /dev/null
+++ b/app/components/app/control-letter/entry-form.vue
@@ -0,0 +1,94 @@
+
+
+
+
+
diff --git a/app/components/app/control-letter/list.cfg.ts b/app/components/app/control-letter/list.cfg.ts
new file mode 100644
index 00000000..3eb7bd84
--- /dev/null
+++ b/app/components/app/control-letter/list.cfg.ts
@@ -0,0 +1,64 @@
+import type { Config } from '~/components/pub/my-ui/data-table'
+import type { Patient } from '~/models/patient'
+import { defineAsyncComponent } from 'vue'
+import { educationCodes, genderCodes } from '~/lib/constants'
+import { calculateAge } from '~/lib/utils'
+
+const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dud.vue'))
+
+export const config: Config = {
+ cols: [{width: 180}, {}, {}, {}, {}, {width: 30},],
+
+ headers: [
+ [
+ { label: 'Tgl Rencana Kontrol' },
+ { label: 'Spesialis' },
+ { label: 'Sub Spesialis' },
+ { label: 'DPJP' },
+ { label: 'Status SEP' },
+ { label: 'Action' },
+ ],
+ ],
+
+ keys: ['date', 'specialist.name', 'subspecialist.name', 'doctor.employee.person.name', 'sep_status', 'action'],
+
+ delKeyNames: [
+ { key: 'code', label: 'Kode' },
+ { key: 'name', label: 'Nama' },
+ ],
+
+ parses: {
+ date: (rec: unknown): unknown => {
+ const date = (rec as any).date
+ if (typeof date == 'object' && date) {
+ return (date as Date).toLocaleDateString('id-ID')
+ } else if (typeof date == 'string') {
+ return (date as string).substring(0, 10)
+ }
+ return date
+ },
+ specialist_subspecialist: (rec: unknown): unknown => {
+ return '-'
+ },
+ dpjp: (rec: unknown): unknown => {
+ // const { person } = rec as Patient
+ return '-'
+ },
+ },
+
+ components: {
+ action(rec, idx) {
+ return {
+ idx,
+ rec: rec as object,
+ component: action,
+ }
+ },
+ },
+
+ htmls: {
+ sep_status(_rec) {
+ return 'SEP Internal'
+ },
+ },
+}
diff --git a/app/components/app/control-letter/list.vue b/app/components/app/control-letter/list.vue
new file mode 100644
index 00000000..8274e752
--- /dev/null
+++ b/app/components/app/control-letter/list.vue
@@ -0,0 +1,31 @@
+
+
+
+
+
diff --git a/app/components/app/control-letter/preview.vue b/app/components/app/control-letter/preview.vue
new file mode 100644
index 00000000..e10a2b91
--- /dev/null
+++ b/app/components/app/control-letter/preview.vue
@@ -0,0 +1,54 @@
+
+
+
+
+ {{ props.instance?.date ? new Date(props.instance?.date).toLocaleDateString('id-ID') : '-' }}
+ {{ props.instance?.unit.name || '-' }}
+ {{ props.instance?.specialist.name || '-' }}
+ {{ props.instance?.subspecialist.name || '-' }}
+ {{ props.instance?.doctor.employee.person.name || '-' }}
+ {{ 'SEP INTERNAL' }}
+
+
+
+
+
diff --git a/app/components/app/device-order-item/entry-form.vue b/app/components/app/device-order-item/entry-form.vue
new file mode 100644
index 00000000..3ae2d200
--- /dev/null
+++ b/app/components/app/device-order-item/entry-form.vue
@@ -0,0 +1,73 @@
+
+
+
+
+
+ Nama
+
+
+
+
+
+ Jumlah
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/components/app/device-order-item/list-entry.config.ts b/app/components/app/device-order-item/list-entry.config.ts
index f2f3ef86..d47c4368 100644
--- a/app/components/app/device-order-item/list-entry.config.ts
+++ b/app/components/app/device-order-item/list-entry.config.ts
@@ -1,36 +1,35 @@
import { defineAsyncComponent } from 'vue'
-import type { Config } from '~/components/pub/my-ui/data-table'
-
+import type { Config, RecComponent } 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 }],
+ cols: [{}, { width: 200 }, { width: 100 }],
headers: [[{ label: 'Nama' }, { label: 'Jumlah' }, { label: '' }]],
- keys: ['name', 'count', 'action'],
+ keys: ['device.name', 'quantity', 'action'],
delKeyNames: [
{ key: 'name', label: 'Nama' },
{ key: 'count', label: 'Jumlah' },
],
- skeletonSize: 10
+ 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
- // },
- // }
+ components: {
+ action(rec, idx) {
+ 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
index 26f6691d..b6031228 100644
--- a/app/components/app/device-order-item/list-entry.vue
+++ b/app/components/app/device-order-item/list-entry.vue
@@ -1,13 +1,23 @@
-
+
-
diff --git a/app/components/app/device-order/confirmation-info.vue b/app/components/app/device-order/confirmation-info.vue
new file mode 100644
index 00000000..6711091f
--- /dev/null
+++ b/app/components/app/device-order/confirmation-info.vue
@@ -0,0 +1,26 @@
+
+
+
+
+ Tgl. Order
+
+
+ {{ data?.createdAt?.substring(0, 10) }}
+
+
+
+ DPJP
+
+
+ {{ data?.doctor?.employee?.person?.name }}
+
+
+
+
\ No newline at end of file
diff --git a/app/components/app/device-order/entry-form.vue b/app/components/app/device-order/entry-form.vue
index bea2b6eb..4e66c441 100644
--- a/app/components/app/device-order/entry-form.vue
+++ b/app/components/app/device-order/entry-form.vue
@@ -1,6 +1,25 @@
- Test
+
+
+ Tanggal
+
+ {{ data?.createdAt?.substring(0, 10) }}
+
+
+
+ DPJP
+
+ {{ data?.doctor?.employee?.person?.name }}
+
+
+
diff --git a/app/components/app/device-order/list.config.ts b/app/components/app/device-order/list.config.ts
index 7580c576..04a6c9fc 100644
--- a/app/components/app/device-order/list.config.ts
+++ b/app/components/app/device-order/list.config.ts
@@ -1,13 +1,18 @@
-import type { Config } from '~/components/pub/my-ui/data-table'
+import type { Config, RecComponent } from '~/components/pub/my-ui/data-table'
import type { DeviceOrder } from '~/models/device-order'
-import { defineAsyncComponent } from 'vue'
+import type { DeviceOrderItem } from '~/models/device-order-item'
-const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-ud.vue'))
+const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dsd.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' },
@@ -16,27 +21,45 @@ export const config: Config = {
htmls: {
items: (rec: unknown): unknown => {
const recX = rec as DeviceOrder
- return recX.items?.length || 0
+ if (recX.items?.length > 0) {
+ let output = '
'
+ recX.items.forEach((item: DeviceOrderItem) => {
+ output += '' +
+ ''+
+ `| ${item.device?.name} | ` +
+ ': | ' +
+ `${item.quantity} | ` +
+ '
'
+ })
+ output += '
'
+ return output
+ } else {
+ return '-'
+ }
+ },
+ },
+ 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 || '-'
+ // },
+ },
+ components: {
+ action(rec, idx) {
+ const res: RecComponent = {
+ idx,
+ rec: rec as object,
+ component: action,
+ props: {
+ size: 'sm',
+ },
+ }
+ return res
},
}
- // 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
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/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 @@
+
+
+
+
+
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/document-upload/_common/select-doc-type.vue b/app/components/app/document-upload/_common/select-doc-type.vue
new file mode 100644
index 00000000..70f78a7b
--- /dev/null
+++ b/app/components/app/document-upload/_common/select-doc-type.vue
@@ -0,0 +1,71 @@
+
+
+
+
+
+ {{ label }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/components/app/document-upload/entry-form.vue b/app/components/app/document-upload/entry-form.vue
new file mode 100644
index 00000000..f97a5161
--- /dev/null
+++ b/app/components/app/document-upload/entry-form.vue
@@ -0,0 +1,73 @@
+
+
+
+
+
diff --git a/app/components/app/document-upload/list.cfg.ts b/app/components/app/document-upload/list.cfg.ts
new file mode 100644
index 00000000..979c916d
--- /dev/null
+++ b/app/components/app/document-upload/list.cfg.ts
@@ -0,0 +1,43 @@
+import type { Config } from '~/components/pub/my-ui/data-table'
+import { defineAsyncComponent } from 'vue'
+import { docTypeCode, docTypeLabel, type docTypeCodeKey } from '~/lib/constants'
+
+const action = defineAsyncComponent(() => import('~/components/pub/my-ui/data/dropdown-action-dd.vue'))
+
+export const config: Config = {
+ cols: [{}, {}, {}, {width: 50},],
+
+ headers: [
+ [
+ { label: 'Nama Dokumen' },
+ { label: 'Tipe Dokumen' },
+ { label: 'Petugas Upload' },
+ { label: 'Action' },
+ ],
+ ],
+
+ keys: ['fileName', 'type_code', 'employee.name', 'action'],
+
+ delKeyNames: [
+
+ ],
+
+ parses: {
+ type_code: (v: unknown) => {
+ return docTypeLabel[v?.type_code as docTypeCodeKey]
+ },
+ },
+
+ components: {
+ action(rec, idx) {
+ return {
+ idx,
+ rec: rec as object,
+ component: action,
+ }
+ },
+ },
+
+ htmls: {
+ },
+}
diff --git a/app/components/app/document-upload/list.vue b/app/components/app/document-upload/list.vue
new file mode 100644
index 00000000..8274e752
--- /dev/null
+++ b/app/components/app/document-upload/list.vue
@@ -0,0 +1,31 @@
+
+
+
+
+
diff --git a/app/components/app/encounter/entry-form.vue b/app/components/app/encounter/entry-form.vue
index 25bdf9d8..9c24a0c6 100644
--- a/app/components/app/encounter/entry-form.vue
+++ b/app/components/app/encounter/entry-form.vue
@@ -1,354 +1,493 @@
-