logo name

This commit is contained in:
jouel88 2026-04-07 11:57:57 +07:00
parent b2c5d494ab
commit 780492d9b4
13 changed files with 59 additions and 45 deletions

View File

@ -48,7 +48,7 @@ public function headings(): array
return [
['LAPORAN REKAPITULASI LEMBUR PEGAWAI'],
['MPG HRIS Enterprise System'],
['HRIS MP Enterprise System'],
['Periode: ' . $namaBulan . ' ' . $this->tahun],
['Dicetak: ' . Carbon::now()->translatedFormat('d F Y, H:i') . ' WIB'],
[],
@ -215,7 +215,7 @@ public function registerEvents(): array
]);
$noteRow = $summaryRow + 2;
$sheet->setCellValue("A{$noteRow}", '* Laporan dibuat otomatis oleh sistem MPG HRIS. Data bersumber dari catatan lembur yang telah disetujui.');
$sheet->setCellValue("A{$noteRow}", '* Laporan dibuat otomatis oleh sistem HRIS MP. Data bersumber dari catatan lembur yang telah disetujui.');
$sheet->getStyle("A{$noteRow}")->getFont()->setItalic(true)->setSize(8)->getColor()->setRGB('94A3B8');
$sheet->mergeCells("A{$noteRow}:I{$noteRow}");
},

View File

@ -46,7 +46,7 @@ public function headings(): array
return [
['LAPORAN REKAPITULASI PRESENSI PEGAWAI'],
['MPG HRIS Enterprise System'],
['HRIS MP Enterprise System'],
['Periode: ' . $namaBulan . ' ' . $this->tahun],
['Dicetak: ' . Carbon::now()->translatedFormat('d F Y, H:i') . ' WIB'],
[],
@ -239,7 +239,7 @@ public function registerEvents(): array
// Catatan kaki
$noteRow = $summaryRow + 2;
$sheet->setCellValue("A{$noteRow}", '* Laporan dibuat otomatis oleh sistem MPG HRIS. Data bersumber dari catatan presensi dan lembur bulan berjalan.');
$sheet->setCellValue("A{$noteRow}", '* Laporan dibuat otomatis oleh sistem HRIS MP. Data bersumber dari catatan presensi dan lembur bulan berjalan.');
$sheet->getStyle("A{$noteRow}")->getFont()->setItalic(true)->setSize(8)->getColor()->setRGB('94A3B8');
$sheet->mergeCells("A{$noteRow}:K{$noteRow}");
},

View File

@ -47,7 +47,7 @@ public function index(Request $request)
if (Storage::disk('local')->exists($datasetPath)) {
$files = Storage::disk('local')->files($datasetPath);
foreach ($files as $file) {
if (preg_match('/frame_\d+\.jpg$/', $file)) {
if (preg_match('/\/frame_\d+\.jpg$/', $file)) {
$frameList[] = $file;
}
}
@ -153,9 +153,12 @@ public function reset($id)
public function showFrame($userId, $frameIndex)
{
$rawFilePath = "face_datasets/{$userId}/raw_frame_{$frameIndex}.jpg";
$filePath = "face_datasets/{$userId}/frame_{$frameIndex}.jpg";
if (Storage::disk('local')->exists($filePath)) {
if (Storage::disk('local')->exists($rawFilePath)) {
return response()->file(Storage::disk('local')->path($rawFilePath));
} elseif (Storage::disk('local')->exists($filePath)) {
return response()->file(Storage::disk('local')->path($filePath));
}

View File

@ -107,8 +107,8 @@ private function generateIdKaryawan($tglBergabung, $idDivisi, $idJabatan)
$nomorUrut = str_pad($nextNumber, 3, '0', STR_PAD_LEFT);
// Format: MPG-202603-ITST-001
return "MPG-{$yearMonth}-{$kodeTengah}-{$nomorUrut}";
// Format: MP-202603-ITST-001
return "MP-{$yearMonth}-{$kodeTengah}-{$nomorUrut}";
}
public function store(StorePegawaiRequest $request)

View File

@ -62,7 +62,7 @@ protected static function booted()
if (empty($model->nomor_surat)) {
$count = static::whereYear('created_at', date('Y'))->count() + 1;
$model->nomor_surat = sprintf('%03d/MPG/IZN/%s', $count, date('Y'));
$model->nomor_surat = sprintf('%03d/MP/IZN/%s', $count, date('Y'));
}
});
}

