From 35e2c663f53539b8e54e86cede92a4ef15ff2a94 Mon Sep 17 00:00:00 2001 From: Abizrh Date: Thu, 28 Aug 2025 01:18:55 +0700 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat=20(user):=20implement=20user?= =?UTF-8?q?=20management=20feature?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/app/user/entry-form.vue | 42 +++ app/components/app/user/list-cfg.ts | 109 +++++++ app/components/app/user/list.vue | 19 ++ app/components/app/user/picker.vue | 0 app/components/app/user/search.vue | 0 app/components/flow/user/entry.vue | 29 ++ app/components/flow/user/list.vue | 53 ++++ app/lib/constants.ts | 288 ++++++++++-------- app/pages/(features)/human-src/user/add.vue | 41 +++ app/pages/(features)/human-src/user/index.vue | 40 +++ eslint.config.js | 6 +- public/side-menu-items/sys.json | 11 + 12 files changed, 517 insertions(+), 121 deletions(-) create mode 100644 app/components/app/user/entry-form.vue create mode 100644 app/components/app/user/list-cfg.ts create mode 100644 app/components/app/user/list.vue create mode 100644 app/components/app/user/picker.vue create mode 100644 app/components/app/user/search.vue create mode 100644 app/pages/(features)/human-src/user/add.vue create mode 100644 app/pages/(features)/human-src/user/index.vue diff --git a/app/components/app/user/entry-form.vue b/app/components/app/user/entry-form.vue new file mode 100644 index 00000000..20780b27 --- /dev/null +++ b/app/components/app/user/entry-form.vue @@ -0,0 +1,42 @@ + + + diff --git a/app/components/app/user/list-cfg.ts b/app/components/app/user/list-cfg.ts new file mode 100644 index 00000000..f697dc88 --- /dev/null +++ b/app/components/app/user/list-cfg.ts @@ -0,0 +1,109 @@ +import type { + Col, + KeyLabel, + RecComponent, + RecStrFuncComponent, + RecStrFuncUnknown, + Th, +} from '~/components/pub/custom-ui/data/types' +import { defineAsyncComponent } from 'vue' + +type SmallDetailDto = any + +const action = defineAsyncComponent(() => import('~/components/pub/custom-ui/data/dropdown-action-dud.vue')) + +const doctorStatus = { + 0: 'Tidak Aktif', + 1: 'Aktif', +} + +export const cols: Col[] = [ + { width: 100 }, + { width: 250 }, + {}, + { width: 100 }, + { width: 100 }, + {}, + {}, + {}, + { width: 100 }, + { width: 100 }, + { width: 100 }, + { width: 50 }, +] + +export const header: Th[][] = [ + [ + { label: 'Kode JKN' }, + { label: 'Nama' }, + { label: 'No KTP' }, + { label: 'No SIP' }, + { label: 'No IHS' }, + { label: 'Telpon' }, + { label: 'Fee Ranap' }, + { label: 'Fee Rajal' }, + { label: 'Status' }, + ], +] + +export const keys = [ + 'bpjs_code', + 'name', + 'identity_number', + 'sip_no', + 'ihs_number', + 'phone', + 'inPatient_itemPrice', + 'outPatient_itemPrice', + 'status', + 'action', +] + +export const delKeyNames: KeyLabel[] = [ + { key: 'code', label: 'Kode' }, + { key: 'name', label: 'Nama' }, +] + +export const funcParsed: RecStrFuncUnknown = { + name: (rec: unknown): unknown => { + console.log(rec) + const recX = rec as SmallDetailDto + return `${recX.frontTitle} ${recX.name} ${recX.endTitle}`.trim() + }, + identity_number: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + if (recX.identity_number?.substring(0, 5) === 'BLANK') { + return '(TANPA NIK)' + } + return recX.identity_number + }, + inPatient_itemPrice: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return Number(recX.inPatient_itemPrice.price).toLocaleString('id-ID') + }, + outPatient_itemPrice: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return Number(recX.outPatient_itemPrice.price).toLocaleString('id-ID') + }, + status: (rec: unknown): unknown => { + const recX = rec as SmallDetailDto + return doctorStatus[recX.status_code as keyof typeof doctorStatus] + }, +} + +export const funcComponent: RecStrFuncComponent = { + action(rec, idx) { + const res: RecComponent = { + idx, + rec: rec as object, + component: action, + } + return res + }, +} + +export const funcHtml: RecStrFuncUnknown = { + patient_address(_rec) { + return '-' + }, +} diff --git a/app/components/app/user/list.vue b/app/components/app/user/list.vue new file mode 100644 index 00000000..5b8778d9 --- /dev/null +++ b/app/components/app/user/list.vue @@ -0,0 +1,19 @@ + + + diff --git a/app/components/app/user/picker.vue b/app/components/app/user/picker.vue new file mode 100644 index 00000000..e69de29b diff --git a/app/components/app/user/search.vue b/app/components/app/user/search.vue new file mode 100644 index 00000000..e69de29b diff --git a/app/components/flow/user/entry.vue b/app/components/flow/user/entry.vue index e69de29b..49f9e84c 100644 --- a/app/components/flow/user/entry.vue +++ b/app/components/flow/user/entry.vue @@ -0,0 +1,29 @@ + + + diff --git a/app/components/flow/user/list.vue b/app/components/flow/user/list.vue index e69de29b..dda69b73 100644 --- a/app/components/flow/user/list.vue +++ b/app/components/flow/user/list.vue @@ -0,0 +1,53 @@ + + + diff --git a/app/lib/constants.ts b/app/lib/constants.ts index 256bc4ce..fb6b9171 100644 --- a/app/lib/constants.ts +++ b/app/lib/constants.ts @@ -1,170 +1,220 @@ -export interface ActiveStatusCode { - code: 'active' | 'inactive' - name: 'Aktif' | 'Tidak Aktif' +export const activeStatusCodes: Record = { + active: 'Aktif', + inactive: 'Tidak Aktif', } -export interface DataStatusCode { - code: 'new' | 'review' | 'process' | 'done' | 'canceled' | 'rejected' | 'skiped' - name: 'Baru' | 'Review' | 'Proses' | 'Selesai' | 'Dibatalkan' | 'Ditolak' | 'Dilewati' +export const dataStatusCodes: Record = { + new: 'Baru', + review: 'Review', + process: 'Proses', + done: 'Selesai', + canceled: 'Dibatalkan', + rejected: 'Ditolak', + skiped: 'Dilewati', } -export interface UserStatusCode { - code: 'new' | 'active' | 'inactive' | 'blocked' | 'suspended' - name: 'Baru' | 'Aktif' | 'Tidak Aktif' | 'Diblokir' | 'Dibekukan' +export const userStatusCodes: Record = { + new: 'Baru', + active: 'Aktif', + inactive: 'Tidak Aktif', + blocked: 'Diblokir', + suspended: 'Dibekukan', } -export interface ItemGroupCode { - code: 'infra' | 'medicine' | 'device' | 'material' - name: 'Infrastruktur' | 'Obat' | 'Peralatan' | 'Perlengkapan' +export const itemGroupCodes: Record = { + infra: 'Infrastruktur', + medicine: 'Obat', + device: 'Peralatan', + material: 'Perlengkapan', } -export interface UnitTypeCode { - code: 'reg' | 'exa' | 'pay' | 'pha' | 'lab' | 'rad' - name: 'Registrasi' | 'Pemeriksaan' | 'Pembayaran' | 'Farmasai' | 'Laboratorium' | 'Radiologi' +export const unitTypeCodes: Record = { + reg: 'Registrasi', + exa: 'Pemeriksaan', + pay: 'Pembayaran', + pha: 'Farmasai', + lab: 'Laboratorium', + rad: 'Radiologi', } -export interface QueueStatusCode { - code: 'wait' | 'proc' | 'done' | 'cancel' | 'skip' - name: 'Tunggu' | 'Proses' | 'Selesai' | 'Batal' | 'Dilewati' +export const queueStatusCodes: Record = { + wait: 'Tunggu', + proc: 'Proses', + done: 'Selesai', + cancel: 'Batal', + skip: 'Dilewati', } -export interface EncounterClassCode { - code: 'outpatient' | 'ambulatory' | 'emergency' | 'inpatient' | 'draft' | 'done' | 'cancel' | 'skip' - name: 'Rawat Jalan' | 'Rawat Jalan' | 'Gawat Darurat' | 'Rawat Inap' | 'Draft' | 'Selesai' | 'Batal' | 'Dilewati' +export const encounterClassCodes: Record = { + outpatient: 'Rawat Jalan', + ambulatory: 'Rawat Jalan', + emergency: 'Gawat Darurat', + inpatient: 'Rawat Inap', + draft: 'Draft', + done: 'Selesai', + cancel: 'Batal', + skip: 'Dilewati', } -export interface TimeUnitCode { - code: 'sec' | 'min' | 'hour' | 'day' | 'week' | 'month' | 'year' - name: 'Detik' | 'Menit' | 'Jam' | 'Hari' | 'Minggu' | 'Bulan' | 'Tahun' +export const timeUnitCodes: Record = { + sec: 'Detik', + min: 'Menit', + hour: 'Jam', + day: 'Hari', + week: 'Minggu', + month: 'Bulan', + year: 'Tahun', } -export interface DischargeMethodCode { - code: 'home' | 'home-request' - name: 'Home' | 'Home Request' +export const dischargeMethodCodes: Record = { + home: 'Home', + 'home-request': 'Home Request', } -export interface GenderCode { - code: 'male' | 'female' | 'not-stated' | 'unknown' - name: 'Laki' | 'Perempuan' | 'Tidak Disebutkan' | 'Tidak Diketahui' +export const genderCodes: Record = { + male: 'Laki - Laki', + female: 'Perempuan', + 'not-stated': 'Tidak Disebutkan', + unknown: 'Tidak Diketahui', } -export interface ReligionCode { - code: 'islam' | 'protestan' | 'katolik' | 'hindu' | 'buda' | 'konghucu' - name: 'Islam' | 'Protestan' | 'Katolik' | 'Hindu' | 'Buda' | 'Konghucu' +export const religionCodes: Record = { + islam: 'Islam', + protestan: 'Protestan', + katolik: 'Katolik', + hindu: 'Hindu', + buda: 'Buda', + konghucu: 'Konghucu', } -export interface EducationCode { - code: 'TS' | 'TK' | 'SD' | 'SMP' | 'SMA' | 'D1' | 'D2' | 'D3' | 'S1' | 'S2' | 'S3' - name: 'TS' | 'TK' | 'SD' | 'SMP' | 'SMA' | 'D1' | 'D2' | 'D3' | 'S1' | 'S2' | 'S3' +export const educationCodes: Record = { + TS: 'TS', + TK: 'TK', + SD: 'SD', + SMP: 'SMP', + SMA: 'SMA', + D1: 'D1', + D2: 'D2', + D3: 'D3', + S1: 'S1', + S2: 'S2', + S3: 'S3', } -export interface OccupationCode { - code: 'tidak-bekerja' | 'pns' | 'polisi' | 'tni' | 'guru' | 'wiraswasta' | 'kary-swasta' | 'lainnya' - name: - | 'Tidak Bekerja' - | 'Pegawai Negeri Sipil' - | 'Polisi' - | 'TNI' - | 'Guru' - | 'Wiraswasta' - | 'Karyawan Swasta' - | 'Lainnya' +export const occupationCodes: Record = { + 'tidak-bekerja': 'Tidak Bekerja', + pns: 'Pegawai Negeri Sipil', + polisi: 'Polisi', + tni: 'TNI', + guru: 'Guru', + wiraswasta: 'Wiraswasta', + 'kary-swasta': 'Karyawan Swasta', + lainnya: 'Lainnya', } -export interface PersonContactType { - code: 'phone' | 'm-phone' | 'email' | 'fax' - name: 'Telepon' | 'HP / Ponsel' | 'Email' | 'Fax' +export const personContactTypes: Record = { + phone: 'Telepon', + 'm-phone': 'HP / Ponsel', + email: 'Email', + fax: 'Fax', } -export interface DayCode { - code: '0' | '1' | '2' | '3' | '4' | '5' | '6' - name: 'Minggu' | '' | '' | '' | '' | '' | 'Sabtu' +export const dayCodes: Record = { + '0': 'Minggu', + '1': '', + '2': '', + '3': '', + '4': '', + '5': '', + '6': 'Sabtu', } -export interface PaymentMethodCode { - code: 'cash' | 'debit' | 'credit' | 'insurance' | 'membership' - name: 'Cash' | 'Debit' | 'Kredit' | 'Asuransi' | 'Membership' +export const paymentMethodCodes: Record = { + cash: 'Cash', + debit: 'Debit', + credit: 'Kredit', + insurance: 'Asuransi', + membership: 'Membership', } -export interface TransportationCode { - code: 'ambulance' | 'car' | 'motor-cycle' | 'other' - name: 'Ambulans' | 'Mobil' | 'Motor' | 'Lainnya' +export const transportationCodes: Record = { + ambulance: 'Ambulans', + car: 'Mobil', + 'motor-cycle': 'Motor', + other: 'Lainnya', } -export interface PersonConditionCode { - code: 'res' | 'emg' | 'urg' | 'lurg' | 'nurg' | 'doa' - name: 'Resutiasi' | 'Darurat' | 'Mendesak' | 'Kurang Mendesak' | 'Mendesak' | 'Meninggal Saat Tiba' +export const personConditionCodes: Record = { + res: 'Resutiasi', + emg: 'Darurat', + urg: 'Mendesak', + lurg: 'Kurang Mendesak', + nurg: 'Mendesak', + doa: 'Meninggal Saat Tiba', } -export interface EmergencyClassCode { - code: 'emg' | 'eon' - name: 'Darurat' | 'Ponek' +export const emergencyClassCodes: Record = { + emg: 'Darurat', + eon: 'Ponek', } -export interface OutpatientClassCode { - code: 'op' | 'icu' | 'hcu' | 'vk' - name: 'Rawat Inap' | 'ICU' | 'HCU' | 'Kamar Bersalin' +export const outpatientClassCodes: Record = { + op: 'Rawat Inap', + icu: 'ICU', + hcu: 'HCU', + vk: 'Kamar Bersalin', } -export interface CheckupScopeCode { - code: 'lab' | 'mic-lab' | 'pa-lab' | 'rad' - name: 'Laboratorium' | 'Microbacterial Laboratorium' | 'Patology Anatomy Laboratorium' | 'Radiology' +export const checkupScopeCodes: Record = { + lab: 'Laboratorium', + 'mic-lab': 'Microbacterial Laboratorium', + 'pa-lab': 'Patology Anatomy Laboratorium', + rad: 'Radiology', } -export interface EmployeePositionCode { - code: 'doctor' | 'nurse' | 'nutritionist' | 'laborant' | 'pharmacy' | 'payment' | 'payment-verificator' | 'management' - name: - | 'Dokter' - | 'Perawat' - | 'Ahli Gisi' - | 'Laboran' - | 'Farmasi' - | 'Pembayaran' - | 'Konfirmasi Pembayaran' - | 'Management' +export const employeePositionCodes: Record = { + doctor: 'Dokter', + nurse: 'Perawat', + nutritionist: 'Ahli Gisi', + laborant: 'Laboran', + pharmacy: 'Farmasi', + payment: 'Pembayaran', + 'payment-verificator': 'Konfirmasi Pembayaran', + management: 'Management', } -export interface SubjectCode { - code: - | 'pri-compl' - | 'sec-compl' - | 'cur-disea-hist' - | 'pas-disea-hist' - | 'fam-disea-hist' - | 'alg-hist' - | 'alg-react' - | 'med-hist' - name: - | 'Primary Complaint' - | 'Secondary Complaint' - | 'Current Disease History' - | 'Past Disease History' - | 'Family Disease History' - | 'Allergic Hist' - | 'Allergic Reaction' - | 'Medication Hist' +export const subjectCodes: Record = { + 'pri-compl': 'Primary Complaint', + 'sec-compl': 'Secondary Complaint', + 'cur-disea-hist': 'Current Disease History', + 'pas-disea-hist': 'Past Disease History', + 'fam-disea-hist': 'Family Disease History', + 'alg-hist': 'Allergic Hist', + 'alg-react': 'Allergic Reaction', + 'med-hist': 'Medication Hist', } -export interface ObjectCode { - code: 'consc-level' | 'consc-level-det' | 'syst-bp' | 'diast-bp' | 'hear-rt' | 'temp' | 'spo2' | 'weight' | 'height' - name: - | 'Tingkat Kesadaran' - | 'Detail Tingkat Kesadaran' - | 'Tekanan Darah Systolic' - | 'Tekanan Darah Diastolic' - | 'Detak Jantung' - | 'Suhu' - | 'SpO2' - | 'Berat Badan' - | 'Tinggi Badan' +export const objectCodes: Record = { + 'consc-level': 'Tingkat Kesadaran', + 'consc-level-det': 'Detail Tingkat Kesadaran', + 'syst-bp': 'Tekanan Darah Systolic', + 'diast-bp': 'Tekanan Darah Diastolic', + 'hear-rt': 'Detak Jantung', + temp: 'Suhu', + spo2: 'SpO2', + weight: 'Berat Badan', + height: 'Tinggi Badan', } -export interface AssessmentCode { - code: 'early-diag' | 'late-diag' | 'sec-diag' - name: 'Diagnosis Awal' | 'Diagnosis Akhir' | 'Diagnosis Sekunder' +export const assessmentCodes: Record = { + 'early-diag': 'Diagnosis Awal', + 'late-diag': 'Diagnosis Akhir', + 'sec-diag': 'Diagnosis Sekunder', } -export interface InstructionCode { - code: 'detail' | 'med-act' | 'medication' | 'material' - name: 'Detail Instruksi' | 'Tindakan medis' | 'Obat' | 'BMHP' +export const instructionCodes: Record = { + detail: 'Detail Instruksi', + 'med-act': 'Tindakan medis', + medication: 'Obat', + material: 'BMHP', } diff --git a/app/pages/(features)/human-src/user/add.vue b/app/pages/(features)/human-src/user/add.vue new file mode 100644 index 00000000..39ba8791 --- /dev/null +++ b/app/pages/(features)/human-src/user/add.vue @@ -0,0 +1,41 @@ + + + diff --git a/app/pages/(features)/human-src/user/index.vue b/app/pages/(features)/human-src/user/index.vue new file mode 100644 index 00000000..2c0f921f --- /dev/null +++ b/app/pages/(features)/human-src/user/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/eslint.config.js b/eslint.config.js index 4879bee5..46987ead 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -10,6 +10,7 @@ export default withNuxt( stylistic: { semi: false, quotes: 'single', + quoteProps: 'as-needed', // Less strict formatting jsx: false, trailingComma: 'all', @@ -18,14 +19,15 @@ export default withNuxt( { rules: { // Basic rules - 'quotes': ['error', 'single', { avoidEscape: true }], + quotes: ['error', 'single', { avoidEscape: true }], + 'style/quote-props': 'off', 'style/no-trailing-spaces': ['error', { ignoreComments: true }], 'no-console': 'off', // Relax strict formatting rules 'style/brace-style': 'off', // Allow inline if - 'curly': ['error', 'multi-line'], // Only require braces for multi-line + curly: ['error', 'multi-line'], // Only require braces for multi-line 'style/arrow-parens': 'off', // UnoCSS - make it warning instead of error, or disable completely diff --git a/public/side-menu-items/sys.json b/public/side-menu-items/sys.json index 18bbd3dc..2b803fc0 100644 --- a/public/side-menu-items/sys.json +++ b/public/side-menu-items/sys.json @@ -30,6 +30,17 @@ } ] }, + { + "title": "Karyawan", + "icon": "i-lucide-users", + "children": [ + { + "title": "User", + "icon": "i-lucide-user", + "link": "/human-src/user" + } + ] + }, { "title": "Dokter", "icon": "i-lucide-cross",