Upload files to "/"

This commit is contained in:
2026-06-12 17:50:24 +00:00
parent baa1bca6cc
commit 77051fb0c5
5 changed files with 237 additions and 495 deletions
+6 -2
View File
@@ -1,4 +1,8 @@
<?php
$conn=new mysqli("localhost","root","","gis_spbu");
$conn->query("DELETE FROM kavling WHERE id=$_POST[id]");
require_once 'koneksi.php';
$id = (int)($_POST['id'] ?? 0);
$stmt = $conn->prepare("DELETE FROM kavling WHERE id=?");
$stmt->bind_param('i', $id);
$stmt->execute();
echo json_encode(['status' => 'success']);
?>
+143 -475
View File
@@ -1,485 +1,153 @@
<!DOCTYPE html>
<html lang="en">
<html lang="id">
<head>
<meta charset="utf-8">
<title>GIS SPBU</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"/>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-geometryutil/0.10.2/leaflet.geometryutil.min.js"></script>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Landing Page Tugas SIG - Freya</title>
<style>
html, body {height:100%; margin:0;}
#map {height:100%;}
input, select {width:100%; margin-bottom:5px;}
button {margin-top:5px;}
</style>
<style>
html, body {height:100%; margin:0;}
#map {height:100%;}
input, select {width:100%; margin-bottom:5px;}
button {margin-top:5px;}
/* ===== LEGENDA ===== */
.legend {
:root {
--bg: #f6f7fb;
--card: #ffffff;
--text: #1f2937;
--muted: #6b7280;
--line: #e5e7eb;
--primary: #111827;
--soft: #f3f4f6;
}
* { box-sizing: border-box; }
body {
margin: 0;
font-family: Arial, Helvetica, sans-serif;
background: var(--bg);
color: var(--text);
}
header {
background: var(--primary);
color: white;
padding: 42px 24px;
text-align: center;
}
header h1 {
margin: 0 0 10px;
font-size: clamp(26px, 4vw, 42px);
}
header p {
margin: 0;
color: #d1d5db;
}
main {
max-width: 1120px;
margin: -28px auto 48px;
padding: 0 18px;
}
.grid {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 18px;
}
.card {
background: var(--card);
border: 1px solid var(--line);
border-radius: 18px;
padding: 22px;
box-shadow: 0 8px 24px rgba(17,24,39,.08);
min-height: 260px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.badge {
display: inline-block;
padding: 7px 10px;
border-radius: 999px;
background: var(--soft);
color: #374151;
font-size: 12px;
font-weight: 700;
margin-bottom: 16px;
}
.card h2 {
margin: 0 0 10px;
font-size: 20px;
}
.card p {
margin: 0 0 18px;
color: var(--muted);
line-height: 1.55;
font-size: 14px;
}
a.btn {
display: inline-block;
text-decoration: none;
background: var(--primary);
color: white;
padding: 11px 14px;
border-radius: 12px;
font-weight: 700;
text-align: center;
}
.info {
background: white;
padding: 10px;
line-height: 18px;
color: #333;
border-radius: 5px;
box-shadow: 0 0 5px rgba(0,0,0,0.3);
}
.legend i {
width: 18px;
height: 18px;
float: left;
margin-right: 8px;
opacity: 0.8;
border: 1px solid var(--line);
border-radius: 16px;
padding: 18px 20px;
margin-top: 18px;
color: var(--muted);
line-height: 1.55;
}
code { background: #f3f4f6; padding: 2px 6px; border-radius: 6px; color: #111827; }
@media (max-width: 900px) { .grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .grid { grid-template-columns: 1fr; } main { margin-top: -18px; } }
</style>
</head>
<body>
<div id="map"></div>
<script>
// ================= MAP =================
const map = L.map('map').setView([-0.02, 109.34], 13);
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png').addTo(map);
// ================= GEOJSON KECAMATAN =================
fetch("Admin_Kecamatan.json")
.then(res => res.json())
.then(data => {
const geojsonLayer = L.geoJSON(data, {
style: function(feature) {
const nama = feature.properties.Ket;
let warna = "gray";
if(nama == "Pontianak Timur") warna = "pink";
else if(nama == "Pontianak Barat") warna = "skyblue";
else if(nama == "Pontianak Kota") warna = "gold";
else if(nama == "Pontianak Selatan") warna = "violet";
else if(nama == "Pontianak Tenggara") warna = "sienna";
else if(nama == "Pontianak Utara") warna = "slategray";
return {
color: "black",
weight: 2,
fillColor: warna,
fillOpacity: 0.5,
interactive: false
};
},
onEachFeature: function(feature, layer) {
const nama = feature.properties.Ket || "Tidak ada nama";
const populasi = feature.properties.Populasi || "Tidak ada data";
layer.bindPopup(`
<b>Kecamatan:</b> ${nama}<br>
<b>Populasi:</b> ${populasi}
`);
}
});
geojsonLayer.addTo(map);
});
// ================= ICON SPBU =================
const iconHijau = new L.Icon({
iconUrl:'https://maps.google.com/mapfiles/ms/icons/green-dot.png',
iconSize:[32,32]
});
const iconMerah = new L.Icon({
iconUrl:'https://maps.google.com/mapfiles/ms/icons/red-dot.png',
iconSize:[32,32]
});
// ================= LAYER GROUP SPBU =================
const spbuBuka = L.layerGroup();
const spbuTutup = L.layerGroup();
// ================= FORM SPBU =================
function formPopup(lat,lng){
return `
<b>Input SPBU</b><br>
Nama:<input id="nama"><br>
WA:<input id="wa"><br>
Buka 24 Jam:
<select id="buka">
<option>Iya</option>
<option>Tidak</option>
</select><br>
<button onclick="simpan(${lat},${lng})">Simpan</button>
<button onclick="map.closePopup()">Batal</button>
`;
}
map.on('click',function(e){
L.popup().setLatLng(e.latlng)
.setContent(formPopup(e.latlng.lat,e.latlng.lng))
.openOn(map);
});
// ================= SIMPAN SPBU =================
function simpan(lat,lng){
const nama=document.getElementById("nama").value;
const wa=document.getElementById("wa").value;
const buka=document.getElementById("buka").value;
fetch("simpan.php",{
method:"POST",
headers:{"Content-Type":"application/x-www-form-urlencoded"},
body:`nama=${nama}&wa=${wa}&buka=${buka}&lat=${lat}&lng=${lng}`
}).then(()=>location.reload());
}
// ================= LOAD SPBU =================
fetch("ambil.php")
.then(res=>res.json())
.then(data=>{
data.forEach(d=>{
const icon = d.buka=="Iya" ? iconHijau : iconMerah;
const marker = L.marker([d.lat,d.lng],{icon})
.bindPopup(`
<b>${d.nama}</b><br>
WA: ${d.wa}<br>
${d.buka=="Iya"?"🟢 Buka 24 Jam":"🔴 Tidak Buka 24 Jam"}<br><br>
<button onclick="editSPBU(${d.id},'${d.nama.replace(/'/g,"")}','${d.wa}','${d.buka}',${d.lat},${d.lng})">Edit</button>
<button onclick="hapusSPBU(${d.id})">Hapus</button>
`);
if(d.buka=="Iya"){
marker.addTo(spbuBuka);
}else{
marker.addTo(spbuTutup);
}
});
});
// ================= EDIT SPBU =================
function editSPBU(id,nama,wa,buka,lat,lng){
const form=`
Nama:<input id="nama" value="${nama}"><br>
WA:<input id="wa" value="${wa}"><br>
<select id="buka">
<option ${buka=="Iya"?"selected":""}>Iya</option>
<option ${buka=="Tidak"?"selected":""}>Tidak</option>
</select><br>
<button onclick="updateSPBU(${id})">Update</button>
`;
L.popup().setLatLng([lat,lng]).setContent(form).openOn(map);
}
function updateSPBU(id){
const nama=document.getElementById("nama").value;
const wa=document.getElementById("wa").value;
const buka=document.getElementById("buka").value;
fetch("update.php",{
method:"POST",
headers:{"Content-Type":"application/x-www-form-urlencoded"},
body:`id=${id}&nama=${nama}&wa=${wa}&buka=${buka}`
}).then(()=>location.reload());
}
function hapusSPBU(id){
if(confirm("Hapus SPBU?")){
fetch("hapus.php",{
method:"POST",
headers:{"Content-Type":"application/x-www-form-urlencoded"},
body:`id=${id}`
}).then(()=>location.reload());
}
}
// ================= DRAW =================
const drawnItems=new L.FeatureGroup();
map.addLayer(drawnItems);
const drawControl=new L.Control.Draw({
edit:{featureGroup:drawnItems},
draw:{marker:false,polyline:true,polygon:true}
});
map.addControl(drawControl);
// ================= FORM JALAN =================
function formJalan(latlngs){
return `
<b>Input Jalan</b><br>
Nama:<input id="nama_jalan"><br>
Status:
<select id="status_jalan">
<option>Nasional</option>
<option>Provinsi</option>
<option>Kabupaten</option>
</select><br>
<button onclick='simpanJalan(${JSON.stringify(latlngs)})'>Simpan</button>
`;
}
// ================= FORM KAVLING =================
function formKavling(latlngs){
return `
<b>Input Kavling</b><br>
Pemilik:<input id="pemilik"><br>
Status:
<select id="status_kavling">
<option>SHM</option>
<option>HGB</option>
<option>HGU</option>
<option>HP</option>
</select><br>
<button onclick='simpanKavling(${JSON.stringify(latlngs)})'>Simpan</button>
`;
}
// ================= DRAW EVENT =================
map.on(L.Draw.Event.CREATED,function(e){
const layer=e.layer;
drawnItems.addLayer(layer);
if(e.layerType==="polyline"){
const latlngs=layer.getLatLngs();
L.popup().setLatLng(layer.getBounds().getCenter())
.setContent(formJalan(latlngs)).openOn(map);
}
if(e.layerType==="polygon"){
const latlngs=layer.getLatLngs()[0];
L.popup().setLatLng(layer.getBounds().getCenter())
.setContent(formKavling(latlngs)).openOn(map);
}
});
// ================= SIMPAN JALAN =================
function simpanJalan(latlngs){
const nama=document.getElementById("nama_jalan").value;
const status=document.getElementById("status_jalan").value;
let panjang=0;
for(let i=0;i<latlngs.length-1;i++){
panjang+=map.distance(latlngs[i],latlngs[i+1]);
}
fetch("simpan_jalan.php",{
method:"POST",
headers:{"Content-Type":"application/x-www-form-urlencoded"},
body:`nama=${nama}&status=${status}&panjang=${panjang}&geom=${JSON.stringify(latlngs)}`
}).then(()=>location.reload());
}
// ================= SIMPAN KAVLING =================
function simpanKavling(latlngs){
const pemilik=document.getElementById("pemilik").value;
const status=document.getElementById("status_kavling").value;
let luas=L.GeometryUtil.geodesicArea(latlngs);
fetch("simpan_kavling.php",{
method:"POST",
headers:{"Content-Type":"application/x-www-form-urlencoded"},
body:`pemilik=${pemilik}&status=${status}&luas=${luas}&geom=${JSON.stringify(latlngs)}`
}).then(()=>location.reload());
}
// ================= LOAD JALAN =================
fetch("ambil_jalan.php")
.then(res=>res.json())
.then(data=>{
data.forEach(d=>{
const coords=JSON.parse(d.geom);
let warna="blue";
if(d.status=="Nasional") warna="red";
if(d.status=="Provinsi") warna="green";
if(d.status=="Kabupaten") warna="orange";
L.polyline(coords,{color:warna})
.addTo(map)
.bindPopup(`
<b>${d.nama}</b><br>
Status: Jalan ${d.status}<br>
Panjang: ${parseFloat(d.panjang).toFixed(2)} meter<br><br>
<button onclick="editJalan(${d.id},'${d.nama.replace(/'/g,"")}','${d.status}',${coords[0].lat},${coords[0].lng})">Edit</button>
<button onclick="hapusJalan(${d.id})">Hapus</button>
`);
});
});
// ================= LOAD KAVLING =================
fetch("ambil_kavling.php")
.then(res=>res.json())
.then(data=>{
data.forEach(d=>{
const coords=JSON.parse(d.geom);
let warna="purple";
if(d.status=="SHM") warna="green";
if(d.status=="HGB") warna="blue";
if(d.status=="HGU") warna="orange";
if(d.status=="HP") warna="red";
L.polygon(coords,{color:warna})
.addTo(map)
.bindPopup(`
<b>${d.pemilik}</b><br>
Status: ${d.status}<br>
Luas: ${parseFloat(d.luas).toFixed(2)} m²<br><br>
<button onclick="editKavling(${d.id},'${d.pemilik.replace(/'/g,"")}','${d.status}',${coords[0].lat},${coords[0].lng})">Edit</button>
<button onclick="hapusKavling(${d.id})">Hapus</button>
`);
});
});
// ================= EDIT JALAN =================
function editJalan(id,nama,status,lat,lng){
const form=`
<b>Edit Jalan</b><br>
Nama:<input id="nama_jalan" value="${nama}"><br>
<select id="status_jalan">
<option ${status=="Nasional"?"selected":""}>Nasional</option>
<option ${status=="Provinsi"?"selected":""}>Provinsi</option>
<option ${status=="Kabupaten"?"selected":""}>Kabupaten</option>
</select><br>
<button onclick="updateJalan(${id})">Update</button>
`;
L.popup().setLatLng([lat,lng]).setContent(form).openOn(map);
}
function updateJalan(id){
const nama=document.getElementById("nama_jalan").value;
const status=document.getElementById("status_jalan").value;
fetch("update_jalan.php",{
method:"POST",
headers:{"Content-Type":"application/x-www-form-urlencoded"},
body:`id=${id}&nama=${nama}&status=${status}`
}).then(()=>location.reload());
}
// ================= EDIT KAVLING =================
function editKavling(id,pemilik,status,lat,lng){
const form=`
<b>Edit Kavling</b><br>
Pemilik:<input id="pemilik" value="${pemilik}"><br>
<select id="status_kavling">
<option ${status=="SHM"?"selected":""}>SHM</option>
<option ${status=="HGB"?"selected":""}>HGB</option>
<option ${status=="HGU"?"selected":""}>HGU</option>
<option ${status=="HP"?"selected":""}>HP</option>
</select><br>
<button onclick="updateKavling(${id})">Update</button>
`;
L.popup().setLatLng([lat,lng]).setContent(form).openOn(map);
}
function updateKavling(id){
const pemilik=document.getElementById("pemilik").value;
const status=document.getElementById("status_kavling").value;
fetch("update_kavling.php",{
method:"POST",
headers:{"Content-Type":"application/x-www-form-urlencoded"},
body:`id=${id}&pemilik=${pemilik}&status=${status}`
}).then(()=>location.reload());
}
// ================= HAPUS =================
function hapusJalan(id){
if(confirm("Hapus jalan?")){
fetch("hapus_jalan.php",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`id=${id}`})
.then(()=>location.reload());
}
}
function hapusKavling(id){
if(confirm("Hapus kavling?")){
fetch("hapus_kavling.php",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:`id=${id}`})
.then(()=>location.reload());
}
}
// ================= LAYER CONTROL =================
const overlayMaps = {
'<img src="https://maps.google.com/mapfiles/ms/icons/green-dot.png" width="18"> SPBU Buka 24 Jam': spbuBuka,
'<img src="https://maps.google.com/mapfiles/ms/icons/red-dot.png" width="18"> SPBU Tidak Buka': spbuTutup
};
L.control.layers(null, overlayMaps).addTo(map);
spbuBuka.addTo(map);
spbuTutup.addTo(map);
// ================= LEGENDA =================
const legend = L.control({position: "bottomright"});
legend.onAdd = function (map) {
const div = L.DomUtil.create("div", "legend");
div.innerHTML = `
<b>Legenda</b><br><br>
<b>Kecamatan Pontianak</b><br>
<i style="background:pink"></i> Pontianak Timur<br>
<i style="background:skyblue"></i> Pontianak Barat<br>
<i style="background:gold"></i> Pontianak Kota<br>
<i style="background:violet"></i> Pontianak Selatan<br>
<i style="background:sienna"></i> Pontianak Tenggara<br>
<i style="background:slategray"></i> Pontianak Utara<br><br>
<b>SPBU</b><br>
<img src="https://maps.google.com/mapfiles/ms/icons/green-dot.png" width="18"> Buka 24 Jam<br>
<img src="https://maps.google.com/mapfiles/ms/icons/red-dot.png" width="18"> Tidak Buka 24<br>
<b>Jalan</b><br>
<i style="background:red"></i> Nasional<br>
<i style="background:green"></i> Provinsi<br>
<i style="background:orange"></i> Kabupaten<br><br>
<b>Kavling</b><br>
<i style="background:green"></i> SHM<br>
<i style="background:blue"></i> HGB<br>
<i style="background:orange"></i> HGU<br>
<i style="background:red"></i> HP
`;
return div;
};
legend.addTo(map);
</script>
<header>
<h1>Landing Page Tugas SIG</h1>
<p>Kumpulan tugas WebGIS kelas milik Freya Martines</p>
</header>
<main>
<section class="grid">
<article class="card">
<div>
<span class="badge">Tugas 1</span>
<h2>WebGIS Pemetaan SPBU</h2>
<p>Menampilkan, menambah, mengedit, dan menghapus titik SPBU menggunakan marker Leaflet.</p>
</div>
<a class="btn" href="Tugas1/">Buka Tugas 1</a>
</article>
<article class="card">
<div>
<span class="badge">Tugas 2</span>
<h2>Jalan & Kavling</h2>
<p>Manajemen data spasial jalan dalam bentuk polyline dan data kavling/tanah dalam bentuk polygon.</p>
</div>
<a class="btn" href="Tugas2/">Buka Tugas 2</a>
</article>
<article class="card">
<div>
<span class="badge">Tugas 3</span>
<h2>Layer Control SPBU</h2>
<p>Menampilkan layer group SPBU berdasarkan status buka 24 jam dan tidak buka 24 jam.</p>
</div>
<a class="btn" href="Tugas3/">Buka Tugas 3</a>
</article>
<article class="card">
<div>
<span class="badge">Tugas 4</span>
<h2>GeoJSON Kecamatan</h2>
<p>Menampilkan batas kecamatan Kota Pontianak dari file GeoJSON beserta nama kecamatan dan populasi.</p>
</div>
<a class="btn" href="Tugas4/">Buka Tugas 4</a>
</article>
</section>
<section class="info">
Setelah deploy, URL tugas akan berbentuk <code>/Tugas1/</code>, <code>/Tugas2/</code>, <code>/Tugas3/</code>, dan <code>/Tugas4/</code> dari domain utama Coolify.
</section>
</main>
</body>
</html>
+47
View File
@@ -0,0 +1,47 @@
<?php
// install_database.php - installer sementara untuk import database.sql
// Hapus file ini setelah database berhasil diimport.
set_time_limit(300);
$host = getenv('DB_HOST') ?: 'localhost';
$user = getenv('DB_USER') ?: 'root';
$pass = getenv('DB_PASS') ?: (getenv('DB_PASSWORD') ?: '');
$db = getenv('DB_NAME') ?: 'gis_spbu';
$port = (int)(getenv('DB_PORT') ?: 3306);
echo "<h2>Install Database Tugas SIG Kelas Freya</h2>";
echo "<p>Target koneksi: <b>" . htmlspecialchars($host) . ":" . htmlspecialchars((string)$port) . "</b>, database: <b>" . htmlspecialchars($db) . "</b>, user: <b>" . htmlspecialchars($user) . "</b></p>";
$conn = new mysqli($host, $user, $pass, $db, $port);
if ($conn->connect_error) {
die("<p style='color:red'>Koneksi gagal: " . htmlspecialchars($conn->connect_error) . "</p>");
}
$conn->set_charset('utf8mb4');
$sqlFile = __DIR__ . '/database.sql';
if (!file_exists($sqlFile)) {
die("<p style='color:red'>File database.sql tidak ditemukan.</p>");
}
$sql = file_get_contents($sqlFile);
$sql = preg_replace('/CREATE\s+DATABASE\s+IF\s+NOT\s+EXISTS\s+`?[^`\s;]+`?.*?;/is', '', $sql);
$sql = preg_replace('/CREATE\s+DATABASE\s+`?[^`\s;]+`?.*?;/is', '', $sql);
$sql = preg_replace('/USE\s+`?[^`\s;]+`?\s*;/is', '', $sql);
if ($conn->multi_query($sql)) {
do {
if ($result = $conn->store_result()) { $result->free(); }
} while ($conn->more_results() && $conn->next_result());
if ($conn->errno) {
echo "<p style='color:red'>Ada error saat import: " . htmlspecialchars($conn->error) . "</p>";
} else {
echo "<p style='color:green;font-weight:bold'>Database berhasil diimport/reset.</p>";
echo "<p>Setelah ini, hapus file <code>install_database.php</code> dari repo lalu redeploy.</p>";
}
} else {
echo "<p style='color:red'>Import gagal: " . htmlspecialchars($conn->error) . "</p>";
}
$conn->close();
?>
+23
View File
@@ -0,0 +1,23 @@
<?php
// koneksi.php - koneksi database untuk Coolify dan XAMPP
// Coolify: pakai environment variable
// XAMPP: fallback ke localhost/root/password kosong/database gis_spbu
$host = getenv('DB_HOST') ?: 'localhost';
$user = getenv('DB_USER') ?: 'root';
$pass = getenv('DB_PASS') ?: (getenv('DB_PASSWORD') ?: '');
$db = getenv('DB_NAME') ?: 'gis_spbu';
$port = (int)(getenv('DB_PORT') ?: 3306);
$conn = new mysqli($host, $user, $pass, $db, $port);
if ($conn->connect_error) {
http_response_code(500);
die(json_encode([
'status' => 'error',
'message' => 'Koneksi database gagal: ' . $conn->connect_error
]));
}
$conn->set_charset('utf8mb4');
?>
+10 -10
View File
@@ -1,12 +1,12 @@
<?php
$conn = new mysqli("localhost", "root", "", "gis_spbu");
$nama = $_POST['nama'];
$wa = $_POST['wa'];
$buka = $_POST['buka'];
$lat = $_POST['lat'];
$lng = $_POST['lng'];
$conn->query("INSERT INTO spbu (nama, wa, buka, lat, lng)
VALUES ('$nama','$wa','$buka','$lat','$lng')");
require_once 'koneksi.php';
$nama = $_POST['nama'] ?? '';
$wa = $_POST['wa'] ?? '';
$buka = $_POST['buka'] ?? 'Tidak';
$lat = $_POST['lat'] ?? 0;
$lng = $_POST['lng'] ?? 0;
$stmt = $conn->prepare("INSERT INTO spbu (nama, wa, buka, lat, lng) VALUES (?, ?, ?, ?, ?)");
$stmt->bind_param('sssdd', $nama, $wa, $buka, $lat, $lng);
$stmt->execute();
echo json_encode(['status' => 'success']);
?>