962 lines
40 KiB
PHP
962 lines
40 KiB
PHP
<?php
|
|
require_once '../includes/config.php';
|
|
|
|
// Check if user is logged in and is admin
|
|
if (!isset($_SESSION['logged_in']) || $_SESSION['logged_in'] !== true || $_SESSION['role'] !== 'admin') {
|
|
header('Location: ../auth/login.php');
|
|
exit();
|
|
}
|
|
|
|
$title = "Attendance Reports";
|
|
|
|
// Get filter parameters
|
|
$start_date = $_GET['start_date'] ?? date('Y-m-01'); // First day of current month
|
|
$end_date = $_GET['end_date'] ?? date('Y-m-t'); // Last day of current month
|
|
$activity_id = $_GET['activity_id'] ?? '';
|
|
$course_id = $_GET['course_id'] ?? '';
|
|
$department_id = $_GET['department_id'] ?? '';
|
|
$status = $_GET['status'] ?? '';
|
|
|
|
// Build SQL query with filters
|
|
$where_conditions = ["DATE(a.created_at) BETWEEN '$start_date' AND '$end_date'"];
|
|
$join_tables = "";
|
|
|
|
if ($activity_id) {
|
|
$where_conditions[] = "a.activity_id = " . intval($activity_id);
|
|
}
|
|
|
|
if ($course_id) {
|
|
$join_tables .= " LEFT JOIN students s ON a.student_id = s.id";
|
|
$where_conditions[] = "s.course_id = " . intval($course_id);
|
|
}
|
|
|
|
if ($department_id) {
|
|
if (strpos($join_tables, 'students s') === false) {
|
|
$join_tables .= " LEFT JOIN students s ON a.student_id = s.id";
|
|
}
|
|
$where_conditions[] = "s.department_id = " . intval($department_id);
|
|
}
|
|
|
|
if ($status && in_array($status, ['present', 'late', 'absent', 'excused'])) {
|
|
$where_conditions[] = "a.status = '$status'";
|
|
}
|
|
|
|
// Get attendance records - FIXED VERSION (walang created_by sa attendance table)
|
|
$attendance_records = [];
|
|
$where_clause = count($where_conditions) > 0 ? "WHERE " . implode(" AND ", $where_conditions) : "";
|
|
|
|
$sql = "SELECT
|
|
a.*,
|
|
s.student_id as student_number,
|
|
s.full_name as student_name,
|
|
s.year_level,
|
|
c.code as course_code,
|
|
c.name as course_name,
|
|
d.code as department_code,
|
|
d.name as department_name,
|
|
ac.name as activity_name,
|
|
ac.date as activity_date,
|
|
ac.time_in as activity_time_in,
|
|
ac.time_out as activity_time_out,
|
|
ac.location as activity_location
|
|
FROM attendance a
|
|
LEFT JOIN students s ON a.student_id = s.id
|
|
LEFT JOIN courses c ON s.course_id = c.id
|
|
LEFT JOIN departments d ON s.department_id = d.id
|
|
LEFT JOIN activities ac ON a.activity_id = ac.id
|
|
$join_tables
|
|
$where_clause
|
|
ORDER BY a.created_at DESC";
|
|
|
|
$result = query($conn, $sql);
|
|
while ($row = mysqli_fetch_assoc($result)) {
|
|
$attendance_records[] = $row;
|
|
}
|
|
|
|
// Get statistics
|
|
$stats = [
|
|
'total' => 0,
|
|
'present' => 0,
|
|
'late' => 0,
|
|
'absent' => 0,
|
|
'excused' => 0
|
|
];
|
|
|
|
foreach ($attendance_records as $record) {
|
|
$stats['total']++;
|
|
switch($record['status']) {
|
|
case 'present': $stats['present']++; break;
|
|
case 'late': $stats['late']++; break;
|
|
case 'absent': $stats['absent']++; break;
|
|
case 'excused': $stats['excused']++; break;
|
|
}
|
|
}
|
|
|
|
// Get filter dropdown data
|
|
$activities = [];
|
|
$courses = [];
|
|
$departments = [];
|
|
|
|
// All activities
|
|
$result = query($conn, "SELECT * FROM activities ORDER BY date DESC, name ASC");
|
|
while ($row = mysqli_fetch_assoc($result)) {
|
|
$activities[] = $row;
|
|
}
|
|
|
|
// All courses
|
|
$result = query($conn, "SELECT * FROM courses WHERE status = 1 ORDER BY code");
|
|
while ($row = mysqli_fetch_assoc($result)) {
|
|
$courses[] = $row;
|
|
}
|
|
|
|
// All departments
|
|
$result = query($conn, "SELECT * FROM departments WHERE status = 1 ORDER BY code");
|
|
while ($row = mysqli_fetch_assoc($result)) {
|
|
$departments[] = $row;
|
|
}
|
|
|
|
// Get daily attendance trend
|
|
$daily_trend = [];
|
|
$sql = "SELECT
|
|
DATE(created_at) as date,
|
|
COUNT(*) as total,
|
|
SUM(CASE WHEN status = 'present' THEN 1 ELSE 0 END) as present,
|
|
SUM(CASE WHEN status = 'late' THEN 1 ELSE 0 END) as late,
|
|
SUM(CASE WHEN status = 'absent' THEN 1 ELSE 0 END) as absent,
|
|
SUM(CASE WHEN status = 'excused' THEN 1 ELSE 0 END) as excused
|
|
FROM attendance
|
|
WHERE DATE(created_at) BETWEEN '$start_date' AND '$end_date'
|
|
GROUP BY DATE(created_at)
|
|
ORDER BY date ASC";
|
|
|
|
$result = query($conn, $sql);
|
|
while ($row = mysqli_fetch_assoc($result)) {
|
|
$daily_trend[] = $row;
|
|
}
|
|
|
|
// Get activity-wise statistics
|
|
$activity_stats = [];
|
|
$sql = "SELECT
|
|
ac.name as activity_name,
|
|
COUNT(a.id) as total_attendance,
|
|
SUM(CASE WHEN a.status = 'present' THEN 1 ELSE 0 END) as present,
|
|
SUM(CASE WHEN a.status = 'late' THEN 1 ELSE 0 END) as late,
|
|
ROUND((SUM(CASE WHEN a.status IN ('present', 'late') THEN 1 ELSE 0 END) * 100.0 / COUNT(a.id)), 1) as attendance_rate
|
|
FROM activities ac
|
|
LEFT JOIN attendance a ON ac.id = a.activity_id
|
|
WHERE ac.date BETWEEN '$start_date' AND '$end_date'
|
|
GROUP BY ac.id
|
|
ORDER BY ac.date DESC, ac.name ASC";
|
|
|
|
$result = query($conn, $sql);
|
|
while ($row = mysqli_fetch_assoc($result)) {
|
|
$activity_stats[] = $row;
|
|
}
|
|
|
|
// Get department-wise statistics
|
|
$department_stats = [];
|
|
$sql = "SELECT
|
|
d.code as department_code,
|
|
d.name as department_name,
|
|
COUNT(a.id) as total_attendance,
|
|
SUM(CASE WHEN a.status = 'present' THEN 1 ELSE 0 END) as present,
|
|
SUM(CASE WHEN a.status = 'late' THEN 1 ELSE 0 END) as late,
|
|
ROUND((SUM(CASE WHEN a.status IN ('present', 'late') THEN 1 ELSE 0 END) * 100.0 / COUNT(a.id)), 1) as attendance_rate
|
|
FROM departments d
|
|
LEFT JOIN students s ON d.id = s.department_id
|
|
LEFT JOIN attendance a ON s.id = a.student_id
|
|
WHERE DATE(a.created_at) BETWEEN '$start_date' AND '$end_date'
|
|
GROUP BY d.id
|
|
HAVING total_attendance > 0
|
|
ORDER BY attendance_rate DESC";
|
|
|
|
$result = query($conn, $sql);
|
|
while ($row = mysqli_fetch_assoc($result)) {
|
|
$department_stats[] = $row;
|
|
}
|
|
|
|
include '../includes/header.php';
|
|
?>
|
|
|
|
<!-- Page Header -->
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<div>
|
|
<h1 class="h3 mb-2">Attendance Reports</h1>
|
|
<p class="text-muted">View and analyze attendance data with detailed reports.</p>
|
|
</div>
|
|
<div>
|
|
<button class="btn btn-primary" onclick="printReport()">
|
|
<i class="bi bi-printer me-2"></i> Print Report
|
|
</button>
|
|
<button class="btn btn-success" onclick="exportToExcel()">
|
|
<i class="bi bi-download me-2"></i> Export Excel
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Filter Card -->
|
|
<div class="card shadow mb-4">
|
|
<div class="card-header">
|
|
<h6 class="m-0 font-weight-bold">
|
|
<i class="bi bi-funnel me-2"></i> Filter Reports
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<form method="GET" action="">
|
|
<div class="row">
|
|
<div class="col-md-3 mb-3">
|
|
<label class="form-label">Start Date</label>
|
|
<input type="date" class="form-control" name="start_date"
|
|
value="<?php echo $start_date; ?>" required>
|
|
</div>
|
|
<div class="col-md-3 mb-3">
|
|
<label class="form-label">End Date</label>
|
|
<input type="date" class="form-control" name="end_date"
|
|
value="<?php echo $end_date; ?>" required>
|
|
</div>
|
|
<div class="col-md-2 mb-3">
|
|
<label class="form-label">Activity</label>
|
|
<select class="form-select" name="activity_id">
|
|
<option value="">All Activities</option>
|
|
<?php foreach ($activities as $activity): ?>
|
|
<option value="<?php echo $activity['id']; ?>"
|
|
<?php echo $activity_id == $activity['id'] ? 'selected' : ''; ?>>
|
|
<?php echo $activity['name']; ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2 mb-3">
|
|
<label class="form-label">Course</label>
|
|
<select class="form-select" name="course_id">
|
|
<option value="">All Courses</option>
|
|
<?php foreach ($courses as $course): ?>
|
|
<option value="<?php echo $course['id']; ?>"
|
|
<?php echo $course_id == $course['id'] ? 'selected' : ''; ?>>
|
|
<?php echo $course['code']; ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2 mb-3">
|
|
<label class="form-label">Status</label>
|
|
<select class="form-select" name="status">
|
|
<option value="">All Status</option>
|
|
<option value="present" <?php echo $status == 'present' ? 'selected' : ''; ?>>Present</option>
|
|
<option value="late" <?php echo $status == 'late' ? 'selected' : ''; ?>>Late</option>
|
|
<option value="absent" <?php echo $status == 'absent' ? 'selected' : ''; ?>>Absent</option>
|
|
<option value="excused" <?php echo $status == 'excused' ? 'selected' : ''; ?>>Excused</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-3 mb-3">
|
|
<label class="form-label">Department</label>
|
|
<select class="form-select" name="department_id">
|
|
<option value="">All Departments</option>
|
|
<?php foreach ($departments as $department): ?>
|
|
<option value="<?php echo $department['id']; ?>"
|
|
<?php echo $department_id == $department['id'] ? 'selected' : ''; ?>>
|
|
<?php echo $department['name']; ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-9 d-flex align-items-end justify-content-end">
|
|
<button type="submit" class="btn btn-primary me-2">
|
|
<i class="bi bi-filter me-1"></i> Apply Filters
|
|
</button>
|
|
<a href="reports.php" class="btn btn-secondary">
|
|
<i class="bi bi-x-circle me-1"></i> Clear Filters
|
|
</a>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Statistics Cards -->
|
|
<div class="row mb-4">
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card stat-card border-left-primary">
|
|
<div class="card-body">
|
|
<div class="row align-items-center">
|
|
<div class="col-8">
|
|
<div class="text-uppercase text-primary mb-1">Total Records</div>
|
|
<div class="h2 font-weight-bold"><?php echo $stats['total']; ?></div>
|
|
<div class="text-muted">Attendance records</div>
|
|
</div>
|
|
<div class="col-4 text-end">
|
|
<i class="bi bi-clipboard-data text-primary" style="font-size: 3rem; opacity: 0.7;"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card stat-card border-left-success">
|
|
<div class="card-body">
|
|
<div class="row align-items-center">
|
|
<div class="col-8">
|
|
<div class="text-uppercase text-success mb-1">Present</div>
|
|
<div class="h2 font-weight-bold"><?php echo $stats['present']; ?></div>
|
|
<div class="text-muted">On-time attendance</div>
|
|
</div>
|
|
<div class="col-4 text-end">
|
|
<i class="bi bi-check-circle-fill text-success" style="font-size: 3rem; opacity: 0.7;"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card stat-card border-left-warning">
|
|
<div class="card-body">
|
|
<div class="row align-items-center">
|
|
<div class="col-8">
|
|
<div class="text-uppercase text-warning mb-1">Late</div>
|
|
<div class="h2 font-weight-bold"><?php echo $stats['late']; ?></div>
|
|
<div class="text-muted">Late arrivals</div>
|
|
</div>
|
|
<div class="col-4 text-end">
|
|
<i class="bi bi-clock-history text-warning" style="font-size: 3rem; opacity: 0.7;"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-xl-3 col-md-6 mb-4">
|
|
<div class="card stat-card border-left-danger">
|
|
<div class="card-body">
|
|
<div class="row align-items-center">
|
|
<div class="col-8">
|
|
<div class="text-uppercase text-danger mb-1">Absent</div>
|
|
<div class="h2 font-weight-bold"><?php echo $stats['absent']; ?></div>
|
|
<div class="text-muted">No attendance</div>
|
|
</div>
|
|
<div class="col-4 text-end">
|
|
<i class="bi bi-x-circle-fill text-danger" style="font-size: 3rem; opacity: 0.7;"></i>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Charts Section -->
|
|
<div class="row mb-4">
|
|
<!-- Attendance Summary Chart -->
|
|
<div class="col-lg-6">
|
|
<div class="card shadow h-100">
|
|
<div class="card-header">
|
|
<h6 class="m-0 font-weight-bold">
|
|
<i class="bi bi-pie-chart me-2"></i> Attendance Summary
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="chart-container" style="position: relative; height: 300px;">
|
|
<canvas id="attendanceChart"></canvas>
|
|
</div>
|
|
<div class="row mt-3 text-center">
|
|
<div class="col-3">
|
|
<div class="text-success">
|
|
<i class="bi bi-check-circle"></i>
|
|
<div class="h5 mb-0"><?php echo $stats['present']; ?></div>
|
|
<small>Present</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-3">
|
|
<div class="text-warning">
|
|
<i class="bi bi-clock-history"></i>
|
|
<div class="h5 mb-0"><?php echo $stats['late']; ?></div>
|
|
<small>Late</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-3">
|
|
<div class="text-danger">
|
|
<i class="bi bi-x-circle"></i>
|
|
<div class="h5 mb-0"><?php echo $stats['absent']; ?></div>
|
|
<small>Absent</small>
|
|
</div>
|
|
</div>
|
|
<div class="col-3">
|
|
<div class="text-info">
|
|
<i class="bi bi-calendar-check"></i>
|
|
<div class="h5 mb-0"><?php echo $stats['excused']; ?></div>
|
|
<small>Excused</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Daily Trend Chart -->
|
|
<div class="col-lg-6">
|
|
<div class="card shadow h-100">
|
|
<div class="card-header">
|
|
<h6 class="m-0 font-weight-bold">
|
|
<i class="bi bi-bar-chart me-2"></i> Daily Attendance Trend
|
|
</h6>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="chart-container" style="position: relative; height: 300px;">
|
|
<canvas id="dailyTrendChart"></canvas>
|
|
</div>
|
|
<div class="text-center mt-3">
|
|
<small class="text-muted">
|
|
<?php echo date('F j, Y', strtotime($start_date)); ?> to
|
|
<?php echo date('F j, Y', strtotime($end_date)); ?>
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Activity Statistics Table -->
|
|
<div class="card shadow mb-4">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h6 class="m-0 font-weight-bold">
|
|
<i class="bi bi-calendar-event me-2"></i> Activity-wise Statistics
|
|
</h6>
|
|
<button class="btn btn-sm btn-outline-primary" onclick="toggleActivityStats()">
|
|
<i class="bi bi-chevron-down"></i>
|
|
</button>
|
|
</div>
|
|
<div class="card-body" id="activityStatsBody">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0" id="activityStatsTable">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Activity</th>
|
|
<th>Total</th>
|
|
<th>Present</th>
|
|
<th>Late</th>
|
|
<th>Attendance Rate</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($activity_stats)): ?>
|
|
<tr>
|
|
<td colspan="6" class="text-center py-4">
|
|
<i class="bi bi-calendar-x text-muted" style="font-size: 3rem;"></i>
|
|
<p class="mt-2">No activity data for selected period</p>
|
|
</td>
|
|
</tr>
|
|
<?php else: ?>
|
|
<?php foreach ($activity_stats as $stat): ?>
|
|
<tr>
|
|
<td>
|
|
<strong><?php echo $stat['activity_name']; ?></strong>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-info"><?php echo $stat['total_attendance']; ?></span>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-success"><?php echo $stat['present']; ?></span>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-warning"><?php echo $stat['late']; ?></span>
|
|
</td>
|
|
<td>
|
|
<div class="d-flex align-items-center">
|
|
<div class="progress flex-grow-1 me-2" style="height: 8px;">
|
|
<div class="progress-bar progress-bar-striped"
|
|
role="progressbar"
|
|
style="width: <?php echo $stat['attendance_rate']; ?>%">
|
|
</div>
|
|
</div>
|
|
<span><?php echo $stat['attendance_rate']; ?>%</span>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<?php
|
|
$activity_id_for_link = '';
|
|
foreach ($activities as $activity) {
|
|
if ($activity['name'] == $stat['activity_name']) {
|
|
$activity_id_for_link = $activity['id'];
|
|
break;
|
|
}
|
|
}
|
|
if ($activity_id_for_link): ?>
|
|
<a href="reports.php?activity_id=<?php echo $activity_id_for_link; ?>&start_date=<?php echo $start_date; ?>&end_date=<?php echo $end_date; ?>"
|
|
class="btn btn-sm btn-info">
|
|
<i class="bi bi-eye"></i> View
|
|
</a>
|
|
<?php endif; ?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Department Statistics Table -->
|
|
<div class="card shadow mb-4">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h6 class="m-0 font-weight-bold">
|
|
<i class="bi bi-building me-2"></i> Department Performance
|
|
</h6>
|
|
<button class="btn btn-sm btn-outline-primary" onclick="toggleDepartmentStats()">
|
|
<i class="bi bi-chevron-down"></i>
|
|
</button>
|
|
</div>
|
|
<div class="card-body" id="departmentStatsBody">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0" id="departmentStatsTable">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Department</th>
|
|
<th>Total</th>
|
|
<th>Present</th>
|
|
<th>Late</th>
|
|
<th>Attendance Rate</th>
|
|
<th>Performance</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($department_stats)): ?>
|
|
<tr>
|
|
<td colspan="6" class="text-center py-4">
|
|
<i class="bi bi-building text-muted" style="font-size: 3rem;"></i>
|
|
<p class="mt-2">No department data for selected period</p>
|
|
</td>
|
|
</tr>
|
|
<?php else: ?>
|
|
<?php foreach ($department_stats as $stat): ?>
|
|
<tr>
|
|
<td>
|
|
<strong><?php echo $stat['department_name']; ?></strong><br>
|
|
<small class="text-muted"><?php echo $stat['department_code']; ?></small>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-info"><?php echo $stat['total_attendance']; ?></span>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-success"><?php echo $stat['present']; ?></span>
|
|
</td>
|
|
<td>
|
|
<span class="badge bg-warning"><?php echo $stat['late']; ?></span>
|
|
</td>
|
|
<td>
|
|
<div class="d-flex align-items-center">
|
|
<div class="progress flex-grow-1 me-2" style="height: 8px;">
|
|
<div class="progress-bar progress-bar-striped"
|
|
role="progressbar"
|
|
style="width: <?php echo $stat['attendance_rate']; ?>%">
|
|
</div>
|
|
</div>
|
|
<span><?php echo $stat['attendance_rate']; ?>%</span>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<?php
|
|
$rate = floatval($stat['attendance_rate']);
|
|
if ($rate >= 90) {
|
|
echo '<span class="badge bg-success">Excellent</span>';
|
|
} elseif ($rate >= 80) {
|
|
echo '<span class="badge bg-info">Good</span>';
|
|
} elseif ($rate >= 70) {
|
|
echo '<span class="badge bg-warning">Fair</span>';
|
|
} else {
|
|
echo '<span class="badge bg-danger">Poor</span>';
|
|
}
|
|
?>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Detailed Attendance Records -->
|
|
<div class="card shadow">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h6 class="m-0 font-weight-bold">
|
|
<i class="bi bi-list-ul me-2"></i> Detailed Attendance Records
|
|
<span class="badge bg-primary ms-2"><?php echo count($attendance_records); ?></span>
|
|
</h6>
|
|
<div>
|
|
<input type="text" id="searchRecords" class="form-control form-control-sm me-2"
|
|
placeholder="Search records..." style="width: 200px;">
|
|
</div>
|
|
</div>
|
|
<div class="card-body p-0">
|
|
<div class="table-responsive">
|
|
<table class="table table-hover mb-0" id="attendanceRecordsTable">
|
|
<thead class="table-light">
|
|
<tr>
|
|
<th>Student</th>
|
|
<th>Activity</th>
|
|
<th>Date & Time</th>
|
|
<th>Time In/Out</th>
|
|
<th>Status</th>
|
|
<th>Course</th>
|
|
<th>Recorded By</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($attendance_records)): ?>
|
|
<tr>
|
|
<td colspan="7" class="text-center py-4">
|
|
<i class="bi bi-clipboard-x text-muted" style="font-size: 3rem;"></i>
|
|
<p class="mt-2">No attendance records found for the selected filters</p>
|
|
</td>
|
|
</tr>
|
|
<?php else: ?>
|
|
<?php foreach ($attendance_records as $record): ?>
|
|
<tr>
|
|
<td>
|
|
<div class="d-flex align-items-center">
|
|
<div class="avatar me-3">
|
|
<div class="bg-primary rounded-circle p-2 text-white">
|
|
<i class="bi bi-person"></i>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<strong><?php echo $record['student_name']; ?></strong><br>
|
|
<small class="text-muted"><?php echo $record['student_number']; ?></small>
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div class="fw-bold"><?php echo $record['activity_name']; ?></div>
|
|
<small class="text-muted">
|
|
<i class="bi bi-geo-alt"></i> <?php echo $record['activity_location']; ?>
|
|
</small>
|
|
</td>
|
|
<td>
|
|
<div class="fw-bold"><?php echo date('M d, Y', strtotime($record['created_at'])); ?></div>
|
|
<small class="text-muted"><?php echo date('h:i A', strtotime($record['created_at'])); ?></small>
|
|
</td>
|
|
<td>
|
|
<div class="d-flex flex-column">
|
|
<?php if ($record['time_in']): ?>
|
|
<small>
|
|
<i class="bi bi-box-arrow-in-right text-success"></i>
|
|
<?php echo date('h:i A', strtotime($record['time_in'])); ?>
|
|
</small>
|
|
<?php endif; ?>
|
|
<?php if ($record['time_out']): ?>
|
|
<small>
|
|
<i class="bi bi-box-arrow-left text-danger"></i>
|
|
<?php echo date('h:i A', strtotime($record['time_out'])); ?>
|
|
</small>
|
|
<?php endif; ?>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<?php
|
|
$status = $record['status'] ?? 'pending';
|
|
$badge_class = 'secondary';
|
|
$icon = 'clock';
|
|
|
|
switch($status) {
|
|
case 'present':
|
|
$badge_class = 'success';
|
|
$icon = 'check-circle';
|
|
break;
|
|
case 'late':
|
|
$badge_class = 'warning';
|
|
$icon = 'clock-history';
|
|
break;
|
|
case 'absent':
|
|
$badge_class = 'danger';
|
|
$icon = 'x-circle';
|
|
break;
|
|
case 'excused':
|
|
$badge_class = 'info';
|
|
$icon = 'calendar-check';
|
|
break;
|
|
default:
|
|
$badge_class = 'secondary';
|
|
$icon = 'clock';
|
|
}
|
|
?>
|
|
<span class="badge bg-<?php echo $badge_class; ?>">
|
|
<i class="bi bi-<?php echo $icon; ?> me-1"></i>
|
|
<?php echo ucfirst($status); ?>
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<div class="fw-bold"><?php echo $record['course_code']; ?></div>
|
|
<small class="text-muted">Year <?php echo $record['year_level']; ?></small>
|
|
</td>
|
|
<td>
|
|
<small>QR System</small>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<div class="card-footer">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<small class="text-muted">
|
|
Showing <?php echo count($attendance_records); ?> record(s)
|
|
</small>
|
|
</div>
|
|
<div class="col-md-6 text-md-end">
|
|
<small class="text-muted">
|
|
Generated: <?php echo date('F j, Y h:i A'); ?>
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Print Modal -->
|
|
<div class="modal fade" id="printModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Print Preview</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body" id="printContent">
|
|
<!-- Print content will be loaded here -->
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="button" class="btn btn-primary" onclick="window.print()">
|
|
<i class="bi bi-printer me-1"></i> Print
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php
|
|
// Include Chart.js library
|
|
$page_scripts = '
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Initialize DataTables
|
|
$("#activityStatsTable").DataTable({
|
|
pageLength: 5,
|
|
lengthMenu: [[5, 10, 25, -1], [5, 10, 25, "All"]],
|
|
order: [[4, "desc"]],
|
|
responsive: true
|
|
});
|
|
|
|
$("#departmentStatsTable").DataTable({
|
|
pageLength: 5,
|
|
lengthMenu: [[5, 10, 25, -1], [5, 10, 25, "All"]],
|
|
order: [[4, "desc"]],
|
|
responsive: true
|
|
});
|
|
|
|
$("#attendanceRecordsTable").DataTable({
|
|
pageLength: 10,
|
|
lengthMenu: [[10, 25, 50, -1], [10, 25, 50, "All"]],
|
|
order: [[2, "desc"]],
|
|
responsive: true
|
|
});
|
|
|
|
// Search functionality
|
|
$("#searchRecords").on("keyup", function() {
|
|
$("#attendanceRecordsTable").DataTable().search($(this).val()).draw();
|
|
});
|
|
|
|
// Initialize charts
|
|
initializeCharts();
|
|
});
|
|
|
|
// Initialize Charts
|
|
function initializeCharts() {
|
|
// Attendance Summary Chart (Pie Chart)
|
|
const ctx1 = document.getElementById("attendanceChart").getContext("2d");
|
|
new Chart(ctx1, {
|
|
type: "pie",
|
|
data: {
|
|
labels: ["Present", "Late", "Absent", "Excused"],
|
|
datasets: [{
|
|
data: [' . $stats['present'] . ', ' . $stats['late'] . ', ' . $stats['absent'] . ', ' . $stats['excused'] . '],
|
|
backgroundColor: [
|
|
"#28a745",
|
|
"#ffc107",
|
|
"#dc3545",
|
|
"#17a2b8"
|
|
],
|
|
borderWidth: 1
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
position: "bottom"
|
|
},
|
|
tooltip: {
|
|
callbacks: {
|
|
label: function(context) {
|
|
let label = context.label || "";
|
|
if (label) {
|
|
label += ": ";
|
|
}
|
|
label += context.parsed + " (" + Math.round((context.parsed / ' . $stats['total'] . ') * 100) + "%)";
|
|
return label;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
// Daily Trend Chart (Line Chart)
|
|
const ctx2 = document.getElementById("dailyTrendChart").getContext("2d");
|
|
const dates = ' . json_encode(array_column($daily_trend, "date")) . ';
|
|
const presentData = ' . json_encode(array_column($daily_trend, "present")) . ';
|
|
const lateData = ' . json_encode(array_column($daily_trend, "late")) . ';
|
|
const totalData = ' . json_encode(array_column($daily_trend, "total")) . ';
|
|
|
|
new Chart(ctx2, {
|
|
type: "line",
|
|
data: {
|
|
labels: dates.map(date => new Date(date).toLocaleDateString("en-US", { month: "short", day: "numeric" })),
|
|
datasets: [
|
|
{
|
|
label: "Total Attendance",
|
|
data: totalData,
|
|
borderColor: "#3498db",
|
|
backgroundColor: "rgba(52, 152, 219, 0.1)",
|
|
fill: true,
|
|
tension: 0.4
|
|
},
|
|
{
|
|
label: "Present",
|
|
data: presentData,
|
|
borderColor: "#28a745",
|
|
backgroundColor: "rgba(40, 167, 69, 0.1)",
|
|
fill: true,
|
|
tension: 0.4
|
|
},
|
|
{
|
|
label: "Late",
|
|
data: lateData,
|
|
borderColor: "#ffc107",
|
|
backgroundColor: "rgba(255, 193, 7, 0.1)",
|
|
fill: true,
|
|
tension: 0.4
|
|
}
|
|
]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
plugins: {
|
|
legend: {
|
|
position: "bottom"
|
|
}
|
|
},
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
title: {
|
|
display: true,
|
|
text: "Number of Students"
|
|
}
|
|
},
|
|
x: {
|
|
title: {
|
|
display: true,
|
|
text: "Date"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Toggle sections
|
|
function toggleActivityStats() {
|
|
$("#activityStatsBody").slideToggle();
|
|
}
|
|
|
|
function toggleDepartmentStats() {
|
|
$("#departmentStatsBody").slideToggle();
|
|
}
|
|
|
|
// Print report - Simple version
|
|
function printReport() {
|
|
window.print();
|
|
}
|
|
|
|
// Export to Excel
|
|
function exportToExcel() {
|
|
showLoader("Preparing Excel export...");
|
|
|
|
const params = new URLSearchParams({
|
|
start_date: "' . $start_date . '",
|
|
end_date: "' . $end_date . '",
|
|
activity_id: "' . $activity_id . '",
|
|
course_id: "' . $course_id . '",
|
|
department_id: "' . $department_id . '",
|
|
status: "' . $status . '"
|
|
});
|
|
|
|
fetch(`../api/export_reports.php?${params}`)
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
hideLoader();
|
|
if (data.success) {
|
|
window.open(data.download_url, "_blank");
|
|
showNotification("Export completed successfully!", "success");
|
|
} else {
|
|
showNotification("Error: " + data.message, "danger");
|
|
}
|
|
})
|
|
.catch(error => {
|
|
hideLoader();
|
|
showNotification("Export failed: " + error, "danger");
|
|
});
|
|
}
|
|
|
|
// Quick filter buttons
|
|
function filterToday() {
|
|
const today = new Date().toISOString().split("T")[0];
|
|
window.location.href = `reports.php?start_date=${today}&end_date=${today}`;
|
|
}
|
|
|
|
function filterThisWeek() {
|
|
const today = new Date();
|
|
const firstDay = new Date(today.setDate(today.getDate() - today.getDay()));
|
|
const lastDay = new Date(today.setDate(today.getDate() - today.getDay() + 6));
|
|
|
|
const start = firstDay.toISOString().split("T")[0];
|
|
const end = lastDay.toISOString().split("T")[0];
|
|
|
|
window.location.href = `reports.php?start_date=${start}&end_date=${end}`;
|
|
}
|
|
|
|
function filterThisMonth() {
|
|
const today = new Date();
|
|
const firstDay = new Date(today.getFullYear(), today.getMonth(), 1);
|
|
const lastDay = new Date(today.getFullYear(), today.getMonth() + 1, 0);
|
|
|
|
const start = firstDay.toISOString().split("T")[0];
|
|
const end = lastDay.toISOString().split("T")[0];
|
|
|
|
window.location.href = `reports.php?start_date=${start}&end_date=${end}`;
|
|
}
|
|
</script>
|
|
';
|
|
|
|
include '../includes/footer.php';
|
|
?>
|