157 lines
9.3 KiB
PHP
157 lines
9.3 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
require_once __DIR__ . '/queue_bootstrap.php';
|
|
qh_boot();
|
|
|
|
$activeCalls = qh_fetch_tickets(['called', 'in_progress'], null, 8);
|
|
$queueOverview = qh_queue_overview();
|
|
|
|
$activeVideos = [];
|
|
try {
|
|
$stmt = db()->query("SELECT video_path FROM hospital_ads WHERE is_active = 1 ORDER BY sort_order ASC, id DESC LIMIT 10");
|
|
if ($stmt) {
|
|
$activeVideos = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
}
|
|
} catch (Throwable $e) {
|
|
// Table might not exist yet, safe to ignore
|
|
}
|
|
|
|
qh_page_start(
|
|
'display',
|
|
qh_t('General display board', 'لوحة العرض العامة'),
|
|
qh_t('Public queue display.', 'شاشة طوابير عامة.')
|
|
);
|
|
?>
|
|
<div class="container-fluid px-3 px-lg-4 py-3" data-auto-refresh="20">
|
|
<div class="row g-4 h-100">
|
|
<div class="col-xl-8 col-lg-7 d-flex flex-column gap-4">
|
|
<div class="card shadow-sm border-0 flex-grow-1">
|
|
<div class="card-header bg-white border-bottom py-3 d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<h1 class="h3 mb-0 text-gray-800 fw-bold"><?= qh_h(qh_t('Now Serving', 'يتم الآن النداء')) ?></h1>
|
|
</div>
|
|
<div class="d-flex align-items-center gap-3">
|
|
<div class="fs-4 fw-bold text-dark js-live-clock"><?= qh_h(date('H:i')) ?></div>
|
|
<button type="button" class="btn btn-outline-secondary btn-sm shadow-sm js-fullscreen-toggle" aria-pressed="false" data-label-enter="<?= qh_h(qh_t('Fullscreen', 'ملء الشاشة')) ?>" data-label-exit="<?= qh_h(qh_t('Exit fullscreen', 'إنهاء ملء الشاشة')) ?>"><i class="bi bi-arrows-fullscreen"></i></button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card-body p-4 bg-light">
|
|
<?php if ($activeCalls): ?>
|
|
<div class="row g-3">
|
|
<?php foreach ($activeCalls as $ticket): $speech = qh_call_message($ticket); ?>
|
|
<div class="col-6 col-lg-3">
|
|
<div class="card border-0 shadow-sm h-100" data-announcement-key="<?= qh_h((string) $ticket['id']) ?>-<?= qh_h((string) strtotime((string) $ticket['called_at'])) ?>" data-announcement-en="<?= qh_h($speech['en']) ?>" data-announcement-ar="<?= qh_h($speech['ar']) ?>">
|
|
<div class="card-body text-center p-3">
|
|
<div class="display-5 fw-bold text-primary mb-1"><?= qh_h($ticket['ticket_number']) ?></div>
|
|
<div class="fs-6 text-muted mb-1 text-truncate" style="max-width: 100%;" title="<?= qh_h(qh_name($ticket, 'doctor_name', qh_t('Doctor', 'الطبيب'))) ?>"><?= qh_h(qh_name($ticket, 'doctor_name', qh_t('Doctor', 'الطبيب'))) ?></div>
|
|
<div class="d-inline-block bg-primary text-white rounded px-2 py-1 fs-6 fw-bold mt-1">
|
|
<?= qh_h(qh_t('Room', 'غرفة')) ?> <?= qh_h($ticket['doctor_room'] ?? '--') ?>
|
|
</div>
|
|
</div>
|
|
<div class="card-footer bg-white text-center text-muted small py-1" style="font-size: 0.75rem;">
|
|
<?= qh_format_datetime($ticket['called_at'] ?? $ticket['updated_at']) ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="d-flex align-items-center justify-content-center h-100 min-vh-50 text-muted">
|
|
<div class="text-center">
|
|
<i class="bi bi-display display-1 mb-3 opacity-50"></i>
|
|
<h2><?= qh_h(qh_t('No active calls right now.', 'لا توجد نداءات نشطة حالياً.')) ?></h2>
|
|
<p class="lead opacity-75"><?= qh_h(qh_t('Please wait for your ticket number.', 'يرجى الانتظار حتى يتم نداء رقم تذكرتك.')) ?></p>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="card shadow-sm border-0">
|
|
<div class="card-header bg-white border-bottom py-3">
|
|
<h5 class="mb-0 font-weight-bold text-dark"><?= qh_h(qh_t('Queue by Clinic', 'الطابور حسب العيادة')) ?></h5>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover align-middle mb-0">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th class="border-0 px-4 py-3"><?= qh_h(qh_t('Clinic', 'العيادة')) ?></th>
|
|
<th class="border-0 py-3 text-center"><?= qh_h(qh_t('Vitals Wait', 'انتظار العلامات')) ?></th>
|
|
<th class="border-0 px-4 py-3 text-center"><?= qh_h(qh_t('Doctor Wait', 'انتظار الطبيب')) ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach ($queueOverview as $row): ?>
|
|
<tr>
|
|
<td class="fw-semibold px-4 py-3 text-dark"><?= qh_h(qh_name($row)) ?></td>
|
|
<td class="py-3 text-center"><span class="badge bg-warning text-dark rounded-pill px-3"><?= qh_h((string) $row['vitals_waiting']) ?></span></td>
|
|
<td class="py-3 text-center px-4"><span class="badge bg-info text-dark rounded-pill px-3"><?= qh_h((string) $row['doctor_waiting']) ?></span></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-4 col-lg-5">
|
|
<div class="sticky-top" style="top: 1rem; height: 60vh;">
|
|
<?php if (!empty($activeVideos)): ?>
|
|
<div class="card shadow-sm border-0 h-100 bg-black overflow-hidden d-flex justify-content-center align-items-center">
|
|
<video id="adsVideoPlayer" class="w-100 h-100 object-fit-contain" autoplay muted playsinline>
|
|
<source src="<?= qh_h($activeVideos[0]) ?>" type="video/mp4">
|
|
</video>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const videos = <?= json_encode($activeVideos, JSON_UNESCAPED_SLASHES) ?>;
|
|
let currentIdx = 0;
|
|
const player = document.getElementById('adsVideoPlayer');
|
|
|
|
if (videos.length > 1) {
|
|
player.addEventListener('ended', function() {
|
|
currentIdx = (currentIdx + 1) % videos.length;
|
|
player.src = videos[currentIdx];
|
|
player.play().catch(function(e) { console.error("Error playing video:", e); });
|
|
});
|
|
} else {
|
|
// If only one video, loop it
|
|
player.loop = true;
|
|
}
|
|
});
|
|
</script>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="card shadow-sm border-0 h-100 bg-primary text-white">
|
|
<div class="card-header border-bottom border-light border-opacity-25 py-3 bg-transparent d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0 font-weight-bold text-white"><i class="bi bi-info-circle me-2"></i><?= qh_h(qh_t('Information', 'معلومات')) ?></h5>
|
|
<span class="badge bg-white text-primary rounded-pill small"><?= qh_h(qh_t('Notices', 'تنبيهات')) ?></span>
|
|
</div>
|
|
<div class="card-body p-4 d-flex flex-column gap-4">
|
|
<div class="border border-light border-opacity-25 rounded p-4 bg-white bg-opacity-10">
|
|
<div class="badge bg-light text-primary mb-2 px-2 py-1"><?= qh_h(qh_t('Service', 'خدمة')) ?></div>
|
|
<h4 class="text-white fw-bold"><?= qh_h(qh_t('Lab packages & checks', 'باقات المختبر والفحوصات')) ?></h4>
|
|
<p class="mb-0 text-white text-opacity-75"><?= qh_h(qh_t('Ask reception about bundled blood tests, diabetes follow-up, and annual screenings.', 'اسأل الاستقبال عن باقات تحاليل الدم، ومتابعة السكري، والفحوصات السنوية.')) ?></p>
|
|
</div>
|
|
|
|
<div class="border border-light border-opacity-25 rounded p-4 bg-white bg-opacity-10">
|
|
<div class="badge bg-light text-primary mb-2 px-2 py-1"><?= qh_h(qh_t('Reminder', 'تذكير')) ?></div>
|
|
<h4 class="text-white fw-bold"><?= qh_h(qh_t('Keep your ticket visible', 'احتفظ بتذكرتك ظاهرة')) ?></h4>
|
|
<p class="mb-0 text-white text-opacity-75"><?= qh_h(qh_t('We announce ticket numbers on this screen and by voice. Stay near your department area.', 'نعلن أرقام التذاكر على هذه الشاشة وبالصوت. يرجى البقاء قرب منطقة القسم الخاص بك.')) ?></p>
|
|
</div>
|
|
|
|
<div class="border border-light border-opacity-25 rounded p-4 bg-white bg-opacity-10">
|
|
<div class="badge bg-light text-primary mb-2 px-2 py-1"><?= qh_h(qh_t('Wayfinding', 'الإرشاد')) ?></div>
|
|
<h4 class="text-white fw-bold"><?= qh_h(qh_t('Pharmacy & billing', 'الصيدلية والمحاسبة')) ?></h4>
|
|
<p class="mb-0 text-white text-opacity-75"><?= qh_h(qh_t('Completed visits can proceed to the pharmacy and billing desk near the main exit.', 'بعد انتهاء الزيارة يمكن التوجه إلى الصيدلية ومكتب المحاسبة قرب المخرج الرئيسي.')) ?></p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php qh_page_end(); ?>
|