View File

@ -51,7 +51,7 @@ public function run()
$hrd = User::updateOrCreate(
['email' => 'hrd@mpg.co.id'],
[
'nik' => 'MPG-202401-HRMG-001',
'nik' => 'MP-202401-HRMG-001',
'nama_lengkap' => 'HRD Manager',
'password' => Hash::make('Mpg123!'),
'status_aktif' => 1,
@ -69,7 +69,7 @@ public function run()
$pegawai = User::updateOrCreate(
['email' => 'budi@mpg.co.id'],
[
'nik' => 'MPG-202401-HRST-001',
'nik' => 'MP-202401-HRST-001',
'nama_lengkap' => 'Budi Santoso',
'password' => Hash::make('Mpg123!'),
'status_aktif' => 1,

BIN
public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -61,10 +61,10 @@ def detect_face(gray_frame):
return faces[0]
def process_frame(gray_frame):
def process_frame(frame, gray_frame):
face_rect = detect_face(gray_frame)
if face_rect is None:
return None, "no_face"
return None, None, "no_face"
(x, y, w, h) = face_rect
@ -74,18 +74,19 @@ def process_frame(gray_frame):
x2 = min(gray_frame.shape[1], x + w + padding)
y2 = min(gray_frame.shape[0], y + h + padding)
face_crop = gray_frame[y1:y2, x1:x2]
face_crop_gray = gray_frame[y1:y2, x1:x2]
face_crop_color = frame[y1:y2, x1:x2]
face_resized = cv2.resize(face_crop, FACE_SIZE, interpolation=cv2.INTER_AREA)
face_resized = cv2.resize(face_crop_gray, FACE_SIZE, interpolation=cv2.INTER_AREA)
blur_score = get_blur_score(face_resized)
if blur_score < BLUR_THRESHOLD:
return None, f"blur ({round(blur_score, 1)})"
return None, None, f"blur ({round(blur_score, 1)})"
face_denoised = cv2.GaussianBlur(face_resized, (3, 3), 0)
face_final = apply_clahe(face_denoised)
return face_final, "ok"
return face_final, face_crop_color, "ok"
def extract_frames(video_path, output_dir, max_frames=100):
@ -127,7 +128,7 @@ def extract_frames(video_path, output_dir, max_frames=100):
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
face_img, status = process_frame(gray)
face_img, face_color, status = process_frame(frame, gray)
if face_img is None:
if "blur" in status:
@ -138,7 +139,9 @@ def extract_frames(video_path, output_dir, max_frames=100):
continue
filename = f"frame_{saved_count:03d}.jpg"
filename_raw = f"raw_frame_{saved_count:03d}.jpg"
cv2.imwrite(os.path.join(output_dir, filename), face_img)
cv2.imwrite(os.path.join(output_dir, filename_raw), face_color)
saved_count += 1
frame_idx += 1

View File

@ -1,9 +1,9 @@
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="id" class="h-full bg-white">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login Administrator - Absensi Digital</title>
<title>Login Administrator - HRIS MP</title>
@vite(['resources/css/app.css', 'resources/js/app.js'])
@ -97,7 +97,7 @@ class="absolute inset-0 h-full w-full object-cover"
<div class="flex-1 flex flex-col justify-center py-12 px-4 sm:px-6 lg:px-20 xl:px-24 bg-white">
<div class="mx-auto w-full max-w-sm lg:w-96">
<div class="mb-8">
<div class="mb-8 text-center flex flex-col items-center">
<h2 class="text-3xl font-extrabold text-[#130F26] tracking-tight">Sign in</h2>
<p class="mt-2 text-sm text-slate-500">
Masuk menggunakan akun administrator Anda.

View File

@ -141,25 +141,36 @@ class="!mb-0" />
<td class="px-6 py-4">
@if($faceStatus !== 'unregistered')
<div class="flex items-center justify-center gap-2">
@php
$poses = ['depan' => 'Depan', 'kanan' => 'Kanan', 'kiri' => 'Kiri', 'bawah' => 'Bawah'];
@endphp
@foreach($poses as $poseKey => $poseLabel)
@if(isset($user->face_photos[$poseKey]))
<div class="relative group cursor-pointer" onclick="openFacePreview('{{ route('face.photo', [$user->id, $poseKey]) }}', '{{ $user->nama_lengkap }}', '{{ $poseLabel }}')">
<img src="{{ route('face.photo', [$user->id, $poseKey]) }}"
@if(isset($user->face_frames) && $user->face_frame_count > 0)
@php
// Ambil 4 frame representatif (atau kurang jika tidak sampai 4)
$frameCount = $user->face_frame_count;
$step = max(1, floor($frameCount / 4));
$selectedFrames = [];
for ($i = 0; $i < $frameCount; $i += $step) {
if (count($selectedFrames) < 4) {
// Extract "01" dari "face_datasets/1/frame_01.jpg"
if (preg_match('/frame_(\d+)\.jpg$/', $user->face_frames[$i], $matches)) {
$selectedFrames[] = $matches[1];
}
}
}
@endphp
@foreach($selectedFrames as $index => $frameIdx)
<div class="relative group cursor-pointer" onclick="openFacePreview('{{ route('face.frame', [$user->id, $frameIdx]) }}', '{{ $user->nama_lengkap }}', 'Frame {{ $frameIdx }}')">
<img src="{{ route('face.frame', [$user->id, $frameIdx]) }}"
class="w-12 h-12 rounded-lg object-cover border-2 border-slate-200 group-hover:border-primary transition-colors shadow-sm">
<span class="absolute -bottom-1 left-1/2 -translate-x-1/2 text-[9px] font-bold bg-slate-800 text-white px-1.5 py-0.5 rounded-full leading-none whitespace-nowrap">{{ $poseLabel }}</span>
<span class="absolute -bottom-1 left-1/2 -translate-x-1/2 text-[9px] font-bold bg-slate-800 text-white px-1.5 py-0.5 rounded-full leading-none whitespace-nowrap">Fr {{ $frameIdx }}</span>
</div>
@else
<div class="w-12 h-12 rounded-lg bg-slate-100 border-2 border-dashed border-slate-300 flex items-center justify-center relative">
<svg class="w-4 h-4 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
</svg>
<span class="absolute -bottom-1 left-1/2 -translate-x-1/2 text-[9px] font-bold bg-slate-400 text-white px-1.5 py-0.5 rounded-full leading-none whitespace-nowrap">{{ $poseLabel }}</span>
</div>
@endif
@endforeach
@endforeach
@else
<div class="text-xs text-slate-400 italic flex items-center justify-center">
<svg class="w-4 h-4 mr-1 animate-spin" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path></svg>
Memproses...
</div>
@endif
</div>
@else
<div class="text-center text-xs text-slate-400 italic">Belum ada foto</div>

View File

@ -191,7 +191,7 @@
{{-- KOP SURAT --}}
<div class="kop">
<div class="kop-left">
<div class="company-name">MPG HRIS Enterprise System</div>
<div class="company-name">HRIS MP Enterprise System</div>
<div class="company-sub">Human Resource Information System</div>
</div>
<div class="kop-right">
@ -337,7 +337,7 @@
{{-- FOOTER --}}
<div class="footer-area">
<div class="footer-left">
<p>* Laporan ini dibuat secara otomatis oleh sistem MPG HRIS.</p>
<p>* Laporan ini dibuat secara otomatis oleh sistem HRIS MP.</p>
<p>* Data bersumber dari catatan presensi dan lembur bulan berjalan.</p>
</div>
<div class="footer-right">

View File

@ -3,11 +3,8 @@
class="fixed inset-y-0 left-0 w-72 bg-white border-r border-slate-200 flex flex-col h-full transition-transform duration-300 font-sans z-[100] shadow-xl lg:shadow-sm lg:static lg:flex-shrink-0">
<div class="flex items-center justify-center h-28 border-b border-slate-100 bg-white">
<div class="text-center">
<span class="block text-3xl font-extrabold tracking-tight text-[#130F26]">
MPG<span class="text-blue-600">HRIS</span>
</span>
<span class="text-[10px] font-bold text-slate-400 uppercase tracking-[0.2em] mt-1 block">Enterprise System</span>
<div class="text-center px-4 pt-2">
<img src="{{ asset('logo.png') }}" class="h-20 w-auto mx-auto object-contain border-none shadow-none" alt="HRIS MP Logo">
</div>
</div>

BIN
schema_dump.json Normal file

Binary file not shown.