save dulu
This commit is contained in:
parent
a1d2dd1990
commit
9f467b7dab
|
|
@ -32,7 +32,10 @@ public function store(Request $request)
|
||||||
'tanggal_lahir' => 'required|date',
|
'tanggal_lahir' => 'required|date',
|
||||||
'jenis_kelamin' => 'required|in:L,P',
|
'jenis_kelamin' => 'required|in:L,P',
|
||||||
'wali_murid_id' => 'required|exists:wali_murids,id',
|
'wali_murid_id' => 'required|exists:wali_murids,id',
|
||||||
// Alamat dihapus, karena ikut Wali Murid
|
|
||||||
|
// --- TAMBAHAN BARU: Validasi Titik Koordinat Peta ---
|
||||||
|
'latitude' => 'nullable|string',
|
||||||
|
'longitude' => 'nullable|string',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Siswa::create([
|
Siswa::create([
|
||||||
|
|
@ -43,6 +46,10 @@ public function store(Request $request)
|
||||||
'tanggal_lahir' => $request->tanggal_lahir,
|
'tanggal_lahir' => $request->tanggal_lahir,
|
||||||
'jenis_kelamin' => $request->jenis_kelamin,
|
'jenis_kelamin' => $request->jenis_kelamin,
|
||||||
'wali_murid_id' => $request->wali_murid_id,
|
'wali_murid_id' => $request->wali_murid_id,
|
||||||
|
|
||||||
|
// --- TAMBAHAN BARU: Simpan ke Database ---
|
||||||
|
'latitude' => $request->latitude,
|
||||||
|
'longitude' => $request->longitude,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return redirect()->route('siswa.index')->with('success', 'Data Siswa berhasil ditambahkan.');
|
return redirect()->route('siswa.index')->with('success', 'Data Siswa berhasil ditambahkan.');
|
||||||
|
|
@ -67,6 +74,10 @@ public function update(Request $request, $id)
|
||||||
'tanggal_lahir' => 'required|date',
|
'tanggal_lahir' => 'required|date',
|
||||||
'jenis_kelamin' => 'required|in:L,P',
|
'jenis_kelamin' => 'required|in:L,P',
|
||||||
'wali_murid_id' => 'required|exists:wali_murids,id',
|
'wali_murid_id' => 'required|exists:wali_murids,id',
|
||||||
|
|
||||||
|
// --- TAMBAHAN BARU: Validasi Titik Koordinat Peta ---
|
||||||
|
'latitude' => 'nullable|string',
|
||||||
|
'longitude' => 'nullable|string',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$siswa->update([
|
$siswa->update([
|
||||||
|
|
@ -77,6 +88,10 @@ public function update(Request $request, $id)
|
||||||
'tanggal_lahir' => $request->tanggal_lahir,
|
'tanggal_lahir' => $request->tanggal_lahir,
|
||||||
'jenis_kelamin' => $request->jenis_kelamin,
|
'jenis_kelamin' => $request->jenis_kelamin,
|
||||||
'wali_murid_id' => $request->wali_murid_id,
|
'wali_murid_id' => $request->wali_murid_id,
|
||||||
|
|
||||||
|
// --- TAMBAHAN BARU: Update ke Database ---
|
||||||
|
'latitude' => $request->latitude,
|
||||||
|
'longitude' => $request->longitude,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return redirect()->route('siswa.index')->with('success', 'Data Siswa berhasil diperbarui!');
|
return redirect()->route('siswa.index')->with('success', 'Data Siswa berhasil diperbarui!');
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,142 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Http\Controllers\Api;
|
||||||
|
|
||||||
|
use App\Http\Controllers\Controller;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class AStarController extends Controller
|
||||||
|
{
|
||||||
|
public function cariRute(Request $request)
|
||||||
|
{
|
||||||
|
$id_awal = 1; // ID PAUD Aisyiyah Kartoharjo (Start)
|
||||||
|
$awal = DB::table('titik_jalans')->where('id', $id_awal)->first();
|
||||||
|
|
||||||
|
// 1. Ambil kordinat dari HP Flutter
|
||||||
|
$latTujuan = $request->query('lat');
|
||||||
|
$lngTujuan = $request->query('lng');
|
||||||
|
|
||||||
|
if (!$latTujuan || !$lngTujuan) {
|
||||||
|
return response()->json(['success' => false, 'message' => 'Koordinat tidak valid'], 400);
|
||||||
|
}
|
||||||
|
|
||||||
|
$semua_titik = DB::table('titik_jalans')->get()->keyBy('id');
|
||||||
|
|
||||||
|
// 2. CARI TITIK TUJUAN YANG PALING COCOK BERDASARKAN KOORDINAT
|
||||||
|
$tujuan = null;
|
||||||
|
$jarakTerdekat = INF;
|
||||||
|
|
||||||
|
foreach ($semua_titik as $titik) {
|
||||||
|
$jarak = $this->hitungJarak($latTujuan, $lngTujuan, $titik->latitude, $titik->longitude);
|
||||||
|
if ($jarak < $jarakTerdekat) {
|
||||||
|
$jarakTerdekat = $jarak;
|
||||||
|
$tujuan = $titik;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$tujuan) {
|
||||||
|
return response()->json(['success' => false, 'message' => 'Titik tidak ditemukan'], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$id_tujuan = $tujuan->id; // Dapatkan ID aslinya di tabel titik_jalans
|
||||||
|
|
||||||
|
// 3. Ambil jalur jembatannya
|
||||||
|
$edges = DB::table('jalur_jalans')->get();
|
||||||
|
$graph = [];
|
||||||
|
foreach ($edges as $edge) {
|
||||||
|
$graph[$edge->titik_awal_id][] = [
|
||||||
|
'tujuan' => $edge->titik_tujuan_id,
|
||||||
|
'jarak' => $edge->jarak
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
|
// PROSES A-STAR (A*)
|
||||||
|
// ==========================================
|
||||||
|
$openList = [$id_awal];
|
||||||
|
$closedList = [];
|
||||||
|
$cameFrom = [];
|
||||||
|
|
||||||
|
$gCost = [];
|
||||||
|
$fCost = [];
|
||||||
|
foreach ($semua_titik as $id => $titik) {
|
||||||
|
$gCost[$id] = INF;
|
||||||
|
$fCost[$id] = INF;
|
||||||
|
}
|
||||||
|
$gCost[$id_awal] = 0;
|
||||||
|
$fCost[$id_awal] = $this->hitungHeuristic($awal, $tujuan);
|
||||||
|
|
||||||
|
while (!empty($openList)) {
|
||||||
|
$current = null;
|
||||||
|
$lowestF = INF;
|
||||||
|
foreach ($openList as $nodeId) {
|
||||||
|
if ($fCost[$nodeId] < $lowestF) {
|
||||||
|
$lowestF = $fCost[$nodeId];
|
||||||
|
$current = $nodeId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($current == $id_tujuan) {
|
||||||
|
return $this->rekonstruksiRute($cameFrom, $current, $semua_titik, $gCost[$current]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$openList = array_diff($openList, [$current]);
|
||||||
|
$closedList[] = $current;
|
||||||
|
|
||||||
|
if (isset($graph[$current])) {
|
||||||
|
foreach ($graph[$current] as $neighbor) {
|
||||||
|
$neighborId = $neighbor['tujuan'];
|
||||||
|
|
||||||
|
if (in_array($neighborId, $closedList)) continue;
|
||||||
|
|
||||||
|
$tentativeGCost = $gCost[$current] + $neighbor['jarak'];
|
||||||
|
|
||||||
|
if ($tentativeGCost < $gCost[$neighborId]) {
|
||||||
|
$cameFrom[$neighborId] = $current;
|
||||||
|
$gCost[$neighborId] = $tentativeGCost;
|
||||||
|
|
||||||
|
$hCost = $this->hitungHeuristic($semua_titik[$neighborId], $tujuan);
|
||||||
|
$fCost[$neighborId] = $tentativeGCost + $hCost;
|
||||||
|
|
||||||
|
if (!in_array($neighborId, $openList)) {
|
||||||
|
$openList[] = $neighborId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json(['success' => false, 'message' => 'Rute tidak ditemukan (Buntu)'], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- RUMUS BANTUAN ---
|
||||||
|
private function hitungJarak($lat1, $lon1, $lat2, $lon2) {
|
||||||
|
$earthRadius = 6371000;
|
||||||
|
$latFrom = deg2rad((float)$lat1);
|
||||||
|
$lonFrom = deg2rad((float)$lon1);
|
||||||
|
$latTo = deg2rad((float)$lat2);
|
||||||
|
$lonTo = deg2rad((float)$lon2);
|
||||||
|
|
||||||
|
$latDelta = $latTo - $latFrom;
|
||||||
|
$lonDelta = $lonTo - $lonFrom;
|
||||||
|
|
||||||
|
$angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) + cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
|
||||||
|
return round($angle * $earthRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function hitungHeuristic($titikA, $titikB) {
|
||||||
|
return $this->hitungJarak($titikA->latitude, $titikA->longitude, $titikB->latitude, $titikB->longitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function rekonstruksiRute($cameFrom, $current, $semua_titik, $jarakTotal) {
|
||||||
|
$rute = [];
|
||||||
|
while (isset($cameFrom[$current])) {
|
||||||
|
array_unshift($rute, $semua_titik[$current]);
|
||||||
|
$current = $cameFrom[$current];
|
||||||
|
}
|
||||||
|
array_unshift($rute, $semua_titik[$current]);
|
||||||
|
|
||||||
|
return response()->json(['success' => true, 'jarak_total_meter' => $jarakTotal, 'titik_rute' => $rute]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class JalurJalan extends Model
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class Kunjungan extends Model
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class TitikJalan extends Model
|
||||||
|
{
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('siswas', function (Blueprint $table) {
|
||||||
|
// Menambahkan kolom untuk titik koordinat GPS
|
||||||
|
$table->string('latitude')->nullable()->after('alamat');
|
||||||
|
$table->string('longitude')->nullable()->after('latitude');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('siswas', function (Blueprint $table) {
|
||||||
|
$table->dropColumn(['latitude', 'longitude']);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::create('kunjungans', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->foreignId('guru_id')->constrained('users')->onDelete('cascade'); // Relasi ke Guru (User)
|
||||||
|
$table->foreignId('siswa_id')->constrained('siswas')->onDelete('cascade'); // Relasi ke Siswa
|
||||||
|
$table->date('tanggal_visit');
|
||||||
|
$table->string('status')->default('menunggu'); // Status: menunggu, jalan, selesai
|
||||||
|
|
||||||
|
// --- Kolom untuk Penilaian (Dibuat fleksibel) ---
|
||||||
|
$table->string('materi_belajar')->nullable();
|
||||||
|
$table->string('nilai')->nullable(); // String, biar bisa diisi "BB", "BSB", atau angka 80
|
||||||
|
$table->text('catatan')->nullable();
|
||||||
|
$table->string('foto_kegiatan')->nullable();
|
||||||
|
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('kunjungans');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('titik_jalans', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('nama_titik'); // Contoh: "Simpang 3 Diponegoro", "PAUD", "Rumah Achazia"
|
||||||
|
$table->string('latitude');
|
||||||
|
$table->string('longitude');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('titik_jalans');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('jalur_jalans', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
// Titik awal persimpangan
|
||||||
|
$table->foreignId('titik_awal_id')->constrained('titik_jalans')->onDelete('cascade');
|
||||||
|
// Titik tujuan persimpangan
|
||||||
|
$table->foreignId('titik_tujuan_id')->constrained('titik_jalans')->onDelete('cascade');
|
||||||
|
// Jarak asli jalan raya (dalam meter / kilometer) -> Ini jadi G-Cost di A*
|
||||||
|
$table->double('jarak');
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('jalur_jalans');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Database\Seeders;
|
||||||
|
|
||||||
|
use Illuminate\Database\Seeder;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class JalurJalanSeeder extends Seeder
|
||||||
|
{
|
||||||
|
public function run(): void
|
||||||
|
{
|
||||||
|
// 1. Bersihkan tabel jalur_jalans sebelum diisi
|
||||||
|
DB::statement('SET FOREIGN_KEY_CHECKS=0;');
|
||||||
|
DB::table('jalur_jalans')->truncate();
|
||||||
|
DB::statement('SET FOREIGN_KEY_CHECKS=1;');
|
||||||
|
|
||||||
|
// 2. Ambil semua data titik yang sudah Ghoza input
|
||||||
|
$titik = DB::table('titik_jalans')->get()->keyBy('id');
|
||||||
|
$jalur = [];
|
||||||
|
|
||||||
|
// 3. Hubungkan PAUD (ID 1) dengan Simpang A (2) dan Simpang B (3)
|
||||||
|
$jalur = array_merge($jalur, $this->buatJalurBolakBalik($titik[1], $titik[2]));
|
||||||
|
$jalur = array_merge($jalur, $this->buatJalurBolakBalik($titik[1], $titik[3]));
|
||||||
|
|
||||||
|
// 4. Hubungkan SETIAP RUMAH SISWA (ID 4 sampai 59) ke titik terdekatnya
|
||||||
|
for ($i = 4; $i <= 59; $i++) {
|
||||||
|
if(!isset($titik[$i])) continue; // Lewati kalau ID tidak ada
|
||||||
|
|
||||||
|
$rumah = $titik[$i];
|
||||||
|
|
||||||
|
// Hitung jarak dari rumah ke PAUD & Persimpangan
|
||||||
|
$jarakKePaud = $this->hitungJarak($rumah->latitude, $rumah->longitude, $titik[1]->latitude, $titik[1]->longitude);
|
||||||
|
$jarakKeSimpangA = $this->hitungJarak($rumah->latitude, $rumah->longitude, $titik[2]->latitude, $titik[2]->longitude);
|
||||||
|
$jarakKeSimpangB = $this->hitungJarak($rumah->latitude, $rumah->longitude, $titik[3]->latitude, $titik[3]->longitude);
|
||||||
|
|
||||||
|
// Cari mana yang paling dekat
|
||||||
|
$terdekat = 1;
|
||||||
|
$jarakMin = $jarakKePaud;
|
||||||
|
|
||||||
|
if ($jarakKeSimpangA < $jarakMin) {
|
||||||
|
$terdekat = 2;
|
||||||
|
$jarakMin = $jarakKeSimpangA;
|
||||||
|
}
|
||||||
|
if ($jarakKeSimpangB < $jarakMin) {
|
||||||
|
$terdekat = 3;
|
||||||
|
$jarakMin = $jarakKeSimpangB;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buat jembatan bolak-balik dari rumah ke titik terdekat tersebut
|
||||||
|
$jalur = array_merge($jalur, $this->buatJalurBolakBalik($rumah, $titik[$terdekat]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Simpan semua data jembatannya ke Database!
|
||||||
|
DB::table('jalur_jalans')->insert($jalur);
|
||||||
|
|
||||||
|
$totalJalur = count($jalur);
|
||||||
|
$this->command->info("WOW! Berhasil membuat {$totalJalur} jembatan rute secara otomatis pakai Haversine Formula!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- RUMUS BANTUAN ---
|
||||||
|
|
||||||
|
// Fungsi bikin jalur 2 arah (Pergi - Pulang)
|
||||||
|
private function buatJalurBolakBalik($titikA, $titikB) {
|
||||||
|
$jarak = $this->hitungJarak($titikA->latitude, $titikA->longitude, $titikB->latitude, $titikB->longitude);
|
||||||
|
return [
|
||||||
|
['titik_awal_id' => $titikA->id, 'titik_tujuan_id' => $titikB->id, 'jarak' => $jarak],
|
||||||
|
['titik_awal_id' => $titikB->id, 'titik_tujuan_id' => $titikA->id, 'jarak' => $jarak],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rumus Haversine: Mengubah Latitude & Longitude menjadi jarak Meter aslinya
|
||||||
|
private function hitungJarak($lat1, $lon1, $lat2, $lon2) {
|
||||||
|
$earthRadius = 6371000; // Radius bumi dalam meter
|
||||||
|
$latFrom = deg2rad((float)$lat1);
|
||||||
|
$lonFrom = deg2rad((float)$lon1);
|
||||||
|
$latTo = deg2rad((float)$lat2);
|
||||||
|
$lonTo = deg2rad((float)$lon2);
|
||||||
|
|
||||||
|
$latDelta = $latTo - $latFrom;
|
||||||
|
$lonDelta = $lonTo - $lonFrom;
|
||||||
|
|
||||||
|
$angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
|
||||||
|
cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
|
||||||
|
|
||||||
|
return round($angle * $earthRadius); // Dibulatkan
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
@extends('layouts.app')
|
@extends('layouts.app')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="bg-white shadow-md rounded-lg p-6 max-w-xl mx-auto mt-10">
|
<div class="bg-white shadow-md rounded-lg p-6 max-w-xl mx-auto mt-10 mb-10">
|
||||||
<div class="flex justify-between items-center mb-6">
|
<div class="flex justify-between items-center mb-6">
|
||||||
<h1 class="text-xl font-bold text-gray-700">➕ Tambah Siswa Baru</h1>
|
<h1 class="text-xl font-bold text-gray-700">➕ Tambah Siswa Baru</h1>
|
||||||
<a href="{{ route('siswa.index') }}" class="text-gray-500 hover:text-gray-700">← Kembali</a>
|
<a href="{{ route('siswa.index') }}" class="text-gray-500 hover:text-gray-700">← Kembali</a>
|
||||||
|
|
@ -74,6 +74,24 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4 p-4 border border-blue-200 bg-blue-50 rounded-lg">
|
||||||
|
<label class="block text-gray-800 font-bold mb-2">📍 Titik Lokasi Rumah (Untuk Rute Kunjungan)</label>
|
||||||
|
<p class="text-xs text-gray-600 mb-2">Geser dan klik pada peta di bawah untuk menandai rumah siswa.</p>
|
||||||
|
|
||||||
|
<div id="map" style="height: 300px; width: 100%; border-radius: 8px; z-index: 1;"></div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-4 mt-3">
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs text-gray-500 mb-1">Latitude</label>
|
||||||
|
<input type="text" name="latitude" id="latitude" value="{{ old('latitude') }}" class="w-full border border-gray-300 rounded p-2 bg-gray-100 text-sm" readonly placeholder="Otomatis terisi">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs text-gray-500 mb-1">Longitude</label>
|
||||||
|
<input type="text" name="longitude" id="longitude" value="{{ old('longitude') }}" class="w-full border border-gray-300 rounded p-2 bg-gray-100 text-sm" readonly placeholder="Otomatis terisi">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end mt-6 gap-3">
|
<div class="flex justify-end mt-6 gap-3">
|
||||||
<button type="submit" class="bg-green-600 text-white font-semibold px-6 py-2 rounded-lg hover:bg-green-700 transition shadow-md">
|
<button type="submit" class="bg-green-600 text-white font-semibold px-6 py-2 rounded-lg hover:bg-green-700 transition shadow-md">
|
||||||
💾 Simpan Data
|
💾 Simpan Data
|
||||||
|
|
@ -81,4 +99,41 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
// Titik tengah default: Alun-alun Jember
|
||||||
|
var map = L.map('map').setView([-7.628337, 111.525506], 13);
|
||||||
|
|
||||||
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
attribution: '© OpenStreetMap contributors'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
var marker;
|
||||||
|
|
||||||
|
// Kalau ada error validasi dan ada data lama, tampilkan markernya
|
||||||
|
@if(old('latitude') && old('longitude'))
|
||||||
|
var oldLat = {{ old('latitude') }};
|
||||||
|
var oldLng = {{ old('longitude') }};
|
||||||
|
marker = L.marker([oldLat, oldLng]).addTo(map);
|
||||||
|
map.setView([oldLat, oldLng], 15);
|
||||||
|
@endif
|
||||||
|
|
||||||
|
// Event saat peta diklik
|
||||||
|
map.on('click', function(e) {
|
||||||
|
var lat = e.latlng.lat;
|
||||||
|
var lng = e.latlng.lng;
|
||||||
|
|
||||||
|
document.getElementById('latitude').value = lat;
|
||||||
|
document.getElementById('longitude').value = lng;
|
||||||
|
|
||||||
|
if (marker) {
|
||||||
|
map.removeLayer(marker);
|
||||||
|
}
|
||||||
|
marker = L.marker([lat, lng]).addTo(map);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
@extends('layouts.app')
|
@extends('layouts.app')
|
||||||
|
|
||||||
@section('content')
|
@section('content')
|
||||||
<div class="bg-white shadow-md rounded-lg p-6 max-w-xl mx-auto mt-10">
|
<div class="bg-white shadow-md rounded-lg p-6 max-w-xl mx-auto mt-10 mb-10">
|
||||||
<div class="flex justify-between items-center mb-6">
|
<div class="flex justify-between items-center mb-6">
|
||||||
<h1 class="text-xl font-bold text-gray-700">✏️ Edit Data Siswa</h1>
|
<h1 class="text-xl font-bold text-gray-700">✏️ Edit Data Siswa</h1>
|
||||||
<a href="{{ route('siswa.index') }}" class="text-gray-500 hover:text-gray-700">← Kembali</a>
|
<a href="{{ route('siswa.index') }}" class="text-gray-500 hover:text-gray-700">← Kembali</a>
|
||||||
|
|
@ -78,6 +78,24 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-4 p-4 border border-blue-200 bg-blue-50 rounded-lg">
|
||||||
|
<label class="block text-gray-800 font-bold mb-2">📍 Titik Lokasi Rumah (Untuk Rute Kunjungan)</label>
|
||||||
|
<p class="text-xs text-gray-600 mb-2">Geser dan klik pada peta untuk mengubah lokasi rumah siswa.</p>
|
||||||
|
|
||||||
|
<div id="map" style="height: 300px; width: 100%; border-radius: 8px; z-index: 1;"></div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-2 gap-4 mt-3">
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs text-gray-500 mb-1">Latitude</label>
|
||||||
|
<input type="text" name="latitude" id="latitude" value="{{ old('latitude', $siswa->latitude) }}" class="w-full border border-gray-300 rounded p-2 bg-gray-100 text-sm" readonly>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label class="block text-xs text-gray-500 mb-1">Longitude</label>
|
||||||
|
<input type="text" name="longitude" id="longitude" value="{{ old('longitude', $siswa->longitude) }}" class="w-full border border-gray-300 rounded p-2 bg-gray-100 text-sm" readonly>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="flex justify-end mt-6 gap-3">
|
<div class="flex justify-end mt-6 gap-3">
|
||||||
<button type="submit" class="bg-green-600 text-white font-semibold px-6 py-2 rounded-lg hover:bg-green-700 transition shadow-md">
|
<button type="submit" class="bg-green-600 text-white font-semibold px-6 py-2 rounded-lg hover:bg-green-700 transition shadow-md">
|
||||||
💾 Simpan Perubahan
|
💾 Simpan Perubahan
|
||||||
|
|
@ -85,4 +103,42 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
// Cek apakah siswa sudah punya koordinat
|
||||||
|
var currentLat = {{ $siswa->latitude ?? '-7.628337' }};
|
||||||
|
var currentLng = {{ $siswa->longitude ?? '111.525506' }};
|
||||||
|
var hasLocation = {{ $siswa->latitude ? 'true' : 'false' }};
|
||||||
|
|
||||||
|
var map = L.map('map').setView([currentLat, currentLng], hasLocation ? 16 : 13);
|
||||||
|
|
||||||
|
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||||||
|
attribution: '© OpenStreetMap contributors'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
var marker;
|
||||||
|
|
||||||
|
// Jika sudah ada koordinat, pasang marker
|
||||||
|
if (hasLocation) {
|
||||||
|
marker = L.marker([currentLat, currentLng]).addTo(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Event saat peta diklik
|
||||||
|
map.on('click', function(e) {
|
||||||
|
var lat = e.latlng.lat;
|
||||||
|
var lng = e.latlng.lng;
|
||||||
|
|
||||||
|
document.getElementById('latitude').value = lat;
|
||||||
|
document.getElementById('longitude').value = lng;
|
||||||
|
|
||||||
|
if (marker) {
|
||||||
|
map.removeLayer(marker);
|
||||||
|
}
|
||||||
|
marker = L.marker([lat, lng]).addTo(map);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
@endsection
|
@endsection
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
use App\Http\Controllers\Api\LaporanController;
|
use App\Http\Controllers\Api\LaporanController;
|
||||||
use App\Http\Controllers\Api\GuruController;
|
use App\Http\Controllers\Api\GuruController;
|
||||||
use App\Http\Controllers\Api\PenjemputanController;
|
use App\Http\Controllers\Api\PenjemputanController;
|
||||||
|
use App\Http\Controllers\Api\AStarController;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
@ -26,7 +27,6 @@
|
||||||
|
|
||||||
// --- KHUSUS WALI MURID (Lihat Data) ---
|
// --- KHUSUS WALI MURID (Lihat Data) ---
|
||||||
// Wali melihat daftar anaknya
|
// Wali melihat daftar anaknya
|
||||||
|
|
||||||
// ==========================================
|
// ==========================================
|
||||||
// 2. AREA TERKUNCI (BUTUH TOKEN)
|
// 2. AREA TERKUNCI (BUTUH TOKEN)
|
||||||
// ==========================================
|
// ==========================================
|
||||||
|
|
@ -55,5 +55,8 @@
|
||||||
|
|
||||||
// RUTE PENJEMPUTAN BARU
|
// RUTE PENJEMPUTAN BARU
|
||||||
Route::post('/penjemputan', [PenjemputanController::class, 'store']);
|
Route::post('/penjemputan', [PenjemputanController::class, 'store']);
|
||||||
|
|
||||||
|
Route::get('/rute-astar', [AStarController::class, 'cariRute']);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,4 +82,30 @@
|
||||||
Route::get('/rapot/{id}/print', [App\Http\Controllers\Admin\RapotController::class, 'print'])->name('rapot.print');
|
Route::get('/rapot/{id}/print', [App\Http\Controllers\Admin\RapotController::class, 'print'])->name('rapot.print');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Route::get('/sinkron-kordinat', function () {
|
||||||
|
// Ambil data dari ID 4 sampai akhir (karena ID 1-3 itu PAUD dan Simpang)
|
||||||
|
$titikRumah = DB::table('titik_jalans')->where('id', '>=', 4)->get();
|
||||||
|
$berhasil = 0;
|
||||||
|
|
||||||
|
foreach ($titikRumah as $titik) {
|
||||||
|
// Hilangkan kata "Rumah " biar sisa nama siswanya aja
|
||||||
|
$namaSiswa = str_replace('Rumah ', '', $titik->nama_titik);
|
||||||
|
$namaSiswa = trim($namaSiswa);
|
||||||
|
|
||||||
|
// Update latitude & longitude di tabel siswas yang namanya mirip
|
||||||
|
$update = DB::table('siswas')
|
||||||
|
->where('nama_siswa', 'LIKE', '%' . $namaSiswa . '%')
|
||||||
|
->update([
|
||||||
|
'latitude' => $titik->latitude,
|
||||||
|
'longitude' => $titik->longitude
|
||||||
|
]);
|
||||||
|
|
||||||
|
if($update) {
|
||||||
|
$berhasil++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Selesai Bosku! Berhasil menyinkronkan $berhasil data koordinat siswa!";
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
Loading…
Reference in New Issue