Aplikasi Perpustakaan Sekolah Gratis Berbasis Google Apps Script

Table of Contents

Aplikasi Perpustakaan Sekolah Gratis Berbasis Google Apps Script

Mengelola perpustakaan sekolah tidak harus selalu menggunakan aplikasi berbayar. Dengan memanfaatkan Google Sheets dan Google Apps Script, kita dapat membuat aplikasi perpustakaan sederhana yang dapat diakses melalui browser.

Aplikasi ini dibuat untuk membantu pengelolaan perpustakaan SMK Dwija Praja dan memiliki beberapa fitur utama, yaitu:

Backend aplikasi menggunakan Google Apps Script dan terhubung dengan Google Sheets sebagai database.

Fitur Aplikasi Perpustakaan

1. Dashboard

Dashboard menampilkan informasi penting secara ringkas, seperti:

  • Total buku

  • Total anggota

  • Buku yang sedang dipinjam

  • Total pengembalian

  • Statistik peminjaman per bulan

Data statistik peminjaman diolah dari database dan ditampilkan dalam bentuk grafik.

2. Manajemen Data Buku

Petugas dapat menambahkan, mengedit, menghapus, dan mencari data buku.

Informasi buku terdiri dari:

KolomKeterangan
ID BukuID otomatis
JudulJudul buku
PengarangNama pengarang
PenerbitNama penerbit
TahunTahun terbit
KategoriKategori buku
RakLokasi rak
StokJumlah buku
StatusKetersediaan

ID buku dibuat otomatis menggunakan prefix BK, misalnya:

BK0001
BK0002
BK0003

Fungsi getNextId() digunakan untuk mencari nomor terbesar kemudian menghasilkan ID berikutnya secara otomatis.


3. Manajemen Data Anggota

Data anggota dapat ditambahkan dan diedit melalui aplikasi.

Informasi yang tersedia meliputi:

  • ID anggota

  • NISN

  • Nama

  • Kelas

  • Jenis kelamin

  • Nomor WhatsApp

  • Email

  • Status

Pada form aplikasi, nama dan NISN wajib diisi sebelum data disimpan.


4. Peminjaman Buku

Proses peminjaman dilakukan dengan memilih anggota dan buku.

Sistem terlebih dahulu memeriksa stok buku. Jika stok habis, peminjaman tidak dapat dilakukan.

Setelah transaksi berhasil:

  • ID peminjaman dibuat otomatis.

  • Tanggal peminjaman dicatat.

  • Tanggal pengembalian ditentukan 7 hari kemudian.

  • Status menjadi DIPINJAM.

  • Stok buku berkurang satu.

  • Data dicatat ke database.

  • Log aktivitas dibuat.


5. Email Konfirmasi Peminjaman

Aplikasi juga dapat mengirimkan email kepada anggota setelah peminjaman berhasil.

Email berisi:

  • Nama peminjam

  • Judul buku

  • ID peminjaman

  • Tanggal peminjaman

  • Tanggal pengembalian

  • Pengingat untuk mengembalikan buku

Fitur ini menggunakan MailApp.sendEmail() dari Google Apps Script.


6. Pengembalian Buku

Ketika buku dikembalikan, sistem akan:

  1. Mencari transaksi peminjaman.

  2. Menambahkan data ke sheet KEMBALI.

  3. Menghapus transaksi dari PINJAM.

  4. Menambahkan kembali stok buku.

  5. Mencatat aktivitas pengembalian.


7. Log Aktivitas

Setiap aktivitas penting dicatat ke sheet LOG.

Contohnya:

  • Tambah buku

  • Edit buku

  • Hapus buku

  • Tambah anggota

  • Edit anggota

  • Hapus anggota

  • Peminjaman

  • Pengembalian

Data log juga menyimpan waktu, email pengguna, detail aktivitas, dan status.


Struktur Google Spreadsheet

Sebelum menjalankan aplikasi, buat satu Google Spreadsheet dengan sheet berikut:

BUKU
ANGGOTA
PINJAM
KEMBALI
LOG

Sheet BUKU

Gunakan struktur:

ID Buku | Judul | Pengarang | Penerbit | Tahun | Kategori | Rak | Stok | Keterangan

Sheet ANGGOTA

ID Anggota | NISN | Nama | Kelas | Jenis Kelamin | No. WA | Email | Status

Sheet PINJAM

ID Pinjam | ID Anggota | Nama | ID Buku | Judul | Tgl Pinjam | Tgl Kembali | Keterangan | Email

