Files
accounting_dev_v2/application/views/employees/attendance_monitoring.php
T
2026-09-14 12:05:53 +07:00

41 lines
8.3 KiB
PHP

<?php $this->load->view('hr_payroll/_header',array('active_menu'=>'attendance_monitoring','title'=>'Monitoring Absensi','subtitle'=>'Pantau karyawan yang dijadwalkan hadir dan kelola absensi manual melalui persetujuan.','action_html'=>$permissions['create']?'<button class="btn btn-warning" id="addManual"><i class="bi bi-plus-lg"></i> Absen Manual</button>':'')); ?>
<section class="card hr-panel border-0">
<div class="card-body p-0">
<ul class="nav nav-pills p-3 gap-2 border-bottom" role="tablist">
<li class="nav-item"><button class="nav-link active" data-bs-toggle="tab" data-bs-target="#dailyPane">Kehadiran Terjadwal</button></li>
<li class="nav-item"><button class="nav-link" data-bs-toggle="tab" data-bs-target="#manualPane">Pengajuan Absen Manual</button></li>
</ul>
<div class="tab-content">
<div class="tab-pane fade show active p-3" id="dailyPane">
<div class="d-flex flex-wrap justify-content-between align-items-end gap-2 mb-3"><div><h5 class="mb-1">Daftar Kehadiran Harian</h5><small class="text-muted">Menampilkan semua karyawan berdasarkan jadwal yang telah dipublikasikan.</small></div><div><label class="form-label">Tanggal</label><input type="date" id="filterDate" class="form-control" value="<?=date('Y-m-d')?>"></div></div>
<div class="table-responsive"><table id="tableAttendance" class="table modern-table align-middle w-100"><thead><tr><th>No</th><th>Kode</th><th>Karyawan</th><th>Shift</th><th>Masuk</th><th>Pulang</th><th>Status</th></tr></thead></table></div>
</div>
<div class="tab-pane fade p-3" id="manualPane">
<div class="d-flex flex-wrap justify-content-between align-items-end gap-2 mb-3"><div><h5 class="mb-1">Alur Absensi Manual</h5><small class="text-muted">Draft dibuat dahulu, diajukan, kemudian baru masuk ke daftar kehadiran setelah disetujui.</small></div><select id="manualStatus" class="form-select" style="max-width:220px"><option value="">Semua status</option><option value="draft">Draft</option><option value="submitted">Menunggu persetujuan</option><option value="approved">Disetujui</option><option value="rejected">Ditolak</option></select></div>
<div class="hr-workflow-strip"><span><b>1</b>Buat Draft</span><span><b>2</b>Ajukan</span><span><b>3</b>Approve/Reject</span><span><b>4</b>Masuk Absensi</span></div>
<div class="table-responsive"><table id="tableManual" class="table modern-table align-middle w-100"><thead><tr><th>Dokumen</th><th>Karyawan</th><th>Tanggal/Jam</th><th>Jenis</th><th>Alasan</th><th>Status</th><th>Pembuat</th><th>Aksi</th></tr></thead></table></div>
</div>
</div>
</div>
</section>
<div class="modal fade" id="manualModal" tabindex="-1" data-bs-backdrop="static"><div class="modal-dialog modal-dialog-centered"><div class="modal-content"><div class="modal-header"><div><small class="text-muted">DRAFT ABSENSI</small><h5 class="modal-title">Tambah Absen Manual</h5></div><button class="btn-close" data-bs-dismiss="modal"></button></div><form id="manualForm" data-ajax="true"><div class="modal-body"><div class="mb-3"><label class="form-label">Karyawan <span class="text-danger">*</span></label><select class="form-select select-search" name="employee_id" required><option value="">Pilih karyawan</option><?php foreach($employees as$e):?><option value="<?=$e->id?>"><?=html_escape($e->employee_code.' - '.$e->full_name)?></option><?php endforeach?></select></div><div class="row g-3"><div class="col-6"><label class="form-label">Tanggal <span class="text-danger">*</span></label><input class="form-control" type="date" name="attendance_date" value="<?=date('Y-m-d')?>" required></div><div class="col-6"><label class="form-label">Jam <span class="text-danger">*</span></label><input class="form-control" type="time" name="attendance_time" value="<?=date('H:i')?>" required></div><div class="col-12"><label class="form-label">Jenis Absen <span class="text-danger">*</span></label><select class="form-select" name="attendance_action" required><option value="check_in">Absen Masuk</option><option value="check_out">Absen Pulang</option></select></div><div class="col-12"><label class="form-label">Alasan / Keterangan <span class="text-danger">*</span></label><textarea class="form-control" name="reason" rows="3" maxlength="1000" placeholder="Jelaskan alasan pencatatan manual agar approver dapat memeriksa." required></textarea></div></div><div class="alert alert-warning mt-3 mb-0 small"><i class="bi bi-shield-check"></i> Data belum mengubah absensi sampai pengajuan disetujui.</div></div><div class="modal-footer"><button type="button" class="btn btn-light" data-bs-dismiss="modal">Batal</button><button type="submit" class="btn btn-warning"><i class="bi bi-save"></i> Simpan Draft</button></div></form></div></div></div>
<script>
$(function(){
const base=window.APP_BASE_URL||'<?=base_url()?>',modal=new bootstrap.Modal('#manualModal');
const daily=$('#tableAttendance').DataTable({processing:true,ajax:{url:base+'attendancemonitoring/get_data',data:d=>d.date=$('#filterDate').val(),dataSrc:'data'},order:[],columns:[0,1,2,3,4,5,6].map(i=>({data:i}))});
const statusLabel={draft:'Draft',submitted:'Menunggu Persetujuan',approved:'Disetujui',rejected:'Ditolak',cancelled:'Dibatalkan'};
const manual=$('#tableManual').DataTable({processing:true,ajax:{url:base+'attendancemonitoring/manual_requests',data:d=>d.status=$('#manualStatus').val(),dataSrc:'data'},order:[],columns:['request','employee','datetime','action','reason','status','creator','actions'].map(x=>({data:x})),columnDefs:[{targets:5,render:v=>`<span class="badge bg-${v==='approved'?'success':(v==='rejected'?'danger':(v==='submitted'?'warning':'secondary'))}">${statusLabel[v]||v}</span>`},{targets:7,orderable:false,searchable:false}]});
$('#filterDate').on('change',()=>daily.ajax.reload());$('#manualStatus').on('change',()=>manual.ajax.reload());$('#addManual').on('click',()=>{document.getElementById('manualForm').reset();modal.show();});
function refresh(){manual.ajax.reload(null,false);daily.ajax.reload(null,false)}
function request(url,data){return $.ajax({url:base+url,type:'POST',data:data||{}}).done(r=>{if(r.status){AppAlert.toast(r.message,'success');refresh()}else AppAlert.toast(r.message,'error')}).fail(x=>AppAlert.toast(x.responseJSON?.message||'Proses gagal.','error'));}
$('#manualForm').on('submit',function(e){e.preventDefault();const form=this,button=form.querySelector('button[type="submit"]'),original=button.innerHTML;button.disabled=true;button.innerHTML='<span class="spinner-border spinner-border-sm"></span> Menyimpan';request('attendancemonitoring/save_manual',$(form).serialize()).done(r=>{if(r.status){modal.hide();form.reset();}}).always(()=>{button.disabled=false;button.innerHTML=original;if(window.AppLoading)AppLoading.hide();});});
$(document).on('click','.manual-submit',function(){const id=this.dataset.id;AppAlert.confirm({title:'Ajukan absensi manual?',text:'Dokumen akan dikirim kepada approver HR.'}).then(x=>{if(x.isConfirmed)request('attendancemonitoring/submit_manual/'+id)});});
$(document).on('click','.manual-approve',function(){const id=this.dataset.id;AppAlert.confirm({title:'Setujui absensi manual?',text:'Setelah disetujui, waktu akan langsung diterapkan ke daftar absensi.',confirmButtonText:'Approve'}).then(x=>{if(x.isConfirmed)request('attendancemonitoring/approve_manual/'+id)});});
$(document).on('click','.manual-reject',function(){const id=this.dataset.id;AppAlert.prompt({title:'Tolak pengajuan',input:'textarea',inputLabel:'Alasan penolakan',inputValidator:v=>!v?.trim()?'Alasan wajib diisi.':undefined,confirmButtonText:'Reject'}).then(x=>{if(x.isConfirmed)request('attendancemonitoring/reject_manual/'+id,{reason:x.value})});});
$(document).on('click','.manual-detail',function(){const id=this.dataset.id;$.getJSON(base+'attendancemonitoring/manual_detail/'+id,r=>{if(!r.status)return AppAlert.toast(r.message,'error');const x=r.request;Swal.fire({title:x.request_no,html:`<div class="text-start"><b>${$('<div>').text(x.employee_code+' - '+x.full_name).html()}</b><hr><div>Tanggal: ${x.attendance_date} ${x.attendance_time.slice(0,5)}</div><div>Jenis: ${x.attendance_action==='check_in'?'Masuk':'Pulang'}</div><div>Status: ${x.status}</div><div class="mt-2"><small>Alasan</small><br>${$('<div>').text(x.reason).html()}</div>${x.rejection_reason?`<div class="alert alert-danger mt-2 mb-0">${$('<div>').text(x.rejection_reason).html()}</div>`:''}</div>`,showConfirmButton:true});});});
});
</script>