Refactor database interactions and schema updates
- Updated column names in insert_data.php and update_data.php to match the database schema. - Added new tables for 'jalan', 'parsil', and 'jalan_rusak' in spbu_db.sql to enhance data structure. - Changed admin password hash in spbu_db.sql for security improvements.
This commit is contained in:
+19
-8
@@ -1,16 +1,27 @@
|
||||
CREATE DATABASE db_spbu;
|
||||
USE db_spbu;
|
||||
CREATE DATABASE IF NOT EXISTS spbu_db;
|
||||
USE spbu_db;
|
||||
|
||||
CREATE TABLE spbu (
|
||||
CREATE TABLE IF NOT EXISTS admin (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama_spbu VARCHAR(100),
|
||||
no_spbu VARCHAR(50),
|
||||
status ENUM('Buka 24 Jam', 'Tidak 24 Jam'),
|
||||
latitude DOUBLE,
|
||||
longitude DOUBLE,
|
||||
username VARCHAR(50) NOT NULL UNIQUE,
|
||||
password VARCHAR(255) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
INSERT INTO admin (username, password) VALUES
|
||||
('admin', '$2y$10$A9m/u6sAxEwgIO4dlmIvNO2WJioIya4TwMvSe06hgFrDsq1xg7x16');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS spbu (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama VARCHAR(200) NOT NULL,
|
||||
no_spbu VARCHAR(50) NOT NULL,
|
||||
status ENUM('24jam', 'terbatas') NOT NULL DEFAULT '24jam',
|
||||
latitude DECIMAL(10, 7) NOT NULL,
|
||||
longitude DECIMAL(10, 7) NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE jalan (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama_jalan VARCHAR(100),
|
||||
|
||||
+105
-169
@@ -11,6 +11,7 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>WebGIS SPBU - Modern</title>
|
||||
<meta charset="UTF-8">
|
||||
@@ -41,7 +42,6 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
/* SIDEBAR */
|
||||
.sidebar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
@@ -64,7 +64,6 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
|
||||
/* Tombol toggle sidebar (hamburger) */
|
||||
.toggle-sidebar-btn {
|
||||
position: absolute;
|
||||
top: 18px;
|
||||
@@ -84,23 +83,28 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
transition: all 0.2s;
|
||||
color: #1f2937;
|
||||
}
|
||||
|
||||
body.sidebar-open .toggle-sidebar-btn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Atur posisi zoom control Leaflet agar tidak tertutup hamburger */
|
||||
.leaflet-control-zoom {
|
||||
transition: margin-left 0.3s ease;
|
||||
margin-left: 60px;
|
||||
}
|
||||
|
||||
body.sidebar-open .leaflet-control-zoom {
|
||||
margin-left: 340px;
|
||||
}
|
||||
|
||||
@media (max-width: 640px) {
|
||||
body.sidebar-open .leaflet-control-zoom {
|
||||
margin-left: 280px;
|
||||
}
|
||||
.sidebar { width: 280px; }
|
||||
|
||||
.sidebar {
|
||||
width: 280px;
|
||||
}
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
@@ -110,6 +114,7 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.sidebar-header h2 {
|
||||
font-size: 1.35rem;
|
||||
font-weight: 600;
|
||||
@@ -118,6 +123,7 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
background-clip: text;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.close-sidebar {
|
||||
background: none;
|
||||
border: none;
|
||||
@@ -131,6 +137,7 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.close-sidebar:hover {
|
||||
background: #f1f5f9;
|
||||
color: #0f172a;
|
||||
@@ -141,6 +148,7 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
background: #ffffff;
|
||||
border-bottom: 1px solid #edf2f7;
|
||||
}
|
||||
|
||||
.search-box input {
|
||||
width: 100%;
|
||||
padding: 10px 16px;
|
||||
@@ -150,16 +158,19 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
outline: none;
|
||||
transition: 0.2s;
|
||||
}
|
||||
|
||||
.search-box input:focus {
|
||||
border-color: #6366f1;
|
||||
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
|
||||
}
|
||||
|
||||
.filter-buttons {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.filter-chip {
|
||||
background: #f1f5f9;
|
||||
border: none;
|
||||
@@ -171,6 +182,7 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
transition: 0.2s;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.filter-chip.active {
|
||||
background: #6366f1;
|
||||
color: white;
|
||||
@@ -181,6 +193,7 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
overflow-y: auto;
|
||||
padding: 12px 16px;
|
||||
}
|
||||
|
||||
.result-card {
|
||||
background: #ffffff;
|
||||
border-radius: 16px;
|
||||
@@ -191,11 +204,13 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
border: 1px solid #ecf3fa;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
|
||||
.result-card:hover {
|
||||
background: #fafcff;
|
||||
transform: translateX(4px);
|
||||
border-color: #cbdff2;
|
||||
}
|
||||
|
||||
.result-title {
|
||||
font-weight: 600;
|
||||
color: #0f172a;
|
||||
@@ -203,6 +218,7 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.result-sub {
|
||||
font-size: 0.7rem;
|
||||
color: #5b6e8c;
|
||||
@@ -222,8 +238,8 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.mode-icon {
|
||||
background: #f1f5f9;
|
||||
border: none;
|
||||
@@ -238,22 +254,27 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
transition: 0.2s;
|
||||
color: #1e293b;
|
||||
}
|
||||
|
||||
.mode-icon.active {
|
||||
background: #6366f1;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.mode-icon.edit-mode {
|
||||
background: #1e293b;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.mode-icon.edit-mode.active {
|
||||
background: #10b981;
|
||||
}
|
||||
|
||||
.draw-actions {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
body.view-mode .draw-actions {
|
||||
display: none;
|
||||
}
|
||||
@@ -271,6 +292,7 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
z-index: 10;
|
||||
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.custom-draw-toolbar button {
|
||||
background: #334155;
|
||||
border: none;
|
||||
@@ -279,6 +301,7 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
border-radius: 40px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.custom-draw-toolbar button:hover {
|
||||
background: #6366f1;
|
||||
}
|
||||
@@ -286,7 +309,10 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
.edit-popup {
|
||||
min-width: 220px;
|
||||
}
|
||||
.edit-popup input, .edit-popup select, .edit-popup textarea {
|
||||
|
||||
.edit-popup input,
|
||||
.edit-popup select,
|
||||
.edit-popup textarea {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
margin: 8px 0;
|
||||
@@ -294,6 +320,7 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
border-radius: 30px;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.edit-popup button {
|
||||
padding: 6px 14px;
|
||||
border-radius: 30px;
|
||||
@@ -302,10 +329,26 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
cursor: pointer;
|
||||
font-weight: 500;
|
||||
}
|
||||
.btn-save { background: #10b981; color: white; }
|
||||
.btn-cancel { background: #94a3b8; color: white; }
|
||||
.btn-edit { background: #f59e0b; color: white; }
|
||||
.btn-delete { background: #ef4444; color: white; }
|
||||
|
||||
.btn-save {
|
||||
background: #10b981;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-cancel {
|
||||
background: #94a3b8;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-edit {
|
||||
background: #f59e0b;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-delete {
|
||||
background: #ef4444;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.toast {
|
||||
position: fixed;
|
||||
@@ -320,22 +363,27 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
transition: 0.2s;
|
||||
pointer-events: none;
|
||||
}
|
||||
.toast.show { opacity: 1; }
|
||||
|
||||
.toast.show {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.drawing-cursor {
|
||||
cursor: crosshair !important;
|
||||
}
|
||||
|
||||
body.view-mode #map {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
body.view-mode #map:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
/* Kursor saat drag marker */
|
||||
|
||||
.leaflet-marker-dragging {
|
||||
cursor: grabbing !important;
|
||||
}
|
||||
/* thumbail foto di popup */
|
||||
|
||||
.popup-img {
|
||||
max-width: 200px;
|
||||
max-height: 150px;
|
||||
@@ -345,6 +393,7 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<button class="toggle-sidebar-btn" id="openSidebarBtn">☰</button>
|
||||
@@ -356,7 +405,8 @@ while ($row = mysqli_fetch_assoc($result)) {
|
||||
</div>
|
||||
<div class="search-area">
|
||||
<div class="search-box">
|
||||
<input type="text" id="searchInput" placeholder="Cari nama, jalan, pemilik, jalan rusak..." autocomplete="off">
|
||||
<input type="text" id="searchInput" placeholder="Cari nama, jalan, pemilik, jalan rusak..."
|
||||
autocomplete="off">
|
||||
</div>
|
||||
<div class="filter-buttons">
|
||||
<button class="filter-chip active" data-filter="all">Semua</button>
|
||||
@@ -404,8 +454,8 @@ L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||
}).addTo(map);
|
||||
|
||||
// ================= GLOBAL STATE =================
|
||||
let globalEditMode = true; // true = edit, false = view
|
||||
let activeMode = null; // null = tidak ada mode aktif, 'marker_add', 'polyline', 'polygon', 'road_damage'
|
||||
let globalEditMode = true;
|
||||
let activeMode = null;
|
||||
let customDrawingActive = false;
|
||||
let customDrawingType = null;
|
||||
let customPoints = [];
|
||||
@@ -415,7 +465,7 @@ let customPreviewLine = null;
|
||||
let markers = {};
|
||||
let polylines = {};
|
||||
let polygons = {};
|
||||
let roadDamageMarkers = {}; // simpan marker jalan rusak
|
||||
let roadDamageMarkers = {};
|
||||
let dataSpbu = <?php echo json_encode($data); ?>;
|
||||
let jalanData = [];
|
||||
let parsilData = [];
|
||||
@@ -425,7 +475,6 @@ let dataLoaded = { jalan: false, parsil: false, roadDamage: false };
|
||||
const greenIcon = L.icon({ iconUrl: 'https://maps.google.com/mapfiles/ms/icons/green-dot.png', iconSize: [32, 32] });
|
||||
const yellowIcon = L.icon({ iconUrl: 'https://maps.google.com/mapfiles/ms/icons/yellow-dot.png', iconSize: [32, 32] });
|
||||
const blueIcon = L.icon({ iconUrl: 'https://maps.google.com/mapfiles/ms/icons/blue-dot.png', iconSize: [32, 32] });
|
||||
// Icon khusus jalan rusak (merah)
|
||||
const damageIcon = L.icon({
|
||||
iconUrl: 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png',
|
||||
shadowUrl: 'https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.7.1/images/marker-shadow.png',
|
||||
@@ -438,7 +487,6 @@ const damageIcon = L.icon({
|
||||
function postForm(url, data) {
|
||||
const params = new URLSearchParams();
|
||||
Object.entries(data).forEach(([key, value]) => params.append(key, value));
|
||||
|
||||
return fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
|
||||
@@ -446,7 +494,6 @@ function postForm(url, data) {
|
||||
}).then(res => res.text()).then(res => res.trim());
|
||||
}
|
||||
|
||||
// Fungsi upload file dengan FormData
|
||||
function uploadForm(url, formData) {
|
||||
return fetch(url, {
|
||||
method: 'POST',
|
||||
@@ -478,14 +525,8 @@ function updateSidebarState() {
|
||||
setTimeout(() => map.invalidateSize(), 250);
|
||||
}
|
||||
|
||||
openBtn.addEventListener('click', () => {
|
||||
sidebar.classList.remove('closed');
|
||||
updateSidebarState();
|
||||
});
|
||||
closeBtn.addEventListener('click', () => {
|
||||
sidebar.classList.add('closed');
|
||||
updateSidebarState();
|
||||
});
|
||||
openBtn.addEventListener('click', () => { sidebar.classList.remove('closed'); updateSidebarState(); });
|
||||
closeBtn.addEventListener('click', () => { sidebar.classList.add('closed'); updateSidebarState(); });
|
||||
updateSidebarState();
|
||||
|
||||
// ================= EDIT / VIEW MODE =================
|
||||
@@ -495,7 +536,6 @@ function setGlobalMode(modeType) {
|
||||
document.body.classList.remove('view-mode');
|
||||
document.getElementById('btn-edit-mode').classList.add('active');
|
||||
document.getElementById('btn-view-mode').classList.remove('active');
|
||||
// Aktifkan drag marker untuk SPBU dan Jalan Rusak
|
||||
for (let id in markers) if (markers[id].dragging) markers[id].dragging.enable();
|
||||
for (let id in roadDamageMarkers) if (roadDamageMarkers[id].dragging) roadDamageMarkers[id].dragging.enable();
|
||||
toast("Mode Edit aktif");
|
||||
@@ -503,9 +543,7 @@ function setGlobalMode(modeType) {
|
||||
document.body.classList.add('view-mode');
|
||||
document.getElementById('btn-view-mode').classList.add('active');
|
||||
document.getElementById('btn-edit-mode').classList.remove('active');
|
||||
// Batalkan drawing jika sedang aktif
|
||||
if (customDrawingActive) cancelCustomDrawing();
|
||||
// Nonaktifkan mode marker_add dan road_damage
|
||||
if (activeMode === 'marker_add' || activeMode === 'road_damage') setActiveMode(null);
|
||||
for (let id in markers) if (markers[id].dragging) markers[id].dragging.disable();
|
||||
for (let id in roadDamageMarkers) if (roadDamageMarkers[id].dragging) roadDamageMarkers[id].dragging.disable();
|
||||
@@ -518,19 +556,13 @@ function setGlobalMode(modeType) {
|
||||
document.getElementById('btn-edit-mode').addEventListener('click', () => setGlobalMode('edit'));
|
||||
document.getElementById('btn-view-mode').addEventListener('click', () => setGlobalMode('view'));
|
||||
|
||||
// ================= FUNGSI MENGATUR MODE AKTIF (SPBU, Jalan, Tanah, Jalan Rusak) =================
|
||||
function setActiveMode(mode) {
|
||||
// Jika mode yang sama dan sedang aktif, nonaktifkan
|
||||
if (activeMode === mode && mode !== null) {
|
||||
mode = null;
|
||||
}
|
||||
if (activeMode === mode && mode !== null) { mode = null; }
|
||||
activeMode = mode;
|
||||
// Update tampilan tombol
|
||||
document.querySelectorAll('.mode-icon[data-mode]').forEach(btn => btn.classList.remove('active'));
|
||||
if (activeMode === 'marker_add') {
|
||||
document.getElementById('btn-marker').classList.add('active');
|
||||
map.getContainer().style.cursor = 'crosshair';
|
||||
// Jika sedang drawing, batalkan
|
||||
if (customDrawingActive) cancelCustomDrawing();
|
||||
} else if (activeMode === 'polyline') {
|
||||
document.getElementById('btn-polyline').classList.add('active');
|
||||
@@ -543,52 +575,26 @@ function setActiveMode(mode) {
|
||||
map.getContainer().style.cursor = 'crosshair';
|
||||
if (customDrawingActive) cancelCustomDrawing();
|
||||
} else {
|
||||
// Tidak ada mode aktif
|
||||
map.getContainer().style.cursor = '';
|
||||
if (customDrawingActive) cancelCustomDrawing();
|
||||
}
|
||||
}
|
||||
|
||||
// Tombol SPBU: toggle mode marker_add
|
||||
document.getElementById('btn-marker').addEventListener('click', () => {
|
||||
if (!globalEditMode) return;
|
||||
if (activeMode === 'marker_add') {
|
||||
setActiveMode(null);
|
||||
} else {
|
||||
setActiveMode('marker_add');
|
||||
}
|
||||
if (activeMode === 'marker_add') { setActiveMode(null); } else { setActiveMode('marker_add'); }
|
||||
});
|
||||
|
||||
// Tombol Jalan: jika sedang drawing polyline, batalkan; jika tidak, mulai drawing polyline
|
||||
document.getElementById('btn-polyline').addEventListener('click', () => {
|
||||
if (!globalEditMode) return;
|
||||
if (customDrawingActive && customDrawingType === 'polyline') {
|
||||
cancelCustomDrawing();
|
||||
setActiveMode(null);
|
||||
} else {
|
||||
setActiveMode('polyline');
|
||||
}
|
||||
if (customDrawingActive && customDrawingType === 'polyline') { cancelCustomDrawing(); setActiveMode(null); } else { setActiveMode('polyline'); }
|
||||
});
|
||||
|
||||
// Tombol Tanah: jika sedang drawing polygon, batalkan; jika tidak, mulai drawing polygon
|
||||
document.getElementById('btn-polygon').addEventListener('click', () => {
|
||||
if (!globalEditMode) return;
|
||||
if (customDrawingActive && customDrawingType === 'polygon') {
|
||||
cancelCustomDrawing();
|
||||
setActiveMode(null);
|
||||
} else {
|
||||
setActiveMode('polygon');
|
||||
}
|
||||
if (customDrawingActive && customDrawingType === 'polygon') { cancelCustomDrawing(); setActiveMode(null); } else { setActiveMode('polygon'); }
|
||||
});
|
||||
|
||||
// Tombol Jalan Rusak: toggle mode road_damage
|
||||
document.getElementById('btn-road-damage').addEventListener('click', () => {
|
||||
if (!globalEditMode) return;
|
||||
if (activeMode === 'road_damage') {
|
||||
setActiveMode(null);
|
||||
} else {
|
||||
setActiveMode('road_damage');
|
||||
}
|
||||
if (activeMode === 'road_damage') { setActiveMode(null); } else { setActiveMode('road_damage'); }
|
||||
});
|
||||
|
||||
// ================= CUSTOM DRAWING =================
|
||||
@@ -686,84 +692,34 @@ function finishCustomDrawing() {
|
||||
}
|
||||
}
|
||||
|
||||
// Fungsi untuk menyimpan jalan dari custom drawing dengan validasi lengkap
|
||||
window.simpanJalanCustom = function () {
|
||||
const namaInput = document.getElementById('nama_jalan');
|
||||
const statusSelect = document.getElementById('status_jalan');
|
||||
|
||||
if (!namaInput || !statusSelect) {
|
||||
toast("Error: Form tidak ditemukan, coba ulangi drawing.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!namaInput || !statusSelect) { toast("Error: Form tidak ditemukan"); return; }
|
||||
const nama = namaInput.value.trim();
|
||||
const status = statusSelect.value;
|
||||
|
||||
if (nama === "") {
|
||||
alert("❌ Nama jalan harus diisi!");
|
||||
return;
|
||||
}
|
||||
if (status === "") {
|
||||
alert("❌ Silakan pilih status jalan!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (nama === "") { alert("❌ Nama jalan harus diisi!"); return; }
|
||||
if (status === "") { alert("❌ Silakan pilih status jalan!"); return; }
|
||||
const geo = JSON.stringify(customPoints.map(p => [p.lat, p.lng]));
|
||||
const panjang = hitungPanjang(customPoints);
|
||||
|
||||
postForm('insert_jalan.php', {
|
||||
nama,
|
||||
status,
|
||||
panjang,
|
||||
geojson: geo
|
||||
}).then(res => {
|
||||
if (res === "success") {
|
||||
toast("Jalan tersimpan");
|
||||
location.reload();
|
||||
} else {
|
||||
alert("Gagal menyimpan: " + res);
|
||||
}
|
||||
}).catch(err => alert("Error: " + err));
|
||||
postForm('insert_jalan.php', { nama, status, panjang, geojson: geo })
|
||||
.then(res => { if (res === "success") { toast("Jalan tersimpan"); location.reload(); } else { alert("Gagal menyimpan: " + res); } })
|
||||
.catch(err => alert("Error: " + err));
|
||||
};
|
||||
|
||||
// Fungsi untuk menyimpan persil dari custom drawing dengan validasi lengkap
|
||||
window.simpanParsilCustom = function () {
|
||||
const pemilikInput = document.getElementById('pemilik');
|
||||
const statusSelect = document.getElementById('status_tanah');
|
||||
|
||||
if (!pemilikInput || !statusSelect) {
|
||||
toast("Error: Form tidak ditemukan, coba ulangi drawing.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pemilikInput || !statusSelect) { toast("Error: Form tidak ditemukan"); return; }
|
||||
const pemilik = pemilikInput.value.trim();
|
||||
const status = statusSelect.value;
|
||||
|
||||
if (pemilik === "") {
|
||||
alert("❌ Nama pemilik harus diisi!");
|
||||
return;
|
||||
}
|
||||
if (status === "") {
|
||||
alert("❌ Silakan pilih status tanah!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (pemilik === "") { alert("❌ Nama pemilik harus diisi!"); return; }
|
||||
if (status === "") { alert("❌ Silakan pilih status tanah!"); return; }
|
||||
const geo = JSON.stringify([customPoints.map(p => [p.lat, p.lng])]);
|
||||
const luas = hitungLuas([customPoints]);
|
||||
|
||||
postForm('insert_parsil.php', {
|
||||
pemilik,
|
||||
status,
|
||||
luas,
|
||||
geojson: geo
|
||||
}).then(res => {
|
||||
if (res === "success") {
|
||||
toast("Persil tersimpan");
|
||||
location.reload();
|
||||
} else {
|
||||
alert("Gagal menyimpan: " + res);
|
||||
}
|
||||
}).catch(err => alert("Error: " + err));
|
||||
postForm('insert_parsil.php', { pemilik, status, luas, geojson: geo })
|
||||
.then(res => { if (res === "success") { toast("Persil tersimpan"); location.reload(); } else { alert("Gagal menyimpan: " + res); } })
|
||||
.catch(err => alert("Error: " + err));
|
||||
};
|
||||
|
||||
function cancelCustomDrawing() {
|
||||
@@ -776,10 +732,7 @@ function cancelCustomDrawing() {
|
||||
customDrawingActive = false;
|
||||
customPoints = [];
|
||||
document.getElementById('customDrawToolbar').style.display = 'none';
|
||||
// Jangan reset activeMode, biar tombol tetap menunjukkan status
|
||||
if (activeMode === 'polyline' || activeMode === 'polygon') {
|
||||
setActiveMode(null);
|
||||
}
|
||||
if (activeMode === 'polyline' || activeMode === 'polygon') { setActiveMode(null); }
|
||||
toast("Drawing dibatalkan");
|
||||
}
|
||||
window.batalCustomDrawing = cancelCustomDrawing;
|
||||
@@ -793,18 +746,13 @@ function hitungLuas(latlngs) {
|
||||
return L.GeometryUtil.geodesicArea(latlngs[0]);
|
||||
}
|
||||
|
||||
// ================= LOAD DATA JALAN & PARSIL & JALAN RUSAK =================
|
||||
// ================= LOAD DATA =================
|
||||
function loadJalan() {
|
||||
fetch('get_jalan.php').then(res => res.json()).then(data => {
|
||||
jalanData = data;
|
||||
data.forEach(j => {
|
||||
let coords = JSON.parse(j.geojson);
|
||||
let colorMap = {
|
||||
"Nasional": "#ef4444", // merah
|
||||
"Provinsi": "#f97316", // oranye
|
||||
"Kabupaten": "#3b82f6", // biru
|
||||
"Kota": "#10b981" // hijau
|
||||
};
|
||||
let colorMap = { "Nasional": "#ef4444", "Provinsi": "#f97316", "Kabupaten": "#3b82f6", "Kota": "#10b981" };
|
||||
let color = colorMap[j.status] || "#6b7280";
|
||||
let polyline = L.polyline(coords, { color: color, weight: 4, opacity: 0.8 }).addTo(map);
|
||||
polyline.on('click', () => polyline.bindPopup(getPopupJalan(j)).openPopup());
|
||||
@@ -841,7 +789,6 @@ function loadRoadDamage() {
|
||||
m.on('dragend', function () {
|
||||
if (!globalEditMode) return;
|
||||
let pos = m.getLatLng();
|
||||
// Update posisi via AJAX
|
||||
postForm('update_jalan_rusak.php', { id: rd.id, lat: pos.lat, lng: pos.lng, deskripsi: rd.deskripsi, foto_lama: rd.foto })
|
||||
.then(res => { if (res !== "success") alert("Gagal update posisi: " + res); else toast("Posisi jalan rusak diperbarui"); })
|
||||
.catch(err => alert("Error: " + err));
|
||||
@@ -858,24 +805,18 @@ function loadRoadDamage() {
|
||||
|
||||
// Load marker SPBU
|
||||
dataSpbu.forEach(d => {
|
||||
let icon = d.status === "Buka 24 Jam" ? greenIcon : yellowIcon;
|
||||
let icon = d.status === '24jam' ? greenIcon : yellowIcon;
|
||||
let m = L.marker([d.latitude, d.longitude], { icon: icon, draggable: globalEditMode }).addTo(map);
|
||||
markers[d.id] = m;
|
||||
m.bindPopup(getPopupMarker(d));
|
||||
m.on('dragstart', () => {
|
||||
map.getContainer().style.cursor = 'grabbing';
|
||||
});
|
||||
m.on('dragstart', () => { map.getContainer().style.cursor = 'grabbing'; });
|
||||
m.on('dragend', () => {
|
||||
map.getContainer().style.cursor = '';
|
||||
if (!globalEditMode) return;
|
||||
let pos = m.getLatLng();
|
||||
postForm('update.php', {
|
||||
id: d.id,
|
||||
lat: pos.lat,
|
||||
lng: pos.lng
|
||||
}).then(res => {
|
||||
if (res !== "OK") alert("Gagal memperbarui posisi SPBU: " + res);
|
||||
}).catch(err => alert("Error: " + err));
|
||||
postForm('update.php', { id: d.id, lat: pos.lat, lng: pos.lng })
|
||||
.then(res => { if (res !== "OK") alert("Gagal memperbarui posisi SPBU: " + res); })
|
||||
.catch(err => alert("Error: " + err));
|
||||
d.latitude = pos.lat; d.longitude = pos.lng;
|
||||
toast("Posisi SPBU diperbarui");
|
||||
});
|
||||
@@ -889,12 +830,12 @@ loadRoadDamage();
|
||||
function getPopupMarker(d) {
|
||||
if (globalEditMode) {
|
||||
return `<div class="edit-popup">
|
||||
<b>📍 ${d.nama_spbu}</b><br>${d.no_spbu}<br>${d.status}<br>
|
||||
<b>📍 ${d.nama}</b><br>${d.no_spbu}<br>${d.status === '24jam' ? '24 Jam' : 'Terbatas'}<br>
|
||||
<button class="btn-edit" onclick="editMarker(${d.id})">Edit</button>
|
||||
<button class="btn-delete" onclick="deleteMarker(${d.id})">Hapus</button>
|
||||
</div>`;
|
||||
} else {
|
||||
return `<div><b>${d.nama_spbu}</b><br>${d.no_spbu}<br>${d.status}</div>`;
|
||||
return `<div><b>${d.nama}</b><br>${d.no_spbu}<br>${d.status === '24jam' ? '24 Jam' : 'Terbatas'}</div>`;
|
||||
}
|
||||
}
|
||||
function getPopupJalan(j) {
|
||||
@@ -950,8 +891,8 @@ function filterSidebar() {
|
||||
|
||||
if (activeFilter === 'all' || activeFilter === 'marker') {
|
||||
dataSpbu.forEach(d => {
|
||||
if (d.nama_spbu.toLowerCase().includes(searchText))
|
||||
results.push({ type: 'marker', id: d.id, name: d.nama_spbu, desc: d.status, latlng: [d.latitude, d.longitude] });
|
||||
if (d.nama.toLowerCase().includes(searchText))
|
||||
results.push({ type: 'marker', id: d.id, name: d.nama, desc: d.status === '24jam' ? '24 Jam' : 'Terbatas', latlng: [d.latitude, d.longitude] });
|
||||
});
|
||||
}
|
||||
if (activeFilter === 'all' || activeFilter === 'polyline') {
|
||||
@@ -1001,12 +942,12 @@ document.querySelectorAll('.filter-chip').forEach(chip => {
|
||||
});
|
||||
document.getElementById('searchInput').addEventListener('input', filterSidebar);
|
||||
|
||||
// ================= CRUD FUNCTIONS (SPBU, Jalan, Tanah) =================
|
||||
// ================= CRUD FUNCTIONS =================
|
||||
window.editMarker = function (id) {
|
||||
let d = dataSpbu.find(x => x.id == id);
|
||||
let form = `<div class="edit-popup">
|
||||
<input id="nama" value="${d.nama_spbu}"><input id="no" value="${d.no_spbu}">
|
||||
<select id="status"><option ${d.status=="Buka 24 Jam"?"selected":""}>Buka 24 Jam</option><option ${d.status=="Tidak 24 Jam"?"selected":""}>Tidak 24 Jam</option></select>
|
||||
<input id="nama" value="${d.nama}"><input id="no" value="${d.no_spbu}">
|
||||
<select id="status"><option ${d.status == "24jam" ? "selected" : ""} value="24jam">24 Jam</option><option ${d.status == "terbatas" ? "selected" : ""} value="terbatas">Terbatas</option></select>
|
||||
<button class="btn-save" onclick="saveEditMarker(${id})">Simpan</button>
|
||||
<button class="btn-cancel" onclick="refreshAllPopups()">Batal</button>
|
||||
</div>`;
|
||||
@@ -1065,13 +1006,9 @@ window.deleteParsil = function(id){
|
||||
.catch(err => alert("Error: " + err));
|
||||
};
|
||||
|
||||
// ================= CRUD JALAN RUSAK =================
|
||||
// Variabel untuk marker sementara saat mode road_damage
|
||||
// ================= JALAN RUSAK =================
|
||||
let tempRoadMarker = null;
|
||||
|
||||
// Hapus event click lama dan ganti dengan yang baru (mencakup road_damage)
|
||||
map.off('click');
|
||||
|
||||
let tempMarker = null;
|
||||
|
||||
map.on('click', function (e) {
|
||||
@@ -1082,7 +1019,7 @@ map.on('click', function(e) {
|
||||
tempMarker = L.marker(e.latlng, { icon: blueIcon }).addTo(map);
|
||||
let form = `<div class="edit-popup">
|
||||
<input id="nama_baru" placeholder="Nama SPBU" autocomplete="off"><input id="no_baru" placeholder="No SPBU" autocomplete="off">
|
||||
<select id="status_baru"><option>Buka 24 Jam</option><option>Tidak 24 Jam</option></select>
|
||||
<select id="status_baru"><option value="24jam">24 Jam</option><option value="terbatas">Terbatas</option></select>
|
||||
<button class="btn-save" onclick="simpanMarkerBaru(${e.latlng.lat}, ${e.latlng.lng})">Simpan</button>
|
||||
<button class="btn-cancel" onclick="batalMarkerBaru()">Batal</button>
|
||||
</div>`;
|
||||
@@ -1129,7 +1066,6 @@ window.simpanRoadDamageBaru = function(lat, lng) {
|
||||
.catch(err => alert("Error: " + err));
|
||||
};
|
||||
|
||||
// Edit & Delete jalan rusak
|
||||
window.saveEditRoadDamage = function (id) {
|
||||
let rd = roadDamageData.find(r => r.id == id);
|
||||
let deskripsiBaru = document.getElementById('deskripsi_edit').value.trim();
|
||||
@@ -1157,9 +1093,9 @@ window.deleteRoadDamage = function(id) {
|
||||
document.getElementById('undoPointBtn').addEventListener('click', undoLastPoint);
|
||||
document.getElementById('finishDrawBtn').addEventListener('click', finishCustomDrawing);
|
||||
document.getElementById('cancelDrawBtn').addEventListener('click', cancelCustomDrawing);
|
||||
// Tidak ada mode aktif saat awal
|
||||
setActiveMode(null);
|
||||
setGlobalMode('edit'); // default mode edit
|
||||
setGlobalMode('edit');
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -7,14 +7,12 @@ $status = $_POST['status'] ?? '';
|
||||
$lat = $_POST['lat'] ?? '';
|
||||
$lng = $_POST['lng'] ?? '';
|
||||
|
||||
// VALIDASI
|
||||
if($nama == "" || $no == "" || $status == "" || $lat == "" || $lng == ""){
|
||||
echo "DATA TIDAK LENGKAP";
|
||||
exit;
|
||||
}
|
||||
|
||||
// PREPARED STATEMENT
|
||||
$stmt = $conn->prepare("INSERT INTO spbu (nama_spbu, no_spbu, status, latitude, longitude) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt = $conn->prepare("INSERT INTO spbu (nama, no_spbu, status, latitude, longitude) VALUES (?, ?, ?, ?, ?)");
|
||||
$stmt->bind_param("sssdd", $nama, $no, $status, $lat, $lng);
|
||||
|
||||
if($stmt->execute()){
|
||||
|
||||
@@ -11,7 +11,7 @@ if($id == "" || $nama == "" || $no == "" || $status == ""){
|
||||
exit;
|
||||
}
|
||||
|
||||
$stmt = $conn->prepare("UPDATE spbu SET nama_spbu=?, no_spbu=?, status=? WHERE id=?");
|
||||
$stmt = $conn->prepare("UPDATE spbu SET nama=?, no_spbu=?, status=? WHERE id=?");
|
||||
$stmt->bind_param("sssi", $nama, $no, $status, $id);
|
||||
|
||||
if($stmt->execute()){
|
||||
|
||||
@@ -9,7 +9,7 @@ CREATE TABLE IF NOT EXISTS admin (
|
||||
);
|
||||
|
||||
INSERT INTO admin (username, password) VALUES
|
||||
('admin', '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi');
|
||||
('admin', '$2y$10$A9m/u6sAxEwgIO4dlmIvNO2WJioIya4TwMvSe06hgFrDsq1xg7x16');
|
||||
|
||||
CREATE TABLE IF NOT EXISTS spbu (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
@@ -21,3 +21,30 @@ CREATE TABLE IF NOT EXISTS spbu (
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE jalan (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama_jalan VARCHAR(100),
|
||||
status ENUM('Nasional','Provinsi','Kabupaten'),
|
||||
panjang DOUBLE,
|
||||
geojson TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE parsil (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
pemilik VARCHAR(100),
|
||||
status ENUM('SHM','HGB','HGU','HP'),
|
||||
luas DOUBLE,
|
||||
geojson TEXT,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `jalan_rusak` (
|
||||
`id` INT AUTO_INCREMENT PRIMARY KEY,
|
||||
`deskripsi` TEXT NOT NULL,
|
||||
`foto` VARCHAR(255) NOT NULL,
|
||||
`latitude` DOUBLE NOT NULL,
|
||||
`longitude` DOUBLE NOT NULL,
|
||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
Reference in New Issue
Block a user