Initial commit

This commit is contained in:
Porawit Dongwang
2026-09-16 23:20:08 +07:00
commit 0041668dbb
32577 changed files with 3687927 additions and 0 deletions
@@ -0,0 +1,313 @@
<?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>