Update Lahan
This commit is contained in:
@@ -6,6 +6,7 @@ use App\Http\Controllers\Controller;
|
|||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use App\Models\Pertanian\Lahan;
|
use App\Models\Pertanian\Lahan;
|
||||||
use App\Models\Profile;
|
use App\Models\Profile;
|
||||||
|
use App\Models\Pertanian\Adat;
|
||||||
use App\Models\Wilayah\Provinsi;
|
use App\Models\Wilayah\Provinsi;
|
||||||
use Illuminate\Support\Facades\Storage;
|
use Illuminate\Support\Facades\Storage;
|
||||||
use Illuminate\Support\Facades\Validator;
|
use Illuminate\Support\Facades\Validator;
|
||||||
@@ -14,24 +15,73 @@ class LahanController extends Controller
|
|||||||
{
|
{
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$query = Lahan::with(['profile', 'desakelurahan'])->orderBy('created_at', 'desc');
|
$query = Lahan::with(['profile', 'desakelurahan.kecamatan.kabupatenkota.provinsi', 'adat'])
|
||||||
|
->orderBy('created_at', 'desc');
|
||||||
|
|
||||||
if ($request->search) {
|
if ($request->search) {
|
||||||
$query->where('nama', 'like', '%' . $request->search . '%')
|
$query->where(function($q) use ($request) {
|
||||||
->orWhereHas('profile', function($q) use ($request) {
|
$q->where('nama', 'like', '%' . $request->search . '%')
|
||||||
$q->where('nama', 'like', '%' . $request->search . '%');
|
->orWhereHas('profile', function($qProfile) use ($request) {
|
||||||
|
$qProfile->where('nama', 'like', '%' . $request->search . '%');
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->filled('profile_id')) {
|
||||||
|
$query->where('profile_id', $request->profile_id);
|
||||||
|
}
|
||||||
|
if ($request->filled('status_kepemilikan')) {
|
||||||
|
$query->where('status_kepemilikan', $request->status_kepemilikan);
|
||||||
|
}
|
||||||
|
if ($request->filled('adat_pemilik_id')) {
|
||||||
|
$query->where('adat_pemilik_id', $request->adat_pemilik_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->filled('desa_kelurahan_id')) {
|
||||||
|
$query->where('desa_kelurahan_id', $request->desa_kelurahan_id);
|
||||||
|
} elseif ($request->filled('kecamatan_id')) {
|
||||||
|
$query->whereHas('desakelurahan', function($q) use ($request) {
|
||||||
|
$q->where('kecamatan_id', $request->kecamatan_id);
|
||||||
|
});
|
||||||
|
} elseif ($request->filled('kabupatenkota_id')) {
|
||||||
|
$query->whereHas('desakelurahan.kecamatan', function($q) use ($request) {
|
||||||
|
$q->where('kabupatenkota_id', $request->kabupatenkota_id);
|
||||||
|
});
|
||||||
|
} elseif ($request->filled('provinsi_id')) {
|
||||||
|
$query->whereHas('desakelurahan.kecamatan.kabupatenkota', function($q) use ($request) {
|
||||||
|
$q->where('provinsi_id', $request->provinsi_id);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$lahan = $query->paginate($request->per_page ?? 10);
|
$lahan = $query->paginate($request->per_page ?? 10);
|
||||||
return view('master.lahan.index', compact('lahan'));
|
|
||||||
|
$provinsi = Provinsi::orderBy('nama', 'asc')->get();
|
||||||
|
$profiles = Profile::orderBy('nama', 'asc')->get();
|
||||||
|
$adat = Adat::orderBy('nama', 'asc')->get();
|
||||||
|
|
||||||
|
$kabupaten = [];
|
||||||
|
$kecamatan = [];
|
||||||
|
$desa = [];
|
||||||
|
|
||||||
|
if ($request->filled('provinsi_id')) {
|
||||||
|
$kabupaten = KabupatenKota::where('provinsi_id', $request->provinsi_id)->orderBy('nama', 'asc')->get();
|
||||||
|
}
|
||||||
|
if ($request->filled('kabupatenkota_id')) {
|
||||||
|
$kecamatan = Kecamatan::where('kabupatenkota_id', $request->kabupatenkota_id)->orderBy('nama', 'asc')->get();
|
||||||
|
}
|
||||||
|
if ($request->filled('kecamatan_id')) {
|
||||||
|
$desa = DesaKelurahan::where('kecamatan_id', $request->kecamatan_id)->orderBy('nama', 'asc')->get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return view('produktivitas.lahan.index', compact('lahan', 'provinsi', 'profiles', 'adat', 'kabupaten', 'kecamatan', 'desa'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function create()
|
public function create()
|
||||||
{
|
{
|
||||||
$provinsi = Provinsi::orderBy('nama', 'asc')->get();
|
$provinsi = Provinsi::orderBy('nama', 'asc')->get();
|
||||||
$profiles = Profile::orderBy('nama', 'asc')->get();
|
$profiles = Profile::orderBy('nama', 'asc')->get();
|
||||||
return view('master.lahan.add', compact('provinsi', 'profiles'));
|
$adat = Adat::orderBy('nama', 'asc')->get();
|
||||||
|
return view('produktivitas.lahan.add', compact('provinsi', 'profiles', 'adat'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function store(Request $request)
|
public function store(Request $request)
|
||||||
@@ -51,22 +101,29 @@ class LahanController extends Controller
|
|||||||
return response()->json(['status' => 'error', 'errors' => $validator->errors()], 422);
|
return response()->json(['status' => 'error', 'errors' => $validator->errors()], 422);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$pathData = null;
|
||||||
|
|
||||||
|
$keluargaPengelolaId = Profile::where('id', $request->profile_id)->value('keluarga_id');
|
||||||
|
|
||||||
if ($request->filled('path')) {
|
if ($request->filled('path')) {
|
||||||
json_decode($request->path);
|
$pathData = json_decode($request->path, true);
|
||||||
|
|
||||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||||
return response()->json(['status' => 'error', 'message' => 'Format koordinat (path) bukan JSON array yang valid.'], 422);
|
return response()->json(['status' => 'error', 'message' => 'Format koordinat (path) bukan JSON array yang valid.'], 422);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Lahan::create([
|
Lahan::create([
|
||||||
'nama' => $request->nama,
|
'nama' => $request->nama,
|
||||||
'status_kepemilikan' => $request->status_kepemilikan,
|
'status_kepemilikan' => $request->status_kepemilikan,
|
||||||
'profile_id' => $request->profile_id,
|
'profile_id' => $request->profile_id,
|
||||||
'desa_kelurahan_id' => $request->desa_kelurahan_id,
|
'keluarga_pengelola_id' => $keluargaPengelolaId ?? null,
|
||||||
'luas_lahan' => $request->luas_lahan,
|
'desa_kelurahan_id' => $request->desa_kelurahan_id,
|
||||||
'path' => $request->path,
|
'adat_pemilik_id' => $request->adat_pemilik_id,
|
||||||
'created_by' => auth()->id(),
|
'luas_lahan' => $request->luas_lahan,
|
||||||
'updated_by' => auth()->id(),
|
'path' => $pathData,
|
||||||
|
'created_by' => auth()->id(),
|
||||||
|
'updated_by' => auth()->id(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return response()->json(['status' => 'success', 'message' => 'Lahan berhasil ditambahkan.']);
|
return response()->json(['status' => 'success', 'message' => 'Lahan berhasil ditambahkan.']);
|
||||||
@@ -74,9 +131,89 @@ class LahanController extends Controller
|
|||||||
|
|
||||||
public function show($id)
|
public function show($id)
|
||||||
{
|
{
|
||||||
$lahan = Lahan::with(['profile', 'desakelurahan.kecamatan.kabupatenkota.provinsi', 'tanaman.komoditas'])->findOrFail($id);
|
$lahan = Lahan::with(['profile', 'desakelurahan.kecamatan.kabupatenkota.provinsi', 'tanaman.komoditas', 'adat'])->findOrFail($id);
|
||||||
|
|
||||||
return view('master.lahan.view', compact('lahan'));
|
return view('produktivitas.lahan.view', compact('lahan'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function edit($id)
|
||||||
|
{
|
||||||
|
$lahan = Lahan::with('desakelurahan.kecamatan.kabupatenkota.provinsi')->findOrFail($id);
|
||||||
|
|
||||||
|
$provinsi = Provinsi::orderBy('nama', 'asc')->get();
|
||||||
|
$profiles = Profile::orderBy('nama', 'asc')->get();
|
||||||
|
$adat = Adat::orderBy('nama', 'asc')->get();
|
||||||
|
|
||||||
|
return view('produktivitas.lahan.edit', compact('lahan', 'provinsi', 'profiles', 'adat'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
$validator = Validator::make($request->all(), [
|
||||||
|
'nama' => ['required', 'string', 'max:255'],
|
||||||
|
'status_kepemilikan' => ['required', 'string', 'max:255'],
|
||||||
|
'profile_id' => ['required'],
|
||||||
|
'keluarga_pengelola_id' => ['nullable'],
|
||||||
|
'adat_pemilik_id' => ['nullable'],
|
||||||
|
'desa_kelurahan_id' => ['nullable'],
|
||||||
|
'luas_lahan' => ['nullable', 'numeric'],
|
||||||
|
'path' => ['nullable', 'string'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($validator->fails()) {
|
||||||
|
return response()->json(['status' => 'error', 'errors' => $validator->errors()], 422);
|
||||||
|
}
|
||||||
|
|
||||||
|
$lahan = Lahan::findOrFail($id);
|
||||||
|
|
||||||
|
$pathData = null;
|
||||||
|
|
||||||
|
$keluargaPengelolaId = Profile::where('id', $request->profile_id)->value('keluarga_id');
|
||||||
|
|
||||||
|
if ($request->filled('path')) {
|
||||||
|
$pathData = json_decode($request->path, true);
|
||||||
|
|
||||||
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||||
|
return response()->json(['status' => 'error', 'message' => 'Format koordinat (path) bukan JSON array yang valid.'], 422);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$lahan->update([
|
||||||
|
'nama' => $request->nama,
|
||||||
|
'status_kepemilikan' => $request->status_kepemilikan,
|
||||||
|
'profile_id' => $request->profile_id,
|
||||||
|
'keluarga_pengelola_id' => $keluargaPengelolaId ?? null,
|
||||||
|
'desa_kelurahan_id' => $request->desa_kelurahan_id,
|
||||||
|
'adat_pemilik_id' => $request->status_kepemilikan === 'adat' ? $request->adat_pemilik_id : null,
|
||||||
|
'luas_lahan' => $request->luas_lahan,
|
||||||
|
'path' => $pathData,
|
||||||
|
'updated_by' => auth()->id(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json(['status' => 'success', 'message' => 'Data Lahan berhasil diperbarui.']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function destroy($id)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$lahan = Lahan::findOrFail($id);
|
||||||
|
|
||||||
|
$lahan->deleted_by = auth()->id(); // atau auth()->user()->id
|
||||||
|
$lahan->save();
|
||||||
|
|
||||||
|
$lahan->delete();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'success',
|
||||||
|
'message' => 'Data lahan berhasil dihapus.'
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return response()->json([
|
||||||
|
'status' => 'error',
|
||||||
|
'message' => 'Gagal menghapus data Lahan. Silakan coba lagi nanti.'
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
|
|||||||
use App\Models\Wilayah\DesaKelurahan;
|
use App\Models\Wilayah\DesaKelurahan;
|
||||||
use App\Models\Pertanian\Tanaman;
|
use App\Models\Pertanian\Tanaman;
|
||||||
use App\Models\Profile;
|
use App\Models\Profile;
|
||||||
|
use App\Models\Pertanian\Adat;
|
||||||
use App\Enums\StatusLahan;
|
use App\Enums\StatusLahan;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||||
@@ -46,6 +47,11 @@ class Lahan extends Model
|
|||||||
return $this->belongsTo(DesaKelurahan::class, 'desa_kelurahan_id');
|
return $this->belongsTo(DesaKelurahan::class, 'desa_kelurahan_id');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function adat(): BelongsTo
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Adat::class, 'adat_pemilik_id');
|
||||||
|
}
|
||||||
|
|
||||||
public function tanaman(): HasMany
|
public function tanaman(): HasMany
|
||||||
{
|
{
|
||||||
return $this->hasMany(Tanaman::class, 'lahan_id');
|
return $this->hasMany(Tanaman::class, 'lahan_id');
|
||||||
|
|||||||
@@ -52,6 +52,10 @@
|
|||||||
<link rel="stylesheet" href="{{ asset('assets/vendor/fonts/flag-icons.css') }}" />
|
<link rel="stylesheet" href="{{ asset('assets/vendor/fonts/flag-icons.css') }}" />
|
||||||
|
|
||||||
<link rel="stylesheet" href="{{ asset('assets/vendor/css/pages/cards-advance.css') }}" />
|
<link rel="stylesheet" href="{{ asset('assets/vendor/css/pages/cards-advance.css') }}" />
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
||||||
|
|
||||||
|
|
||||||
@stack('style')
|
@stack('style')
|
||||||
<script src="{{ asset('assets/vendor/js/helpers.js') }}"></script>
|
<script src="{{ asset('assets/vendor/js/helpers.js') }}"></script>
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,429 @@
|
|||||||
|
@extends('layout.main')
|
||||||
|
|
||||||
|
@push('style')
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#map {
|
||||||
|
height: 600px;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@endpush
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container-xxl flex-grow-1 container-p-y">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header border-bottom mb-4 d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="card-title mb-0">Tambah Data Lahan</h5>
|
||||||
|
<a href="{{ route('lahan.index') }}" class="btn btn-sm btn-label-secondary">
|
||||||
|
<i class="ti tabler-arrow-left me-1"></i> Kembali
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<form id="formLahan" action="{{ route('lahan.store') }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-6 mb-4">
|
||||||
|
<h6 class="mb-3 text-primary"><i class="ti tabler-info-circle me-1"></i> Form Info Lahan</h6>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Nama Lahan <span class="text-danger">*</span></label>
|
||||||
|
<input type="text" name="nama" class="form-control" placeholder="Masukkan nama lahan" required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Pemilik (Profile) <span class="text-danger">*</span></label>
|
||||||
|
<select name="profile_id" class="form-select" required>
|
||||||
|
<option value="">Pilih Pemilik</option>
|
||||||
|
@foreach($profiles ?? [] as $profile)
|
||||||
|
<option value="{{ $profile->id }}">{{ $profile->nama }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Status Kepemilikan <span class="text-danger">*</span></label>
|
||||||
|
<select name="status_kepemilikan" id="status_kepemilikan" class="form-select" required>
|
||||||
|
<option value="">Pilih Status</option>
|
||||||
|
<option value="sendiri">Milik Pribadi</option>
|
||||||
|
<option value="sewa">Sewa</option>
|
||||||
|
<option value="adat">Tanah Adat</option>
|
||||||
|
<option value="lainnya">Lainnya</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Luas Lahan (Ha/m2) <span class="text-danger">*</span></label>
|
||||||
|
<input type="number" step="0.01" name="luas_lahan" class="form-control" placeholder="Contoh: 1.5" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3 d-none" id="adat_wrapper">
|
||||||
|
<label class="form-label text-warning">Data Adat Pemilik <span class="text-danger">*</span></label>
|
||||||
|
<select name="adat_pemilik_id" id="adat_pemilik_id" class="form-select border-warning">
|
||||||
|
<option value="">Pilih Adat</option>
|
||||||
|
@foreach($adat as $adat)
|
||||||
|
<option value="{{ $adat->id }}">{{ $adat->nama }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="my-4">
|
||||||
|
<h6 class="mb-3 text-primary"><i class="ti tabler-map-pin me-1"></i> Lokasi Wilayah</h6>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Provinsi <span class="text-danger">*</span></label>
|
||||||
|
<select name="provinsi_id" id="provinsi_id" class="form-select" required>
|
||||||
|
<option value="" data-path="">Pilih Provinsi</option>
|
||||||
|
@foreach($provinsi as $prov)
|
||||||
|
<option value="{{ $prov->id }}" data-path="{{ is_string($prov->path) ? $prov->path : json_encode($prov->path) }}">
|
||||||
|
{{ $prov->nama }}
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Kabupaten/Kota <span class="text-danger">*</span></label>
|
||||||
|
<select name="kabupatenkota_id" id="kabupatenkota_id" class="form-select" disabled required>
|
||||||
|
<option value="" data-path="">Pilih Kabupaten/Kota</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Kecamatan <span class="text-danger">*</span></label>
|
||||||
|
<select name="kecamatan_id" id="kecamatan_id" class="form-select" disabled required>
|
||||||
|
<option value="" data-path="">Pilih Kecamatan</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Desa/Kelurahan <span class="text-danger">*</span></label>
|
||||||
|
<select name="desa_kelurahan_id" id="desa_kelurahan_id" class="form-select" disabled required>
|
||||||
|
<option value="" data-path="">Pilih Desa/Kelurahan</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
<label class="form-label">Raw Data Koordinat Lahan (Auto-generated JSON) <span class="text-danger">*</span></label>
|
||||||
|
<textarea name="path" id="path" class="form-control bg-lighter font-monospace" rows="4" readonly required placeholder="Koordinat akan terisi otomatis setelah Anda menggambar polygon di peta..."></textarea>
|
||||||
|
<small class="text-muted">Pastikan menggambar polygon di peta dengan menyambungkan titik akhir ke titik awal.</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-lg-6 mb-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
|
<h6 class="text-primary mb-0"><i class="ti tabler-map me-1"></i> Gambar Area Lahan</h6>
|
||||||
|
<span class="badge bg-label-info">Gunakan tool ⬟ di kiri peta</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="map" class="border rounded shadow-sm"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col-12 text-end">
|
||||||
|
<button type="reset" class="btn btn-label-secondary me-2">Reset</button>
|
||||||
|
<button type="submit" class="btn btn-primary"><i class="ti tabler-device-floppy me-2"></i> Simpan Data</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
|
||||||
|
let map = L.map('map').setView([-0.789275, 113.921327], 5); // Default: Tengah Indonesia
|
||||||
|
|
||||||
|
L.tileLayer('http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}', {
|
||||||
|
maxZoom: 22,
|
||||||
|
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
|
||||||
|
attribution: '© Google Maps Satellite'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
let regionBoundaryLayer = L.featureGroup().addTo(map);
|
||||||
|
|
||||||
|
function focusToRegionBoundary(selectElement) {
|
||||||
|
regionBoundaryLayer.clearLayers(); // Bersihkan garis wilayah sebelumnya
|
||||||
|
|
||||||
|
let selectedOption = selectElement.options[selectElement.selectedIndex];
|
||||||
|
if (!selectedOption || !selectedOption.hasAttribute('data-path')) return;
|
||||||
|
|
||||||
|
let pathStr = selectedOption.getAttribute('data-path');
|
||||||
|
if (!pathStr || pathStr === "null" || pathStr === "") return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let rawData = typeof pathStr === 'string' ? JSON.parse(pathStr) : pathStr;
|
||||||
|
|
||||||
|
if (Array.isArray(rawData) && rawData.length > 0) {
|
||||||
|
|
||||||
|
function formatCoordinates(coords) {
|
||||||
|
if (coords.length === 2 && typeof coords[0] === 'number') {
|
||||||
|
return [coords[0], coords[1]]; // JANGAN DIBALIK
|
||||||
|
}
|
||||||
|
return coords.map(formatCoordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
let latLngs = formatCoordinates(rawData);
|
||||||
|
|
||||||
|
let polygon = L.polygon(latLngs, {
|
||||||
|
color: '#3b5998',
|
||||||
|
fillColor: '#3b5998',
|
||||||
|
fillOpacity: 0.1,
|
||||||
|
weight: 2,
|
||||||
|
dashArray: '5, 5',
|
||||||
|
interactive: false
|
||||||
|
});
|
||||||
|
|
||||||
|
regionBoundaryLayer.addLayer(polygon);
|
||||||
|
map.fitBounds(polygon.getBounds(), { padding: [20, 20] });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Format JSON path wilayah tidak valid:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let drawnItems = new L.FeatureGroup();
|
||||||
|
map.addLayer(drawnItems);
|
||||||
|
|
||||||
|
let drawControl = new L.Control.Draw({
|
||||||
|
draw: {
|
||||||
|
polygon: {
|
||||||
|
allowIntersection: false,
|
||||||
|
showArea: true,
|
||||||
|
shapeOptions: {
|
||||||
|
color: '#28c76f',
|
||||||
|
fillColor: '#28c76f',
|
||||||
|
fillOpacity: 0.4,
|
||||||
|
weight: 3
|
||||||
|
}
|
||||||
|
},
|
||||||
|
polyline: false,
|
||||||
|
circle: false,
|
||||||
|
rectangle: false,
|
||||||
|
marker: false,
|
||||||
|
circlemarker: false
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
featureGroup: drawnItems,
|
||||||
|
remove: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
map.addControl(drawControl);
|
||||||
|
|
||||||
|
map.on(L.Draw.Event.CREATED, function (e) {
|
||||||
|
let layer = e.layer;
|
||||||
|
|
||||||
|
drawnItems.clearLayers();
|
||||||
|
drawnItems.addLayer(layer);
|
||||||
|
|
||||||
|
updatePathTextarea(layer);
|
||||||
|
});
|
||||||
|
|
||||||
|
map.on(L.Draw.Event.EDITED, function (e) {
|
||||||
|
e.layers.eachLayer(function (layer) {
|
||||||
|
updatePathTextarea(layer);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
map.on(L.Draw.Event.DELETED, function () {
|
||||||
|
document.getElementById('path').value = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
function updatePathTextarea(layer) {
|
||||||
|
let latlngs = layer.getLatLngs()[0];
|
||||||
|
let pathData = latlngs.map(function(latlng) {
|
||||||
|
return [latlng.lng, latlng.lat];
|
||||||
|
});
|
||||||
|
document.getElementById('path').value = JSON.stringify(pathData);
|
||||||
|
}
|
||||||
|
|
||||||
|
let statusSelect = document.getElementById('status_kepemilikan');
|
||||||
|
let adatWrapper = document.getElementById('adat_wrapper');
|
||||||
|
let adatInput = document.getElementById('adat_pemilik_id');
|
||||||
|
|
||||||
|
statusSelect.addEventListener('change', function() {
|
||||||
|
if (this.value === 'adat') {
|
||||||
|
adatWrapper.classList.remove('d-none');
|
||||||
|
adatInput.setAttribute('required', 'required');
|
||||||
|
} else {
|
||||||
|
adatWrapper.classList.add('d-none');
|
||||||
|
adatInput.removeAttribute('required');
|
||||||
|
adatInput.value = '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const provSelect = document.getElementById('provinsi_id');
|
||||||
|
const kabSelect = document.getElementById('kabupatenkota_id');
|
||||||
|
const kecSelect = document.getElementById('kecamatan_id');
|
||||||
|
const desaSelect = document.getElementById('desa_kelurahan_id');
|
||||||
|
|
||||||
|
function resetDropdown(element, defaultText) {
|
||||||
|
element.innerHTML = `<option value="" data-path="">${defaultText}</option>`;
|
||||||
|
element.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
provSelect.addEventListener('change', function() {
|
||||||
|
let provId = this.value;
|
||||||
|
focusToRegionBoundary(this);
|
||||||
|
|
||||||
|
resetDropdown(kabSelect, 'Pilih Kabupaten/Kota');
|
||||||
|
resetDropdown(kecSelect, 'Pilih Kecamatan');
|
||||||
|
resetDropdown(desaSelect, 'Pilih Desa/Kelurahan');
|
||||||
|
|
||||||
|
if (provId) {
|
||||||
|
kabSelect.innerHTML = '<option value="" data-path="">Memuat...</option>';
|
||||||
|
fetch(`{{ url('kabupatenkotabyprovinsi') }}/${provId}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
resetDropdown(kabSelect, 'Pilih Kabupaten/Kota');
|
||||||
|
kabSelect.disabled = false;
|
||||||
|
data.forEach(item => {
|
||||||
|
let option = new Option(item.nama, item.id);
|
||||||
|
if(item.path) {
|
||||||
|
option.setAttribute('data-path', typeof item.path === 'string' ? item.path : JSON.stringify(item.path));
|
||||||
|
}
|
||||||
|
kabSelect.add(option);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error fetching Kabupaten:', error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
kabSelect.addEventListener('change', function() {
|
||||||
|
let kabId = this.value;
|
||||||
|
focusToRegionBoundary(this);
|
||||||
|
|
||||||
|
resetDropdown(kecSelect, 'Pilih Kecamatan');
|
||||||
|
resetDropdown(desaSelect, 'Pilih Desa/Kelurahan');
|
||||||
|
|
||||||
|
if (kabId) {
|
||||||
|
kecSelect.innerHTML = '<option value="" data-path="">Memuat...</option>';
|
||||||
|
fetch(`{{ url('kecamatanbykabupatenkota') }}/${kabId}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
resetDropdown(kecSelect, 'Pilih Kecamatan');
|
||||||
|
kecSelect.disabled = false;
|
||||||
|
data.forEach(item => {
|
||||||
|
let option = new Option(item.nama, item.id);
|
||||||
|
if(item.path) {
|
||||||
|
option.setAttribute('data-path', typeof item.path === 'string' ? item.path : JSON.stringify(item.path));
|
||||||
|
}
|
||||||
|
kecSelect.add(option);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error fetching Kecamatan:', error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
kecSelect.addEventListener('change', function() {
|
||||||
|
let kecId = this.value;
|
||||||
|
focusToRegionBoundary(this);
|
||||||
|
|
||||||
|
resetDropdown(desaSelect, 'Pilih Desa/Kelurahan');
|
||||||
|
|
||||||
|
if (kecId) {
|
||||||
|
desaSelect.innerHTML = '<option value="" data-path="">Memuat...</option>';
|
||||||
|
fetch(`{{ url('desakelurahanbykecamatan') }}/${kecId}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
resetDropdown(desaSelect, 'Pilih Desa/Kelurahan');
|
||||||
|
desaSelect.disabled = false;
|
||||||
|
data.forEach(item => {
|
||||||
|
let option = new Option(item.nama, item.id);
|
||||||
|
if(item.path) {
|
||||||
|
option.setAttribute('data-path', typeof item.path === 'string' ? item.path : JSON.stringify(item.path));
|
||||||
|
}
|
||||||
|
desaSelect.add(option);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error fetching Desa:', error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
desaSelect.addEventListener('change', function() {
|
||||||
|
focusToRegionBoundary(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
const formLahan = document.getElementById('formLahan');
|
||||||
|
|
||||||
|
if(formLahan) {
|
||||||
|
formLahan.addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let form = this;
|
||||||
|
let formData = new FormData(form);
|
||||||
|
let submitBtn = form.querySelector('button[type="submit"]');
|
||||||
|
let originalBtnText = submitBtn.innerHTML;
|
||||||
|
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
submitBtn.innerHTML = 'Menyimpan...';
|
||||||
|
|
||||||
|
fetch(form.action, {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
headers: {
|
||||||
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
submitBtn.innerHTML = originalBtnText;
|
||||||
|
|
||||||
|
if (data.status === 'success') {
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Berhasil!',
|
||||||
|
text: data.message,
|
||||||
|
showConfirmButton: false,
|
||||||
|
timer: 2000
|
||||||
|
}).then(() => {
|
||||||
|
window.location.href = "{{ route('lahan.index') }}";
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let errorMsg = data.message || 'Terjadi kesalahan saat menyimpan data.';
|
||||||
|
if (data.errors) {
|
||||||
|
errorMsg = Object.values(data.errors).map(err => err.join(', ')).join('<br>');
|
||||||
|
}
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'error',
|
||||||
|
title: 'Gagal Menyimpan!',
|
||||||
|
html: errorMsg
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
submitBtn.innerHTML = originalBtnText;
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'error',
|
||||||
|
title: 'Error Sistem',
|
||||||
|
text: 'Terjadi kesalahan pada server atau koneksi internet.'
|
||||||
|
});
|
||||||
|
console.error('Error:', error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
@@ -0,0 +1,466 @@
|
|||||||
|
@extends('layout.main')
|
||||||
|
|
||||||
|
@push('style')
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.css" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
#map {
|
||||||
|
height: 600px;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@endpush
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container-xxl flex-grow-1 container-p-y">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header border-bottom mb-4 d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="card-title mb-0">Edit Data Lahan</h5>
|
||||||
|
<a href="{{ route('lahan.index') }}" class="btn btn-sm btn-label-secondary">
|
||||||
|
<i class="ti tabler-arrow-left me-1"></i> Kembali
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<form id="formLahan" action="{{ route('lahan.update', $lahan->id) }}" method="POST">
|
||||||
|
@csrf
|
||||||
|
@method('PUT')
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-6 mb-4">
|
||||||
|
<h6 class="mb-3 text-primary"><i class="ti tabler-info-circle me-1"></i> Form Info Lahan</h6>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Nama Lahan <span class="text-danger">*</span></label>
|
||||||
|
<input type="text" name="nama" class="form-control" value="{{ old('nama', $lahan->nama) }}" placeholder="Masukkan nama lahan" required />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Pemilik (Profile) <span class="text-danger">*</span></label>
|
||||||
|
<select name="profile_id" class="form-select" required>
|
||||||
|
<option value="">Pilih Pemilik</option>
|
||||||
|
@foreach($profiles ?? [] as $profile)
|
||||||
|
<option value="{{ $profile->id }}" {{ old('profile_id', $lahan->profile_id) == $profile->id ? 'selected' : '' }}>
|
||||||
|
{{ $profile->nama }}
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Status Kepemilikan <span class="text-danger">*</span></label>
|
||||||
|
<select name="status_kepemilikan" id="status_kepemilikan" class="form-select" required>
|
||||||
|
<option value="">Pilih Status</option>
|
||||||
|
@php $status = old('status_kepemilikan', $lahan->status_kepemilikan->value); @endphp
|
||||||
|
<option value="sendiri" {{ $status == 'sendiri' ? 'selected' : '' }}>Milik Pribadi</option>
|
||||||
|
<option value="sewa" {{ $status == 'sewa' ? 'selected' : '' }}>Sewa</option>
|
||||||
|
<option value="adat" {{ $status == 'adat' ? 'selected' : '' }}>Tanah Adat</option>
|
||||||
|
<option value="lainnya" {{ $status == 'lainnya' ? 'selected' : '' }}>Lainnya</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Luas Lahan (Ha/m2) <span class="text-danger">*</span></label>
|
||||||
|
<input type="number" step="0.01" name="luas_lahan" class="form-control" value="{{ old('luas_lahan', $lahan->luas_lahan) }}" placeholder="Contoh: 1.5" required />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3 d-none" id="adat_wrapper">
|
||||||
|
<label class="form-label text-warning">Data Adat Pemilik <span class="text-danger">*</span></label>
|
||||||
|
<select name="adat_pemilik_id" id="adat_pemilik_id" class="form-select border-warning">
|
||||||
|
<option value="">Pilih Adat</option>
|
||||||
|
@foreach($adat as $item)
|
||||||
|
<option value="{{ $item->id }}" {{ old('adat_pemilik_id', $lahan->adat_pemilik_id) == $item->id ? 'selected' : '' }}>
|
||||||
|
{{ $item->nama }}
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr class="my-4">
|
||||||
|
<h6 class="mb-3 text-primary"><i class="ti tabler-map-pin me-1"></i> Lokasi Wilayah</h6>
|
||||||
|
|
||||||
|
@php
|
||||||
|
$selectedDesa = $lahan->desakelurahan ?? null;
|
||||||
|
$selectedKec = $selectedDesa ? $selectedDesa->kecamatan : null;
|
||||||
|
$selectedKab = $selectedKec ? $selectedKec->kabupatenkota : null;
|
||||||
|
$selectedProv = $selectedKab ? $selectedKab->provinsi : null;
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Provinsi <span class="text-danger">*</span></label>
|
||||||
|
<select name="provinsi_id" id="provinsi_id" class="form-select" required>
|
||||||
|
<option value="" data-path="">Pilih Provinsi</option>
|
||||||
|
@foreach($provinsi as $prov)
|
||||||
|
<option value="{{ $prov->id }}" data-path="{{ is_string($prov->path) ? $prov->path : json_encode($prov->path) }}" {{ ($selectedProv && $selectedProv->id == $prov->id) ? 'selected' : '' }}>
|
||||||
|
{{ $prov->nama }}
|
||||||
|
</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Kabupaten/Kota <span class="text-danger">*</span></label>
|
||||||
|
<select name="kabupatenkota_id" id="kabupatenkota_id" class="form-select" required>
|
||||||
|
<option value="" data-path="">Pilih Kabupaten/Kota</option>
|
||||||
|
@if($selectedKab)
|
||||||
|
<option value="{{ $selectedKab->id }}" selected data-path="{{ is_string($selectedKab->path) ? $selectedKab->path : json_encode($selectedKab->path) }}">{{ $selectedKab->nama }}</option>
|
||||||
|
@endif
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Kecamatan <span class="text-danger">*</span></label>
|
||||||
|
<select name="kecamatan_id" id="kecamatan_id" class="form-select" required>
|
||||||
|
<option value="" data-path="">Pilih Kecamatan</option>
|
||||||
|
@if($selectedKec)
|
||||||
|
<option value="{{ $selectedKec->id }}" selected data-path="{{ is_string($selectedKec->path) ? $selectedKec->path : json_encode($selectedKec->path) }}">{{ $selectedKec->nama }}</option>
|
||||||
|
@endif
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Desa/Kelurahan <span class="text-danger">*</span></label>
|
||||||
|
<select name="desa_kelurahan_id" id="desa_kelurahan_id" class="form-select" required>
|
||||||
|
<option value="" data-path="">Pilih Desa/Kelurahan</option>
|
||||||
|
@if($selectedDesa)
|
||||||
|
<option value="{{ $selectedDesa->id }}" selected data-path="{{ is_string($selectedDesa->path) ? $selectedDesa->path : json_encode($selectedDesa->path) }}">{{ $selectedDesa->nama }}</option>
|
||||||
|
@endif
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
<label class="form-label">Raw Data Koordinat Lahan (Auto-generated JSON) <span class="text-danger">*</span></label>
|
||||||
|
<textarea name="path" id="path" class="form-control bg-lighter font-monospace" rows="4" readonly required placeholder="Koordinat akan terisi otomatis setelah Anda menggambar polygon di peta...">{{ old('path', is_string($lahan->path) ? $lahan->path : json_encode($lahan->path)) }}</textarea>
|
||||||
|
<small class="text-muted">Gunakan tombol edit (pensil) atau hapus (tong sampah) di peta untuk mengubah bentuk lahan.</small>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-lg-6 mb-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
|
<h6 class="text-primary mb-0"><i class="ti tabler-map me-1"></i> Gambar Area Lahan</h6>
|
||||||
|
<span class="badge bg-label-warning">Mode Edit Polygon Aktif</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="map" class="border rounded shadow-sm"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row mt-3">
|
||||||
|
<div class="col-12 text-end">
|
||||||
|
<a href="{{ route('lahan.index') }}" class="btn btn-label-secondary me-2">Batal</a>
|
||||||
|
<button type="submit" class="btn btn-primary"><i class="ti tabler-device-floppy me-2"></i> Update Data</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet.draw/1.0.4/leaflet.draw.js"></script>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
|
||||||
|
let map = L.map('map').setView([-0.789275, 113.921327], 5);
|
||||||
|
|
||||||
|
L.tileLayer('http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}', {
|
||||||
|
maxZoom: 22,
|
||||||
|
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
|
||||||
|
attribution: '© Google Maps Satellite'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
let regionBoundaryLayer = L.featureGroup().addTo(map);
|
||||||
|
|
||||||
|
function focusToRegionBoundary(selectElement, shouldZoom = true) {
|
||||||
|
regionBoundaryLayer.clearLayers();
|
||||||
|
|
||||||
|
let selectedOption = selectElement.options[selectElement.selectedIndex];
|
||||||
|
if (!selectedOption || !selectedOption.hasAttribute('data-path')) return;
|
||||||
|
|
||||||
|
let pathStr = selectedOption.getAttribute('data-path');
|
||||||
|
if (!pathStr || pathStr === "null" || pathStr === "") return;
|
||||||
|
|
||||||
|
try {
|
||||||
|
let rawData = typeof pathStr === 'string' ? JSON.parse(pathStr) : pathStr;
|
||||||
|
|
||||||
|
if (Array.isArray(rawData) && rawData.length > 0) {
|
||||||
|
function formatCoordinates(coords) {
|
||||||
|
if (coords.length === 2 && typeof coords[0] === 'number') {
|
||||||
|
return [coords[0], coords[1]];
|
||||||
|
}
|
||||||
|
return coords.map(formatCoordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
let latLngs = formatCoordinates(rawData);
|
||||||
|
|
||||||
|
let polygon = L.polygon(latLngs, {
|
||||||
|
color: '#3b5998',
|
||||||
|
fillColor: '#3b5998',
|
||||||
|
fillOpacity: 0.1,
|
||||||
|
weight: 2,
|
||||||
|
dashArray: '5, 5',
|
||||||
|
interactive: false
|
||||||
|
});
|
||||||
|
|
||||||
|
regionBoundaryLayer.addLayer(polygon);
|
||||||
|
if (shouldZoom) map.fitBounds(polygon.getBounds(), { padding: [20, 20] });
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Format JSON path wilayah tidak valid:", error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let drawnItems = new L.FeatureGroup();
|
||||||
|
map.addLayer(drawnItems);
|
||||||
|
|
||||||
|
let drawControl = new L.Control.Draw({
|
||||||
|
draw: {
|
||||||
|
polygon: {
|
||||||
|
allowIntersection: false,
|
||||||
|
showArea: true,
|
||||||
|
shapeOptions: { color: '#28c76f', fillColor: '#28c76f', fillOpacity: 0.4, weight: 3 }
|
||||||
|
},
|
||||||
|
polyline: false, circle: false, rectangle: false, marker: false, circlemarker: false
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
featureGroup: drawnItems,
|
||||||
|
remove: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
map.addControl(drawControl);
|
||||||
|
|
||||||
|
let rawLahanPath = document.getElementById('path').value;
|
||||||
|
if (rawLahanPath) {
|
||||||
|
try {
|
||||||
|
let parsedPath = JSON.parse(rawLahanPath);
|
||||||
|
if (Array.isArray(parsedPath) && parsedPath.length > 0) {
|
||||||
|
let existingLatLngs = parsedPath.map(function(coord) {
|
||||||
|
return [coord[1], coord[0]];
|
||||||
|
});
|
||||||
|
|
||||||
|
let existingPolygon = L.polygon(existingLatLngs, {
|
||||||
|
color: '#28c76f', fillColor: '#28c76f', fillOpacity: 0.4, weight: 3
|
||||||
|
});
|
||||||
|
|
||||||
|
drawnItems.addLayer(existingPolygon);
|
||||||
|
|
||||||
|
setTimeout(() => { map.fitBounds(existingPolygon.getBounds(), { padding: [30, 30] }); }, 500);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Gagal merender polygon lahan eksisting: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map.on(L.Draw.Event.CREATED, function (e) {
|
||||||
|
let layer = e.layer;
|
||||||
|
drawnItems.clearLayers();
|
||||||
|
drawnItems.addLayer(layer);
|
||||||
|
updatePathTextarea(layer);
|
||||||
|
});
|
||||||
|
|
||||||
|
map.on(L.Draw.Event.EDITED, function (e) {
|
||||||
|
e.layers.eachLayer(function (layer) {
|
||||||
|
updatePathTextarea(layer);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
map.on(L.Draw.Event.DELETED, function () {
|
||||||
|
document.getElementById('path').value = '';
|
||||||
|
});
|
||||||
|
|
||||||
|
function updatePathTextarea(layer) {
|
||||||
|
let latlngs = layer.getLatLngs()[0];
|
||||||
|
let pathData = latlngs.map(function(latlng) {
|
||||||
|
return [latlng.lng, latlng.lat];
|
||||||
|
});
|
||||||
|
document.getElementById('path').value = JSON.stringify(pathData);
|
||||||
|
}
|
||||||
|
|
||||||
|
let statusSelect = document.getElementById('status_kepemilikan');
|
||||||
|
let adatWrapper = document.getElementById('adat_wrapper');
|
||||||
|
let adatInput = document.getElementById('adat_pemilik_id');
|
||||||
|
|
||||||
|
function toggleAdat() {
|
||||||
|
if (statusSelect.value === 'adat') {
|
||||||
|
adatWrapper.classList.remove('d-none');
|
||||||
|
adatInput.setAttribute('required', 'required');
|
||||||
|
} else {
|
||||||
|
adatWrapper.classList.add('d-none');
|
||||||
|
adatInput.removeAttribute('required');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
statusSelect.addEventListener('change', toggleAdat);
|
||||||
|
toggleAdat();
|
||||||
|
|
||||||
|
const provSelect = document.getElementById('provinsi_id');
|
||||||
|
const kabSelect = document.getElementById('kabupatenkota_id');
|
||||||
|
const kecSelect = document.getElementById('kecamatan_id');
|
||||||
|
const desaSelect = document.getElementById('desa_kelurahan_id');
|
||||||
|
|
||||||
|
if (desaSelect.value) focusToRegionBoundary(desaSelect, false);
|
||||||
|
else if (provSelect.value) focusToRegionBoundary(provSelect, false);
|
||||||
|
|
||||||
|
function resetDropdown(element, defaultText) {
|
||||||
|
element.innerHTML = `<option value="" data-path="">${defaultText}</option>`;
|
||||||
|
element.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
provSelect.addEventListener('change', function() {
|
||||||
|
let provId = this.value;
|
||||||
|
focusToRegionBoundary(this);
|
||||||
|
|
||||||
|
resetDropdown(kabSelect, 'Pilih Kabupaten/Kota');
|
||||||
|
resetDropdown(kecSelect, 'Pilih Kecamatan');
|
||||||
|
resetDropdown(desaSelect, 'Pilih Desa/Kelurahan');
|
||||||
|
|
||||||
|
if (provId) {
|
||||||
|
kabSelect.innerHTML = '<option value="" data-path="">Memuat...</option>';
|
||||||
|
fetch(`{{ url('kabupatenkotabyprovinsi') }}/${provId}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
resetDropdown(kabSelect, 'Pilih Kabupaten/Kota');
|
||||||
|
kabSelect.disabled = false;
|
||||||
|
data.forEach(item => {
|
||||||
|
let option = new Option(item.nama, item.id);
|
||||||
|
if(item.path) {
|
||||||
|
option.setAttribute('data-path', typeof item.path === 'string' ? item.path : JSON.stringify(item.path));
|
||||||
|
}
|
||||||
|
kabSelect.add(option);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error fetching Kabupaten:', error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
kabSelect.addEventListener('change', function() {
|
||||||
|
let kabId = this.value;
|
||||||
|
focusToRegionBoundary(this);
|
||||||
|
|
||||||
|
resetDropdown(kecSelect, 'Pilih Kecamatan');
|
||||||
|
resetDropdown(desaSelect, 'Pilih Desa/Kelurahan');
|
||||||
|
|
||||||
|
if (kabId) {
|
||||||
|
kecSelect.innerHTML = '<option value="" data-path="">Memuat...</option>';
|
||||||
|
fetch(`{{ url('kecamatanbykabupatenkota') }}/${kabId}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
resetDropdown(kecSelect, 'Pilih Kecamatan');
|
||||||
|
kecSelect.disabled = false;
|
||||||
|
data.forEach(item => {
|
||||||
|
let option = new Option(item.nama, item.id);
|
||||||
|
if(item.path) {
|
||||||
|
option.setAttribute('data-path', typeof item.path === 'string' ? item.path : JSON.stringify(item.path));
|
||||||
|
}
|
||||||
|
kecSelect.add(option);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error fetching Kecamatan:', error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
kecSelect.addEventListener('change', function() {
|
||||||
|
let kecId = this.value;
|
||||||
|
focusToRegionBoundary(this);
|
||||||
|
|
||||||
|
resetDropdown(desaSelect, 'Pilih Desa/Kelurahan');
|
||||||
|
|
||||||
|
if (kecId) {
|
||||||
|
desaSelect.innerHTML = '<option value="" data-path="">Memuat...</option>';
|
||||||
|
fetch(`{{ url('desakelurahanbykecamatan') }}/${kecId}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
resetDropdown(desaSelect, 'Pilih Desa/Kelurahan');
|
||||||
|
desaSelect.disabled = false;
|
||||||
|
data.forEach(item => {
|
||||||
|
let option = new Option(item.nama, item.id);
|
||||||
|
if(item.path) {
|
||||||
|
option.setAttribute('data-path', typeof item.path === 'string' ? item.path : JSON.stringify(item.path));
|
||||||
|
}
|
||||||
|
desaSelect.add(option);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(error => console.error('Error fetching Desa:', error));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
desaSelect.addEventListener('change', function() {
|
||||||
|
focusToRegionBoundary(this);
|
||||||
|
});
|
||||||
|
|
||||||
|
const formLahan = document.getElementById('formLahan');
|
||||||
|
|
||||||
|
if(formLahan) {
|
||||||
|
formLahan.addEventListener('submit', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
let form = this;
|
||||||
|
let formData = new FormData(form);
|
||||||
|
let submitBtn = form.querySelector('button[type="submit"]');
|
||||||
|
let originalBtnText = submitBtn.innerHTML;
|
||||||
|
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
submitBtn.innerHTML = 'Menyimpan...';
|
||||||
|
|
||||||
|
fetch(form.action, {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
headers: {
|
||||||
|
'X-Requested-With': 'XMLHttpRequest',
|
||||||
|
'Accept': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
submitBtn.innerHTML = originalBtnText;
|
||||||
|
|
||||||
|
if (data.status === 'success') {
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Berhasil!',
|
||||||
|
text: data.message,
|
||||||
|
showConfirmButton: false,
|
||||||
|
timer: 2000
|
||||||
|
}).then(() => {
|
||||||
|
window.location.href = "{{ route('lahan.index') }}";
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let errorMsg = data.message || 'Terjadi kesalahan saat menyimpan data.';
|
||||||
|
if (data.errors) {
|
||||||
|
errorMsg = Object.values(data.errors).map(err => err.join(', ')).join('<br>');
|
||||||
|
}
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'error',
|
||||||
|
title: 'Gagal Menyimpan!',
|
||||||
|
html: errorMsg
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
submitBtn.innerHTML = originalBtnText;
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'error',
|
||||||
|
title: 'Error Sistem',
|
||||||
|
text: 'Terjadi kesalahan pada server atau koneksi internet.'
|
||||||
|
});
|
||||||
|
console.error('Error:', error);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
@@ -0,0 +1,335 @@
|
|||||||
|
@extends('layout.main')
|
||||||
|
|
||||||
|
@push('style')
|
||||||
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/sweetalert2@11/dist/sweetalert2.min.css">
|
||||||
|
@endpush
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container-xxl flex-grow-1 container-p-y">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header border-bottom d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="card-title mb-0">Data Map Lahan</h5>
|
||||||
|
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<button class="btn btn-sm btn-label-secondary" type="button" data-bs-toggle="collapse" data-bs-target="#filterSection" aria-expanded="false" aria-controls="filterSection">
|
||||||
|
<i class="ti tabler-filter me-1"></i> Filter Lanjut
|
||||||
|
</button>
|
||||||
|
<a href="{{ route('lahan.create') }}" class="btn btn-sm btn-primary">
|
||||||
|
<i class="ti tabler-plus me-1"></i> Tambah Lahan
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form method="GET" action="{{ route('lahan.index') }}" id="filterForm">
|
||||||
|
|
||||||
|
<div class="card-body border-bottom pt-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center row gap-3 gap-md-0">
|
||||||
|
<div class="col-md-auto">
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<label class="me-2 text-nowrap">Show</label>
|
||||||
|
<select name="per_page" class="form-select form-select-sm w-auto" onchange="this.form.submit()">
|
||||||
|
<option value="10" {{ request('per_page') == 10 ? 'selected' : '' }}>10</option>
|
||||||
|
<option value="25" {{ request('per_page') == 25 ? 'selected' : '' }}>25</option>
|
||||||
|
<option value="50" {{ request('per_page') == 50 ? 'selected' : '' }}>50</option>
|
||||||
|
</select>
|
||||||
|
<label class="ms-2 text-nowrap">entries</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-auto">
|
||||||
|
<div class="input-group input-group-sm">
|
||||||
|
<input type="text" name="search" class="form-control" placeholder="Cari Lahan / Pemilik..." value="{{ request('search') }}">
|
||||||
|
<button type="submit" class="btn btn-primary"><i class="ti tabler-search"></i></button>
|
||||||
|
@if(request()->anyFilled(['search', 'provinsi_id', 'kabupatenkota_id', 'kecamatan_id', 'desa_kelurahan_id', 'profile_id', 'status_kepemilikan', 'adat_pemilik_id']))
|
||||||
|
<a href="{{ route('lahan.index') }}" class="btn btn-label-secondary" title="Reset Semua Filter"><i class="ti tabler-refresh"></i></a>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@php
|
||||||
|
$isFilterActive = request()->anyFilled([
|
||||||
|
'provinsi_id', 'kabupatenkota_id', 'kecamatan_id', 'desa_kelurahan_id',
|
||||||
|
'profile_id', 'status_kepemilikan', 'adat_pemilik_id'
|
||||||
|
]);
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
<div class="collapse {{ $isFilterActive ? 'show' : '' }}" id="filterSection">
|
||||||
|
<div class="card-body border-bottom bg-lighter">
|
||||||
|
<div class="row g-3 mb-3">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="form-label small text-muted">Provinsi</label>
|
||||||
|
<select name="provinsi_id" id="provinsi_id" class="form-select form-select-sm">
|
||||||
|
<option value="">Semua Provinsi</option>
|
||||||
|
@foreach($provinsi as $prov)
|
||||||
|
<option value="{{ $prov->id }}" {{ request('provinsi_id') == $prov->id ? 'selected' : '' }}>{{ $prov->nama }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="form-label small text-muted">Kabupaten/Kota</label>
|
||||||
|
<select name="kabupatenkota_id" id="kabupatenkota_id" class="form-select form-select-sm" {{ empty($kabupaten) ? 'disabled' : '' }}>
|
||||||
|
<option value="">Semua Kab/Kota</option>
|
||||||
|
@foreach($kabupaten ?? [] as $kab)
|
||||||
|
<option value="{{ $kab->id }}" {{ request('kabupatenkota_id') == $kab->id ? 'selected' : '' }}>{{ $kab->nama }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="form-label small text-muted">Kecamatan</label>
|
||||||
|
<select name="kecamatan_id" id="kecamatan_id" class="form-select form-select-sm" {{ empty($kecamatan) ? 'disabled' : '' }}>
|
||||||
|
<option value="">Semua Kecamatan</option>
|
||||||
|
@foreach($kecamatan ?? [] as $kec)
|
||||||
|
<option value="{{ $kec->id }}" {{ request('kecamatan_id') == $kec->id ? 'selected' : '' }}>{{ $kec->nama }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="form-label small text-muted">Desa/Kelurahan</label>
|
||||||
|
<select name="desa_kelurahan_id" id="desa_kelurahan_id" class="form-select form-select-sm" {{ empty($desa) ? 'disabled' : '' }}>
|
||||||
|
<option value="">Semua Desa</option>
|
||||||
|
@foreach($desa ?? [] as $ds)
|
||||||
|
<option value="{{ $ds->id }}" {{ request('desa_kelurahan_id') == $ds->id ? 'selected' : '' }}>{{ $ds->nama }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="form-label small text-muted">Pemilik Lahan</label>
|
||||||
|
<select name="profile_id" class="form-select form-select-sm">
|
||||||
|
<option value="">Semua Pemilik</option>
|
||||||
|
@foreach($profiles as $prof)
|
||||||
|
<option value="{{ $prof->id }}" {{ request('profile_id') == $prof->id ? 'selected' : '' }}>{{ $prof->nama }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="form-label small text-muted">Status Kepemilikan</label>
|
||||||
|
<select name="status_kepemilikan" class="form-select form-select-sm">
|
||||||
|
<option value="">Semua Status</option>
|
||||||
|
<option value="sendiri" {{ request('status_kepemilikan') == 'sendiri' ? 'selected' : '' }}>Milik Pribadi</option>
|
||||||
|
<option value="sewa" {{ request('status_kepemilikan') == 'sewa' ? 'selected' : '' }}>Sewa</option>
|
||||||
|
<option value="adat" {{ request('status_kepemilikan') == 'adat' ? 'selected' : '' }}>Tanah Adat</option>
|
||||||
|
<option value="lainnya" {{ request('status_kepemilikan') == 'lainnya' ? 'selected' : '' }}>Lainnya</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label class="form-label small text-muted">Data Adat</label>
|
||||||
|
<select name="adat_pemilik_id" class="form-select form-select-sm">
|
||||||
|
<option value="">Semua Adat</option>
|
||||||
|
@foreach($adat as $ad)
|
||||||
|
<option value="{{ $ad->id }}" {{ request('adat_pemilik_id') == $ad->id ? 'selected' : '' }}>{{ $ad->nama }}</option>
|
||||||
|
@endforeach
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-md-3 d-flex align-items-end">
|
||||||
|
<button type="submit" class="btn btn-sm btn-primary">Terapkan Filter</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="table-responsive text-nowrap">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead class="border-top">
|
||||||
|
<tr>
|
||||||
|
<th>No</th>
|
||||||
|
<th>Nama Lahan</th>
|
||||||
|
<th>Pemilik</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Lokasi</th>
|
||||||
|
<th>Luas (Ha/m2)</th>
|
||||||
|
<th>GeoJSON</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@forelse($lahan as $index => $item)
|
||||||
|
<tr>
|
||||||
|
<td>{{ $lahan->firstItem() + $index }}</td>
|
||||||
|
<td><span class="text-heading fw-medium">{{ $item->nama }}</span></td>
|
||||||
|
<td>{{ $item->profile->nama ?? '-' }}</td>
|
||||||
|
<td>
|
||||||
|
@if(trim(strtolower($item->status_kepemilikan->value)) == 'adat')
|
||||||
|
<span class="badge bg-label-warning">Adat: {{ $item->adat->nama ?? 'Ada' }}</span>
|
||||||
|
@else
|
||||||
|
<span class="badge bg-label-info">{{ ucfirst($item->status_kepemilikan->value) }}</span>
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<small class="text-muted">
|
||||||
|
@php
|
||||||
|
$kodeDesa = (string) ($item->desakelurahan->kode ?? '');
|
||||||
|
$labelWilayah = 'Desa';
|
||||||
|
if (strlen($kodeDesa) >= 4) {
|
||||||
|
$digitStatus = substr($kodeDesa, -4, 1);
|
||||||
|
if ($digitStatus === '1') {
|
||||||
|
$labelWilayah = 'Kel.';
|
||||||
|
} elseif ($digitStatus === '2') {
|
||||||
|
$labelWilayah = 'Desa';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@endphp
|
||||||
|
{{ $labelWilayah }} {{ $item->desakelurahan->nama ?? '-' }},<br>
|
||||||
|
Kec. {{ $item->desakelurahan->kecamatan->nama ?? '-' }}
|
||||||
|
</small>
|
||||||
|
</td>
|
||||||
|
<td>{{ $item->luas_lahan ?? '-' }}</td>
|
||||||
|
<td>
|
||||||
|
@if($item->path)
|
||||||
|
<i class="ti tabler-check text-success"></i> Ada
|
||||||
|
@else
|
||||||
|
<i class="ti tabler-x text-danger"></i> Tidak Ada
|
||||||
|
@endif
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div class="d-flex align-items-center">
|
||||||
|
<a href="{{ route('lahan.edit', $item->id) }}" class="btn btn-icon btn-text-secondary rounded-pill" title="Edit"><i class="ti tabler-edit ti-md"></i></a>
|
||||||
|
<a href="javascript:;" class="btn btn-icon btn-text-secondary rounded-pill delete-record" data-id="{{ $item->id }}" data-nama="{{ $item->nama }}" title="Hapus"><i class="ti tabler-trash ti-md"></i></a>
|
||||||
|
<a href="{{ route('lahan.show', $item->id) }}" class="btn btn-icon btn-text-secondary rounded-pill" title="Lihat Peta"><i class="ti tabler-eye ti-md"></i></a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@empty
|
||||||
|
<tr><td colspan="8" class="text-center py-4">Tidak ada data lahan ditemukan.</td></tr>
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer d-flex justify-content-center justify-content-md-end border-top">
|
||||||
|
{{ $lahan->appends(request()->query())->links('pagination::bootstrap-5') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||||
|
<script>
|
||||||
|
'use strict';
|
||||||
|
const csrfToken = "{{ csrf_token() }}";
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
|
||||||
|
// --- CASCADING DROPDOWN LOGIC ---
|
||||||
|
const provSelect = document.getElementById('provinsi_id');
|
||||||
|
const kabSelect = document.getElementById('kabupatenkota_id');
|
||||||
|
const kecSelect = document.getElementById('kecamatan_id');
|
||||||
|
const desaSelect = document.getElementById('desa_kelurahan_id');
|
||||||
|
|
||||||
|
function resetDropdown(element, defaultText) {
|
||||||
|
element.innerHTML = `<option value="">${defaultText}</option>`;
|
||||||
|
element.disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(provSelect) {
|
||||||
|
provSelect.addEventListener('change', function() {
|
||||||
|
let provId = this.value;
|
||||||
|
resetDropdown(kabSelect, 'Semua Kab/Kota');
|
||||||
|
resetDropdown(kecSelect, 'Semua Kecamatan');
|
||||||
|
resetDropdown(desaSelect, 'Semua Desa');
|
||||||
|
|
||||||
|
if (provId) {
|
||||||
|
kabSelect.innerHTML = '<option value="">Memuat...</option>';
|
||||||
|
fetch(`{{ url('kabupatenkotabyprovinsi') }}/${provId}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
resetDropdown(kabSelect, 'Semua Kab/Kota');
|
||||||
|
kabSelect.disabled = false;
|
||||||
|
data.forEach(item => {
|
||||||
|
kabSelect.add(new Option(item.nama, item.id));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(kabSelect) {
|
||||||
|
kabSelect.addEventListener('change', function() {
|
||||||
|
let kabId = this.value;
|
||||||
|
resetDropdown(kecSelect, 'Semua Kecamatan');
|
||||||
|
resetDropdown(desaSelect, 'Semua Desa');
|
||||||
|
|
||||||
|
if (kabId) {
|
||||||
|
kecSelect.innerHTML = '<option value="">Memuat...</option>';
|
||||||
|
fetch(`{{ url('kecamatanbykabupatenkota') }}/${kabId}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
resetDropdown(kecSelect, 'Semua Kecamatan');
|
||||||
|
kecSelect.disabled = false;
|
||||||
|
data.forEach(item => {
|
||||||
|
kecSelect.add(new Option(item.nama, item.id));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(kecSelect) {
|
||||||
|
kecSelect.addEventListener('change', function() {
|
||||||
|
let kecId = this.value;
|
||||||
|
resetDropdown(desaSelect, 'Semua Desa');
|
||||||
|
|
||||||
|
if (kecId) {
|
||||||
|
desaSelect.innerHTML = '<option value="">Memuat...</option>';
|
||||||
|
fetch(`{{ url('desakelurahanbykecamatan') }}/${kecId}`)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
resetDropdown(desaSelect, 'Semua Desa');
|
||||||
|
desaSelect.disabled = false;
|
||||||
|
data.forEach(item => {
|
||||||
|
desaSelect.add(new Option(item.nama, item.id));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(document).ready(function () {
|
||||||
|
$(document).on('click', '.delete-record', function () {
|
||||||
|
const id = $(this).data('id');
|
||||||
|
const name = $(this).data('nama');
|
||||||
|
|
||||||
|
Swal.fire({
|
||||||
|
title: 'Hapus Lahan?',
|
||||||
|
text: `Lahan "${name}" beserta file mapping-nya akan dihapus permanen!`,
|
||||||
|
icon: 'warning',
|
||||||
|
showCancelButton: true,
|
||||||
|
confirmButtonText: 'Ya, Hapus!',
|
||||||
|
cancelButtonText: 'Batal',
|
||||||
|
customClass: { confirmButton: 'btn btn-danger me-3', cancelButton: 'btn btn-label-secondary' },
|
||||||
|
buttonsStyling: false
|
||||||
|
}).then(function (result) {
|
||||||
|
if (result.value) {
|
||||||
|
$.ajax({
|
||||||
|
url: `/lahan/${id}`,
|
||||||
|
type: 'DELETE',
|
||||||
|
headers: { 'X-CSRF-TOKEN': csrfToken },
|
||||||
|
success: function (res) {
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'success',
|
||||||
|
title: 'Terhapus!',
|
||||||
|
text: res.message,
|
||||||
|
showConfirmButton: false,
|
||||||
|
timer: 1500
|
||||||
|
}).then(() => window.location.reload());
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
Swal.fire({
|
||||||
|
icon: 'error',
|
||||||
|
title: 'Gagal!',
|
||||||
|
text: 'Terjadi kesalahan saat menghapus data.'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
@extends('layout.main')
|
||||||
|
|
||||||
|
@push('style')
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.plant-marker {
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 2px;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0 0 5px rgba(0,0,0,0.6);
|
||||||
|
animation: pulse 2s infinite;
|
||||||
|
}
|
||||||
|
@keyframes pulse {
|
||||||
|
0% { box-shadow: 0 0 0 0 rgba(0,0,0, 0.4); }
|
||||||
|
70% { box-shadow: 0 0 0 10px rgba(0,0,0, 0); }
|
||||||
|
100% { box-shadow: 0 0 0 0 rgba(0,0,0, 0); }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
@endpush
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="container-xxl flex-grow-1 container-p-y">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header border-bottom mb-4 d-flex justify-content-between align-items-center">
|
||||||
|
<h5 class="card-title mb-0">Detail Map Lahan</h5>
|
||||||
|
<a href="{{ route('lahan.index') }}" class="btn btn-sm btn-label-secondary">
|
||||||
|
<i class="ti tabler-arrow-left me-1"></i> Kembali
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body">
|
||||||
|
<form onsubmit="return false;">
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-lg-6 mb-4">
|
||||||
|
<h6 class="mb-3 text-primary"><i class="ti tabler-info-circle me-1"></i> Info Lahan</h6>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Nama Lahan</label>
|
||||||
|
<input type="text" class="form-control bg-lighter" value="{{ $lahan->nama }}" readonly />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Pemilik (Profile)</label>
|
||||||
|
<input type="text" class="form-control bg-lighter" value="{{ $lahan->profile->nama ?? '-' }}" readonly />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Status Kepemilikan</label>
|
||||||
|
<input type="text" class="form-control bg-lighter" value="{{ $lahan->status_kepemilikan }}" readonly />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Luas Lahan (Ha/m2)</label>
|
||||||
|
<input type="text" class="form-control bg-lighter" value="{{ $lahan->luas_lahan ?? '-' }}" readonly />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if($lahan->status_kepemilikan->value === 'adat')
|
||||||
|
<div class="mb-3">
|
||||||
|
<label class="form-label">Data Adat Pemilik</label>
|
||||||
|
<input type="text" class="form-control bg-lighter" value="{{ $lahan->adat->nama ?? 'Tidak ada data adat' }}" readonly />
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<hr class="my-4">
|
||||||
|
<h6 class="mb-3 text-primary"><i class="ti tabler-map-pin me-1"></i> Lokasi Wilayah</h6>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Provinsi</label>
|
||||||
|
<input type="text" class="form-control bg-lighter" value="{{ $lahan->desakelurahan->kecamatan->kabupatenkota->provinsi->nama ?? '-' }}" readonly />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Kabupaten/Kota</label>
|
||||||
|
<input type="text" class="form-control bg-lighter" value="{{ $lahan->desakelurahan->kecamatan->kabupatenkota->nama ?? '-' }}" readonly />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Kecamatan</label>
|
||||||
|
<input type="text" class="form-control bg-lighter" value="{{ $lahan->desakelurahan->kecamatan->nama ?? '-' }}" readonly />
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6 mb-3">
|
||||||
|
<label class="form-label">Desa/Kelurahan</label>
|
||||||
|
<input type="text" class="form-control bg-lighter" value="{{ $lahan->desakelurahan->nama ?? '-' }}" readonly />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-lg-6 mb-4">
|
||||||
|
<div class="d-flex justify-content-between align-items-center mb-3">
|
||||||
|
<h6 class="text-primary mb-0"><i class="ti tabler-map me-1"></i> Visualisasi Peta Lahan</h6>
|
||||||
|
|
||||||
|
<div class="form-check form-switch mb-0">
|
||||||
|
<input class="form-check-input" type="checkbox" id="toggleTanaman">
|
||||||
|
<label class="form-check-label text-nowrap fw-bold text-success" for="toggleTanaman"><i class="ti tabler-seeding me-1"></i>Tampilkan Tanaman</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="map" class="border rounded" style="height: 400px; width: 100%; background-color: #f8f9fa; z-index: 1;">
|
||||||
|
<div id="map-fallback" class="d-flex align-items-center justify-content-center h-100 text-muted d-none">
|
||||||
|
Memuat Peta...
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-3">
|
||||||
|
<label class="form-label">Raw Data Koordinat (JSON)</label>
|
||||||
|
<textarea class="form-control bg-lighter font-monospace" rows="3" readonly>
|
||||||
|
{{ is_array($lahan->path) || is_object($lahan->path) ? json_encode($lahan->path, JSON_PRETTY_PRINT) : ($lahan->path ?? 'Tidak ada data koordinat') }}
|
||||||
|
</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
|
||||||
|
let rawData = {!! json_encode($lahan->path ?? []) !!};
|
||||||
|
let dataTanaman = {!! json_encode($lahan->tanaman ?? []) !!};
|
||||||
|
|
||||||
|
let mapContainer = document.getElementById('map');
|
||||||
|
let fallbackMsg = document.getElementById('map-fallback');
|
||||||
|
|
||||||
|
const colorPalette = [
|
||||||
|
'#FF33A8', '#3357FF', '#F3FF33', '#FF5733', '#33FFF5',
|
||||||
|
'#8A33FF', '#FF8F33', '#33FF8A', '#FF3333', '#33A8FF'
|
||||||
|
];
|
||||||
|
|
||||||
|
if (Array.isArray(rawData) && rawData.length > 0) {
|
||||||
|
|
||||||
|
let map = L.map('map').setView([rawData[0][1], rawData[0][0]], 16);
|
||||||
|
|
||||||
|
L.tileLayer('http://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}', {
|
||||||
|
maxZoom: 22,
|
||||||
|
subdomains: ['mt0', 'mt1', 'mt2', 'mt3'],
|
||||||
|
attribution: '© Google Maps Satellite'
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
let latLngs = rawData.map(function(coord) {
|
||||||
|
return [coord[1], coord[0]];
|
||||||
|
});
|
||||||
|
|
||||||
|
let polygon = L.polygon(latLngs, {
|
||||||
|
color: '#28c76f',
|
||||||
|
fillColor: '#28c76f',
|
||||||
|
fillOpacity: 0.3,
|
||||||
|
weight: 2
|
||||||
|
}).addTo(map);
|
||||||
|
|
||||||
|
polygon.bindPopup("<b>{{ $lahan->nama }}</b><br>Luas: {{ $lahan->luas_lahan ?? '-' }} Ha");
|
||||||
|
map.fitBounds(polygon.getBounds(), { padding: [20, 20] });
|
||||||
|
|
||||||
|
let tanamanLayerGroup = L.layerGroup();
|
||||||
|
|
||||||
|
dataTanaman.forEach(function(tanaman) {
|
||||||
|
if(tanaman.latitude && tanaman.longitude) {
|
||||||
|
let komoditasId = tanaman.komoditas_id || 1;
|
||||||
|
|
||||||
|
let markerColor = colorPalette[komoditasId % colorPalette.length];
|
||||||
|
let komoditasNama = tanaman.komoditas ? tanaman.komoditas.nama : 'Unknown';
|
||||||
|
|
||||||
|
let badgeClass = 'bg-label-success';
|
||||||
|
let borderColor = '#28c76f';
|
||||||
|
|
||||||
|
if (tanaman.kondisi_tanaman === 'sakit') {
|
||||||
|
badgeClass = 'bg-label-warning';
|
||||||
|
borderColor = '#ea5455';
|
||||||
|
} else if (tanaman.kondisi_tanaman === 'mati') {
|
||||||
|
badgeClass = 'bg-label-danger';
|
||||||
|
borderColor = '#2f2f2f';
|
||||||
|
}
|
||||||
|
|
||||||
|
let customIcon = L.divIcon({
|
||||||
|
className: 'custom-div-icon',
|
||||||
|
html: `<div class="plant-marker" style="background-color:${markerColor}; border-color:${borderColor}; width:16px; height:16px;"></div>`,
|
||||||
|
iconSize: [16, 16],
|
||||||
|
iconAnchor: [8, 8]
|
||||||
|
});
|
||||||
|
|
||||||
|
let popupContent = `
|
||||||
|
<div class="text-center" style="min-width: 120px;">
|
||||||
|
<h6 class="mb-1 fw-bold">${tanaman.nama}</h6>
|
||||||
|
<small class="text-muted d-block mb-1">${komoditasNama}</small>
|
||||||
|
<hr class="my-1">
|
||||||
|
<span class="badge ${badgeClass} w-100">Kondisi: ${tanaman.kondisi_tanaman.charAt(0).toUpperCase() + tanaman.kondisi_tanaman.slice(1)}</span>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
L.marker([tanaman.latitude, tanaman.longitude], { icon: customIcon })
|
||||||
|
.bindPopup(popupContent)
|
||||||
|
.addTo(tanamanLayerGroup);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let toggleBtn = document.getElementById('toggleTanaman');
|
||||||
|
toggleBtn.addEventListener('change', function() {
|
||||||
|
if (this.checked) {
|
||||||
|
map.addLayer(tanamanLayerGroup);
|
||||||
|
} else {
|
||||||
|
map.removeLayer(tanamanLayerGroup);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
fallbackMsg.classList.remove('d-none');
|
||||||
|
fallbackMsg.innerHTML = '<div class="text-center"><i class="ti tabler-map-off mb-2" style="font-size: 2rem;"></i><br>Tidak ada data koordinat polygon untuk lahan ini.</div>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
@endpush
|
||||||
+1
-7
@@ -80,13 +80,7 @@ Route::middleware('auth')
|
|||||||
Route::put('/profile/{id}', [App\Http\Controllers\Web\Produktivitas\ProfileController::class, 'update'])->name('profile.update');
|
Route::put('/profile/{id}', [App\Http\Controllers\Web\Produktivitas\ProfileController::class, 'update'])->name('profile.update');
|
||||||
Route::delete('/profile/{id}', [App\Http\Controllers\Web\Produktivitas\ProfileController::class, 'destroy'])->name('profile.destroy');
|
Route::delete('/profile/{id}', [App\Http\Controllers\Web\Produktivitas\ProfileController::class, 'destroy'])->name('profile.destroy');
|
||||||
|
|
||||||
Route::get('/lahan', [App\Http\Controllers\Web\Produktivitas\LahanController::class, 'index'])->name('lahan.index');
|
Route::resource('lahan', App\Http\Controllers\Web\Produktivitas\LahanController::class);
|
||||||
Route::get('/lahan/add', [App\Http\Controllers\Web\Produktivitas\LahanController::class, 'create'])->name('lahan.create');
|
|
||||||
Route::post('/lahan', [App\Http\Controllers\Web\Produktivitas\LahanController::class, 'store'])->name('lahan.store');
|
|
||||||
Route::get('/lahan/edit/{id}', [App\Http\Controllers\Web\Produktivitas\LahanController::class, 'edit'])->name('lahan.edit');
|
|
||||||
Route::put('/lahan/{id}', [App\Http\Controllers\Web\Produktivitas\LahanController::class, 'update'])->name('lahan.update');
|
|
||||||
Route::delete('/lahan/{id}', [App\Http\Controllers\Web\Produktivitas\LahanController::class, 'destroy'])->name('lahan.destroy');
|
|
||||||
Route::get('/lahan/{id}', [App\Http\Controllers\Web\Produktivitas\LahanController::class, 'show'])->name('lahan.show');
|
|
||||||
|
|
||||||
Route::get('/komoditas', [App\Http\Controllers\Web\Master\KomoditasController::class, 'index'])->name('komoditas.index');
|
Route::get('/komoditas', [App\Http\Controllers\Web\Master\KomoditasController::class, 'index'])->name('komoditas.index');
|
||||||
Route::post('/komoditas', [App\Http\Controllers\Web\Master\KomoditasController::class, 'store'])->name('komoditas.store');
|
Route::post('/komoditas', [App\Http\Controllers\Web\Master\KomoditasController::class, 'store'])->name('komoditas.store');
|
||||||
|
|||||||
Reference in New Issue
Block a user