add all project files
This commit is contained in:
+10
@@ -0,0 +1,10 @@
|
|||||||
|
FROM php:8.2-apache
|
||||||
|
|
||||||
|
# Install ekstensi mysqli untuk koneksi ke database
|
||||||
|
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
|
||||||
|
|
||||||
|
# Aktifkan mod_rewrite Apache (berguna untuk URL yang bersih/routing)
|
||||||
|
RUN a2enmod rewrite
|
||||||
|
|
||||||
|
# Update permissions
|
||||||
|
RUN chown -R www-data:www-data /var/www/html
|
||||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
mysqli_report(MYSQLI_REPORT_OFF);
|
||||||
|
|
||||||
|
$host = getenv("DB_HOST") ?: "localhost";
|
||||||
|
$user = "root";
|
||||||
|
$pass = "fira123";
|
||||||
|
$db = "webgis"; // Menggunakan database sendiri sesuai setup_webgis.sql
|
||||||
|
|
||||||
|
$conn = new mysqli($host, $user, $pass, $db);
|
||||||
|
|
||||||
|
if ($conn->connect_error) {
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
die(json_encode([
|
||||||
|
"status" => "error",
|
||||||
|
"message" => "Koneksi database gagal",
|
||||||
|
"detail" => $conn->connect_error
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
|
||||||
|
$conn->set_charset('utf8mb4');
|
||||||
|
?>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
include "db_config.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"), true);
|
||||||
|
$id = isset($data['id']) ? intval($data['id']) : 0;
|
||||||
|
|
||||||
|
if ($id <= 0) {
|
||||||
|
echo json_encode(["status" => "error", "message" => "ID tidak valid"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "DELETE FROM spbu WHERE id=$id";
|
||||||
|
|
||||||
|
if ($conn->query($sql)) {
|
||||||
|
echo json_encode(["status" => "success"]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(["status" => "error", "message" => $conn->error]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
include "db_config.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"), true);
|
||||||
|
$id = isset($data['id']) ? intval($data['id']) : 0;
|
||||||
|
|
||||||
|
if ($id <= 0) {
|
||||||
|
echo json_encode(["status" => "error", "message" => "ID tidak valid"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "DELETE FROM jalan WHERE id=$id";
|
||||||
|
|
||||||
|
if ($conn->query($sql)) {
|
||||||
|
echo json_encode(["status" => "success"]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(["status" => "error", "message" => $conn->error]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
include "db_config.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"), true);
|
||||||
|
$id = isset($data['id']) ? intval($data['id']) : 0;
|
||||||
|
|
||||||
|
if ($id <= 0) {
|
||||||
|
echo json_encode(["status" => "error", "message" => "ID tidak valid"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "DELETE FROM parsil WHERE id=$id";
|
||||||
|
|
||||||
|
if ($conn->query($sql)) {
|
||||||
|
echo json_encode(["status" => "success"]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(["status" => "error", "message" => $conn->error]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
include "db_config.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$sql = "SELECT * FROM spbu";
|
||||||
|
$result = $conn->query($sql);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
echo json_encode([
|
||||||
|
"status" => "error",
|
||||||
|
"message" => "Gagal membaca tabel spbu",
|
||||||
|
"detail" => $conn->error
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
while($row = $result->fetch_assoc()){
|
||||||
|
$data[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode($data);
|
||||||
|
?>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
include "db_config.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$sql = "SELECT * FROM jalan";
|
||||||
|
$result = $conn->query($sql);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
echo json_encode([
|
||||||
|
"status" => "error",
|
||||||
|
"message" => "Gagal membaca tabel jalan",
|
||||||
|
"detail" => $conn->error
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
while($row = $result->fetch_assoc()){
|
||||||
|
$data[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode($data);
|
||||||
|
?>
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
include "db_config.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$sql = "SELECT * FROM parsil";
|
||||||
|
$result = $conn->query($sql);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
echo json_encode([
|
||||||
|
"status" => "error",
|
||||||
|
"message" => "Gagal membaca tabel parsil",
|
||||||
|
"detail" => $conn->error
|
||||||
|
]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = [];
|
||||||
|
|
||||||
|
while($row = $result->fetch_assoc()){
|
||||||
|
$data[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
echo json_encode($data);
|
||||||
|
?>
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
include "db_config.php";
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"), true);
|
||||||
|
|
||||||
|
$nama = $conn->real_escape_string($data['nama']);
|
||||||
|
$no = $conn->real_escape_string($data['no']);
|
||||||
|
$status = $conn->real_escape_string($data['status']);
|
||||||
|
$alamat = isset($data['alamat']) ? $conn->real_escape_string($data['alamat']) : '';
|
||||||
|
$lat = $data['lat'];
|
||||||
|
$lng = $data['lng'];
|
||||||
|
|
||||||
|
$sql = "INSERT INTO spbu (nama,no,status,alamat,lat,lng)
|
||||||
|
VALUES ('$nama','$no','$status','$alamat','$lat','$lng')";
|
||||||
|
|
||||||
|
if($conn->query($sql)){
|
||||||
|
echo json_encode([
|
||||||
|
"status"=>"success",
|
||||||
|
"id"=>$conn->insert_id
|
||||||
|
]);
|
||||||
|
}else{
|
||||||
|
echo json_encode(["status"=>"error", "msg"=>$conn->error]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
include "db_config.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"), true);
|
||||||
|
|
||||||
|
$nama = $data['nama'];
|
||||||
|
$status = $data['status'];
|
||||||
|
$panjang = $data['panjang'];
|
||||||
|
$koordinatInput = $data['koordinat'] ?? [];
|
||||||
|
|
||||||
|
if (is_string($koordinatInput)) {
|
||||||
|
$decoded = json_decode($koordinatInput, true);
|
||||||
|
$koordinat = (json_last_error() === JSON_ERROR_NONE) ? json_encode($decoded) : '[]';
|
||||||
|
} else {
|
||||||
|
$koordinat = json_encode($koordinatInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "INSERT INTO jalan (nama,status,panjang,koordinat)
|
||||||
|
VALUES ('$nama','$status','$panjang','$koordinat')";
|
||||||
|
|
||||||
|
if($conn->query($sql)){
|
||||||
|
echo json_encode([
|
||||||
|
"status"=>"success",
|
||||||
|
"id"=>$conn->insert_id
|
||||||
|
]);
|
||||||
|
}else{
|
||||||
|
echo json_encode([
|
||||||
|
"status"=>"error",
|
||||||
|
"error"=>$conn->error
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
include "db_config.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"), true);
|
||||||
|
|
||||||
|
$nama = $data['nama'];
|
||||||
|
$pemilik = $data['pemilik'];
|
||||||
|
$status = $data['status'];
|
||||||
|
$luas = $data['luas'];
|
||||||
|
$koordinatInput = $data['koordinat'] ?? [];
|
||||||
|
|
||||||
|
if (is_string($koordinatInput)) {
|
||||||
|
$decoded = json_decode($koordinatInput, true);
|
||||||
|
$koordinat = (json_last_error() === JSON_ERROR_NONE) ? json_encode($decoded) : '[]';
|
||||||
|
} else {
|
||||||
|
$koordinat = json_encode($koordinatInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "INSERT INTO parsil
|
||||||
|
(nama, pemilik, status, luas, koordinat)
|
||||||
|
VALUES
|
||||||
|
('$nama','$pemilik','$status','$luas','$koordinat')";
|
||||||
|
|
||||||
|
if($conn->query($sql)){
|
||||||
|
echo json_encode([
|
||||||
|
"status"=>"success",
|
||||||
|
"id"=>$conn->insert_id
|
||||||
|
]);
|
||||||
|
}else{
|
||||||
|
echo json_encode([
|
||||||
|
"status"=>"error",
|
||||||
|
"message"=>$conn->error
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
CREATE DATABASE IF NOT EXISTS webgis
|
||||||
|
CHARACTER SET utf8mb4
|
||||||
|
COLLATE utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
USE webgis;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS spbu (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
nama VARCHAR(200) NOT NULL,
|
||||||
|
no VARCHAR(60) NOT NULL,
|
||||||
|
status ENUM('Ya','Tidak') NOT NULL DEFAULT 'Tidak',
|
||||||
|
lat DECIMAL(10,7) NOT NULL,
|
||||||
|
lng DECIMAL(10,7) NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS jalan (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
nama VARCHAR(200) NOT NULL,
|
||||||
|
status ENUM('Nasional','Provinsi','Kabupaten') NOT NULL DEFAULT 'Kabupaten',
|
||||||
|
panjang DECIMAL(12,2) NOT NULL DEFAULT 0,
|
||||||
|
koordinat LONGTEXT NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS parsil (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
nama VARCHAR(200) NOT NULL,
|
||||||
|
pemilik VARCHAR(200) NOT NULL,
|
||||||
|
status ENUM('SHM','HGB','Sewa','Lainnya') NOT NULL DEFAULT 'SHM',
|
||||||
|
luas DECIMAL(14,2) NOT NULL DEFAULT 0,
|
||||||
|
koordinat LONGTEXT NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS kemiskinan (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
nama_kk VARCHAR(200) NOT NULL,
|
||||||
|
jumlah_kk INT NOT NULL DEFAULT 1,
|
||||||
|
alamat TEXT NOT NULL,
|
||||||
|
lat DECIMAL(10,7) NOT NULL,
|
||||||
|
lng DECIMAL(10,7) NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS masjid (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
nama_masjid VARCHAR(200) NOT NULL,
|
||||||
|
pic_masjid VARCHAR(200) NOT NULL,
|
||||||
|
alamat_masjid TEXT NOT NULL,
|
||||||
|
radius INT NOT NULL DEFAULT 500,
|
||||||
|
lat DECIMAL(10,7) NOT NULL,
|
||||||
|
lng DECIMAL(10,7) NOT NULL,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||||
|
INSERT INTO `spbu` (`nama`, `no`, `status`, `lat`, `lng`) VALUES
|
||||||
|
('SPBU Ahmad Yani', '64.781.01', 'Ya', -0.043513, 109.336423),
|
||||||
|
('SPBU Komyos Sudarso', '64.781.18', 'Tidak', -0.015243, 109.317540),
|
||||||
|
('SPBU Kapuas Indah', '64.781.14', 'Ya', -0.027581, 109.360541),
|
||||||
|
('SPBU Imam Bonjol', '64.781.19', 'Tidak', -0.038180, 109.349692),
|
||||||
|
('SPBU Gajah Mada', '64.781.11', 'Ya', -0.032159, 109.343513),
|
||||||
|
('SPBU Sungai Jawi', '64.781.05', 'Tidak', -0.021589, 109.320491),
|
||||||
|
('SPBU Siantan', '64.781.12', 'Ya', 0.007519, 109.336492);
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
include "db_config.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"), true);
|
||||||
|
|
||||||
|
$id = isset($data['id']) ? intval($data['id']) : 0;
|
||||||
|
$nama = $conn->real_escape_string($data['nama'] ?? '');
|
||||||
|
$no = $conn->real_escape_string($data['no'] ?? '');
|
||||||
|
$status = $conn->real_escape_string($data['status'] ?? 'Tidak');
|
||||||
|
$alamat = $conn->real_escape_string($data['alamat'] ?? '');
|
||||||
|
$lat = isset($data['lat']) ? floatval($data['lat']) : 0;
|
||||||
|
$lng = isset($data['lng']) ? floatval($data['lng']) : 0;
|
||||||
|
|
||||||
|
if ($id <= 0 || $nama === '' || $no === '') {
|
||||||
|
echo json_encode(["status" => "error", "message" => "Data tidak valid"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = "UPDATE spbu SET nama='$nama', no='$no', status='$status', alamat='$alamat', lat='$lat', lng='$lng' WHERE id=$id";
|
||||||
|
|
||||||
|
if ($conn->query($sql)) {
|
||||||
|
echo json_encode(["status" => "success"]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(["status" => "error", "message" => $conn->error]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
include "db_config.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"), true);
|
||||||
|
|
||||||
|
$id = isset($data['id']) ? intval($data['id']) : 0;
|
||||||
|
$nama = $conn->real_escape_string($data['nama'] ?? '');
|
||||||
|
$status = $conn->real_escape_string($data['status'] ?? 'Kabupaten');
|
||||||
|
$panjang = isset($data['panjang']) ? floatval($data['panjang']) : 0;
|
||||||
|
$koordinatInput = $data['koordinat'] ?? [];
|
||||||
|
|
||||||
|
if ($id <= 0 || $nama === '') {
|
||||||
|
echo json_encode(["status" => "error", "message" => "Data tidak valid"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($koordinatInput)) {
|
||||||
|
$decoded = json_decode($koordinatInput, true);
|
||||||
|
$koordinat = (json_last_error() === JSON_ERROR_NONE) ? json_encode($decoded) : '[]';
|
||||||
|
} else {
|
||||||
|
$koordinat = json_encode($koordinatInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
$koordinat = $conn->real_escape_string($koordinat);
|
||||||
|
|
||||||
|
$sql = "UPDATE jalan SET nama='$nama', status='$status', panjang='$panjang', koordinat='$koordinat' WHERE id=$id";
|
||||||
|
|
||||||
|
if ($conn->query($sql)) {
|
||||||
|
echo json_encode(["status" => "success"]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(["status" => "error", "message" => $conn->error]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
include "db_config.php";
|
||||||
|
|
||||||
|
header('Content-Type: application/json');
|
||||||
|
|
||||||
|
$data = json_decode(file_get_contents("php://input"), true);
|
||||||
|
|
||||||
|
$id = isset($data['id']) ? intval($data['id']) : 0;
|
||||||
|
$nama = $conn->real_escape_string($data['nama'] ?? '');
|
||||||
|
$pemilik = $conn->real_escape_string($data['pemilik'] ?? '');
|
||||||
|
$status = $conn->real_escape_string($data['status'] ?? 'SHM');
|
||||||
|
$luas = isset($data['luas']) ? floatval($data['luas']) : 0;
|
||||||
|
$koordinatInput = $data['koordinat'] ?? [];
|
||||||
|
|
||||||
|
if ($id <= 0 || $nama === '') {
|
||||||
|
echo json_encode(["status" => "error", "message" => "Data tidak valid"]);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_string($koordinatInput)) {
|
||||||
|
$decoded = json_decode($koordinatInput, true);
|
||||||
|
$koordinat = (json_last_error() === JSON_ERROR_NONE) ? json_encode($decoded) : '[]';
|
||||||
|
} else {
|
||||||
|
$koordinat = json_encode($koordinatInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
$koordinat = $conn->real_escape_string($koordinat);
|
||||||
|
|
||||||
|
$sql = "UPDATE parsil SET nama='$nama', pemilik='$pemilik', status='$status', luas='$luas', koordinat='$koordinat' WHERE id=$id";
|
||||||
|
|
||||||
|
if ($conn->query($sql)) {
|
||||||
|
echo json_encode(["status" => "success"]);
|
||||||
|
} else {
|
||||||
|
echo json_encode(["status" => "error", "message" => $conn->error]);
|
||||||
|
}
|
||||||
|
?>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,31 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
web:
|
||||||
|
build: .
|
||||||
|
ports:
|
||||||
|
- "8080:80"
|
||||||
|
volumes:
|
||||||
|
- ./:/var/www/html
|
||||||
|
environment:
|
||||||
|
- DB_HOST=db
|
||||||
|
depends_on:
|
||||||
|
- db
|
||||||
|
|
||||||
|
db:
|
||||||
|
image: mysql:8.0
|
||||||
|
command: --default-authentication-plugin=mysql_native_password
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: fira123
|
||||||
|
MYSQL_DATABASE: webgis
|
||||||
|
ports:
|
||||||
|
- "3307:3306"
|
||||||
|
volumes:
|
||||||
|
- db_data:/var/lib/mysql
|
||||||
|
# Script ini akan otomatis dijalankan oleh MySQL saat pertama kali menyala (hanya untuk setup awal)
|
||||||
|
- ./WEBGIS/01/api/setup_webgis.sql:/docker-entrypoint-initdb.d/1_setup_webgis.sql
|
||||||
|
- ./webtugas/01/api/setup_webtugas.sql:/docker-entrypoint-initdb.d/2_setup_webtugas.sql
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
db_data:
|
||||||
+507
@@ -0,0 +1,507 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="id">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>WebGIS Portal — Sistem Informasi Geografis</title>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
||||||
|
<style>
|
||||||
|
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--cyan: #06b6d4;
|
||||||
|
--cyan-dark: #0891b2;
|
||||||
|
--violet: #8b5cf6;
|
||||||
|
--violet-dark: #7c3aed;
|
||||||
|
--blue: #3b82f6;
|
||||||
|
--slate-50: #f8fafc;
|
||||||
|
--slate-100: #f1f5f9;
|
||||||
|
--slate-200: #e2e8f0;
|
||||||
|
--slate-400: #94a3b8;
|
||||||
|
--slate-500: #64748b;
|
||||||
|
--slate-700: #334155;
|
||||||
|
--slate-900: #0f172a;
|
||||||
|
}
|
||||||
|
|
||||||
|
html { scroll-behavior: smooth; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Plus Jakarta Sans', sans-serif;
|
||||||
|
background: var(--slate-50);
|
||||||
|
color: var(--slate-900);
|
||||||
|
min-height: 100vh;
|
||||||
|
overflow-x: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── BACKGROUND ─────────────────────────────── */
|
||||||
|
.bg-layer {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.orb {
|
||||||
|
position: absolute;
|
||||||
|
border-radius: 50%;
|
||||||
|
filter: blur(90px);
|
||||||
|
mix-blend-mode: multiply;
|
||||||
|
opacity: .55;
|
||||||
|
animation: float 8s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
.orb-1 { width: 520px; height: 520px; background: #a5f3fc; top: -120px; left: -120px; animation-delay: 0s; }
|
||||||
|
.orb-2 { width: 440px; height: 440px; background: #ddd6fe; top: 30%; right: -80px; animation-delay: -3s; }
|
||||||
|
.orb-3 { width: 360px; height: 360px; background: #bfdbfe; bottom: -80px; left: 30%; animation-delay: -5s; }
|
||||||
|
|
||||||
|
@keyframes float {
|
||||||
|
0%, 100% { transform: translate(0, 0) scale(1); }
|
||||||
|
33% { transform: translate(25px, -35px) scale(1.06); }
|
||||||
|
66% { transform: translate(-18px, 22px) scale(.95); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* grid mesh overlay */
|
||||||
|
.mesh {
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(rgba(148,163,184,.12) 1px, transparent 1px),
|
||||||
|
linear-gradient(90deg, rgba(148,163,184,.12) 1px, transparent 1px);
|
||||||
|
background-size: 60px 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── LAYOUT ─────────────────────────────── */
|
||||||
|
.wrapper {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
padding: 24px 24px 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── NAVBAR ─────────────────────────────── */
|
||||||
|
nav {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 780px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-icon {
|
||||||
|
width: 38px; height: 38px;
|
||||||
|
background: linear-gradient(135deg, var(--cyan), var(--blue));
|
||||||
|
border-radius: 10px;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
box-shadow: 0 4px 14px rgba(6,182,212,.35);
|
||||||
|
}
|
||||||
|
.nav-icon svg { width: 20px; height: 20px; color: white; }
|
||||||
|
|
||||||
|
.nav-brand {
|
||||||
|
font-size: 1.05rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -.01em;
|
||||||
|
color: var(--slate-900);
|
||||||
|
}
|
||||||
|
.nav-brand span { color: var(--cyan-dark); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ── HERO ─────────────────────────────── */
|
||||||
|
.hero {
|
||||||
|
text-align: center;
|
||||||
|
max-width: 600px;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-eyebrow {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
background: white;
|
||||||
|
border: 1px solid var(--slate-200);
|
||||||
|
border-radius: 99px;
|
||||||
|
padding: 6px 16px 6px 8px;
|
||||||
|
margin-bottom: 28px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,.06);
|
||||||
|
}
|
||||||
|
.hero-dot {
|
||||||
|
width: 26px; height: 26px;
|
||||||
|
background: linear-gradient(135deg, #ecfeff, #cffafe);
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
}
|
||||||
|
.pulse {
|
||||||
|
width: 8px; height: 8px;
|
||||||
|
background: var(--cyan);
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0 0 0 0 rgba(6,182,212,.5);
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
}
|
||||||
|
@keyframes pulse {
|
||||||
|
0% { box-shadow: 0 0 0 0 rgba(6,182,212,.6); }
|
||||||
|
70% { box-shadow: 0 0 0 8px rgba(6,182,212,0); }
|
||||||
|
100% { box-shadow: 0 0 0 0 rgba(6,182,212,0); }
|
||||||
|
}
|
||||||
|
.hero-eyebrow-text {
|
||||||
|
font-size: .78rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: .06em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--slate-500);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-title {
|
||||||
|
font-size: clamp(2.6rem, 6vw, 4rem);
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1.1;
|
||||||
|
letter-spacing: -.03em;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.hero-title .gradient {
|
||||||
|
background: linear-gradient(135deg, var(--cyan-dark) 0%, var(--blue) 50%, var(--violet) 100%);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-desc {
|
||||||
|
font-size: 1.05rem;
|
||||||
|
color: var(--slate-500);
|
||||||
|
line-height: 1.75;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── DIVIDER ─────────────────────────────── */
|
||||||
|
.section-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 16px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 780px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
.section-label::before, .section-label::after {
|
||||||
|
content: '';
|
||||||
|
flex: 1;
|
||||||
|
height: 1px;
|
||||||
|
background: var(--slate-200);
|
||||||
|
}
|
||||||
|
.section-label-text {
|
||||||
|
font-size: .72rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: .12em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--slate-400);
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── CARDS ─────────────────────────────── */
|
||||||
|
.cards {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
gap: 20px;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 780px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: white;
|
||||||
|
border: 1.5px solid var(--slate-200);
|
||||||
|
border-radius: 28px;
|
||||||
|
padding: 32px;
|
||||||
|
text-decoration: none;
|
||||||
|
color: inherit;
|
||||||
|
transition: transform .35s cubic-bezier(.34,1.56,.64,1), box-shadow .35s ease, border-color .25s ease;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity .35s ease;
|
||||||
|
border-radius: 28px;
|
||||||
|
}
|
||||||
|
.card-1::before { background: linear-gradient(135deg, rgba(6,182,212,.04), rgba(59,130,246,.04)); }
|
||||||
|
.card-2::before { background: linear-gradient(135deg, rgba(139,92,246,.04), rgba(236,72,153,.04)); }
|
||||||
|
|
||||||
|
.card:hover {
|
||||||
|
transform: translateY(-8px) scale(1.01);
|
||||||
|
}
|
||||||
|
.card-1:hover {
|
||||||
|
border-color: rgba(6,182,212,.4);
|
||||||
|
box-shadow: 0 24px 60px -12px rgba(6,182,212,.22), 0 8px 20px rgba(0,0,0,.06);
|
||||||
|
}
|
||||||
|
.card-2:hover {
|
||||||
|
border-color: rgba(139,92,246,.4);
|
||||||
|
box-shadow: 0 24px 60px -12px rgba(139,92,246,.22), 0 8px 20px rgba(0,0,0,.06);
|
||||||
|
}
|
||||||
|
.card:hover::before { opacity: 1; }
|
||||||
|
|
||||||
|
/* card top bar accent */
|
||||||
|
.card-accent {
|
||||||
|
position: absolute;
|
||||||
|
top: 0; left: 32px; right: 32px;
|
||||||
|
height: 2px;
|
||||||
|
border-radius: 0 0 4px 4px;
|
||||||
|
transform: scaleX(0);
|
||||||
|
transition: transform .4s cubic-bezier(.34,1.56,.64,1);
|
||||||
|
transform-origin: left;
|
||||||
|
}
|
||||||
|
.card:hover .card-accent { transform: scaleX(1); }
|
||||||
|
.card-1 .card-accent { background: linear-gradient(90deg, var(--cyan), var(--blue)); }
|
||||||
|
.card-2 .card-accent { background: linear-gradient(90deg, var(--violet), #ec4899); }
|
||||||
|
|
||||||
|
/* icon */
|
||||||
|
.card-icon-wrap {
|
||||||
|
width: 58px; height: 58px;
|
||||||
|
border-radius: 16px;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
transition: transform .35s cubic-bezier(.34,1.56,.64,1);
|
||||||
|
}
|
||||||
|
.card:hover .card-icon-wrap { transform: scale(1.12) rotate(-4deg); }
|
||||||
|
.card-1 .card-icon-wrap {
|
||||||
|
background: linear-gradient(135deg, #ecfeff, #cffafe);
|
||||||
|
border: 1.5px solid rgba(6,182,212,.25);
|
||||||
|
}
|
||||||
|
.card-2 .card-icon-wrap {
|
||||||
|
background: linear-gradient(135deg, #f5f3ff, #ede9fe);
|
||||||
|
border: 1.5px solid rgba(139,92,246,.25);
|
||||||
|
}
|
||||||
|
.card-1 .card-icon-wrap svg { color: var(--cyan-dark); width: 28px; height: 28px; }
|
||||||
|
.card-2 .card-icon-wrap svg { color: var(--violet); width: 28px; height: 28px; }
|
||||||
|
|
||||||
|
/* tag */
|
||||||
|
.card-tag {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 5px;
|
||||||
|
font-size: .7rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: .1em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 99px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
.card-1 .card-tag { background: #ecfeff; color: var(--cyan-dark); }
|
||||||
|
.card-2 .card-tag { background: #f5f3ff; color: var(--violet-dark); }
|
||||||
|
|
||||||
|
.card-title {
|
||||||
|
font-size: 1.45rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -.02em;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-desc {
|
||||||
|
font-size: .9rem;
|
||||||
|
color: var(--slate-500);
|
||||||
|
line-height: 1.7;
|
||||||
|
flex-grow: 1;
|
||||||
|
margin-bottom: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pills */
|
||||||
|
.card-pills {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 6px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
}
|
||||||
|
.pill {
|
||||||
|
font-size: .7rem;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 3px 10px;
|
||||||
|
border-radius: 99px;
|
||||||
|
background: var(--slate-100);
|
||||||
|
color: var(--slate-500);
|
||||||
|
border: 1px solid var(--slate-200);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cta */
|
||||||
|
.card-cta {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
font-size: .88rem;
|
||||||
|
font-weight: 700;
|
||||||
|
border-radius: 99px;
|
||||||
|
padding: 12px 22px;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: gap .3s ease, box-shadow .3s ease;
|
||||||
|
}
|
||||||
|
.card:hover .card-cta { gap: 14px; }
|
||||||
|
.card-1 .card-cta {
|
||||||
|
background: linear-gradient(135deg, var(--cyan), var(--blue));
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0 6px 20px rgba(6,182,212,.3);
|
||||||
|
}
|
||||||
|
.card-1:hover .card-cta { box-shadow: 0 8px 28px rgba(6,182,212,.45); }
|
||||||
|
.card-2 .card-cta {
|
||||||
|
background: linear-gradient(135deg, var(--violet), #a855f7);
|
||||||
|
color: white;
|
||||||
|
box-shadow: 0 6px 20px rgba(139,92,246,.3);
|
||||||
|
}
|
||||||
|
.card-2:hover .card-cta { box-shadow: 0 8px 28px rgba(139,92,246,.45); }
|
||||||
|
.cta-arrow { transition: transform .3s ease; }
|
||||||
|
.card:hover .cta-arrow { transform: translateX(4px); }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ── FOOTER ─────────────────────────────── */
|
||||||
|
footer {
|
||||||
|
margin-top: 48px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: .78rem;
|
||||||
|
color: var(--slate-400);
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── RESPONSIVE ─────────────────────────── */
|
||||||
|
@media (max-width: 640px) {
|
||||||
|
.cards { grid-template-columns: 1fr; }
|
||||||
|
nav { flex-direction: column; gap: 12px; }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div class="bg-layer">
|
||||||
|
<div class="mesh"></div>
|
||||||
|
<div class="orb orb-1"></div>
|
||||||
|
<div class="orb orb-2"></div>
|
||||||
|
<div class="orb orb-3"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="wrapper">
|
||||||
|
|
||||||
|
<!-- NAVBAR -->
|
||||||
|
<nav>
|
||||||
|
<div class="nav-logo">
|
||||||
|
<div class="nav-icon">
|
||||||
|
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M9 20l-5.447-2.724A1 1 0 013 16.382V5.618a1 1 0 011.447-.894L9 7m0 13l6-3m-6 3V7m6 10l4.553 2.276A1 1 0 0021 18.382V7.618a1 1 0 00-.553-.894L15 4m0 13V4m0 0L9 7" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<span class="nav-brand">Web<span>GIS</span></span>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<!-- HERO -->
|
||||||
|
<div class="hero">
|
||||||
|
<div class="hero-eyebrow">
|
||||||
|
<div class="hero-dot"><div class="pulse"></div></div>
|
||||||
|
<span class="hero-eyebrow-text">Sistem Aktif & Berjalan</span>
|
||||||
|
</div>
|
||||||
|
<h1 class="hero-title">
|
||||||
|
Portal Pemetaan<br>
|
||||||
|
<span class="gradient">Spasial Digital</span>
|
||||||
|
</h1>
|
||||||
|
<p class="hero-desc">
|
||||||
|
Platform terpadu untuk eksplorasi data geografis Kota Pontianak.<br>
|
||||||
|
Pilih project di bawah ini untuk mulai menjelajah.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- SECTION LABEL -->
|
||||||
|
<div class="section-label">
|
||||||
|
<span class="section-label-text">Pilih Project</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- CARDS -->
|
||||||
|
<div class="cards">
|
||||||
|
|
||||||
|
<!-- Card 1 -->
|
||||||
|
<a href="WEBGIS/01/" class="card card-1">
|
||||||
|
<div class="card-accent"></div>
|
||||||
|
|
||||||
|
<div class="card-icon-wrap">
|
||||||
|
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-tag">Project 01</div>
|
||||||
|
<h2 class="card-title">Sistem Tata<br>Ruang Kota</h2>
|
||||||
|
<p class="card-desc">
|
||||||
|
Pemetaan komprehensif Point of Interest SPBU, jaringan jalan, dan parsil tanah berbasis administrasi kecamatan Kota Pontianak.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card-pills">
|
||||||
|
<span class="pill">📍 SPBU & POI</span>
|
||||||
|
<span class="pill">🛣️ Jaringan Jalan</span>
|
||||||
|
<span class="pill">🗺️ Parsil Tanah</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-cta">
|
||||||
|
Buka Project
|
||||||
|
<svg class="cta-arrow" width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M17 8l4 4m0 0l-4 4m4-4H3" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<!-- Card 2 -->
|
||||||
|
<a href="webtugas/01/" class="card card-2">
|
||||||
|
<div class="card-accent"></div>
|
||||||
|
|
||||||
|
<div class="card-icon-wrap">
|
||||||
|
<svg fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="1.8">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M17 20h5v-2a3 3 0 00-5.356-1.857M17 20H7m10 0v-2c0-.656-.126-1.283-.356-1.857M7 20H2v-2a3 3 0 015.356-1.857M7 20v-2c0-.656.126-1.283.356-1.857m0 0a5.002 5.002 0 019.288 0M15 7a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-tag">Project 02</div>
|
||||||
|
<h2 class="card-title">SiPetaSos<br><span style="font-weight:500;opacity:.6;font-size:1rem">Peta Sosial</span></h2>
|
||||||
|
<p class="card-desc">
|
||||||
|
Sistem informasi pemetaan kemiskinan berbasis Rumah Ibadah. Visualisasi sebaran KK miskin, ekstrem, dan blank spot layanan sosial.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="card-pills">
|
||||||
|
<span class="pill">👥 Data KK Miskin</span>
|
||||||
|
<span class="pill">🕌 Rumah Ibadah</span>
|
||||||
|
<span class="pill">📊 Laporan</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-cta">
|
||||||
|
Buka Project
|
||||||
|
<svg class="cta-arrow" width="16" height="16" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2.5">
|
||||||
|
<path stroke-linecap="round" stroke-linejoin="round" d="M17 8l4 4m0 0l-4 4m4-4H3" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<!-- FOOTER -->
|
||||||
|
<footer>
|
||||||
|
© 2026 WebGIS Portal — Sistem Informasi Geografis Kota Pontianak
|
||||||
|
</footer>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
INSERT INTO `spbu` (`nama`, `no`, `status`, `lat`, `lng`) VALUES
|
||||||
|
('SPBU Ahmad Yani', '64.781.01', 'Ya', -0.043513, 109.336423),
|
||||||
|
('SPBU Komyos Sudarso', '64.781.18', 'Tidak', -0.015243, 109.317540),
|
||||||
|
('SPBU Kapuas Indah', '64.781.14', 'Ya', -0.027581, 109.360541),
|
||||||
|
('SPBU Imam Bonjol', '64.781.19', 'Tidak', -0.038180, 109.349692),
|
||||||
|
('SPBU Gajah Mada', '64.781.11', 'Ya', -0.032159, 109.343513),
|
||||||
|
('SPBU Sungai Jawi', '64.781.05', 'Tidak', -0.021589, 109.320491),
|
||||||
|
('SPBU Siantan', '64.781.12', 'Ya', 0.007519, 109.336492);
|
||||||
Submodule
+1
Submodule webtugas added at 30b16bb877
Reference in New Issue
Block a user