app script GS

Run Settings
LanguageJavaScript
Language Version
Run Command
let loginSheetName = "Admin"; // Nama sheet yang menyimpan data login // Sintaks untuk maping ke index.html function doGet() { return HtmlService.createHtmlOutputFromFile('dashboard'); // Mengembalikan halaman index } function getPage(pageName) { if (pageName === 'dashboard') { return HtmlService.createHtmlOutputFromFile('dashboard'); } else if (pageName === 'nilai') { return HtmlService.createHtmlOutputFromFile('nilai'); } else if (pageName === 'lihat-data') { return HtmlService.createHtmlOutputFromFile('lihat-data'); } else if (pageName === 'pengaturan') { return HtmlService.createHtmlOutputFromFile('pengaturan'); } } function logoutUser() { // Fungsi untuk menghapus status login dan mengarahkan ke halaman login return HtmlService.createHtmlOutput("window.location.href = 'login.html';"); } function doGet(e) { // Ambil parameter page dari URL, default ke 'login' const page = (e.parameter.page || 'login').toLowerCase(); // Daftar halaman HTML yang diizinkan const allowedPages = ['login', 'lihat-data', 'nilai', 'pengaturan', 'dashboard']; // Cek apakah halaman yang diminta diizinkan const safePage = allowedPages.includes(page) ? page : 'login'; return HtmlService.createHtmlOutputFromFile(safePage) .setTitle("Aplikasi Penilaian") .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL); } // Fungsi cek login // Fungsi untuk memverifikasi login dan mengambil data nama guru function verifyLogin(username, password) { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('Admin'); const data = sheet.getDataRange().getValues(); // Ambil semua data dari sheet Admin // Loop untuk mencari username dan password yang cocok for (let i = 1; i < data.length; i++) { const storedUsername = data[i][1]; // Kolom USERNAME (indeks 1) const storedPassword = data[i][2]; // Kolom PASSWORD (indeks 2) if (storedUsername === username && storedPassword === password) { // Login berhasil, simpan status login const userProps = PropertiesService.getUserProperties(); userProps.setProperty('username', username); // Menyimpan username login // Mengembalikan data pengguna yang login, termasuk nama guru return { success: true, nama: data[i][3], // Kolom NAMA GURU (indeks 3) role: 'Guru' // Menyimpan role sebagai Guru }; } } function getDataGuru() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheetByName("Admin"); const data = sheet.getRange(2, 1, sheet.getLastRow()-1, 6).getValues(); // tanpa header return data; } // Jika tidak ditemukan kecocokan, kembalikan status gagal dengan pesan kesalahan return { success: false, message: 'Username atau Password salah!' // Pesan kesalahan yang jelas }; } // Menampilkan halaman dashboard setelah login berhasil function loadIndexPage(nama, position, email) { // Ini adalah template untuk halaman index.html setelah login var template = HtmlService.createTemplateFromFile('dashboard.html'); // Pastikan nama file 'index.html' sesuai template.nama = nama; template.position = position; template.email = email; // Kembalikan HTML ke browser return template.evaluate().getContent(); } function getPage(pageName) { const allowedPages = ['dashboard', 'nilai', 'lihat-data', 'pengaturan']; if (!allowedPages.includes(pageName)) { pageName = 'dashboard'; } return HtmlService.createHtmlOutputFromFile(pageName).getContent(); } // Menu di spreadsheet function onOpen() { SpreadsheetApp.getUi() .createMenu('📘 Menu Rapor') .addItem('📊 Tampilkan Sidebar', 'tampilkanSidebar') .addToUi(); } // Buat header jika belum ada di sheet "Data" function buatHeaderJikaBelumAda() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("DATA"); if (!sheet) { SpreadsheetApp.getActiveSpreadsheet().insertSheet("DATA"); } if (sheet.getLastRow() === 0) { sheet.appendRow([ "NO", "NAMA", "NISN", "MAPEL", "KELAS", "TP1", "TP2", "TP3", "TP4", "TP5", "TP6", "TP7", "TP8", "LM1", "LM2", "LM3", "LM4", "LM5", "LM6", "LM7", "LM8", "NA STS", "NA SAS", "TANGGAL INPUT" ]); } } function showDataPage() { return HtmlService.createHtmlOutputFromFile('data') .setWidth(1200) .setHeight(600); } function getData() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('DATA'); // ganti sesuai nama sheet kamu const data = sheet.getDataRange().getValues(); return data; } // Simpan data siswa function simpanData(data) { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data"); const semuaData = sheet.getDataRange().getValues(); const nomorUrut = semuaData.length; const totalTP = [data.tp_1, data.tp_2, data.tp_3, data.tp_4, data.tp_5, data.tp_6, data.tp_7, data.tp_8] .reduce((sum, val) => sum + (parseFloat(val) || 0), 0); const totalLM = [data.lm_1, data.lm_2, data.lm_3, data.lm_4, data.lm_5, data.lm_6, data.lm_7, data.lm_8] .reduce((sum, val) => sum + (parseFloat(val) || 0), 0); const na_sts = (totalTP / 8).toFixed(2); const na_sas = (totalLM / 8).toFixed(2); const row = [ nomorUrut, data.nama_siswa, data.nisn, data.mata_pelajaran, data.kelas, data.tp_1, data.tp_2, data.tp_3, data.tp_4, data.tp_5, data.tp_6, data.tp_7, data.tp_8, data.lm_1, data.lm_2, data.lm_3, data.lm_4, data.lm_5, data.lm_6, data.lm_7, data.lm_8, na_sts, na_sas, new Date() ]; sheet.getRange(sheet.getLastRow() + 1, 1, 1, row.length).setValues([row]); SpreadsheetApp.flush(); // Pastikan data segera disimpan resetNomorUrut(); // Menjaga urutan NO tetap rapi return '✅ Data berhasil disimpan!'; } // Fungsi reset nomor urut otomatis function resetNomorUrut() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data"); const data = sheet.getDataRange().getValues(); for (let i = 1; i < data.length; i++) { sheet.getRange(i + 1, 1).setValue(i); } SpreadsheetApp.flush(); } // Cari data berdasarkan NISN function cariData(nisn) { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data"); const data = sheet.getDataRange().getValues(); for (let i = 1; i < data.length; i++) { if (data[i][2] == nisn) { return { rowIndex: i + 1, nama_siswa: data[i][1], nisn: data[i][2], mata_pelajaran: data[i][3], kelas: data[i][4], tp_1: data[i][5], tp_2: data[i][6], tp_3: data[i][7], tp_4: data[i][8], tp_5: data[i][9], tp_6: data[i][10], tp_7: data[i][11], tp_8: data[i][12], lm_1: data[i][13], lm_2: data[i][14], lm_3: data[i][15], lm_4: data[i][16], lm_5: data[i][17], lm_6: data[i][18], lm_7: data[i][19], lm_8: data[i][20], na_sts: data[i][21], na_sas: data[i][22], tanggal_input: data[i][23] }; } } return null; // Jika data tidak ditemukan } function ambilDataRapor() { const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Data Rapor"); const data = sheet.getDataRange().getValues(); // Ambil semua data return data.slice(1); // Hapus header } // Skript Untuk integrasi ke pengaturan.html function simpanDataTP(mapel, tpList, semester) { const ss = SpreadsheetApp.openById("1AThNmj05y6NqfXWpn9AQOPoNcNf-xpEeRx58WZlQnfY"); let sheet = ss.getSheetByName("TP"); if (!sheet) { sheet = ss.insertSheet("TP"); sheet.appendRow(["No", "MAPEL", "TP", "Semester"]); } const tps = tpList.split("\n").map(tp => tp.trim()).filter(tp => tp !== ""); const startRow = sheet.getLastRow() + 1; for (let i = 0; i < tps.length; i++) { sheet.appendRow([ startRow + i - 1, // Nomor urut mapel, tps[i], semester ]); } } function doPost(e) { try { const sheet = SpreadsheetApp.openById('1AThNmj05y6NqfXWpn9AQOPoNcNf-xpEeRx58WZlQnfY').getSheetByName('TP'); const data = JSON.parse(e.postData.contents); const lastRow = sheet.getLastRow(); const no = lastRow + 1; // Menambah nomor urut sheet.appendRow([no, data.mapel, data.tp, data.semester]); return ContentService.createTextOutput(JSON.stringify({ success: true })) .setMimeType(ContentService.MimeType.JSON); } catch (err) { return ContentService.createTextOutput(JSON.stringify({ success: false, error: err.message })) .setMimeType(ContentService.MimeType.JSON); } }
<!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Form Nilai Rapor</title> <!-- ✅ Bootstrap 5 CDN --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" /> <style> * { box-sizing: border-box; } body { font-family: 'Segoe UI', sans-serif; margin: 0; padding: 0; background-color: #f5f7fa; color: #333; display: flex; height: 100vh; } .sidebar { width: 220px; background-color: #1a73e8; color: white; padding: 20px; display: flex; flex-direction: column; } .sidebar h2 { color: white; margin-bottom: 30px; font-size: 1.2em; text-align: center; } .sidebar a { color: white; text-decoration: none; margin-bottom: 15px; font-weight: 500; display: block; transition: background 0.3s; } .sidebar a:hover { background-color: #1558b0; padding-left: 10px; border-radius: 4px; } .content { flex-grow: 1; padding: 20px; overflow-y: auto; } h2 { text-align: center; color: #1a73e8; } .section { background: white; padding: 20px; border-radius: 12px; margin-bottom: 20px; box-shadow: 0 2px 6px rgba(0,0,0,0.05); } h3 { margin-bottom: 15px; color: #444; } label { font-size: 0.9em; margin-top: 10px; display: block; } input, select { width: 100%; padding: 6px 8px; margin-top: 5px; font-size: 0.9em; border: 1px solid #ccc; border-radius: 6px; } .grid-inputs { display: grid; grid-template-columns: repeat(auto-fill, minmax(70px, 1fr)); gap: 10px; } .grid-inputs label { font-size: 0.8em; } button { background-color: #1a73e8; color: white; padding: 12px; width: 100%; border: none; border-radius: 8px; font-size: 1em; cursor: pointer; margin-top: 10px; } button:hover { background-color: #0f4ea4; } input[readonly] { background-color: #eee; } .hidden { display: none; } </style> </head> <!-- Sidebar --> <nav class="sidebar d-flex flex-column p-3 bg-primary text-white" style="width: 220px; height: 100vh;"> <h2 class="text-center mb-4">📊 Menu Rapor</h2> <!-- HTML untuk Menampilkan Nama Guru --> <div class="mb-4 small"> 👤 <strong id="user-name">Guru</strong><br/> 🧭 <em id="user-role">Pengguna</em> </div> <!-- Script untuk Menampilkan Nama Guru yang Login --> <script> function tampilkanNamaGuru() { google.script.run.withSuccessHandler(function(response) { if (response.success) { document.getElementById('user-name').textContent = response.nama; // Set nama guru document.getElementById('user-role').textContent = response.role; // Set role Guru } else { alert('Login gagal: ' + response.message); } }).verifyLogin('USERNAME', 'PASSWORD'); // Ganti dengan username dan password yang sesuai } // Panggil fungsi saat halaman dimuat window.onload = tampilkanNamaGuru; </script> <ul class="nav nav-pills flex-column mb-auto"> <li class="nav-item"> <a href="#" class="nav-link text-white">🏠 Beranda</a> </li> <li> <a href="#" class="nav-link text-white">📝 Input Nilai</a> </li> <li> <a href="#" class="nav-link text-white">📄 Lihat Data</a> </li> <li> <a href="#" class="nav-link text-white">⚙️ Pengaturan</a> </li> <li> <a href="#" class="nav-link text-white" onclick="logout()">🚪 Logout</a> </li> </ul> </nav> <div class="content"> <h2 class="text-center text-primary mb-4">📝 Form Input Nilai Rapor</h2> <form id="raporForm"> <!-- Identitas --> <div class="section mb-4"> <h3 class="mb-3">📘 Identitas Siswa</h3> <div class="mb-3"> <label for="nama_siswa" class="form-label">Nama Siswa</label> <input type="text" class="form-control" name="nama_siswa" id="nama_siswa" required /> </div> <div class="mb-3"> <label for="nisn" class="form-label">NISN</label> <input type="text" class="form-control" name="nisn" id="nisn" required /> </div> <div class="mb-3"> <label for="kelas" class="form-label">Kelas</label> <select name="kelas" id="kelas" class="form-select" required> <option value="">--Pilih Kelas--</option> <option>Kelas I</option> <option>Kelas II</option> <option>Kelas III</option> <option>Kelas IV</option> <option>Kelas V</option> <option>Kelas VI</option> </select> </div> <div class="mb-3"> <label for="mata_pelajaran" class="form-label">Mata Pelajaran</label> <select name="mata_pelajaran" id="mata_pelajaran" class="form-select" required> <option value="">--Pilih Mapel--</option> <option>Pendidikan Agama Katolik dan Budi Pekerti</option> <option>Pendidikan Pancasila</option> <option>Bahasa Indonesia</option> <option>Matematika</option> <option>IPAS</option> <option>Bahasa Inggris</option> <option>Seni Tari</option> <option>Seni Musik</option> <option>Seni Rupa</option> <option>Mulok 1</option> <option>Mulok 2</option> <option>Mulok 3</option> </select> </div> <form id="raporForm"> <!-- TP --> <div class="section"> <h3>🧪 Nilai Sumatif TP</h3> <div class="grid-inputs" id="tpInputs"></div> </div> <!-- LM --> <div class="section"> <h3>📚 Nilai Sumatif LM</h3> <div class="grid-inputs" id="lmInputs"></div> </div> <!-- Input Nilai Akhir --> <div class="section"> <h3>📊 Nilai Akhir</h3> <label>NA STS (otomatis)</label> <input type="number" name="sts" id="sts" readonly> <label>NA SAS (otomatis)</label> <input type="number" name="sas" id="sas" readonly> </div> <!-- Tombol Simpan, Update, dll --> <button type="submit" id="saveBtn">💾 Simpan Nilai</button> <button type="button" id="updateBtn" class="hidden">Update Nilai</button> <button type="button" id="searchBtn">🔍 Cari Data</button> <button type="button" id="deleteBtn" class="hidden">🗑️ Hapus Data</button> </form> <script> const form = document.getElementById("raporForm"); // Generate input TP dan LM window.onload = function () { const tpContainer = document.getElementById("tpInputs"); const lmContainer = document.getElementById("lmInputs"); for (let i = 1; i <= 8; i++) { tpContainer.innerHTML += ` <div> <label>TP ${i}</label> <input type="number" name="tp_${i}" min="0" max="100" required> </div>`; lmContainer.innerHTML += ` <div> <label>LM ${i}</label> <input type="number" name="lm_${i}" min="0" max="100" required> </div>`; } }; // Hitung rata-rata otomatis saat input berubah form.addEventListener("input", () => { let totalTP = 0, totalLM = 0; for (let i = 1; i <= 8; i++) { const tpVal = parseFloat(form.querySelector(`[name="tp_${i}"]`)?.value) || 0; const lmVal = parseFloat(form.querySelector(`[name="lm_${i}"]`)?.value) || 0; totalTP += tpVal; totalLM += lmVal; } form.querySelector('[name="sts"]').value = (totalTP / 8).toFixed(2); form.querySelector('[name="sas"]').value = (totalLM / 8).toFixed(2); }); // Fungsi untuk meng-clear form function clearForm() { form.reset(); // Reset form for (let i = 1; i <= 8; i++) { form.querySelector(`[name="tp_${i}"]`).value = ''; form.querySelector(`[name="lm_${i}"]`).value = ''; } form.querySelector('[name="sts"]').value = ''; form.querySelector('[name="sas"]').value = ''; document.getElementById("updateBtn").classList.add("hidden"); document.getElementById("deleteBtn").classList.add("hidden"); } // Tombol Simpan Data document.getElementById("saveBtn").addEventListener("click", (e) => { e.preventDefault(); // Mencegah form submit default const nisn = form.querySelector('[name="nisn"]').value.trim(); if (!nisn) { alert("❌ Masukkan NISN untuk menyimpan data."); return; } const data = { nisn: nisn, nama_siswa: form.querySelector('[name="nama_siswa"]').value.trim(), kelas: form.querySelector('[name="kelas"]').value.trim(), mata_pelajaran: form.querySelector('[name="mata_pelajaran"]').value.trim(), sts: form.querySelector('[name="sts"]').value.trim(), sas: form.querySelector('[name="sas"]').value.trim(), }; for (let i = 1; i <= 8; i++) { data[`tp_${i}`] = form.querySelector(`[name="tp_${i}"]`).value.trim(); data[`lm_${i}`] = form.querySelector(`[name="lm_${i}"]`).value.trim(); } google.script.run .withSuccessHandler(() => { alert("✅ Data berhasil disimpan."); clearForm(); // Clear form after saving }) .withFailureHandler((err) => alert("❌ Gagal menyimpan data: " + err.message)) .simpanData(data); }); // Tombol Cari Data document.getElementById("searchBtn").addEventListener("click", () => { const nisn = form.querySelector('[name="nisn"]').value.trim(); if (!nisn) { alert("❌ Masukkan NISN untuk mencari data."); return; } google.script.run .withSuccessHandler((data) => { if (data) { form.querySelector('[name="nama_siswa"]').value = data.nama_siswa || ""; form.querySelector('[name="kelas"]').value = data.kelas || ""; form.querySelector('[name="mata_pelajaran"]').value = data.mata_pelajaran || ""; for (let i = 1; i <= 8; i++) { if (data[`tp_${i}`]) form.querySelector(`[name="tp_${i}"]`).value = data[`tp_${i}`]; if (data[`lm_${i}`]) form.querySelector(`[name="lm_${i}"]`).value = data[`lm_${i}`]; } form.querySelector('[name="sts"]').value = data.sts || ""; form.querySelector('[name="sas"]').value = data.sas || ""; document.getElementById("updateBtn").classList.remove("hidden"); document.getElementById("deleteBtn").classList.remove("hidden"); } else { alert("❌ Data tidak ditemukan."); } }) .withFailureHandler((err) => alert("❌ Gagal mencari data: " + err.message)) .cariData(nisn); }); // Tombol Update Data document.getElementById("updateBtn").addEventListener("click", () => { const nisn = form.querySelector('[name="nisn"]').value.trim(); if (!nisn) { alert("❌ NISN tidak ditemukan."); return; } const data = { nisn: nisn, nama_siswa: form.querySelector('[name="nama_siswa"]').value.trim(), kelas: form.querySelector('[name="kelas"]').value.trim(), mata_pelajaran: form.querySelector('[name="mata_pelajaran"]').value.trim(), sts: form.querySelector('[name="sts"]').value.trim(), sas: form.querySelector('[name="sas"]').value.trim(), }; for (let i = 1; i <= 8; i++) { data[`tp_${i}`] = form.querySelector(`[name="tp_${i}"]`).value.trim(); data[`lm_${i}`] = form.querySelector(`[name="lm_${i}"]`).value.trim(); } google.script.run .withSuccessHandler(() => { alert("✅ Data berhasil diperbarui."); clearForm(); // Clear form after updating }) .withFailureHandler((err) => alert("❌ Gagal memperbarui data: " + err.message)) .updateData(data); }); // Tombol Hapus Data document.getElementById("deleteBtn").addEventListener("click", () => { const nisn = form.querySelector('[name="nisn"]').value.trim(); if (!nisn) { alert("❌ NISN tidak ditemukan."); return; } const confirmDelete = confirm("⚠️ Apakah Anda yakin ingin menghapus data ini?"); if (confirmDelete) { google.script.run .withSuccessHandler(() => { alert("✅ Data berhasil dihapus."); clearForm(); // Clear form after deleting }) .withFailureHandler((err) => alert("❌ Gagal menghapus data: " + err.message)) .hapusData(nisn); } }); </script> <script> // Logout handler function logout() { if (confirm("Yakin ingin logout?")) { google.script.run .withSuccessHandler(() => location.reload()) .logoutUser(); } }
<!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Form Nilai Rapor</title> <!-- ✅ Bootstrap 5 CDN --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" /> <style> * { box-sizing: border-box; } body { font-family: 'Segoe UI', sans-serif; margin: 0; padding: 0; background-color: #f5f7fa; color: #333; display: flex; height: 100vh; } .sidebar { width: 220px; background-color: #1a73e8; color: white; padding: 20px; display: flex; flex-direction: column; } .sidebar h2 { color: white; margin-bottom: 30px; font-size: 1.2em; text-align: center; } .sidebar a { color: white; text-decoration: none; margin-bottom: 15px; font-weight: 500; display: block; transition: background 0.3s; } .sidebar a:hover { background-color: #1558b0; padding-left: 10px; border-radius: 4px; } .content { flex-grow: 1; padding: 20px; overflow-y: auto; } h2 { text-align: center; color: #1a73e8; } .section { background: white; padding: 20px; border-radius: 12px; margin-bottom: 20px; box-shadow: 0 2px 6px rgba(0,0,0,0.05); } h3 { margin-bottom: 15px; color: #444; } label { font-size: 0.9em; margin-top: 10px; display: block; } input, select { width: 100%; padding: 6px 8px; margin-top: 5px; font-size: 0.9em; border: 1px solid #ccc; border-radius: 6px; } .grid-inputs { display: grid; grid-template-columns: repeat(auto-fill, minmax(70px, 1fr)); gap: 10px; } .grid-inputs label { font-size: 0.8em; } button { background-color: #1a73e8; color: white; padding: 12px; width: 100%; border: none; border-radius: 8px; font-size: 1em; cursor: pointer; margin-top: 10px; } button:hover { background-color: #0f4ea4; } input[readonly] { background-color: #eee; } .hidden { display: none; } </style> </head> <!-- Sidebar --> <nav class="sidebar d-flex flex-column p-3 bg-primary text-white" style="width: 220px; height: 100vh;"> <h2 class="text-center mb-4">📊 Menu Rapor</h2> <!-- HTML untuk Menampilkan Nama Guru --> <div class="mb-4 small"> 👤 <strong id="user-name">Guru</strong><br/> 🧭 <em id="user-role">Pengguna</em> </div> <!-- Script untuk Menampilkan Nama Guru yang Login --> <script> function tampilkanNamaGuru() { google.script.run.withSuccessHandler(function(response) { if (response.success) { document.getElementById('user-name').textContent = response.nama; // Set nama guru document.getElementById('user-role').textContent = response.role; // Set role Guru } else { alert('Login gagal: ' + response.message); } }).verifyLogin('USERNAME', 'PASSWORD'); // Ganti dengan username dan password yang sesuai } // Panggil fungsi saat halaman dimuat window.onload = tampilkanNamaGuru; </script> <ul class="nav nav-pills flex-column mb-auto"> <li class="nav-item"> <a href="#" class="nav-link text-white">🏠 Beranda</a> </li> <li> <a href="#" class="nav-link text-white">📝 Input Nilai</a> </li> <li> <a href="#" class="nav-link text-white">📄 Lihat Data</a> </li> <li> <a href="#" class="nav-link text-white">⚙️ Pengaturan</a> </li> <li> <a href="#" class="nav-link text-white" onclick="logout()">🚪 Logout</a> </li> </ul> </nav> <div class="content"> <h2 class="text-center text-primary mb-4">📝 Form Input Nilai Rapor</h2> <form id="raporForm"> <!-- Identitas --> <div class="section mb-4"> <h3 class="mb-3">📘 Identitas Siswa</h3> <div class="mb-3"> <label for="nama_siswa" class="form-label">Nama Siswa</label> <input type="text" class="form-control" name="nama_siswa" id="nama_siswa" required /> </div> <div class="mb-3"> <label for="nisn" class="form-label">NISN</label> <input type="text" class="form-control" name="nisn" id="nisn" required /> </div> <div class="mb-3"> <label for="kelas" class="form-label">Kelas</label> <select name="kelas" id="kelas" class="form-select" required> <option value="">--Pilih Kelas--</option> <option>Kelas I</option> <option>Kelas II</option> <option>Kelas III</option> <option>Kelas IV</option> <option>Kelas V</option> <option>Kelas VI</option> </select> </div> <div class="mb-3"> <label for="mata_pelajaran" class="form-label">Mata Pelajaran</label> <select name="mata_pelajaran" id="mata_pelajaran" class="form-select" required> <option value="">--Pilih Mapel--</option> <option>Pendidikan Agama Katolik dan Budi Pekerti</option> <option>Pendidikan Pancasila</option> <option>Bahasa Indonesia</option> <option>Matematika</option> <option>IPAS</option> <option>Bahasa Inggris</option> <option>Seni Tari</option> <option>Seni Musik</option> <option>Seni Rupa</option> <option>Mulok 1</option> <option>Mulok 2</option> <option>Mulok 3</option> </select> </div> <form id="raporForm"> <!-- TP --> <div class="section"> <h3>🧪 Nilai Sumatif TP</h3> <div class="grid-inputs" id="tpInputs"></div> </div> <!-- LM --> <div class="section"> <h3>📚 Nilai Sumatif LM</h3> <div class="grid-inputs" id="lmInputs"></div> </div> <!-- Input Nilai Akhir --> <div class="section"> <h3>📊 Nilai Akhir</h3> <label>NA STS (otomatis)</label> <input type="number" name="sts" id="sts" readonly> <label>NA SAS (otomatis)</label> <input type="number" name="sas" id="sas" readonly> </div> <!-- Tombol Simpan, Update, dll --> <button type="submit" id="saveBtn">💾 Simpan Nilai</button> <button type="button" id="updateBtn" class="hidden">Update Nilai</button> <button type="button" id="searchBtn">🔍 Cari Data</button> <button type="button" id="deleteBtn" class="hidden">🗑️ Hapus Data</button> </form> <script> const form = document.getElementById("raporForm"); // Generate input TP dan LM window.onload = function () { const tpContainer = document.getElementById("tpInputs"); const lmContainer = document.getElementById("lmInputs"); for (let i = 1; i <= 8; i++) { tpContainer.innerHTML += ` <div> <label>TP ${i}</label> <input type="number" name="tp_${i}" min="0" max="100" required> </div>`; lmContainer.innerHTML += ` <div> <label>LM ${i}</label> <input type="number" name="lm_${i}" min="0" max="100" required> </div>`; } }; // Hitung rata-rata otomatis saat input berubah form.addEventListener("input", () => { let totalTP = 0, totalLM = 0; for (let i = 1; i <= 8; i++) { const tpVal = parseFloat(form.querySelector(`[name="tp_${i}"]`)?.value) || 0; const lmVal = parseFloat(form.querySelector(`[name="lm_${i}"]`)?.value) || 0; totalTP += tpVal; totalLM += lmVal; } form.querySelector('[name="sts"]').value = (totalTP / 8).toFixed(2); form.querySelector('[name="sas"]').value = (totalLM / 8).toFixed(2); }); // Fungsi untuk meng-clear form function clearForm() { form.reset(); // Reset form for (let i = 1; i <= 8; i++) { form.querySelector(`[name="tp_${i}"]`).value = ''; form.querySelector(`[name="lm_${i}"]`).value = ''; } form.querySelector('[name="sts"]').value = ''; form.querySelector('[name="sas"]').value = ''; document.getElementById("updateBtn").classList.add("hidden"); document.getElementById("deleteBtn").classList.add("hidden"); } // Tombol Simpan Data document.getElementById("saveBtn").addEventListener("click", (e) => { e.preventDefault(); // Mencegah form submit default const nisn = form.querySelector('[name="nisn"]').value.trim(); if (!nisn) { alert("❌ Masukkan NISN untuk menyimpan data."); return; } const data = { nisn: nisn, nama_siswa: form.querySelector('[name="nama_siswa"]').value.trim(), kelas: form.querySelector('[name="kelas"]').value.trim(), mata_pelajaran: form.querySelector('[name="mata_pelajaran"]').value.trim(), sts: form.querySelector('[name="sts"]').value.trim(), sas: form.querySelector('[name="sas"]').value.trim(), }; for (let i = 1; i <= 8; i++) { data[`tp_${i}`] = form.querySelector(`[name="tp_${i}"]`).value.trim(); data[`lm_${i}`] = form.querySelector(`[name="lm_${i}"]`).value.trim(); } google.script.run .withSuccessHandler(() => { alert("✅ Data berhasil disimpan."); clearForm(); // Clear form after saving }) .withFailureHandler((err) => alert("❌ Gagal menyimpan data: " + err.message)) .simpanData(data); }); // Tombol Cari Data document.getElementById("searchBtn").addEventListener("click", () => { const nisn = form.querySelector('[name="nisn"]').value.trim(); if (!nisn) { alert("❌ Masukkan NISN untuk mencari data."); return; } google.script.run .withSuccessHandler((data) => { if (data) { form.querySelector('[name="nama_siswa"]').value = data.nama_siswa || ""; form.querySelector('[name="kelas"]').value = data.kelas || ""; form.querySelector('[name="mata_pelajaran"]').value = data.mata_pelajaran || ""; for (let i = 1; i <= 8; i++) { if (data[`tp_${i}`]) form.querySelector(`[name="tp_${i}"]`).value = data[`tp_${i}`]; if (data[`lm_${i}`]) form.querySelector(`[name="lm_${i}"]`).value = data[`lm_${i}`]; } form.querySelector('[name="sts"]').value = data.sts || ""; form.querySelector('[name="sas"]').value = data.sas || ""; document.getElementById("updateBtn").classList.remove("hidden"); document.getElementById("deleteBtn").classList.remove("hidden"); } else { alert("❌ Data tidak ditemukan."); } }) .withFailureHandler((err) => alert("❌ Gagal mencari data: " + err.message)) .cariData(nisn); }); // Tombol Update Data document.getElementById("updateBtn").addEventListener("click", () => { const nisn = form.querySelector('[name="nisn"]').value.trim(); if (!nisn) { alert("❌ NISN tidak ditemukan."); return; } const data = { nisn: nisn, nama_siswa: form.querySelector('[name="nama_siswa"]').value.trim(), kelas: form.querySelector('[name="kelas"]').value.trim(), mata_pelajaran: form.querySelector('[name="mata_pelajaran"]').value.trim(), sts: form.querySelector('[name="sts"]').value.trim(), sas: form.querySelector('[name="sas"]').value.trim(), }; for (let i = 1; i <= 8; i++) { data[`tp_${i}`] = form.querySelector(`[name="tp_${i}"]`).value.trim(); data[`lm_${i}`] = form.querySelector(`[name="lm_${i}"]`).value.trim(); } google.script.run .withSuccessHandler(() => { alert("✅ Data berhasil diperbarui."); clearForm(); // Clear form after updating }) .withFailureHandler((err) => alert("❌ Gagal memperbarui data: " + err.message)) .updateData(data); }); // Tombol Hapus Data document.getElementById("deleteBtn").addEventListener("click", () => { const nisn = form.querySelector('[name="nisn"]').value.trim(); if (!nisn) { alert("❌ NISN tidak ditemukan."); return; } const confirmDelete = confirm("⚠️ Apakah Anda yakin ingin menghapus data ini?"); if (confirmDelete) { google.script.run .withSuccessHandler(() => { alert("✅ Data berhasil dihapus."); clearForm(); // Clear form after deleting }) .withFailureHandler((err) => alert("❌ Gagal menghapus data: " + err.message)) .hapusData(nisn); } }); </script> <script> // Logout handler function logout() { if (confirm("Yakin ingin logout?")) { google.script.run .withSuccessHandler(() => location.reload()) .logoutUser(); } }
<!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Lihat Data Nilai</title> <!-- ✅ Bootstrap 5 CDN --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" /> <style> /* Style yang sudah ada sebelumnya */ * { box-sizing: border-box; } body { font-family: 'Segoe UI', sans-serif; margin: 0; padding: 0; background-color: #f5f7fa; color: #333; display: flex; height: 100vh; } .sidebar { width: 220px; background-color: #1a73e8; color: white; padding: 20px; display: flex; flex-direction: column; } .sidebar h2 { color: white; margin-bottom: 30px; font-size: 1.2em; text-align: center; } .sidebar a { color: white; text-decoration: none; margin-bottom: 15px; font-weight: 500; display: block; transition: background 0.3s; } .sidebar a:hover { background-color: #1558b0; padding-left: 10px; border-radius: 4px; } .content { flex-grow: 1; padding: 20px; overflow-y: auto; } h2 { text-align: center; color: #1a73e8; } </style> </head> <!-- Sidebar --> <nav class="sidebar d-flex flex-column p-3 bg-primary text-white" style="width: 220px; height: 100vh;"> <h2 class="text-center mb-4">📊 Menu Rapor</h2> <div class="mb-4 small"> 👤 <strong id="user-name">Guru</strong><br/> 🧭 <em id="user-role">Pengguna</em> </div> <ul class="nav nav-pills flex-column mb-auto"> <li class="nav-item"> <a href="index.html" class="nav-link text-white">🏠 Beranda</a> </li> <li> <a href="#" class="nav-link text-white">📄 Lihat Data</a> </li> <li> <a href="#" class="nav-link text-white">⚙️ Pengaturan</a> </li> <li> <a href="#" class="nav-link text-white" onclick="logout()">🚪 Logout</a> </li> </ul> </nav> <div class="content"> <h2 class="text-center text-primary mb-4">📄 Lihat Data Nilai</h2> <div id="table_div">Memuat data...</div> </div> <script> // Panggil fungsi untuk menampilkan nama guru saat halaman dimuat function tampilkanNamaGuru() { google.script.run.withSuccessHandler(function(response) { if (response.success) { document.getElementById('user-name').textContent = response.nama; // Set nama guru document.getElementById('user-role').textContent = response.role; // Set role Guru } else { alert('Login gagal: ' + response.message); } }).verifyLogin('USERNAME', 'PASSWORD'); // Ganti dengan username dan password yang sesuai } // Memuat dan menampilkan data nilai dari Google Sheets google.charts.load('current', { packages: ['DATA'] }); google.charts.setOnLoadCallback(drawTable); let originalData; function drawTable() { const queryString = encodeURIComponent("SELECT B, C, D, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W"); const spreadsheetId = "1mqz0rC0lBC1YmBVCwy1K64PUnZGKpMuFQ0tww5MknRI"; const dataSourceUrl = `https://docs.google.com/spreadsheets/d/${spreadsheetId}/gviz/tq?tq=${queryString}`; const query = new google.visualization.Query(dataSourceUrl); query.send(function(response) { const data = response.getDataTable(); originalData = data; const table = new google.visualization.Table(document.getElementById('table_div')); table.draw(data, {showRowNumber: false, width: '100%', height: '100%'}); }); } </script> </body> </html>
<!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Form Nilai Rapor</title> <!-- ✅ Bootstrap 5 CDN --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" /> <style> * { box-sizing: border-box; } body { font-family: 'Segoe UI', sans-serif; margin: 0; padding: 0; background-color: #f5f7fa; color: #333; display: flex; height: 100vh; } .sidebar { width: 220px; background-color: #1a73e8; color: white; padding: 20px; display: flex; flex-direction: column; } .sidebar h2 { color: white; margin-bottom: 30px; font-size: 1.2em; text-align: center; } .sidebar a { color: white; text-decoration: none; margin-bottom: 15px; font-weight: 500; display: block; transition: background 0.3s; } .sidebar a:hover { background-color: #1558b0; padding-left: 10px; border-radius: 4px; } .content { flex-grow: 1; padding: 20px; overflow-y: auto; } h2 { text-align: center; color: #1a73e8; } .section { background: white; padding: 20px; border-radius: 12px; margin-bottom: 20px; box-shadow: 0 2px 6px rgba(0,0,0,0.05); } h3 { margin-bottom: 15px; color: #444; } label { font-size: 0.9em; margin-top: 10px; display: block; } input, select { width: 100%; padding: 6px 8px; margin-top: 5px; font-size: 0.9em; border: 1px solid #ccc; border-radius: 6px; } .grid-inputs { display: grid; grid-template-columns: repeat(auto-fill, minmax(70px, 1fr)); gap: 10px; } .grid-inputs label { font-size: 0.8em; } button { background-color: #1a73e8; color: white; padding: 12px; width: 100%; border: none; border-radius: 8px; font-size: 1em; cursor: pointer; margin-top: 10px; } button:hover { background-color: #0f4ea4; } input[readonly] { background-color: #eee; } .hidden { display: none; } </style> </head> <!-- Sidebar --> <nav class="sidebar d-flex flex-column p-3 bg-primary text-white" style="width: 220px; height: 100vh;"> <h2 class="text-center mb-4">📊 Menu Rapor</h2> <!-- HTML untuk Menampilkan Nama Guru --> <div class="mb-4 small"> 👤 <strong id="user-name">Guru</strong><br/> 🧭 <em id="user-role">Pengguna</em> </div> </script> <ul class="nav nav-pills flex-column mb-auto"> <li class="nav-item"> <a href="#" class="nav-link text-white">🏠 Beranda</a> </li> <li> <a href="#" class="nav-link text-white">📝 Input Nilai</a> </li> <li> <a href="#" class="nav-link text-white">📄 Lihat Nilai</a> </li> <li> <a href="#" class="nav-link text-white">⚙️ Raport</a> </li> <li> <a href="#" class="nav-link text-white" onclick="logout()">🚪 Logout</a> </li> </ul> </nav> <!-- Content --> <div class="content"> <h2>Selamat datang di Dashboard Rapor Online!</h2> <p>Kelola data rapor, nilai, dan deskripsi capaian dengan mudah melalui aplikasi ini.</p> <p>Akses berbagai fitur untuk memperbarui nilai, melihat capaian kompetensi, dan mencetak rapor dengan cepat.</p> <p>Gunakan menu di sebelah kiri untuk navigasi ke berbagai bagian aplikasi dan pantau perkembangan siswa secara real-time.</p> <p>Semua data disinkronkan dengan Google Sheets, sehingga Anda bisa mengelola nilai dan laporan kapan saja, di mana saja.</p> <!-- Nama dan Kontak di sebelah kanan bawah --> <div style="position: absolute; bottom: 10px; right: 20px; font-size: 14px; color: #555; text-align: left;"> <p>Markus Paru</p> <p>+6281338607300</p> <p>markusparu54@guru.sd.belajar.id</p> </div> </div> <script> // Fungsi logout function logout() { localStorage.clear(); window.location.href = "login.html"; } // Panggil saat halaman dimuat window.onload = tampilkanNamaGuru; </script> </body> </html>
<!-- guru.html --> <!DOCTYPE html> <html lang="id"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <title>Data Guru</title> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" /> </head> <body class="bg-light"> <div class="container mt-4"> <h2 class="mb-4 text-primary">👩‍🏫 Data Guru</h2> <table class="table table-bordered table-striped"> <thead class="table-primary"> <tr> <th>ID</th> <th>Username</th> <th>Password</th> <th>Nama</th> <th>Jabatan</th> <th>Email</th> </tr> </thead> <tbody id="dataGuruBody"> <tr><td colspan="6">Memuat data...</td></tr> </tbody> </table> </div> <script> // Ambil data guru dari Apps Script google.script.run.withSuccessHandler(function(data) { const tbody = document.getElementById('dataGuruBody'); tbody.innerHTML = ""; // Kosongkan if (data.length === 0) { tbody.innerHTML = "<tr><td colspan='6'>Tidak ada data ditemukan.</td></tr>"; return; } data.forEach(function(row) { const tr = document.createElement("tr"); row.forEach(function(cell) { const td = document.createElement("td"); td.textContent = cell; tr.appendChild(td); }); tbody.appendChild(tr); }); }).getDataGuru(); // Fungsi dari .gs </script> </body> </html>
Editor Settings
Theme
Key bindings
Full width
Lines