diff --git a/P0_log.txt b/P0_log.txt index 42e50cf..ec59040 100644 --- a/P0_log.txt +++ b/P0_log.txt @@ -19,5 +19,41 @@ ('Phlebotomist', 3, 'Pengambilan dan pencatatan spesimen'), ('Customer Service', 4, 'Monitoring & pelayanan informasi pasien'); -2. Tambahkan [USERROLEID] dan [NAME] pada Tabel USERS +2. Hapus semua isi USERS lalu : + INSERT INTO USERS(USERID, [PASSWORD], USERROLEID, NAME) + VALUES + ('LISFSE', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 0, 'SYSTEM'), + ('ABB', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Ardea Bagus Bimantara, S.Tr.Kes'), + ('AHT', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 1, 'dr. Arifoe Hajat, Sp.PK(K)'), + + ('ASW', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Asti Sri Wiyanti, A.Md.AK'), + ('BYS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Betha Yogyanti Setyarini, A.Md.AK'), + + ('FKS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Fairushafa Khairunnisa Sasmita, S.Tr.Kes'), + ('HAY', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Hewi Aryanti, A.Md.Kep'), + + ('KNS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Kartya Nur Sholihatul Umah, S.Kep.Ns'), + ('LPS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Lintang Pramuli Suradi, S.S.T'), + + ('LDK', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Lidya Dwindana Kartikasari, A.Md.Kes'), + + ('RID', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 4, 'Rhemanda Ivena Dinta, A.Md.Bns'), + ('MDW', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Margareta Dwi Widiani, A.Md.Kep'), + ('MJS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Mentari Jaya Sari, A.Md.AK'), + ('MRS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Maria Scholastica, A.Md.Kep'), + + ('AQP', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Anjani Okta Prastiwi, A.Md.Kep'), + + ('RSW', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 0, 'Ratna Setyowati, A.Md.T'), + ('SAI', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 1, 'Sri Andayani, A.Md.Kes'), + ('SFB', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Stevani Florentina Bihi, S.Pd., S.Tr.Kes'), + + ('VSO', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Veronica Sulistyo, A.Md.Kes'), + ('YAA', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 2, 'Yulia Anita, A.Md.Kes'), + ('SYA', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Sutyi Yuliyana, A.Md.Kep'), + + ('MTP', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 0, 'Muhammad Tegar Prasetya, S.Kom'), + ('NRR', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 0, 'Nur Rizky Romadhon, M.Tr.Kom'), + ('LAS', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 3, 'Luthfi Anindyani Sulistiono, S.Kep.Ns'), + ('HSI', '$2y$10$qUKTBKk.gJsgIKKlNB5QwuJ4TFLBl6buARUjaY9eSSmdDX3EO/tSi', 1, 'Dr. dr. Hermi Suprati, M.Kes'); diff --git a/app/Controllers/Cs.php b/app/Controllers/Cs.php index 933a5db..814bbfe 100644 --- a/app/Controllers/Cs.php +++ b/app/Controllers/Cs.php @@ -4,7 +4,7 @@ namespace App\Controllers; use App\Controllers\BaseController; -class Lab extends BaseController { +class Cs extends BaseController { public function __construct() { helper(['url', 'form', 'text']); diff --git a/app/Views/cs/dialog_preview.php b/app/Views/cs/dialog_preview.php new file mode 100644 index 0000000..493d542 --- /dev/null +++ b/app/Views/cs/dialog_preview.php @@ -0,0 +1,54 @@ + + + \ No newline at end of file diff --git a/app/Views/cs/dialog_setPassword.php b/app/Views/cs/dialog_setPassword.php new file mode 100644 index 0000000..623e8b2 --- /dev/null +++ b/app/Views/cs/dialog_setPassword.php @@ -0,0 +1,28 @@ + + + + diff --git a/app/Views/cs/index.php b/app/Views/cs/index.php index ba496df..4dd2e6c 100644 --- a/app/Views/cs/index.php +++ b/app/Views/cs/index.php @@ -1,176 +1,299 @@ extend('cs/main'); ?> section('content') ?> -
-
-
- - -
-
-
-

- Requests Overview -

-
- - -
- - - - - - - -
+
+
+
+ + +
+
+
+

+ Requests Overview +

- -
-
- -
- - - - -
-
- -
- - -
- - - -
-
- - -
-
+ +
+ + + + + + +
+ +
+
+ +
+ + - + +
+
+ +
+ + +
+ + + +
+ +
+
+
+
- +
+ + +
+
+ Showing to + of + entries
+
+ + + +
+
- - include('admin/dialog_sample'); ?> - include('admin/dialog_val'); ?> - include('admin/dialog_unval'); ?> - -
+ + include('cs/dialog_sample'); ?> + include('cs/dialog_unval'); ?> + include('cs/dialog_preview'); ?> + +
endSection(); ?> section('script') ?> - + endSection(); ?> \ No newline at end of file diff --git a/app/Views/cs/main.php b/app/Views/cs/main.php index f9317a8..19f6038 100644 --- a/app/Views/cs/main.php +++ b/app/Views/cs/main.php @@ -1,5 +1,6 @@ + @@ -14,49 +15,82 @@ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; font-size: 0.71rem; } + .navbar { padding: 0.2rem 1rem; min-height: 0rem; } - .card-body { + + .card-body { font-size: 0.71rem !important; - } + } - - + + + renderSection('content'); ?> + include('cs/dialog_setPassword'); ?> + + - - renderSection('content');?> + +
+ + +
+ - - - renderSection('script');?> + renderSection('script'); ?> + \ No newline at end of file diff --git a/app/Views/lab/dialog_preview.php b/app/Views/lab/dialog_preview.php new file mode 100644 index 0000000..493d542 --- /dev/null +++ b/app/Views/lab/dialog_preview.php @@ -0,0 +1,54 @@ + + + \ No newline at end of file diff --git a/app/Views/lab/dialog_setPassword.php b/app/Views/lab/dialog_setPassword.php new file mode 100644 index 0000000..623e8b2 --- /dev/null +++ b/app/Views/lab/dialog_setPassword.php @@ -0,0 +1,28 @@ + + + + diff --git a/app/Views/lab/index.php b/app/Views/lab/index.php index c305629..5daed66 100644 --- a/app/Views/lab/index.php +++ b/app/Views/lab/index.php @@ -74,11 +74,10 @@
-
- - -
+
@@ -97,6 +96,9 @@
+ +
+
@@ -106,12 +108,15 @@
- +
+ +
+
@@ -120,7 +125,7 @@ @@ -191,11 +252,32 @@ + +
+
+ Showing to + of + entries +
+
+ + + +
+
+ - include('admin/dialog_sample'); ?> - include('admin/dialog_val'); ?> - include('admin/dialog_unval'); ?> + include('lab/dialog_sample'); ?> + include('lab/dialog_unval'); ?> + include('lab/dialog_preview'); ?> endSection(); ?> @@ -223,19 +305,65 @@ }, filterTable: "", filterKey: 'Total', + filterKey: 'Total', statusMap: { Total: [], Pend: ['Pend'], Coll: ['Coll', 'PartColl'], - Recv: ['Recv'], + Recv: ['Recv', 'PartRecv'], Inc: ['Inc'], Fin: ['Fin'], }, + // Sorting & Pagination + sortCol: 'REQDATE', + sortAsc: false, + currentPage: 1, + pageSize: 15, + + sort(col) { + if (this.sortCol === col) { + this.sortAsc = !this.sortAsc; + } else { + this.sortCol = col; + this.sortAsc = true; + } + }, + + nextPage() { + if (this.currentPage < this.totalPages) this.currentPage++; + }, + + prevPage() { + if (this.currentPage > 1) this.currentPage--; + }, + + get totalPages() { + return Math.ceil(this.filtered.length / this.pageSize) || 1; + }, + + get sorted() { + return this.filtered.slice().sort((a, b) => { + let modifier = this.sortAsc ? 1 : -1; + if (a[this.sortCol] < b[this.sortCol]) return -1 * modifier; + if (a[this.sortCol] > b[this.sortCol]) return 1 * modifier; + return 0; + }); + }, + + get paginated() { + const start = (this.currentPage - 1) * this.pageSize; + const end = start + this.pageSize; + return this.sorted.slice(start, end); + }, + init() { this.today = new Date().toISOString().slice(0, 10); this.filter.date1 = this.today; this.filter.date2 = this.today; + this.$watch('filterTable', () => { + this.currentPage = 1; + }); this.fetchList(); }, @@ -244,7 +372,6 @@ this.list = []; let statusOrder = { Pend: 1, PartColl: 2, Coll: 3, PartRecv: 4, Recv: 5, Inc: 6, Fin: 7 }; let param = new URLSearchParams(this.filter).toString(); - // reset counters before processing for (let k in this.counters) { this.counters[k] = 0; } fetch(`${BASEURL}/api/requests?${param}`, { method: 'GET', @@ -252,7 +379,6 @@ }).then(res => res.json()).then(data => { this.list = data.data ?? []; this.filterKey = 'Total'; - // count + sort in a single loop this.list.forEach(item => { if (this.counters[item.STATS] !== undefined) { this.counters[item.STATS]++; this.counters.Total++; } else { @@ -281,6 +407,10 @@ return item.ISVAL == 1 && item.ISPENDING != 1; }, get filtered() { + // Reset pagination when filter changes (implied by this getter being accessed if dependencies change) + // However, side-effects in getters are tricky. + // Better to just let the user navigate back, or watch variables. + // For now, let's keep it pure. let filteredList = this.list; if (this.filterKey === 'Validated') { filteredList = filteredList.filter(item => this.isValidated(item)); @@ -365,47 +495,35 @@ }, /* - validate dialog + preview dialog */ - isDialogValOpen: false, - isValidateEnabled: false, - valAccessnumber: null, - openValDialog(accessnumber) { - this.isDialogValOpen = true; - this.valAccessnumber = accessnumber; - this.$nextTick(() => { - // refs will be available after render - const iframe = this.$root.querySelector('#result-iframe') || (this.$refs && this.$refs.resultIframe); - const validateBtn = this.$root.querySelector('#validate-btn') || (this.$refs && this.$refs.validateBtn); - if (!iframe || !validateBtn) return; - - const setup = () => { - try { - const doc = iframe.contentDocument || iframe.contentWindow.document; - const scrollable = doc.documentElement || doc.body; - const checkScroll = () => { - try { - const atBottom = (scrollable.scrollHeight - scrollable.scrollTop - scrollable.clientHeight) < 2; - this.isValidateEnabled = atBottom; - validateBtn.disabled = !atBottom; - } catch (e) { /* cross-origin or not ready */ } - }; - iframe.contentWindow.removeEventListener('scroll', checkScroll); - iframe.contentWindow.addEventListener('scroll', checkScroll); - checkScroll(); - } catch (e) { /* ignore cross-origin */ } - }; - - // If iframe already loaded, setup immediately; otherwise wait for load - if (iframe.contentWindow && (iframe.contentDocument && iframe.contentDocument.readyState === 'complete')) { - setup(); - } else { - iframe.addEventListener('load', setup); - } - }); + isDialogPreviewOpen: false, + reviewed: false, + previewItem: null, + openPreviewDialog(accessnumber, type, item) { + this.previewAccessnumber = accessnumber; + this.previewItem = item; + this.previewType = type; + this.isDialogPreviewOpen = true; + this.reviewed = false; }, - closeValDialog() { - this.isDialogValOpen = false; + closePreviewDialog() { + this.isDialogPreviewOpen = false; + this.previewItem = null; + }, + setPreviewType(type) { + this.previewType = type; + }, + getPreviewUrl() { + let base = 'http://glenlis/spooler_db/main_dev.php'; + let url = `${base}?acc=${this.previewAccessnumber}`; + if (this.previewType === 'ind') url += '&lang=ID'; + if (this.previewType === 'eng') url += '&lang=EN'; + if (this.previewType === 'pdf') url += '&output=pdf'; + + // Keep fallback for local dev if needed, but the above is the expected logic + // return "http://localhost/application.html"; + return url; }, validate(accessnumber, userid) { fetch(`${BASEURL}/api/requests/validate/${accessnumber}`, { @@ -413,9 +531,9 @@ headers: { "Content-Type": "application/json" }, body: JSON.stringify({ userid: `${userid}` }) }).then(response => { - this.closeValDialog(); + this.closePreviewDialog(); this.fetchList(); - console.log('Validate clicked for', this.valAccessnumber, 'by user', userid); + console.log('Validate clicked for', this.previewAccessnumber, 'by user', userid); }); }, @@ -445,7 +563,6 @@ closeUnvalDialog() { this.isDialogUnvalOpen = false; }, - })); }); diff --git a/app/Views/lab/main.php b/app/Views/lab/main.php index e95b31e..2e2c851 100644 --- a/app/Views/lab/main.php +++ b/app/Views/lab/main.php @@ -27,7 +27,7 @@ - +
@@ -59,6 +59,7 @@ renderSection('content'); ?> + include('lab/dialog_setPassword'); ?>
© - 5Panda
@@ -78,7 +79,7 @@
-
  • Set Password
  • +
  • Change Password
  • Logout
  • diff --git a/app/Views/phlebo/dialog_preview.php b/app/Views/phlebo/dialog_preview.php new file mode 100644 index 0000000..493d542 --- /dev/null +++ b/app/Views/phlebo/dialog_preview.php @@ -0,0 +1,54 @@ + + + \ No newline at end of file diff --git a/app/Views/phlebo/dialog_setPassword.php b/app/Views/phlebo/dialog_setPassword.php new file mode 100644 index 0000000..623e8b2 --- /dev/null +++ b/app/Views/phlebo/dialog_setPassword.php @@ -0,0 +1,28 @@ + + + + diff --git a/app/Views/phlebo/index.php b/app/Views/phlebo/index.php index c333baa..521afc8 100644 --- a/app/Views/phlebo/index.php +++ b/app/Views/phlebo/index.php @@ -1,176 +1,299 @@ extend('phlebo/main'); ?> section('content') ?> -
    -
    -
    - - -
    -
    -
    -

    - Requests Overview -

    -
    - - -
    - - - - - - - -
    +
    +
    +
    + + +
    +
    +
    +

    + Requests Overview +

    - -
    -
    - -
    - - - - -
    -
    - -
    - - -
    - - - -
    -
    - - -
    -
    + +
    + + + + + + +
    + +
    +
    + +
    + + - + +
    +
    + +
    + + +
    + + + +
    + +
    +
    +
    +
    - +
    + + +
    +
    + Showing to + of + entries
    +
    + + + +
    +
    - - include('admin/dialog_sample'); ?> - include('admin/dialog_val'); ?> - include('admin/dialog_unval'); ?> - -
    + + include('phlebo/dialog_sample'); ?> + include('phlebo/dialog_unval'); ?> + include('phlebo/dialog_preview'); ?> + +
    endSection(); ?> section('script') ?> - + endSection(); ?> \ No newline at end of file diff --git a/app/Views/phlebo/main.php b/app/Views/phlebo/main.php index a3d7f7d..e012c36 100644 --- a/app/Views/phlebo/main.php +++ b/app/Views/phlebo/main.php @@ -1,5 +1,6 @@ + @@ -14,49 +15,82 @@ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; font-size: 0.71rem; } + .navbar { padding: 0.2rem 1rem; min-height: 0rem; } - .card-body { + + .card-body { font-size: 0.71rem !important; - } + } - - + + + renderSection('content'); ?> + include('phlebo/dialog_setPassword'); ?> + +
    - - renderSection('content');?> + +
    + + +
    + - - - renderSection('script');?> + renderSection('script'); ?> + \ No newline at end of file diff --git a/app/Views/superuser/index.php b/app/Views/superuser/index.php index b00883a..1c6316c 100644 --- a/app/Views/superuser/index.php +++ b/app/Views/superuser/index.php @@ -1,401 +1,571 @@ extend('superuser/main'); ?> section('content') ?> -
    -
    -
    - - -
    -
    -
    -

    - Requests Overview -

    -
    - - -
    - - - - - - - -
    +
    +
    +
    + + +
    +
    +
    +

    + Requests Overview +

    - -
    -
    - -
    - - - - -
    -
    - -
    - - -
    - - - -
    - -
    + +
    + + + + + + +
    -
    - - -