fix: update final code deployment
This commit is contained in:
+283
@@ -0,0 +1,283 @@
|
||||
<?php
|
||||
if (isset($_GET['action'])) { include 'api.php'; exit; }
|
||||
include 'db.php';
|
||||
require_once 'includes/stats.php';
|
||||
$stats = spbu_stats($conn);
|
||||
$activePage = 'index';
|
||||
$saved = isset($_GET['saved']);
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>Sistem Informasi Geografis SPBU — Pontianak</title>
|
||||
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;600;700&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
|
||||
<link rel="stylesheet" href="assets/spbu.css?v=1.2"/>
|
||||
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<?php include 'includes/sidebar.php'; ?>
|
||||
<div class="sb-body">
|
||||
<div class="sb-search"><input type="text" id="search-input" placeholder="Cari nama atau nomor SPBU..."></div>
|
||||
<div class="sb-filter">
|
||||
<button class="active" data-filter="semua">Semua (<?= $stats['total'] ?>)</button>
|
||||
<button data-filter="24 Jam">24 Jam (<?= $stats['jam24'] ?>)</button>
|
||||
<button data-filter="Tidak 24 Jam">Lainnya (<?= $stats['tidak24'] ?>)</button>
|
||||
</div>
|
||||
<div class="sb-list-head">
|
||||
<span>Daftar SPBU</span>
|
||||
<span id="list-count"><?= $stats['total'] ?> lokasi</span>
|
||||
</div>
|
||||
<div class="sb-list" id="spbu-list"></div>
|
||||
</div>
|
||||
<div class="sb-foot" style="flex-direction:column; gap:10px">
|
||||
<div style="display:flex; justify-content:space-between; width:100%">
|
||||
<span>Operasional 24 jam: <b><?= $stats['pct24'] ?>%</b></span>
|
||||
<span><?= date('d M Y') ?></span>
|
||||
</div>
|
||||
<a href="../index.php" class="btn-portal" style="display:flex; align-items:center; justify-content:center; gap:6px; padding:10px; background:#eff6ff; color:#1d4ed8; border:1px solid #bfdbfe; border-radius:8px; font-weight:600; text-decoration:none; font-size:12px; transition:all 0.15s; width:100%">
|
||||
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" style="flex-shrink:0"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
|
||||
Kembali ke Portal
|
||||
</a>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<div id="map-area">
|
||||
<!-- Topbar -->
|
||||
<div id="topbar" style="position:relative; z-index:1000; height:56px; background:#fff; border-bottom:1px solid #e2e8f0; display:flex; align-items:center; justify-content:space-between; padding:0 16px; flex-shrink:0">
|
||||
<div style="display:flex; align-items:center; gap:8px">
|
||||
<button type="button" onclick="document.getElementById('sidebar').style.display=document.getElementById('sidebar').style.display==='none'?'flex':'none';setTimeout(function(){map.invalidateSize()},300)" style="background:none;border:none;cursor:pointer;color:#64748b;padding:4px;display:flex;align-items:center"><svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg></button>
|
||||
<div style="font-size:15px; font-weight:700; color:#1e293b">Peta GIS <span style="font-size:13px; font-weight:500; color:#64748b; margin-left:4px">Kanalisasi SPBU</span></div>
|
||||
</div>
|
||||
<div style="display:flex; gap:8px">
|
||||
<a href="tambah.php" style="display:flex; align-items:center; gap:6px; padding:8px 14px; background:#1d4ed8; color:#fff; border-radius:8px; font-size:12px; font-weight:600; text-decoration:none; box-shadow:0 2px 4px rgba(29,78,216,0.15)">
|
||||
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" style="flex-shrink:0"><line x1="12" y1="5" x2="12" y2="19"></line><line x1="5" y1="12" x2="19" y2="12"></line></svg>
|
||||
Tambah Baru
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="map"></div>
|
||||
<?php include 'includes/map-controls.php'; ?>
|
||||
</div>
|
||||
|
||||
<div id="edit-modal">
|
||||
<div id="edit-box">
|
||||
<h3>Edit Data SPBU</h3>
|
||||
<input type="hidden" id="edit-id">
|
||||
<label>Nama SPBU</label>
|
||||
<input type="text" id="edit-nama">
|
||||
<label>Nomor Depot</label>
|
||||
<input type="text" id="edit-nomor">
|
||||
<label>Jam Operasional</label>
|
||||
<select id="edit-status">
|
||||
<option value="24 Jam">24 Jam</option>
|
||||
<option value="Tidak 24 Jam">Tidak 24 Jam</option>
|
||||
</select>
|
||||
<div class="edit-btns">
|
||||
<button class="btn-cancel" type="button" onclick="closeModal()">Batal</button>
|
||||
<button class="btn-save" type="button" onclick="submitEdit()">Simpan</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="toast"></div>
|
||||
<?php include 'includes/confirm-modal.php'; ?>
|
||||
<script src="assets/map-base.js"></script>
|
||||
<script>
|
||||
var map = L.map('map', { zoomControl: false }).setView([-0.0263, 109.3425], 13);
|
||||
L.control.zoom({ position: 'bottomright' }).addTo(map);
|
||||
initBaseLayers(map);
|
||||
<?php if ($saved): ?>showToast('Data SPBU berhasil disimpan.');<?php endif ?>
|
||||
|
||||
var spbuData = [];
|
||||
var layer24Jam = L.layerGroup().addTo(map);
|
||||
var layerTidak24 = L.layerGroup().addTo(map);
|
||||
document.getElementById('ly-24').addEventListener('change', function() {
|
||||
this.checked ? map.addLayer(layer24Jam) : map.removeLayer(layer24Jam);
|
||||
});
|
||||
document.getElementById('ly-tdk').addEventListener('change', function() {
|
||||
this.checked ? map.addLayer(layerTidak24) : map.removeLayer(layerTidak24);
|
||||
});
|
||||
|
||||
async function deleteData(id) {
|
||||
var ok = await showConfirm({
|
||||
title: 'Hapus Data SPBU',
|
||||
message: 'Data ini akan dihapus permanen dari database.',
|
||||
confirmText: 'Ya, Hapus', danger: true
|
||||
});
|
||||
if (ok) window.location.href = 'index.php?action=delete&id=' + id;
|
||||
}
|
||||
function openEdit(id, nama, nomor, status) {
|
||||
document.getElementById('edit-id').value = id;
|
||||
document.getElementById('edit-nama').value = nama;
|
||||
document.getElementById('edit-nomor').value = nomor;
|
||||
document.getElementById('edit-status').value = status;
|
||||
document.getElementById('edit-modal').classList.add('active');
|
||||
}
|
||||
function closeModal() { document.getElementById('edit-modal').classList.remove('active'); }
|
||||
function submitEdit() {
|
||||
var id = document.getElementById('edit-id').value;
|
||||
var nama = document.getElementById('edit-nama').value.trim();
|
||||
var nomor = document.getElementById('edit-nomor').value.trim();
|
||||
var status = document.getElementById('edit-status').value;
|
||||
if (!nama || !nomor) { showToast('Nama dan nomor wajib diisi.'); return; }
|
||||
window.location.href = 'index.php?action=edit&id=' + id
|
||||
+ '&nama=' + encodeURIComponent(nama)
|
||||
+ '&nomor=' + encodeURIComponent(nomor)
|
||||
+ '&status=' + encodeURIComponent(status);
|
||||
}
|
||||
document.getElementById('edit-modal').addEventListener('click', function(e) {
|
||||
if (e.target === this) closeModal();
|
||||
});
|
||||
|
||||
function flyToSpbu(id) {
|
||||
var s = spbuData.find(function(x) { return x.id === id; });
|
||||
if (!s) return;
|
||||
document.querySelectorAll('.spbu-item').forEach(function(el) { el.classList.remove('active'); });
|
||||
var el = document.querySelector('.spbu-item[data-id="' + id + '"]');
|
||||
if (el) el.classList.add('active');
|
||||
map.flyTo([s.lat, s.lng], 17, { duration: 1 });
|
||||
setTimeout(function() { s.marker.openPopup(); }, 1100);
|
||||
}
|
||||
|
||||
<?php
|
||||
$data = $conn->query("SELECT * FROM tempat ORDER BY nama_tempat ASC");
|
||||
while ($row = $data->fetch_assoc()):
|
||||
$id = $row['id']; $lat = $row['latitude']; $lng = $row['longitude'];
|
||||
$nama = addslashes($row['nama_tempat']); $nomor = addslashes($row['nomor_tempat']);
|
||||
$status = addslashes($row['status']);
|
||||
$color = ($row['status'] === '24 Jam') ? '#22c55e' : '#ef4444';
|
||||
$badge = ($row['status'] === '24 Jam') ? 'badge-green' : 'badge-red';
|
||||
$layerVar = ($row['status'] === '24 Jam') ? 'layer24Jam' : 'layerTidak24';
|
||||
$latFmt = number_format($lat, 5); $lngFmt = number_format($lng, 5);
|
||||
?>
|
||||
(function() {
|
||||
var savedLat = <?= $lat ?>, savedLng = <?= $lng ?>, markerId = <?= $id ?>, color = '<?= $color ?>';
|
||||
var marker = L.marker([savedLat, savedLng], { icon: makeSpbuIcon(color), draggable: true }).addTo(<?= $layerVar ?>);
|
||||
spbuData.push({ id: markerId, lat: savedLat, lng: savedLng, nama: '<?= $nama ?>', nomor: '<?= $nomor ?>', status: '<?= $status ?>', color: color, badge: '<?= $badge ?>', marker: marker });
|
||||
function showInfoPopup() {
|
||||
marker.unbindPopup();
|
||||
marker.bindPopup(
|
||||
'<div class="popup-wrap"><div class="popup-title"><?= $nama ?></div>' +
|
||||
'<div class="popup-row">Depot No. <?= $nomor ?></div>' +
|
||||
'<div class="popup-coord"><?= $latFmt ?>, <?= $lngFmt ?></div>' +
|
||||
'<span class="popup-badge <?= $badge ?>"><?= $status ?></span>' +
|
||||
'<div class="popup-actions">' +
|
||||
'<button class="btn-edit" onclick="openEdit(<?= $id ?>,\'<?= $nama ?>\',\'<?= $nomor ?>\',\'<?= $status ?>\')">Edit</button>' +
|
||||
'<button class="btn-delete" onclick="deleteData(<?= $id ?>)">Hapus</button></div></div>'
|
||||
);
|
||||
}
|
||||
showInfoPopup();
|
||||
var dragStartLat, dragStartLng;
|
||||
marker.on('dragstart', function() {
|
||||
dragStartLat = marker.getLatLng().lat; dragStartLng = marker.getLatLng().lng;
|
||||
marker.closePopup(); marker.unbindPopup();
|
||||
});
|
||||
marker.on('dragend', function() {
|
||||
var np = marker.getLatLng();
|
||||
var msgBase = '<div style="text-align:left;line-height:1.6">' +
|
||||
'<b>' + '<?= $nama ?>' + '</b><br>' +
|
||||
'<span style="color:var(--text3);font-size:12px">Koordinat: ' + np.lat.toFixed(6) + ', ' + np.lng.toFixed(6) + '</span><br>';
|
||||
|
||||
fetch('https://nominatim.openstreetmap.org/reverse?format=jsonv2&lat='+np.lat+'&lon='+np.lng+'&accept-language=id&zoom=18')
|
||||
.then(r => r.json())
|
||||
.then(d => {
|
||||
var alamat = d.display_name || 'Alamat tidak ditemukan';
|
||||
showConfirm({
|
||||
title: 'Simpan posisi baru?',
|
||||
message: msgBase + '<span style="font-size:13px;color:var(--text2)"><b>Alamat Baru:</b> ' + alamat + '</span></div>',
|
||||
confirmText: 'Ya, Simpan',
|
||||
icon: 'move',
|
||||
position: 'top'
|
||||
}).then(function(ok) {
|
||||
if (ok) {
|
||||
fetch('index.php?action=update_pos&id=' + markerId + '&lat=' + np.lat + '&lng=' + np.lng)
|
||||
.then(function(r) { return r.text(); }).then(function(t) {
|
||||
if (t.trim() === 'ok') {
|
||||
savedLat = np.lat; savedLng = np.lng;
|
||||
var s = spbuData.find(function(x) { return x.id === markerId; });
|
||||
if (s) { s.lat = savedLat; s.lng = savedLng; }
|
||||
showToast('Posisi diperbarui.');
|
||||
} else {
|
||||
showToast('Gagal menyimpan.');
|
||||
marker.setLatLng([dragStartLat, dragStartLng]);
|
||||
}
|
||||
showInfoPopup();
|
||||
});
|
||||
} else {
|
||||
marker.setLatLng([dragStartLat, dragStartLng]);
|
||||
showInfoPopup();
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
showConfirm({
|
||||
title: 'Simpan posisi baru?',
|
||||
message: msgBase + '<span style="font-size:13px;color:var(--text2)"><b>Alamat Baru:</b> Gagal memuat alamat</span></div>',
|
||||
confirmText: 'Ya, Simpan',
|
||||
icon: 'move',
|
||||
position: 'top'
|
||||
}).then(function(ok) {
|
||||
if (ok) {
|
||||
fetch('index.php?action=update_pos&id=' + markerId + '&lat=' + np.lat + '&lng=' + np.lng)
|
||||
.then(function(r) { return r.text(); }).then(function(t) {
|
||||
if (t.trim() === 'ok') {
|
||||
savedLat = np.lat; savedLng = np.lng;
|
||||
var s = spbuData.find(function(x) { return x.id === markerId; });
|
||||
if (s) { s.lat = savedLat; s.lng = savedLng; }
|
||||
showToast('Posisi diperbarui.');
|
||||
} else {
|
||||
showToast('Gagal menyimpan.');
|
||||
marker.setLatLng([dragStartLat, dragStartLng]);
|
||||
}
|
||||
showInfoPopup();
|
||||
});
|
||||
} else {
|
||||
marker.setLatLng([dragStartLat, dragStartLng]);
|
||||
showInfoPopup();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
marker.on('click', function() {
|
||||
document.querySelectorAll('.spbu-item').forEach(function(el) { el.classList.remove('active'); });
|
||||
var el = document.querySelector('.spbu-item[data-id="' + markerId + '"]');
|
||||
if (el) { el.classList.add('active'); el.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }
|
||||
});
|
||||
})();
|
||||
<?php endwhile; ?>
|
||||
|
||||
var currentFilter = 'semua', currentSearch = '';
|
||||
function renderList() {
|
||||
var list = document.getElementById('spbu-list');
|
||||
var kw = currentSearch.toLowerCase();
|
||||
var filtered = spbuData.filter(function(s) {
|
||||
var f = (currentFilter === 'semua') || (s.status === currentFilter);
|
||||
var q = s.nama.toLowerCase().indexOf(kw) !== -1 || s.nomor.toLowerCase().indexOf(kw) !== -1;
|
||||
return f && q;
|
||||
});
|
||||
document.getElementById('list-count').textContent = filtered.length + ' lokasi';
|
||||
if (!filtered.length) { list.innerHTML = '<div class="no-result">Tidak ada SPBU ditemukan</div>'; return; }
|
||||
list.innerHTML = filtered.map(function(s) {
|
||||
return '<div class="spbu-item" data-id="' + s.id + '" onclick="flyToSpbu(' + s.id + ')">' +
|
||||
'<div class="spbu-dot" style="background:' + s.color + '"></div>' +
|
||||
'<div><div class="spbu-nama">' + s.nama + '</div>' +
|
||||
'<div class="spbu-meta">No. ' + s.nomor + ' · ' + s.lat.toFixed(5) + ', ' + s.lng.toFixed(5) + '</div></div>' +
|
||||
'<span class="spbu-badge ' + s.badge + '">' + (s.status === '24 Jam' ? '24 Jam' : 'Tdk 24 Jam') + '</span></div>';
|
||||
}).join('');
|
||||
}
|
||||
document.getElementById('search-input').addEventListener('input', function() { currentSearch = this.value; renderList(); });
|
||||
document.querySelectorAll('.sb-filter button').forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
document.querySelectorAll('.sb-filter button').forEach(function(b) { b.classList.remove('active'); });
|
||||
this.classList.add('active'); currentFilter = this.dataset.filter; renderList();
|
||||
});
|
||||
});
|
||||
renderList();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user