207 lines
15 KiB
PHP
207 lines
15 KiB
PHP
<x-master-page title="Import Data Siswa" description="Import data siswa lengkap dari file Excel/CSV. Gunakan template agar format kolom sesuai.">
|
|
<div class="grid grid-cols-1 gap-6 xl:grid-cols-3">
|
|
<div class="xl:col-span-2 space-y-6">
|
|
<x-master-card title="Upload File Import" subtitle="Semua field inti siswa bisa diimport dari Excel/CSV selama kolomnya mengikuti template.">
|
|
<form method="POST" action="{{ route('students.import.preview') }}" enctype="multipart/form-data" class="space-y-6">
|
|
@csrf
|
|
|
|
<div>
|
|
<label for="import_file" class="mb-2 block text-sm font-medium text-slate-700">File Excel / CSV</label>
|
|
<input id="import_file" name="import_file" type="file" accept=".xlsx,.csv,.txt" class="block w-full rounded-2xl border border-slate-200 bg-white px-4 py-3 text-sm text-slate-700 file:mr-4 file:rounded-xl file:border-0 file:bg-indigo-50 file:px-4 file:py-2 file:font-semibold file:text-indigo-700 hover:file:bg-indigo-100">
|
|
<p class="mt-2 text-xs text-slate-500">Format didukung: <strong>.xlsx</strong> dan <strong>.csv</strong>. Untuk paling aman, pakai template yang disediakan lalu isi di Excel.</p>
|
|
</div>
|
|
|
|
<div class="flex flex-wrap items-center gap-3">
|
|
<button type="submit" class="inline-flex items-center rounded-2xl bg-indigo-600 px-5 py-3 text-sm font-semibold text-white shadow-lg shadow-indigo-200 transition hover:bg-indigo-700">
|
|
Preview Import
|
|
</button>
|
|
<a href="{{ route('students.import.template') }}" class="inline-flex items-center rounded-2xl border border-emerald-200 bg-emerald-50 px-5 py-3 text-sm font-semibold text-emerald-700 transition hover:bg-emerald-100">
|
|
Download Template
|
|
</a>
|
|
<a href="{{ route('students.import.example') }}" class="inline-flex items-center rounded-2xl border border-sky-200 bg-sky-50 px-5 py-3 text-sm font-semibold text-sky-700 transition hover:bg-sky-100">
|
|
Download Contoh File
|
|
</a>
|
|
<a href="{{ route('students.index') }}" class="inline-flex items-center rounded-2xl border border-slate-200 px-5 py-3 text-sm font-semibold text-slate-700 transition hover:bg-slate-50">
|
|
Kembali ke Data Siswa
|
|
</a>
|
|
</div>
|
|
</form>
|
|
</x-master-card>
|
|
|
|
@if ($preview)
|
|
<x-master-card title="Preview Import" subtitle="Periksa dulu data yang akan diproses sebelum disimpan ke database.">
|
|
<div class="mb-6 grid grid-cols-1 gap-4 md:grid-cols-4">
|
|
<div class="rounded-3xl border border-slate-200 bg-slate-50 px-5 py-4">
|
|
<div class="text-xs font-semibold uppercase tracking-[0.18em] text-slate-500">Total Baris</div>
|
|
<div class="mt-2 text-3xl font-bold text-slate-800">{{ $preview['summary']['total_rows'] }}</div>
|
|
</div>
|
|
<div class="rounded-3xl border border-emerald-200 bg-emerald-50 px-5 py-4">
|
|
<div class="text-xs font-semibold uppercase tracking-[0.18em] text-emerald-600">Valid</div>
|
|
<div class="mt-2 text-3xl font-bold text-emerald-700">{{ $preview['summary']['valid_rows'] }}</div>
|
|
</div>
|
|
<div class="rounded-3xl border border-sky-200 bg-sky-50 px-5 py-4">
|
|
<div class="text-xs font-semibold uppercase tracking-[0.18em] text-sky-600">Insert Baru</div>
|
|
<div class="mt-2 text-3xl font-bold text-sky-700">{{ $preview['summary']['insert_rows'] }}</div>
|
|
</div>
|
|
<div class="rounded-3xl border border-amber-200 bg-amber-50 px-5 py-4">
|
|
<div class="text-xs font-semibold uppercase tracking-[0.18em] text-amber-600">Update Data</div>
|
|
<div class="mt-2 text-3xl font-bold text-amber-700">{{ $preview['summary']['update_rows'] }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
@if (!empty($preview['errors']))
|
|
<div class="mb-6 rounded-2xl border border-rose-200 bg-rose-50 px-5 py-4 text-sm text-rose-700">
|
|
<div class="font-semibold">Ada baris yang belum valid.</div>
|
|
<ul class="mt-2 list-disc space-y-1 pl-5">
|
|
@foreach (array_slice($preview['errors'], 0, 10) as $error)
|
|
<li>{{ $error }}</li>
|
|
@endforeach
|
|
</ul>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="overflow-x-auto rounded-3xl border border-slate-200">
|
|
<table class="min-w-full divide-y divide-slate-200 text-sm">
|
|
<thead class="bg-slate-50">
|
|
<tr>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-[0.16em] text-slate-500">Baris</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-[0.16em] text-slate-500">NIS / NISN</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-[0.16em] text-slate-500">Nama</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-[0.16em] text-slate-500">Akademik</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-[0.16em] text-slate-500">Aksi</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-[0.16em] text-slate-500">Status Validasi</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-slate-100 bg-white">
|
|
@foreach ($preview['rows'] as $row)
|
|
<tr class="align-top {{ $row['is_valid'] ? '' : 'bg-rose-50/50' }}">
|
|
<td class="px-4 py-4 font-semibold text-slate-700">{{ $row['row_number'] }}</td>
|
|
<td class="px-4 py-4 text-slate-600">
|
|
<div>{{ $row['data']['student_number'] ?: '-' }}</div>
|
|
<div class="text-xs text-slate-400">NISN: {{ $row['data']['nisn'] ?: '-' }}</div>
|
|
</td>
|
|
<td class="px-4 py-4 text-slate-700">
|
|
<div class="font-medium">{{ $row['data']['full_name'] ?: '-' }}</div>
|
|
<div class="text-xs text-slate-400">{{ $row['data']['gender'] ?: '-' }} · {{ $row['data']['phone_number'] ?: '-' }}</div>
|
|
</td>
|
|
<td class="px-4 py-4 text-slate-600">
|
|
<div>Tahun: {{ $row['display']['academic_year'] ?? ($row['data']['academic_year_id'] ?: '-') }}</div>
|
|
<div>Jurusan: {{ $row['display']['department'] ?? ($row['data']['department_id'] ?: '-') }}</div>
|
|
<div>Kelas: {{ $row['display']['class'] ?? ($row['data']['class_id'] ?: '-') }}</div>
|
|
@if (!empty($row['display']['class_context']))
|
|
<div class="text-xs text-slate-400">{{ $row['display']['class_context'] }}</div>
|
|
@endif
|
|
</td>
|
|
<td class="px-4 py-4">
|
|
<div class="flex flex-col gap-2">
|
|
<span class="rounded-full px-3 py-1 text-xs font-semibold {{ $row['action'] === 'update' ? 'bg-amber-100 text-amber-700' : 'bg-sky-100 text-sky-700' }}">
|
|
{{ $row['action'] === 'update' ? 'Update' : 'Insert' }}
|
|
</span>
|
|
<span class="rounded-full bg-slate-100 px-3 py-1 text-xs font-semibold text-slate-600">
|
|
Status: {{ $row['display']['status'] ?? ($row['data']['status'] ?: '-') }}
|
|
</span>
|
|
</div>
|
|
</td>
|
|
<td class="px-4 py-4 text-sm">
|
|
@if ($row['is_valid'])
|
|
<span class="rounded-full bg-emerald-100 px-3 py-1 text-xs font-semibold text-emerald-700">Valid</span>
|
|
@else
|
|
<div class="space-y-1 text-rose-700">
|
|
<div class="inline-flex rounded-full bg-rose-100 px-3 py-1 text-xs font-semibold">Perlu perbaikan</div>
|
|
<ul class="list-disc pl-4 text-xs">
|
|
@foreach ($row['errors'] as $error)
|
|
<li>{{ $error }}</li>
|
|
@endforeach
|
|
</ul>
|
|
</div>
|
|
@endif
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
@if ($preview['summary']['valid_rows'] > 0)
|
|
<form method="POST" action="{{ route('students.import') }}" class="mt-6 flex flex-wrap items-center gap-3">
|
|
@csrf
|
|
<input type="hidden" name="preview_token" value="{{ $preview['token'] }}">
|
|
<button type="submit" class="inline-flex items-center rounded-2xl bg-emerald-600 px-5 py-3 text-sm font-semibold text-white shadow-lg shadow-emerald-200 transition hover:bg-emerald-700 focus:outline-none focus:ring-2 focus:ring-emerald-200">
|
|
Konfirmasi Import ke Database
|
|
</button>
|
|
<span class="text-sm text-slate-500">Hanya baris valid yang akan diproses.</span>
|
|
</form>
|
|
@endif
|
|
</x-master-card>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="space-y-6">
|
|
<x-master-card title="Kolom Import" subtitle="Field inti siswa yang didukung saat import Excel/CSV.">
|
|
<ul class="space-y-2 text-sm text-slate-600">
|
|
<li><strong>student_number</strong> — NIS</li>
|
|
<li><strong>nisn</strong> — NISN</li>
|
|
<li><strong>nik</strong> — NIK</li>
|
|
<li><strong>full_name</strong> — nama lengkap</li>
|
|
<li><strong>gender</strong> — L / P</li>
|
|
<li><strong>place_of_birth</strong> — tempat lahir</li>
|
|
<li><strong>date_of_birth</strong> — tanggal lahir</li>
|
|
<li><strong>religion</strong> — agama</li>
|
|
<li><strong>nationality</strong> — kewarganegaraan</li>
|
|
<li><strong>family_card_number</strong> — no. kartu keluarga</li>
|
|
<li><strong>child_order</strong> — anak ke</li>
|
|
<li><strong>number_of_siblings</strong> — jumlah saudara</li>
|
|
<li><strong>phone_number</strong> — nomor HP</li>
|
|
<li><strong>email</strong> — email</li>
|
|
<li><strong>address</strong> — alamat</li>
|
|
<li><strong>province_id / provinsi</strong> — provinsi</li>
|
|
<li><strong>regency_id / kabupaten_kota</strong> — kabupaten/kota</li>
|
|
<li><strong>district_id / kecamatan</strong> — kecamatan</li>
|
|
<li><strong>village_id / kelurahan_desa</strong> — kelurahan/desa</li>
|
|
<li><strong>postal_code</strong> — kode pos</li>
|
|
<li><strong>academic_year_id</strong> — ID atau nama tahun ajaran</li>
|
|
<li><strong>department_id</strong> — ID atau nama program keahlian</li>
|
|
<li><strong>class_id</strong> — ID atau nama kelas</li>
|
|
<li><strong>entry_date</strong> — tanggal masuk</li>
|
|
<li><strong>status</strong> — status siswa</li>
|
|
<li><strong>notes</strong> — catatan</li>
|
|
<li><strong>parent_father_*</strong> — data ayah</li>
|
|
<li><strong>parent_mother_*</strong> — data ibu</li>
|
|
<li><strong>parent_guardian_*</strong> — data wali</li>
|
|
</ul>
|
|
</x-master-card>
|
|
|
|
<x-master-card title="Referensi ID Master" subtitle="Pakai ID ini saat mengisi template import.">
|
|
<div class="space-y-4 text-sm text-slate-600">
|
|
<div>
|
|
<div class="mb-2 text-xs font-semibold uppercase tracking-[0.14em] text-slate-500">Tahun Ajaran</div>
|
|
<div class="space-y-1">
|
|
@foreach ($academicYears as $id => $label)
|
|
<div>• <strong>{{ $id }}</strong> — {{ $label }}</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<div class="mb-2 text-xs font-semibold uppercase tracking-[0.14em] text-slate-500">Program Keahlian</div>
|
|
<div class="space-y-1">
|
|
@foreach ($departments as $id => $label)
|
|
<div>• <strong>{{ $id }}</strong> — {{ $label }}</div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<div class="mb-2 text-xs font-semibold uppercase tracking-[0.14em] text-slate-500">Kelas</div>
|
|
<div class="max-h-72 space-y-1 overflow-y-auto pr-2">
|
|
@foreach ($classes as $classRoom)
|
|
<div>• <strong>{{ $classRoom->id }}</strong> — {{ $classRoom->name }} <span class="text-slate-400">({{ $classRoom->academicYear?->name }} · {{ $classRoom->department?->name }})</span></div>
|
|
@endforeach
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</x-master-card>
|
|
</div>
|
|
</div>
|
|
</x-master-page>
|