Sheet KEMBALI

ID Pinjam | ID Anggota | Nama | ID Buku | Judul | Tgl Pinjam | Tgl Kembali | Keterangan | Email

Sheet LOG

Timestamp | Aksi | Email | Detail | Status

Dua Script yang Dibutuhkan

Aplikasi ini menggunakan dua bagian utama.

Script 1 — Code2.gs

Script pertama merupakan backend aplikasi.

Fungsinya menangani komunikasi dengan Google Sheets, pengelolaan buku, anggota, peminjaman, pengembalian, dashboard, email, dan log aktivitas.

Code2.gs Lengkap

Catatan: Gunakan script asli berikut secara utuh. Jangan mengubah nama fungsi karena Index.html memanggil fungsi-fungsi tersebut.

// ============================================
// APLIKASI PERPUSTAKAAN - WEB APP
// SMK DWIJA PRAJA
// ============================================
const SPREADSHEET_ID = 'GANTI SPREADSHEET ID DISINI';
// ============================================
// WEB APP ENTRY POINTS
// ============================================
function doGet(e) {
return HtmlService.createHtmlOutputFromFile('Index')
.setTitle('Aplikasi Perpustakaan - SMK Dwija Praja')
.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)
.addMetaTag('viewport', 'width=device-width, initial-scale=1');
}
function doPost(e) {
try {
const params = JSON.parse(e.postData.contents);
const action = params.action;
const data = params.data || {};
switch(action) {
case 'getDashboard': return jsonResponse(getDashboardData());
case 'getBuku': return jsonResponse(getAllBuku());
case 'getAnggota': return jsonResponse(getAllAnggota());
case 'getPinjam': return jsonResponse(getAllPinjam());
case 'getKembali': return jsonResponse(getAllKembali());
case 'getLog': return jsonResponse(getAllLog());
case 'tambahBuku': return jsonResponse(tambahBuku(data));
case 'editBuku': return jsonResponse(editBuku(data));
case 'hapusBuku': return jsonResponse(hapusBuku(data));
case 'tambahAnggota': return jsonResponse(tambahAnggota(data));
case 'editAnggota': return jsonResponse(editAnggota(data));
case 'hapusAnggota': return jsonResponse(hapusAnggota(data));
case 'pinjamBuku': return jsonResponse(pinjamBuku(data));
case 'kembalikanBuku': return jsonResponse(kembalikanBuku(data));
case 'cariBuku': return jsonResponse(cariBuku(data));
case 'getKategori': return jsonResponse(getKategoriList());
case 'getRak': return jsonResponse(getRakList());
default: return jsonResponse({
success: false,
error: 'Action tidak dikenal: ' + action
});
}
} catch(err) {
return jsonResponse({
success: false,
error: err.toString(),
stack: err.stack
});
}
}
function jsonResponse(data) {
return ContentService.createTextOutput(JSON.stringify(data))
.setMimeType(ContentService.MimeType.JSON);
}
// ============================================
// HELPER FUNCTIONS
// ============================================
function getSheet(sheetName) {
const ss = SpreadsheetApp.openById(SPREADSHEET_ID);
const sheet = ss.getSheetByName(sheetName);
if (!sheet) {
throw new Error(
'Sheet "' + sheetName + '" tidak ditemukan di spreadsheet'
);
}
return sheet;
}
function getNextId(sheet, prefix, idCol) {
const data = sheet.getDataRange().getValues();
if (data.length <= 1) return prefix + '0001';
let maxNum = 0;
for (let i = 1; i < data.length; i++) {
const id = data[i][idCol]
? data[i][idCol].toString()
: '';
const num = parseInt(
id.replace(prefix, '').replace(/\D/g, '')
);
if (!isNaN(num) && num > maxNum) {
maxNum = num;
}
}
return prefix + String(maxNum + 1).padStart(4, '0');
}
function writeLog(aksi, detail, status) {
try {
const sheet = getSheet('LOG');
const timestamp = new Date();
const email =
Session.getActiveUser().getEmail() ||
'admin.smkdwijapraja@gmail.com';
sheet.appendRow([
timestamp,
aksi,
email,
detail,
status
]);
} catch(e) {
console.log('Write log error: ' + e);
}
}
function sendEmail(to, subject, body) {
try {
if (to && to.includes('@')) {
MailApp.sendEmail(to, subject, body);
}
} catch(e) {
console.log('Email gagal: ' + e);
}
}
// ============================================
// DASHBOARD
// ============================================
function getDashboardData() {
try {
const bukuSheet = getSheet('BUKU');
const anggotaSheet = getSheet('ANGGOTA');
const pinjamSheet = getSheet('PINJAM');
const kembaliSheet = getSheet('KEMBALI');
const totalBuku =
Math.max(0, bukuSheet.getLastRow() - 1);
const totalAnggota =
Math.max(0, anggotaSheet.getLastRow() - 1);
const totalPinjam =
Math.max(0, pinjamSheet.getLastRow() - 1);
const totalKembali =
Math.max(0, kembaliSheet.getLastRow() - 1);
let stokTersedia = 0;
let stokDipinjam = 0;
const bukuData =
bukuSheet.getDataRange().getValues();
for (let i = 1; i < bukuData.length; i++) {
stokTersedia += parseInt(bukuData[i][7]) || 0;
}
const pinjamData =
pinjamSheet.getDataRange().getValues();
for (let i = 1; i < pinjamData.length; i++) {
if (pinjamData[i][7] === 'DIPINJAM') {
stokDipinjam++;
}
}
const kategoriCount = {};
for (let i = 1; i < bukuData.length; i++) {
const kat = bukuData[i][5];
if (kat) {
kategoriCount[kat] =
(kategoriCount[kat] || 0) + 1;
}
}
const pinjamPerBulan = {};
for (let i = 1; i < pinjamData.length; i++) {
const tgl = pinjamData[i][5];
if (tgl && tgl instanceof Date) {
const key =
tgl.getFullYear() +
'-' +
String(tgl.getMonth() + 1).padStart(2, '0');
pinjamPerBulan[key] =
(pinjamPerBulan[key] || 0) + 1;
}
}
return {
success: true,
totalBuku,
totalAnggota,
totalPinjam,
totalKembali,
stokTersedia,
stokDipinjam,
kategoriPopuler: kategoriCount,
pinjamPerBulan: pinjamPerBulan
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
// ============================================
// BUKU CRUD
// ============================================
function getAllBuku() {
try {
const sheet = getSheet('BUKU');
const data = sheet.getDataRange().getValues();
const result = [];
for (let i = 1; i < data.length; i++) {
result.push({
id_buku: data[i][0] || '',
judul: data[i][1] || '',
pengarang: data[i][2] || '',
penerbit: data[i][3] || '',
tahun: data[i][4] || '',
kategori: data[i][5] || '',
rak: data[i][6] || '',
stok: data[i][7] || 0,
ket: data[i][8] || ''
});
}
return {
success: true,
data: result
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
function tambahBuku(data) {
try {
const sheet = getSheet('BUKU');
const idBuku = getNextId(sheet, 'BK', 0);
sheet.appendRow([
idBuku,
data.judul,
data.pengarang,
data.penerbit,
data.tahun,
data.kategori,
data.rak,
data.stok || 50,
'TERSEDIA'
]);
writeLog(
'TAMBAH BUKU',
'Buku: ' + data.judul +
' (ID: ' + idBuku + ')',
'SUKSES'
);
return {
success: true,
id: idBuku,
message: 'Buku berhasil ditambahkan'
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
function editBuku(data) {
try {
const sheet = getSheet('BUKU');
const values = sheet.getDataRange().getValues();
for (let i = 1; i < values.length; i++) {
if (values[i][0] === data.id_buku) {
sheet.getRange(i + 1, 2)
.setValue(data.judul);
sheet.getRange(i + 1, 3)
.setValue(data.pengarang);
sheet.getRange(i + 1, 4)
.setValue(data.penerbit);
sheet.getRange(i + 1, 5)
.setValue(data.tahun);
sheet.getRange(i + 1, 6)
.setValue(data.kategori);
sheet.getRange(i + 1, 7)
.setValue(data.rak);
sheet.getRange(i + 1, 8)
.setValue(data.stok);
writeLog(
'EDIT BUKU',
'Buku: ' + data.judul +
' (ID: ' + data.id_buku + ')',
'SUKSES'
);
return {
success: true,
message: 'Buku berhasil diupdate'
};
}
}
return {
success: false,
message: 'Buku tidak ditemukan'
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
function hapusBuku(data) {
try {
const sheet = getSheet('BUKU');
const values = sheet.getDataRange().getValues();
for (let i = 1; i < values.length; i++) {
if (values[i][0] === data.id_buku) {
sheet.deleteRow(i + 1);
writeLog(
'HAPUS BUKU',
'ID: ' + data.id_buku,
'SUKSES'
);
return {
success: true,
message: 'Buku berhasil dihapus'
};
}
}
return {
success: false,
message: 'Buku tidak ditemukan'
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
function cariBuku(keyword) {
try {
const result = getAllBuku();
if (!result.success) return result;
const all = result.data;
const lower =
(keyword || '').toLowerCase();
const filtered = all.filter(b =>
(b.judul || '').toLowerCase()
.includes(lower) ||
(b.pengarang || '').toLowerCase()
.includes(lower) ||
(b.kategori || '').toLowerCase()
.includes(lower)
);
return {
success: true,
data: filtered
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
function getKategoriList() {
try {
const result = getAllBuku();
if (!result.success) return result;
const kategori = [
...new Set(
result.data
.map(b => b.kategori)
.filter(k => k)
)
];
return {
success: true,
data: kategori.sort()
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
function getRakList() {
try {
const result = getAllBuku();
if (!result.success) return result;
const rak = [
...new Set(
result.data
.map(b => b.rak)
.filter(r => r)
)
];
return {
success: true,
data: rak.sort()
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
// ============================================
// ANGGOTA CRUD
// ============================================
function getAllAnggota() {
try {
const sheet = getSheet('ANGGOTA');
const data = sheet.getDataRange().getValues();
const result = [];
for (let i = 1; i < data.length; i++) {
result.push({
id_anggota: data[i][0] || '',
nisn: data[i][1] || '',
nama: data[i][2] || '',
kelas: data[i][3] || '',
jenis_kelamin: data[i][4] || '',
no_wa: data[i][5] || '',
email: data[i][6] || '',
status: data[i][7] || 'AKTIF'
});
}
return {
success: true,
data: result
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
function tambahAnggota(data) {
try {
const sheet = getSheet('ANGGOTA');
const idAnggota =
getNextId(sheet, 'A', 0);
sheet.appendRow([
idAnggota,
data.nisn,
data.nama,
data.kelas,
data.jenis_kelamin,
data.no_wa,
data.email,
'AKTIF'
]);
writeLog(
'TAMBAH ANGGOTA',
'Anggota: ' + data.nama +
' (ID: ' + idAnggota + ')',
'SUKSES'
);
return {
success: true,
id: idAnggota,
message: 'Anggota berhasil ditambahkan'
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
function editAnggota(data) {
try {
const sheet = getSheet('ANGGOTA');
const values = sheet.getDataRange().getValues();
for (let i = 1; i < values.length; i++) {
if (values[i][0] === data.id_anggota) {
sheet.getRange(i + 1, 2)
.setValue(data.nisn);
sheet.getRange(i + 1, 3)
.setValue(data.nama);
sheet.getRange(i + 1, 4)
.setValue(data.kelas);
sheet.getRange(i + 1, 5)
.setValue(data.jenis_kelamin);
sheet.getRange(i + 1, 6)
.setValue(data.no_wa);
sheet.getRange(i + 1, 7)
.setValue(data.email);
writeLog(
'EDIT ANGGOTA',
'Anggota: ' + data.nama +
' (ID: ' + data.id_anggota + ')',
'SUKSES'
);
return {
success: true,
message: 'Anggota berhasil diupdate'
};
}
}
return {
success: false,
message: 'Anggota tidak ditemukan'
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
function hapusAnggota(data) {
try {
const sheet = getSheet('ANGGOTA');
const values = sheet.getDataRange().getValues();
for (let i = 1; i < values.length; i++) {
if (values[i][0] === data.id_anggota) {
sheet.deleteRow(i + 1);
writeLog(
'HAPUS ANGGOTA',
'ID: ' + data.id_anggota,
'SUKSES'
);
return {
success: true,
message: 'Anggota berhasil dihapus'
};
}
}
return {
success: false,
message: 'Anggota tidak ditemukan'
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
// ============================================
// PEMINJAMAN
// ============================================
function getAllPinjam() {
try {
const sheet = getSheet('PINJAM');
const data = sheet.getDataRange().getValues();
const result = [];
for (let i = 1; i < data.length; i++) {
result.push({
id_pinjam: data[i][0] || '',
id_anggota: data[i][1] || '',
nama: data[i][2] || '',
id_buku: data[i][3] || '',
judul: data[i][4] || '',
tgl_pinjam: formatDate(data[i][5]),
tgl_kembali: formatDate(data[i][6]),
ket: data[i][7] || '',
email: data[i][8] || ''
});
}
return {
success: true,
data: result
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
function pinjamBuku(data) {
try {
// Cek stok
const bukuSheet = getSheet('BUKU');
const bukuData =
bukuSheet.getDataRange().getValues();
let stokNow = 0;
let bukuRow = -1;
for (let i = 1; i < bukuData.length; i++) {
if (bukuData[i][0] === data.id_buku) {
stokNow =
parseInt(bukuData[i][7]) || 0;
bukuRow = i;
break;
}
}
if (stokNow <= 0) {
return {
success: false,
message: 'Stok buku habis atau tidak tersedia'
};
}
const sheet = getSheet('PINJAM');
const idPinjam =
getNextId(sheet, 'P', 0);
const tglPinjam = new Date();
const tglKembali = new Date();
tglKembali.setDate(
tglKembali.getDate() + 7
);
sheet.appendRow([
idPinjam,
data.id_anggota,
data.nama,
data.id_buku,
data.judul,
tglPinjam,
tglKembali,
'DIPINJAM',
data.email
]);
// Kurangi stok
if (bukuRow > 0) {
bukuSheet
.getRange(bukuRow + 1, 8)
.setValue(stokNow - 1);
}
// Email
const subject =
'Konfirmasi Peminjaman Buku - Perpustakaan SMK Dwija Praja';
const body =
'Yth. ' + data.nama + ',\n\n' +
'Anda telah meminjam buku:\n' +
'Judul: ' + data.judul + '\n' +
'ID Peminjaman: ' + idPinjam + '\n' +
'Tanggal Pinjam: ' +
formatDate(tglPinjam) + '\n' +
'Tanggal Kembali: ' +
formatDate(tglKembali) + '\n\n' +
'Harap mengembalikan buku tepat waktu.\n\n' +
'Terima kasih.\n' +
'Perpustakaan SMK Dwija Praja';
sendEmail(
data.email,
subject,
body
);
writeLog(
'PINJAM',
'ID Pinjam: ' +
idPinjam +
' - ' +
data.judul,
'SUKSES'
);
return {
success: true,
id: idPinjam,
message: 'Peminjaman berhasil'
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
function kembalikanBuku(data) {
try {
const pinjamSheet = getSheet('PINJAM');
const kembaliSheet = getSheet('KEMBALI');
const pinjamData =
pinjamSheet.getDataRange().getValues();
for (let i = 1; i < pinjamData.length; i++) {
if (pinjamData[i][0] === data.id_pinjam) {
kembaliSheet.appendRow([
pinjamData[i][0],
pinjamData[i][1],
pinjamData[i][2],
pinjamData[i][3],
pinjamData[i][4],
pinjamData[i][5],
new Date(),
'DIKEMBALIKAN',
pinjamData[i][8]
]);
pinjamSheet.deleteRow(i + 1);
// Tambah stok
const bukuSheet = getSheet('BUKU');
const bukuData =
bukuSheet.getDataRange().getValues();
for (let j = 1; j < bukuData.length; j++) {
if (bukuData[j][0] === pinjamData[i][3]) {
const stokNow =
parseInt(bukuData[j][7]) || 0;
bukuSheet
.getRange(j + 1, 8)
.setValue(stokNow + 1);
break;
}
}
writeLog(
'KEMBALI',
'ID Pinjam: ' +
data.id_pinjam +
' - ' +
pinjamData[i][4],
'SUKSES'
);
return {
success: true,
message: 'Buku berhasil dikembalikan'
};
}
}
return {
success: false,
message: 'Data peminjaman tidak ditemukan'
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
function getAllKembali() {
try {
const sheet = getSheet('KEMBALI');
const data = sheet.getDataRange().getValues();
const result = [];
for (let i = 1; i < data.length; i++) {
result.push({
id_pinjam: data[i][0] || '',
id_anggota: data[i][1] || '',
nama: data[i][2] || '',
id_buku: data[i][3] || '',
judul: data[i][4] || '',
tgl_pinjam: formatDate(data[i][5]),
tgl_kembali: formatDate(data[i][6]),
ket: data[i][7] || '',
email: data[i][8] || ''
});
}
return {
success: true,
data: result
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
// ============================================
// LOG
// ============================================
function getAllLog() {
try {
const sheet = getSheet('LOG');
const data = sheet.getDataRange().getValues();
const result = [];
for (let i = 1; i < data.length; i++) {
result.push({
timestamp: formatDateTime(data[i][0]),
aksi: data[i][1] || '',
email: data[i][2] || '',
detail: data[i][3] || '',
status: data[i][4] || ''
});
}
return {
success: true,
data: result.reverse()
};
} catch(err) {
return {
success: false,
error: err.toString()
};
}
}
// ============================================
// UTILITIES
// ============================================
function formatDate(dateVal) {
if (!dateVal) return '-';
const d = new Date(dateVal);
if (isNaN(d.getTime())) return '-';
return d.toLocaleDateString('id-ID');
}
function formatDateTime(dateVal) {
if (!dateVal) return '-';
const d = new Date(dateVal);
if (isNaN(d.getTime())) return '-';
return d.toLocaleString('id-ID');
}

Script backend asli memang menggunakan SPREADSHEET_ID, doGet(), fungsi CRUD buku dan anggota, transaksi peminjaman/pengembalian, serta log aktivitas.


Script 2 — Index.html

Script kedua adalah frontend aplikasi.

File HTML ini bertanggung jawab terhadap tampilan dashboard, menu, tabel, form tambah/edit, pencarian, peminjaman, pengembalian, loading, notifikasi, dan grafik.

Nama file harus:

Index.html

karena doGet() pada Code2.gs memanggil file dengan nama Index.

Script Index2.html asli Anda terdiri dari 1.225 baris, sehingga untuk artikel Blogspot saya sarankan script tersebut ditampilkan dalam satu blok kode terpisah setelah penjelasan ini, bukan dipotong menjadi beberapa bagian.

Frontend tersebut menggunakan:

google.script.run

untuk memanggil fungsi backend seperti:

getDashboardData()
getAllBuku()
getAllAnggota()
getAllPinjam()
getAllKembali()
getAllLog()
tambahBuku()
editBuku()
hapusBuku()
tambahAnggota()
editAnggota()
hapusAnggota()
pinjamBuku()
kembalikanBuku()

Komunikasi frontend dan backend tersebut terlihat pada fungsi callAPI().

Frontend juga menggunakan Chart.js untuk menampilkan statistik peminjaman dalam bentuk grafik.


Cara Memasang Aplikasi

1. Buat Google Spreadsheet

Buat spreadsheet baru dan buat lima sheet:

BUKU
ANGGOTA
PINJAM
KEMBALI
LOG

Masukkan header sesuai struktur database di atas.


2. Buka Apps Script

Dari Google Spreadsheet pilih:

Extensions → Apps Script


3. Masukkan Code2.gs

Hapus kode bawaan Apps Script.

Masukkan script backend pada bagian:

Script 1 — Code2.gs


4. Buat Index.html

Klik:

+ → HTML

Berikan nama:

Index

Kemudian masukkan seluruh kode Index2.html.

Jangan mengganti nama file menjadi Index2 karena doGet() memanggil:

HtmlService.createHtmlOutputFromFile('Index')


Cara Deploy Aplikasi

Setelah kedua script selesai:

  1. Klik Deploy

  2. Pilih New deployment

  3. Pada tipe deployment pilih Web app

  4. Atur akses sesuai kebutuhan

  5. Klik Deploy

  6. Berikan izin yang diminta Google

  7. Salin URL Web App

  8. Buka URL tersebut melalui browser

Aplikasi kemudian dapat digunakan sebagai sistem perpustakaan berbasis web.


Kesimpulan

Aplikasi perpustakaan berbasis Google Apps Script dan Google Sheets dapat menjadi solusi sederhana untuk membantu digitalisasi administrasi perpustakaan sekolah.

Dengan aplikasi ini, pengelolaan buku, anggota, peminjaman, pengembalian, stok, statistik, dan log aktivitas dapat dilakukan melalui satu halaman Web App.

Keunggulan lainnya adalah aplikasi tidak membutuhkan hosting tradisional karena backend berjalan menggunakan Google Apps Script dan database menggunakan Google Sheets.

Aplikasi ini juga masih dapat dikembangkan lebih lanjut dengan fitur:

  • Login administrator

  • Hak akses petugas

  • Barcode buku

  • QR Code

  • Kartu anggota

  • Cetak kartu anggota

  • Cetak laporan

  • Export PDF

  • Export Excel

  • Denda keterlambatan otomatis

  • WhatsApp notifikasi

  • Backup database

  • Laporan peminjaman per kelas

  • Laporan buku paling sering dipinjam

Dengan pengembangan tersebut, aplikasi sederhana ini dapat menjadi sistem informasi perpustakaan sekolah yang lebih lengkap dan profesional.

Post a Comment