const persilCfg = { SHM: { color: '#16a34a', label: 'Sertifikat Hak Milik' }, HGB: { color: '#2563eb', label: 'Hak Guna Bangunan' }, HGU: { color: '#d97706', label: 'Hak Guna Usaha' }, HP: { color: '#7c3aed', label: 'Hak Pakai' } }; function renderPersilPanel(pb) { return callAPI('data_persil.php').then(res => { const data = res.data || []; const cnt = k => data.filter(d => d.jenis_hak === k).length; pb.innerHTML = `
Filter Layer
${Object.entries(persilCfg).map(([k, v]) => `
${layerVisible['persil' + k] ? '✓' : ''}
${k} — ${v.label}
${cnt(k)}
`).join('')}
Tambah Data
Data Persil (${data.length})
${data.length ? data.map(d => `
📐
${esc(d.nama_pemilik)}
${d.luas_m2.toFixed(1)} m² · ${d.no_sertifikat || '—'}
${d.jenis_hak}
`).join('') : '
Belum ada data persil
'}
`; loadPersilLayer(data); registerSearchEntries('persil', data.map(d => ({ key: `persil:${d.id}`, label: d.nama_pemilik, subtitle: `Persil ${d.jenis_hak} · ${d.luas_m2.toFixed(1)} m²${d.no_sertifikat ? ` · ${d.no_sertifikat}` : ''}`, typeLabel: 'Persil', icon: '📐', searchText: normalizeSearchText(`${d.nama_pemilik} ${d.jenis_hak} persil tanah`), focus: () => focusGeom(d.id, 'persil') }))); updateStatusCount(); }); } function loadPersilLayer(data) { ['SHM', 'HGB', 'HGU', 'HP'].forEach(k => layers['persil' + k].clearLayers()); data.forEach(d => { const cfg = persilCfg[d.jenis_hak], coords = d.geojson.coordinates[0].map(c => [c[1], c[0]]); const poly = L.polygon(coords, { color: cfg.color, fillColor: cfg.color, fillOpacity: 0.18, weight: 2 }) .bindPopup(`

📐 ${esc(d.nama_pemilik)}

Jenis Hak: ${d.jenis_hak} — ${cfg.label}

Luas: ${d.luas_m2.toFixed(2)} m² (${(d.luas_m2 / 10000).toFixed(4)} ha)

${d.no_sertifikat ? `

No. Sertifikat: ${d.no_sertifikat}

` : ''} ${d.keterangan ? `

${esc(d.keterangan)}

` : ''} `); poly._dataId = d.id; poly._groupKey = 'persil' + d.jenis_hak; layers['persil' + d.jenis_hak].addLayer(poly); }); } function openPersilForm() { openModal('Simpan Persil Tanah', `
📐 Luas: ${pendingArea.toFixed(2)} m² = ${(pendingArea / 10000).toFixed(4)} ha
`, ` `); } async function savePersil() { const body = { nama_pemilik: document.getElementById('ps-nama').value.trim(), jenis_hak: document.getElementById('ps-hak').value, no_sertifikat: document.getElementById('ps-sert').value, luas_m2: pendingArea, keterangan: document.getElementById('ps-ket').value, geojson: pendingGeoJSON }; if (!body.nama_pemilik) return toast('Nama wajib diisi', 'error'); const res = await callAPI('data_persil.php', 'POST', body); if (res.status === 'success') { toast(res.message, 'success'); closeModal(); drawnItems.clearLayers(); pendingGeoJSON = null; pendingArea = null; switchTab('persil'); } else { toast(res.message, 'error'); } } async function editPersil(id) { map.closePopup(); const res = await callAPI(`data_persil.php?id=${id}`); const data = res.data; const sourceLayer = findGeomLayer('persil', id); if (!data) return toast('Data persil tidak ditemukan', 'error'); const groupKey = getGeometryGroupKey('persil', data); const editLayer = sourceLayer ? cloneEditableLayer('persil', sourceLayer) : buildGeometryLayer('persil', data); editLayer._dataId = id; editLayer._groupKey = groupKey; if (sourceLayer) layers[groupKey].removeLayer(sourceLayer); drawnItems.clearLayers(); drawnItems.addLayer(editLayer); geometryEditState = { type: 'persil', id, groupKey, sourceLayer, editLayer }; if (editLayer.editing && editLayer.editing.enable) { editLayer.editing.enable(); } else { const handler = getGeometryEditHandler(); if (!handler) { drawnItems.clearLayers(); if (sourceLayer) layers[groupKey].addLayer(sourceLayer); geometryEditState = null; return toast('Mode edit geometri belum siap', 'error'); } handler.enable(); } map.fitBounds(editLayer.getBounds(), { padding: [50, 50], duration: 1 }); document.getElementById('panel-title').textContent = 'Edit Persil Tanah'; document.getElementById('panel-body').innerHTML = `
Edit Persil
Geser titik-titik batas bidang di peta lalu simpan perubahan.
`; document.getElementById('panel-body').insertAdjacentHTML('beforeend', `
`); } async function savePersilEdit(id) { const state = geometryEditState; if (!state || state.type !== 'persil') return; const layer = state.editLayer; const ringLatLngs = layer.getLatLngs()[0]; const ring = ringLatLngs.map(ll => [ll.lng, ll.lat]); ring.push([ringLatLngs[0].lng, ringLatLngs[0].lat]); const luas_m2 = turf.area(turf.polygon([ring])); const body = { nama_pemilik: document.getElementById('ps-edit-nama').value.trim(), jenis_hak: document.getElementById('ps-edit-hak').value, no_sertifikat: document.getElementById('ps-edit-sert').value, luas_m2, keterangan: document.getElementById('ps-edit-ket').value, geojson: { type: 'Polygon', coordinates: [ring] } }; if (!body.nama_pemilik) return toast('Nama wajib diisi', 'error'); const res = await callAPI(`data_persil.php?id=${id}`, 'PUT', body); if (res.status === 'success') { toast(res.message, 'success'); if (layer.editing && layer.editing.disable) layer.editing.disable(); const handler = getGeometryEditHandler(); if (handler) handler.disable(); drawnItems.clearLayers(); geometryEditState = null; switchTab('persil'); } else { toast(res.message, 'error'); } } async function deletePersil(id) { if (!confirm('Hapus?')) return; const r = await callAPI(`data_persil.php?id=${id}`, 'DELETE'); if (r.status === 'success') { toast('Dihapus', 'success'); map.closePopup(); switchTab('persil'); } }