๐ File Manager
๐
/
/
home
/
u449181296
/
domains
/
birulogi.smakpbaleendah.sch.id
/
public_html
/
lms
/
tukang-ngatur
/
assets
/
img
/
qr-logos
/home/u449181296/domains/birulogi.smakpbaleendah.sch.id/public_html/lms/tukang-ngatur/assets/img/qr-logos
Upload
Name
Size
Date
CHMOD
Action
โ FILE โ
logo_1773801405.php
6.73 KB
2026-03-18 02:36
644
(rw-r--r--)
Edit
|
Rename
|
Preview
|
Del
Edit
/* ---------------------------------------------------------- SISTEM ELIGIBLE BIRULOGI - FULL CLOUD REALTIME ---------------------------------------------------------- */ const firebaseConfig = { databaseURL: "https://snbp-smakpbe-default-rtdb.asia-southeast1.firebasedatabase.app/" }; firebase.initializeApp(firebaseConfig); const db = firebase.database(); let config = { judul: "CHECKER.", info: "Silakan Pilih Angkatan Peserta Didik", bgUrl: "", bgColor: "#1e40af", nLoad: "Sedang menarik data...", nWin: "PESERTA DIDIK LOLOS", nLose: "DATA TIDAK DITEMUKAN", sheetUrl: "", angkatan: [] }; window.onload = () => { db.ref("settings").on("value", (snapshot) => { const data = snapshot.val(); if (data) { config = data; applyVisual(); if (document.getElementById('grid-angkatan')) renderHome(); } else { // Inisialisasi jika kosong db.ref("settings").set(config); } if (typeof lucide !== 'undefined') lucide.createIcons(); }); }; /* ---------------------------------------------------------- I. LOGIKA PESERTA DIDIK (ANTARMUKA PENGGUNA) ---------------------------------------------------------- */ function applyVisual() { const b = document.getElementById('body-render'); if (!b) return; b.style.backgroundColor = config.bgColor || "#1e40af"; if (config.bgUrl) { b.style.backgroundImage = `url('${config.bgUrl}')`; b.style.backgroundSize = 'cover'; b.style.backgroundAttachment = 'fixed'; } else { b.style.backgroundImage = 'none'; } const titleEl = document.getElementById('view-judul'); if (titleEl) titleEl.innerText = config.judul; const infoEl = document.getElementById('view-info'); if (infoEl) infoEl.innerText = config.info; } function renderHome() { const g = document.getElementById('grid-angkatan'); if (!g) return; if (!config.angkatan || config.angkatan.length === 0) { g.innerHTML = `<p class="text-white/50 text-center font-bold py-10 uppercase text-[10px] tracking-widest">Belum ada data angkatan</p>`; return; } // Filter hanya angkatan yang aktif const activeAngkatan = Object.values(config.angkatan).filter(a => a.active); g.innerHTML = activeAngkatan.map(a => ` <div onclick="pilihTahun('${a.name}')" class="relative overflow-hidden group cursor-pointer active:scale-95 transition-all duration-300 rounded-[2.5rem] h-32 flex items-center justify-center shadow-xl border border-white/20" style="${a.img ? `background-image:url('${a.img}');background-size:cover;background-position:center;` : `background-color:${a.color || '#3b82f6'};`}"> <div class="absolute inset-0 bg-black/40 group-hover:bg-black/20 transition-colors"></div> <div class="relative text-center"> <h3 class="text-4xl font-black italic uppercase tracking-tighter text-white">${a.name}</h3> <p class="text-[8px] font-black text-white/70 uppercase tracking-[0.3em]">Cek Peserta Didik</p> </div> </div> `).join(''); } async function prosesCek() { // 1. DEBUGGING: Cek satu per satu elemennya const elNISN = document.getElementById('in-nisn'); const elNama = document.getElementById('in-nama'); const elYear = document.getElementById('selected-year'); // Cek elemen mana yang null if (!elNISN) return Swal.fire({ icon: 'error', title: 'Struktur Error', text: 'Elemen ID "in-nisn" tidak ditemukan!' }); if (!elNama) return Swal.fire({ icon: 'error', title: 'Struktur Error', text: 'Elemen ID "in-nama" tidak ditemukan!' }); if (!elYear) return Swal.fire({ icon: 'error', title: 'Struktur Error', text: 'Elemen ID "selected-year" tidak ditemukan!' }); const nisnInput = elNISN.value.trim(); const namaInput = elNama.value.trim().toLowerCase(); const th = elYear.innerText.replace(/[^0-9]/g, ''); if(!nisnInput || !namaInput) { return Swal.fire({ icon: 'warning', title: 'Data Kosong', text: 'NISN dan Nama wajib diisi!', confirmButtonColor: '#1e40af' }); } Swal.fire({ title: config.nLoad || 'Memproses...', allowOutsideClick: false, didOpen: () => Swal.showLoading() }); try { const sidMatch = config.sheetUrl.match(/[-\w]{25,}/); const sid = sidMatch[0]; // Ambil data dari Google Sheets (Tab sesuai Tahun) const r = await fetch(`https://docs.google.com/spreadsheets/d/${sid}/gviz/tq?tqx=out:json&sheet=${th}`); const t = await r.text(); const j = JSON.parse(t.substr(47).slice(0, -2)); const rows = j.table.rows; // Pencarian: No(0), NIS(1), NISN(2), NAMA(3), KELAS(4), STATUS(5) const res = rows.find(x => { const valNISN = x.c[2] ? String(x.c[2].v || "").trim() : ""; const valNama = x.c[3] ? String(x.c[3].v || "").toLowerCase().trim() : ""; return valNISN === nisnInput && valNama === namaInput; }); if(res) { Swal.close(); const statusVerif = String(res.c[5]?.v || "").toUpperCase(); const isLolos = statusVerif.includes("DITERIMA") || statusVerif.includes("LOLOS"); if (isLolos) { confetti({ particleCount: 150, spread: 70, origin: { y: 0.6 } }); Swal.fire({ icon: 'success', title: 'SELAMAT!', text: config.nWin, confirmButtonColor: '#1e40af' }).then(() => showResultPopup(res.c)); } else { showResultPopup(res.c); } } else { Swal.fire({ icon: 'error', title: 'Gagal', text: config.nLose, confirmButtonColor: '#1e40af' }); } } catch(e) { Swal.fire({ icon: 'error', title: 'Error', text: 'Koneksi database bermasalah atau Sheet belum di-publish.' }); } } function showResultPopup(data) { const list = document.getElementById('res-data-list'); list.innerHTML = ""; // Pemetaan data berdasarkan urutan kolom Bos const fields = [ { label: "NIS", val: data[1]?.v }, { label: "NISN", val: data[2]?.v }, { label: "NAMA LENGKAP", val: data[3]?.v }, { label: "KELAS", val: data[4]?.v } ]; fields.forEach(f => { if (f.val) { list.innerHTML += ` <div class="mb-2 p-4 bg-white rounded-2xl border border-slate-100 shadow-sm flex justify-between items-center"> <div> <p class="text-[7px] text-slate-400 font-black tracking-widest uppercase">${f.label}</p> <p class="text-[12px] text-slate-800 font-black uppercase">${f.val}</p> </div> </div>`; } }); const statusRaw = String(data[5]?.v || "PROSES").toUpperCase(); const isLolos = statusRaw.includes("LOLOS") || statusRaw.includes("DITERIMA"); document.getElementById('res-header').innerText = isLolos ? "SELAMAT" : "HASIL CEK"; document.getElementById('res-status-box').innerText = statusRaw; if (isLolos) { document.getElementById('res-status-box').className = "py-6 rounded-[2rem] font-black text-2xl uppercase italic bg-blue-600 text-white shadow-xl border-none"; document.getElementById('res-icon').innerHTML = `<div class="bg-blue-100 p-6 rounded-full animate-bounce"><i data-lucide="award" class="w-12 h-12 text-blue-600"></i></div>`; } else { document.getElementById('res-status-box').className = "py-6 rounded-[2rem] font-black text-2xl uppercase italic bg-red-500 text-white shadow-xl border-none"; document.getElementById('res-icon').innerHTML = `<div class="bg-red-100 p-6 rounded-full"><i data-lucide="frown" class="w-12 h-12 text-red-600"></i></div>`; } document.getElementById('result-screen').classList.remove('hidden'); if (typeof lucide !== 'undefined') lucide.createIcons(); } function pilihTahun(th) { document.getElementById('home-view').classList.add('hidden'); document.getElementById('search-view').classList.remove('hidden'); document.getElementById('selected-year').innerText = `ANGKATAN ${th}`; } function backToHome() { document.getElementById('home-view').classList.remove('hidden'); document.getElementById('search-view').classList.add('hidden'); } function closeResult() { document.getElementById('result-screen').classList.add('hidden'); backToHome(); } function exportHasil() { const area = document.getElementById('print-area'); html2canvas(area, { backgroundColor: null, borderRadius: 40 }).then(canvas => { const link = document.createElement('a'); link.download = `Hasil_Cek_Birulogi.png`; link.href = canvas.toDataURL(); link.click(); }); } /* ---------------------------------------------------------- II. LOGIKA ADMIN (Sesi Online & Database Cloud) ---------------------------------------------------------- */ // Identifikasi Browser Unik (Fingerprint Sederhana) function getBrowserID() { return navigator.userAgent.replace(/\D/g, '').substring(0, 10); } // 1. Sistem Proteksi Sesi Online async function cekSesiOnline() { // Hanya jalankan proteksi jika berada di halaman admin if (!window.location.pathname.includes("admin_snbp.html")) return; const localToken = localStorage.getItem("birulogi_token"); const bID = getBrowserID(); if (!localToken) { window.location.href = "cek_snbp.html"; return; } try { const snapshot = await db.ref("admin_sessions/" + bID).get(); if (snapshot.exists()) { const cloudData = snapshot.val(); // Validasi token lokal dengan token di Firebase if (cloudData.token !== localToken || cloudData.status !== "active") { logoutSesi(); } } else { logoutSesi(); } } catch (e) { console.error("Auth Error:", e); } } function logoutSesi() { localStorage.removeItem("birulogi_token"); window.location.href = "cek_snbp.html"; } // Jalankan pengecekan setiap kali script dimuat cekSesiOnline(); // Shortcut Login Admin (CTRL + B x2) let bKey = 0; document.addEventListener('keydown', (e) => { if(e.ctrlKey && e.key.toLowerCase() === 'b') { e.preventDefault(); bKey++; if(bKey === 2) { bKey = 0; loginPrompt(); } setTimeout(() => bKey = 0, 1000); } }); // 2. Fungsi Login (Membuat Sesi Cloud) async function loginPrompt() { const snapshot = await db.ref("admin_config/password").get(); const cloudPassword = snapshot.exists() ? snapshot.val() : "birulogi2026"; const { value: p } = await Swal.fire({ title: 'Akses Admin', input: 'password', confirmButtonColor: '#1e40af', confirmButtonText: 'MASUK', customClass: { popup: 'rounded-[2rem]' } }); if (p === cloudPassword) { const sessionToken = "TOKEN_" + Math.random().toString(36).substr(2, 9); const bID = getBrowserID(); // Daftarkan sesi aktif ke Firebase await db.ref("admin_sessions/" + bID).set({ token: sessionToken, last_login: new Date().toISOString(), status: "active" }); localStorage.setItem("birulogi_token", sessionToken); Swal.fire({ icon: 'success', title: 'Berhasil', timer: 1000, showConfirmButton: false }) .then(() => { window.location.href = "admin_snbp.html"; }); } else if (p !== undefined) { Swal.fire({ icon: 'error', title: 'Akses Ditolak', text: 'Kata sandi salah!' }); } } // 3. Pengaturan Global & Sinkronisasi function simpanGlobal(silent = false) { const fields = { 'set-judul': 'judul', 'set-bg-url': 'bgUrl', 'set-bg-color': 'bgColor', 'set-n-load': 'nLoad', 'set-n-win': 'nWin', 'set-n-lose': 'nLose', 'set-sheet-url': 'sheetUrl' }; for (let id in fields) { const el = document.getElementById(id); if (el) config[fields[id]] = el.value; } db.ref("settings").set(config) .then(() => { if(!silent) Swal.fire({ icon: 'success', title: 'Sinkronisasi Berhasil!', timer: 1500, showConfirmButton: false }); }) .catch((err) => { Swal.fire({ icon: 'error', title: 'Koneksi Gagal', text: err.message }); }); } async function gantiPasswordAdmin() { const { value: newPass } = await Swal.fire({ title: 'Ganti Kata Sandi Cloud', input: 'text', inputLabel: 'Password Baru', showCancelButton: true, confirmButtonColor: '#1e40af', customClass: { popup: 'rounded-[2rem]' } }); if (newPass) { db.ref("admin_config/password").set(newPass) .then(() => { Swal.fire({ icon: 'success', title: 'Sandi Diperbarui!', timer: 1500, showConfirmButton: false }); }); } } function isiInputAdmin() { const fields = { 'set-judul': config.judul, 'set-bg-url': config.bgUrl, 'set-bg-color': config.bgColor, 'set-n-load': config.nLoad, 'set-n-win': config.nWin, 'set-n-lose': config.nLose, 'set-sheet-url': config.sheetUrl }; for (let id in fields) { const el = document.getElementById(id); if (el) el.value = fields[id] || ""; } renderAngkatanEditor(); if(config.angkatan && config.angkatan.length > 0) { const previewArea = document.getElementById('db-preview-area'); if(previewArea) previewArea.classList.remove('hidden'); const s = document.getElementById('select-db-view'); if(s) { s.innerHTML = config.angkatan.map(a => `<option value="${a.name}">${a.name}</option>`).join(''); renderPaging(0); } } } function renderAngkatanEditor() { const container = document.getElementById('list-editor-angkatan'); if (!container) return; container.innerHTML = config.angkatan.map((a, i) => ` <div class="bg-white p-6 rounded-[2rem] border-l-[12px] shadow-sm mb-4" style="border-left-color:${a.color}"> <div class="flex justify-between items-center mb-4"> <span class="font-black text-xs uppercase">Angkatan ${a.name}</span> <input type="checkbox" ${a.active?'checked':''} onchange="config.angkatan[${i}].active=this.checked; simpanGlobal(true)" class="w-6 h-6 accent-blue-600"> </div> <p class="text-[8px] font-black text-slate-400 uppercase mb-1 ml-1">URL Kartu Hasil</p> <input type="text" class="w-full p-3 text-[10px] border rounded-xl mb-3" value="${a.img}" placeholder="https://..." onchange="config.angkatan[${i}].img=this.value; simpanGlobal(true)"> <p class="text-[8px] font-black text-slate-400 uppercase mb-1 ml-1">Warna Identitas</p> <input type="color" class="w-full h-10 cursor-pointer bg-transparent" value="${a.color}" onchange="config.angkatan[${i}].color=this.value; simpanGlobal(true)"> </div> `).join(''); } async function deteksiDatabase() { let urlInput = document.getElementById('set-sheet-url').value; const sidMatch = urlInput.match(/[-\w]{25,}/); if(!sidMatch) return Swal.fire({ icon: 'error', title: 'Gagal', text: 'URL tidak valid!' }); const sheetId = sidMatch[0]; Swal.fire({ title: 'Pemindaian Cloud...', text: 'Mencari daftar angkatan di Spreadsheet Bos', allowOutsideClick: false, didOpen: () => Swal.showLoading() }); try { let tabDitemukan = []; // KITA SCAN OTOMATIS TAHUN 2024 - 2030 SECARA PARALEL (CEPAT) const rangeTahun = Array.from({length: 7}, (_, i) => (2024 + i).toString()); await Promise.all(rangeTahun.map(async (th) => { try { // Mencoba memanggil tab tahun tersebut const res = await fetch(`https://docs.google.com/spreadsheets/d/${sheetId}/gviz/tq?tqx=out:json&sheet=${th}`); const txt = await res.text(); // Jika Google merespon dengan tabel, berarti TAB ADA if (txt.includes("table")) { tabDitemukan.push(th); } } catch (err) { } })); if (tabDitemukan.length > 0) { tabDitemukan.sort(); tampilkanChecklistAngkatan(sheetId, tabDitemukan); } else { // Jika benar-benar tidak ada yang cocok, baru tanya user throw new Error("Tidak ada tab tahun (2024-2030) yang aktif."); } } catch (e) { Swal.fire({ icon: 'warning', title: 'Tab Tidak Terdeteksi', text: 'Pastikan nama tab di Spreadsheet adalah angka tahun (2025, 2026, dst) dan sudah Publish to Web.', confirmButtonColor: '#1e40af' }); } } // Fungsi bantu untuk menampilkan pilihan checklist function tampilkanChecklistAngkatan(sheetId, tabs) { let htmlChecklist = `<div class="text-left mt-4 p-4 bg-slate-50 rounded-[2rem] border max-h-60 overflow-y-auto">`; tabs.sort().forEach(tab => { htmlChecklist += ` <div class="flex items-center justify-between p-3 border-b border-slate-200"> <label class="text-[11px] font-black uppercase text-slate-700">Angkatan ${tab}</label> <input type="checkbox" value="${tab}" checked class="w-6 h-6 chk-tab accent-blue-600"> </div>`; }); htmlChecklist += `</div>`; Swal.fire({ title: 'Tab Terdeteksi!', html: htmlChecklist, showCancelButton: true, confirmButtonText: 'Simpan ke Cloud', confirmButtonColor: '#1e40af', customClass: { popup: 'rounded-[2rem]' } }).then((result) => { if (result.isConfirmed) { const selected = Array.from(document.querySelectorAll('.chk-tab:checked')).map(el => el.value); prosesSimpanKeCloud(sheetId, selected); } }); } // Fungsi final untuk kirim data ke Firebase function prosesSimpanKeCloud(sheetId, listTahun) { config.sheetUrl = `https://docs.google.com/spreadsheets/d/${sheetId}/edit`; // Sinkronisasi data angkatan agar gambar/warna lama tidak hilang config.angkatan = listTahun.map(name => { const old = (config.angkatan || []).find(o => o.name === name); return old || { name, active: true, img: '', color: '#1e40af' }; }); document.getElementById('set-sheet-url').value = config.sheetUrl; simpanGlobal(); // Simpan ke Firebase settings isiInputAdmin(); // Refresh tampilan admin Swal.fire({ icon: 'success', title: 'Cloud Updated!', text: `${listTahun.length} Angkatan berhasil diaktifkan.`, timer: 2000, showConfirmButton: false }); } async function renderPaging(page) { const thSelect = document.getElementById('select-db-view'); if(!thSelect || !config.sheetUrl) return; const th = thSelect.value; const sid = config.sheetUrl.match(/[-\w]{25,}/)[0]; try { const r = await fetch(`https://docs.google.com/spreadsheets/d/${sid}/gviz/tq?tqx=out:json&sheet=${th}`); const t = await r.text(); const j = JSON.parse(t.substr(47).slice(0, -2)); // Mengambil data per 10 baris untuk paging const rows = j.table.rows.slice(page * 10, (page * 10) + 10); // Header Tabel Sesuai Urutan Bos: No, NIS, NISN, Nama Lengkap, Kelas, Status let h = ` <div class="overflow-x-auto"> <table class="w-full text-left border-collapse"> <thead> <tr class="bg-slate-50 uppercase text-[8px] text-slate-400 border-b"> <th class="p-4">No</th> <th class="p-4">NIS</th> <th class="p-4">NISN</th> <th class="p-4">Nama Lengkap</th> <th class="p-4">Kelas</th> <th class="p-4">Status</th> </tr> </thead> <tbody>`; rows.forEach(x => { const d = x.c; h += ` <tr class="border-t hover:bg-slate-50 transition-colors"> <td class="p-4 text-slate-400 font-bold">${d[0]?.v || '-'}</td> <td class="p-4 font-black text-blue-600">${d[1]?.v || '-'}</td> <td class="p-4 text-slate-600">${d[2]?.v || '-'}</td> <td class="p-4 uppercase font-bold text-slate-800">${d[3]?.v || '-'}</td> <td class="p-4 text-slate-600">${d[4]?.v || '-'}</td> <td class="p-4"> <span class="px-3 py-1 rounded-full text-[9px] font-black uppercase ${String(d[5]?.v).includes('LOLOS') || String(d[5]?.v).includes('DITERIMA') ? 'bg-green-100 text-green-600' : 'bg-red-100 text-red-600'}"> ${d[5]?.v || '-'} </span> </td> </tr>`; }); h += `</tbody></table></div>`; document.getElementById('table-view').innerHTML = h; document.getElementById('paging-box').innerHTML = ` <button onclick="renderPaging(${page-1})" ${page===0?'disabled':''} class="p-2 border rounded-xl disabled:opacity-30"> <i data-lucide="chevron-left" class="w-4 h-4"></i> </button> <span class="font-black text-[10px] uppercase">Halaman ${page+1}</span> <button onclick="renderPaging(${page+1})" class="p-2 border rounded-xl"> <i data-lucide="chevron-right" class="w-4 h-4"></i> </button> `; lucide.createIcons(); } catch(e) { document.getElementById('table-view').innerHTML = `<p class="p-10 text-center text-red-500 font-bold uppercase text-[10px]">Gagal Memuat Data Tab ${th}</p>`; } } function bersihkanData() { Swal.fire({ title: 'Reset Pabrik Cloud?', text: "Semua pengaturan, sesi admin, dan daftar angkatan akan dihapus total!", icon: 'warning', showCancelButton: true, confirmButtonColor: '#dc2626', // Warna Merah (Bahaya) cancelButtonColor: '#64748b', confirmButtonText: 'YA, RESET TOTAL!', cancelButtonText: 'BATAL', reverseButtons: true, customClass: { popup: 'rounded-[2.5rem]' } }).then(async (result) => { if (result.isConfirmed) { // Tampilkan Loading Swal.fire({ title: 'Membersihkan Cloud...', allowOutsideClick: false, didOpen: () => Swal.showLoading() }); try { // 1. Definisikan Data Default (Kembali ke setelan pabrik) const defaultConfig = { judul: "CHECKER.", info: "Silakan Pilih Angkatan Peserta Didik", bgUrl: "", bgColor: "#1e40af", // Kembali ke Biru sesuai permintaan Bos nLoad: "Sedang menarik data...", nWin: "PESERTA DIDIK LOLOS", nLose: "DATA TIDAK DITEMUKAN", sheetUrl: "", angkatan: [] }; // 2. Hapus Sesi & Password Admin (Opsional, agar password balik ke standar) await db.ref("admin_sessions").remove(); await db.ref("admin_config/password").set("birulogi2026"); // 3. Timpa Pengaturan Lama dengan Default await db.ref("settings").set(defaultConfig); // 4. Bersihkan Penyimpanan Lokal Browser localStorage.removeItem("birulogi_token"); // 5. Notifikasi Berhasil Swal.fire({ icon: 'success', title: 'Cloud Berhasil Direset', text: 'Sistem kembali ke pengaturan awal Birulogi.', showConfirmButton: true, confirmButtonText: 'MUAT ULANG', confirmButtonColor: '#1e40af' }).then(() => { window.location.href = 'cek_snbp.html'; // Tendang keluar ke halaman cek }); } catch (err) { Swal.fire({ icon: 'error', title: 'Gagal Reset', text: 'Terjadi kendala koneksi ke Firebase.' }); } } }); } function konfirmasiKeluar() { Swal.fire({ title: 'Keluar Admin?', text: "Sesi Cloud akan dihentikan untuk browser ini.", icon: 'info', showCancelButton: true, confirmButtonColor: '#2563eb', confirmButtonText: 'Ya, Keluar!', customClass: { popup: 'rounded-[2.5rem]' } }).then(async (result) => { if (result.isConfirmed) { const bID = getBrowserID(); await db.ref("admin_sessions/" + bID).remove(); localStorage.removeItem("birulogi_token"); window.location.href = 'cek_snbp.html'; } }); }
Save
๐งช PHP Preview
<?php echo 'hello'; ?>
Run PHP
๐ฅ Linux CMD
Run CMD