300 lines
14 KiB
PHP
300 lines
14 KiB
PHP
<?php
|
|
session_start();
|
|
require_once 'config.php';
|
|
header('Content-Type: text/html; charset=utf-8');
|
|
|
|
if (empty($_SESSION['logged_in'])) {
|
|
header("Location: index.php");
|
|
exit;
|
|
}
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="th">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>เอกสารการจัดเวร</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<link href="https://fonts.googleapis.com/css2?family=Sarabun:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
|
<style>
|
|
body {
|
|
font-family: 'Sarabun', sans-serif;
|
|
background-color: #f1f5f9;
|
|
}
|
|
|
|
@media print {
|
|
@page {
|
|
size: A4;
|
|
margin: 5mm;
|
|
}
|
|
body, main {
|
|
background-color: white;
|
|
overflow: visible !important;
|
|
height: auto !important;
|
|
}
|
|
.no-print {
|
|
display: none !important;
|
|
}
|
|
.print-area {
|
|
padding: 0 !important;
|
|
margin: 0 !important;
|
|
width: 100% !important;
|
|
box-shadow: none !important;
|
|
overflow: visible !important;
|
|
}
|
|
.a4-page {
|
|
width: 100% !important;
|
|
margin: 0 !important;
|
|
padding: 5mm 10mm !important;
|
|
box-shadow: none !important;
|
|
min-height: auto !important;
|
|
}
|
|
.doc-table th, .doc-table td {
|
|
padding: 2px 4px !important;
|
|
}
|
|
table {
|
|
page-break-inside: auto;
|
|
}
|
|
tr {
|
|
page-break-inside: avoid;
|
|
page-break-after: auto;
|
|
}
|
|
}
|
|
|
|
.a4-page {
|
|
width: 210mm;
|
|
min-height: 297mm;
|
|
background: white;
|
|
margin: 0 auto;
|
|
padding: 20mm;
|
|
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.doc-table th, .doc-table td {
|
|
border: 1px solid #000;
|
|
padding: 2px 4px;
|
|
font-size: 12px;
|
|
line-height: 1.2;
|
|
}
|
|
.doc-table th {
|
|
text-align: center;
|
|
font-weight: bold;
|
|
-webkit-print-color-adjust: exact;
|
|
print-color-adjust: exact;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="flex h-screen overflow-hidden">
|
|
<!-- Sidebar -->
|
|
<aside class="w-64 bg-slate-800 text-white flex flex-col no-print">
|
|
<div class="p-4 bg-slate-900 font-bold text-lg flex items-center gap-2">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 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" />
|
|
</svg>
|
|
ระบบพิมพ์เอกสาร
|
|
</div>
|
|
<nav class="flex-1 overflow-y-auto py-4">
|
|
<ul class="space-y-1">
|
|
<li>
|
|
<a href="#" class="block px-4 py-2 bg-blue-600 text-white font-medium border-l-4 border-white">
|
|
บัญชีลงชื่อการปฏิบัติงาน
|
|
</a>
|
|
</li>
|
|
<!-- Future documents will be added here -->
|
|
</ul>
|
|
</nav>
|
|
<div class="p-4 border-t border-slate-700">
|
|
<button onclick="window.close()" class="w-full py-2 bg-slate-700 hover:bg-slate-600 rounded text-center text-sm transition-colors">
|
|
ปิดหน้าต่าง
|
|
</button>
|
|
</div>
|
|
</aside>
|
|
|
|
<!-- Main Content -->
|
|
<main class="flex-1 overflow-y-auto flex flex-col">
|
|
<!-- Topbar -->
|
|
<header class="bg-white shadow-sm p-4 flex justify-between items-center no-print">
|
|
<h1 class="text-xl font-bold text-slate-800" id="docTitle">บัญชีลงชื่อการปฏิบัติงาน</h1>
|
|
<div class="flex gap-2">
|
|
<button onclick="window.print()" class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded shadow flex items-center gap-2">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 17h2a2 2 0 002-2v-4a2 2 0 00-2-2H5a2 2 0 00-2 2v4a2 2 0 002 2h2m2 4h6a2 2 0 002-2v-4a2 2 0 00-2-2H9a2 2 0 00-2 2v4a2 2 0 002 2zm8-12V5a2 2 0 00-2-2H9a2 2 0 00-2 2v4h10z" />
|
|
</svg>
|
|
พิมพ์เอกสาร
|
|
</button>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Document Area -->
|
|
<div class="p-8 print-area flex-1 overflow-y-auto">
|
|
<div class="a4-page text-black" id="documentContent">
|
|
<!-- Data will be populated here -->
|
|
<div class="text-center mb-2 leading-tight">
|
|
<h2 class="font-bold text-[14px]">บัญชีลงชื่อการปฏิบัติงาน กลุ่มงาน/สุขภาพดิจิทัล</h2>
|
|
<h3 class="font-bold text-[14px]">ประจำวันที่ <span id="dateRangeDisplay"></span> เดือน <span id="monthDisplay"></span> พ.ศ. <span id="yearDisplay"></span></h3>
|
|
</div>
|
|
|
|
<table class="w-full doc-table border-collapse mb-8">
|
|
<thead>
|
|
<tr class="whitespace-nowrap bg-gray-100">
|
|
<th class="w-24">ว.ด.ป.</th>
|
|
<th class="w-64">ชื่อ - สกุล(ตัวบรรจง)</th>
|
|
<th class="w-24">ลายมือชื่อ</th>
|
|
<th class="w-20">เวลามา</th>
|
|
<th class="w-24">ลายมือชื่อ</th>
|
|
<th class="w-20">เวลากลับ</th>
|
|
<th>หมายเหตุ</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="tableBody">
|
|
<tr><td colspan="7" class="text-center py-4">กำลังโหลดข้อมูล...</td></tr>
|
|
</tbody>
|
|
</table>
|
|
|
|
<div class="flex justify-end mt-6 pr-12 text-[12px]">
|
|
<div class="text-center">
|
|
<div class="mb-2">ลงชื่อ .................................................... ผู้ควบคุมกำกับ</div>
|
|
<div contenteditable="true" class="hover:bg-gray-100 px-2 py-1 rounded inline-block outline-none min-w-[200px] text-center">(นางจิตติมา ทองนาค)</div>
|
|
<br>
|
|
<div contenteditable="true" class="hover:bg-gray-100 px-2 py-1 rounded inline-block outline-none min-w-[200px] text-center">นักวิชาการคอมพิวเตอร์ชำนาญการ</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<script>
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const qYear = parseInt(urlParams.get('year')) || new Date().getFullYear();
|
|
const urlMonth = parseInt(urlParams.get('month'));
|
|
const qMonth = !isNaN(urlMonth) ? urlMonth - 1 : new Date().getMonth();
|
|
|
|
const thaiMonths = [
|
|
"มกราคม", "กุมภาพันธ์", "มีนาคม", "เมษายน", "พฤษภาคม", "มิถุนายน",
|
|
"กรกฎาคม", "สิงหาคม", "กันยายน", "ตุลาคม", "พฤศจิกายน", "ธันวาคม"
|
|
];
|
|
const thaiMonthsShort = [
|
|
"ม.ค.", "ก.พ.", "มี.ค.", "เม.ย.", "พ.ค.", "มิ.ย.",
|
|
"ก.ค.", "ส.ค.", "ก.ย.", "ต.ค.", "พ.ย.", "ธ.ค."
|
|
];
|
|
|
|
document.getElementById('monthDisplay').textContent = thaiMonths[qMonth];
|
|
document.getElementById('yearDisplay').textContent = qYear + 543;
|
|
|
|
let staffList = [];
|
|
let scheduleData = {};
|
|
|
|
function getDaysInMonth(month, year) {
|
|
return new Date(year, month + 1, 0).getDate();
|
|
}
|
|
|
|
async function init() {
|
|
const daysInMonth = getDaysInMonth(qMonth, qYear);
|
|
document.getElementById('dateRangeDisplay').textContent = `1-${daysInMonth}`;
|
|
|
|
try {
|
|
// Fetch Staff
|
|
const staffRes = await fetch('api/staff.php');
|
|
const staffJson = await staffRes.json();
|
|
staffList = staffJson.data || [];
|
|
|
|
// Fetch Schedules (Database uses 1-12 for month)
|
|
const apiMonth = qMonth + 1;
|
|
const schedRes = await fetch(`api/schedules.php?year=${qYear}&month=${apiMonth}`);
|
|
const schedJson = await schedRes.json();
|
|
|
|
// Process schedule structure: scheduleData[day] = [staffIds]
|
|
const dailySchedules = {};
|
|
for (let d = 1; d <= daysInMonth; d++) {
|
|
dailySchedules[d] = [];
|
|
}
|
|
|
|
if (schedJson.data) {
|
|
for (const staffId in schedJson.data) {
|
|
for (const dayStr in schedJson.data[staffId]) {
|
|
const shift = schedJson.data[staffId][dayStr];
|
|
if (shift === 'ช' || shift === 'บ' || shift === 'ช/บ' || shift === 'ป') {
|
|
const day = parseInt(dayStr);
|
|
if (dailySchedules[day]) {
|
|
dailySchedules[day].push({ staffId: staffId, shift: shift });
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
renderTable(dailySchedules, daysInMonth);
|
|
} catch (err) {
|
|
console.error(err);
|
|
document.getElementById('tableBody').innerHTML = '<tr><td colspan="7" class="text-center text-red-600 py-4">เกิดข้อผิดพลาดในการโหลดข้อมูล</td></tr>';
|
|
}
|
|
}
|
|
|
|
function getStaffName(id) {
|
|
const staff = staffList.find(s => s.id == id);
|
|
return staff ? staff.name : 'ไม่ทราบชื่อ';
|
|
}
|
|
|
|
function renderTable(dailySchedules, daysInMonth) {
|
|
const tbody = document.getElementById('tableBody');
|
|
let html = '';
|
|
const yearShort = (qYear + 543).toString().substring(2);
|
|
|
|
let hasData = false;
|
|
|
|
for (let day = 1; day <= daysInMonth; day++) {
|
|
const dateStr = `${day.toString().padStart(2, '0')}-${thaiMonthsShort[qMonth]}-${yearShort}`;
|
|
const staffListOnDay = dailySchedules[day] || [];
|
|
|
|
if (staffListOnDay.length > 0) {
|
|
hasData = true;
|
|
staffListOnDay.forEach((record, index) => {
|
|
const staffName = getStaffName(record.staffId);
|
|
let timeIn = '';
|
|
let timeOut = '';
|
|
let note = '';
|
|
|
|
if (record.shift === 'ช') {
|
|
timeIn = '08.00';
|
|
timeOut = '16.00';
|
|
} else if (record.shift === 'บ') {
|
|
timeIn = '16.00';
|
|
timeOut = '24.00';
|
|
} else if (record.shift === 'ช/บ') {
|
|
timeIn = '08.00';
|
|
timeOut = '24.00';
|
|
} else if (record.shift === 'ป') {
|
|
timeIn = '08.00';
|
|
timeOut = '16.00';
|
|
note = 'ประชุม';
|
|
}
|
|
|
|
html += `
|
|
<tr class="whitespace-nowrap">
|
|
<td class="text-center">${dateStr}</td>
|
|
<td>
|
|
<div contenteditable="true" class="font-medium outline-none hover:bg-slate-100 rounded transition-colors">${staffName}</div>
|
|
</td>
|
|
<td></td>
|
|
<td class="text-center"><div contenteditable="true" class="outline-none hover:bg-slate-100 rounded">${timeIn}</div></td>
|
|
<td></td>
|
|
<td class="text-center"><div contenteditable="true" class="outline-none hover:bg-slate-100 rounded">${timeOut}</div></td>
|
|
<td><div contenteditable="true" class="outline-none hover:bg-slate-100 rounded w-full h-full min-h-[16px]">${note}</div></td>
|
|
</tr>
|
|
`;
|
|
});
|
|
}
|
|
}
|
|
|
|
if (!hasData) {
|
|
html = '<tr><td colspan="7" class="text-center py-8 text-slate-500">ไม่มีข้อมูลการปฏิบัติงานในเดือนนี้</td></tr>';
|
|
}
|
|
|
|
tbody.innerHTML = html;
|
|
}
|
|
|
|
init();
|
|
</script>
|
|
</body>
|
|
</html>
|