improve index.html interface with ninja template

This commit is contained in:
cowrie
2026-04-16 22:51:20 +08:00
parent 4530afde5f
commit 02a06ed434
1388 changed files with 533479 additions and 272 deletions

272
site/index copy 2.html Normal file
View File

@ -0,0 +1,272 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sensor Kualitas Udara</title>
<style>
body {
font-family: Arial, sans-serif;
background: #0f172a;
color: #e5e7eb;
padding: 20px;
}
.card {
background: #1e293b;
padding: 15px;
margin: 10px 0;
border-radius: 8px;
font-size: 20px;
}
#container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 10px;
}
</style>
</head>
<body>
<h1>🌱 Sensor Kualitas Udara</h1>
<div id="container"></div>
<hr>
<button onclick="openDialog()">Add Sensor</button>
<!-- MODAL -->
<div id="dialog"
style="display:none; position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(0,0,0,0.7);">
<div style="background:#1e293b; padding:20px; width:300px; margin:100px auto; border-radius:10px;">
<h3>Tambah Sensor</h3>
<label>Kecamatan:</label><br>
<select id="kecamatan" onchange="loadKelurahan()">
<option value="">-- Pilih Kecamatan --</option>
</select>
<br><br>
<label>Kelurahan:</label><br>
<select id="kelurahan">
<option value="">-- Pilih Kelurahan --</option>
</select>
<br><br>
<label>Alamat:</label><br>
<textarea id="alamat" rows="3" style="width:100%"></textarea>
<br><br>
<button onclick="addSensor()">Simpan</button>
<button onclick="closeDialog()">Batal</button>
</div>
</div>
<script>
function getStatus(aq) {
if (aq >= 90) return "Sangat Baik";
if (aq >= 70) return "Baik";
if (aq >= 50) return "Sedang";
if (aq > 30) return "Buruk";
return "Sangat Buruk";
}
async function fetchAllSensors() {
try {
const res = await fetch("/api/sensors");
return await res.json();
} catch (err) {
console.error("Failed to fetch sensors", err);
return [];
}
}
async function fetchSensorData(id) {
try {
const res = await fetch(`/api/sensordata/${id}`);
return await res.json();
} catch (err) {
console.error(`Failed sensor ${id}`, err);
return null;
}
}
// ============================
// BUILD UI ONCE
// ============================
async function initSensors() {
const container = document.getElementById("container");
container.innerHTML = "";
const sensors = await fetchAllSensors();
for (const sensor of sensors) {
const data = await fetchSensorData(sensor.id);
const card = document.createElement("div");
card.className = "card";
if (!data || data.error) {
card.innerHTML = `
<h3>Sensor ID: ${sensor.id}</h3>
<p style="color: orange;">Belum Ada Data</p>
`;
} else {
card.innerHTML = `
<h3>Sensor ID: ${sensor.id}</h3>
<small>${data.kecamatan} - ${data.kelurahan}</small><br>
<small>${data.alamat}</small><br><br>
Karbon Oksida: <span id="co2-${sensor.id}">-</span> ppm<br>
Karbon Monoksida: <span id="co-${sensor.id}">-</span> ppm<br>
Benzena: <span id="bz-${sensor.id}">-</span> ppm<br>
Jumlah: <span id="aq-${sensor.id}">-</span> %<br>
Kualitas: <span id="qa-${sensor.id}">-</span>
`;
}
container.appendChild(card);
}
}
// ============================
// UPDATE VALUES ONLY
// ============================
async function updateSensorValues() {
const sensors = await fetchAllSensors();
for (const sensor of sensors) {
const data = await fetchSensorData(sensor.id);
if (!data || data.error) continue;
document.getElementById(`co2-${sensor.id}`).textContent = data.co2;
document.getElementById(`co-${sensor.id}`).textContent = data.co;
document.getElementById(`bz-${sensor.id}`).textContent = data.bz;
document.getElementById(`aq-${sensor.id}`).textContent = data.aq;
document.getElementById(`qa-${sensor.id}`).textContent = getStatus(data.aq);
}
}
// ============================
// MODAL CONTROL
// ============================
function openDialog() {
document.getElementById("dialog").style.display = "block";
loadKecamatan();
}
function closeDialog() {
document.getElementById("dialog").style.display = "none";
}
// ============================
// LOAD KECAMATAN
// ============================
async function loadKecamatan() {
try {
const res = await fetch("/api/kecamatan");
const data = await res.json();
const select = document.getElementById("kecamatan");
select.innerHTML = `<option value="">-- Pilih Kecamatan --</option>`;
data.forEach(k => {
const option = document.createElement("option");
option.value = k.id;
option.textContent = k.nama;
select.appendChild(option);
});
} catch (err) {
console.error("Failed load kecamatan", err);
}
}
// ============================
// LOAD KELURAHAN
// ============================
async function loadKelurahan() {
const kecamatanId = document.getElementById("kecamatan").value;
const select = document.getElementById("kelurahan");
select.innerHTML = `<option value="">-- Pilih Kelurahan --</option>`;
if (!kecamatanId) return;
try {
const res = await fetch(`/api/kelurahan?kecamatan_id=${kecamatanId}`);
const data = await res.json();
data.forEach(k => {
const option = document.createElement("option");
option.value = k.id;
option.textContent = k.nama;
select.appendChild(option);
});
} catch (err) {
console.error("Failed load kelurahan", err);
}
}
// ============================
// ADD SENSOR
// ============================
async function addSensor() {
const kelurahan = document.getElementById("kelurahan").value;
const alamat = document.getElementById("alamat").value;
if (!kelurahan || !alamat) {
alert("Semua field wajib diisi!");
return;
}
try {
const res = await fetch("/api/addSensor", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({
kelurahan,
alamat
})
});
const result = await res.json();
if (!res.ok) {
alert(result.error || "Gagal");
return;
}
alert("Sensor berhasil ditambahkan!");
closeDialog();
document.getElementById("kecamatan").value = "";
document.getElementById("kelurahan").innerHTML = `<option value="">-- Pilih Kelurahan --</option>`;
document.getElementById("alamat").value = "";
await initSensors(); // rebuild only when new sensor added
} catch (err) {
console.error(err);
alert("Error");
}
}
// ============================
// INIT
// ============================
initSensors();
updateSensorValues()
setInterval(updateSensorValues, 5000);
</script>
</body>
</html>