2853 lines
44 KiB
HTML
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()">×</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()">×</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>
|
|
|
|
|