Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f5043b13d7 | |||
| 1b44fc6a8f |
@@ -0,0 +1,103 @@
|
|||||||
|
# Draft Dokumen Pengumpulan Project Ujian/Tugas WebGIS
|
||||||
|
|
||||||
|
Berdasarkan screenshot form pengumpulan tugas yang Anda berikan, berikut adalah draft untuk dokumen-dokumen yang perlu disiapkan:
|
||||||
|
|
||||||
|
## 1. Dokumen Panduan Pengguna (User Guide) Aplikasi WebGIS
|
||||||
|
*(Simpan sebagai file PDF/Word)*
|
||||||
|
|
||||||
|
**Judul:** Panduan Pengguna WebGIS Poverty Mapping (Pusat Integrasi Data GIS Kota Pontianak)
|
||||||
|
|
||||||
|
**Daftar Isi:**
|
||||||
|
1. **Pendahuluan:** Penjelasan singkat tentang aplikasi WebGIS Poverty Mapping.
|
||||||
|
2. **Cara Mengakses Aplikasi:** URL/Link aplikasi dan cara masuk ke Portal Utama.
|
||||||
|
3. **Modul Fasilitas & Tata Kota (Infrastruktur):**
|
||||||
|
- Cara melihat data spasial fasilitas umum dan jaringan jalan raya.
|
||||||
|
- Cara melihat batas kepemilikan lahan dan lokasi SPBU.
|
||||||
|
- (Jika ada fitur admin/login) Cara menambah atau mengubah data spasial infrastruktur.
|
||||||
|
4. **Modul Sosial & Kemasyarakatan:**
|
||||||
|
- Cara memetakan dan melihat kawasan rentan serta distribusi penduduk.
|
||||||
|
- Cara melihat pemantauan rumah ibadah dan data laporan darurat.
|
||||||
|
5. **Modul Portal Publik (Warga):**
|
||||||
|
- Cara warga mengakses aplikasi secara publik (tanpa login).
|
||||||
|
- Cara warga melihat fasilitas umum terdekat.
|
||||||
|
- Cara warga melakukan pelaporan cepat kedaruratan.
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Dokumen Spesifikasi Kebutuhan Perangkat Lunak (SKPL)
|
||||||
|
*(Simpan sebagai file PDF/Word)*
|
||||||
|
|
||||||
|
**Judul:** Spesifikasi Kebutuhan Perangkat Lunak (SKPL) - WebGIS Poverty Mapping
|
||||||
|
|
||||||
|
**1. Pendahuluan**
|
||||||
|
- **Tujuan:** Mendokumentasikan kebutuhan fungsional dan non-fungsional aplikasi WebGIS Poverty Mapping.
|
||||||
|
- **Ruang Lingkup:** Aplikasi berbasis web untuk pemetaan kemiskinan, fasilitas umum, dan pelaporan darurat di Kota Pontianak.
|
||||||
|
|
||||||
|
**2. Deskripsi Umum Sistem**
|
||||||
|
- Aplikasi ini terdiri dari 3 modul utama: Portal Infrastruktur, Portal Sosial, dan Portal Warga.
|
||||||
|
- Pengguna sistem terdiri dari: Admin (pengelola data) dan Masyarakat Umum (warga).
|
||||||
|
|
||||||
|
**3. Kebutuhan Fungsional (Functional Requirements)**
|
||||||
|
- **FR-01:** Sistem harus dapat menampilkan peta dasar (base map) menggunakan Leaflet.js atau sejenisnya.
|
||||||
|
- **FR-02:** Sistem menyediakan fitur bagi Admin untuk mengelola (CRUD) data fasilitas umum, SPBU, jalan raya, dan persil tanah (Modul Infrastruktur).
|
||||||
|
- **FR-03:** Sistem menyediakan fitur bagi Admin untuk memantau data demografi/sosial, rumah ibadah, dan melihat laporan darurat (Modul Sosial).
|
||||||
|
- **FR-04:** Sistem memungkinkan warga (tanpa login) untuk melihat peta titik-titik fasilitas, serta mengisi form pelaporan kejadian darurat.
|
||||||
|
- **FR-05:** Sistem memungkinkan warga menarik/drag pin pada peta untuk menentukan koordinat kejadian secara akurat.
|
||||||
|
|
||||||
|
**4. Kebutuhan Non-Fungsional (Non-Functional Requirements)**
|
||||||
|
- **Ketersediaan (Availability):** Aplikasi dapat diakses 24/7 melalui browser web.
|
||||||
|
- **Keamanan (Security):** Sistem dirancang terbuka (tanpa otentikasi login yang ketat) untuk memudahkan masyarakat dan petugas lapangan dalam menginput data secara langsung.
|
||||||
|
- **Performa:** Peta dan marker harus dapat dimuat dalam waktu kurang dari 5 detik pada koneksi internet standar.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Slide Presentasi
|
||||||
|
*(Buat di PowerPoint / Google Slides dan simpan sebagai PDF/PPT)*
|
||||||
|
|
||||||
|
**Slide 1: Judul Project**
|
||||||
|
- Nama Project: WebGIS Poverty Mapping (Pusat Integrasi Data GIS Kota Pontianak)
|
||||||
|
- Nama / NIM Kelompok Anda
|
||||||
|
|
||||||
|
**Slide 2: Latar Belakang & Tujuan**
|
||||||
|
- Mengapa aplikasi ini dibuat? (Untuk mengintegrasikan data spasial kemiskinan, infrastruktur, sosial, dan memfasilitasi pelaporan warga).
|
||||||
|
- Manfaat bagi pemerintah dan masyarakat.
|
||||||
|
|
||||||
|
**Slide 3: Arsitektur / Teknologi yang Digunakan**
|
||||||
|
- Frontend: HTML, CSS, JavaScript, Leaflet.js (untuk peta).
|
||||||
|
- Backend: PHP.
|
||||||
|
- Database: MySQL / MariaDB (Menyimpan titik koordinat dan data).
|
||||||
|
- Server/Hosting: Coolify (jika sudah di-deploy) / Localhost XAMPP.
|
||||||
|
|
||||||
|
**Slide 4: Fitur Utama: Modul Infrastruktur & Sosial**
|
||||||
|
- Screenshot halaman Dashboard Admin (Infrastruktur & Sosial).
|
||||||
|
- Penjelasan singkat fitur (Manajemen SPBU, fasilitas umum, demografi).
|
||||||
|
|
||||||
|
**Slide 5: Fitur Utama: Modul Warga (Publik)**
|
||||||
|
- Screenshot halaman Portal Warga.
|
||||||
|
- Penjelasan alur warga melakukan pelaporan darurat menggunakan *draggable map markers*.
|
||||||
|
|
||||||
|
**Slide 6: Demo Singkat (Opsional)**
|
||||||
|
- Siapkan link / video demo singkat penggunaan aplikasi.
|
||||||
|
|
||||||
|
**Slide 7: Kesimpulan & Penutup**
|
||||||
|
- Kesimpulan keberhasilan project.
|
||||||
|
- Sesi tanya jawab.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Persiapan File Project (.ZIP)
|
||||||
|
Form meminta 2 file ZIP: **Upload File Project WebGIS Poverty Map** dan **Upload File Project Tugas di Kelas**.
|
||||||
|
|
||||||
|
**Langkah membuat ZIP:**
|
||||||
|
1. Buka folder `c:\Webargis\webgis01` (atau folder utama project Anda).
|
||||||
|
2. Pastikan file database (`.sql`) sudah diekspor dan dimasukkan ke dalam folder project. Saya melihat ada file `CREATE DATABASE webgis_spbu;.sql`, pastikan ini adalah versi terbaru dari database Anda.
|
||||||
|
3. Blok semua file & folder di dalam `webgis01` (`api`, `infra`, `portal`, `sosial`, `warga`, `index.php`, `test.php`, `.sql`, dll).
|
||||||
|
4. Klik kanan -> Send to -> **Compressed (zipped) folder** (atau gunakan WinRAR/7-zip).
|
||||||
|
5. Beri nama file ZIP tersebut sesuai format tugas, misalnya:
|
||||||
|
- `Project_WebGIS_Poverty_Map_Nama_NIM.zip`
|
||||||
|
- `Project_Tugas_Kelas_Nama_NIM.zip`
|
||||||
|
6. Upload kedua file ZIP ini di form.
|
||||||
|
|
||||||
|
---
|
||||||
|
Silakan salin teks di atas ke Microsoft Word atau PowerPoint untuk melengkapi tugas Anda. Apakah Anda butuh bantuan untuk membuat dokumen secara utuh dalam format PDF/Word melalui kode?
|
||||||
+2
-1
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
session_set_cookie_params(['path' => '/']);
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
$is_public_action = ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'simpan_pelaporan');
|
$is_public_action = ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action']) && $_POST['action'] === 'simpan_pelaporan');
|
||||||
@@ -27,7 +28,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$allowed_sosial_actions = ['simpan_warga', 'simpan_masjid', 'simpan_pelaporan'];
|
$allowed_sosial_actions = ['simpan_warga', 'simpan_masjid', 'simpan_pelaporan'];
|
||||||
$allowed_sosial_tables = ['warga', 'rumah_ibadah', 'pelaporan'];
|
$allowed_sosial_tables = ['warga', 'rumah_ibadah', 'pelaporan'];
|
||||||
|
|
||||||
$is_authorized = false;
|
$is_authorized = true; // Bypassed for demo/user request
|
||||||
|
|
||||||
if (in_array($role, ['admin', 'admin_infra', 'admin_sosial'])) {
|
if (in_array($role, ['admin', 'admin_infra', 'admin_sosial'])) {
|
||||||
$is_authorized = true;
|
$is_authorized = true;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
session_set_cookie_params(['path' => '/']);
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
require_once '../api/db.php';
|
require_once '../api/db.php';
|
||||||
|
|||||||
+65
-65
@@ -36,9 +36,9 @@ var currentRadius = 500;
|
|||||||
var cachedData = null;
|
var cachedData = null;
|
||||||
|
|
||||||
var drawControl = new L.Control.Draw({
|
var drawControl = new L.Control.Draw({
|
||||||
draw: {
|
draw: {
|
||||||
marker:false, circle:false, circlemarker:false,
|
marker: false, circle: false, circlemarker: false,
|
||||||
polyline: { shapeOptions: { color: 'blue', weight: 4 } },
|
polyline: { shapeOptions: { color: 'blue', weight: 4 } },
|
||||||
polygon: { shapeOptions: { color: 'red' } },
|
polygon: { shapeOptions: { color: 'red' } },
|
||||||
rectangle: false
|
rectangle: false
|
||||||
},
|
},
|
||||||
@@ -47,7 +47,7 @@ var drawControl = new L.Control.Draw({
|
|||||||
map.addControl(drawControl);
|
map.addControl(drawControl);
|
||||||
|
|
||||||
// Locate Control
|
// Locate Control
|
||||||
var locateBtn = L.control({position: 'topleft'});
|
var locateBtn = L.control({ position: 'topleft' });
|
||||||
locateBtn.onAdd = function (map) {
|
locateBtn.onAdd = function (map) {
|
||||||
var div = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
|
var div = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
|
||||||
div.style.backgroundColor = 'white';
|
div.style.backgroundColor = 'white';
|
||||||
@@ -59,13 +59,13 @@ locateBtn.onAdd = function (map) {
|
|||||||
div.style.justifyContent = 'center';
|
div.style.justifyContent = 'center';
|
||||||
div.innerHTML = '<i class="fas fa-crosshairs" style="font-size:1.2rem; color:#2563eb;"></i>';
|
div.innerHTML = '<i class="fas fa-crosshairs" style="font-size:1.2rem; color:#2563eb;"></i>';
|
||||||
div.title = "Lokasi Anda Saat Ini";
|
div.title = "Lokasi Anda Saat Ini";
|
||||||
div.onclick = function(){ map.locate({setView: true, maxZoom: 16}); }
|
div.onclick = function () { map.locate({ setView: true, maxZoom: 16 }); }
|
||||||
return div;
|
return div;
|
||||||
};
|
};
|
||||||
locateBtn.addTo(map);
|
locateBtn.addTo(map);
|
||||||
|
|
||||||
map.on('locationfound', function(e) {
|
map.on('locationfound', function (e) {
|
||||||
L.circleMarker(e.latlng, {radius: 8, fillColor: '#3b82f6', color: '#fff', weight: 3, fillOpacity: 1}).addTo(map).bindPopup("Lokasi Anda").openPopup();
|
L.circleMarker(e.latlng, { radius: 8, fillColor: '#3b82f6', color: '#fff', weight: 3, fillOpacity: 1 }).addTo(map).bindPopup("Lokasi Anda").openPopup();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Event Draw
|
// Event Draw
|
||||||
@@ -80,21 +80,21 @@ map.on(L.Draw.Event.CREATED, function (e) {
|
|||||||
if (type === 'polyline') {
|
if (type === 'polyline') {
|
||||||
document.getElementById('jenis').value = 'jalan';
|
document.getElementById('jenis').value = 'jalan';
|
||||||
toggleForm();
|
toggleForm();
|
||||||
|
|
||||||
var coords = layer.getLatLngs();
|
var coords = layer.getLatLngs();
|
||||||
document.getElementById('jalan_coords').value = JSON.stringify(coords);
|
document.getElementById('jalan_coords').value = JSON.stringify(coords);
|
||||||
|
|
||||||
// Calculate Length automatically
|
// Calculate Length automatically
|
||||||
var length = 0;
|
var length = 0;
|
||||||
for (var i = 0; i < coords.length - 1; i++) {
|
for (var i = 0; i < coords.length - 1; i++) {
|
||||||
length += coords[i].distanceTo(coords[i + 1]);
|
length += coords[i].distanceTo(coords[i + 1]);
|
||||||
}
|
}
|
||||||
document.getElementById('panjang_jalan').value = length.toFixed(2);
|
document.getElementById('panjang_jalan').value = length.toFixed(2);
|
||||||
|
|
||||||
} else if (type === 'polygon') {
|
} else if (type === 'polygon') {
|
||||||
document.getElementById('jenis').value = 'parsil';
|
document.getElementById('jenis').value = 'parsil';
|
||||||
toggleForm();
|
toggleForm();
|
||||||
|
|
||||||
var coords = layer.getLatLngs()[0];
|
var coords = layer.getLatLngs()[0];
|
||||||
document.getElementById('parsil_coords').value = JSON.stringify(coords);
|
document.getElementById('parsil_coords').value = JSON.stringify(coords);
|
||||||
}
|
}
|
||||||
@@ -103,15 +103,15 @@ map.on(L.Draw.Event.CREATED, function (e) {
|
|||||||
map.on(L.Draw.Event.EDITED, function (e) {
|
map.on(L.Draw.Event.EDITED, function (e) {
|
||||||
var layers = e.layers;
|
var layers = e.layers;
|
||||||
layers.eachLayer(function (layer) {
|
layers.eachLayer(function (layer) {
|
||||||
if(layer.db_id && layer.db_tipe) {
|
if (layer.db_id && layer.db_tipe) {
|
||||||
var coords = (layer.db_tipe === 'parsil') ? layer.getLatLngs()[0] : layer.getLatLngs();
|
var coords = (layer.db_tipe === 'parsil') ? layer.getLatLngs()[0] : layer.getLatLngs();
|
||||||
var fd = new FormData();
|
var fd = new FormData();
|
||||||
fd.append('action', 'update_koordinat');
|
fd.append('action', 'update_koordinat');
|
||||||
fd.append('id', layer.db_id);
|
fd.append('id', layer.db_id);
|
||||||
fd.append('tipe', layer.db_tipe);
|
fd.append('tipe', layer.db_tipe);
|
||||||
fd.append('koordinat', JSON.stringify(coords));
|
fd.append('koordinat', JSON.stringify(coords));
|
||||||
|
|
||||||
if(layer.db_tipe === 'jalan') {
|
if (layer.db_tipe === 'jalan') {
|
||||||
var length = 0;
|
var length = 0;
|
||||||
for (var i = 0; i < coords.length - 1; i++) {
|
for (var i = 0; i < coords.length - 1; i++) {
|
||||||
length += coords[i].distanceTo(coords[i + 1]);
|
length += coords[i].distanceTo(coords[i + 1]);
|
||||||
@@ -121,13 +121,13 @@ map.on(L.Draw.Event.EDITED, function (e) {
|
|||||||
fetch('../api/api.php', { method: 'POST', body: fd });
|
fetch('../api/api.php', { method: 'POST', body: fd });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Swal.fire({icon: 'success', title: 'Tersimpan', text: 'Perubahan bentuk berhasil disimpan!', timer: 1500, showConfirmButton: false});
|
Swal.fire({ icon: 'success', title: 'Tersimpan', text: 'Perubahan bentuk berhasil disimpan!', timer: 1500, showConfirmButton: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
map.on(L.Draw.Event.DELETED, function (e) {
|
map.on(L.Draw.Event.DELETED, function (e) {
|
||||||
var layers = e.layers;
|
var layers = e.layers;
|
||||||
layers.eachLayer(function (layer) {
|
layers.eachLayer(function (layer) {
|
||||||
if(layer.db_id && layer.db_tipe) {
|
if (layer.db_id && layer.db_tipe) {
|
||||||
var fd = new FormData();
|
var fd = new FormData();
|
||||||
fd.append('action', 'hapus_data');
|
fd.append('action', 'hapus_data');
|
||||||
fd.append('id', layer.db_id);
|
fd.append('id', layer.db_id);
|
||||||
@@ -135,20 +135,20 @@ map.on(L.Draw.Event.DELETED, function (e) {
|
|||||||
fetch('../api/api.php', { method: 'POST', body: fd });
|
fetch('../api/api.php', { method: 'POST', body: fd });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Swal.fire({icon: 'success', title: 'Terhapus', text: 'Data berhasil dihapus dari peta!', timer: 1500, showConfirmButton: false});
|
Swal.fire({ icon: 'success', title: 'Terhapus', text: 'Data berhasil dihapus dari peta!', timer: 1500, showConfirmButton: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggleSidebar() { document.getElementById('sidebar').classList.toggle('active'); }
|
function toggleSidebar() { document.getElementById('sidebar').classList.toggle('active'); }
|
||||||
|
|
||||||
function toggleRightPanel() {
|
function toggleRightPanel() {
|
||||||
var panel = document.getElementById('panelInput');
|
var panel = document.getElementById('panelInput');
|
||||||
if(panel) panel.classList.toggle('collapsed');
|
if (panel) panel.classList.toggle('collapsed');
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterData() {
|
function filterData() {
|
||||||
var input = document.getElementById('searchInput').value.toLowerCase();
|
var input = document.getElementById('searchInput').value.toLowerCase();
|
||||||
var cards = document.getElementsByClassName('item-data');
|
var cards = document.getElementsByClassName('item-data');
|
||||||
if(input.length > 0) document.getElementById('sidebar').classList.add('active');
|
if (input.length > 0) document.getElementById('sidebar').classList.add('active');
|
||||||
for (var i = 0; i < cards.length; i++) {
|
for (var i = 0; i < cards.length; i++) {
|
||||||
cards[i].style.display = cards[i].getAttribute('data-nama').includes(input) ? "" : "none";
|
cards[i].style.display = cards[i].getAttribute('data-nama').includes(input) ? "" : "none";
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ function filterData() {
|
|||||||
function changeRadius(v) {
|
function changeRadius(v) {
|
||||||
currentRadius = parseInt(v);
|
currentRadius = parseInt(v);
|
||||||
document.getElementById('radiusVal').innerText = v;
|
document.getElementById('radiusVal').innerText = v;
|
||||||
if(cachedData) renderMap(cachedData);
|
if (cachedData) renderMap(cachedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
var prevReportCount = -1;
|
var prevReportCount = -1;
|
||||||
@@ -166,7 +166,7 @@ function loadData(isPolling = false) {
|
|||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
cachedData = data;
|
cachedData = data;
|
||||||
|
|
||||||
// Logika Notifikasi Bubble
|
// Logika Notifikasi Bubble
|
||||||
if (prevReportCount !== -1 && data.pelaporan.length > prevReportCount) {
|
if (prevReportCount !== -1 && data.pelaporan.length > prevReportCount) {
|
||||||
var newCount = data.pelaporan.length - prevReportCount;
|
var newCount = data.pelaporan.length - prevReportCount;
|
||||||
@@ -181,10 +181,10 @@ function loadData(isPolling = false) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
prevReportCount = data.pelaporan.length;
|
prevReportCount = data.pelaporan.length;
|
||||||
|
|
||||||
var badge = document.getElementById('notifBadge');
|
var badge = document.getElementById('notifBadge');
|
||||||
if(badge) {
|
if (badge) {
|
||||||
if(data.pelaporan.length > 0) {
|
if (data.pelaporan.length > 0) {
|
||||||
badge.style.display = 'block';
|
badge.style.display = 'block';
|
||||||
badge.innerText = data.pelaporan.length;
|
badge.innerText = data.pelaporan.length;
|
||||||
} else {
|
} else {
|
||||||
@@ -208,7 +208,7 @@ function loadData(isPolling = false) {
|
|||||||
// Auto-poll every 10 seconds
|
// Auto-poll every 10 seconds
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
// Only poll if not currently editing (edit_id is 0)
|
// Only poll if not currently editing (edit_id is 0)
|
||||||
if(document.getElementById('edit_id') && document.getElementById('edit_id').value === "0") {
|
if (document.getElementById('edit_id') && document.getElementById('edit_id').value === "0") {
|
||||||
loadData(true);
|
loadData(true);
|
||||||
}
|
}
|
||||||
}, 10000);
|
}, 10000);
|
||||||
@@ -238,12 +238,12 @@ function renderSidebar(data) {
|
|||||||
if (!window.dashboardType || window.dashboardType === 'sosial' || window.dashboardType === 'admin') {
|
if (!window.dashboardType || window.dashboardType === 'sosial' || window.dashboardType === 'admin') {
|
||||||
// Pelaporan
|
// Pelaporan
|
||||||
html += `<div class="section-title" style="color:#ef4444">🚨 Laporan Darurat</div>`;
|
html += `<div class="section-title" style="color:#ef4444">🚨 Laporan Darurat</div>`;
|
||||||
if(data.pelaporan.length === 0) html += `<small style="color:#666">Belum ada laporan</small>`;
|
if (data.pelaporan.length === 0) html += `<small style="color:#666">Belum ada laporan</small>`;
|
||||||
data.pelaporan.forEach(p => {
|
data.pelaporan.forEach(p => {
|
||||||
html += `<div class="card item-data" data-nama="${p.nama_pelapor.toLowerCase()} ${p.isi_laporan.toLowerCase()}">
|
html += `<div class="card item-data" data-nama="${p.nama_pelapor.toLowerCase()} ${p.isi_laporan.toLowerCase()}">
|
||||||
<div style="display:flex; justify-content:space-between">
|
<div style="display:flex; justify-content:space-between">
|
||||||
<span onclick="fokus(${p.latitude}, ${p.longitude})" style="cursor:pointer">
|
<span onclick="fokus(${p.latitude}, ${p.longitude})" style="cursor:pointer">
|
||||||
<b>${p.nama_pelapor}</b><small><i class="far fa-clock"></i> ${p.waktu}</small><br><span>${p.isi_laporan.substring(0,40)}...</span>
|
<b>${p.nama_pelapor}</b><small><i class="far fa-clock"></i> ${p.waktu}</small><br><span>${p.isi_laporan.substring(0, 40)}...</span>
|
||||||
</span>
|
</span>
|
||||||
<div>
|
<div>
|
||||||
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-bottom:5px;" onclick="editData('pelaporan', ${p.id})">Edit</button><br>
|
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-bottom:5px;" onclick="editData('pelaporan', ${p.id})">Edit</button><br>
|
||||||
@@ -313,9 +313,9 @@ function renderSidebar(data) {
|
|||||||
html += `<div class="section-title">🛣️ Manajemen Jalan</div>`;
|
html += `<div class="section-title">🛣️ Manajemen Jalan</div>`;
|
||||||
data.jalan.forEach(j => {
|
data.jalan.forEach(j => {
|
||||||
var color = '#ef4444'; // default red
|
var color = '#ef4444'; // default red
|
||||||
if(j.status_jalan === 'Nasional') color = '#ef4444';
|
if (j.status_jalan === 'Nasional') color = '#ef4444';
|
||||||
else if(j.status_jalan === 'Provinsi') color = '#eab308';
|
else if (j.status_jalan === 'Provinsi') color = '#eab308';
|
||||||
else if(j.status_jalan === 'Kabupaten') color = '#22c55e';
|
else if (j.status_jalan === 'Kabupaten') color = '#22c55e';
|
||||||
html += `<div class="card item-data" data-nama="${j.nama_jalan.toLowerCase()}">
|
html += `<div class="card item-data" data-nama="${j.nama_jalan.toLowerCase()}">
|
||||||
<div style="display:flex; justify-content:space-between">
|
<div style="display:flex; justify-content:space-between">
|
||||||
<span>
|
<span>
|
||||||
@@ -373,10 +373,10 @@ function renderMap(data) {
|
|||||||
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${m.id}, 'masjid')">Hapus</button>
|
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${m.id}, 'masjid')">Hapus</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
var faClass = 'fa-mosque';
|
var faClass = 'fa-mosque';
|
||||||
if(m.jenis === 'Gereja') faClass = 'fa-church';
|
if (m.jenis === 'Gereja') faClass = 'fa-church';
|
||||||
else if(m.jenis === 'Vihara') faClass = 'fa-vihara';
|
else if (m.jenis === 'Vihara') faClass = 'fa-vihara';
|
||||||
else if(m.jenis === 'Pura') faClass = 'fa-torii-gate';
|
else if (m.jenis === 'Pura') faClass = 'fa-torii-gate';
|
||||||
|
|
||||||
// Buat custom marker bentuk map pin dengan icon sesuai jenis
|
// Buat custom marker bentuk map pin dengan icon sesuai jenis
|
||||||
var masjidIcon = L.divIcon({
|
var masjidIcon = L.divIcon({
|
||||||
html: `
|
html: `
|
||||||
@@ -408,7 +408,7 @@ function renderMap(data) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
L.marker([m.latitude, m.longitude], { icon: masjidIcon, draggable: true }).addTo(layerMasjid).bindPopup(popup)
|
L.marker([m.latitude, m.longitude], { icon: masjidIcon, draggable: true }).addTo(layerMasjid).bindPopup(popup)
|
||||||
.on('dragend', function(e){ updateMarkerCoord(m.id, 'masjid', e.target.getLatLng()); });
|
.on('dragend', function (e) { updateMarkerCoord(m.id, 'masjid', e.target.getLatLng()); });
|
||||||
L.circle([m.latitude, m.longitude], {
|
L.circle([m.latitude, m.longitude], {
|
||||||
radius: currentRadius, color: '#2563eb', fillOpacity: 0.1, weight: 1
|
radius: currentRadius, color: '#2563eb', fillOpacity: 0.1, weight: 1
|
||||||
}).addTo(layerMasjidRadius);
|
}).addTo(layerMasjidRadius);
|
||||||
@@ -454,7 +454,7 @@ function renderMap(data) {
|
|||||||
L.marker([p.latitude, p.longitude], {
|
L.marker([p.latitude, p.longitude], {
|
||||||
icon: pelaporanIcon, draggable: true
|
icon: pelaporanIcon, draggable: true
|
||||||
}).addTo(layerPelaporan).bindPopup(popup)
|
}).addTo(layerPelaporan).bindPopup(popup)
|
||||||
.on('dragend', function(e){ updateMarkerCoord(p.id, 'pelaporan', e.target.getLatLng()); });
|
.on('dragend', function (e) { updateMarkerCoord(p.id, 'pelaporan', e.target.getLatLng()); });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,7 +464,7 @@ function renderMap(data) {
|
|||||||
var is24 = s.kategori === '24jam';
|
var is24 = s.kategori === '24jam';
|
||||||
var iconUrl = is24 ? 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png' : 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png';
|
var iconUrl = is24 ? 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png' : 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png';
|
||||||
var targetLayer = is24 ? layerSpbu24 : layerSpbuNon24;
|
var targetLayer = is24 ? layerSpbu24 : layerSpbuNon24;
|
||||||
|
|
||||||
var popup = `<b>⛽ ${s.nama}</b><br>Kategori: ${s.kategori === '24jam' ? 'Buka 24 Jam' : 'Tidak 24 Jam'}<br>
|
var popup = `<b>⛽ ${s.nama}</b><br>Kategori: ${s.kategori === '24jam' ? 'Buka 24 Jam' : 'Tidak 24 Jam'}<br>
|
||||||
<div style="margin-top:10px; text-align:center;">
|
<div style="margin-top:10px; text-align:center;">
|
||||||
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('spbu', ${s.id})">Edit</button>
|
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('spbu', ${s.id})">Edit</button>
|
||||||
@@ -473,7 +473,7 @@ function renderMap(data) {
|
|||||||
L.marker([s.latitude, s.longitude], {
|
L.marker([s.latitude, s.longitude], {
|
||||||
icon: L.icon({ iconUrl: iconUrl, iconSize: [25, 41], iconAnchor: [12, 41] }), draggable: true
|
icon: L.icon({ iconUrl: iconUrl, iconSize: [25, 41], iconAnchor: [12, 41] }), draggable: true
|
||||||
}).addTo(targetLayer).bindPopup(popup)
|
}).addTo(targetLayer).bindPopup(popup)
|
||||||
.on('dragend', function(e){ updateMarkerCoord(s.id, 'spbu', e.target.getLatLng()); });
|
.on('dragend', function (e) { updateMarkerCoord(s.id, 'spbu', e.target.getLatLng()); });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +482,7 @@ function renderMap(data) {
|
|||||||
data.warga.forEach(w => {
|
data.warga.forEach(w => {
|
||||||
var pos = L.latLng(w.latitude, w.longitude);
|
var pos = L.latLng(w.latitude, w.longitude);
|
||||||
var isCovered = lokMasjid.some(m => pos.distanceTo(m) <= currentRadius);
|
var isCovered = lokMasjid.some(m => pos.distanceTo(m) <= currentRadius);
|
||||||
|
|
||||||
// Buat elemen point berbentuk map pin (teardrop) dengan ikon rumah di dalamnya
|
// Buat elemen point berbentuk map pin (teardrop) dengan ikon rumah di dalamnya
|
||||||
var color = isCovered ? '#16a34a' : '#ef4444'; // Hijau aman, merah di luar
|
var color = isCovered ? '#16a34a' : '#ef4444'; // Hijau aman, merah di luar
|
||||||
var houseIcon = L.divIcon({
|
var houseIcon = L.divIcon({
|
||||||
@@ -521,7 +521,7 @@ function renderMap(data) {
|
|||||||
iconAnchor: [15, 36], // Titik jangkar di ujung bawah pin
|
iconAnchor: [15, 36], // Titik jangkar di ujung bawah pin
|
||||||
popupAnchor: [0, -36]
|
popupAnchor: [0, -36]
|
||||||
});
|
});
|
||||||
|
|
||||||
var isPenerima = (w.histori_bantuan && w.histori_bantuan.trim().length > 0) ? 'Ya' : 'Belum';
|
var isPenerima = (w.histori_bantuan && w.histori_bantuan.trim().length > 0) ? 'Ya' : 'Belum';
|
||||||
var txtPendidikan = w.pendidikan ? w.pendidikan : 'Tidak diketahui';
|
var txtPendidikan = w.pendidikan ? w.pendidikan : 'Tidak diketahui';
|
||||||
var txtPenyakit = (w.riwayat_penyakit && w.riwayat_penyakit.trim().length > 0) ? w.riwayat_penyakit : 'Tidak ada';
|
var txtPenyakit = (w.riwayat_penyakit && w.riwayat_penyakit.trim().length > 0) ? w.riwayat_penyakit : 'Tidak ada';
|
||||||
@@ -546,8 +546,8 @@ function renderMap(data) {
|
|||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
L.marker(pos, { icon: houseIcon, draggable: true })
|
L.marker(pos, { icon: houseIcon, draggable: true })
|
||||||
.addTo(layerWarga).bindPopup(popup)
|
.addTo(layerWarga).bindPopup(popup)
|
||||||
.on('dragend', function(e){ updateMarkerCoord(w.id, 'warga', e.target.getLatLng()); });
|
.on('dragend', function (e) { updateMarkerCoord(w.id, 'warga', e.target.getLatLng()); });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,16 +556,16 @@ function renderMap(data) {
|
|||||||
data.jalan.forEach(j => {
|
data.jalan.forEach(j => {
|
||||||
var coords = JSON.parse(j.koordinat);
|
var coords = JSON.parse(j.koordinat);
|
||||||
var color = '#ef4444'; // default red
|
var color = '#ef4444'; // default red
|
||||||
if(j.status_jalan === 'Nasional') color = '#ef4444'; // Merah
|
if (j.status_jalan === 'Nasional') color = '#ef4444'; // Merah
|
||||||
else if(j.status_jalan === 'Provinsi') color = '#eab308'; // Kuning
|
else if (j.status_jalan === 'Provinsi') color = '#eab308'; // Kuning
|
||||||
else if(j.status_jalan === 'Kabupaten') color = '#22c55e'; // Hijau
|
else if (j.status_jalan === 'Kabupaten') color = '#22c55e'; // Hijau
|
||||||
|
|
||||||
var popup = `<b>🛣️ ${j.nama_jalan}</b><br>Status: ${j.status_jalan}<br>Panjang: ${j.panjang_m} meter<br>
|
var popup = `<b>🛣️ ${j.nama_jalan}</b><br>Status: ${j.status_jalan}<br>Panjang: ${j.panjang_m} meter<br>
|
||||||
<div style="margin-top:10px; text-align:center;">
|
<div style="margin-top:10px; text-align:center;">
|
||||||
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('jalan', ${j.id})">Edit</button>
|
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('jalan', ${j.id})">Edit</button>
|
||||||
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${j.id}, 'jalan')">Hapus</button>
|
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${j.id}, 'jalan')">Hapus</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
var polyline = L.polyline(coords, {color: color, weight: 6}).addTo(layerLines).bindPopup(popup);
|
var polyline = L.polyline(coords, { color: color, weight: 6 }).addTo(layerLines).bindPopup(popup);
|
||||||
polyline.db_id = j.id;
|
polyline.db_id = j.id;
|
||||||
polyline.db_tipe = 'jalan';
|
polyline.db_tipe = 'jalan';
|
||||||
drawnItems.addLayer(polyline);
|
drawnItems.addLayer(polyline);
|
||||||
@@ -579,7 +579,7 @@ function renderMap(data) {
|
|||||||
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('parsil', ${p.id})">Edit</button>
|
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('parsil', ${p.id})">Edit</button>
|
||||||
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${p.id}, 'parsil')">Hapus</button>
|
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${p.id}, 'parsil')">Hapus</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
var polygon = L.polygon(coords, {color: '#2563eb', fillOpacity: 0.4}).addTo(layerPolygons).bindPopup(popup);
|
var polygon = L.polygon(coords, { color: '#2563eb', fillOpacity: 0.4 }).addTo(layerPolygons).bindPopup(popup);
|
||||||
polygon.db_id = p.id;
|
polygon.db_id = p.id;
|
||||||
polygon.db_tipe = 'parsil';
|
polygon.db_tipe = 'parsil';
|
||||||
drawnItems.addLayer(polygon);
|
drawnItems.addLayer(polygon);
|
||||||
@@ -622,12 +622,12 @@ function simpanData() {
|
|||||||
fd.append('status_hak', document.getElementById('status_hak').value);
|
fd.append('status_hak', document.getElementById('status_hak').value);
|
||||||
fd.append('koordinat', document.getElementById('parsil_coords').value);
|
fd.append('koordinat', document.getElementById('parsil_coords').value);
|
||||||
} else {
|
} else {
|
||||||
if(j !== 'geometri' && (!lat || !lng) && document.getElementById('edit_id').value === "0") {
|
if (j !== 'geometri' && (!lat || !lng) && document.getElementById('edit_id').value === "0") {
|
||||||
Swal.fire({icon: 'warning', title: 'Oops...', text: 'Silakan klik titik koordinat di peta terlebih dahulu!'});
|
Swal.fire({ icon: 'warning', title: 'Oops...', text: 'Silakan klik titik koordinat di peta terlebih dahulu!' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fd.append('lat', lat); fd.append('lng', lng);
|
fd.append('lat', lat); fd.append('lng', lng);
|
||||||
|
|
||||||
if (j === 'pelaporan') {
|
if (j === 'pelaporan') {
|
||||||
fd.append('nama', document.getElementById('nama_pelapor').value);
|
fd.append('nama', document.getElementById('nama_pelapor').value);
|
||||||
fd.append('laporan', document.getElementById('isi_laporan').value);
|
fd.append('laporan', document.getElementById('isi_laporan').value);
|
||||||
@@ -651,15 +651,15 @@ function simpanData() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Swal.fire({ title: 'Menyimpan...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() }});
|
Swal.fire({ title: 'Menyimpan...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() } });
|
||||||
fetch('../api/api.php', { method: 'POST', body: fd })
|
fetch('../api/api.php', { method: 'POST', body: fd })
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === 'error') {
|
if (res.status === 'error') {
|
||||||
Swal.fire('Gagal!', res.message, 'error');
|
Swal.fire('Gagal!', res.message, 'error');
|
||||||
} else {
|
} else {
|
||||||
Swal.fire({icon: 'success', title: 'Berhasil', text: 'Data berhasil disimpan!', timer: 1500, showConfirmButton: false})
|
Swal.fire({ icon: 'success', title: 'Berhasil', text: 'Data berhasil disimpan!', timer: 1500, showConfirmButton: false })
|
||||||
.then(() => location.reload());
|
.then(() => location.reload());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -670,7 +670,7 @@ function hapusData(id, tipe) {
|
|||||||
showCancelButton: true, confirmButtonColor: '#ef4444', cancelButtonColor: '#94a3b8', confirmButtonText: 'Ya, Hapus!'
|
showCancelButton: true, confirmButtonColor: '#ef4444', cancelButtonColor: '#94a3b8', confirmButtonText: 'Ya, Hapus!'
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
Swal.fire({ title: 'Menghapus...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() }});
|
Swal.fire({ title: 'Menghapus...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() } });
|
||||||
var fd = new FormData();
|
var fd = new FormData();
|
||||||
fd.append('action', 'hapus_data');
|
fd.append('action', 'hapus_data');
|
||||||
fd.append('id', id);
|
fd.append('id', id);
|
||||||
@@ -700,16 +700,16 @@ function batalEdit() {
|
|||||||
|
|
||||||
function editData(tipe, id) {
|
function editData(tipe, id) {
|
||||||
var item = cachedData[tipe].find(x => x.id == id);
|
var item = cachedData[tipe].find(x => x.id == id);
|
||||||
if(!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
document.getElementById('edit_id').value = id;
|
document.getElementById('edit_id').value = id;
|
||||||
document.getElementById('jenis').value = tipe;
|
document.getElementById('jenis').value = tipe;
|
||||||
toggleForm();
|
toggleForm();
|
||||||
|
|
||||||
var panel = document.getElementById('panelInput');
|
|
||||||
if(panel) panel.classList.remove('collapsed');
|
|
||||||
|
|
||||||
if(tipe == 'warga') {
|
var panel = document.getElementById('panelInput');
|
||||||
|
if (panel) panel.classList.remove('collapsed');
|
||||||
|
|
||||||
|
if (tipe == 'warga') {
|
||||||
document.getElementById('nama_kk').value = item.nama;
|
document.getElementById('nama_kk').value = item.nama;
|
||||||
document.getElementById('jumlah_kk').value = item.jumlah_kk;
|
document.getElementById('jumlah_kk').value = item.jumlah_kk;
|
||||||
document.getElementById('tanggal_lahir').value = item.tanggal_lahir || '';
|
document.getElementById('tanggal_lahir').value = item.tanggal_lahir || '';
|
||||||
@@ -739,7 +739,7 @@ function editData(tipe, id) {
|
|||||||
document.getElementById('parsil_coords').value = item.koordinat;
|
document.getElementById('parsil_coords').value = item.koordinat;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(item.latitude && item.longitude) {
|
if (item.latitude && item.longitude) {
|
||||||
document.getElementById('lat').value = item.latitude;
|
document.getElementById('lat').value = item.latitude;
|
||||||
document.getElementById('lng').value = item.longitude;
|
document.getElementById('lng').value = item.longitude;
|
||||||
fokus(item.latitude, item.longitude);
|
fokus(item.latitude, item.longitude);
|
||||||
@@ -762,10 +762,10 @@ function updateMarkerCoord(id, tipe, latlng) {
|
|||||||
fetch('../api/api.php', { method: 'POST', body: fd })
|
fetch('../api/api.php', { method: 'POST', body: fd })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
icon: 'success',
|
icon: 'success',
|
||||||
title: 'Tersimpan',
|
title: 'Tersimpan',
|
||||||
text: 'Posisi titik berhasil digeser!',
|
text: 'Posisi titik berhasil digeser!',
|
||||||
timer: 1500,
|
timer: 1500,
|
||||||
showConfirmButton: false,
|
showConfirmButton: false,
|
||||||
toast: true,
|
toast: true,
|
||||||
position: 'top-end'
|
position: 'top-end'
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
session_set_cookie_params(['path' => '/']);
|
||||||
session_start();
|
session_start();
|
||||||
$role = $_SESSION['role'] ?? null;
|
$role = $_SESSION['role'] ?? null;
|
||||||
$is_logged_in = isset($_SESSION['login']);
|
$is_logged_in = isset($_SESSION['login']);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
session_set_cookie_params(['path' => '/']);
|
||||||
session_start();
|
session_start();
|
||||||
require_once '../api/db.php';
|
require_once '../api/db.php';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
session_set_cookie_params(['path' => '/']);
|
||||||
session_start();
|
session_start();
|
||||||
session_unset();
|
session_unset();
|
||||||
session_destroy();
|
session_destroy();
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
session_set_cookie_params(['path' => '/']);
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
require_once '../api/db.php';
|
require_once '../api/db.php';
|
||||||
|
|||||||
+68
-68
@@ -36,9 +36,9 @@ var currentRadius = 500;
|
|||||||
var cachedData = null;
|
var cachedData = null;
|
||||||
|
|
||||||
var drawControl = new L.Control.Draw({
|
var drawControl = new L.Control.Draw({
|
||||||
draw: {
|
draw: {
|
||||||
marker:false, circle:false, circlemarker:false,
|
marker: false, circle: false, circlemarker: false,
|
||||||
polyline: { shapeOptions: { color: 'blue', weight: 4 } },
|
polyline: { shapeOptions: { color: 'blue', weight: 4 } },
|
||||||
polygon: { shapeOptions: { color: 'red' } },
|
polygon: { shapeOptions: { color: 'red' } },
|
||||||
rectangle: false
|
rectangle: false
|
||||||
},
|
},
|
||||||
@@ -47,7 +47,7 @@ var drawControl = new L.Control.Draw({
|
|||||||
map.addControl(drawControl);
|
map.addControl(drawControl);
|
||||||
|
|
||||||
// Locate Control
|
// Locate Control
|
||||||
var locateBtn = L.control({position: 'topleft'});
|
var locateBtn = L.control({ position: 'topleft' });
|
||||||
locateBtn.onAdd = function (map) {
|
locateBtn.onAdd = function (map) {
|
||||||
var div = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
|
var div = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
|
||||||
div.style.backgroundColor = 'white';
|
div.style.backgroundColor = 'white';
|
||||||
@@ -59,13 +59,13 @@ locateBtn.onAdd = function (map) {
|
|||||||
div.style.justifyContent = 'center';
|
div.style.justifyContent = 'center';
|
||||||
div.innerHTML = '<i class="fas fa-crosshairs" style="font-size:1.2rem; color:#2563eb;"></i>';
|
div.innerHTML = '<i class="fas fa-crosshairs" style="font-size:1.2rem; color:#2563eb;"></i>';
|
||||||
div.title = "Lokasi Anda Saat Ini";
|
div.title = "Lokasi Anda Saat Ini";
|
||||||
div.onclick = function(){ map.locate({setView: true, maxZoom: 16}); }
|
div.onclick = function () { map.locate({ setView: true, maxZoom: 16 }); }
|
||||||
return div;
|
return div;
|
||||||
};
|
};
|
||||||
locateBtn.addTo(map);
|
locateBtn.addTo(map);
|
||||||
|
|
||||||
map.on('locationfound', function(e) {
|
map.on('locationfound', function (e) {
|
||||||
L.circleMarker(e.latlng, {radius: 8, fillColor: '#3b82f6', color: '#fff', weight: 3, fillOpacity: 1}).addTo(map).bindPopup("Lokasi Anda").openPopup();
|
L.circleMarker(e.latlng, { radius: 8, fillColor: '#3b82f6', color: '#fff', weight: 3, fillOpacity: 1 }).addTo(map).bindPopup("Lokasi Anda").openPopup();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Event Draw
|
// Event Draw
|
||||||
@@ -80,21 +80,21 @@ map.on(L.Draw.Event.CREATED, function (e) {
|
|||||||
if (type === 'polyline') {
|
if (type === 'polyline') {
|
||||||
document.getElementById('jenis').value = 'jalan';
|
document.getElementById('jenis').value = 'jalan';
|
||||||
toggleForm();
|
toggleForm();
|
||||||
|
|
||||||
var coords = layer.getLatLngs();
|
var coords = layer.getLatLngs();
|
||||||
document.getElementById('jalan_coords').value = JSON.stringify(coords);
|
document.getElementById('jalan_coords').value = JSON.stringify(coords);
|
||||||
|
|
||||||
// Calculate Length automatically
|
// Calculate Length automatically
|
||||||
var length = 0;
|
var length = 0;
|
||||||
for (var i = 0; i < coords.length - 1; i++) {
|
for (var i = 0; i < coords.length - 1; i++) {
|
||||||
length += coords[i].distanceTo(coords[i + 1]);
|
length += coords[i].distanceTo(coords[i + 1]);
|
||||||
}
|
}
|
||||||
document.getElementById('panjang_jalan').value = length.toFixed(2);
|
document.getElementById('panjang_jalan').value = length.toFixed(2);
|
||||||
|
|
||||||
} else if (type === 'polygon') {
|
} else if (type === 'polygon') {
|
||||||
document.getElementById('jenis').value = 'parsil';
|
document.getElementById('jenis').value = 'parsil';
|
||||||
toggleForm();
|
toggleForm();
|
||||||
|
|
||||||
var coords = layer.getLatLngs()[0];
|
var coords = layer.getLatLngs()[0];
|
||||||
document.getElementById('parsil_coords').value = JSON.stringify(coords);
|
document.getElementById('parsil_coords').value = JSON.stringify(coords);
|
||||||
}
|
}
|
||||||
@@ -103,15 +103,15 @@ map.on(L.Draw.Event.CREATED, function (e) {
|
|||||||
map.on(L.Draw.Event.EDITED, function (e) {
|
map.on(L.Draw.Event.EDITED, function (e) {
|
||||||
var layers = e.layers;
|
var layers = e.layers;
|
||||||
layers.eachLayer(function (layer) {
|
layers.eachLayer(function (layer) {
|
||||||
if(layer.db_id && layer.db_tipe) {
|
if (layer.db_id && layer.db_tipe) {
|
||||||
var coords = (layer.db_tipe === 'parsil') ? layer.getLatLngs()[0] : layer.getLatLngs();
|
var coords = (layer.db_tipe === 'parsil') ? layer.getLatLngs()[0] : layer.getLatLngs();
|
||||||
var fd = new FormData();
|
var fd = new FormData();
|
||||||
fd.append('action', 'update_koordinat');
|
fd.append('action', 'update_koordinat');
|
||||||
fd.append('id', layer.db_id);
|
fd.append('id', layer.db_id);
|
||||||
fd.append('tipe', layer.db_tipe);
|
fd.append('tipe', layer.db_tipe);
|
||||||
fd.append('koordinat', JSON.stringify(coords));
|
fd.append('koordinat', JSON.stringify(coords));
|
||||||
|
|
||||||
if(layer.db_tipe === 'jalan') {
|
if (layer.db_tipe === 'jalan') {
|
||||||
var length = 0;
|
var length = 0;
|
||||||
for (var i = 0; i < coords.length - 1; i++) {
|
for (var i = 0; i < coords.length - 1; i++) {
|
||||||
length += coords[i].distanceTo(coords[i + 1]);
|
length += coords[i].distanceTo(coords[i + 1]);
|
||||||
@@ -121,13 +121,13 @@ map.on(L.Draw.Event.EDITED, function (e) {
|
|||||||
fetch('../api/api.php', { method: 'POST', body: fd });
|
fetch('../api/api.php', { method: 'POST', body: fd });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Swal.fire({icon: 'success', title: 'Tersimpan', text: 'Perubahan bentuk berhasil disimpan!', timer: 1500, showConfirmButton: false});
|
Swal.fire({ icon: 'success', title: 'Tersimpan', text: 'Perubahan bentuk berhasil disimpan!', timer: 1500, showConfirmButton: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
map.on(L.Draw.Event.DELETED, function (e) {
|
map.on(L.Draw.Event.DELETED, function (e) {
|
||||||
var layers = e.layers;
|
var layers = e.layers;
|
||||||
layers.eachLayer(function (layer) {
|
layers.eachLayer(function (layer) {
|
||||||
if(layer.db_id && layer.db_tipe) {
|
if (layer.db_id && layer.db_tipe) {
|
||||||
var fd = new FormData();
|
var fd = new FormData();
|
||||||
fd.append('action', 'hapus_data');
|
fd.append('action', 'hapus_data');
|
||||||
fd.append('id', layer.db_id);
|
fd.append('id', layer.db_id);
|
||||||
@@ -135,20 +135,20 @@ map.on(L.Draw.Event.DELETED, function (e) {
|
|||||||
fetch('../api/api.php', { method: 'POST', body: fd });
|
fetch('../api/api.php', { method: 'POST', body: fd });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Swal.fire({icon: 'success', title: 'Terhapus', text: 'Data berhasil dihapus dari peta!', timer: 1500, showConfirmButton: false});
|
Swal.fire({ icon: 'success', title: 'Terhapus', text: 'Data berhasil dihapus dari peta!', timer: 1500, showConfirmButton: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggleSidebar() { document.getElementById('sidebar').classList.toggle('active'); }
|
function toggleSidebar() { document.getElementById('sidebar').classList.toggle('active'); }
|
||||||
|
|
||||||
function toggleRightPanel() {
|
function toggleRightPanel() {
|
||||||
var panel = document.getElementById('panelInput');
|
var panel = document.getElementById('panelInput');
|
||||||
if(panel) panel.classList.toggle('collapsed');
|
if (panel) panel.classList.toggle('collapsed');
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterData() {
|
function filterData() {
|
||||||
var input = document.getElementById('searchInput').value.toLowerCase();
|
var input = document.getElementById('searchInput').value.toLowerCase();
|
||||||
var cards = document.getElementsByClassName('item-data');
|
var cards = document.getElementsByClassName('item-data');
|
||||||
if(input.length > 0) document.getElementById('sidebar').classList.add('active');
|
if (input.length > 0) document.getElementById('sidebar').classList.add('active');
|
||||||
for (var i = 0; i < cards.length; i++) {
|
for (var i = 0; i < cards.length; i++) {
|
||||||
cards[i].style.display = cards[i].getAttribute('data-nama').includes(input) ? "" : "none";
|
cards[i].style.display = cards[i].getAttribute('data-nama').includes(input) ? "" : "none";
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ function filterData() {
|
|||||||
function changeRadius(v) {
|
function changeRadius(v) {
|
||||||
currentRadius = parseInt(v);
|
currentRadius = parseInt(v);
|
||||||
document.getElementById('radiusVal').innerText = v;
|
document.getElementById('radiusVal').innerText = v;
|
||||||
if(cachedData) {
|
if (cachedData) {
|
||||||
renderMap(cachedData);
|
renderMap(cachedData);
|
||||||
renderSidebar(cachedData);
|
renderSidebar(cachedData);
|
||||||
}
|
}
|
||||||
@@ -169,7 +169,7 @@ function loadData(isPolling = false) {
|
|||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
cachedData = data;
|
cachedData = data;
|
||||||
|
|
||||||
// Logika Notifikasi Bubble
|
// Logika Notifikasi Bubble
|
||||||
if (prevReportCount !== -1 && data.pelaporan.length > prevReportCount) {
|
if (prevReportCount !== -1 && data.pelaporan.length > prevReportCount) {
|
||||||
var newCount = data.pelaporan.length - prevReportCount;
|
var newCount = data.pelaporan.length - prevReportCount;
|
||||||
@@ -184,10 +184,10 @@ function loadData(isPolling = false) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
prevReportCount = data.pelaporan.length;
|
prevReportCount = data.pelaporan.length;
|
||||||
|
|
||||||
var badge = document.getElementById('notifBadge');
|
var badge = document.getElementById('notifBadge');
|
||||||
if(badge) {
|
if (badge) {
|
||||||
if(data.pelaporan.length > 0) {
|
if (data.pelaporan.length > 0) {
|
||||||
badge.style.display = 'block';
|
badge.style.display = 'block';
|
||||||
badge.innerText = data.pelaporan.length;
|
badge.innerText = data.pelaporan.length;
|
||||||
} else {
|
} else {
|
||||||
@@ -211,7 +211,7 @@ function loadData(isPolling = false) {
|
|||||||
// Auto-poll every 10 seconds
|
// Auto-poll every 10 seconds
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
// Only poll if not currently editing (edit_id is 0)
|
// Only poll if not currently editing (edit_id is 0)
|
||||||
if(document.getElementById('edit_id') && document.getElementById('edit_id').value === "0") {
|
if (document.getElementById('edit_id') && document.getElementById('edit_id').value === "0") {
|
||||||
loadData(true);
|
loadData(true);
|
||||||
}
|
}
|
||||||
}, 10000);
|
}, 10000);
|
||||||
@@ -241,12 +241,12 @@ function renderSidebar(data) {
|
|||||||
if (!window.dashboardType || window.dashboardType === 'sosial' || window.dashboardType === 'admin') {
|
if (!window.dashboardType || window.dashboardType === 'sosial' || window.dashboardType === 'admin') {
|
||||||
// Pelaporan
|
// Pelaporan
|
||||||
html += `<div class="section-title" style="color:#ef4444">🚨 Laporan Darurat</div>`;
|
html += `<div class="section-title" style="color:#ef4444">🚨 Laporan Darurat</div>`;
|
||||||
if(data.pelaporan.length === 0) html += `<small style="color:#666">Belum ada laporan</small>`;
|
if (data.pelaporan.length === 0) html += `<small style="color:#666">Belum ada laporan</small>`;
|
||||||
data.pelaporan.forEach(p => {
|
data.pelaporan.forEach(p => {
|
||||||
html += `<div class="card item-data" data-nama="${p.nama_pelapor.toLowerCase()} ${p.isi_laporan.toLowerCase()}">
|
html += `<div class="card item-data" data-nama="${p.nama_pelapor.toLowerCase()} ${p.isi_laporan.toLowerCase()}">
|
||||||
<div style="display:flex; justify-content:space-between">
|
<div style="display:flex; justify-content:space-between">
|
||||||
<span onclick="fokus(${p.latitude}, ${p.longitude})" style="cursor:pointer">
|
<span onclick="fokus(${p.latitude}, ${p.longitude})" style="cursor:pointer">
|
||||||
<b>${p.nama_pelapor}</b><small><i class="far fa-clock"></i> ${p.waktu}</small><br><span>${p.isi_laporan.substring(0,40)}...</span>
|
<b>${p.nama_pelapor}</b><small><i class="far fa-clock"></i> ${p.waktu}</small><br><span>${p.isi_laporan.substring(0, 40)}...</span>
|
||||||
</span>
|
</span>
|
||||||
<div>
|
<div>
|
||||||
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-bottom:5px;" onclick="editData('pelaporan', ${p.id})">Edit</button><br>
|
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-bottom:5px;" onclick="editData('pelaporan', ${p.id})">Edit</button><br>
|
||||||
@@ -262,8 +262,8 @@ function renderSidebar(data) {
|
|||||||
var pos = L.latLng(w.latitude, w.longitude);
|
var pos = L.latLng(w.latitude, w.longitude);
|
||||||
var nearbyFacilities = data.masjid.map(m => {
|
var nearbyFacilities = data.masjid.map(m => {
|
||||||
return { nama: m.nama, distance: pos.distanceTo(L.latLng(m.latitude, m.longitude)) };
|
return { nama: m.nama, distance: pos.distanceTo(L.latLng(m.latitude, m.longitude)) };
|
||||||
}).filter(f => f.distance <= currentRadius).sort((a,b) => a.distance - b.distance);
|
}).filter(f => f.distance <= currentRadius).sort((a, b) => a.distance - b.distance);
|
||||||
|
|
||||||
var facilityInfo = nearbyFacilities.length > 0 ? `<br><small style="color:#16a34a"><i class="fas fa-check-circle"></i> Jangkauan: ${nearbyFacilities[0].nama} (${Math.round(nearbyFacilities[0].distance)}m)</small>` : `<br><small style="color:#ef4444"><i class="fas fa-exclamation-triangle"></i> Jauh dari fasilitas / bantuan</small>`;
|
var facilityInfo = nearbyFacilities.length > 0 ? `<br><small style="color:#16a34a"><i class="fas fa-check-circle"></i> Jangkauan: ${nearbyFacilities[0].nama} (${Math.round(nearbyFacilities[0].distance)}m)</small>` : `<br><small style="color:#ef4444"><i class="fas fa-exclamation-triangle"></i> Jauh dari fasilitas / bantuan</small>`;
|
||||||
|
|
||||||
html += `<div class="card item-data" data-nama="${w.nama.toLowerCase()}">
|
html += `<div class="card item-data" data-nama="${w.nama.toLowerCase()}">
|
||||||
@@ -324,9 +324,9 @@ function renderSidebar(data) {
|
|||||||
html += `<div class="section-title">🛣️ Manajemen Jalan</div>`;
|
html += `<div class="section-title">🛣️ Manajemen Jalan</div>`;
|
||||||
data.jalan.forEach(j => {
|
data.jalan.forEach(j => {
|
||||||
var color = '#ef4444'; // default red
|
var color = '#ef4444'; // default red
|
||||||
if(j.status_jalan === 'Nasional') color = '#ef4444';
|
if (j.status_jalan === 'Nasional') color = '#ef4444';
|
||||||
else if(j.status_jalan === 'Provinsi') color = '#eab308';
|
else if (j.status_jalan === 'Provinsi') color = '#eab308';
|
||||||
else if(j.status_jalan === 'Kabupaten') color = '#22c55e';
|
else if (j.status_jalan === 'Kabupaten') color = '#22c55e';
|
||||||
html += `<div class="card item-data" data-nama="${j.nama_jalan.toLowerCase()}">
|
html += `<div class="card item-data" data-nama="${j.nama_jalan.toLowerCase()}">
|
||||||
<div style="display:flex; justify-content:space-between">
|
<div style="display:flex; justify-content:space-between">
|
||||||
<span>
|
<span>
|
||||||
@@ -384,10 +384,10 @@ function renderMap(data) {
|
|||||||
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${m.id}, 'masjid')">Hapus</button>
|
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${m.id}, 'masjid')">Hapus</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
var faClass = 'fa-mosque';
|
var faClass = 'fa-mosque';
|
||||||
if(m.jenis === 'Gereja') faClass = 'fa-church';
|
if (m.jenis === 'Gereja') faClass = 'fa-church';
|
||||||
else if(m.jenis === 'Vihara') faClass = 'fa-vihara';
|
else if (m.jenis === 'Vihara') faClass = 'fa-vihara';
|
||||||
else if(m.jenis === 'Pura') faClass = 'fa-torii-gate';
|
else if (m.jenis === 'Pura') faClass = 'fa-torii-gate';
|
||||||
|
|
||||||
// Buat custom marker bentuk map pin dengan icon sesuai jenis
|
// Buat custom marker bentuk map pin dengan icon sesuai jenis
|
||||||
var masjidIcon = L.divIcon({
|
var masjidIcon = L.divIcon({
|
||||||
html: `
|
html: `
|
||||||
@@ -419,7 +419,7 @@ function renderMap(data) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
L.marker([m.latitude, m.longitude], { icon: masjidIcon, draggable: true }).addTo(layerMasjid).bindPopup(popup)
|
L.marker([m.latitude, m.longitude], { icon: masjidIcon, draggable: true }).addTo(layerMasjid).bindPopup(popup)
|
||||||
.on('dragend', function(e){ updateMarkerCoord(m.id, 'masjid', e.target.getLatLng()); });
|
.on('dragend', function (e) { updateMarkerCoord(m.id, 'masjid', e.target.getLatLng()); });
|
||||||
L.circle([m.latitude, m.longitude], {
|
L.circle([m.latitude, m.longitude], {
|
||||||
radius: currentRadius, color: '#2563eb', fillOpacity: 0.1, weight: 1
|
radius: currentRadius, color: '#2563eb', fillOpacity: 0.1, weight: 1
|
||||||
}).addTo(layerMasjidRadius);
|
}).addTo(layerMasjidRadius);
|
||||||
@@ -465,7 +465,7 @@ function renderMap(data) {
|
|||||||
L.marker([p.latitude, p.longitude], {
|
L.marker([p.latitude, p.longitude], {
|
||||||
icon: pelaporanIcon, draggable: true
|
icon: pelaporanIcon, draggable: true
|
||||||
}).addTo(layerPelaporan).bindPopup(popup)
|
}).addTo(layerPelaporan).bindPopup(popup)
|
||||||
.on('dragend', function(e){ updateMarkerCoord(p.id, 'pelaporan', e.target.getLatLng()); });
|
.on('dragend', function (e) { updateMarkerCoord(p.id, 'pelaporan', e.target.getLatLng()); });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,7 +475,7 @@ function renderMap(data) {
|
|||||||
var is24 = s.kategori === '24jam';
|
var is24 = s.kategori === '24jam';
|
||||||
var iconUrl = is24 ? 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png' : 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png';
|
var iconUrl = is24 ? 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png' : 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png';
|
||||||
var targetLayer = is24 ? layerSpbu24 : layerSpbuNon24;
|
var targetLayer = is24 ? layerSpbu24 : layerSpbuNon24;
|
||||||
|
|
||||||
var popup = `<b>⛽ ${s.nama}</b><br>Kategori: ${s.kategori === '24jam' ? 'Buka 24 Jam' : 'Tidak 24 Jam'}<br>
|
var popup = `<b>⛽ ${s.nama}</b><br>Kategori: ${s.kategori === '24jam' ? 'Buka 24 Jam' : 'Tidak 24 Jam'}<br>
|
||||||
<div style="margin-top:10px; text-align:center;">
|
<div style="margin-top:10px; text-align:center;">
|
||||||
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('spbu', ${s.id})">Edit</button>
|
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('spbu', ${s.id})">Edit</button>
|
||||||
@@ -484,7 +484,7 @@ function renderMap(data) {
|
|||||||
L.marker([s.latitude, s.longitude], {
|
L.marker([s.latitude, s.longitude], {
|
||||||
icon: L.icon({ iconUrl: iconUrl, iconSize: [25, 41], iconAnchor: [12, 41] }), draggable: true
|
icon: L.icon({ iconUrl: iconUrl, iconSize: [25, 41], iconAnchor: [12, 41] }), draggable: true
|
||||||
}).addTo(targetLayer).bindPopup(popup)
|
}).addTo(targetLayer).bindPopup(popup)
|
||||||
.on('dragend', function(e){ updateMarkerCoord(s.id, 'spbu', e.target.getLatLng()); });
|
.on('dragend', function (e) { updateMarkerCoord(s.id, 'spbu', e.target.getLatLng()); });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -494,11 +494,11 @@ function renderMap(data) {
|
|||||||
var pos = L.latLng(w.latitude, w.longitude);
|
var pos = L.latLng(w.latitude, w.longitude);
|
||||||
var nearbyFacilities = data.masjid.map(m => {
|
var nearbyFacilities = data.masjid.map(m => {
|
||||||
return { nama: m.nama, distance: pos.distanceTo(L.latLng(m.latitude, m.longitude)) };
|
return { nama: m.nama, distance: pos.distanceTo(L.latLng(m.latitude, m.longitude)) };
|
||||||
}).filter(f => f.distance <= currentRadius).sort((a,b) => a.distance - b.distance);
|
}).filter(f => f.distance <= currentRadius).sort((a, b) => a.distance - b.distance);
|
||||||
var isCovered = nearbyFacilities.length > 0;
|
var isCovered = nearbyFacilities.length > 0;
|
||||||
var nearestName = isCovered ? nearbyFacilities[0].nama : '-';
|
var nearestName = isCovered ? nearbyFacilities[0].nama : '-';
|
||||||
var nearestDist = isCovered ? Math.round(nearbyFacilities[0].distance) + 'm' : '-';
|
var nearestDist = isCovered ? Math.round(nearbyFacilities[0].distance) + 'm' : '-';
|
||||||
|
|
||||||
// Buat elemen point berbentuk map pin (teardrop) dengan ikon rumah di dalamnya
|
// Buat elemen point berbentuk map pin (teardrop) dengan ikon rumah di dalamnya
|
||||||
var color = isCovered ? '#16a34a' : '#ef4444'; // Hijau aman, merah di luar
|
var color = isCovered ? '#16a34a' : '#ef4444'; // Hijau aman, merah di luar
|
||||||
var houseIcon = L.divIcon({
|
var houseIcon = L.divIcon({
|
||||||
@@ -537,7 +537,7 @@ function renderMap(data) {
|
|||||||
iconAnchor: [15, 36], // Titik jangkar di ujung bawah pin
|
iconAnchor: [15, 36], // Titik jangkar di ujung bawah pin
|
||||||
popupAnchor: [0, -36]
|
popupAnchor: [0, -36]
|
||||||
});
|
});
|
||||||
|
|
||||||
var isPenerima = (w.status_bantuan === 'Sudah') ? 'Ya' : 'Belum';
|
var isPenerima = (w.status_bantuan === 'Sudah') ? 'Ya' : 'Belum';
|
||||||
var txtPendidikan = w.pendidikan ? w.pendidikan : 'Tidak diketahui';
|
var txtPendidikan = w.pendidikan ? w.pendidikan : 'Tidak diketahui';
|
||||||
var txtPenyakit = (w.riwayat_penyakit && w.riwayat_penyakit.trim().length > 0) ? w.riwayat_penyakit : 'Tidak ada';
|
var txtPenyakit = (w.riwayat_penyakit && w.riwayat_penyakit.trim().length > 0) ? w.riwayat_penyakit : 'Tidak ada';
|
||||||
@@ -563,8 +563,8 @@ function renderMap(data) {
|
|||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
L.marker(pos, { icon: houseIcon, draggable: true })
|
L.marker(pos, { icon: houseIcon, draggable: true })
|
||||||
.addTo(layerWarga).bindPopup(popup)
|
.addTo(layerWarga).bindPopup(popup)
|
||||||
.on('dragend', function(e){ updateMarkerCoord(w.id, 'warga', e.target.getLatLng()); });
|
.on('dragend', function (e) { updateMarkerCoord(w.id, 'warga', e.target.getLatLng()); });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,16 +573,16 @@ function renderMap(data) {
|
|||||||
data.jalan.forEach(j => {
|
data.jalan.forEach(j => {
|
||||||
var coords = JSON.parse(j.koordinat);
|
var coords = JSON.parse(j.koordinat);
|
||||||
var color = '#ef4444'; // default red
|
var color = '#ef4444'; // default red
|
||||||
if(j.status_jalan === 'Nasional') color = '#ef4444'; // Merah
|
if (j.status_jalan === 'Nasional') color = '#ef4444'; // Merah
|
||||||
else if(j.status_jalan === 'Provinsi') color = '#eab308'; // Kuning
|
else if (j.status_jalan === 'Provinsi') color = '#eab308'; // Kuning
|
||||||
else if(j.status_jalan === 'Kabupaten') color = '#22c55e'; // Hijau
|
else if (j.status_jalan === 'Kabupaten') color = '#22c55e'; // Hijau
|
||||||
|
|
||||||
var popup = `<b>🛣️ ${j.nama_jalan}</b><br>Status: ${j.status_jalan}<br>Panjang: ${j.panjang_m} meter<br>
|
var popup = `<b>🛣️ ${j.nama_jalan}</b><br>Status: ${j.status_jalan}<br>Panjang: ${j.panjang_m} meter<br>
|
||||||
<div style="margin-top:10px; text-align:center;">
|
<div style="margin-top:10px; text-align:center;">
|
||||||
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('jalan', ${j.id})">Edit</button>
|
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('jalan', ${j.id})">Edit</button>
|
||||||
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${j.id}, 'jalan')">Hapus</button>
|
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${j.id}, 'jalan')">Hapus</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
var polyline = L.polyline(coords, {color: color, weight: 6}).addTo(layerLines).bindPopup(popup);
|
var polyline = L.polyline(coords, { color: color, weight: 6 }).addTo(layerLines).bindPopup(popup);
|
||||||
polyline.db_id = j.id;
|
polyline.db_id = j.id;
|
||||||
polyline.db_tipe = 'jalan';
|
polyline.db_tipe = 'jalan';
|
||||||
drawnItems.addLayer(polyline);
|
drawnItems.addLayer(polyline);
|
||||||
@@ -596,7 +596,7 @@ function renderMap(data) {
|
|||||||
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('parsil', ${p.id})">Edit</button>
|
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('parsil', ${p.id})">Edit</button>
|
||||||
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${p.id}, 'parsil')">Hapus</button>
|
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${p.id}, 'parsil')">Hapus</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
var polygon = L.polygon(coords, {color: '#2563eb', fillOpacity: 0.4}).addTo(layerPolygons).bindPopup(popup);
|
var polygon = L.polygon(coords, { color: '#2563eb', fillOpacity: 0.4 }).addTo(layerPolygons).bindPopup(popup);
|
||||||
polygon.db_id = p.id;
|
polygon.db_id = p.id;
|
||||||
polygon.db_tipe = 'parsil';
|
polygon.db_tipe = 'parsil';
|
||||||
drawnItems.addLayer(polygon);
|
drawnItems.addLayer(polygon);
|
||||||
@@ -639,12 +639,12 @@ function simpanData() {
|
|||||||
fd.append('status_hak', document.getElementById('status_hak').value);
|
fd.append('status_hak', document.getElementById('status_hak').value);
|
||||||
fd.append('koordinat', document.getElementById('parsil_coords').value);
|
fd.append('koordinat', document.getElementById('parsil_coords').value);
|
||||||
} else {
|
} else {
|
||||||
if(j !== 'geometri' && (!lat || !lng) && document.getElementById('edit_id').value === "0") {
|
if (j !== 'geometri' && (!lat || !lng) && document.getElementById('edit_id').value === "0") {
|
||||||
Swal.fire({icon: 'warning', title: 'Oops...', text: 'Silakan klik titik koordinat di peta terlebih dahulu!'});
|
Swal.fire({ icon: 'warning', title: 'Oops...', text: 'Silakan klik titik koordinat di peta terlebih dahulu!' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fd.append('lat', lat); fd.append('lng', lng);
|
fd.append('lat', lat); fd.append('lng', lng);
|
||||||
|
|
||||||
if (j === 'pelaporan') {
|
if (j === 'pelaporan') {
|
||||||
fd.append('nama', document.getElementById('nama_pelapor').value);
|
fd.append('nama', document.getElementById('nama_pelapor').value);
|
||||||
fd.append('laporan', document.getElementById('isi_laporan').value);
|
fd.append('laporan', document.getElementById('isi_laporan').value);
|
||||||
@@ -669,15 +669,15 @@ function simpanData() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Swal.fire({ title: 'Menyimpan...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() }});
|
Swal.fire({ title: 'Menyimpan...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() } });
|
||||||
fetch('../api/api.php', { method: 'POST', body: fd })
|
fetch('../api/api.php', { method: 'POST', body: fd })
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === 'error') {
|
if (res.status === 'error') {
|
||||||
Swal.fire('Gagal!', res.message, 'error');
|
Swal.fire('Gagal!', res.message, 'error');
|
||||||
} else {
|
} else {
|
||||||
Swal.fire({icon: 'success', title: 'Berhasil', text: 'Data berhasil disimpan!', timer: 1500, showConfirmButton: false})
|
Swal.fire({ icon: 'success', title: 'Berhasil', text: 'Data berhasil disimpan!', timer: 1500, showConfirmButton: false })
|
||||||
.then(() => location.reload());
|
.then(() => location.reload());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -688,7 +688,7 @@ function hapusData(id, tipe) {
|
|||||||
showCancelButton: true, confirmButtonColor: '#ef4444', cancelButtonColor: '#94a3b8', confirmButtonText: 'Ya, Hapus!'
|
showCancelButton: true, confirmButtonColor: '#ef4444', cancelButtonColor: '#94a3b8', confirmButtonText: 'Ya, Hapus!'
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
Swal.fire({ title: 'Menghapus...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() }});
|
Swal.fire({ title: 'Menghapus...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() } });
|
||||||
var fd = new FormData();
|
var fd = new FormData();
|
||||||
fd.append('action', 'hapus_data');
|
fd.append('action', 'hapus_data');
|
||||||
fd.append('id', id);
|
fd.append('id', id);
|
||||||
@@ -718,16 +718,16 @@ function batalEdit() {
|
|||||||
|
|
||||||
function editData(tipe, id) {
|
function editData(tipe, id) {
|
||||||
var item = cachedData[tipe].find(x => x.id == id);
|
var item = cachedData[tipe].find(x => x.id == id);
|
||||||
if(!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
document.getElementById('edit_id').value = id;
|
document.getElementById('edit_id').value = id;
|
||||||
document.getElementById('jenis').value = tipe;
|
document.getElementById('jenis').value = tipe;
|
||||||
toggleForm();
|
toggleForm();
|
||||||
|
|
||||||
var panel = document.getElementById('panelInput');
|
|
||||||
if(panel) panel.classList.remove('collapsed');
|
|
||||||
|
|
||||||
if(tipe == 'warga') {
|
var panel = document.getElementById('panelInput');
|
||||||
|
if (panel) panel.classList.remove('collapsed');
|
||||||
|
|
||||||
|
if (tipe == 'warga') {
|
||||||
document.getElementById('nama_kk').value = item.nama;
|
document.getElementById('nama_kk').value = item.nama;
|
||||||
document.getElementById('jumlah_kk').value = item.jumlah_kk;
|
document.getElementById('jumlah_kk').value = item.jumlah_kk;
|
||||||
document.getElementById('tanggal_lahir').value = item.tanggal_lahir || '';
|
document.getElementById('tanggal_lahir').value = item.tanggal_lahir || '';
|
||||||
@@ -758,7 +758,7 @@ function editData(tipe, id) {
|
|||||||
document.getElementById('parsil_coords').value = item.koordinat;
|
document.getElementById('parsil_coords').value = item.koordinat;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(item.latitude && item.longitude) {
|
if (item.latitude && item.longitude) {
|
||||||
document.getElementById('lat').value = item.latitude;
|
document.getElementById('lat').value = item.latitude;
|
||||||
document.getElementById('lng').value = item.longitude;
|
document.getElementById('lng').value = item.longitude;
|
||||||
fokus(item.latitude, item.longitude);
|
fokus(item.latitude, item.longitude);
|
||||||
@@ -781,10 +781,10 @@ function updateMarkerCoord(id, tipe, latlng) {
|
|||||||
fetch('../api/api.php', { method: 'POST', body: fd })
|
fetch('../api/api.php', { method: 'POST', body: fd })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
icon: 'success',
|
icon: 'success',
|
||||||
title: 'Tersimpan',
|
title: 'Tersimpan',
|
||||||
text: 'Posisi titik berhasil digeser!',
|
text: 'Posisi titik berhasil digeser!',
|
||||||
timer: 1500,
|
timer: 1500,
|
||||||
showConfirmButton: false,
|
showConfirmButton: false,
|
||||||
toast: true,
|
toast: true,
|
||||||
position: 'top-end'
|
position: 'top-end'
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
|
session_set_cookie_params(['path' => '/']);
|
||||||
session_start();
|
session_start();
|
||||||
|
|
||||||
require_once '../api/db.php';
|
require_once '../api/db.php';
|
||||||
|
|||||||
+65
-65
@@ -36,9 +36,9 @@ var currentRadius = 500;
|
|||||||
var cachedData = null;
|
var cachedData = null;
|
||||||
|
|
||||||
var drawControl = new L.Control.Draw({
|
var drawControl = new L.Control.Draw({
|
||||||
draw: {
|
draw: {
|
||||||
marker:false, circle:false, circlemarker:false,
|
marker: false, circle: false, circlemarker: false,
|
||||||
polyline: { shapeOptions: { color: 'blue', weight: 4 } },
|
polyline: { shapeOptions: { color: 'blue', weight: 4 } },
|
||||||
polygon: { shapeOptions: { color: 'red' } },
|
polygon: { shapeOptions: { color: 'red' } },
|
||||||
rectangle: false
|
rectangle: false
|
||||||
},
|
},
|
||||||
@@ -47,7 +47,7 @@ var drawControl = new L.Control.Draw({
|
|||||||
map.addControl(drawControl);
|
map.addControl(drawControl);
|
||||||
|
|
||||||
// Locate Control
|
// Locate Control
|
||||||
var locateBtn = L.control({position: 'topleft'});
|
var locateBtn = L.control({ position: 'topleft' });
|
||||||
locateBtn.onAdd = function (map) {
|
locateBtn.onAdd = function (map) {
|
||||||
var div = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
|
var div = L.DomUtil.create('div', 'leaflet-bar leaflet-control');
|
||||||
div.style.backgroundColor = 'white';
|
div.style.backgroundColor = 'white';
|
||||||
@@ -59,13 +59,13 @@ locateBtn.onAdd = function (map) {
|
|||||||
div.style.justifyContent = 'center';
|
div.style.justifyContent = 'center';
|
||||||
div.innerHTML = '<i class="fas fa-crosshairs" style="font-size:1.2rem; color:#2563eb;"></i>';
|
div.innerHTML = '<i class="fas fa-crosshairs" style="font-size:1.2rem; color:#2563eb;"></i>';
|
||||||
div.title = "Lokasi Anda Saat Ini";
|
div.title = "Lokasi Anda Saat Ini";
|
||||||
div.onclick = function(){ map.locate({setView: true, maxZoom: 16}); }
|
div.onclick = function () { map.locate({ setView: true, maxZoom: 16 }); }
|
||||||
return div;
|
return div;
|
||||||
};
|
};
|
||||||
locateBtn.addTo(map);
|
locateBtn.addTo(map);
|
||||||
|
|
||||||
map.on('locationfound', function(e) {
|
map.on('locationfound', function (e) {
|
||||||
L.circleMarker(e.latlng, {radius: 8, fillColor: '#3b82f6', color: '#fff', weight: 3, fillOpacity: 1}).addTo(map).bindPopup("Lokasi Anda").openPopup();
|
L.circleMarker(e.latlng, { radius: 8, fillColor: '#3b82f6', color: '#fff', weight: 3, fillOpacity: 1 }).addTo(map).bindPopup("Lokasi Anda").openPopup();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Event Draw
|
// Event Draw
|
||||||
@@ -80,21 +80,21 @@ map.on(L.Draw.Event.CREATED, function (e) {
|
|||||||
if (type === 'polyline') {
|
if (type === 'polyline') {
|
||||||
document.getElementById('jenis').value = 'jalan';
|
document.getElementById('jenis').value = 'jalan';
|
||||||
toggleForm();
|
toggleForm();
|
||||||
|
|
||||||
var coords = layer.getLatLngs();
|
var coords = layer.getLatLngs();
|
||||||
document.getElementById('jalan_coords').value = JSON.stringify(coords);
|
document.getElementById('jalan_coords').value = JSON.stringify(coords);
|
||||||
|
|
||||||
// Calculate Length automatically
|
// Calculate Length automatically
|
||||||
var length = 0;
|
var length = 0;
|
||||||
for (var i = 0; i < coords.length - 1; i++) {
|
for (var i = 0; i < coords.length - 1; i++) {
|
||||||
length += coords[i].distanceTo(coords[i + 1]);
|
length += coords[i].distanceTo(coords[i + 1]);
|
||||||
}
|
}
|
||||||
document.getElementById('panjang_jalan').value = length.toFixed(2);
|
document.getElementById('panjang_jalan').value = length.toFixed(2);
|
||||||
|
|
||||||
} else if (type === 'polygon') {
|
} else if (type === 'polygon') {
|
||||||
document.getElementById('jenis').value = 'parsil';
|
document.getElementById('jenis').value = 'parsil';
|
||||||
toggleForm();
|
toggleForm();
|
||||||
|
|
||||||
var coords = layer.getLatLngs()[0];
|
var coords = layer.getLatLngs()[0];
|
||||||
document.getElementById('parsil_coords').value = JSON.stringify(coords);
|
document.getElementById('parsil_coords').value = JSON.stringify(coords);
|
||||||
}
|
}
|
||||||
@@ -103,15 +103,15 @@ map.on(L.Draw.Event.CREATED, function (e) {
|
|||||||
map.on(L.Draw.Event.EDITED, function (e) {
|
map.on(L.Draw.Event.EDITED, function (e) {
|
||||||
var layers = e.layers;
|
var layers = e.layers;
|
||||||
layers.eachLayer(function (layer) {
|
layers.eachLayer(function (layer) {
|
||||||
if(layer.db_id && layer.db_tipe) {
|
if (layer.db_id && layer.db_tipe) {
|
||||||
var coords = (layer.db_tipe === 'parsil') ? layer.getLatLngs()[0] : layer.getLatLngs();
|
var coords = (layer.db_tipe === 'parsil') ? layer.getLatLngs()[0] : layer.getLatLngs();
|
||||||
var fd = new FormData();
|
var fd = new FormData();
|
||||||
fd.append('action', 'update_koordinat');
|
fd.append('action', 'update_koordinat');
|
||||||
fd.append('id', layer.db_id);
|
fd.append('id', layer.db_id);
|
||||||
fd.append('tipe', layer.db_tipe);
|
fd.append('tipe', layer.db_tipe);
|
||||||
fd.append('koordinat', JSON.stringify(coords));
|
fd.append('koordinat', JSON.stringify(coords));
|
||||||
|
|
||||||
if(layer.db_tipe === 'jalan') {
|
if (layer.db_tipe === 'jalan') {
|
||||||
var length = 0;
|
var length = 0;
|
||||||
for (var i = 0; i < coords.length - 1; i++) {
|
for (var i = 0; i < coords.length - 1; i++) {
|
||||||
length += coords[i].distanceTo(coords[i + 1]);
|
length += coords[i].distanceTo(coords[i + 1]);
|
||||||
@@ -121,13 +121,13 @@ map.on(L.Draw.Event.EDITED, function (e) {
|
|||||||
fetch('../api/api.php', { method: 'POST', body: fd });
|
fetch('../api/api.php', { method: 'POST', body: fd });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Swal.fire({icon: 'success', title: 'Tersimpan', text: 'Perubahan bentuk berhasil disimpan!', timer: 1500, showConfirmButton: false});
|
Swal.fire({ icon: 'success', title: 'Tersimpan', text: 'Perubahan bentuk berhasil disimpan!', timer: 1500, showConfirmButton: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
map.on(L.Draw.Event.DELETED, function (e) {
|
map.on(L.Draw.Event.DELETED, function (e) {
|
||||||
var layers = e.layers;
|
var layers = e.layers;
|
||||||
layers.eachLayer(function (layer) {
|
layers.eachLayer(function (layer) {
|
||||||
if(layer.db_id && layer.db_tipe) {
|
if (layer.db_id && layer.db_tipe) {
|
||||||
var fd = new FormData();
|
var fd = new FormData();
|
||||||
fd.append('action', 'hapus_data');
|
fd.append('action', 'hapus_data');
|
||||||
fd.append('id', layer.db_id);
|
fd.append('id', layer.db_id);
|
||||||
@@ -135,20 +135,20 @@ map.on(L.Draw.Event.DELETED, function (e) {
|
|||||||
fetch('../api/api.php', { method: 'POST', body: fd });
|
fetch('../api/api.php', { method: 'POST', body: fd });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Swal.fire({icon: 'success', title: 'Terhapus', text: 'Data berhasil dihapus dari peta!', timer: 1500, showConfirmButton: false});
|
Swal.fire({ icon: 'success', title: 'Terhapus', text: 'Data berhasil dihapus dari peta!', timer: 1500, showConfirmButton: false });
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggleSidebar() { document.getElementById('sidebar').classList.toggle('active'); }
|
function toggleSidebar() { document.getElementById('sidebar').classList.toggle('active'); }
|
||||||
|
|
||||||
function toggleRightPanel() {
|
function toggleRightPanel() {
|
||||||
var panel = document.getElementById('panelInput');
|
var panel = document.getElementById('panelInput');
|
||||||
if(panel) panel.classList.toggle('collapsed');
|
if (panel) panel.classList.toggle('collapsed');
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterData() {
|
function filterData() {
|
||||||
var input = document.getElementById('searchInput').value.toLowerCase();
|
var input = document.getElementById('searchInput').value.toLowerCase();
|
||||||
var cards = document.getElementsByClassName('item-data');
|
var cards = document.getElementsByClassName('item-data');
|
||||||
if(input.length > 0) document.getElementById('sidebar').classList.add('active');
|
if (input.length > 0) document.getElementById('sidebar').classList.add('active');
|
||||||
for (var i = 0; i < cards.length; i++) {
|
for (var i = 0; i < cards.length; i++) {
|
||||||
cards[i].style.display = cards[i].getAttribute('data-nama').includes(input) ? "" : "none";
|
cards[i].style.display = cards[i].getAttribute('data-nama').includes(input) ? "" : "none";
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ function filterData() {
|
|||||||
function changeRadius(v) {
|
function changeRadius(v) {
|
||||||
currentRadius = parseInt(v);
|
currentRadius = parseInt(v);
|
||||||
document.getElementById('radiusVal').innerText = v;
|
document.getElementById('radiusVal').innerText = v;
|
||||||
if(cachedData) renderMap(cachedData);
|
if (cachedData) renderMap(cachedData);
|
||||||
}
|
}
|
||||||
|
|
||||||
var prevReportCount = -1;
|
var prevReportCount = -1;
|
||||||
@@ -166,7 +166,7 @@ function loadData(isPolling = false) {
|
|||||||
.then(r => r.json())
|
.then(r => r.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
cachedData = data;
|
cachedData = data;
|
||||||
|
|
||||||
// Logika Notifikasi Bubble
|
// Logika Notifikasi Bubble
|
||||||
if (prevReportCount !== -1 && data.pelaporan.length > prevReportCount) {
|
if (prevReportCount !== -1 && data.pelaporan.length > prevReportCount) {
|
||||||
var newCount = data.pelaporan.length - prevReportCount;
|
var newCount = data.pelaporan.length - prevReportCount;
|
||||||
@@ -181,10 +181,10 @@ function loadData(isPolling = false) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
prevReportCount = data.pelaporan.length;
|
prevReportCount = data.pelaporan.length;
|
||||||
|
|
||||||
var badge = document.getElementById('notifBadge');
|
var badge = document.getElementById('notifBadge');
|
||||||
if(badge) {
|
if (badge) {
|
||||||
if(data.pelaporan.length > 0) {
|
if (data.pelaporan.length > 0) {
|
||||||
badge.style.display = 'block';
|
badge.style.display = 'block';
|
||||||
badge.innerText = data.pelaporan.length;
|
badge.innerText = data.pelaporan.length;
|
||||||
} else {
|
} else {
|
||||||
@@ -208,7 +208,7 @@ function loadData(isPolling = false) {
|
|||||||
// Auto-poll every 10 seconds
|
// Auto-poll every 10 seconds
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
// Only poll if not currently editing (edit_id is 0)
|
// Only poll if not currently editing (edit_id is 0)
|
||||||
if(document.getElementById('edit_id') && document.getElementById('edit_id').value === "0") {
|
if (document.getElementById('edit_id') && document.getElementById('edit_id').value === "0") {
|
||||||
loadData(true);
|
loadData(true);
|
||||||
}
|
}
|
||||||
}, 10000);
|
}, 10000);
|
||||||
@@ -238,12 +238,12 @@ function renderSidebar(data) {
|
|||||||
if (!window.dashboardType || window.dashboardType === 'sosial' || window.dashboardType === 'admin') {
|
if (!window.dashboardType || window.dashboardType === 'sosial' || window.dashboardType === 'admin') {
|
||||||
// Pelaporan
|
// Pelaporan
|
||||||
html += `<div class="section-title" style="color:#ef4444">🚨 Laporan Darurat</div>`;
|
html += `<div class="section-title" style="color:#ef4444">🚨 Laporan Darurat</div>`;
|
||||||
if(data.pelaporan.length === 0) html += `<small style="color:#666">Belum ada laporan</small>`;
|
if (data.pelaporan.length === 0) html += `<small style="color:#666">Belum ada laporan</small>`;
|
||||||
data.pelaporan.forEach(p => {
|
data.pelaporan.forEach(p => {
|
||||||
html += `<div class="card item-data" data-nama="${p.nama_pelapor.toLowerCase()} ${p.isi_laporan.toLowerCase()}">
|
html += `<div class="card item-data" data-nama="${p.nama_pelapor.toLowerCase()} ${p.isi_laporan.toLowerCase()}">
|
||||||
<div style="display:flex; justify-content:space-between">
|
<div style="display:flex; justify-content:space-between">
|
||||||
<span onclick="fokus(${p.latitude}, ${p.longitude})" style="cursor:pointer">
|
<span onclick="fokus(${p.latitude}, ${p.longitude})" style="cursor:pointer">
|
||||||
<b>${p.nama_pelapor}</b><small><i class="far fa-clock"></i> ${p.waktu}</small><br><span>${p.isi_laporan.substring(0,40)}...</span>
|
<b>${p.nama_pelapor}</b><small><i class="far fa-clock"></i> ${p.waktu}</small><br><span>${p.isi_laporan.substring(0, 40)}...</span>
|
||||||
</span>
|
</span>
|
||||||
<div>
|
<div>
|
||||||
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-bottom:5px;" onclick="editData('pelaporan', ${p.id})">Edit</button><br>
|
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-bottom:5px;" onclick="editData('pelaporan', ${p.id})">Edit</button><br>
|
||||||
@@ -313,9 +313,9 @@ function renderSidebar(data) {
|
|||||||
html += `<div class="section-title">🛣️ Manajemen Jalan</div>`;
|
html += `<div class="section-title">🛣️ Manajemen Jalan</div>`;
|
||||||
data.jalan.forEach(j => {
|
data.jalan.forEach(j => {
|
||||||
var color = '#ef4444'; // default red
|
var color = '#ef4444'; // default red
|
||||||
if(j.status_jalan === 'Nasional') color = '#ef4444';
|
if (j.status_jalan === 'Nasional') color = '#ef4444';
|
||||||
else if(j.status_jalan === 'Provinsi') color = '#eab308';
|
else if (j.status_jalan === 'Provinsi') color = '#eab308';
|
||||||
else if(j.status_jalan === 'Kabupaten') color = '#22c55e';
|
else if (j.status_jalan === 'Kabupaten') color = '#22c55e';
|
||||||
html += `<div class="card item-data" data-nama="${j.nama_jalan.toLowerCase()}">
|
html += `<div class="card item-data" data-nama="${j.nama_jalan.toLowerCase()}">
|
||||||
<div style="display:flex; justify-content:space-between">
|
<div style="display:flex; justify-content:space-between">
|
||||||
<span>
|
<span>
|
||||||
@@ -373,10 +373,10 @@ function renderMap(data) {
|
|||||||
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${m.id}, 'masjid')">Hapus</button>
|
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${m.id}, 'masjid')">Hapus</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
var faClass = 'fa-mosque';
|
var faClass = 'fa-mosque';
|
||||||
if(m.jenis === 'Gereja') faClass = 'fa-church';
|
if (m.jenis === 'Gereja') faClass = 'fa-church';
|
||||||
else if(m.jenis === 'Vihara') faClass = 'fa-vihara';
|
else if (m.jenis === 'Vihara') faClass = 'fa-vihara';
|
||||||
else if(m.jenis === 'Pura') faClass = 'fa-torii-gate';
|
else if (m.jenis === 'Pura') faClass = 'fa-torii-gate';
|
||||||
|
|
||||||
// Buat custom marker bentuk map pin dengan icon sesuai jenis
|
// Buat custom marker bentuk map pin dengan icon sesuai jenis
|
||||||
var masjidIcon = L.divIcon({
|
var masjidIcon = L.divIcon({
|
||||||
html: `
|
html: `
|
||||||
@@ -408,7 +408,7 @@ function renderMap(data) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
L.marker([m.latitude, m.longitude], { icon: masjidIcon, draggable: true }).addTo(layerMasjid).bindPopup(popup)
|
L.marker([m.latitude, m.longitude], { icon: masjidIcon, draggable: true }).addTo(layerMasjid).bindPopup(popup)
|
||||||
.on('dragend', function(e){ updateMarkerCoord(m.id, 'masjid', e.target.getLatLng()); });
|
.on('dragend', function (e) { updateMarkerCoord(m.id, 'masjid', e.target.getLatLng()); });
|
||||||
L.circle([m.latitude, m.longitude], {
|
L.circle([m.latitude, m.longitude], {
|
||||||
radius: currentRadius, color: '#2563eb', fillOpacity: 0.1, weight: 1
|
radius: currentRadius, color: '#2563eb', fillOpacity: 0.1, weight: 1
|
||||||
}).addTo(layerMasjidRadius);
|
}).addTo(layerMasjidRadius);
|
||||||
@@ -454,7 +454,7 @@ function renderMap(data) {
|
|||||||
L.marker([p.latitude, p.longitude], {
|
L.marker([p.latitude, p.longitude], {
|
||||||
icon: pelaporanIcon, draggable: true
|
icon: pelaporanIcon, draggable: true
|
||||||
}).addTo(layerPelaporan).bindPopup(popup)
|
}).addTo(layerPelaporan).bindPopup(popup)
|
||||||
.on('dragend', function(e){ updateMarkerCoord(p.id, 'pelaporan', e.target.getLatLng()); });
|
.on('dragend', function (e) { updateMarkerCoord(p.id, 'pelaporan', e.target.getLatLng()); });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,7 +464,7 @@ function renderMap(data) {
|
|||||||
var is24 = s.kategori === '24jam';
|
var is24 = s.kategori === '24jam';
|
||||||
var iconUrl = is24 ? 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png' : 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png';
|
var iconUrl = is24 ? 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-green.png' : 'https://raw.githubusercontent.com/pointhi/leaflet-color-markers/master/img/marker-icon-red.png';
|
||||||
var targetLayer = is24 ? layerSpbu24 : layerSpbuNon24;
|
var targetLayer = is24 ? layerSpbu24 : layerSpbuNon24;
|
||||||
|
|
||||||
var popup = `<b>⛽ ${s.nama}</b><br>Kategori: ${s.kategori === '24jam' ? 'Buka 24 Jam' : 'Tidak 24 Jam'}<br>
|
var popup = `<b>⛽ ${s.nama}</b><br>Kategori: ${s.kategori === '24jam' ? 'Buka 24 Jam' : 'Tidak 24 Jam'}<br>
|
||||||
<div style="margin-top:10px; text-align:center;">
|
<div style="margin-top:10px; text-align:center;">
|
||||||
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('spbu', ${s.id})">Edit</button>
|
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('spbu', ${s.id})">Edit</button>
|
||||||
@@ -473,7 +473,7 @@ function renderMap(data) {
|
|||||||
L.marker([s.latitude, s.longitude], {
|
L.marker([s.latitude, s.longitude], {
|
||||||
icon: L.icon({ iconUrl: iconUrl, iconSize: [25, 41], iconAnchor: [12, 41] }), draggable: true
|
icon: L.icon({ iconUrl: iconUrl, iconSize: [25, 41], iconAnchor: [12, 41] }), draggable: true
|
||||||
}).addTo(targetLayer).bindPopup(popup)
|
}).addTo(targetLayer).bindPopup(popup)
|
||||||
.on('dragend', function(e){ updateMarkerCoord(s.id, 'spbu', e.target.getLatLng()); });
|
.on('dragend', function (e) { updateMarkerCoord(s.id, 'spbu', e.target.getLatLng()); });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +482,7 @@ function renderMap(data) {
|
|||||||
data.warga.forEach(w => {
|
data.warga.forEach(w => {
|
||||||
var pos = L.latLng(w.latitude, w.longitude);
|
var pos = L.latLng(w.latitude, w.longitude);
|
||||||
var isCovered = lokMasjid.some(m => pos.distanceTo(m) <= currentRadius);
|
var isCovered = lokMasjid.some(m => pos.distanceTo(m) <= currentRadius);
|
||||||
|
|
||||||
// Buat elemen point berbentuk map pin (teardrop) dengan ikon rumah di dalamnya
|
// Buat elemen point berbentuk map pin (teardrop) dengan ikon rumah di dalamnya
|
||||||
var color = isCovered ? '#16a34a' : '#ef4444'; // Hijau aman, merah di luar
|
var color = isCovered ? '#16a34a' : '#ef4444'; // Hijau aman, merah di luar
|
||||||
var houseIcon = L.divIcon({
|
var houseIcon = L.divIcon({
|
||||||
@@ -521,7 +521,7 @@ function renderMap(data) {
|
|||||||
iconAnchor: [15, 36], // Titik jangkar di ujung bawah pin
|
iconAnchor: [15, 36], // Titik jangkar di ujung bawah pin
|
||||||
popupAnchor: [0, -36]
|
popupAnchor: [0, -36]
|
||||||
});
|
});
|
||||||
|
|
||||||
var isPenerima = (w.status_bantuan === 'Sudah') ? 'Ya' : 'Belum';
|
var isPenerima = (w.status_bantuan === 'Sudah') ? 'Ya' : 'Belum';
|
||||||
var txtPendidikan = w.pendidikan ? w.pendidikan : 'Tidak diketahui';
|
var txtPendidikan = w.pendidikan ? w.pendidikan : 'Tidak diketahui';
|
||||||
var txtPenyakit = (w.riwayat_penyakit && w.riwayat_penyakit.trim().length > 0) ? w.riwayat_penyakit : 'Tidak ada';
|
var txtPenyakit = (w.riwayat_penyakit && w.riwayat_penyakit.trim().length > 0) ? w.riwayat_penyakit : 'Tidak ada';
|
||||||
@@ -546,8 +546,8 @@ function renderMap(data) {
|
|||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
L.marker(pos, { icon: houseIcon, draggable: true })
|
L.marker(pos, { icon: houseIcon, draggable: true })
|
||||||
.addTo(layerWarga).bindPopup(popup)
|
.addTo(layerWarga).bindPopup(popup)
|
||||||
.on('dragend', function(e){ updateMarkerCoord(w.id, 'warga', e.target.getLatLng()); });
|
.on('dragend', function (e) { updateMarkerCoord(w.id, 'warga', e.target.getLatLng()); });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,16 +556,16 @@ function renderMap(data) {
|
|||||||
data.jalan.forEach(j => {
|
data.jalan.forEach(j => {
|
||||||
var coords = JSON.parse(j.koordinat);
|
var coords = JSON.parse(j.koordinat);
|
||||||
var color = '#ef4444'; // default red
|
var color = '#ef4444'; // default red
|
||||||
if(j.status_jalan === 'Nasional') color = '#ef4444'; // Merah
|
if (j.status_jalan === 'Nasional') color = '#ef4444'; // Merah
|
||||||
else if(j.status_jalan === 'Provinsi') color = '#eab308'; // Kuning
|
else if (j.status_jalan === 'Provinsi') color = '#eab308'; // Kuning
|
||||||
else if(j.status_jalan === 'Kabupaten') color = '#22c55e'; // Hijau
|
else if (j.status_jalan === 'Kabupaten') color = '#22c55e'; // Hijau
|
||||||
|
|
||||||
var popup = `<b>🛣️ ${j.nama_jalan}</b><br>Status: ${j.status_jalan}<br>Panjang: ${j.panjang_m} meter<br>
|
var popup = `<b>🛣️ ${j.nama_jalan}</b><br>Status: ${j.status_jalan}<br>Panjang: ${j.panjang_m} meter<br>
|
||||||
<div style="margin-top:10px; text-align:center;">
|
<div style="margin-top:10px; text-align:center;">
|
||||||
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('jalan', ${j.id})">Edit</button>
|
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('jalan', ${j.id})">Edit</button>
|
||||||
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${j.id}, 'jalan')">Hapus</button>
|
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${j.id}, 'jalan')">Hapus</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
var polyline = L.polyline(coords, {color: color, weight: 6}).addTo(layerLines).bindPopup(popup);
|
var polyline = L.polyline(coords, { color: color, weight: 6 }).addTo(layerLines).bindPopup(popup);
|
||||||
polyline.db_id = j.id;
|
polyline.db_id = j.id;
|
||||||
polyline.db_tipe = 'jalan';
|
polyline.db_tipe = 'jalan';
|
||||||
drawnItems.addLayer(polyline);
|
drawnItems.addLayer(polyline);
|
||||||
@@ -579,7 +579,7 @@ function renderMap(data) {
|
|||||||
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('parsil', ${p.id})">Edit</button>
|
<button class="btn-save" style="padding:4px 8px; font-size:0.75rem; width:auto; margin-right:5px;" onclick="editData('parsil', ${p.id})">Edit</button>
|
||||||
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${p.id}, 'parsil')">Hapus</button>
|
<button class="btn-del" style="padding:4px 8px; font-size:0.75rem; width:auto;" onclick="hapusData(${p.id}, 'parsil')">Hapus</button>
|
||||||
</div>`;
|
</div>`;
|
||||||
var polygon = L.polygon(coords, {color: '#2563eb', fillOpacity: 0.4}).addTo(layerPolygons).bindPopup(popup);
|
var polygon = L.polygon(coords, { color: '#2563eb', fillOpacity: 0.4 }).addTo(layerPolygons).bindPopup(popup);
|
||||||
polygon.db_id = p.id;
|
polygon.db_id = p.id;
|
||||||
polygon.db_tipe = 'parsil';
|
polygon.db_tipe = 'parsil';
|
||||||
drawnItems.addLayer(polygon);
|
drawnItems.addLayer(polygon);
|
||||||
@@ -622,12 +622,12 @@ function simpanData() {
|
|||||||
fd.append('status_hak', document.getElementById('status_hak').value);
|
fd.append('status_hak', document.getElementById('status_hak').value);
|
||||||
fd.append('koordinat', document.getElementById('parsil_coords').value);
|
fd.append('koordinat', document.getElementById('parsil_coords').value);
|
||||||
} else {
|
} else {
|
||||||
if(j !== 'geometri' && (!lat || !lng) && document.getElementById('edit_id').value === "0") {
|
if (j !== 'geometri' && (!lat || !lng) && document.getElementById('edit_id').value === "0") {
|
||||||
Swal.fire({icon: 'warning', title: 'Oops...', text: 'Silakan klik titik koordinat di peta terlebih dahulu!'});
|
Swal.fire({ icon: 'warning', title: 'Oops...', text: 'Silakan klik titik koordinat di peta terlebih dahulu!' });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fd.append('lat', lat); fd.append('lng', lng);
|
fd.append('lat', lat); fd.append('lng', lng);
|
||||||
|
|
||||||
if (j === 'pelaporan') {
|
if (j === 'pelaporan') {
|
||||||
fd.append('nama', document.getElementById('nama_pelapor').value);
|
fd.append('nama', document.getElementById('nama_pelapor').value);
|
||||||
fd.append('laporan', document.getElementById('isi_laporan').value);
|
fd.append('laporan', document.getElementById('isi_laporan').value);
|
||||||
@@ -651,15 +651,15 @@ function simpanData() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Swal.fire({ title: 'Menyimpan...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() }});
|
Swal.fire({ title: 'Menyimpan...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() } });
|
||||||
fetch('../api/api.php', { method: 'POST', body: fd })
|
fetch('../api/api.php', { method: 'POST', body: fd })
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.status === 'error') {
|
if (res.status === 'error') {
|
||||||
Swal.fire('Gagal!', res.message, 'error');
|
Swal.fire('Gagal!', res.message, 'error');
|
||||||
} else {
|
} else {
|
||||||
Swal.fire({icon: 'success', title: 'Berhasil', text: 'Data berhasil disimpan!', timer: 1500, showConfirmButton: false})
|
Swal.fire({ icon: 'success', title: 'Berhasil', text: 'Data berhasil disimpan!', timer: 1500, showConfirmButton: false })
|
||||||
.then(() => location.reload());
|
.then(() => location.reload());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -670,7 +670,7 @@ function hapusData(id, tipe) {
|
|||||||
showCancelButton: true, confirmButtonColor: '#ef4444', cancelButtonColor: '#94a3b8', confirmButtonText: 'Ya, Hapus!'
|
showCancelButton: true, confirmButtonColor: '#ef4444', cancelButtonColor: '#94a3b8', confirmButtonText: 'Ya, Hapus!'
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result.isConfirmed) {
|
if (result.isConfirmed) {
|
||||||
Swal.fire({ title: 'Menghapus...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() }});
|
Swal.fire({ title: 'Menghapus...', allowOutsideClick: false, didOpen: () => { Swal.showLoading() } });
|
||||||
var fd = new FormData();
|
var fd = new FormData();
|
||||||
fd.append('action', 'hapus_data');
|
fd.append('action', 'hapus_data');
|
||||||
fd.append('id', id);
|
fd.append('id', id);
|
||||||
@@ -700,16 +700,16 @@ function batalEdit() {
|
|||||||
|
|
||||||
function editData(tipe, id) {
|
function editData(tipe, id) {
|
||||||
var item = cachedData[tipe].find(x => x.id == id);
|
var item = cachedData[tipe].find(x => x.id == id);
|
||||||
if(!item) return;
|
if (!item) return;
|
||||||
|
|
||||||
document.getElementById('edit_id').value = id;
|
document.getElementById('edit_id').value = id;
|
||||||
document.getElementById('jenis').value = tipe;
|
document.getElementById('jenis').value = tipe;
|
||||||
toggleForm();
|
toggleForm();
|
||||||
|
|
||||||
var panel = document.getElementById('panelInput');
|
|
||||||
if(panel) panel.classList.remove('collapsed');
|
|
||||||
|
|
||||||
if(tipe == 'warga') {
|
var panel = document.getElementById('panelInput');
|
||||||
|
if (panel) panel.classList.remove('collapsed');
|
||||||
|
|
||||||
|
if (tipe == 'warga') {
|
||||||
document.getElementById('nama_kk').value = item.nama;
|
document.getElementById('nama_kk').value = item.nama;
|
||||||
document.getElementById('jumlah_kk').value = item.jumlah_kk;
|
document.getElementById('jumlah_kk').value = item.jumlah_kk;
|
||||||
document.getElementById('tanggal_lahir').value = item.tanggal_lahir || '';
|
document.getElementById('tanggal_lahir').value = item.tanggal_lahir || '';
|
||||||
@@ -739,7 +739,7 @@ function editData(tipe, id) {
|
|||||||
document.getElementById('parsil_coords').value = item.koordinat;
|
document.getElementById('parsil_coords').value = item.koordinat;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(item.latitude && item.longitude) {
|
if (item.latitude && item.longitude) {
|
||||||
document.getElementById('lat').value = item.latitude;
|
document.getElementById('lat').value = item.latitude;
|
||||||
document.getElementById('lng').value = item.longitude;
|
document.getElementById('lng').value = item.longitude;
|
||||||
fokus(item.latitude, item.longitude);
|
fokus(item.latitude, item.longitude);
|
||||||
@@ -762,10 +762,10 @@ function updateMarkerCoord(id, tipe, latlng) {
|
|||||||
fetch('../api/api.php', { method: 'POST', body: fd })
|
fetch('../api/api.php', { method: 'POST', body: fd })
|
||||||
.then(() => {
|
.then(() => {
|
||||||
Swal.fire({
|
Swal.fire({
|
||||||
icon: 'success',
|
icon: 'success',
|
||||||
title: 'Tersimpan',
|
title: 'Tersimpan',
|
||||||
text: 'Posisi titik berhasil digeser!',
|
text: 'Posisi titik berhasil digeser!',
|
||||||
timer: 1500,
|
timer: 1500,
|
||||||
showConfirmButton: false,
|
showConfirmButton: false,
|
||||||
toast: true,
|
toast: true,
|
||||||
position: 'top-end'
|
position: 'top-end'
|
||||||
|
|||||||
Reference in New Issue
Block a user