Prompt dan Source Code Aplikasi E-Sarpras Sekolah
Sistem Informasi Sarana dan Prasarana (E-Sarpras) adalah kebutuhan krusial bagi instansi atau sekolah modern. Jika Anda mencari solusi yang gratis, aman, dan ringan, kombinasi antara Google Apps Script dan Blogger adalah jawabannya. Pada artikel ini, kita akan membongkar rahasia membuat aplikasi E-Sarpras secara lengkap beserta source code-nya.
Apa itu Google Apps Script & Blogger?
1. Google Apps Script (Backend & Database)
Fungsi: Berperan sebagai otak (server) dan database aplikasi.
Manfaat: Anda tidak perlu menyewa hosting atau membeli database SQL. Semua data inventaris akan tersimpan rapi dan aman di dalam Google Sheets milik Anda sendiri. Script ini bertugas menerima data dari pengguna (Frontend) dan menyimpannya ke baris Excel.
2. Blogger (Frontend & UI)
Fungsi: Berperan sebagai antarmuka (tampilan) yang dilihat oleh pengguna.
Manfaat: Blogger menyediakan hosting gratis dengan server Google yang sangat cepat dan tidak pernah down. Dengan menyuntikkan kode HTML/Blogger XML, kita bisa menyulap blog biasa menjadi aplikasi web yang profesional, responsif di HP, dan dilengkapi berbagai fitur canggih tanpa biaya sepeser pun.
Prompt AI (Gemini) Pembuat E-Sarpras
Aplikasi ini dibangun dengan bantuan AI. Jika Anda ingin bereksperimen atau memodifikasinya sendiri, berikut adalah prompt rahasia yang saya gunakan untuk memerintahkan AI Gemini membuatkan sistem yang canggih ini:
Buatkan saya Source Code Sistem Informasi Sarana dan Prasarana (E-Sarpras) berbasis web.
Sistem ini menggunakan Google Apps Script sebagai Backend (menyimpan data ke Google Sheets) dan Blogger (XML/HTML) sebagai Frontend.
Syarat Aplikasi:
1. Desain Frontend menggunakan Bootstrap 5, FontAwesome, dan SweetAlert2 agar elegan dan profesional.
2. Terdapat 5 Menu/Tab: Dashboard (dengan Chart.js), Data Aset (CRUD), Peminjaman Barang, Laporan (Print PDF menggunakan jsPDF & AutoTable), dan Label Barcode (Generate Code128 menggunakan JsBarcode).
3. Terdapat fitur Scanner menggunakan kamera (Html5-QRCode) untuk scan Barcode 1D.
4. Buatkan juga satu tab Pengaturan untuk memasukkan Link Web App Google Apps Script dan Identitas Sekolah secara dinamis (tanpa perlu edit kode HTML).
5. Kode Backend harus lengkap dengan fungsi doGet, doPost, setupDatabase otomatis untuk tabel (Data_Sarpras, Data_Peminjaman, Pengaturan).
Panduan Instalasi & Deploy E-Sarpras
Ikuti langkah-langkah mudah di bawah ini agar aplikasi Anda dapat berjalan dengan sempurna:
- Buka akun Google Drive Anda, lalu buat file Google Sheets baru. Bebas beri nama apa saja (misal: "Database Sarpras").
- Pada menu atas Google Sheets, klik Ekstensi > Apps Script.
- Hapus kode bawaan yang ada di sana, lalu tempel (paste) kode Backend di bawah ini.
- Simpan proyek, lalu klik tombol biru Terapkan (Deploy) > Deployment Baru (New deployment).
- Pilih jenis Aplikasi Web. Isi kolom deskripsi.
Pada Akses: pilih "Siapa saja" (Anyone). Lalu klik Terapkan. - Beri izin akses pada pop-up yang muncul. Setelah selesai, salin URL Aplikasi Web tersebut.
- Gunakan tema XML Frontend dengan menekan tombol Download Tema pelangi di bawah postingan ini.
- Buka Blogger, masuk ke menu Tema, Edit HTML, hapus semua kode bawaan lalu paste kode hasil download tadi. Ganti URL Apps Script pada bagian bawah kode XML tersebut dengan URL yang baru Anda salin.
Source Code Google Apps Script (Backend)
Salin kode di bawah ini ke dalam Google Apps Script Anda (Langkah 3):
/**
* SISTEM INFORMASI SARPRAS BACKEND (FINAL V4)
* Mendukung: CRUD Aset, Peminjaman, Scanner 1D, Laporan PDF, & Pengaturan
*/
const SHEET_SARPRAS = 'Data_Sarpras';
const SHEET_PENGATURAN = 'Pengaturan';
const SHEET_PEMINJAMAN = 'Data_Peminjaman';
function setupDatabase() {
let ss = SpreadsheetApp.getActiveSpreadsheet();
// 1. Setup Sheet Sarpras
let sheetSarpras = ss.getSheetByName(SHEET_SARPRAS);
if (!sheetSarpras) {
sheetSarpras = ss.insertSheet(SHEET_SARPRAS);
sheetSarpras.appendRow(['ID', 'Waktu', 'Nama Barang', 'Kategori', 'Jumlah', 'Kondisi', 'Ruangan', 'Keterangan']);
sheetSarpras.getRange("A1:H1").setFontWeight("bold").setBackground("#e2e8f0");
sheetSarpras.setFrozenRows(1);
}
// 2. Setup Sheet Pengaturan
let sheetPengaturan = ss.getSheetByName(SHEET_PENGATURAN);
if (!sheetPengaturan) {
sheetPengaturan = ss.insertSheet(SHEET_PENGATURAN);
sheetPengaturan.appendRow(['Key', 'Value']);
sheetPengaturan.getRange("A1:B1").setFontWeight("bold").setBackground("#e2e8f0");
// Konfigurasi Default Identitas
let defaultSettings = [
['namaSekolah', 'SMP NEGERI 3 KERINCI'],
['alamatSekolah', 'Jl Lempur Tengah, Kec. Gunung Raya. Kab. Kerinci - Kode Pos 37174'],
['tempatTtd', 'Kerinci'],
['logoKiri', 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Tut_Wuri_Handayani.svg/1200px-Tut_Wuri_Handayani.svg.png'],
['logoKanan', 'https://upload.wikimedia.org/wikipedia/commons/thumb/b/b2/Tut_Wuri_Handayani.svg/1200px-Tut_Wuri_Handayani.svg.png'],
['namaKepsek', 'Hamdani, S.Pd.'],
['nipKepsek', '-'],
['namaWaka', '-'],
['nipWaka', '-']
];
defaultSettings.forEach(row => sheetPengaturan.appendRow(row));
sheetPengaturan.autoResizeColumns(1, 2);
}
// 3. Setup Sheet Peminjaman
let sheetPeminjaman = ss.getSheetByName(SHEET_PEMINJAMAN);
if (!sheetPeminjaman) {
sheetPeminjaman = ss.insertSheet(SHEET_PEMINJAMAN);
sheetPeminjaman.appendRow(['ID_Pinjam', 'Waktu_Input', 'Nama_Peminjam', 'ID_Barang', 'Nama_Barang', 'Tgl_Pinjam', 'Tgl_Kembali', 'Status']);
sheetPeminjaman.getRange("A1:H1").setFontWeight("bold").setBackground("#e2e8f0");
sheetPeminjaman.setFrozenRows(1);
}
return { sarpras: sheetSarpras, pengaturan: sheetPengaturan, peminjaman: sheetPeminjaman };
}
function doGet(e) {
let db = setupDatabase();
// Ambil Data Sarpras
let dataSarpras = db.sarpras.getDataRange().getDisplayValues();
let headers = dataSarpras[0];
let resultSarpras = [];
for (let i = 1; i < dataSarpras.length; i++) {
let obj = {};
for (let j = 0; j < headers.length; j++) obj[headers[j]] = dataSarpras[i][j];
resultSarpras.push(obj);
}
// Ambil Data Peminjaman
let dataPinjam = db.peminjaman.getDataRange().getDisplayValues();
let headersPinjam = dataPinjam[0];
let resultPinjam = [];
for (let i = 1; i < dataPinjam.length; i++) {
let obj = {};
for (let j = 0; j < headersPinjam.length; j++) obj[headersPinjam[j]] = dataPinjam[i][j];
resultPinjam.push(obj);
}
// Ambil Data Pengaturan
let dataPengaturan = db.pengaturan.getDataRange().getDisplayValues();
let resultPengaturan = {};
for (let i = 1; i < dataPengaturan.length; i++) resultPengaturan[dataPengaturan[i][0]] = dataPengaturan[i][1];
return ContentService.createTextOutput(JSON.stringify({
status: 'success', data: resultSarpras, peminjaman: resultPinjam, settings: resultPengaturan
})).setMimeType(ContentService.MimeType.JSON);
}
function doPost(e) {
try {
let db = setupDatabase();
let postData = JSON.parse(e.postData.contents);
let action = postData.action;
// --- AKSI SARPRAS ---
if (action === 'create') {
let id = Utilities.getUuid();
let timestamp = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "dd/MM/yyyy HH:mm:ss");
db.sarpras.appendRow([id, timestamp, postData.namaBarang, postData.kategori, postData.jumlah, postData.kondisi, postData.ruangan, postData.keterangan || '-']);
return ContentService.createTextOutput(JSON.stringify({status: 'success', message: 'Data Sarpras berhasil ditambahkan!'})).setMimeType(ContentService.MimeType.JSON);
}
if (action === 'delete') {
let data = db.sarpras.getDataRange().getValues();
for (let i = 1; i < data.length; i++) {
if (data[i][0] === postData.id) {
db.sarpras.deleteRow(i + 1);
return ContentService.createTextOutput(JSON.stringify({status: 'success', message: 'Data berhasil dihapus!'})).setMimeType(ContentService.MimeType.JSON);
}
}
return ContentService.createTextOutput(JSON.stringify({status: 'error', message: 'Data tidak ditemukan!'})).setMimeType(ContentService.MimeType.JSON);
}
if (action === 'updateCondition') {
let data = db.sarpras.getDataRange().getValues();
for (let i = 1; i < data.length; i++) {
if (data[i][0] === postData.id) {
db.sarpras.getRange(i + 1, 6).setValue(postData.kondisi);
db.sarpras.getRange(i + 1, 8).setValue(postData.keterangan);
return ContentService.createTextOutput(JSON.stringify({status: 'success', message: 'Kondisi barang diperbarui!'})).setMimeType(ContentService.MimeType.JSON);
}
}
return ContentService.createTextOutput(JSON.stringify({status: 'error', message: 'Data barang tidak ditemukan!'})).setMimeType(ContentService.MimeType.JSON);
}
// --- AKSI PEMINJAMAN ---
if (action === 'createPeminjaman') {
let idPinjam = Utilities.getUuid();
let timestamp = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "dd/MM/yyyy HH:mm:ss");
db.peminjaman.appendRow([idPinjam, timestamp, postData.namaPeminjam, postData.idBarang, postData.namaBarang, postData.tglPinjam, '-', 'Dipinjam']);
return ContentService.createTextOutput(JSON.stringify({status: 'success', message: 'Peminjaman dicatat!'})).setMimeType(ContentService.MimeType.JSON);
}
if (action === 'returnPeminjaman') {
let data = db.peminjaman.getDataRange().getValues();
let tglKembali = Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "yyyy-MM-dd");
for (let i = 1; i < data.length; i++) {
if (data[i][0] === postData.idPinjam) {
db.peminjaman.getRange(i + 1, 7).setValue(tglKembali);
db.peminjaman.getRange(i + 1, 8).setValue('Dikembalikan');
return ContentService.createTextOutput(JSON.stringify({status: 'success', message: 'Barang dikembalikan!'})).setMimeType(ContentService.MimeType.JSON);
}
}
return ContentService.createTextOutput(JSON.stringify({status: 'error', message: 'Data tidak ditemukan!'})).setMimeType(ContentService.MimeType.JSON);
}
if (action === 'deletePeminjaman') {
let data = db.peminjaman.getDataRange().getValues();
for (let i = 1; i < data.length; i++) {
if (data[i][0] === postData.idPinjam) {
db.peminjaman.deleteRow(i + 1);
return ContentService.createTextOutput(JSON.stringify({status: 'success', message: 'Riwayat dihapus!'})).setMimeType(ContentService.MimeType.JSON);
}
}
return ContentService.createTextOutput(JSON.stringify({status: 'error', message: 'Data tidak ditemukan!'})).setMimeType(ContentService.MimeType.JSON);
}
// --- AKSI PENGATURAN ---
if (action === 'saveSettings') {
let currentData = db.pengaturan.getDataRange().getValues();
let keyMap = {};
for(let i = 1; i < currentData.length; i++) keyMap[currentData[i][0]] = i + 1;
for (let key in postData.settings) {
if(keyMap[key]) db.pengaturan.getRange(keyMap[key], 2).setValue(postData.settings[key]);
else db.pengaturan.appendRow([key, postData.settings[key]]);
}
return ContentService.createTextOutput(JSON.stringify({status: 'success', message: 'Pengaturan disimpan!'})).setMimeType(ContentService.MimeType.JSON);
}
return ContentService.createTextOutput(JSON.stringify({status: 'error', message: 'Aksi tidak valid'})).setMimeType(ContentService.MimeType.JSON);
} catch (error) {
return ContentService.createTextOutput(JSON.stringify({status: 'error', message: error.toString()})).setMimeType(ContentService.MimeType.JSON);
}
}
