first commit
This commit is contained in:
+86
@@ -0,0 +1,86 @@
|
||||
CREATE DATABASE IF NOT EXISTS webgis_spbu;
|
||||
|
||||
USE webgis_spbu;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS spbu (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama VARCHAR(100) NOT NULL,
|
||||
no_spbu VARCHAR(50) NOT NULL,
|
||||
status ENUM('24jam', 'tidak') NOT NULL,
|
||||
latitude DOUBLE NOT NULL,
|
||||
longitude DOUBLE NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS jalan (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama VARCHAR(100) NOT NULL,
|
||||
status ENUM('Jalan Nasional', 'Jalan Provinsi', 'Jalan Kabupaten') NOT NULL,
|
||||
panjang DOUBLE NOT NULL,
|
||||
geom LONGTEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS kavling (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama VARCHAR(100) NOT NULL,
|
||||
status ENUM('SHM', 'HGB', 'HGU', 'HP') NOT NULL,
|
||||
luas DOUBLE NOT NULL,
|
||||
geom LONGTEXT NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS kemiskinan (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama_kepala_keluarga VARCHAR(150) NOT NULL,
|
||||
jumlah_kk INT NOT NULL,
|
||||
alamat TEXT NOT NULL,
|
||||
latitude DOUBLE NOT NULL,
|
||||
longitude DOUBLE NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS masjid (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama_masjid VARCHAR(150) NOT NULL,
|
||||
pic_masjid VARCHAR(150) NOT NULL,
|
||||
alamat TEXT NOT NULL,
|
||||
latitude DOUBLE NOT NULL,
|
||||
longitude DOUBLE NOT NULL,
|
||||
radius DOUBLE NOT NULL DEFAULT 500,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
ALTER TABLE spbu
|
||||
MODIFY COLUMN nama VARCHAR(100) NOT NULL,
|
||||
MODIFY COLUMN no_spbu VARCHAR(50) NOT NULL,
|
||||
MODIFY COLUMN status ENUM('24jam', 'tidak') NOT NULL,
|
||||
MODIFY COLUMN latitude DOUBLE NOT NULL,
|
||||
MODIFY COLUMN longitude DOUBLE NOT NULL;
|
||||
|
||||
ALTER TABLE jalan
|
||||
MODIFY COLUMN nama VARCHAR(100) NOT NULL,
|
||||
MODIFY COLUMN status ENUM('Jalan Nasional', 'Jalan Provinsi', 'Jalan Kabupaten') NOT NULL,
|
||||
MODIFY COLUMN panjang DOUBLE NOT NULL,
|
||||
MODIFY COLUMN geom LONGTEXT NOT NULL;
|
||||
|
||||
ALTER TABLE kavling
|
||||
MODIFY COLUMN nama VARCHAR(100) NOT NULL,
|
||||
MODIFY COLUMN status ENUM('SHM', 'HGB', 'HGU', 'HP') NOT NULL,
|
||||
MODIFY COLUMN luas DOUBLE NOT NULL,
|
||||
MODIFY COLUMN geom LONGTEXT NOT NULL;
|
||||
|
||||
ALTER TABLE kemiskinan
|
||||
MODIFY COLUMN nama_kepala_keluarga VARCHAR(150) NOT NULL,
|
||||
MODIFY COLUMN jumlah_kk INT NOT NULL,
|
||||
MODIFY COLUMN alamat TEXT NOT NULL,
|
||||
MODIFY COLUMN latitude DOUBLE NOT NULL,
|
||||
MODIFY COLUMN longitude DOUBLE NOT NULL;
|
||||
|
||||
ALTER TABLE masjid
|
||||
MODIFY COLUMN nama_masjid VARCHAR(150) NOT NULL,
|
||||
MODIFY COLUMN pic_masjid VARCHAR(150) NOT NULL,
|
||||
MODIFY COLUMN alamat TEXT NOT NULL,
|
||||
MODIFY COLUMN latitude DOUBLE NOT NULL,
|
||||
MODIFY COLUMN longitude DOUBLE NOT NULL,
|
||||
MODIFY COLUMN radius DOUBLE NOT NULL DEFAULT 500;
|
||||
+934
@@ -0,0 +1,934 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>WebGIS SPBU</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css"/>
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--primary: #5b5cf6;
|
||||
--primary-strong: #4f46e5;
|
||||
--primary-soft: #ecebff;
|
||||
--success: #16a34a;
|
||||
--danger: #ef4444;
|
||||
--warning: #f97316;
|
||||
--info: #2563eb;
|
||||
--ink: #0f172a;
|
||||
--muted: #667085;
|
||||
--line: #e6eaf2;
|
||||
--panel: rgba(255, 255, 255, 0.96);
|
||||
--shadow: 0 18px 45px rgba(15, 23, 42, 0.14);
|
||||
}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Inter, "Segoe UI", Arial, sans-serif;
|
||||
color: var(--ink);
|
||||
background: #eef2f7;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
button,
|
||||
input {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
position: fixed;
|
||||
top: 14px;
|
||||
left: 18px;
|
||||
right: 18px;
|
||||
z-index: 1200;
|
||||
height: 64px;
|
||||
padding: 10px 14px;
|
||||
border: 1px solid rgba(226, 232, 240, 0.92);
|
||||
border-radius: 14px;
|
||||
background: rgba(255, 255, 255, 0.97);
|
||||
box-shadow: 0 12px 32px rgba(15, 23, 42, 0.12);
|
||||
backdrop-filter: blur(16px);
|
||||
display: grid;
|
||||
grid-template-columns: minmax(320px, 1fr) auto;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.brand {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.brand-icon {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 9px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
color: var(--primary);
|
||||
background: var(--primary-soft);
|
||||
border: 1px solid #d9d8ff;
|
||||
font-size: 18px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.navbar h2 {
|
||||
margin: 0;
|
||||
font-size: 15px;
|
||||
color: var(--primary-strong);
|
||||
line-height: 1.2;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.navbar p {
|
||||
margin: 2px 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 11px;
|
||||
max-width: 540px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.top-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.top-actions {
|
||||
justify-self: end;
|
||||
}
|
||||
|
||||
.navbar button,
|
||||
.panel-button,
|
||||
.action-chip {
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 11px;
|
||||
background: #fff;
|
||||
color: #475467;
|
||||
cursor: pointer;
|
||||
font-weight: 700;
|
||||
transition: background 0.18s ease, border-color 0.18s ease, color 0.18s ease, box-shadow 0.18s ease;
|
||||
}
|
||||
|
||||
.action-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 40px;
|
||||
padding: 0 14px;
|
||||
color: #344054;
|
||||
background: #fff;
|
||||
white-space: nowrap;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.status-text {
|
||||
color: #667085;
|
||||
border-color: #edf0f6;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.map-stage {
|
||||
position: relative;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#map {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.left-panel,
|
||||
#sidebar,
|
||||
.stats-card {
|
||||
position: absolute;
|
||||
z-index: 1100;
|
||||
border: 1px solid rgba(226, 232, 240, 0.95);
|
||||
border-radius: 16px;
|
||||
background: var(--panel);
|
||||
box-shadow: var(--shadow);
|
||||
backdrop-filter: blur(16px);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.left-panel {
|
||||
top: 92px;
|
||||
left: 18px;
|
||||
bottom: 18px;
|
||||
width: 292px;
|
||||
padding: 16px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
top: 92px;
|
||||
right: 18px;
|
||||
bottom: 18px;
|
||||
width: 410px;
|
||||
padding: 18px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
left: 336px;
|
||||
bottom: 24px;
|
||||
width: 430px;
|
||||
padding: 16px 18px;
|
||||
}
|
||||
|
||||
.mode-switch {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 8px;
|
||||
padding: 4px;
|
||||
margin-bottom: 18px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 12px;
|
||||
background: #f8fafc;
|
||||
}
|
||||
|
||||
.mode-switch button {
|
||||
min-height: 40px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 9px;
|
||||
color: #667085;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.mode-switch button.active {
|
||||
color: #fff;
|
||||
border-color: transparent;
|
||||
background: var(--primary);
|
||||
box-shadow: 0 8px 18px rgba(91, 92, 246, 0.24);
|
||||
}
|
||||
|
||||
.panel-button {
|
||||
min-height: 44px;
|
||||
padding: 0 12px;
|
||||
color: #667085;
|
||||
background: #f8fafc;
|
||||
border-color: #e8edf5;
|
||||
border-radius: 10px;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.panel-button.active {
|
||||
color: #fff;
|
||||
border-color: transparent;
|
||||
background: var(--primary);
|
||||
box-shadow: 0 8px 18px rgba(91, 92, 246, 0.24);
|
||||
}
|
||||
|
||||
.panel-section {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.panel-section h3,
|
||||
.section h3,
|
||||
.stats-title {
|
||||
margin: 0 0 10px;
|
||||
color: #667085;
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.type-list {
|
||||
display: grid;
|
||||
gap: 7px;
|
||||
}
|
||||
|
||||
.panel-button {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
gap: 12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tool-icon {
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
border-radius: 8px;
|
||||
color: #667085;
|
||||
background: #eef2f7;
|
||||
font-size: 15px;
|
||||
line-height: 1;
|
||||
flex: 0 0 28px;
|
||||
}
|
||||
|
||||
.panel-button.active .tool-icon {
|
||||
color: var(--primary);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.legend-list {
|
||||
display: grid;
|
||||
gap: 9px;
|
||||
color: #536179;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.legend-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 9px;
|
||||
}
|
||||
|
||||
.legend-dot {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
border-radius: 99px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.sidebar-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.sidebar-title {
|
||||
margin: 0;
|
||||
color: var(--primary-strong);
|
||||
font-size: 18px;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.sidebar-subtitle {
|
||||
margin: 7px 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.panel-close {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
color: #667085;
|
||||
background: transparent;
|
||||
cursor: default;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 18px;
|
||||
}
|
||||
|
||||
.section h3 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 10px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.section-count {
|
||||
min-width: 24px;
|
||||
height: 24px;
|
||||
padding: 0 8px;
|
||||
display: inline-grid;
|
||||
place-items: center;
|
||||
border-radius: 99px;
|
||||
background: #eef2ff;
|
||||
color: var(--primary-strong);
|
||||
font-size: 11px;
|
||||
letter-spacing: 0;
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 14px;
|
||||
margin-bottom: 12px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 12px;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
border-color: #c8cdfd;
|
||||
box-shadow: 0 12px 24px rgba(15, 23, 42, 0.08);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 16px;
|
||||
font-weight: 800;
|
||||
color: var(--ink);
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
color: #175cd3;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
.meta {
|
||||
font-size: 12px;
|
||||
color: var(--muted);
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.card-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
min-height: 24px;
|
||||
padding: 4px 8px;
|
||||
border-radius: 7px;
|
||||
font-size: 11px;
|
||||
font-weight: 800;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.green {
|
||||
background: #dcfce7;
|
||||
color: #15803d;
|
||||
}
|
||||
|
||||
.red {
|
||||
background: #fee2e2;
|
||||
color: #dc2626;
|
||||
}
|
||||
|
||||
.blue {
|
||||
background: #dbeafe;
|
||||
color: #1d4ed8;
|
||||
}
|
||||
|
||||
.orange {
|
||||
background: #ffedd5;
|
||||
color: #ea580c;
|
||||
}
|
||||
|
||||
.gray {
|
||||
background: #eef2f7;
|
||||
color: #475467;
|
||||
}
|
||||
|
||||
.delete-btn,
|
||||
.secondary-btn {
|
||||
min-width: 42px;
|
||||
min-height: 38px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 10px;
|
||||
padding: 8px 10px;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
cursor: pointer;
|
||||
background: #fff;
|
||||
color: #667085;
|
||||
}
|
||||
|
||||
.delete-btn:hover {
|
||||
color: #dc2626;
|
||||
border-color: #fecaca;
|
||||
background: #fff5f5;
|
||||
}
|
||||
|
||||
.secondary-btn:hover {
|
||||
color: #1d4ed8;
|
||||
border-color: #bfdbfe;
|
||||
background: #eff6ff;
|
||||
}
|
||||
|
||||
.delete-btn:disabled,
|
||||
.secondary-btn:disabled {
|
||||
background: #f3f4f6;
|
||||
color: #a2aab8;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.custom-point-icon {
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.point-dot {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
display: block;
|
||||
border-radius: 999px;
|
||||
border: 3px solid white;
|
||||
box-shadow: 0 4px 12px rgba(15, 23, 42, 0.35);
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
padding: 14px;
|
||||
border-radius: 12px;
|
||||
border: 1px dashed #d7dce7;
|
||||
background: #f8fafc;
|
||||
color: var(--muted);
|
||||
font-size: 13px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.modal-backdrop {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 2000;
|
||||
display: none;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
background: rgba(15, 23, 42, 0.46);
|
||||
backdrop-filter: blur(4px);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.modal-backdrop.is-open {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.edit-modal {
|
||||
width: min(460px, 100%);
|
||||
max-height: min(720px, 92vh);
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(226, 232, 240, 0.95);
|
||||
border-radius: 16px;
|
||||
background: #fff;
|
||||
box-shadow: 0 24px 70px rgba(15, 23, 42, 0.26);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.edit-modal-header {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
justify-content: space-between;
|
||||
gap: 14px;
|
||||
padding: 18px 20px 14px;
|
||||
border-bottom: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.edit-modal-title {
|
||||
margin: 0;
|
||||
color: var(--ink);
|
||||
font-size: 18px;
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.edit-modal-subtitle {
|
||||
margin: 5px 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 12px;
|
||||
line-height: 1.45;
|
||||
}
|
||||
|
||||
.edit-modal-close {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 10px;
|
||||
color: #667085;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.edit-modal-body {
|
||||
padding: 18px 20px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
display: grid;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.form-field {
|
||||
display: grid;
|
||||
gap: 7px;
|
||||
}
|
||||
|
||||
.form-field label {
|
||||
color: #344054;
|
||||
font-size: 12px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.form-field input,
|
||||
.form-field select,
|
||||
.form-field textarea {
|
||||
width: 100%;
|
||||
min-height: 42px;
|
||||
border: 1px solid #dbe2ec;
|
||||
border-radius: 10px;
|
||||
padding: 10px 12px;
|
||||
color: var(--ink);
|
||||
background: #fff;
|
||||
box-sizing: border-box;
|
||||
outline: none;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.form-field textarea {
|
||||
min-height: 86px;
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
.form-field input:focus,
|
||||
.form-field select:focus,
|
||||
.form-field textarea:focus {
|
||||
border-color: var(--primary);
|
||||
box-shadow: 0 0 0 3px rgba(91, 92, 246, 0.12);
|
||||
}
|
||||
|
||||
.form-error {
|
||||
display: none;
|
||||
padding: 10px 12px;
|
||||
border-radius: 10px;
|
||||
color: #b42318;
|
||||
background: #fff1f3;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.form-error.is-visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.edit-modal-actions {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
padding: 14px 20px 18px;
|
||||
border-top: 1px solid var(--line);
|
||||
background: #fbfcff;
|
||||
}
|
||||
|
||||
.modal-btn {
|
||||
min-height: 40px;
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 10px;
|
||||
padding: 0 14px;
|
||||
color: #475467;
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.modal-btn.primary {
|
||||
color: #fff;
|
||||
border-color: transparent;
|
||||
background: var(--primary);
|
||||
box-shadow: 0 8px 18px rgba(91, 92, 246, 0.24);
|
||||
}
|
||||
|
||||
.filter-box {
|
||||
display: grid;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 9px;
|
||||
min-height: 38px;
|
||||
padding: 7px 10px;
|
||||
border-radius: 10px;
|
||||
color: #536179;
|
||||
background: #f8fafc;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.filter-item input {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
accent-color: var(--primary);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.stats-head {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 12px;
|
||||
padding-top: 10px;
|
||||
border-top: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
color: var(--primary);
|
||||
font-size: 24px;
|
||||
font-weight: 900;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
margin-top: 6px;
|
||||
color: #667085;
|
||||
font-size: 10px;
|
||||
font-weight: 800;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.leaflet-control-zoom {
|
||||
border: none !important;
|
||||
box-shadow: var(--shadow) !important;
|
||||
}
|
||||
|
||||
.leaflet-top.leaflet-left {
|
||||
top: 108px;
|
||||
left: 320px;
|
||||
}
|
||||
|
||||
.leaflet-top.leaflet-right {
|
||||
top: 92px;
|
||||
right: 446px;
|
||||
}
|
||||
|
||||
.leaflet-control-zoom a,
|
||||
.leaflet-control-layers {
|
||||
border-radius: 10px !important;
|
||||
}
|
||||
|
||||
@media (max-width: 1180px) {
|
||||
.navbar {
|
||||
grid-template-columns: minmax(260px, 1fr) auto;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
width: 360px;
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
left: 336px;
|
||||
width: 360px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
body {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.map-stage {
|
||||
height: auto;
|
||||
min-height: 100vh;
|
||||
display: grid;
|
||||
grid-template-rows: 70vh auto auto auto;
|
||||
padding-top: 92px;
|
||||
overflow: visible;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.navbar,
|
||||
.left-panel,
|
||||
#sidebar,
|
||||
.stats-card,
|
||||
#map {
|
||||
position: relative;
|
||||
inset: auto;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
height: 58px;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.navbar p {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#map {
|
||||
height: 70vh;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.leaflet-top.leaflet-left {
|
||||
top: 12px;
|
||||
left: 12px;
|
||||
}
|
||||
|
||||
.leaflet-top.leaflet-right {
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
}
|
||||
|
||||
.left-panel,
|
||||
#sidebar,
|
||||
.stats-card {
|
||||
width: auto;
|
||||
margin: 12px;
|
||||
box-shadow: 0 10px 28px rgba(15, 23, 42, 0.1);
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
order: 3;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
order: 4;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="navbar">
|
||||
<div class="brand">
|
||||
<div class="brand-icon">□</div>
|
||||
<div>
|
||||
<h2>Admin WebGIS SPBU</h2>
|
||||
<p id="mapHint">Mode view aktif. Pindah ke edit jika ingin menambah atau menghapus data.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="top-actions">
|
||||
<span class="action-chip status-text">Admin SPBU</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="map-stage">
|
||||
<div id="map"></div>
|
||||
|
||||
<aside class="left-panel">
|
||||
<div class="mode-switch">
|
||||
<button id="modeViewBtn" onclick="setMode('view')">◉ Lihat</button>
|
||||
<button id="modeEditBtn" onclick="setMode('edit')">✎ Edit</button>
|
||||
</div>
|
||||
|
||||
<div class="panel-section">
|
||||
<h3>Alat Peta</h3>
|
||||
<div class="type-list">
|
||||
<button class="panel-button" id="typeSpbuBtn" onclick="setDataType('spbu')"><span class="tool-icon">S</span><span>Tambah SPBU</span></button>
|
||||
<button class="panel-button" id="typeKemiskinanBtn" onclick="setDataType('kemiskinan')"><span class="tool-icon">K</span><span>Tambah Kemiskinan</span></button>
|
||||
<button class="panel-button" id="typeMasjidBtn" onclick="setDataType('masjid')"><span class="tool-icon">M</span><span>Tambah Masjid</span></button>
|
||||
<button class="panel-button" id="typeJalanBtn" onclick="setDataType('jalan')"><span class="tool-icon">J</span><span>Tambah Jalan</span></button>
|
||||
<button class="panel-button" id="typeKavlingBtn" onclick="setDataType('kavling')"><span class="tool-icon">V</span><span>Tambah Kavling</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="layerFilters"></div>
|
||||
|
||||
<div class="panel-section">
|
||||
<h3>Legenda Peta</h3>
|
||||
<div class="legend-list">
|
||||
<div class="legend-item"><span class="legend-dot" style="background:#28a745"></span>SPBU 24 jam</div>
|
||||
<div class="legend-item"><span class="legend-dot" style="background:#dc3545"></span>SPBU tidak 24 jam</div>
|
||||
<div class="legend-item"><span class="legend-dot" style="background:#ff8c00"></span>Kemiskinan</div>
|
||||
<div class="legend-item"><span class="legend-dot" style="background:#007bff"></span>Masjid dan radius</div>
|
||||
<div class="legend-item"><span class="legend-dot" style="background:#6f42c1"></span>Kavling</div>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<section class="stats-card">
|
||||
<div class="stats-head">
|
||||
<h3 class="stats-title">Statistik Wilayah</h3>
|
||||
</div>
|
||||
<div class="stats-grid">
|
||||
<div>
|
||||
<div class="stat-value" id="statSpbu">0</div>
|
||||
<div class="stat-label">Total SPBU</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="stat-value" id="statMasjid">0</div>
|
||||
<div class="stat-label">Masjid</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="stat-value" id="statJalan">0</div>
|
||||
<div class="stat-label">Jalan</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="stat-value" id="statKavling">0</div>
|
||||
<div class="stat-label">Kavling</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="sidebar"></div>
|
||||
</div>
|
||||
|
||||
<div class="modal-backdrop" id="editModalBackdrop" aria-hidden="true">
|
||||
<form class="edit-modal" id="editModalForm">
|
||||
<div class="edit-modal-header">
|
||||
<div>
|
||||
<h2 class="edit-modal-title" id="editModalTitle">Edit Data</h2>
|
||||
<p class="edit-modal-subtitle" id="editModalSubtitle">Perbarui atribut data terpilih.</p>
|
||||
</div>
|
||||
<button class="edit-modal-close" id="editModalClose" type="button">×</button>
|
||||
</div>
|
||||
<div class="edit-modal-body">
|
||||
<div class="form-error" id="editModalError"></div>
|
||||
<div class="form-grid" id="editModalFields"></div>
|
||||
</div>
|
||||
<div class="edit-modal-actions">
|
||||
<button class="modal-btn" id="editModalCancel" type="button">Batal</button>
|
||||
<button class="modal-btn primary" type="submit">Simpan Perubahan</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
|
||||
<script src="js/map.js"></script>
|
||||
<script src="js/line.js"></script>
|
||||
<script src="js/polygon.js"></script>
|
||||
<script src="js/loadData.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
window.getRoadColor = function (status) {
|
||||
if (status === "Jalan Nasional") {
|
||||
return "#dc3545";
|
||||
}
|
||||
|
||||
if (status === "Jalan Provinsi") {
|
||||
return "#007bff";
|
||||
}
|
||||
|
||||
return "#28a745";
|
||||
};
|
||||
|
||||
window.normalizeRoadStatus = function (value) {
|
||||
var normalized = String(value || "").trim().toLowerCase();
|
||||
|
||||
if (normalized === "jalan nasional" || normalized === "nasional") {
|
||||
return "Jalan Nasional";
|
||||
}
|
||||
|
||||
if (normalized === "jalan provinsi" || normalized === "provinsi") {
|
||||
return "Jalan Provinsi";
|
||||
}
|
||||
|
||||
if (normalized === "jalan kabupaten" || normalized === "kabupaten") {
|
||||
return "Jalan Kabupaten";
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
window.serializeGeometry = function (latlngs) {
|
||||
return JSON.stringify(latlngs.map(function (point) {
|
||||
return [
|
||||
Number(point.lat.toFixed(6)),
|
||||
Number(point.lng.toFixed(6))
|
||||
];
|
||||
}));
|
||||
};
|
||||
|
||||
window.parseGeometry = function (geom) {
|
||||
try {
|
||||
var parsed = JSON.parse(geom);
|
||||
return Array.isArray(parsed) ? parsed : [];
|
||||
} catch (error) {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
window.collectRoadData = async function () {
|
||||
return window.openEditModal({
|
||||
title: "Tambah Jalan",
|
||||
subtitle: "Lengkapi atribut jalan untuk garis yang sudah digambar.",
|
||||
fields: [
|
||||
{ name: "nama", label: "Nama Jalan", value: "", required: true },
|
||||
{
|
||||
name: "status",
|
||||
label: "Status Jalan",
|
||||
type: "select",
|
||||
value: "Jalan Nasional",
|
||||
options: [
|
||||
{ value: "Jalan Nasional", label: "Jalan Nasional" },
|
||||
{ value: "Jalan Provinsi", label: "Jalan Provinsi" },
|
||||
{ value: "Jalan Kabupaten", label: "Jalan Kabupaten" }
|
||||
]
|
||||
}
|
||||
],
|
||||
validate: function (data) {
|
||||
if (!data.nama || !window.normalizeRoadStatus(data.status)) {
|
||||
return "Nama dan status jalan wajib valid.";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.buildRoadLayer = function (jalan) {
|
||||
var coordinates = window.parseGeometry(jalan.geom).map(function (point) {
|
||||
return L.latLng(point[0], point[1]);
|
||||
});
|
||||
|
||||
if (coordinates.length < 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return L.polyline(coordinates, {
|
||||
color: window.getRoadColor(jalan.status),
|
||||
weight: 4
|
||||
}).bindPopup(
|
||||
"<b>" + window.escapeHtml(jalan.nama) + "</b><br>" +
|
||||
"Status: " + window.escapeHtml(jalan.status) + "<br>" +
|
||||
"Panjang: " + window.formatMeters(jalan.panjang)
|
||||
);
|
||||
};
|
||||
+1007
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,567 @@
|
||||
window.appState = {
|
||||
mode: "view",
|
||||
activeType: "spbu",
|
||||
drawControl: null,
|
||||
layers: {},
|
||||
layerControl: null,
|
||||
layerVisibility: {
|
||||
spbu24: true,
|
||||
spbuTidak: true,
|
||||
kemiskinan: true,
|
||||
masjid: true,
|
||||
jalan: true,
|
||||
kavling: true
|
||||
}
|
||||
};
|
||||
|
||||
window.escapeHtml = function (value) {
|
||||
return String(value ?? "")
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'");
|
||||
};
|
||||
|
||||
window.createPointIcon = function (color) {
|
||||
return L.divIcon({
|
||||
className: "custom-point-icon",
|
||||
html: '<span class="point-dot" style="background:' + color + ';"></span>',
|
||||
iconSize: [18, 18],
|
||||
iconAnchor: [9, 9],
|
||||
popupAnchor: [0, -12]
|
||||
});
|
||||
};
|
||||
|
||||
window.greenIcon = window.createPointIcon("#28a745");
|
||||
window.redIcon = window.createPointIcon("#dc3545");
|
||||
window.orangeIcon = window.createPointIcon("#ff8c00");
|
||||
window.blueIcon = window.createPointIcon("#007bff");
|
||||
|
||||
window.calculateLineLength = function (latlngs) {
|
||||
var total = 0;
|
||||
|
||||
for (var i = 1; i < latlngs.length; i += 1) {
|
||||
total += map.distance(latlngs[i - 1], latlngs[i]);
|
||||
}
|
||||
|
||||
return total;
|
||||
};
|
||||
|
||||
window.calculatePolygonArea = function (latlngs) {
|
||||
if (L.GeometryUtil && typeof L.GeometryUtil.geodesicArea === "function") {
|
||||
return L.GeometryUtil.geodesicArea(latlngs);
|
||||
}
|
||||
|
||||
if (!latlngs.length) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var earthRadius = 6378137;
|
||||
var avgLat = latlngs.reduce(function (sum, point) {
|
||||
return sum + point.lat;
|
||||
}, 0) / latlngs.length;
|
||||
var avgLatRad = avgLat * Math.PI / 180;
|
||||
var projected = latlngs.map(function (point) {
|
||||
return {
|
||||
x: earthRadius * point.lng * Math.PI / 180 * Math.cos(avgLatRad),
|
||||
y: earthRadius * point.lat * Math.PI / 180
|
||||
};
|
||||
});
|
||||
var area = 0;
|
||||
|
||||
for (var i = 0; i < projected.length; i += 1) {
|
||||
var next = projected[(i + 1) % projected.length];
|
||||
area += (projected[i].x * next.y) - (next.x * projected[i].y);
|
||||
}
|
||||
|
||||
return Math.abs(area / 2);
|
||||
};
|
||||
|
||||
window.formatMeters = function (value) {
|
||||
return Number(value).toLocaleString("id-ID", {
|
||||
maximumFractionDigits: 2
|
||||
}) + " m";
|
||||
};
|
||||
|
||||
window.formatSquareMeters = function (value) {
|
||||
return Number(value).toLocaleString("id-ID", {
|
||||
maximumFractionDigits: 2
|
||||
}) + " m²";
|
||||
};
|
||||
|
||||
window.postForm = async function (url, payload) {
|
||||
var response = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded"
|
||||
},
|
||||
body: new URLSearchParams(payload)
|
||||
});
|
||||
var text = (await response.text()).trim();
|
||||
|
||||
if (!response.ok || text !== "success") {
|
||||
throw new Error(text || "Permintaan gagal.");
|
||||
}
|
||||
};
|
||||
|
||||
window.collectSpbuData = async function () {
|
||||
return window.openEditModal({
|
||||
title: "Tambah SPBU",
|
||||
subtitle: "Lengkapi atribut SPBU untuk titik yang dipilih di peta.",
|
||||
fields: [
|
||||
{ name: "nama", label: "Nama SPBU", value: "", required: true },
|
||||
{ name: "no", label: "Nomor SPBU", value: "", required: true },
|
||||
{
|
||||
name: "status",
|
||||
label: "Status Operasional",
|
||||
type: "select",
|
||||
value: "24jam",
|
||||
options: [
|
||||
{ value: "24jam", label: "24 Jam" },
|
||||
{ value: "tidak", label: "Tidak 24 Jam" }
|
||||
]
|
||||
}
|
||||
],
|
||||
validate: function (data) {
|
||||
if (!data.nama || !data.no) {
|
||||
return "Nama dan nomor SPBU wajib diisi.";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.collectKemiskinanData = async function () {
|
||||
return window.openEditModal({
|
||||
title: "Tambah Data Kemiskinan",
|
||||
subtitle: "Lengkapi data keluarga untuk titik yang dipilih di peta.",
|
||||
fields: [
|
||||
{ name: "nama_kepala_keluarga", label: "Nama Kepala Keluarga", value: "", required: true },
|
||||
{ name: "jumlah_kk", label: "Jumlah KK", type: "number", min: 1, step: 1, value: 1, required: true },
|
||||
{ name: "alamat", label: "Alamat", type: "textarea", value: "", required: true }
|
||||
],
|
||||
validate: function (data) {
|
||||
if (!data.nama_kepala_keluarga || !data.alamat) {
|
||||
return "Nama kepala keluarga dan alamat wajib diisi.";
|
||||
}
|
||||
if (!Number.isInteger(data.jumlah_kk) || data.jumlah_kk < 1) {
|
||||
return "Jumlah KK harus angka minimal 1.";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.collectMasjidData = async function () {
|
||||
return window.openEditModal({
|
||||
title: "Tambah Masjid",
|
||||
subtitle: "Lengkapi identitas masjid untuk titik yang dipilih di peta.",
|
||||
fields: [
|
||||
{ name: "nama_masjid", label: "Nama Masjid", value: "", required: true },
|
||||
{ name: "pic_masjid", label: "PIC Masjid", value: "", required: true },
|
||||
{ name: "alamat", label: "Alamat Masjid", type: "textarea", value: "", required: true },
|
||||
{ name: "radius", label: "Radius Jangkauan (meter)", type: "number", min: 100, max: 5000, step: 1, value: 500, required: true }
|
||||
],
|
||||
validate: function (data) {
|
||||
if (!data.nama_masjid || !data.pic_masjid || !data.alamat) {
|
||||
return "Nama, PIC, dan alamat masjid wajib diisi.";
|
||||
}
|
||||
if (!Number.isInteger(data.radius) || data.radius < 100 || data.radius > 5000) {
|
||||
return "Radius harus angka antara 100 sampai 5000 meter.";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.updateMapHint = function () {
|
||||
var hint = document.getElementById("mapHint");
|
||||
if (!hint) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (appState.mode === "view") {
|
||||
hint.textContent = "Mode lihat aktif. Data hanya ditampilkan di peta dan sidebar.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (appState.activeType === "spbu") {
|
||||
hint.textContent = "Mode edit SPBU aktif. Klik peta untuk menambahkan titik SPBU.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (appState.activeType === "kemiskinan") {
|
||||
hint.textContent = "Mode edit Kemiskinan aktif. Klik peta untuk menambahkan titik data kemiskinan.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (appState.activeType === "masjid") {
|
||||
hint.textContent = "Mode edit Masjid aktif. Klik peta untuk menambahkan titik masjid dengan radius awal 500 meter.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (appState.activeType === "jalan") {
|
||||
hint.textContent = "Mode edit Jalan aktif. Gunakan tool draw polyline pada peta.";
|
||||
return;
|
||||
}
|
||||
|
||||
hint.textContent = "Mode edit Kavling aktif. Gunakan tool draw polygon pada peta.";
|
||||
};
|
||||
|
||||
window.updateToolbarState = function () {
|
||||
var buttonStates = {
|
||||
modeViewBtn: appState.mode === "view",
|
||||
modeEditBtn: appState.mode === "edit",
|
||||
typeSpbuBtn: appState.activeType === "spbu",
|
||||
typeKemiskinanBtn: appState.activeType === "kemiskinan",
|
||||
typeMasjidBtn: appState.activeType === "masjid",
|
||||
typeJalanBtn: appState.activeType === "jalan",
|
||||
typeKavlingBtn: appState.activeType === "kavling"
|
||||
};
|
||||
|
||||
Object.keys(buttonStates).forEach(function (id) {
|
||||
var button = document.getElementById(id);
|
||||
if (button) {
|
||||
button.classList.toggle("active", buttonStates[id]);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.configureDrawControl = function () {
|
||||
if (!window.map) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (appState.drawControl) {
|
||||
map.removeControl(appState.drawControl);
|
||||
appState.drawControl = null;
|
||||
}
|
||||
|
||||
if (appState.mode !== "edit" || appState.activeType === "spbu" || appState.activeType === "kemiskinan" || appState.activeType === "masjid") {
|
||||
return;
|
||||
}
|
||||
|
||||
var drawOptions = {
|
||||
polyline: false,
|
||||
polygon: false,
|
||||
rectangle: false,
|
||||
circle: false,
|
||||
marker: false,
|
||||
circlemarker: false
|
||||
};
|
||||
|
||||
if (appState.activeType === "jalan") {
|
||||
drawOptions.polyline = {
|
||||
shapeOptions: {
|
||||
color: "#dc3545",
|
||||
weight: 4
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (appState.activeType === "kavling") {
|
||||
drawOptions.polygon = {
|
||||
allowIntersection: false,
|
||||
shapeOptions: {
|
||||
color: "#ff8c00",
|
||||
weight: 3,
|
||||
fillOpacity: 0.35
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
appState.drawControl = new L.Control.Draw({
|
||||
edit: false,
|
||||
draw: drawOptions
|
||||
});
|
||||
|
||||
map.addControl(appState.drawControl);
|
||||
};
|
||||
|
||||
window.setMode = function (mode) {
|
||||
appState.mode = mode;
|
||||
window.updateToolbarState();
|
||||
window.updateMapHint();
|
||||
window.configureDrawControl();
|
||||
|
||||
if (typeof window.loadAllData === "function") {
|
||||
window.loadAllData();
|
||||
}
|
||||
};
|
||||
|
||||
window.setDataType = function (type) {
|
||||
appState.activeType = type;
|
||||
window.updateToolbarState();
|
||||
window.updateMapHint();
|
||||
window.configureDrawControl();
|
||||
};
|
||||
|
||||
window.getLayerGroupByKey = function (key) {
|
||||
if (key === "spbu24") {
|
||||
return appState.layers.spbu24;
|
||||
}
|
||||
|
||||
if (key === "spbuTidak") {
|
||||
return appState.layers.spbuTidak;
|
||||
}
|
||||
|
||||
if (key === "kemiskinan") {
|
||||
return appState.layers.kemiskinan;
|
||||
}
|
||||
|
||||
if (key === "masjid") {
|
||||
return appState.layers.masjid;
|
||||
}
|
||||
|
||||
if (key === "jalan") {
|
||||
return appState.layers.jalan;
|
||||
}
|
||||
|
||||
if (key === "kavling") {
|
||||
return appState.layers.kavling;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
window.setLayerVisibility = function (key, isVisible) {
|
||||
appState.layerVisibility[key] = !!isVisible;
|
||||
|
||||
var layer = window.getLayerGroupByKey(key);
|
||||
if (!layer || !window.map) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isVisible) {
|
||||
if (!map.hasLayer(layer)) {
|
||||
map.addLayer(layer);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (map.hasLayer(layer)) {
|
||||
map.removeLayer(layer);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
window.map = L.map("map").setView([-0.0263, 109.3425], 13);
|
||||
|
||||
appState.layers.spbu24 = L.layerGroup().addTo(map);
|
||||
appState.layers.spbuTidak = L.layerGroup().addTo(map);
|
||||
appState.layers.kemiskinan = L.layerGroup().addTo(map);
|
||||
appState.layers.masjid = L.layerGroup().addTo(map);
|
||||
appState.layers.jalan = L.layerGroup().addTo(map);
|
||||
appState.layers.kavling = L.layerGroup().addTo(map);
|
||||
|
||||
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||
attribution: "© OpenStreetMap"
|
||||
}).addTo(map);
|
||||
|
||||
appState.layerControl = L.control.layers(null, {
|
||||
"SPBU 24 Jam": appState.layers.spbu24,
|
||||
"SPBU Tidak 24 Jam": appState.layers.spbuTidak,
|
||||
"Kemiskinan": appState.layers.kemiskinan,
|
||||
"Masjid": appState.layers.masjid,
|
||||
"Jalan": appState.layers.jalan,
|
||||
"Kavling": appState.layers.kavling
|
||||
}).addTo(map);
|
||||
|
||||
map.on("overlayadd", function (event) {
|
||||
if (event.layer === appState.layers.spbu24) {
|
||||
appState.layerVisibility.spbu24 = true;
|
||||
} else if (event.layer === appState.layers.spbuTidak) {
|
||||
appState.layerVisibility.spbuTidak = true;
|
||||
} else if (event.layer === appState.layers.kemiskinan) {
|
||||
appState.layerVisibility.kemiskinan = true;
|
||||
} else if (event.layer === appState.layers.masjid) {
|
||||
appState.layerVisibility.masjid = true;
|
||||
} else if (event.layer === appState.layers.jalan) {
|
||||
appState.layerVisibility.jalan = true;
|
||||
} else if (event.layer === appState.layers.kavling) {
|
||||
appState.layerVisibility.kavling = true;
|
||||
}
|
||||
|
||||
if (typeof window.refreshLayerFilterUI === "function") {
|
||||
window.refreshLayerFilterUI();
|
||||
}
|
||||
});
|
||||
|
||||
map.on("overlayremove", function (event) {
|
||||
if (event.layer === appState.layers.spbu24) {
|
||||
appState.layerVisibility.spbu24 = false;
|
||||
} else if (event.layer === appState.layers.spbuTidak) {
|
||||
appState.layerVisibility.spbuTidak = false;
|
||||
} else if (event.layer === appState.layers.kemiskinan) {
|
||||
appState.layerVisibility.kemiskinan = false;
|
||||
} else if (event.layer === appState.layers.masjid) {
|
||||
appState.layerVisibility.masjid = false;
|
||||
} else if (event.layer === appState.layers.jalan) {
|
||||
appState.layerVisibility.jalan = false;
|
||||
} else if (event.layer === appState.layers.kavling) {
|
||||
appState.layerVisibility.kavling = false;
|
||||
}
|
||||
|
||||
if (typeof window.refreshLayerFilterUI === "function") {
|
||||
window.refreshLayerFilterUI();
|
||||
}
|
||||
});
|
||||
|
||||
map.on("click", async function (event) {
|
||||
if (appState.mode !== "edit") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (appState.activeType === "spbu") {
|
||||
var spbuData = await window.collectSpbuData();
|
||||
if (!spbuData) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await window.postForm("php/create.php", {
|
||||
nama: spbuData.nama,
|
||||
no: spbuData.no,
|
||||
status: spbuData.status,
|
||||
lat: event.latlng.lat.toFixed(6),
|
||||
lng: event.latlng.lng.toFixed(6)
|
||||
});
|
||||
|
||||
await window.loadAllData();
|
||||
alert("Data SPBU berhasil disimpan.");
|
||||
} catch (error) {
|
||||
alert("Gagal menyimpan SPBU: " + error.message);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (appState.activeType === "kemiskinan") {
|
||||
var kemiskinanData = await window.collectKemiskinanData();
|
||||
if (!kemiskinanData) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await window.postForm("php/create_kemiskinan.php", {
|
||||
nama_kepala_keluarga: kemiskinanData.nama_kepala_keluarga,
|
||||
jumlah_kk: kemiskinanData.jumlah_kk,
|
||||
alamat: kemiskinanData.alamat,
|
||||
lat: event.latlng.lat.toFixed(6),
|
||||
lng: event.latlng.lng.toFixed(6)
|
||||
});
|
||||
|
||||
await window.loadAllData();
|
||||
alert("Data kemiskinan berhasil disimpan.");
|
||||
} catch (error) {
|
||||
alert("Gagal menyimpan data kemiskinan: " + error.message);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (appState.activeType === "masjid") {
|
||||
var masjidData = await window.collectMasjidData();
|
||||
if (!masjidData) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await window.postForm("php/create_masjid.php", {
|
||||
nama_masjid: masjidData.nama_masjid,
|
||||
pic_masjid: masjidData.pic_masjid,
|
||||
alamat: masjidData.alamat,
|
||||
radius: masjidData.radius,
|
||||
lat: event.latlng.lat.toFixed(6),
|
||||
lng: event.latlng.lng.toFixed(6)
|
||||
});
|
||||
|
||||
await window.loadAllData();
|
||||
alert("Data masjid berhasil disimpan.");
|
||||
} catch (error) {
|
||||
alert("Gagal menyimpan data masjid: " + error.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
map.on(L.Draw.Event.CREATED, async function (event) {
|
||||
var layer = event.layer;
|
||||
|
||||
if (appState.mode !== "edit") {
|
||||
alert("Pindah ke mode edit sebelum menggambar data.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.layerType === "polyline") {
|
||||
if (appState.activeType !== "jalan") {
|
||||
alert("Tipe aktif saat ini bukan Jalan.");
|
||||
return;
|
||||
}
|
||||
|
||||
var lineLatLngs = layer.getLatLngs();
|
||||
var panjang = window.calculateLineLength(lineLatLngs);
|
||||
var roadData = await window.collectRoadData();
|
||||
|
||||
if (!roadData) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await window.postForm("php/create_line.php", {
|
||||
nama: roadData.nama,
|
||||
status: roadData.status,
|
||||
panjang: panjang.toFixed(2),
|
||||
geom: window.serializeGeometry(lineLatLngs)
|
||||
});
|
||||
|
||||
await window.loadAllData();
|
||||
alert("Data jalan berhasil disimpan.");
|
||||
} catch (error) {
|
||||
alert("Gagal menyimpan jalan: " + error.message);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.layerType === "polygon") {
|
||||
if (appState.activeType !== "kavling") {
|
||||
alert("Tipe aktif saat ini bukan Kavling.");
|
||||
return;
|
||||
}
|
||||
|
||||
var polygonLatLngs = layer.getLatLngs()[0] || [];
|
||||
var luas = window.calculatePolygonArea(polygonLatLngs);
|
||||
var landData = await window.collectPolygonData();
|
||||
|
||||
if (!landData) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await window.postForm("php/create_polygon.php", {
|
||||
nama: landData.nama,
|
||||
status: landData.status,
|
||||
luas: luas.toFixed(2),
|
||||
geom: window.serializeGeometry(polygonLatLngs)
|
||||
});
|
||||
|
||||
await window.loadAllData();
|
||||
alert("Data kavling berhasil disimpan.");
|
||||
} catch (error) {
|
||||
alert("Gagal menyimpan kavling: " + error.message);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
window.setMode("view");
|
||||
window.setDataType("spbu");
|
||||
|
||||
setTimeout(function () {
|
||||
map.invalidateSize();
|
||||
}, 300);
|
||||
|
||||
if (typeof window.loadAllData === "function") {
|
||||
window.loadAllData();
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,77 @@
|
||||
window.getPolygonColor = function (status) {
|
||||
if (status === "SHM") {
|
||||
return "#ff8c00";
|
||||
}
|
||||
|
||||
if (status === "HGB") {
|
||||
return "#6f42c1";
|
||||
}
|
||||
|
||||
if (status === "HGU") {
|
||||
return "#20c997";
|
||||
}
|
||||
|
||||
return "#6c757d";
|
||||
};
|
||||
|
||||
window.normalizePolygonStatus = function (value) {
|
||||
var normalized = String(value || "").trim().toUpperCase();
|
||||
var allowed = ["SHM", "HGB", "HGU", "HP"];
|
||||
|
||||
if (allowed.indexOf(normalized) === -1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return normalized;
|
||||
};
|
||||
|
||||
window.collectPolygonData = async function () {
|
||||
return window.openEditModal({
|
||||
title: "Tambah Kavling",
|
||||
subtitle: "Lengkapi atribut kavling untuk polygon yang sudah digambar.",
|
||||
fields: [
|
||||
{ name: "nama", label: "Nama Kavling", value: "", required: true },
|
||||
{
|
||||
name: "status",
|
||||
label: "Status Kavling",
|
||||
type: "select",
|
||||
value: "SHM",
|
||||
options: [
|
||||
{ value: "SHM", label: "SHM" },
|
||||
{ value: "HGB", label: "HGB" },
|
||||
{ value: "HGU", label: "HGU" },
|
||||
{ value: "HP", label: "HP" }
|
||||
]
|
||||
}
|
||||
],
|
||||
validate: function (data) {
|
||||
if (!data.nama || !window.normalizePolygonStatus(data.status)) {
|
||||
return "Nama dan status kavling wajib valid.";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
window.buildPolygonLayer = function (kavling) {
|
||||
var coordinates = window.parseGeometry(kavling.geom).map(function (point) {
|
||||
return L.latLng(point[0], point[1]);
|
||||
});
|
||||
|
||||
if (coordinates.length < 3) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var color = window.getPolygonColor(kavling.status);
|
||||
|
||||
return L.polygon(coordinates, {
|
||||
color: color,
|
||||
fillColor: color,
|
||||
fillOpacity: 0.35,
|
||||
weight: 3
|
||||
}).bindPopup(
|
||||
"<b>" + window.escapeHtml(kavling.nama) + "</b><br>" +
|
||||
"Status: " + window.escapeHtml(kavling.status) + "<br>" +
|
||||
"Luas: " + window.formatSquareMeters(kavling.luas)
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$nama = trim($_POST['nama'] ?? '');
|
||||
$nomor = trim($_POST['no'] ?? '');
|
||||
$status = trim($_POST['status'] ?? '');
|
||||
$latitudeRaw = $_POST['lat'] ?? null;
|
||||
$longitudeRaw = $_POST['lng'] ?? null;
|
||||
$latitude = is_numeric($latitudeRaw) ? (float) $latitudeRaw : null;
|
||||
$longitude = is_numeric($longitudeRaw) ? (float) $longitudeRaw : null;
|
||||
$allowedStatus = ['24jam', 'tidak'];
|
||||
|
||||
if ($nama === '' || $nomor === '' || !in_array($status, $allowedStatus, true) || $latitude === null || $longitude === null) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare(
|
||||
$conn,
|
||||
"INSERT INTO spbu (nama, no_spbu, status, latitude, longitude) VALUES (?, ?, ?, ?, ?)"
|
||||
);
|
||||
|
||||
mysqli_stmt_bind_param($statement, "sssdd", $nama, $nomor, $status, $latitude, $longitude);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$namaKepalaKeluarga = trim($_POST['nama_kepala_keluarga'] ?? '');
|
||||
$jumlahKkRaw = $_POST['jumlah_kk'] ?? null;
|
||||
$jumlahKk = filter_var($jumlahKkRaw, FILTER_VALIDATE_INT);
|
||||
$alamat = trim($_POST['alamat'] ?? '');
|
||||
$latitudeRaw = $_POST['lat'] ?? null;
|
||||
$longitudeRaw = $_POST['lng'] ?? null;
|
||||
$latitude = is_numeric($latitudeRaw) ? (float) $latitudeRaw : null;
|
||||
$longitude = is_numeric($longitudeRaw) ? (float) $longitudeRaw : null;
|
||||
|
||||
if ($namaKepalaKeluarga === '' || $alamat === '' || $jumlahKk === false || $jumlahKk === null || $jumlahKk < 1 || $latitude === null || $longitude === null) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = null;
|
||||
|
||||
try {
|
||||
$statement = mysqli_prepare(
|
||||
$conn,
|
||||
"INSERT INTO kemiskinan (nama_kepala_keluarga, jumlah_kk, alamat, latitude, longitude) VALUES (?, ?, ?, ?, ?)"
|
||||
);
|
||||
|
||||
mysqli_stmt_bind_param($statement, "sisdd", $namaKepalaKeluarga, $jumlahKk, $alamat, $latitude, $longitude);
|
||||
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
if ($statement) {
|
||||
mysqli_stmt_close($statement);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$nama = trim($_POST['nama'] ?? '');
|
||||
$status = trim($_POST['status'] ?? '');
|
||||
$panjangRaw = $_POST['panjang'] ?? null;
|
||||
$panjang = is_numeric($panjangRaw) ? (float) $panjangRaw : null;
|
||||
$geom = trim($_POST['geom'] ?? '');
|
||||
$allowedStatus = ['Jalan Nasional', 'Jalan Provinsi', 'Jalan Kabupaten'];
|
||||
|
||||
if ($nama === '' || $geom === '' || !in_array($status, $allowedStatus, true) || $panjang === null) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare(
|
||||
$conn,
|
||||
"INSERT INTO jalan (nama, status, panjang, geom) VALUES (?, ?, ?, ?)"
|
||||
);
|
||||
|
||||
mysqli_stmt_bind_param($statement, "ssds", $nama, $status, $panjang, $geom);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$namaMasjid = trim($_POST['nama_masjid'] ?? '');
|
||||
$picMasjid = trim($_POST['pic_masjid'] ?? '');
|
||||
$alamat = trim($_POST['alamat'] ?? '');
|
||||
$latitudeRaw = $_POST['lat'] ?? null;
|
||||
$longitudeRaw = $_POST['lng'] ?? null;
|
||||
$radiusRaw = $_POST['radius'] ?? 500;
|
||||
$latitude = is_numeric($latitudeRaw) ? (float) $latitudeRaw : null;
|
||||
$longitude = is_numeric($longitudeRaw) ? (float) $longitudeRaw : null;
|
||||
$radius = is_numeric($radiusRaw) ? (float) $radiusRaw : null;
|
||||
|
||||
if ($namaMasjid === '' || $picMasjid === '' || $alamat === '' || $latitude === null || $longitude === null || $radius === null || $radius < 100 || $radius > 5000) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = null;
|
||||
|
||||
try {
|
||||
$statement = mysqli_prepare(
|
||||
$conn,
|
||||
"INSERT INTO masjid (nama_masjid, pic_masjid, alamat, latitude, longitude, radius) VALUES (?, ?, ?, ?, ?, ?)"
|
||||
);
|
||||
|
||||
mysqli_stmt_bind_param($statement, "sssddd", $namaMasjid, $picMasjid, $alamat, $latitude, $longitude, $radius);
|
||||
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
if ($statement) {
|
||||
mysqli_stmt_close($statement);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$nama = trim($_POST['nama'] ?? '');
|
||||
$status = trim($_POST['status'] ?? '');
|
||||
$luasRaw = $_POST['luas'] ?? null;
|
||||
$luas = is_numeric($luasRaw) ? (float) $luasRaw : null;
|
||||
$geom = trim($_POST['geom'] ?? '');
|
||||
$allowedStatus = ['SHM', 'HGB', 'HGU', 'HP'];
|
||||
|
||||
if ($nama === '' || $geom === '' || !in_array($status, $allowedStatus, true) || $luas === null) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare(
|
||||
$conn,
|
||||
"INSERT INTO kavling (nama, status, luas, geom) VALUES (?, ?, ?, ?)"
|
||||
);
|
||||
|
||||
mysqli_stmt_bind_param($statement, "ssds", $nama, $status, $luas, $geom);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$idRaw = $_POST['id'] ?? null;
|
||||
$id = filter_var($idRaw, FILTER_VALIDATE_INT);
|
||||
|
||||
if ($id === false || $id === null || $id <= 0) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare($conn, "DELETE FROM spbu WHERE id = ?");
|
||||
mysqli_stmt_bind_param($statement, "i", $id);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$idRaw = $_POST['id'] ?? null;
|
||||
$id = filter_var($idRaw, FILTER_VALIDATE_INT);
|
||||
|
||||
if ($id === false || $id === null || $id <= 0) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare($conn, "DELETE FROM kemiskinan WHERE id = ?");
|
||||
mysqli_stmt_bind_param($statement, "i", $id);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$idRaw = $_POST['id'] ?? null;
|
||||
$id = filter_var($idRaw, FILTER_VALIDATE_INT);
|
||||
|
||||
if ($id === false || $id === null || $id <= 0) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare($conn, "DELETE FROM jalan WHERE id = ?");
|
||||
mysqli_stmt_bind_param($statement, "i", $id);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$idRaw = $_POST['id'] ?? null;
|
||||
$id = filter_var($idRaw, FILTER_VALIDATE_INT);
|
||||
|
||||
if ($id === false || $id === null || $id <= 0) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare($conn, "DELETE FROM masjid WHERE id = ?");
|
||||
mysqli_stmt_bind_param($statement, "i", $id);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$idRaw = $_POST['id'] ?? null;
|
||||
$id = filter_var($idRaw, FILTER_VALIDATE_INT);
|
||||
|
||||
if ($id === false || $id === null || $id <= 0) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare($conn, "DELETE FROM kavling WHERE id = ?");
|
||||
mysqli_stmt_bind_param($statement, "i", $id);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
$conn = mysqli_connect("127.0.0.1", "root", "", "webgis_spbu");
|
||||
|
||||
if (!$conn) {
|
||||
die("Koneksi gagal: " . mysqli_connect_error());
|
||||
}
|
||||
|
||||
mysqli_set_charset($conn, "utf8mb4");
|
||||
|
||||
$bootstrapQueries = [
|
||||
"CREATE TABLE IF NOT EXISTS kemiskinan (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama_kepala_keluarga VARCHAR(150) NOT NULL,
|
||||
jumlah_kk INT NOT NULL,
|
||||
alamat TEXT NOT NULL,
|
||||
latitude DOUBLE NOT NULL,
|
||||
longitude DOUBLE NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)",
|
||||
"CREATE TABLE IF NOT EXISTS masjid (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
nama_masjid VARCHAR(150) NOT NULL,
|
||||
pic_masjid VARCHAR(150) NOT NULL,
|
||||
alamat TEXT NOT NULL,
|
||||
latitude DOUBLE NOT NULL,
|
||||
longitude DOUBLE NOT NULL,
|
||||
radius DOUBLE NOT NULL DEFAULT 500,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
)"
|
||||
];
|
||||
|
||||
foreach ($bootstrapQueries as $query) {
|
||||
mysqli_query($conn, $query);
|
||||
}
|
||||
?>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$query = "SELECT * FROM spbu ORDER BY id DESC";
|
||||
$result = mysqli_query($conn, $query);
|
||||
$data = [];
|
||||
|
||||
if ($result) {
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$data[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($data);
|
||||
?>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$query = "SELECT * FROM kemiskinan ORDER BY id DESC";
|
||||
$result = mysqli_query($conn, $query);
|
||||
$data = [];
|
||||
|
||||
if ($result) {
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$data[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($data);
|
||||
?>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$query = "SELECT * FROM jalan ORDER BY id DESC";
|
||||
$result = mysqli_query($conn, $query);
|
||||
$data = [];
|
||||
|
||||
if ($result) {
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$data[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($data);
|
||||
?>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$query = "SELECT * FROM masjid ORDER BY id DESC";
|
||||
$result = mysqli_query($conn, $query);
|
||||
$data = [];
|
||||
|
||||
if ($result) {
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$data[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($data);
|
||||
?>
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
|
||||
$query = "SELECT * FROM kavling ORDER BY id DESC";
|
||||
$result = mysqli_query($conn, $query);
|
||||
$data = [];
|
||||
|
||||
if ($result) {
|
||||
while ($row = mysqli_fetch_assoc($result)) {
|
||||
$data[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($data);
|
||||
?>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$idRaw = $_POST['id'] ?? null;
|
||||
$id = filter_var($idRaw, FILTER_VALIDATE_INT);
|
||||
$nama = trim($_POST['nama'] ?? '');
|
||||
$nomor = trim($_POST['no'] ?? '');
|
||||
$status = trim($_POST['status'] ?? '');
|
||||
$allowedStatus = ['24jam', 'tidak'];
|
||||
|
||||
if ($id === false || $id === null || $id <= 0 || $nama === '' || $nomor === '' || !in_array($status, $allowedStatus, true)) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare(
|
||||
$conn,
|
||||
"UPDATE spbu SET nama = ?, no_spbu = ?, status = ? WHERE id = ?"
|
||||
);
|
||||
|
||||
mysqli_stmt_bind_param($statement, "sssi", $nama, $nomor, $status, $id);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$idRaw = $_POST['id'] ?? null;
|
||||
$id = filter_var($idRaw, FILTER_VALIDATE_INT);
|
||||
$namaKepalaKeluarga = trim($_POST['nama_kepala_keluarga'] ?? '');
|
||||
$jumlahKkRaw = $_POST['jumlah_kk'] ?? null;
|
||||
$jumlahKk = filter_var($jumlahKkRaw, FILTER_VALIDATE_INT);
|
||||
$alamat = trim($_POST['alamat'] ?? '');
|
||||
|
||||
if ($id === false || $id === null || $id <= 0 || $namaKepalaKeluarga === '' || $jumlahKk === false || $jumlahKk === null || $jumlahKk < 1 || $alamat === '') {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare(
|
||||
$conn,
|
||||
"UPDATE kemiskinan SET nama_kepala_keluarga = ?, jumlah_kk = ?, alamat = ? WHERE id = ?"
|
||||
);
|
||||
|
||||
mysqli_stmt_bind_param($statement, "sisi", $namaKepalaKeluarga, $jumlahKk, $alamat, $id);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$idRaw = $_POST['id'] ?? null;
|
||||
$id = filter_var($idRaw, FILTER_VALIDATE_INT);
|
||||
$nama = trim($_POST['nama'] ?? '');
|
||||
$status = trim($_POST['status'] ?? '');
|
||||
$allowedStatus = ['Jalan Nasional', 'Jalan Provinsi', 'Jalan Kabupaten'];
|
||||
|
||||
if ($id === false || $id === null || $id <= 0 || $nama === '' || !in_array($status, $allowedStatus, true)) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare(
|
||||
$conn,
|
||||
"UPDATE jalan SET nama = ?, status = ? WHERE id = ?"
|
||||
);
|
||||
|
||||
mysqli_stmt_bind_param($statement, "ssi", $nama, $status, $id);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$idRaw = $_POST['id'] ?? null;
|
||||
$id = filter_var($idRaw, FILTER_VALIDATE_INT);
|
||||
$namaMasjid = trim($_POST['nama_masjid'] ?? '');
|
||||
$picMasjid = trim($_POST['pic_masjid'] ?? '');
|
||||
$alamat = trim($_POST['alamat'] ?? '');
|
||||
$radiusRaw = $_POST['radius'] ?? null;
|
||||
$radius = is_numeric($radiusRaw) ? (float) $radiusRaw : null;
|
||||
|
||||
if ($id === false || $id === null || $id <= 0 || $namaMasjid === '' || $picMasjid === '' || $alamat === '' || $radius === null || $radius < 100 || $radius > 5000) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare(
|
||||
$conn,
|
||||
"UPDATE masjid SET nama_masjid = ?, pic_masjid = ?, alamat = ?, radius = ? WHERE id = ?"
|
||||
);
|
||||
|
||||
mysqli_stmt_bind_param($statement, "sssdi", $namaMasjid, $picMasjid, $alamat, $radius, $id);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$idRaw = $_POST['id'] ?? null;
|
||||
$radiusRaw = $_POST['radius'] ?? null;
|
||||
$id = filter_var($idRaw, FILTER_VALIDATE_INT);
|
||||
$radius = is_numeric($radiusRaw) ? (float) $radiusRaw : null;
|
||||
|
||||
if ($id === false || $id === null || $id <= 0 || $radius === null || $radius < 100 || $radius > 5000) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare($conn, "UPDATE masjid SET radius = ? WHERE id = ?");
|
||||
mysqli_stmt_bind_param($statement, "di", $radius, $id);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
include 'koneksi.php';
|
||||
|
||||
$idRaw = $_POST['id'] ?? null;
|
||||
$id = filter_var($idRaw, FILTER_VALIDATE_INT);
|
||||
$nama = trim($_POST['nama'] ?? '');
|
||||
$status = trim($_POST['status'] ?? '');
|
||||
$allowedStatus = ['SHM', 'HGB', 'HGU', 'HP'];
|
||||
|
||||
if ($id === false || $id === null || $id <= 0 || $nama === '' || !in_array($status, $allowedStatus, true)) {
|
||||
http_response_code(400);
|
||||
exit('error');
|
||||
}
|
||||
|
||||
$statement = mysqli_prepare(
|
||||
$conn,
|
||||
"UPDATE kavling SET nama = ?, status = ? WHERE id = ?"
|
||||
);
|
||||
|
||||
mysqli_stmt_bind_param($statement, "ssi", $nama, $status, $id);
|
||||
|
||||
try {
|
||||
if (mysqli_stmt_execute($statement)) {
|
||||
echo 'success';
|
||||
} else {
|
||||
http_response_code(500);
|
||||
echo 'error';
|
||||
}
|
||||
} catch (mysqli_sql_exception $exception) {
|
||||
http_response_code(500);
|
||||
echo 'error: ' . $exception->getMessage();
|
||||
}
|
||||
|
||||
mysqli_stmt_close($statement);
|
||||
?>
|
||||
Reference in New Issue
Block a user