287 lines
19 KiB
PHP
287 lines
19 KiB
PHP
@extends('layouts.master')
|
|
|
|
@section('styles')
|
|
<style>
|
|
.foto-thumb { width: 48px; height: 48px; object-fit: cover; border-radius: 6px; border: 1px solid #dee2e6; }
|
|
.foto-preview { width: 120px; height: 120px; object-fit: cover; border-radius: 8px; border: 1px solid #dee2e6; }
|
|
.card-body label { font-size: 13px; color: #6c757d; }
|
|
</style>
|
|
@endsection
|
|
|
|
@section('content')
|
|
<div class="container-fluid page-body-wrapper">
|
|
<div class="main-panel">
|
|
<div class="content-wrapper">
|
|
<div class="row">
|
|
<div class="col-12 grid-margin stretch-card">
|
|
<div class="card">
|
|
<div class="card-body">
|
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
<h4 class="card-title mb-0">Master Petugas / Pegawai</h4>
|
|
<button class="btn btn-primary btn-sm" id="btnAdd" type="button">
|
|
<i class="fa fa-plus me-1"></i>Tambah
|
|
</button>
|
|
</div>
|
|
<div class="table-responsive">
|
|
<table class="table table-bordered table-striped" id="petugas-table">
|
|
<thead>
|
|
<tr>
|
|
<th class="text-center" width="5%">Foto</th>
|
|
<th>Nomer</th>
|
|
<th>Nama</th>
|
|
<th>Username</th>
|
|
<th>Level</th>
|
|
<th class="text-center">Bisa Login</th>
|
|
<th class="text-center">Status</th>
|
|
<th class="text-center" width="18%">Aksi</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@forelse ($petugas as $p)
|
|
<tr>
|
|
<td class="text-center">
|
|
<img class="foto-thumb" src="{{ route('petugas.foto', $p->id, false) }}" alt="foto" loading="lazy">
|
|
</td>
|
|
<td>{{ $p->nomer }}</td>
|
|
<td>{{ $p->nama }}</td>
|
|
<td>{{ $p->username }}</td>
|
|
<td>{{ $levels->firstWhere('level_code', $p->level_pegawai)->level_name ?? $p->level_pegawai }}</td>
|
|
<td class="text-center">
|
|
<span class="badge {{ $p->bisalogin == 1 ? 'bg-success' : 'bg-secondary' }}">
|
|
{{ $p->bisalogin == 1 ? 'Ya' : 'Tidak' }}
|
|
</span>
|
|
</td>
|
|
<td class="text-center">
|
|
<span class="badge {{ $p->status == 1 ? 'bg-success' : 'bg-danger' }}">
|
|
{{ $p->status == 1 ? 'Aktif' : 'Nonaktif' }}
|
|
</span>
|
|
</td>
|
|
<td class="text-center">
|
|
<button class="btn btn-info btn-sm btn-detail" type="button" data-id="{{ $p->id }}">Detail</button>
|
|
<button class="btn btn-warning btn-sm btn-edit" type="button" data-id="{{ $p->id }}">Ubah</button>
|
|
<button class="btn btn-danger btn-sm btn-delete" type="button" data-id="{{ $p->id }}" data-nama="{{ $p->nama }}">Hapus</button>
|
|
</td>
|
|
</tr>
|
|
@empty
|
|
<tr><td colspan="8" class="text-center">Belum ada data petugas.</td></tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- MODAL FORM -->
|
|
<div class="modal fade" id="modal-petugas" tabindex="-1" data-bs-backdrop="static">
|
|
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="modal-title">Tambah Petugas</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<form id="form-petugas" enctype="multipart/form-data">
|
|
@csrf
|
|
<input type="hidden" name="_method" id="form-method" value="POST">
|
|
<input type="hidden" id="form-id" value="">
|
|
<div class="modal-body">
|
|
<div class="row g-2">
|
|
<div class="col-md-3 text-center">
|
|
<img class="foto-preview mb-2" id="foto-preview" src="{{ asset('images/no-image.jpg') }}" alt="preview">
|
|
<input type="file" class="form-control form-control-sm" name="foto" id="foto" accept="image/*">
|
|
<small class="text-muted">JPG/PNG/BMP, maks 2MB</small>
|
|
</div>
|
|
<div class="col-md-9">
|
|
<div class="row g-2">
|
|
<div class="col-md-6"><label class="form-label">Nomer *</label><input class="form-control" name="nomer" id="f-nomer" maxlength="50" required></div>
|
|
<div class="col-md-6"><label class="form-label">Nama *</label><input class="form-control" name="nama" id="f-nama" maxlength="50" required></div>
|
|
<div class="col-md-6"><label class="form-label">Username *</label><input class="form-control" name="username" id="f-username" maxlength="50" required></div>
|
|
<div class="col-md-6"><label class="form-label">Password <span id="pw-hint">*</span></label><input type="text" class="form-control" name="password" id="f-password" maxlength="50" placeholder="Kosongkan jika tidak diubah"></div>
|
|
<div class="col-md-6"><label class="form-label">Level</label>
|
|
<select class="form-select" name="level_pegawai" id="f-level">
|
|
<option value="">-- Pilih --</option>
|
|
@foreach ($levels as $lv)
|
|
<option value="{{ $lv->level_code }}">{{ $lv->level_name }}</option>
|
|
@endforeach
|
|
</select>
|
|
</div>
|
|
<div class="col-md-6"><label class="form-label">NIP</label><input class="form-control" name="nip" id="f-nip" maxlength="50"></div>
|
|
<div class="col-md-4"><label class="form-label">Bisa Login</label>
|
|
<select class="form-select" name="bisalogin" id="f-bisalogin"><option value="1">Ya</option><option value="0">Tidak</option></select>
|
|
</div>
|
|
<div class="col-md-4"><label class="form-label">Status</label>
|
|
<select class="form-select" name="status" id="f-status"><option value="1">Aktif</option><option value="0">Nonaktif</option></select>
|
|
</div>
|
|
<div class="col-md-4"><label class="form-label">Jenis Kelamin</label>
|
|
<select class="form-select" name="jeniskelamin" id="f-jk"><option value="0">Laki-laki</option><option value="1">Perempuan</option></select>
|
|
</div>
|
|
<div class="col-md-6"><label class="form-label">Agama</label><input class="form-control" name="agama" id="f-agama" maxlength="50"></div>
|
|
<div class="col-md-6"><label class="form-label">Telepon</label><input class="form-control" name="telepon" id="f-telepon" maxlength="255"></div>
|
|
<div class="col-md-6"><label class="form-label">Tgl Lahir</label><input type="date" class="form-control" name="tgl_lahir" id="f-tgl-lahir"></div>
|
|
<div class="col-md-6"><label class="form-label">Tgl Masuk</label><input type="date" class="form-control" name="tgl_masuk" id="f-tgl-masuk"></div>
|
|
<div class="col-md-6"><label class="form-label">Email</label><input class="form-control" name="email" id="f-email" maxlength="64"></div>
|
|
<div class="col-md-6"><label class="form-label">Alamat</label><input class="form-control" name="alamat" id="f-alamat" maxlength="100"></div>
|
|
<div class="col-md-6"><label class="form-label">Alamat Lahir</label><input class="form-control" name="alamat_lahir" id="f-alamat-lahir" maxlength="255"></div>
|
|
<div class="col-md-6"><label class="form-label">Alamat Sekarang</label><input class="form-control" name="alamat_sekarang" id="f-alamat-sekarang" maxlength="255"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="submit" class="btn btn-primary">Simpan</button>
|
|
<button type="button" class="btn btn-danger" data-bs-dismiss="modal">Batal</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- MODAL DETAIL -->
|
|
<div class="modal fade" id="modal-detail" tabindex="-1">
|
|
<div class="modal-dialog modal-dialog-centered">
|
|
<div class="modal-content">
|
|
<div class="modal-header"><h5 class="modal-title">Detail Petugas</h5><button class="btn-close" data-bs-dismiss="modal"></button></div>
|
|
<div class="modal-body" id="detail-body"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('javascript')
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
|
|
<script src="{{ asset('vendor/sweetalert2/dist/sweetalert2.min.js') }}"></script>
|
|
<script>
|
|
$(function () {
|
|
const csrf = $('meta[name="csrf-token"]').attr('content');
|
|
const noImage = '{{ asset('images/no-image.jpg') }}';
|
|
const levelMap = @json($levels->pluck('level_name', 'level_code'));
|
|
const routes = {
|
|
store: '{{ route('petugas.store', [], false) }}',
|
|
show: '{{ route('petugas.show', ':id', false) }}',
|
|
update: '{{ route('petugas.update', ':id', false) }}',
|
|
destroy: '{{ route('petugas.destroy', ':id', false) }}',
|
|
foto: '{{ route('petugas.foto', ':id', false) }}'
|
|
};
|
|
const modal = new bootstrap.Modal(document.getElementById('modal-petugas'));
|
|
|
|
function errMsg(xhr) {
|
|
if (xhr.status === 419) return 'Sesi berakhir, silakan muat ulang halaman.';
|
|
if (xhr.status === 422 && xhr.responseJSON?.errors) {
|
|
return Object.values(xhr.responseJSON.errors).flat().join('\n');
|
|
}
|
|
return xhr.responseJSON?.message || 'Operasi gagal.';
|
|
}
|
|
|
|
$('#foto').on('change', function () {
|
|
const f = this.files[0];
|
|
$('#foto-preview').attr('src', f ? URL.createObjectURL(f) : noImage);
|
|
});
|
|
|
|
$('#btnAdd').on('click', function () {
|
|
$('#form-petugas')[0].reset();
|
|
$('#form-id').val('');
|
|
$('#form-method').val('POST');
|
|
$('#pw-hint').text('*');
|
|
$('#f-password').prop('required', true);
|
|
$('#foto-preview').attr('src', noImage);
|
|
$('#modal-title').text('Tambah Petugas');
|
|
modal.show();
|
|
});
|
|
|
|
$(document).on('click', '.btn-edit', function () {
|
|
const id = $(this).data('id');
|
|
const btn = $(this); const btnHtml = btn.html();
|
|
btn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm"></span>');
|
|
$.get(routes.show.replace(':id', id), function (r) {
|
|
const d = r.data;
|
|
$('#form-id').val(d.id);
|
|
$('#form-method').val('PUT');
|
|
$('#pw-hint').text('(kosongkan jika tidak diubah)');
|
|
$('#f-password').prop('required', false).val('');
|
|
$('#f-nomer').val(d.nomer);
|
|
$('#f-nama').val(d.nama);
|
|
$('#f-username').val(d.username);
|
|
$('#f-level').val(d.level_pegawai);
|
|
$('#f-nip').val(d.nip);
|
|
$('#f-bisalogin').val(d.bisalogin ?? 1);
|
|
$('#f-status').val(d.status ?? 1);
|
|
$('#f-jk').val(d.jeniskelamin ?? 0);
|
|
$('#f-agama').val(d.agama);
|
|
$('#f-telepon').val(d.telepon);
|
|
$('#f-tgl-lahir').val(d.tgl_lahir);
|
|
$('#f-tgl-masuk').val(d.tgl_masuk);
|
|
$('#f-email').val(d.email);
|
|
$('#f-alamat').val(d.alamat);
|
|
$('#f-alamat-lahir').val(d.alamat_lahir);
|
|
$('#f-alamat-sekarang').val(d.alamat_sekarang);
|
|
$('#foto').val('');
|
|
$('#foto-preview').attr('src', r.has_foto ? routes.foto.replace(':id', d.id) + '?t=' + Date.now() : noImage);
|
|
$('#modal-title').text('Ubah Petugas');
|
|
modal.show();
|
|
}).fail(xhr => Swal.fire({icon: 'error', title: 'Gagal memuat data', text: errMsg(xhr)})).always(() => btn.prop('disabled', false).html(btnHtml));
|
|
});
|
|
|
|
$('#form-petugas').on('submit', function (e) {
|
|
e.preventDefault();
|
|
const id = $('#form-id').val();
|
|
const isEdit = !!id;
|
|
const url = isEdit ? routes.update.replace(':id', encodeURIComponent(id)) : routes.store;
|
|
const fd = new FormData(this);
|
|
if (isEdit) fd.set('_method', 'PUT');
|
|
const saveBtn = $(this).find('[type="submit"]'); const saveHtml = saveBtn.html();
|
|
saveBtn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm me-1"></span>Menyimpan...');
|
|
$.ajax({
|
|
url: url, type: 'POST', data: fd, processData: false, contentType: false,
|
|
headers: {'X-CSRF-TOKEN': csrf},
|
|
success: () => window.location.reload(),
|
|
error: xhr => {
|
|
saveBtn.prop('disabled', false).html(saveHtml);
|
|
Swal.fire({icon: 'error', title: 'Gagal menyimpan', text: errMsg(xhr)});
|
|
}
|
|
});
|
|
});
|
|
|
|
$(document).on('click', '.btn-delete', function () {
|
|
const id = $(this).data('id');
|
|
const nama = $(this).data('nama');
|
|
Swal.fire({title: 'Hapus petugas?', text: nama, icon: 'warning', showCancelButton: true, confirmButtonText: 'Ya, hapus', cancelButtonText: 'Batal', confirmButtonColor: '#dc3545', showLoaderOnConfirm: true, preConfirm: () => $.ajax({url: routes.destroy.replace(':id', encodeURIComponent(id)), type: 'DELETE', headers: {'X-CSRF-TOKEN': csrf}}).catch(xhr => { Swal.showValidationMessage(errMsg(xhr)); })})
|
|
.then(res => {
|
|
if (res.isConfirmed && res.value) {
|
|
Swal.fire({icon: 'success', title: 'Berhasil', text: 'Petugas dihapus.', timer: 1500, showConfirmButton: false}).then(() => window.location.reload());
|
|
}
|
|
});
|
|
});
|
|
|
|
$(document).on('click', '.btn-detail', function () {
|
|
const id = $(this).data('id');
|
|
const btn = $(this); const btnHtml = btn.html();
|
|
btn.prop('disabled', true).html('<span class="spinner-border spinner-border-sm"></span>');
|
|
$('#detail-body').html('<div class="text-center py-3"><span class="spinner-border spinner-border-sm me-2"></span>Memuat...</div>');
|
|
new bootstrap.Modal(document.getElementById('modal-detail')).show();
|
|
$.get(routes.show.replace(':id', id), function (r) {
|
|
const d = r.data;
|
|
const img = r.has_foto ? routes.foto.replace(':id', d.id) : noImage;
|
|
$('#detail-body').html(
|
|
'<div class="text-center mb-3"><img src="' + img + '" class="foto-preview" alt="foto"></div>' +
|
|
'<dl class="row mb-0">' +
|
|
'<dt class="col-4">Nomer</dt><dd class="col-8">' + (d.nomer ?? '-') + '</dd>' +
|
|
'<dt class="col-4">Nama</dt><dd class="col-8">' + (d.nama ?? '-') + '</dd>' +
|
|
'<dt class="col-4">Username</dt><dd class="col-8">' + (d.username ?? '-') + '</dd>' +
|
|
'<dt class="col-4">Level</dt><dd class="col-8">' + (levelMap[d.level_pegawai] ?? d.level_pegawai ?? '-') + '</dd>' +
|
|
'<dt class="col-4">NIP</dt><dd class="col-8">' + (d.nip ?? '-') + '</dd>' +
|
|
'<dt class="col-4">Telepon</dt><dd class="col-8">' + (d.telepon ?? '-') + '</dd>' +
|
|
'<dt class="col-4">Alamat</dt><dd class="col-8">' + (d.alamat ?? '-') + '</dd>' +
|
|
'<dt class="col-4">Tgl Lahir</dt><dd class="col-8">' + (d.tgl_lahir ?? '-') + '</dd>' +
|
|
'<dt class="col-4">Tgl Masuk</dt><dd class="col-8">' + (d.tgl_masuk ?? '-') + '</dd>' +
|
|
'</dl>'
|
|
);
|
|
}).fail(xhr => $('#detail-body').html('<div class="text-danger text-center">' + errMsg(xhr) + '</div>')).always(() => btn.prop('disabled', false).html(btnHtml));
|
|
});
|
|
});
|
|
</script>
|
|
@endsection
|