This commit is contained in:
2026-10-15 14:05:01 +07:00
parent 9b5c0a7309
commit 2e8271d27a
2 changed files with 97 additions and 87 deletions
@@ -233,14 +233,14 @@ class SummaryController extends Controller
$aksesPasar = $this->filteredAksesPasar($request);
$kpiCards = [
[
'value' => number_format($totalPetani, 0, ',', '.'),
'unit' => 'orang',
'label' => 'Jumlah Petani',
'description' => 'Petani sesuai filter yang dipilih',
'icon' => 'tabler-users',
'variant' => 'primary',
],
// [
// 'value' => number_format($totalPetani, 0, ',', '.'),
// 'unit' => 'orang',
// 'label' => 'Jumlah Petani',
// 'description' => 'Petani sesuai filter yang dipilih',
// 'icon' => 'tabler-users',
// 'variant' => 'primary',
// ],
[
'value' => number_format($totalLuasLahan, 2, ',', '.'),
'unit' => 'ha',
@@ -418,6 +418,7 @@ class SummaryController extends Controller
return [
'jumlah_petani' => $petaniIds->count(),
'jumlah_lahan' => $mapLahanRows->count(),
'total_luas_lahan' => (float) $mapLahanRows->sum('luas_lahan'),
'petani_per_komoditas' => $commodityRows,
'opt' => collect($optCounts)
@@ -752,7 +752,7 @@
<div class="card-body d-flex justify-content-between align-items-center gap-3">
<div>
<h5>Peta Sebaran</h5>
<p class="text-body-secondary mb-0">Lahan, tanaman, OPT, dan praktik budidaya berdasarkan filter wilayah.</p>
<p class="text-body-secondary mb-0">Lahan, tanaman, dan OPT berdasarkan filter wilayah.</p>
</div>
<span class="btn btn-icon btn-label-secondary btn-sm chart-group-icon-toggle" aria-hidden="true">
<i class="icon-base ti tabler-chevron-down"></i>
@@ -764,15 +764,7 @@
<div class="row g-4 mb-4">
<div class="col-12">
<div class="card h-100 produksi-chart-card">
<!-- <div class="card-header">
<div class="card-title mb-0">
<h5 class="m-0 me-2">Peta Sebaran & Praktik Budidaya</h5>
<small class="text-body-secondary">Petani, luas lahan, komoditas, OPT, dan praktik budidaya berdasarkan filter aktif</small>
</div>
</div> -->
<div class="card-body">
<div class="d-flex flex-column gap-4">
<section>
<div class="d-flex align-items-center justify-content-between gap-3 flex-wrap mb-2">
<div>
<h6 class="mb-0">Peta Sebaran Lahan & Tanaman</h6>
@@ -794,9 +786,13 @@
<div class="produksi-map-information" id="produksi-map-information"></div>
</div>
</div>
</section>
</div>
</div>
</div>
<section>
<div class="col-12">
<div class="card h-100 produksi-chart-card">
<div class="card-body">
<div class="d-flex align-items-center justify-content-between gap-3 flex-wrap mb-2">
<div>
<h6 class="mb-0">Peta Praktik Budidaya</h6>
@@ -818,8 +814,6 @@
<div class="produksi-map-information" id="produksi-budidaya-map-information"></div>
</div>
</div>
</section>
</div>
</div>
</div>
</div>
@@ -1079,7 +1073,11 @@ document.addEventListener('DOMContentLoaded', function () {
const mapData = @json($mapData);
const dashboardFilters = @json($dashboardFilters);
const mapInformationUrl = @json(route('dashboard.produktivitas.map-information'));
const mapInformation = mapData.information || {};
const initialMapInformation = mapData.information || {};
const mapInformation = {
production: { ...initialMapInformation },
cultivation: { ...initialMapInformation },
};
const wilayah = @json($wilayah);
const headingColor = config.colors.headingColor;
const legendColor = config.colors.bodyColor;
@@ -1092,7 +1090,7 @@ document.addEventListener('DOMContentLoaded', function () {
let productionMapRendered = false;
let cultivationMapRendered = false;
let actualProductivityRendered = false;
let mapInformationRequestId = 0;
const mapInformationRequestIds = { production: 0, cultivation: 0 };
function hasData(data) {
return data && Array.isArray(data.series) && data.series.some(function (value) {
@@ -1110,18 +1108,18 @@ document.addEventListener('DOMContentLoaded', function () {
});
}
function renderProductionMapInformation(elementId, includeOpt = true) {
function renderProductionMapInformation(elementId, information, includeOpt = true) {
const element = document.getElementById(elementId);
if (!element) return;
const commodityRows = Array.isArray(mapInformation.petani_per_komoditas)
? mapInformation.petani_per_komoditas
const commodityRows = Array.isArray(information.petani_per_komoditas)
? information.petani_per_komoditas
: [];
const optRows = Array.isArray(mapInformation.opt) ? mapInformation.opt : [];
const indexValue = mapInformation.indeks === null || mapInformation.indeks === undefined
const optRows = Array.isArray(information.opt) ? information.opt : [];
const indexValue = information.indeks === null || information.indeks === undefined
? '-'
: `${formatNumber(mapInformation.indeks, 2)} / 5`;
: `${formatNumber(information.indeks, 2)} / 5`;
const renderBars = function (rows, emptyLabel, unitLabel) {
if (!rows.length) {
return `<div class="produksi-map-information-empty">${emptyLabel}</div>`;
@@ -1152,14 +1150,21 @@ document.addEventListener('DOMContentLoaded', function () {
<div class="produksi-map-information-summary">
<span class="produksi-map-information-summary-icon"><i class="icon-base ti tabler-users"></i></span>
<div>
<div class="produksi-map-information-summary-value">${formatNumber(mapInformation.jumlah_petani || 0, 0)}</div>
<div class="produksi-map-information-summary-value">${formatNumber(information.jumlah_petani || 0, 0)}</div>
<div class="produksi-map-information-summary-label">Jumlah Petani</div>
</div>
</div>
<div class="produksi-map-information-summary mt-2">
<span class="produksi-map-information-summary-icon"><i class="icon-base ti tabler-map-pin"></i></span>
<div>
<div class="produksi-map-information-summary-value">${formatNumber(information.jumlah_lahan || 0, 0)}</div>
<div class="produksi-map-information-summary-label">Jumlah Lahan</div>
</div>
</div>
<div class="produksi-map-information-summary mt-2">
<span class="produksi-map-information-summary-icon"><i class="icon-base ti tabler-map-2"></i></span>
<div>
<div class="produksi-map-information-summary-value">${formatNumber(mapInformation.total_luas_lahan || 0, 2)} <small class="fs-6 fw-normal">ha</small></div>
<div class="produksi-map-information-summary-value">${formatNumber(information.total_luas_lahan || 0, 2)} <small class="fs-6 fw-normal">ha</small></div>
<div class="produksi-map-information-summary-label">Total Luas Lahan</div>
</div>
</div>
@@ -1171,11 +1176,11 @@ document.addEventListener('DOMContentLoaded', function () {
</div>
<div class="produksi-map-information-metric">
<span class="produksi-map-information-metric-label">Segmen</span>
<strong class="produksi-map-information-metric-value">${escapeHtml(mapInformation.segmen || 'Belum Lengkap')}</strong>
<strong class="produksi-map-information-metric-value">${escapeHtml(information.segmen || 'Belum Lengkap')}</strong>
</div>
<div class="produksi-map-information-metric">
<span class="produksi-map-information-metric-label">Segmen Dominan</span>
<strong class="produksi-map-information-metric-value">${escapeHtml(mapInformation.segmen_dominan || 'Belum Lengkap')}</strong>
<strong class="produksi-map-information-metric-value">${escapeHtml(information.segmen_dominan || 'Belum Lengkap')}</strong>
</div>
</div>
<section>
@@ -1191,8 +1196,8 @@ document.addEventListener('DOMContentLoaded', function () {
`;
}
async function loadProductionMapInformation(level = null, id = null) {
const requestId = ++mapInformationRequestId;
async function loadProductionMapInformation(mapType, level = null, id = null) {
const requestId = ++mapInformationRequestIds[mapType];
const params = new URLSearchParams();
Object.entries(dashboardFilters || {}).forEach(function ([key, value]) {
@@ -1214,11 +1219,14 @@ document.addEventListener('DOMContentLoaded', function () {
if (!response.ok) return;
const information = await response.json();
if (requestId !== mapInformationRequestId) return;
if (requestId !== mapInformationRequestIds[mapType]) return;
Object.assign(mapInformation, information);
renderProductionMapInformation('produksi-map-information');
renderProductionMapInformation('produksi-budidaya-map-information', false);
Object.assign(mapInformation[mapType], information);
if (mapType === 'production') {
renderProductionMapInformation('produksi-map-information', mapInformation.production);
} else {
renderProductionMapInformation('produksi-budidaya-map-information', mapInformation.cultivation, false);
}
} catch (error) {
console.error('Gagal memuat informasi wilayah pada peta.', error);
}
@@ -1487,7 +1495,7 @@ document.addEventListener('DOMContentLoaded', function () {
renderProductionMapLevel(previous.level, previous.parentId);
productionMapState.informationLevel = previous.informationLevel;
productionMapState.informationId = previous.informationId;
loadProductionMapInformation(previous.informationLevel, previous.informationId);
loadProductionMapInformation('production', previous.informationLevel, previous.informationId);
if (previous.bounds?.isValid()) {
productionMapState.map.fitBounds(previous.bounds, { padding: [30, 30] });
@@ -1580,7 +1588,7 @@ document.addEventListener('DOMContentLoaded', function () {
});
productionMapState.informationLevel = nextLevel;
productionMapState.informationId = item.id;
loadProductionMapInformation(nextLevel, item.id);
loadProductionMapInformation('production', nextLevel, item.id);
renderProductionMapLevel(nextProductionMapLevel(nextLevel), item.id, event.target.getBounds());
});
}
@@ -1714,7 +1722,7 @@ document.addEventListener('DOMContentLoaded', function () {
renderCultivationMapLevel(previous.level, previous.parentId);
cultivationMapState.informationLevel = previous.informationLevel;
cultivationMapState.informationId = previous.informationId;
loadProductionMapInformation(previous.informationLevel, previous.informationId);
loadProductionMapInformation('cultivation', previous.informationLevel, previous.informationId);
if (previous.bounds?.isValid()) {
cultivationMapState.map.fitBounds(previous.bounds, { padding: [30, 30] });
@@ -1807,7 +1815,7 @@ document.addEventListener('DOMContentLoaded', function () {
});
cultivationMapState.informationLevel = nextLevel;
cultivationMapState.informationId = item.id;
loadProductionMapInformation(nextLevel, item.id);
loadProductionMapInformation('cultivation', nextLevel, item.id);
renderCultivationMapLevel(nextProductionMapLevel(nextLevel), item.id, event.target.getBounds());
});
}
@@ -2249,8 +2257,8 @@ document.addEventListener('DOMContentLoaded', function () {
cultivationMapRendered = true;
}
renderProductionMapInformation('produksi-map-information');
renderProductionMapInformation('produksi-budidaya-map-information', false);
renderProductionMapInformation('produksi-map-information', mapInformation.production);
renderProductionMapInformation('produksi-budidaya-map-information', mapInformation.cultivation, false);
if (typeof L === 'undefined') {
const mapEmpty = document.getElementById('produksi-map-empty');
@@ -2338,9 +2346,10 @@ document.addEventListener('DOMContentLoaded', function () {
const control = document.querySelector('.chart-group-header-toggle[aria-controls="' + panel.id + '"]');
if (!control) return;
const icon = control.querySelector('.chart-group-icon-toggle i');
const groupLabel = panel.id === 'peta-sebaran-panel' ? 'peta' : 'chart';
const syncState = function () {
const expanded = panel.classList.contains('show');
const label = expanded ? 'Sembunyikan chart' : 'Tampilkan chart';
const label = expanded ? `Sembunyikan ${groupLabel}` : `Tampilkan ${groupLabel}`;
control.setAttribute('aria-expanded', String(expanded));
control.setAttribute('aria-label', label);
control.title = label;