440 lines
19 KiB
PHP
440 lines
19 KiB
PHP
@extends('layouts.master')
|
|
|
|
@section('css')
|
|
<!-- DataTables -->
|
|
<link href="{{ URL::asset('plugins/datatables/dataTables.bootstrap4.min.css') }}" rel="stylesheet" type="text/css" />
|
|
<link href="{{ URL::asset('plugins/datatables/buttons.bootstrap4.min.css') }}" rel="stylesheet" type="text/css" />
|
|
<link href="{{ URL::asset('plugins/datatables/responsive.bootstrap4.min.css') }}" rel="stylesheet" type="text/css" />
|
|
<style>
|
|
.filter-section {
|
|
display: flex;
|
|
align-items: flex-end;
|
|
gap: 20px;
|
|
margin-bottom: 20px;
|
|
}
|
|
.filter-section .form-group {
|
|
flex: 1;
|
|
margin-bottom: 0;
|
|
}
|
|
.filter-section label {
|
|
font-weight: 500;
|
|
margin-bottom: 8px;
|
|
}
|
|
.filter-section .btn {
|
|
height: 38px;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
}
|
|
.search-box {
|
|
position: relative;
|
|
margin-left: auto;
|
|
width: 250px;
|
|
}
|
|
.search-box input {
|
|
width: 100%;
|
|
padding: 8px 15px;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.dt-button {
|
|
background-color: #fff;
|
|
border: 1px solid #ddd;
|
|
border-radius: 4px;
|
|
padding: 5px;
|
|
display: inline-flex;
|
|
gap: 1px;
|
|
}
|
|
.swal2-image-custom {
|
|
max-width: 400px;
|
|
max-height: 400px;
|
|
width: auto;
|
|
height: auto;
|
|
}
|
|
.badge-success {
|
|
background-color: #28a745;
|
|
}
|
|
.badge-danger {
|
|
background-color: #dc3545;
|
|
}
|
|
.badge-warning {
|
|
background-color: #ffc107;
|
|
color: #212529;
|
|
}
|
|
.badge-info {
|
|
background-color: #17a2b8;
|
|
}
|
|
</style>
|
|
@endsection
|
|
|
|
@section('breadcrumb')
|
|
<div class="col-sm-6">
|
|
<h4 class="page-title text-left">Rekap Data Presensi</h4>
|
|
<ol class="breadcrumb">
|
|
<li class="breadcrumb-item"><a href="javascript:void(0);">Home</a></li>
|
|
<li class="breadcrumb-item active">Rekap Data</li>
|
|
</ol>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('content')
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<!-- Filter Section -->
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<div class="filter-section">
|
|
<div class="form-group">
|
|
<label for="month">Bulan</label>
|
|
<input type="month" class="form-control" id="month" value="{{ request('month', date('Y-m')) }}">
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="status">Status</label>
|
|
<select class="form-control" id="status">
|
|
<option value="">Semua Status</option>
|
|
<option value="Hadir" {{ request('status') == 'Hadir' ? 'selected' : '' }}>Hadir</option>
|
|
<option value="Terlambat" {{ request('status') == 'Terlambat' ? 'selected' : '' }}>Terlambat</option>
|
|
<option value="Sakit" {{ request('status') == 'Sakit' ? 'selected' : '' }}>Sakit</option>
|
|
<option value="Izin" {{ request('status') == 'Izin' ? 'selected' : '' }}>Izin</option>
|
|
</select>
|
|
</div>
|
|
<button type="button" class="btn btn-primary" id="filter-btn">
|
|
<i class="fas fa-filter"></i> Filter
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Summary Cards -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="card bg-primary text-white">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Hadir Bulan Ini</h5>
|
|
<h3 class="card-text" id="total-hadir">{{ $hadir }}</h3>
|
|
<small id="date-display">{{ Carbon\Carbon::now()->format('F Y') }}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-warning text-white">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Sakit Bulan Ini</h5>
|
|
<h3 class="card-text" id="total-sakit">{{ $sakit }}</h3>
|
|
<small id="date-display-sakit">{{ Carbon\Carbon::now()->format('F Y') }}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="card bg-info text-white">
|
|
<div class="card-body">
|
|
<h5 class="card-title">Izin Bulan Ini</h5>
|
|
<h3 class="card-text" id="total-izin">{{ $izin }}</h3>
|
|
<small id="date-display-izin">{{ Carbon\Carbon::now()->format('F Y') }}</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Data Table -->
|
|
<div class="table-responsive">
|
|
<table id="rekap-table" class="table table-bordered table-striped dt-responsive nowrap">
|
|
<thead class="thead-light">
|
|
<tr>
|
|
<th>No</th>
|
|
<th>Tanggal</th>
|
|
<th>Nama</th>
|
|
<th>Status</th>
|
|
<th>Clock In</th>
|
|
<th>Clock Out</th>
|
|
<th>Keterangan</th>
|
|
<th>Dokumen</th>
|
|
<th>Aksi</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@php
|
|
$no = 1;
|
|
$groupedData = [];
|
|
@endphp
|
|
|
|
@foreach($presensis as $presensi)
|
|
@php
|
|
$date = $presensi->created_at->format('Y-m-d');
|
|
$userId = $presensi->user_id;
|
|
$key = $date . '_' . $userId;
|
|
|
|
if (!isset($groupedData[$key])) {
|
|
$groupedData[$key] = [
|
|
'date' => $presensi->created_at,
|
|
'user' => $presensi->user,
|
|
'status' => $presensi->status,
|
|
'keterangan' => $presensi->keterangan,
|
|
'clock_in' => null,
|
|
'clock_out' => null,
|
|
'foto' => $presensi->foto,
|
|
'file_pdf' => $presensi->file_pdf,
|
|
'id' => $presensi->id
|
|
];
|
|
}
|
|
|
|
if ($presensi->clock_type == 'in') {
|
|
$groupedData[$key]['clock_in'] = $presensi->created_at;
|
|
} else {
|
|
$groupedData[$key]['clock_out'] = $presensi->created_at;
|
|
}
|
|
@endphp
|
|
@endforeach
|
|
|
|
@forelse($groupedData as $key => $data)
|
|
<tr>
|
|
<td>{{ $no++ }}</td>
|
|
<td>{{ $data['date']->format('d-m-Y') }}</td>
|
|
<td>{{ $data['user']->name }}</td>
|
|
<td>
|
|
@if($data['status'] == 'Hadir' || $data['status'] == 'Masuk')
|
|
<span class="badge badge-success">Hadir</span>
|
|
@elseif($data['status'] == 'Terlambat')
|
|
<span class="badge badge-danger">Terlambat</span>
|
|
@elseif($data['status'] == 'Sakit')
|
|
<span class="badge badge-warning">Sakit</span>
|
|
@elseif($data['status'] == 'Izin')
|
|
<span class="badge badge-info">Izin</span>
|
|
@endif
|
|
</td>
|
|
<td>
|
|
@if($data['clock_in'])
|
|
{{ $data['clock_in']->format('H:i:s') }}
|
|
@else
|
|
-
|
|
@endif
|
|
</td>
|
|
<td>
|
|
@if($data['clock_out'])
|
|
{{ $data['clock_out']->format('H:i:s') }}
|
|
@else
|
|
-
|
|
@endif
|
|
</td>
|
|
<td>{{ $data['keterangan'] }}</td>
|
|
<td>
|
|
@if($data['foto'])
|
|
<button type="button" class="btn btn-info btn-sm" onclick="showPhoto('{{ asset('presensi/' . $data['foto']) }}')">
|
|
<i class="fas fa-eye"></i> Foto
|
|
</button>
|
|
@endif
|
|
@if($data['file_pdf'])
|
|
<a href="{{ asset('storage/' . $data['file_pdf']) }}" target="_blank" class="btn btn-info btn-sm">
|
|
<i class="fas fa-file-pdf"></i> PDF
|
|
</a>
|
|
@endif
|
|
</td>
|
|
<td>
|
|
<form action="{{ route('attendance.destroy', $data['id']) }}" method="POST" style="display: inline-block;" id="delete-form-{{ $data['id'] }}">
|
|
@csrf
|
|
@method('DELETE')
|
|
<button type="button" class="btn btn-danger btn-sm" onclick="confirmDelete({{ $data['id'] }})">
|
|
<i class="fas fa-trash"></i> Hapus
|
|
</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="9" class="text-center">
|
|
Tidak ada data presensi untuk ditampilkan
|
|
</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('script')
|
|
<!-- Required datatable js -->
|
|
<script src="{{ URL::asset('plugins/datatables/jquery.dataTables.min.js') }}"></script>
|
|
<script src="{{ URL::asset('plugins/datatables/dataTables.bootstrap4.min.js') }}"></script>
|
|
<!-- Buttons examples -->
|
|
<script src="{{ URL::asset('plugins/datatables/dataTables.buttons.min.js') }}"></script>
|
|
<script src="{{ URL::asset('plugins/datatables/buttons.bootstrap4.min.js') }}"></script>
|
|
<script src="{{ URL::asset('plugins/datatables/jszip.min.js') }}"></script>
|
|
<script src="{{ URL::asset('plugins/datatables/pdfmake.min.js') }}"></script>
|
|
<script src="{{ URL::asset('plugins/datatables/vfs_fonts.js') }}"></script>
|
|
<script src="{{ URL::asset('plugins/datatables/buttons.html5.min.js') }}"></script>
|
|
<script src="{{ URL::asset('plugins/datatables/buttons.print.min.js') }}"></script>
|
|
<!-- Sweet-Alert -->
|
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
|
<!-- Moment.js -->
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
|
|
|
|
<script>
|
|
$(document).ready(function() {
|
|
// Initialize DataTable
|
|
let table = $('#rekap-table').DataTable({
|
|
dom: 'Bfrtip',
|
|
buttons: [
|
|
{
|
|
extend: 'copy',
|
|
text: '<i class="fas fa-copy"></i> Copy',
|
|
className: 'dt-button buttons-copy',
|
|
exportOptions: {
|
|
columns: [0,1,2,3,4,5,6]
|
|
}
|
|
},
|
|
{
|
|
extend: 'excel',
|
|
text: '<i class="fas fa-file-excel"></i> Excel',
|
|
className: 'dt-button buttons-excel',
|
|
title: 'Rekap Data Presensi - ' + moment($('#month').val()).format('MMMM YYYY'),
|
|
exportOptions: {
|
|
columns: [0,1,2,3,4,5,6]
|
|
}
|
|
},
|
|
{
|
|
extend: 'pdf',
|
|
text: '<i class="fas fa-file-pdf"></i> PDF',
|
|
className: 'dt-button buttons-pdf',
|
|
title: 'Rekap Data Presensi - ' + moment($('#month').val()).format('MMMM YYYY'),
|
|
exportOptions: {
|
|
columns: [0,1,2,3,4,5,6]
|
|
},
|
|
orientation: 'landscape'
|
|
}
|
|
],
|
|
order: [[1, 'desc']],
|
|
pageLength: 10,
|
|
language: {
|
|
search: "Cari:",
|
|
lengthMenu: "Tampilkan _MENU_ data per halaman",
|
|
zeroRecords: "Data tidak ditemukan",
|
|
info: "Menampilkan _START_ sampai _END_ dari _TOTAL_ data",
|
|
infoEmpty: "Menampilkan 0 sampai 0 dari 0 data",
|
|
infoFiltered: "(disaring dari _MAX_ total data)",
|
|
paginate: {
|
|
first: "Pertama",
|
|
last: "Terakhir",
|
|
next: "Selanjutnya",
|
|
previous: "Sebelumnya"
|
|
}
|
|
}
|
|
});
|
|
|
|
// Filter button click handler
|
|
$('#filter-btn').click(function() {
|
|
let selectedMonth = $('#month').val();
|
|
let selectedStatus = $('#status').val();
|
|
|
|
// Build URL with parameters
|
|
let url = '{{ route("admin.reports") }}';
|
|
let params = new URLSearchParams();
|
|
|
|
if (selectedMonth) {
|
|
params.append('month', selectedMonth);
|
|
}
|
|
if (selectedStatus) {
|
|
params.append('status', selectedStatus);
|
|
}
|
|
|
|
// Redirect to filtered URL
|
|
window.location.href = url + '?' + params.toString();
|
|
});
|
|
|
|
// Update summary cards when month changes
|
|
$('#month').change(function() {
|
|
updateSummaryCards();
|
|
});
|
|
|
|
// Function to update summary cards
|
|
function updateSummaryCards() {
|
|
let selectedMonth = $('#month').val();
|
|
|
|
$.ajax({
|
|
url: '{{ route("admin.reports.summary") }}',
|
|
type: 'GET',
|
|
data: {
|
|
month: selectedMonth
|
|
},
|
|
success: function(response) {
|
|
if (response.success) {
|
|
$('#total-hadir').text(response.data.hadir || 0);
|
|
$('#total-sakit').text(response.data.sakit || 0);
|
|
$('#total-izin').text(response.data.izin || 0);
|
|
updateDateDisplay();
|
|
} else {
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Error',
|
|
text: response.error || 'Gagal memperbarui data ringkasan'
|
|
});
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
console.error('Error updating summary:', error);
|
|
Swal.fire({
|
|
icon: 'error',
|
|
title: 'Error',
|
|
text: 'Gagal memperbarui data ringkasan'
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Function to update date display
|
|
function updateDateDisplay() {
|
|
const month = moment($('#month').val()).format('MMMM YYYY');
|
|
$('#date-display, #date-display-sakit, #date-display-izin').text(month);
|
|
}
|
|
|
|
// Initial update
|
|
updateDateDisplay();
|
|
updateSummaryCards();
|
|
});
|
|
|
|
function showPhoto(photoUrl) {
|
|
Swal.fire({
|
|
imageUrl: photoUrl,
|
|
imageAlt: 'Foto Presensi',
|
|
width: 'auto',
|
|
padding: '1em',
|
|
showConfirmButton: false,
|
|
showCloseButton: true,
|
|
background: '#fff',
|
|
backdrop: `
|
|
rgba(0,0,0,0.8)
|
|
`,
|
|
customClass: {
|
|
image: 'swal2-image-custom'
|
|
}
|
|
});
|
|
}
|
|
|
|
function confirmDelete(id) {
|
|
Swal.fire({
|
|
title: 'Apakah anda yakin?',
|
|
text: "Data yang dihapus tidak dapat dikembalikan!",
|
|
icon: 'warning',
|
|
showCancelButton: true,
|
|
confirmButtonColor: '#3085d6',
|
|
cancelButtonColor: '#d33',
|
|
confirmButtonText: 'Ya, hapus!',
|
|
cancelButtonText: 'Batal'
|
|
}).then((result) => {
|
|
if (result.isConfirmed) {
|
|
document.getElementById('delete-form-' + id).submit();
|
|
}
|
|
});
|
|
}
|
|
</script>
|
|
@endsection
|
|
|
|
|
|
|
|
|