EduScore
Total Siswa

-

Total Mapel

-

Rata-Rata Kelas

-

Persentase Lulus

-

Selamat Datang di Sistem Raport EduScore

Kelola data siswa, mata pelajaran, kalkulasi nilai secara langsung, dan hasilkan rekap nilai rapi tanpa formula manual.

Status Database

Sistem sinkronisasi otomatis
Total Input Nilai 0 Record
Siswa Remedial 0 Orang

Akses EduScore

Gunakan Akun Default V1 Anda untuk login

Sistem V1 Otomatis admin / 123
``` eof ```javascript:EduScore Apps Script Backend:Code.gs /** * EDUSCORE - BACKEND ENGINE (GOOGLE APPS SCRIPT) * Versi V1 - Fungsional Failsafe Multi-User CRUD & Autoconfig */ function doGet(e) { var action = e.parameter.action; if (action === "readAll") { return handleReadAll(); } return createJSONResponse({ status: "error", message: "Aksi tidak dikenali" }); } function doPost(e) { var lock = LockService.getScriptLock(); try { if (!lock.tryLock(10000)) { return createJSONResponse({ status: "error", message: "Server sibuk, silakan coba beberapa saat lagi." }); } var requestData = JSON.parse(e.postData.contents); var action = requestData.action; switch (action) { case "addSiswa": return handleAddSiswa(requestData); case "editSiswa": return handleEditSiswa(requestData); case "deleteSiswa": return handleDeleteSiswa(requestData); case "addMapel": return handleAddMapel(requestData); case "editMapel": return handleEditMapel(requestData); case "deleteMapel": return handleDeleteMapel(requestData); case "addNilai": return handleAddNilai(requestData); case "editNilai": return handleEditNilai(requestData); case "deleteNilai": return handleDeleteNilai(requestData); default: return createJSONResponse({ status: "error", message: "Aksi POST tidak valid." }); } } catch (error) { return createJSONResponse({ status: "error", message: error.toString() }); } finally { lock.releaseLock(); } } /* --- STREAMING_CHUNK: Fungsi Setup Otomatis --- */ function setupAwal() { var ss = SpreadsheetApp.getActiveSpreadsheet(); // 1. Setup Sheet Siswa createAndFormatSheet(ss, "Siswa", ["NIS", "Nama", "Kelas"]); // 2. Setup Sheet Mapel createAndFormatSheet(ss, "Mapel", ["Kode", "Nama", "KKM"]); // 3. Setup Sheet Nilai createAndFormatSheet(ss, "Nilai", ["ID", "NIS", "MapelKode", "Tugas", "UTS", "UAS", "NilaiAkhir", "Predikat", "Status"]); Logger.log("Inisialisasi & Setup Tabel EduScore sukses diselesaikan."); } function createAndFormatSheet(ss, name, headers) { var sheet = ss.getSheetByName(name); if (!sheet) { sheet = ss.insertSheet(name); } else { sheet.clear(); } sheet.appendRow(headers); // Desain Header Elegan (Mac Vibe) var range = sheet.getRange(1, 1, 1, headers.length); range.setFontWeight("bold"); range.setFontColor("#ffffff"); range.setBackgroundColor("#1e1b4b"); // Navy Indigo range.setHorizontalAlignment("center"); sheet.setFrozenRows(1); // Buat rapi lebar kolom otomatis for (var i = 1; i <= headers.length; i++) { sheet.autoResizeColumn(i); } } /* --- STREAMING_CHUNK: Fungsi Pembacaan Database Utama (Read) --- */ function handleReadAll() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var siswaSheet = ss.getSheetByName("Siswa"); var mapelSheet = ss.getSheetByName("Mapel"); var nilaiSheet = ss.getSheetByName("Nilai"); var siswaData = siswaSheet ? getSheetDataAsJSON(siswaSheet) : []; var mapelData = mapelSheet ? getSheetDataAsJSON(mapelSheet) : []; var nilaiData = nilaiSheet ? getSheetDataAsJSON(nilaiSheet) : []; return createJSONResponse({ status: "success", siswa: siswaData, mapel: mapelData, nilai: nilaiData }); } function getSheetDataAsJSON(sheet) { var rows = sheet.getDataRange().getValues(); if (rows.length <= 1) return []; var headers = rows[0]; var data = []; for (var i = 1; i < rows.length; i++) { var row = rows[i]; var obj = {}; for (var j = 0; j < headers.length; j++) { obj[headers[j].toString().toLowerCase()] = row[j]; } data.push(obj); } return data; } /* --- STREAMING_CHUNK: Failsafe CRUD Siswa --- */ function handleAddSiswa(data) { var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Siswa"); sheet.appendRow([data.nis.toString(), data.nama, data.kelas]); return createJSONResponse({ status: "success" }); } function handleEditSiswa(data) { var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Siswa"); var rows = sheet.getDataRange().getValues(); for (var i = 1; i < rows.length; i++) { if (rows[i][0].toString() === data.oldNis.toString()) { sheet.getRange(i + 1, 1, 1, 3).setValues([[data.nis.toString(), data.nama, data.kelas]]); break; } } return createJSONResponse({ status: "success" }); } function handleDeleteSiswa(data) { var ss = SpreadsheetApp.getActiveSpreadsheet(); var siswaSheet = ss.getSheetByName("Siswa"); var rows = siswaSheet.getDataRange().getValues(); for (var i = 1; i < rows.length; i++) { if (rows[i][0].toString() === data.nis.toString()) { siswaSheet.deleteRow(i + 1); break; } } // Cascading delete nilai siswa terkait var nilaiSheet = ss.getSheetByName("Nilai"); if (nilaiSheet) { var nRows = nilaiSheet.getDataRange().getValues(); for (var j = nRows.length - 1; j >= 1; j--) { if (nRows[j][1].toString() === data.nis.toString()) { nilaiSheet.deleteRow(j + 1); } } } return createJSONResponse({ status: "success" }); } /* --- STREAMING_CHUNK: Failsafe CRUD Mapel --- */ function handleAddMapel(data) { var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Mapel"); sheet.appendRow([data.kode.toString(), data.nama, Number(data.kkm)]); return createJSONResponse({ status: "success" }); } function handleEditMapel(data) { var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Mapel"); var rows = sheet.getDataRange().getValues(); for (var i = 1; i < rows.length; i++) { if (rows[i][0].toString() === data.oldKode.toString()) { sheet.getRange(i + 1, 1, 1, 3).setValues([[data.kode.toString(), data.nama, Number(data.kkm)]]); break; } } return createJSONResponse({ status: "success" }); } function handleDeleteMapel(data) { var ss = SpreadsheetApp.getActiveSpreadsheet(); var mapelSheet = ss.getSheetByName("Mapel"); var rows = mapelSheet.getDataRange().getValues(); for (var i = 1; i < rows.length; i++) { if (rows[i][0].toString() === data.kode.toString()) { mapelSheet.deleteRow(i + 1); break; } } // Cascading delete nilai mapel terkait var nilaiSheet = ss.getSheetByName("Nilai"); if (nilaiSheet) { var nRows = nilaiSheet.getDataRange().getValues(); for (var j = nRows.length - 1; j >= 1; j--) { if (nRows[j][2].toString() === data.kode.toString()) { nilaiSheet.deleteRow(j + 1); } } } return createJSONResponse({ status: "success" }); } /* --- STREAMING_CHUNK: Failsafe CRUD Nilai --- */ function handleAddNilai(data) { var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Nilai"); sheet.appendRow([ data.id, data.nis.toString(), data.mapelKode.toString(), Number(data.tugas), Number(data.uts), Number(data.uas), Number(data.nilaiAkhir), data.predikat, data.status ]); return createJSONResponse({ status: "success" }); } function handleEditNilai(data) { var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Nilai"); var rows = sheet.getDataRange().getValues(); for (var i = 1; i < rows.length; i++) { if (rows[i][0].toString() === data.id.toString()) { sheet.getRange(i + 1, 1, 1, 9).setValues([[ data.id, data.nis.toString(), data.mapelKode.toString(), Number(data.tugas), Number(data.uts), Number(data.uas), Number(data.nilaiAkhir), data.predikat, data.status ]]); break; } } return createJSONResponse({ status: "success" }); } function handleDeleteNilai(data) { var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Nilai"); var rows = sheet.getDataRange().getValues(); for (var i = 1; i < rows.length; i++) { if (rows[i][0].toString() === data.id.toString()) { sheet.deleteRow(i + 1); break; } } return createJSONResponse({ status: "success" }); } /* --- CORE UTILITY: OUTPUT FORMATTER JSON --- */ function createJSONResponse(data) { return ContentService.createTextOutput(JSON.stringify(data)) .setMimeType(ContentService.MimeType.JSON); } /* PLACEHOLDER: FUNGSI CRUD BARU */ ``` eof ```markdown:Panduan Rilis Aplikasi:panduan.md ### Panduan Rilis & Panduan Penggunaan Aplikasi (EduScore) --- ### BAGIAN A: LANGKAH MERILIS APLIKASI KE INTERNET **Langkah 1: Siapkan Database (Google Sheets & Apps Script)** 1. Buka browser baru, ketik [sheets.new](https://sheets.new) untuk membuat file Google Sheets kosong baru. 2. Klik menu **Extensions** (Ekstensi) > **Apps Script**. 3. Hapus semua kode bawaan yang ada di editor, lalu *paste* seluruh kode dari file **[EduScore Apps Script Backend]** ke dalam lembar editor tersebut (pertahankan nama file bawaan tetap `Code.gs`). 4. Klik tombol 💾 **Save** (Simpan) di panel atas. 5. Di menu drop-down fungsi atas (sebelah kanan tombol Run), ganti fungsinya menjadi `setupAwal`, lalu klik tombol ▶️ **Run**. 6. Jika muncul peringatan izin otentikasi Google: klik **Review permissions** > pilih akun Google Anda > klik tombol **Advanced** > klik tulisan kecil **Go to Untitled project (unsafe)** > lalu klik **Allow** (Izinkan). 7. Periksa file Google Sheets Anda. Di sana akan otomatis terbentuk 3 sheet baru bernama `Siswa`, `Mapel`, dan `Nilai` dengan layout yang sudah terformat rapi secara otomatis. **Langkah 2: Deploy Backend ke Internet** 1. Di kanan atas halaman Google Apps Script, klik tombol biru **Deploy** > pilih **New deployment**. 2. Klik ikon gir (Gear ⚙️) untuk memilih tipe deployment: pilih **Web app**. 3. Atur konfigurasinya sebagai berikut: * **Execute as:** Pilih `Me` (Akun Google Anda). * **Who has access:** Pilih `Anyone` (Siapa saja, hal ini wajib agar frontend bisa saling bertukar data). 4. Klik tombol biru **Deploy**. 5. Copy/Salin alamat tautan **Web app URL** yang dimunculkan di layar. **Langkah 3: Hubungkan Aplikasi Frontend & Rilis ke Cloudflare** 1. Buka kembali file **[EduScore Dashboard & Frontend]** di komputer Anda. 2. Cari baris berikut di bagian atas script javascript: ```javascript const APP_URL = "URL_GAS_KAMU_DISINI"; /* GANTI dengan URL Web App GAS Anda setelah publish */ const PREVIEW_MODE = true; /* GANTI menjadi false jika ingin langsung terhubung ke database asli */ ``` 3. Ubah `const APP_URL = "URL_GAS_KAMU_DISINI";` dengan menempelkan tautan **Web app URL** yang telah Anda copy di Langkah 2 tadi. 4. Ganti baris di bawahnya menjadi `const PREVIEW_MODE = false;` agar mode simulasi data dummy dimatikan dan langsung tersambung ke database real milik Anda sendiri. 5. Buat sebuah folder baru di komputer, simpan file frontend tersebut ke dalamnya dengan nama file `index.html`. 6. Rilis aplikasi ke internet secara gratis menggunakan layanan hosting cepat **Cloudflare Pages**: * Masuk ke website [dash.cloudflare.com](https://dash.cloudflare.com) (daftar jika belum memiliki akun). * Klik menu **Compute** > **Workers & Pages**. * Klik tombol **Create application** > arahkan ke tab **Pages** > scroll ke bawah dan klik tombol **Get Started** pada menu *Upload assets*. * Beri nama proyek aplikasi Anda, lalu drag & drop folder yang berisi file `index.html` tadi ke dalam kotak upload. * Klik **Deploy**. Selesai! Aplikasi Anda sudah online sepenuhnya dan bisa diakses oleh guru dari perangkat mana saja! --- ### BAGIAN B: TUTORIAL PENGGUNAAN APLIKASI (BAGI GURU & WALI KELAS) Setelah aplikasi Anda online/live, berikut adalah alur kerja operasional harian untuk mengelola nilai raport: #### 🔐 1. Login Pertama Kali * Buka link aplikasi web Anda di browser. * Pada kotak login, masukkan kredensial bawaan admin: * **Username**: `admin` * **Password**: `123` * Klik **Masuk Sekarang**. Anda akan diarahkan langsung ke halaman ringkasan Dashboard. #### 👥 2. Daftarkan Siswa * Klik menu **Data Siswa** pada sidebar sebelah kiri. * Klik tombol **Tambah Siswa**. * Isi formulir: * **NIS** (Nomor Induk Siswa): misal `1001` * **Nama Lengkap**: misal `Ahmad Fauzi` * **Kelas**: Pilih `XII-RPL` atau `XII-TKJ` * Klik **Simpan**. Siswa Anda kini terdaftar di database cloud Google Sheets secara langsung. #### 📚 3. Daftarkan Mata Pelajaran & Batas KKM * Klik menu **Mata Pelajaran** pada sidebar. * Klik tombol **Tambah Mapel**. * Isi formulir: * **Kode Mapel**: misal `IND-01` * **Nama Mapel**: misal `Bahasa Indonesia` * **KKM Minimal**: misal `75` (Siswa dengan nilai di bawah angka ini otomatis akan terdeteksi sebagai remedial) * Klik **Simpan**. #### ✍️ 4. Masukkan Nilai Menggunakan Kalkulator Otomatis * Klik menu **Input Nilai** pada sidebar. * Pada form sebelah kiri: * Pilih **Nama Siswa** yang ingin dinilai. * Pilih **Mata Pelajaran** yang diujikan. * Masukkan nilai angka (0-100) untuk **N. Tugas**, **N. UTS**, dan **N. UAS**. * **Kalkulasi Real-time:** Perhatikan box abu-abu di bagian bawah formulir. Nilai Akhir (NA), Predikat (A/B/C/D), dan status kelulusan (Lulus/Remedial) akan otomatis terhitung secara instan saat Anda mengetik! * Klik **Simpan Nilai** untuk menyimpannya ke database cloud, atau klik tombol ikon panah melingkar untuk mereset inputan. #### 📊 5. Unduh Laporan Rekapitulasi Rapor * Klik menu **Rekap Raport** pada sidebar. * Di sini Anda akan melihat visualisasi matriks nilai terpadu per kelas. * Nilai siswa yang berada di bawah standar KKM otomatis disorot dengan **warna merah** (mempermudah guru menandai siswa yang butuh perbaikan). * Di bagian atas, gunakan **Filter Kelas** untuk memilah data siswa dengan rapi. * Klik tombol hijau **Export ke Excel/CSV** di sebelah kanan atas untuk langsung mengunduh lembar rekap nilai ini ke komputer Anda, siap untuk diserahkan ke kepala sekolah atau diarsipkan. ``` eof 🚀 **Aplikasi komplit & siap rilis!** Cek tab Preview untuk testing (dummy data aktif). Untuk rilis ke internet, ikuti `Panduan Rilis`. Jika ingin menghidupkan fitur 'Coming Soon', balas chat ini: **'Aktifkan menu [Nama Menu]'**.