314 lines
16 KiB
PHP
314 lines
16 KiB
PHP
<?php
|
|
session_start();
|
|
if (!isset($_SESSION["loggedin"]) || $_SESSION["loggedin"] !== true || !isset($_SESSION['is_admin']) || !$_SESSION['is_admin']) {
|
|
header("location: index.php");
|
|
exit;
|
|
}
|
|
|
|
require_once 'includes/db_assessment.php';
|
|
|
|
// Fetch all available years for the filter
|
|
$years_stmt = $pdo_assess->query("SELECT year_text FROM it_years ORDER BY year_text DESC");
|
|
$years = $years_stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
|
|
// Fetch counts by year
|
|
$counts_stmt = $pdo_assess->query("SELECT assess_year, COUNT(id) as total_assessments FROM it_assessments GROUP BY assess_year ORDER BY assess_year DESC");
|
|
$counts_by_year = $counts_stmt->fetchAll();
|
|
|
|
// Filter by selected year
|
|
$filter_year = $_GET['year'] ?? ($years[0] ?? (date('Y')+543));
|
|
|
|
// Fetch Rules and SLAs for Headers (Assuming we show all currently active ones, or all that exist)
|
|
$rules = $pdo_assess->query("SELECT id, content FROM it_rules ORDER BY order_no ASC")->fetchAll();
|
|
$slas = $pdo_assess->query("SELECT id, service_name FROM it_slas ORDER BY order_no ASC")->fetchAll();
|
|
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="th">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>สรุปผลประเมินประจำปี - Admin</title>
|
|
<!-- Favicon -->
|
|
<link rel="icon" type="image/png" href="assets/images/logo.png">
|
|
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<link href="https://fonts.googleapis.com/css2?family=Sarabun:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
|
|
|
<!-- DataTables -->
|
|
<link href="https://cdn.datatables.net/1.13.6/css/dataTables.bootstrap5.min.css" rel="stylesheet">
|
|
<link href="https://cdn.datatables.net/buttons/2.4.1/css/buttons.bootstrap5.min.css" rel="stylesheet">
|
|
|
|
<style>
|
|
body { font-family: 'Sarabun', sans-serif; background-color: #f8f9fa; }
|
|
.navbar-custom { background: linear-gradient(135deg, #12344d, #1a2938); }
|
|
.card { border: none; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.05); }
|
|
table.dataTable thead th, table.dataTable thead td { text-align: center; vertical-align: middle; background-color: #f1f5f9; color: #334155; border-bottom: 2px solid #cbd5e1; font-size: 0.85rem; white-space: nowrap; }
|
|
table.dataTable tbody td { font-size: 0.9rem; vertical-align: middle; }
|
|
.table-responsive { overflow-x: auto; }
|
|
|
|
/* ปรับขนาดไอคอนเรียงลำดับ (Sort) ของ DataTables ให้เล็กและบางลง */
|
|
table.dataTable thead > tr > th.sorting::before,
|
|
table.dataTable thead > tr > th.sorting_asc::before,
|
|
table.dataTable thead > tr > th.sorting_desc::before,
|
|
table.dataTable thead > tr > th.sorting_asc_disabled::before,
|
|
table.dataTable thead > tr > th.sorting_desc_disabled::before {
|
|
right: 1.2em !important;
|
|
content: "▲" !important;
|
|
font-size: 0.55em !important;
|
|
bottom: 1em !important;
|
|
opacity: 0.2;
|
|
}
|
|
|
|
table.dataTable thead > tr > th.sorting::after,
|
|
table.dataTable thead > tr > th.sorting_asc::after,
|
|
table.dataTable thead > tr > th.sorting_desc::after,
|
|
table.dataTable thead > tr > th.sorting_asc_disabled::after,
|
|
table.dataTable thead > tr > th.sorting_desc_disabled::after {
|
|
right: 0.5em !important;
|
|
content: "▼" !important;
|
|
font-size: 0.55em !important;
|
|
bottom: 1em !important;
|
|
opacity: 0.2;
|
|
}
|
|
|
|
/* เน้นสีไอคอนเมื่อถูกเลือก (Active Sort) */
|
|
table.dataTable thead > tr > th.sorting_asc::before,
|
|
table.dataTable thead > tr > th.sorting_desc::after {
|
|
opacity: 1 !important;
|
|
color: #008f91;
|
|
}
|
|
|
|
/* เพิ่มระยะห่างข้อความกับไอคอน */
|
|
table.dataTable thead > tr > th {
|
|
padding-right: 25px !important;
|
|
}
|
|
|
|
/* ปุ่มส่งออก Excel สำหรับตารางรายชื่อผู้ที่ยังไม่ได้ทำประเมิน */
|
|
.btn-excel-unassessed {
|
|
background: linear-gradient(135deg, #107c41, #189853);
|
|
color: #ffffff !important;
|
|
border: none;
|
|
border-radius: 8px;
|
|
font-weight: 600;
|
|
padding: 8px 16px;
|
|
box-shadow: 0 4px 6px rgba(16, 124, 65, 0.2);
|
|
transition: all 0.3s ease;
|
|
}
|
|
.btn-excel-unassessed:hover {
|
|
background: linear-gradient(135deg, #0b5e31, #107c41);
|
|
transform: translateY(-2px);
|
|
box-shadow: 0 6px 12px rgba(16, 124, 65, 0.3);
|
|
}
|
|
.btn-excel-unassessed i {
|
|
margin-right: 5px;
|
|
font-size: 1.1em;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<nav class="navbar navbar-expand-lg navbar-dark navbar-custom mb-4">
|
|
<div class="container-fluid px-4">
|
|
<a class="navbar-brand fw-bold d-flex align-items-center" href="admin_settings.php">
|
|
<img src="assets/images/logo.png" alt="Logo" width="40" height="40" class="d-inline-block align-text-top me-2 bg-white rounded-circle">
|
|
<span>ระบบประเมินสุขภาพดิจิทัล (Admin)</span>
|
|
</a>
|
|
<div class="d-flex">
|
|
<span class="text-white me-3 mt-1">ผู้ดูแล: <?php echo htmlspecialchars($_SESSION['fullname']); ?></span>
|
|
<a href="admin_settings.php" class="btn btn-warning btn-sm rounded-pill px-3 me-2">ตั้งค่าระบบ</a>
|
|
<a href="form.php" class="btn btn-light btn-sm rounded-pill px-3 me-2">ไปหน้าฟอร์ม</a>
|
|
<a href="actions/logout.php" class="btn btn-outline-light btn-sm rounded-pill px-3">ออกจากระบบ</a>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="container-fluid">
|
|
<div class="card p-4">
|
|
|
|
<!-- Summary Cards for Counts -->
|
|
<?php if(!empty($counts_by_year)): ?>
|
|
<div class="row mb-4">
|
|
<?php foreach($counts_by_year as $c): ?>
|
|
<div class="col-md-3 col-sm-6 mb-2">
|
|
<div class="card bg-light border-0 shadow-sm">
|
|
<div class="card-body text-center p-3">
|
|
<h6 class="text-muted mb-1">ปีประเมิน <?php echo htmlspecialchars($c['assess_year']); ?></h6>
|
|
<h3 class="text-primary mb-0 fw-bold"><?php echo number_format($c['total_assessments']); ?> <small class="text-muted fs-6">รายการ</small></h3>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-4 pb-3 border-bottom">
|
|
<h4 class="m-0 fw-bold text-dark"><i class="bi bi-file-earmark-bar-graph text-primary me-2"></i>สรุปผลประเมินประจำปี</h4>
|
|
<div class="d-flex gap-3 align-items-center">
|
|
<form method="GET" class="d-flex align-items-center bg-light px-3 py-2 rounded shadow-sm border border-1">
|
|
<label class="me-2 fw-bold text-muted mb-0">เลือกปีประเมิน:</label>
|
|
<select name="year" class="form-select form-select-sm" style="width: 120px;" onchange="this.form.submit()">
|
|
<?php foreach($years as $y): ?>
|
|
<option value="<?php echo htmlspecialchars($y); ?>" <?php if($y == $filter_year) echo 'selected'; ?>>
|
|
<?php echo htmlspecialchars($y); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
<?php if(empty($years)): ?>
|
|
<option value="">ไม่มีข้อมูล</option>
|
|
<?php endif; ?>
|
|
</select>
|
|
</form>
|
|
<a href="print_report.php?year=<?php echo urlencode($filter_year); ?>" target="_blank" class="btn btn-outline-secondary d-flex align-items-center shadow-sm">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" class="bi bi-printer me-2" viewBox="0 0 16 16">
|
|
<path d="M2.5 8a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1"/>
|
|
<path d="M5 1a2 2 0 0 0-2 2v2H2a2 2 0 0 0-2 2v3a2 2 0 0 0 2 2h1v1a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2v-1h1a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-1V3a2 2 0 0 0-2-2zM4 3a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2H4zm1 5a2 2 0 0 0-2 2v1H2a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-1v-1a2 2 0 0 0-2-2zm7 2v3a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1"/>
|
|
</svg>
|
|
พิมพ์รายงานสรุป
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="table-responsive mt-2">
|
|
<table id="summaryTable" class="table table-hover table-bordered w-100 align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th>ลำดับ</th>
|
|
<th>ปีประเมิน</th>
|
|
<th>ชื่อ-สกุล</th>
|
|
<th>ตำแหน่ง</th>
|
|
<th>หน่วยงาน</th>
|
|
<th>ใช้คอมพิวเตอร์</th>
|
|
|
|
<!-- Dynamic Rules -->
|
|
<?php
|
|
$n = 1;
|
|
foreach($rules as $r):
|
|
?>
|
|
<th title="<?php echo htmlspecialchars($r['content']); ?>">R<?php echo $n; ?>_รู้</th>
|
|
<th title="<?php echo htmlspecialchars($r['content']); ?>">R<?php echo $n; ?>_เข้าใจ</th>
|
|
<th title="<?php echo htmlspecialchars($r['content']); ?>">R<?php echo $n; ?>_ปฏิบัติ</th>
|
|
<?php
|
|
$n++;
|
|
endforeach;
|
|
?>
|
|
|
|
<!-- Dynamic SLA -->
|
|
<?php
|
|
$n = 1;
|
|
foreach($slas as $s):
|
|
?>
|
|
<th title="<?php echo htmlspecialchars($s['service_name']); ?>">SLA<?php echo $n; ?>_คะแนน</th>
|
|
<th title="<?php echo htmlspecialchars($s['service_name']); ?>">SLA<?php echo $n; ?>_เสนอแนะ</th>
|
|
<?php
|
|
$n++;
|
|
endforeach;
|
|
?>
|
|
|
|
<th>วันที่ทำประเมิน</th>
|
|
<th>จัดการ</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<!-- Data populated via AJAX -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- New Section for Unassessed Users -->
|
|
<div class="card p-4 mt-4 shadow-sm border-0 mb-5">
|
|
<div class="d-flex justify-content-between align-items-center mb-4 pb-3 border-bottom">
|
|
<h4 class="m-0 fw-bold text-dark">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" fill="currentColor" class="bi bi-person-x text-danger me-2" viewBox="0 0 16 16" style="vertical-align: text-bottom;">
|
|
<path d="M11 5a3 3 0 1 1-6 0 3 3 0 0 1 6 0M8 7a2 2 0 1 0 0-4 2 2 0 0 0 0 4m.256 7a4.5 4.5 0 0 1-.229-1.004H3c.001-.246.154-.986.832-1.664C4.484 10.68 5.711 10 8 10q.39 0 .74.025c.226-.341.496-.65.804-.918Q8.844 9.002 8 9c-5 0-6 3-6 4s1 1 1 1z"/>
|
|
<path d="M12.5 16a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7m-.646-4.854.646.647.646-.647a.5.5 0 0 1 .708.708l-.647.646.647.646a.5.5 0 0 1-.708.708l-.646-.647-.646.647a.5.5 0 0 1-.708-.708l.647-.646-.647-.646a.5.5 0 0 1 .708-.708"/>
|
|
</svg>
|
|
รายชื่อผู้ที่ยังไม่ได้ทำการประเมิน (ปี <?php echo htmlspecialchars($filter_year); ?>)
|
|
</h4>
|
|
<span id="unassessed-count" class="badge bg-danger fs-6">กำลังโหลด...</span>
|
|
</div>
|
|
<div class="table-responsive mt-2">
|
|
<table id="unassessedTable" class="table table-hover table-bordered w-100 align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th width="10%">ลำดับ</th>
|
|
<th width="30%">ชื่อ-สกุล</th>
|
|
<th width="30%">ตำแหน่ง</th>
|
|
<th width="30%">หน่วยงาน</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<!-- Data populated via AJAX -->
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script src="https://cdn.datatables.net/1.13.6/js/jquery.dataTables.min.js"></script>
|
|
<script src="https://cdn.datatables.net/1.13.6/js/dataTables.bootstrap5.min.js"></script>
|
|
<script src="https://cdn.datatables.net/buttons/2.4.1/js/dataTables.buttons.min.js"></script>
|
|
<script src="https://cdn.datatables.net/buttons/2.4.1/js/buttons.bootstrap5.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.10.1/jszip.min.js"></script>
|
|
<script src="https://cdn.datatables.net/buttons/2.4.1/js/buttons.html5.min.js"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
var year = "<?php echo urlencode($filter_year); ?>";
|
|
|
|
var summaryTable = $('#summaryTable').DataTable({
|
|
"pageLength": 10,
|
|
"language": { "url": "//cdn.datatables.net/plug-ins/1.13.6/i18n/th.json" },
|
|
"ajax": "actions/get_summary_data.php?year=" + year,
|
|
"dom": "<'row mb-3 align-items-center'<'col-md-5'l><'col-md-7 d-flex justify-content-end align-items-center gap-3'fB>>" +
|
|
"<'row'<'col-sm-12'tr>>" +
|
|
"<'row mt-3 align-items-center'<'col-md-5'i><'col-md-7 text-end'p>>",
|
|
"buttons": [
|
|
{ extend: 'excelHtml5', text: '<i class="bi bi-file-earmark-excel"></i> ส่งออก Excel', className: 'btn btn-success shadow-sm', exportOptions: { columns: ':not(:last-child)' } }
|
|
],
|
|
"scrollX": true
|
|
});
|
|
|
|
var unassessedTable = $('#unassessedTable').DataTable({
|
|
"pageLength": 10,
|
|
"language": { "url": "//cdn.datatables.net/plug-ins/1.13.6/i18n/th.json" },
|
|
"ajax": {
|
|
"url": "actions/get_unassessed_data.php?year=" + year,
|
|
"dataSrc": function (json) {
|
|
// Update the badge count dynamically
|
|
$('#unassessed-count').text(json.count + " คน");
|
|
return json.data;
|
|
}
|
|
},
|
|
"dom": "<'row mb-3 align-items-center'<'col-md-5'l><'col-md-7 d-flex justify-content-end align-items-center gap-3'fB>>" +
|
|
"<'row'<'col-sm-12'tr>>" +
|
|
"<'row mt-3 align-items-center'<'col-md-5'i><'col-md-7 text-end'p>>",
|
|
"buttons": [
|
|
{ extend: 'excelHtml5', text: '<i class="bi bi-file-earmark-excel"></i> ส่งออก Excel รายชื่อผู้ที่ยังไม่ประเมิน', className: 'btn-excel-unassessed' }
|
|
],
|
|
"scrollX": false
|
|
});
|
|
|
|
// Auto refresh data every 15 seconds silently
|
|
setInterval(function(){
|
|
summaryTable.ajax.reload(null, false); // false = keep current paging
|
|
unassessedTable.ajax.reload(null, false);
|
|
}, 15000);
|
|
});
|
|
|
|
<?php if(isset($_SESSION['success_msg'])): ?>
|
|
Swal.fire({
|
|
icon: 'success',
|
|
title: 'สำเร็จ!',
|
|
text: '<?php echo $_SESSION['success_msg']; ?>',
|
|
timer: 2000,
|
|
showConfirmButton: false
|
|
});
|
|
<?php unset($_SESSION['success_msg']); ?>
|
|
<?php endif; ?>
|
|
</script>
|
|
</body>
|
|
</html>
|