Files
gravity/hosxp-webservice/components/card_patient_stats.php
T
2026-09-16 23:20:08 +07:00

218 lines
14 KiB
PHP

<?php
// components/card_patient_stats.php
$timezone = "Asia/Bangkok";
date_default_timezone_set($timezone);
$today = date("Y-m-d H:i:s");
// News (Changelogs from new system)
require_once(__DIR__."/../core/settings.php");
$all_logs = get_changelogs();
$news_items = array_slice($all_logs, 0, 5);
?>
<div class="mb-8 flex flex-col md:flex-row md:items-end justify-between gap-4 animate-enter">
<div>
<h2 class="text-3xl font-bold text-slate-800 tracking-tight">สวัสดี, <?php echo htmlspecialchars($_SESSION['name'] ?? 'ผู้ใช้งาน'); ?> 👋</h2>
<p class="text-slate-500 mt-2 text-lg">ภาพรวมการให้บริการประจำวันที่ <?php echo thai_date5(datetime_to_date($today)); ?></p>
</div>
<div class="flex gap-3">
<a href="search.php" class="btn-primary py-2.5 px-5 text-sm shadow-md">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
ค้นหาผู้ป่วย
</a>
</div>
</div>
<!-- Top Stat Widgets -->
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4 mb-8 animate-enter" style="animation-delay: 0.1s;">
<!-- ER Widget -->
<div class="glass-card !p-5 border-l-4 !border-l-rose-500 hover:-translate-y-1 transition-transform">
<div class="flex justify-between items-start">
<div>
<p class="text-slate-500 text-sm font-medium mb-1">ฉุกเฉิน (ER)</p>
<h4 class="text-3xl font-bold text-slate-800" id="stat-er">-</h4>
</div>
<div class="w-10 h-10 rounded-full bg-rose-50 text-rose-500 flex items-center justify-center">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z"></path></svg>
</div>
</div>
</div>
<!-- PQ Widget -->
<div class="glass-card !p-5 border-l-4 !border-l-blue-500 hover:-translate-y-1 transition-transform">
<div class="flex justify-between items-start">
<div>
<p class="text-slate-500 text-sm font-medium mb-1">ซักประวัติ</p>
<h4 class="text-3xl font-bold text-slate-800" id="stat-pq">-</h4>
</div>
<div class="w-10 h-10 rounded-full bg-blue-50 text-blue-500 flex items-center justify-center">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"></path></svg>
</div>
</div>
</div>
<!-- Dental Widget -->
<div class="glass-card !p-5 border-l-4 !border-l-purple-500 hover:-translate-y-1 transition-transform">
<div class="flex justify-between items-start">
<div>
<p class="text-slate-500 text-sm font-medium mb-1">ทันตกรรม</p>
<h4 class="text-3xl font-bold text-slate-800" id="stat-dt">-</h4>
</div>
<div class="w-10 h-10 rounded-full bg-purple-50 text-purple-500 flex items-center justify-center">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.828 14.828a4 4 0 01-5.656 0M9 10h.01M15 10h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path></svg>
</div>
</div>
</div>
<!-- Rx Widget -->
<div class="glass-card !p-5 border-l-4 !border-l-emerald-500 hover:-translate-y-1 transition-transform">
<div class="flex justify-between items-start">
<div>
<p class="text-slate-500 text-sm font-medium mb-1">สั่งจ่ายยา</p>
<h4 class="text-3xl font-bold text-slate-800" id="stat-rx">-</h4>
</div>
<div class="w-10 h-10 rounded-full bg-emerald-50 text-emerald-500 flex items-center justify-center">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 8.5a5.5 5.5 0 00-7.778 0L5.5 14.222a5.5 5.5 0 007.778 7.778l5.722-5.722A5.5 5.5 0 0019 8.5z" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.3 14.7l5.4-5.4" />
</svg>
</div>
</div>
</div>
<!-- Lab Widget -->
<div class="glass-card !p-5 border-l-4 !border-l-amber-500 hover:-translate-y-1 transition-transform">
<div class="flex justify-between items-start">
<div>
<p class="text-slate-500 text-sm font-medium mb-1">ห้องแล็บ</p>
<h4 class="text-3xl font-bold text-slate-800" id="stat-lab">-</h4>
</div>
<div class="w-10 h-10 rounded-full bg-amber-50 text-amber-500 flex items-center justify-center">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"></path></svg>
</div>
</div>
</div>
</div>
<div class="grid grid-cols-1 xl:grid-cols-2 gap-8 animate-enter">
<!-- Quick Actions / Menu -->
<div class="glass-card">
<div class="glass-header">
<h3 class="text-emerald-600 flex items-center gap-3 font-bold text-lg">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2V6zM14 6a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2V6zM4 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2H6a2 2 0 01-2-2v-2zM14 16a2 2 0 012-2h2a2 2 0 012 2v2a2 2 0 01-2 2h-2a2 2 0 01-2-2v-2z"></path></svg>
เมนูลัด (Quick Actions)
</h3>
</div>
<div class="glass-body p-6">
<div class="grid grid-cols-2 gap-4">
<a href="search.php" class="flex flex-col items-center justify-center p-6 bg-emerald-50 rounded-2xl hover:bg-emerald-100 hover:shadow-md transition-all text-emerald-700 font-semibold group cursor-pointer border border-emerald-100">
<div class="w-14 h-14 bg-white rounded-full flex items-center justify-center mb-3 shadow-sm group-hover:scale-110 transition-transform">
<svg class="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path></svg>
</div>
ค้นหาผู้ป่วย
</a>
<a href="#" class="flex flex-col items-center justify-center p-6 bg-blue-50 rounded-2xl hover:bg-blue-100 hover:shadow-md transition-all text-blue-700 font-semibold group cursor-pointer border border-blue-100">
<div class="w-14 h-14 bg-white rounded-full flex items-center justify-center mb-3 shadow-sm group-hover:scale-110 transition-transform">
<svg class="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 17v-2m3 2v-4m3 4v-6m2 10H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path></svg>
</div>
รายงานสถิติ
</a>
<a href="#" class="flex flex-col items-center justify-center p-6 bg-purple-50 rounded-2xl hover:bg-purple-100 hover:shadow-md transition-all text-purple-700 font-semibold group cursor-pointer border border-purple-100">
<div class="w-14 h-14 bg-white rounded-full flex items-center justify-center mb-3 shadow-sm group-hover:scale-110 transition-transform">
<svg class="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6"></path></svg>
</div>
ลงทะเบียนใหม่
</a>
<a href="#" class="flex flex-col items-center justify-center p-6 bg-amber-50 rounded-2xl hover:bg-amber-100 hover:shadow-md transition-all text-amber-700 font-semibold group cursor-pointer border border-amber-100">
<div class="w-14 h-14 bg-white rounded-full flex items-center justify-center mb-3 shadow-sm group-hover:scale-110 transition-transform">
<svg class="w-7 h-7" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path></svg>
</div>
ตั้งค่าระบบ
</a>
</div>
</div>
</div>
<!-- News Right -->
<div class="glass-card">
<div class="glass-header">
<h3 class="text-amber-500 flex items-center gap-3 font-bold text-lg">
<svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 5.882V19.24a1.76 1.76 0 01-3.417.592l-2.147-6.15M18 13a3 3 0 100-6M5.436 13.683A4.001 4.001 0 017 6h1.832c4.1 0 7.625-1.234 9.168-3v14c-1.543-1.766-5.067-3-9.168-3H7a3.988 3.988 0 01-1.564-.317z"></path></svg>
ประกาศข่าวสาร
</h3>
</div>
<div class="glass-body flex flex-col gap-4">
<?php if(count($news_items) > 0): ?>
<?php foreach($news_items as $news):
$d = new DateTime($news['release_date']);
$thai_year = $d->format('Y') + 543;
$display_date = $d->format('d-m-') . $thai_year;
?>
<div class="p-5 bg-white/60 rounded-2xl border-l-4 border-amber-400 shadow-sm hover:shadow-md transition-shadow">
<div class="text-xs text-amber-600 mb-1.5 font-bold tracking-wide">
<?php echo $display_date; ?>
</div>
<div class="text-slate-800 font-medium leading-relaxed flex flex-wrap items-center gap-y-2">
<?php echo htmlspecialchars($news['version']); ?>
<?php if(!empty($news['description'])): ?>
<span class="ml-2 inline-flex items-center px-3 py-1 rounded-full text-[11px] font-bold bg-emerald-100 text-emerald-800 shadow-sm border border-emerald-200/50">
<?php echo htmlspecialchars($news['description']); ?>
</span>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
<?php else: ?>
<div class="text-center text-slate-400 py-12 flex flex-col items-center">
<svg class="w-12 h-12 mb-3 opacity-30" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 20H5a2 2 0 01-2-2V6a2 2 0 012-2h10a2 2 0 012 2v1m2 13a2 2 0 01-2-2V7m2 13a2 2 0 002-2V9.5a2.5 2.5 0 00-2.5-2.5H15"></path></svg>
ไม่มีข้อมูลประกาศ
</div>
<?php endif; ?>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
fetch('../core/ajax_dashboard_stats.php')
.then(response => response.json())
.then(data => {
// Animate numbers
animateValue('stat-er', 0, parseInt(data.er.replace(/,/g, '')), 1000);
animateValue('stat-pq', 0, parseInt(data.pq.replace(/,/g, '')), 1000);
animateValue('stat-dt', 0, parseInt(data.dt.replace(/,/g, '')), 1000);
animateValue('stat-rx', 0, parseInt(data.rx.replace(/,/g, '')), 1000);
animateValue('stat-lab', 0, parseInt(data.lab.replace(/,/g, '')), 1000);
})
.catch(err => {
console.error('Error loading stats:', err);
['stat-er','stat-pq','stat-dt','stat-rx','stat-lab'].forEach(id => {
document.getElementById(id).innerText = "Err";
});
});
function animateValue(id, start, end, duration) {
if (isNaN(end)) return;
let obj = document.getElementById(id);
let startTimestamp = null;
const step = (timestamp) => {
if (!startTimestamp) startTimestamp = timestamp;
const progress = Math.min((timestamp - startTimestamp) / duration, 1);
// easeOutQuad
const easeProgress = progress * (2 - progress);
obj.innerHTML = Math.floor(easeProgress * (end - start) + start).toLocaleString('en-US');
if (progress < 1) {
window.requestAnimationFrame(step);
} else {
obj.innerHTML = end.toLocaleString('en-US');
}
};
window.requestAnimationFrame(step);
}
});
</script>