Files

2853 lines
44 KiB
HTML

<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SIJAGAD RSSA | Dashboard Hotline</title>
</head>
<style>
/* ===================================================
SIJAGAD RSSA
Dashboard Hotline
Part 3A
=================================================== */
/* ================= RESET ================= */
*{
margin:0;
padding:0;
box-sizing:border-box;
font-family:"Segoe UI",Tahoma,Geneva,Verdana,sans-serif;
}
html{
scroll-behavior:smooth;
}
body{
background:#f4f6f9;
color:#333;
min-height:100vh;
}
/*==================================================
HEADER GODMODE
==================================================*/
.header{
position:sticky;
top:0;
z-index:999;
display:flex;
justify-content:space-between;
align-items:center;
padding:15px 30px;
background:linear-gradient(
135deg,
#0D47A1,
#1565C0,
#1976D2
);
color:#fff;
box-shadow:0 10px 25px rgba(0,0,0,.18);
}
/*================ LEFT ================*/
.header-left{
display:flex;
align-items:center;
gap:18px;
}
.logo-icon{
width:70px;
height:70px;
display:flex;
justify-content:center;
align-items:center;
overflow:hidden;
animation:pulseLogo 3s infinite;
}
.logo-icon img{
width:100%;
height:100%;
object-fit:contain;
user-select:none;
-webkit-user-drag:none;
}
.logo h1{
font-size:30px;
letter-spacing:1px;
}
.logo span{
opacity:.9;
font-size:14px;
}
.logo{
display:flex;
flex-direction:column;
}
.marquee{
overflow:hidden;
white-space:nowrap;
width:100%;
margin-top:4px;
}
.marquee span{
display:inline-block;
padding-left:100%;
animation:marqueeMove 12s linear infinite;
font-size:24px;
color:rgba(255,255,255,.9);
letter-spacing:.5px;
}
/* animasi jalan */
@keyframes marqueeMove{
0%{
transform:translateX(0);
}
100%{
transform:translateX(-100%);
}
}
/*================ CENTER ================*/
.system-status{
display:flex;
align-items:center;
gap:10px;
padding:10px 18px;
border-radius:30px;
background:rgba(255,255,255,.12);
backdrop-filter:blur(12px);
font-weight:600;
}
.status-dot{
width:12px;
height:12px;
background:#00ff6a;
border-radius:50%;
animation:online 1.2s infinite;
}
/*================ RIGHT ================*/
.header-right{
display:flex;
gap:15px;
}
.operator-card,
.datetime-card{
min-width:200px;
padding:15px 18px;
border-radius:15px;
background:rgba(255,255,255,.15);
backdrop-filter:blur(15px);
transition:.3s;
}
.operator-card:hover,
.datetime-card:hover{
transform:translateY(-3px);
}
.operator-card .title{
font-size:13px;
opacity:.85;
}
.operator-card .value{
margin-top:6px;
font-size:18px;
font-weight:bold;
}
.date{
font-size:13px;
}
.clock{
font-size:34px;
font-weight:bold;
letter-spacing:2px;
}
.shift{
margin-top:5px;
color:#FFE082;
font-weight:bold;
}
/*================ ANIMATION ================*/
@keyframes pulseLogo{
0%{
transform:scale(1);
box-shadow:0 0 0 rgba(255,255,255,.2);
}
50%{
transform:scale(1.08);
box-shadow:0 0 25px rgba(255,255,255,.35);
}
100%{
transform:scale(1);
box-shadow:0 0 0 rgba(255,255,255,.2);
}
}
@keyframes online{
0%{
opacity:1;
transform:scale(1);
}
50%{
opacity:.3;
transform:scale(1.5);
}
100%{
opacity:1;
transform:scale(1);
}
}
/*================ RESPONSIVE ================*/
@media(max-width:992px){
.header{
flex-direction:column;
gap:15px;
}
.header-right{
width:100%;
justify-content:center;
flex-wrap:wrap;
}
.system-status{
margin:10px 0;
}
}
@media(max-width:600px){
.logo h1{
font-size:22px;
}
.clock{
font-size:26px;
}
.operator-card,
.datetime-card{
width:100%;
}
}
/* ================= CONTAINER ================= */
.container{
padding:25px;
}
/* ================= CARDS ================= */
.cards{
display:grid;
grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
gap:20px;
margin-bottom:25px;
}
.card{
background:#fff;
border-radius:14px;
padding:20px;
box-shadow:0 5px 15px rgba(0,0,0,.08);
transition:.3s;
border-left:6px solid #1565C0;
}
.card:hover{
transform:translateY(-5px);
box-shadow:0 10px 25px rgba(0,0,0,.12);
}
.card h4{
color:#666;
font-size:14px;
margin-bottom:10px;
font-weight:600;
}
.card h2{
font-size:32px;
color:#1565C0;
font-weight:bold;
}
/* ================= WARNA CARD ================= */
.emergency-card{
border-left-color:#e53935;
}
.emergency-card h2{
color:#e53935;
}
.fasttrack-card{
border-left-color:#fb8c00;
}
.fasttrack-card h2{
color:#fb8c00;
}
.elektif-card{
border-left-color:#43a047;
}
.elektif-card h2{
color:#43a047;
}
.selesai-card{
border-left-color:#3949ab;
}
.selesai-card h2{
color:#3949ab;
}
/* ===================================================
SIJAGAD RSSA
Dashboard Hotline
Part 3B
Toolbar • Table • Badge • Button
===================================================*/
/* ================= TOOLBAR ================= */
.toolbar{
display:flex;
align-items:center;
justify-content:space-between;
gap:15px;
margin-bottom:20px;
flex-wrap:wrap;
}
.toolbar input{
flex:1;
min-width:280px;
height:45px;
padding:0 15px;
border:1px solid #dcdcdc;
border-radius:8px;
background:#fff;
font-size:14px;
outline:none;
transition:.3s;
}
.toolbar input:focus{
border-color:#1565C0;
box-shadow:0 0 8px rgba(21,101,192,.2);
}
.toolbar select{
min-width:190px;
height:45px;
padding:0 15px;
border:1px solid #dcdcdc;
border-radius:8px;
background:#fff;
font-size:14px;
cursor:pointer;
outline:none;
}
.toolbar select:focus{
border-color:#1565C0;
box-shadow:0 0 8px rgba(21,101,192,.2);
}
.toolbar .btn-primary{
height:45px;
white-space:nowrap;
}
/* ================= BUTTON ================= */
.btn-primary{
background:#1565C0;
color:#fff;
border:none;
border-radius:8px;
padding:11px 20px;
cursor:pointer;
font-size:14px;
font-weight:600;
transition:.3s;
}
.btn-primary:hover{
background:#0D47A1;
}
.btn-secondary{
background:#757575;
color:#fff;
border:none;
border-radius:8px;
padding:11px 20px;
cursor:pointer;
transition:.3s;
}
.btn-secondary:hover{
background:#616161;
}
.btn-delete{
background:#D32F2F;
color:#fff;
border:none;
border-radius:6px;
padding:7px 12px;
cursor:pointer;
font-size:12px;
transition:.3s;
}
.btn-delete:hover{
background:#B71C1C;
}
.btn-timeline{
background:#5E35B1;
color:white;
border:none;
border-radius:6px;
padding:6px 12px;
cursor:pointer;
font-size:12px;
transition:.3s;
}
.btn-timeline:hover{
background:#4527A0;
}
.timeline-link{
color:#1565C0;
font-weight:bold;
cursor:pointer;
text-decoration:none;
}
.timeline-link:hover{
text-decoration:underline;
}
/* ================= TABLE ================= */
.table-responsive{
background:#fff;
border-radius:12px;
overflow:hidden;
box-shadow:0 5px 15px rgba(0,0,0,.08);
}
table{
width:100%;
border-collapse:collapse;
}
thead{
background:#1565C0;
color:#fff;
}
thead th{
padding:14px;
font-size:14px;
text-align:center;
white-space:nowrap;
}
tbody td{
padding:14px;
border-bottom:1px solid #ececec;
text-align:center;
font-size:14px;
}
tbody tr{
transition:.2s;
}
tbody tr:hover{
background:#f8fbff;
}
.empty-data{
padding:50px 20px;
text-align:center;
color:#888;
}
.empty-data h3{
margin-bottom:10px;
}
/* ================= BADGE PRIORITAS ================= */
.badge{
display:inline-block;
padding:6px 12px;
border-radius:20px;
color:#fff;
font-size:12px;
font-weight:600;
}
.badge-emergency{
background:#E53935;
}
.badge-fasttrack{
background:#FB8C00;
}
.badge-elektif{
background:#43A047;
}
/* ================= BADGE STATUS ================= */
.status{
display:inline-block;
padding:6px 12px;
border-radius:20px;
color:#fff;
font-size:12px;
font-weight:600;
}
.status-proses{
background:#FFA000;
}
.status-diterima{
background:#2E7D32;
}
.status-ditolak{
background:#D32F2F;
}
.status-ditunda{
background:#757575;
}
.status-dibatalkan{
background:#6D4C41;
}
.status-selesai{
background:#1565C0;
}
/* ================= TOMBOL AKSI ================= */
.action{
display:flex;
justify-content:center;
gap:6px;
flex-wrap:wrap;
}
.btn-detail{
background:#1976D2;
color:#fff;
border:none;
border-radius:6px;
padding:7px 12px;
cursor:pointer;
font-size:12px;
}
.btn-edit{
background:#FB8C00;
color:#fff;
border:none;
border-radius:6px;
padding:7px 12px;
cursor:pointer;
font-size:12px;
}
.btn-delete{
background:#D32F2F;
color:#fff;
border:none;
border-radius:6px;
padding:7px 12px;
cursor:pointer;
font-size:12px;
}
.btn-finish{
background:#2E7D32;
color:#fff;
border:none;
border-radius:6px;
padding:7px 12px;
cursor:pointer;
font-size:12px;
}
.btn-detail:hover,
.btn-edit:hover,
.btn-delete:hover,
.btn-finish:hover{
opacity:.85;
transform:translateY(-1px);
}
/* ===================================================
SIJAGAD RSSA
Dashboard Hotline
Part 3C
Modal • Form • Timeline • Responsive
===================================================*/
/* ================= MODAL ================= */
.modal{
display:none;
position:fixed;
inset:0;
background:rgba(0,0,0,.45);
z-index:999;
overflow:auto;
animation:fadeIn .25s;
}
@keyframes fadeIn{
from{opacity:0;}
to{opacity:1;}
}
.modal-content{
width:900px;
max-width:95%;
background:#fff;
margin:40px auto;
border-radius:12px;
overflow:hidden;
animation:zoomIn .25s;
}
@keyframes zoomIn{
from{
transform:scale(.95);
opacity:0;
}
to{
transform:scale(1);
opacity:1;
}
}
.modal-header{
background:#1565C0;
color:#fff;
padding:16px 22px;
display:flex;
justify-content:space-between;
align-items:center;
}
.modal-header h2{
font-size:20px;
}
.close{
font-size:28px;
cursor:pointer;
transition:.2s;
}
.close:hover{
transform:rotate(90deg);
}
/* ================= FORM ================= */
form{
padding:25px;
}
.grid{
display:grid;
grid-template-columns:repeat(2,1fr);
gap:18px;
}
.form-group{
display:flex;
flex-direction:column;
}
.form-group label{
margin-bottom:6px;
font-size:14px;
font-weight:600;
color:#444;
}
.form-group input,
.form-group select,
.form-group textarea{
padding:11px 12px;
border:1px solid #d6d6d6;
border-radius:8px;
outline:none;
transition:.3s;
font-size:14px;
}
.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus{
border-color:#1565C0;
box-shadow:0 0 8px rgba(21,101,192,.15);
}
textarea{
resize:vertical;
min-height:90px;
}
.footer-modal{
display:flex;
justify-content:flex-end;
gap:10px;
margin-top:25px;
}
/* ================= DETAIL ================= */
.modal-detail{
width:700px;
}
.detail-body{
padding:25px;
}
.detail-info{
display:grid;
grid-template-columns:repeat(3,1fr);
gap:15px;
margin-bottom:20px;
}
/* ================= TIMELINE ================= */
.timeline{
position:relative;
margin-top:20px;
padding-left:35px;
}
.timeline::before{
content:"";
position:absolute;
left:12px;
top:0;
width:3px;
height:100%;
background:#1565C0;
}
.timeline-item{
position:relative;
margin-bottom:28px;
}
.timeline-item:last-child{
margin-bottom:0;
}
.timeline-dot{
position:absolute;
left:-30px;
width:18px;
height:18px;
border-radius:50%;
background:#1565C0;
border:3px solid #fff;
box-shadow:0 0 0 2px #1565C0;
}
.timeline-content{
background:#f8f9fb;
border-radius:8px;
padding:14px;
border-left:4px solid #1565C0;
}
.timeline-content h4{
color:#1565C0;
margin-bottom:5px;
}
.timeline-content p{
color:#666;
font-size:13px;
margin-top:3px;
}
/* ================= SCROLL ================= */
::-webkit-scrollbar{
width:8px;
height:8px;
}
::-webkit-scrollbar-thumb{
background:#1565C0;
border-radius:20px;
}
::-webkit-scrollbar-track{
background:#ececec;
}
/* ================= RESPONSIVE ================= */
@media(max-width:992px){
.grid{
grid-template-columns:1fr;
}
.detail-info{
grid-template-columns:1fr;
}
}
@media(max-width:768px){
.header{
flex-direction:column;
height:auto;
gap:12px;
padding:18px;
text-align:center;
}
.toolbar{
flex-direction:column;
align-items:stretch;
}
.toolbar input{
width:100%;
}
.cards{
grid-template-columns:repeat(2,1fr);
}
table{
min-width:1200px;
}
}
@media(max-width:480px){
.cards{
grid-template-columns:1fr;
}
.modal-content{
width:96%;
margin:15px auto;
}
.footer-modal{
flex-direction:column;
}
.footer-modal button{
width:100%;
}
}
/* ================= HEADER INFO ================= */
.header-info{
display:flex;
gap:15px;
align-items:center;
flex-wrap:wrap;
}
.operator-card,
.datetime-card{
background:rgba(255,255,255,.15);
padding:12px 18px;
border-radius:12px;
color:white;
backdrop-filter:blur(10px);
min-width:180px;
}
.datetime-card{
text-align:right;
}
#liveClock{
font-size:24px;
font-weight:bold;
}
#liveShift{
margin-top:5px;
color:#ffe082;
font-weight:bold;
}
</style>
<body>
<!-- ================= HEADER ================= -->
<header class="header">
<div class="header-left">
<div class="logo-icon">
<img src="https://yt3.googleusercontent.com/ytc/AIdro_nGlzE8gWzWR7YoAYcq2TanbSHNTgFOAmsdluOTxMbL86o=s160-c-k-c0x00ffffff-no-rj" alt="Logo RSSA">
</div>
<div class="logo">
<h1>SIJAGAD RSSA</h1>
<div class="marquee">
<span>Sistem Jaringan Akses Gawat Darurat • RSUD Dr. Saiful Anwar • Hotline Rujukan 24 Jam •</span>
</div>
</div>
</div>
<div class="header-center">
<div class="system-status">
<span class="status-dot"></span>
<span>Sistem Online</span>
</div>
</div>
<div class="header-right">
<div class="operator-card">
<div class="title">
👨‍⚕️ Operator
</div>
<div class="value">
Admin Hotline
</div>
</div>
<div class="datetime-card">
<div id="liveDate" class="date"></div>
<div id="liveClock" class="clock"></div>
<div id="liveShift" class="shift"></div>
</div>
</div>
</header>
<!-- ================= CONTENT ================= -->
<div class="container">
<!-- ================= DASHBOARD ================= -->
<div class="cards">
<div class="card">
<h4>Total Tiket</h4>
<h2 id="totalTiket">0</h2>
</div>
<div class="card emergency-card">
<h4>Emergency</h4>
<h2 id="totalEmergency">0</h2>
</div>
<div class="card fasttrack-card">
<h4>Fasttrack</h4>
<h2 id="totalFasttrack">0</h2>
</div>
<div class="card elektif-card">
<h4>Elektif</h4>
<h2 id="totalElektif">0</h2>
</div>
<div class="card selesai-card">
<h4>Selesai</h4>
<h2 id="totalSelesai">0</h2>
</div>
</div>
<!-- ================= TOOLBAR ================= -->
<div class="toolbar">
<input
type="text"
id="search"
placeholder="🔍 Cari Nomor Tiket / Nama Pasien...">
<select id="filterPeriode">
<option value="all">📋 Semua Data</option>
<option value="today">📅 Hari Ini</option>
<option value="week">🗓 Minggu Ini</option>
<option value="month">📆 Bulan Ini</option>
<option value="year">🗂 Tahun Ini</option>
</select>
<button
class="btn-primary"
onclick="openModal()">
+ Tiket Baru
</button>
</div>
<!-- ================= TABEL ================= -->
<div class="table-responsive">
<table>
<thead>
<tr>
<th>No. Tiket</th>
<th>Nama Pasien</th>
<th>Asal Faskes</th>
<th>Lama Perawatan</th>
<th>Prioritas</th>
<th>Dokter Perujuk</th>
<th>SMF DPJP</th>
<th>Status Rujukan</th>
<th>Tujuan IGD</th>
<th>Waktu Proses</th>
<th>Keterangan Status</th>
<th>Aksi</th>
</tr>
</thead>
<tbody id="tableBody">
<!--
Data akan ditambahkan oleh JavaScript
Contoh:
HT202606290001
-->
</tbody>
</table>
<div class="empty-data" id="emptyData">
<h3>Belum ada data Hotline.</h3>
<p>Silakan klik <b>+ Tiket Baru</b> untuk membuat tiket pertama.</p>
</div>
</div>
</div>
<!-- ================= MODAL INPUT TIKET ================= -->
<div id="modalInput" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2>Input Hotline Rujukan</h2>
<span class="close" onclick="closeModal()">&times;</span>
</div>
<form id="formHotline">
<div class="grid">
<div class="form-group">
<label>Nomor Tiket</label>
<input
type="text"
id="nomorTiket"
readonly
placeholder="Otomatis">
</div>
<div class="form-group">
<label>Nama Pasien</label>
<input
type="text"
id="namaPasien"
required>
</div>
<div class="form-group">
<label>Asal Faskes</label>
<input
type="text"
id="asalFaskes"
required>
</div>
<div class="form-group">
<label>Lama Perawatan</label>
<input
type="text"
id="lamaPerawatan"
placeholder="Contoh : 2 Hari">
</div>
<div class="form-group">
<label>Prioritas</label>
<select id="prioritas">
<option value="">-- Pilih Prioritas --</option>
<option value="Emergency">
Emergency
</option>
<option value="Fasttrack">
Fasttrack
</option>
<option value="Elektif">
Elektif
</option>
</select>
</div>
<div class="form-group">
<label>Dokter Perujuk</label>
<input
type="text"
id="dokterPerujuk"
placeholder="Nama Dokter Perujuk">
</div>
<div class="form-group">
<label>SMF DPJP RSSA</label>
<input
type="text"
id="dpjp"
placeholder="SMF DPJP">
</div>
<div class="form-group">
<label>Status Rujukan</label>
<select id="statusRujukan">
<option value="Proses Penapisan">
Proses Penapisan
</option>
<option value="Diterima">
Diterima
</option>
<option value="Ditolak">
Ditolak
</option>
<option value="Ditunda">
Ditunda
</option>
<option value="Dibatalkan">
Dibatalkan
</option>
<option value="Selesai">
Selesai
</option>
</select>
</div>
<div class="form-group">
<label>Tujuan IGD</label>
<select id="tujuanIGD">
<option value="----">----</option>
<option value="IGD Reguler">IGD Reguler</option>
<option value="IGD Infeksi">IGD Infeksi</option>
<option value="Fasttrack">Fasttrack</option>
</select>
</div>
<div class="form-group">
<label>Waktu Proses</label>
<input
type="text"
id="waktuProses"
readonly
placeholder="Timeline Otomatis">
</div>
</div>
<div class="form-group">
<label>Keterangan Status Rujukan</label>
<textarea
id="keterangan"
rows="4"
placeholder="Masukkan keterangan..."></textarea>
</div>
<div class="footer-modal">
<button
type="button"
class="btn-secondary"
onclick="closeModal()">
Batal
</button>
<button
type="submit"
class="btn-primary">
Simpan Tiket
</button>
</div>
</form>
</div>
</div>
<!-- ================= MODAL DETAIL ================= -->
<div id="modalDetail" class="modal">
<div class="modal-content modal-detail">
<div class="modal-header">
<h2>📋 Timeline Proses Rujukan</h2>
<span class="close" onclick="closeDetail()">&times;</span>
</div>
<div class="detail-body">
<!-- ================= INFORMASI TIKET ================= -->
<div class="detail-info">
<div><b>Nomor Tiket :</b> <span id="detailNomor"></span></div>
<div><b>Pasien :</b> <span id="detailPasien"></span></div>
<div><b>Dokter Perujuk :</b> <span id="detailDokterPerujuk"></span></div>
<div><b>DPJP RSSA :</b> <span id="detailDPJP"></span></div>
<div><b>Status :</b> <span id="detailStatus"></span></div>
<div><b>Tujuan IGD :</b> <span id="detailTujuanIGD"></span></div>
</div>
<hr style="margin:20px 0;">
<h3 style="margin-bottom:15px;color:#1565C0;">
Riwayat Penanganan Tiket
</h3>
<!-- ================= TIMELINE ================= -->
<div id="timelineContainer" class="timeline">
<!-- Timeline otomatis dari JavaScript -->
<!--
🟢 Tiket Dibuat
🟡 Proses Penapisan
🔵 Menunggu DPJP
🟢 Diterima
🟠 Ditunda
🔴 Ditolak
⚫ Dibatalkan
✅ Selesai
-->
</div>
<div class="footer-modal">
<button
class="btn-primary"
onclick="printTimeline()">
🖨 Cetak Timeline
</button>
<button
class="btn-secondary"
onclick="closeDetail()">
Tutup
</button>
</div>
</div>
</div>
</div>
<!-- ================= JAVASCRIPT ================= -->
<script>
/*=========================================================
SIJAGAD RSSA
Dashboard Hotline
script.js
PART 4A
=========================================================*/
/* ================= DATA ================= */
let daftarTiket = [];
let editIndex = -1;
let detailIndex = -1;
/* ================= ELEMENT ================= */
const modalInput = document.getElementById("modalInput");
const modalDetail = document.getElementById("modalDetail");
const formHotline = document.getElementById("formHotline");
const nomorTiket = document.getElementById("nomorTiket");
const namaPasien = document.getElementById("namaPasien");
const asalFaskes = document.getElementById("asalFaskes");
const lamaPerawatan = document.getElementById("lamaPerawatan");
const prioritas = document.getElementById("prioritas");
const dokterPerujuk = document.getElementById("dokterPerujuk");
const dpjp = document.getElementById("dpjp");
const statusRujukan = document.getElementById("statusRujukan");
const tujuanIGD = document.getElementById("tujuanIGD");
const waktuProses = document.getElementById("waktuProses");
const keterangan = document.getElementById("keterangan");
/* ================= MODAL ================= */
function openModal(){
modalInput.style.display = "block";
if(editIndex === -1){
nomorTiket.value = generateNomorTiket();
waktuProses.value = "Dimulai : " + getTanggalJam();
}
}
function closeModal(){
modalInput.style.display = "none";
formHotline.reset();
editIndex = -1;
}
function openDetail(){
modalDetail.style.display = "block";
}
function closeDetail(){
modalDetail.style.display = "none";
}
/* ================= KLIK DI LUAR MODAL ================= */
window.onclick = function(e){
if(e.target === modalInput){
closeModal();
}
if(e.target === modalDetail){
closeDetail();
}
}
/* ================= GENERATE NOMOR TIKET ================= */
function generateNomorTiket(){
const sekarang = new Date();
const tahun = sekarang.getFullYear();
const bulan = String(sekarang.getMonth()+1).padStart(2,'0');
const tanggal = String(sekarang.getDate()).padStart(2,'0');
const urut = String(daftarTiket.length + 1).padStart(4,'0');
return "HOT" + tahun + bulan + tanggal + urut;
}
/* ================= ID INTERNAL ================= */
function generateID(){
return Date.now();
}
/* ================= FORMAT TANGGAL ================= */
function getTanggalJam(){
const sekarang = new Date();
return sekarang.toLocaleString("id-ID",{
day:"2-digit",
month:"2-digit",
year:"numeric",
hour:"2-digit",
minute:"2-digit",
second:"2-digit"
});
}
/* ================= FORMAT DURASI ================= */
function formatDurasi(ms){
const detik = Math.floor(ms / 1000);
const jam = Math.floor(detik / 3600);
const menit = Math.floor((detik % 3600)/60);
const sisa = detik % 60;
return jam + " Jam "
+ menit + " Menit "
+ sisa + " Detik";
}
/* ================= INIT ================= */
document.addEventListener("DOMContentLoaded",function(){
nomorTiket.value = generateNomorTiket();
});
/*=========================================================
SIJAGAD RSSA
Dashboard Hotline
PART 4B
=========================================================*/
/* ================= SIMPAN DATA ================= */
formHotline.addEventListener("submit", function (e) {
e.preventDefault();
const tiket = {
id: editIndex === -1 ? generateID() : daftarTiket[editIndex].id,
nomor: nomorTiket.value,
pasien: namaPasien.value,
faskes: asalFaskes.value,
lama: lamaPerawatan.value,
prioritas: prioritas.value,
dokterPerujuk: dokterPerujuk.value,
dpjp: dpjp.value,
status: statusRujukan.value,
tujuanIGD: tujuanIGD.value,
tanggal: editIndex === -1
? new Date().toISOString()
: daftarTiket[editIndex].tanggal,
waktuMulai: editIndex === -1
? new Date()
: daftarTiket[editIndex].waktuMulai,
keterangan: keterangan.value,
timeline: editIndex === -1
? [
{
status: statusRujukan.value,
waktu: getTanggalJam(),
keterangan: keterangan.value
}
]
: daftarTiket[editIndex].timeline
};
if (editIndex === -1) {
// Tambah data baru
daftarTiket.push(tiket);
} else {
// Update data lama
daftarTiket[editIndex] = tiket;
}
/* Simpan ke Local Storage */
simpanData();
renderTable();
updateDashboard();
closeModal();
});
/* ================= FILTER PERIODE ================= */
document.getElementById("filterPeriode").addEventListener("change", function(){
renderTable();
updateDashboard();
});
/* ================= RENDER TABEL ================= */
function renderTable() {
const tbody = document.getElementById("tableBody");
const kosong = document.getElementById("emptyData");
tbody.innerHTML = "";
// ================= FILTER =================
const filter = document.getElementById("filterPeriode").value;
const sekarang = new Date();
const dataTampil = daftarTiket.filter(function(item){
if(!item.tanggal){
return true;
}
const tgl = new Date(item.tanggal);
switch(filter){
case "today":
return tgl.toDateString() === sekarang.toDateString();
case "week":
const awal = new Date(sekarang);
awal.setDate(sekarang.getDate() - 7);
return tgl >= awal;
case "month":
return tgl.getMonth() === sekarang.getMonth() &&
tgl.getFullYear() === sekarang.getFullYear();
case "year":
return tgl.getFullYear() === sekarang.getFullYear();
default:
return true;
}
});
// ================= DATA KOSONG =================
if (dataTampil.length === 0) {
kosong.style.display = "block";
return;
}
kosong.style.display = "none";
// ================= TAMPILKAN DATA =================
dataTampil.forEach(function (item, index) {
let badgePrioritas = "";
switch (item.prioritas) {
case "Emergency":
badgePrioritas = '<span class="badge badge-emergency">Emergency</span>';
break;
case "Fasttrack":
badgePrioritas = '<span class="badge badge-fasttrack">Fasttrack</span>';
break;
default:
badgePrioritas = '<span class="badge badge-elektif">Elektif</span>';
}
let badgeStatus = "";
switch (item.status) {
case "Proses Penapisan":
badgeStatus = '<span class="status status-proses">Proses Penapisan</span>';
break;
case "Diterima":
badgeStatus = '<span class="status status-diterima">Diterima</span>';
break;
case "Ditolak":
badgeStatus = '<span class="status status-ditolak">Ditolak</span>';
break;
case "Ditunda":
badgeStatus = '<span class="status status-ditunda">Ditunda</span>';
break;
case "Dibatalkan":
badgeStatus = '<span class="status status-dibatalkan">Dibatalkan</span>';
break;
default:
badgeStatus = '<span class="status status-selesai">Selesai</span>';
}
tbody.innerHTML += `
<tr>
<td>${item.nomor}</td>
<td>${item.pasien}</td>
<td>${item.faskes}</td>
<td>${item.lama}</td>
<td>${badgePrioritas}</td>
<td>${item.dokterPerujuk}</td>
<td>${item.dpjp}</td>
<td>${badgeStatus}</td>
<td>${item.tujuanIGD}</td>
<td>
<button
class="btn-timeline"
onclick="lihatDetail(${index})">
⏱ Timeline
</button>
</td>
<td>${item.keterangan}</td>
<td class="action">
<button
class="btn-edit"
onclick="editData(${index})">
Edit
</button>
<button
class="btn-delete"
onclick="hapusData(${index})">
Hapus
</button>
<button
class="btn-finish"
onclick="selesai(${index})">
Selesai
</button>
</td>
</tr>
`;
});
}
/* ================= DASHBOARD ================= */
function updateDashboard() {
document.getElementById("totalTiket").innerHTML = daftarTiket.length;
document.getElementById("totalEmergency").innerHTML =
daftarTiket.filter(x => x.prioritas === "Emergency").length;
document.getElementById("totalFasttrack").innerHTML =
daftarTiket.filter(x => x.prioritas === "Fasttrack").length;
document.getElementById("totalElektif").innerHTML =
daftarTiket.filter(x => x.prioritas === "Elektif").length;
document.getElementById("totalSelesai").innerHTML =
daftarTiket.filter(x => x.status === "Selesai").length;
}
/* ================= REFRESH ================= */
loadData();
renderTable();
updateDashboard();
/*=========================================================
SIJAGAD RSSA
Dashboard Hotline
PART 4C
Edit • Detail • Update Status • Pencarian
=========================================================*/
/* ================= EDIT DATA ================= */
function editData(index){
editIndex = index;
const data = daftarTiket[index];
openModal();
nomorTiket.value = data.nomor;
namaPasien.value = data.pasien;
asalFaskes.value = data.faskes;
lamaPerawatan.value = data.lama;
prioritas.value = data.prioritas;
dokterPerujuk.value = data.dokterPerujuk;
dpjp.value = data.dpjp;
statusRujukan.value = data.status;
tujuanIGD.value = data.tujuanIGD;
keterangan.value = data.keterangan;
waktuProses.value = data.timeline[data.timeline.length - 1].waktu;
namaPasien.focus();
}
/* ================= UPDATE STATUS ================= */
statusRujukan.addEventListener("change", function(){
if(editIndex == -1) return;
daftarTiket[editIndex].status = this.value;
daftarTiket[editIndex].timeline.push({
status: this.value,
waktu: getTanggalJam(),
keterangan: keterangan.value
});
simpanData();
});
/* ================= SELESAI ================= */
function selesai(index){
daftarTiket[index].status="Selesai";
daftarTiket[index].timeline.push({
status:"Selesai",
waktu:getTanggalJam(),
keterangan:"Tiket telah selesai"
});
simpanData();
renderTable();
updateDashboard();
}
/* ================= DETAIL TIMELINE ================= */
function lihatDetail(index){
detailIndex = index;
const data = daftarTiket[index];
document.getElementById("detailNomor").innerHTML = data.nomor;
document.getElementById("detailPasien").innerHTML = data.pasien;
document.getElementById("detailDokterPerujuk").innerHTML = data.dokterPerujuk;
document.getElementById("detailDPJP").innerHTML = data.dpjp;
document.getElementById("detailStatus").innerHTML = data.status;
document.getElementById("detailTujuanIGD").innerHTML = data.tujuanIGD;
const timeline = document.getElementById("timelineContainer");
timeline.innerHTML = "";
data.timeline.forEach(function(item){
let icon = "🟡";
switch(item.status){
case "Proses Penapisan":
icon = "🟡";
break;
case "Menunggu DPJP":
icon = "🔵";
break;
case "Diterima":
icon = "🟢";
break;
case "Ditunda":
icon = "🟠";
break;
case "Ditolak":
icon = "🔴";
break;
case "Dibatalkan":
icon = "⚫";
break;
case "Selesai":
icon = "✅";
break;
}
timeline.innerHTML += `
<div class="timeline-item">
<div class="timeline-dot"></div>
<div class="timeline-content">
<h4>${icon} ${item.status}</h4>
<small>🕒 ${item.waktu}</small>
<p>${item.keterangan || "-"}</p>
</div>
</div>
`;
});
openDetail();
}
/* ================= PENCARIAN ================= */
document.getElementById("search").addEventListener("keyup",function(){
const keyword=this.value.toLowerCase();
const rows=document.querySelectorAll("#tableBody tr");
rows.forEach(function(row){
const text=row.innerText.toLowerCase();
if(text.indexOf(keyword)>-1){
row.style.display="";
}else{
row.style.display="none";
}
});
});
/* ================= TANGGAL ================= */
function updateDateTime(){
const now = new Date();
const tanggal = now.toLocaleDateString("id-ID",{
weekday:"long",
day:"2-digit",
month:"long",
year:"numeric"
});
const jam = now.toLocaleTimeString("id-ID",{
hour:"2-digit",
minute:"2-digit",
second:"2-digit",
hour12:false
});
let shift = "";
const h = now.getHours();
if(h >= 7 && h < 14){
shift = "🌞 Shift PAGI";
}
else if(h >=14 && h <21){
shift = "🌤 Shift SORE";
}
else{
shift = "🌙 Shift MALAM";
}
document.getElementById("liveDate").innerHTML = tanggal;
document.getElementById("liveClock").innerHTML = jam + " WIB";
document.getElementById("liveShift").innerHTML = shift;
}
updateDateTime();
setInterval(updateDateTime,1000);
/* ================= LOCAL STORAGE ================= */
function simpanData(){
localStorage.setItem(
"sijagad_rssa",
JSON.stringify(daftarTiket)
);
}
function loadData(){
const data = localStorage.getItem("sijagad_rssa");
if(data){
daftarTiket = JSON.parse(data);
}
}
/* ================= HAPUS DATA ================= */
function hapusData(index){
const password = prompt("Masukkan Password Admin");
if(password === null) return;
if(password !== "admin119"){
alert("Password salah!");
return;
}
if(confirm("Yakin ingin menghapus tiket ini?")){
daftarTiket.splice(index,1);
simpanData();
renderTable();
updateDashboard();
alert("Data berhasil dihapus.");
}
}
/* ================= PRINT TIMELINE ================= */
function printTimeline(){
const data = daftarTiket[detailIndex];
let isiTimeline = "";
data.timeline.forEach(function(item){
isiTimeline += `
<tr>
<td>${item.waktu}</td>
<td>${item.status}</td>
<td>${item.keterangan}</td>
</tr>
`;
});
const win = window.open("", "_blank");
win.document.write(`
<html>
<head>
<title>Timeline Rujukan</title>
<style>
body{
font-family:Arial;
padding:30px;
}
.print-header{
text-align:center;
margin-bottom:20px;
}
.print-header h2{
margin:0;
font-size:22px;
font-weight:bold;
}
.print-header div{
font-size:14px;
color:#444;
}
table{
width:100%;
border-collapse:collapse;
margin-top:20px;
}
th,td{
border:1px solid #444;
padding:10px;
text-align:left;
}
th{
background:#1565C0;
color:white;
}
.info{
margin-bottom:20px;
line-height:1.8;
}
</style>
</head>
<body>
<div class="print-header">
<h2>SIJAGAD RSSA</h2>
<div>Sistem Jaringan Akses Gawat Darurat</div>
<div>RSUD Dr. Saiful Anwar</div>
</div>
<h3>Timeline Proses Hotline Rujukan</h3>
<div class="info">
<b>No Tiket :</b> ${data.nomor}<br>
<b>Nama Pasien :</b> ${data.pasien}<br>
<b>Asal Faskes :</b> ${data.faskes}<br>
<b>Dokter Perujuk :</b> ${data.dokterPerujuk}<br>
<b>DPJP :</b> ${data.dpjp}<br>
<b>Tujuan IGD :</b> ${data.tujuanIGD}<br>
<b>Status Akhir :</b> ${data.status}
</div>
<table>
<thead>
<tr>
<th>Waktu</th>
<th>Status</th>
<th>Keterangan</th>
</tr>
</thead>
<tbody>
${isiTimeline}
</tbody>
</table>
<br><br>
<div style="text-align:right">
Dicetak :
${new Date().toLocaleString("id-ID")}
</div>
</body>
</html>
`);
win.document.close();
win.print();
}
</script>
</body>
</html>