ganti
This commit is contained in:
parent
6f6eabcaef
commit
4b2eeb4f8e
|
|
@ -55,7 +55,7 @@ public function index(Request $request)
|
|||
$query->where('wisata', $request->wisata);
|
||||
}
|
||||
|
||||
$hasil = $query->latest()->paginate(10);
|
||||
$hasil = $query->orderBy('id', 'desc')->paginate(10);
|
||||
$standalone = true;
|
||||
|
||||
return view('analisis.index', compact(
|
||||
|
|
|
|||
|
|
@ -230,10 +230,11 @@ public function index(Request $request)
|
|||
->distinct('wisata')
|
||||
->count('wisata');
|
||||
|
||||
$hasil = DB::table('hasil_analisis')
|
||||
->when($periodeId, fn($q) => $q->where('periode_id', $periodeId))
|
||||
->when($wisata && $wisata != 'Semua Destinasi', fn($q) => $q->where('wisata', $wisata))
|
||||
->paginate(10);
|
||||
$hasil = DB::table('hasil_analisis')
|
||||
->when($periodeId, fn($q) => $q->where('periode_id', $periodeId))
|
||||
->when($wisata && $wisata != 'Semua Destinasi', fn($q) => $q->where('wisata', $wisata))
|
||||
->orderByDesc('ulasan_id')
|
||||
->paginate(10);
|
||||
|
||||
$jumlahKelasAnalisis = DB::table('hasil_analisis')
|
||||
->when($periodeId, fn($q) => $q->where('periode_id', $periodeId))
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ class="border rounded-lg pl-3 pr-9 py-2 text-sm min-w-[220px] focus:outline-none
|
|||
</div>
|
||||
|
||||
{{-- SUMMARY CARDS --}}
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-5">
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
|
||||
<div class="bg-white rounded-xl shadow p-5 flex items-center gap-4">
|
||||
<div class="bg-blue-100 text-blue-600 p-3 rounded-full text-xl">📍</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,222 @@
|
|||
<?php
|
||||
$destinasiList ??= collect([]);
|
||||
$totalDestinasiAnalisis ??= 0;
|
||||
$totalDestinasiBerkeluhan ??= 0;
|
||||
$totalNegatif ??= 0;
|
||||
$totalUlasan ??= 0;
|
||||
$persenNegatif ??= 0;
|
||||
$tingkatKepuasan ??= 0;
|
||||
$labelKepuasan ??= 'Kurang';
|
||||
$isuDominan ??= '-';
|
||||
$isuDominanPersen ??= 0;
|
||||
$isuUtama ??= [];
|
||||
$kataDominan ??= [];
|
||||
$saranPerbaikan ??= [];
|
||||
$prioritas ??= [];
|
||||
?>
|
||||
|
||||
<div class="space-y-6">
|
||||
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Rekomendasi Layanan</h2>
|
||||
<p class="text-sm text-gray-500">
|
||||
Rekomendasi dibuat dari ulasan negatif agar saran perbaikan fokus pada keluhan pengunjung.
|
||||
</p>
|
||||
<p class="text-xs text-gray-400 mt-1">
|
||||
<?php echo e($totalDestinasiAnalisis); ?> destinasi dianalisis, <?php echo e($totalDestinasiBerkeluhan); ?> destinasi memiliki ulasan negatif.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<form method="GET" action="<?php echo e(route('dashboard')); ?>" class="flex gap-3">
|
||||
<input type="hidden" name="tab" value="rekomendasi">
|
||||
<input type="hidden" name="periode_id" value="<?php echo e($periodeAktif->id ?? request('periode_id')); ?>">
|
||||
<select name="destinasi" onchange="this.form.submit()"
|
||||
class="border rounded-lg pl-3 pr-9 py-2 text-sm min-w-[220px] focus:outline-none focus:ring-2 focus:ring-blue-400">
|
||||
<option value="">Semua Destinasi</option>
|
||||
<?php $__currentLoopData = $destinasiList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $destinasi): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||
<option value="<?php echo e($destinasi); ?>" <?php echo e(request('destinasi') == $destinasi ? 'selected' : ''); ?>>
|
||||
<?php echo e($destinasi); ?>
|
||||
|
||||
</option>
|
||||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
||||
|
||||
<div class="bg-white rounded-xl shadow p-5 flex items-center gap-4">
|
||||
<div class="bg-blue-100 text-blue-600 p-3 rounded-full text-xl">📍</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-500">Destinasi Dianalisis</p>
|
||||
<h3 class="text-xl font-bold"><?php echo e($totalDestinasiAnalisis); ?></h3>
|
||||
<p class="text-xs text-gray-500"><?php echo e($totalDestinasiBerkeluhan); ?> punya keluhan</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-xl shadow p-5 flex items-center gap-4">
|
||||
<div class="bg-red-100 text-red-500 p-3 rounded-full text-xl">😟</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-500">Total Ulasan Negatif</p>
|
||||
<h3 class="text-xl font-bold"><?php echo e($totalNegatif); ?></h3>
|
||||
<p class="text-xs text-red-500"><?php echo e($persenNegatif); ?>% dari total</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-xl shadow p-5 flex items-center gap-4">
|
||||
<div class="bg-green-100 text-green-600 p-3 rounded-full text-xl">😊</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-500">Tingkat Kepuasan</p>
|
||||
<h3 class="text-xl font-bold"><?php echo e($tingkatKepuasan); ?>%</h3>
|
||||
<span class="text-xs px-2 py-1 rounded
|
||||
<?php echo e($labelKepuasan === 'Baik' ? 'bg-green-100 text-green-700' :
|
||||
($labelKepuasan === 'Sedang' ? 'bg-yellow-100 text-yellow-700' :
|
||||
'bg-red-100 text-red-700')); ?>">
|
||||
<?php echo e($labelKepuasan); ?>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="bg-white rounded-xl shadow p-5 flex items-center gap-4">
|
||||
<div class="bg-purple-100 text-purple-600 p-3 rounded-full text-xl">❗</div>
|
||||
<div>
|
||||
<p class="text-sm text-gray-500">Isu Dominan</p>
|
||||
<h3 class="text-xl font-bold"><?php echo e($isuDominan); ?></h3>
|
||||
<p class="text-xs text-gray-500"><?php echo e($isuDominanPersen); ?>% dari total isu</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
|
||||
|
||||
<div class="bg-white rounded-xl shadow p-5">
|
||||
<h3 class="font-semibold mb-4 text-gray-700">Isu Utama (Top 5)</h3>
|
||||
|
||||
<?php $__empty_1 = true; $__currentLoopData = $isuUtama; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $i => $isu): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
|
||||
<?php
|
||||
$warnaClass = match($isu['color']) {
|
||||
'red' => 'bg-red-500',
|
||||
'orange' => 'bg-orange-500',
|
||||
'yellow' => 'bg-yellow-400',
|
||||
'green' => 'bg-green-500',
|
||||
default => 'bg-blue-500',
|
||||
};
|
||||
?>
|
||||
<div class="mb-4">
|
||||
<div class="flex justify-between text-sm mb-1">
|
||||
<span><?php echo e($i + 1); ?>. <?php echo e($isu['nama']); ?></span>
|
||||
<span class="font-semibold"><?php echo e($isu['persen']); ?>%</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-200 h-2 rounded">
|
||||
<div class="h-2 rounded <?php echo e($warnaClass); ?>" style="width: <?php echo e($isu['persen']); ?>%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
|
||||
<p class="text-sm text-gray-400 text-center py-4">Belum ada data isu.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="bg-white rounded-xl shadow p-5">
|
||||
<h3 class="font-semibold mb-4 text-gray-700">Kata Kunci Dominan</h3>
|
||||
|
||||
<?php $maxFreq = !empty($kataDominan) ? max($kataDominan) : 1; ?>
|
||||
|
||||
<?php $__empty_1 = true; $__currentLoopData = array_slice($kataDominan, 0, 5, true); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $kata => $jumlah): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
|
||||
<div class="mb-3">
|
||||
<div class="flex justify-between text-sm">
|
||||
<span><?php echo e($kata); ?></span>
|
||||
<span class="font-semibold text-blue-600"><?php echo e($jumlah); ?>x</span>
|
||||
</div>
|
||||
<div class="w-full bg-gray-200 h-2 rounded mt-1">
|
||||
<div class="bg-blue-500 h-2 rounded" style="width: <?php echo e(round(($jumlah / $maxFreq) * 100)); ?>%"></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
|
||||
<p class="text-sm text-gray-400 text-center py-4">Belum ada kata kunci.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="bg-white rounded-xl shadow p-5">
|
||||
<h3 class="font-semibold mb-4 text-gray-700">Saran Perbaikan</h3>
|
||||
|
||||
<div class="space-y-4 text-sm">
|
||||
<?php $__empty_1 = true; $__currentLoopData = $saranPerbaikan; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $saran): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
|
||||
<div class="flex gap-3">
|
||||
<div class="text-xl"><?php echo e($saran['icon']); ?></div>
|
||||
<div>
|
||||
<p class="font-semibold"><?php echo e($saran['nama']); ?></p>
|
||||
<p class="text-gray-600"><?php echo e($saran['tip']); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
|
||||
<p class="text-sm text-gray-400 text-center py-4">Belum ada saran.</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
|
||||
<?php $__empty_1 = true; $__currentLoopData = $prioritas; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $p): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
|
||||
<?php
|
||||
$border = match($p['color']) {
|
||||
'red' => 'border-red-300',
|
||||
'orange' => 'border-orange-300',
|
||||
'yellow' => 'border-yellow-300',
|
||||
'green' => 'border-green-300',
|
||||
default => 'border-blue-300',
|
||||
};
|
||||
$title = match($p['color']) {
|
||||
'red' => 'text-red-600',
|
||||
'orange' => 'text-orange-500',
|
||||
'yellow' => 'text-yellow-600',
|
||||
'green' => 'text-green-600',
|
||||
default => 'text-blue-600',
|
||||
};
|
||||
$dampak = match($p['color']) {
|
||||
'red' => 'bg-red-100 text-red-600',
|
||||
'orange' => 'bg-orange-100 text-orange-600',
|
||||
'yellow' => 'bg-yellow-100 text-yellow-600',
|
||||
'green' => 'bg-green-100 text-green-700',
|
||||
default => 'bg-blue-100 text-blue-600',
|
||||
};
|
||||
?>
|
||||
<div class="border <?php echo e($border); ?> rounded-xl p-5 bg-white">
|
||||
<h4 class="font-semibold <?php echo e($title); ?> mb-2">Prioritas <?php echo e($p['rank']); ?></h4>
|
||||
<h3 class="text-lg font-bold mb-3"><?php echo e($p['nama']); ?></h3>
|
||||
|
||||
<ul class="text-sm space-y-2 mb-4">
|
||||
<?php $__currentLoopData = $p['actions']; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $action): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||
<li class="flex items-center gap-2">
|
||||
<span class="text-blue-500">✔</span> <?php echo e($action); ?>
|
||||
|
||||
</li>
|
||||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||
</ul>
|
||||
|
||||
<div class="text-xs <?php echo e($dampak); ?> p-2 rounded">
|
||||
Dampak: <?php echo e($p['dampak']); ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
|
||||
<div class="col-span-3 text-center text-gray-400 text-sm py-6">
|
||||
Belum ada data rekomendasi. Pastikan analisis sentimen sudah dijalankan.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
|
||||
</div><?php /**PATH C:\laragon\www\SistemAnalisisSentimen\resources\views/rekomendasi/index.blade.php ENDPATH**/ ?>
|
||||
|
|
@ -0,0 +1,354 @@
|
|||
<?php $__env->startSection('content'); ?>
|
||||
|
||||
<div class="max-w-7xl mx-auto">
|
||||
|
||||
|
||||
<?php if(session('success')): ?>
|
||||
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4 mb-6 rounded">
|
||||
<?php echo e(session('success')); ?>
|
||||
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if(session('error')): ?>
|
||||
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded whitespace-pre-line">
|
||||
<?php echo e(session('error')); ?>
|
||||
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<?php if($noDataPesan ?? null): ?>
|
||||
<div class="bg-blue-50 border-l-4 border-blue-400 text-blue-700 p-4 mb-6 rounded flex items-center gap-2">
|
||||
<span>📅</span> <span><?php echo e($noDataPesan); ?></span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if($periodeAktif && !$hasAnalisis): ?>
|
||||
<div class="bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4 mb-6 rounded">
|
||||
Data ulasan sudah tersedia, tetapi belum dilakukan analisis sentimen.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<span class="text-sm text-gray-600 font-medium">
|
||||
Periode aktif: <?php echo e($periodeAktif->nama ?? 'Belum ada data'); ?>
|
||||
|
||||
</span>
|
||||
<a href="<?php echo e(route('riwayat.index')); ?>" class="text-sm text-blue-600 hover:underline">
|
||||
Lihat riwayat
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<?php if($periodeAktif): ?>
|
||||
<span class="text-xs text-gray-400">
|
||||
Terakhir update: <?php echo e($lastUpdate ? \Carbon\Carbon::parse($lastUpdate)->format('d M Y H:i') : '-'); ?>
|
||||
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
<form method="GET"
|
||||
action="<?php echo e(route('dashboard')); ?>"
|
||||
class="flex flex-col md:flex-row gap-3 md:items-center">
|
||||
|
||||
|
||||
|
||||
<input type="month"
|
||||
name="periode_bulan"
|
||||
value="<?php echo e(request('periode_bulan', now()->format('Y-m'))); ?>"
|
||||
max="<?php echo e(now()->format('Y-m')); ?>"
|
||||
onchange="this.form.submit()"
|
||||
class="border rounded-lg px-3 py-2 text-sm bg-white shadow-sm min-w-[150px]">
|
||||
|
||||
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div x-data="{ tab: new URLSearchParams(window.location.search).get('tab') || 'dashboard' }"
|
||||
x-init="$nextTick(() => { if (tab === 'dashboard') renderAllCharts() })"
|
||||
class="mb-6">
|
||||
|
||||
<!-- TAB -->
|
||||
<div class="bg-blue-700 rounded-xl p-1 flex space-x-2 shadow mb-6">
|
||||
<button @click="tab='dashboard'; $nextTick(() => renderAllCharts())"
|
||||
:class="tab==='dashboard' ? 'bg-white text-blue-700 shadow' : 'text-white hover:bg-blue-600'"
|
||||
class="flex-1 py-3 rounded-lg text-sm font-medium transition">
|
||||
Dashboard Sentara
|
||||
</button>
|
||||
<button @click="tab='analisis'"
|
||||
:class="tab==='analisis' ? 'bg-white text-blue-700 shadow' : 'text-white hover:bg-blue-600'"
|
||||
class="flex-1 py-3 rounded-lg text-sm font-medium transition">
|
||||
Hasil Analisis Sentimen
|
||||
</button>
|
||||
<button @click="tab='rekomendasi'"
|
||||
:class="tab==='rekomendasi' ? 'bg-white text-blue-700 shadow' : 'text-white hover:bg-blue-600'"
|
||||
class="flex-1 py-3 rounded-lg text-sm font-medium transition">
|
||||
Rekomendasi Layanan
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- ================= DASHBOARD ================= -->
|
||||
<div x-show="tab === 'dashboard'">
|
||||
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6 mb-8">
|
||||
<div class="bg-white rounded-xl shadow p-5">
|
||||
<p class="text-gray-500 text-sm">Total Ulasan</p>
|
||||
<h3 class="text-2xl font-bold mt-2 text-gray-900"><?php echo e($stats['total']); ?></h3>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl shadow p-5">
|
||||
<p class="text-gray-500 text-sm">Sentimen Positif</p>
|
||||
<h3 class="text-2xl font-bold mt-2 text-green-600"><?php echo e($stats['positif_persen']); ?>%</h3>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl shadow p-5">
|
||||
<p class="text-gray-500 text-sm">Sentimen Negatif</p>
|
||||
<h3 class="text-2xl font-bold mt-2 text-red-600"><?php echo e($stats['negatif_persen']); ?>%</h3>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl shadow p-5">
|
||||
<p class="text-gray-500 text-sm">Sentimen Netral</p>
|
||||
<h3 class="text-2xl font-bold mt-2 text-yellow-500"><?php echo e($stats['netral_persen']); ?>%</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-8">
|
||||
|
||||
|
||||
<div class="bg-white rounded-xl shadow p-6">
|
||||
<h3 class="font-semibold mb-4 text-gray-700">Distribusi Sentimen</h3>
|
||||
<div style="height:300px;">
|
||||
<canvas id="pieChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="bg-white rounded-xl shadow p-6">
|
||||
<h3 class="font-semibold mb-4 text-gray-700">Sentimen per Destinasi</h3>
|
||||
<div class="h-[300px]">
|
||||
<canvas id="destinationChart"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
<div class="bg-white rounded-xl shadow p-6 h-[320px]">
|
||||
<h3 class="font-semibold mb-6 text-gray-700">Total Data per Destinasi</h3>
|
||||
<div class="space-y-4 text-sm text-gray-600">
|
||||
<?php $__currentLoopData = $totalPerWisata; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||
<div class="flex justify-between border-b pb-3">
|
||||
<span><?php echo e($item->wisata); ?></span>
|
||||
<span class="font-semibold text-gray-800"><?php echo e($item->total); ?> ulasan</span>
|
||||
</div>
|
||||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-white rounded-xl shadow p-6 h-[320px]">
|
||||
<h3 class="font-semibold mb-6 text-gray-700">Word Cloud</h3>
|
||||
<div id="wordCloud" class="w-full h-[240px] overflow-hidden flex flex-wrap content-center justify-center gap-3 text-center">
|
||||
<p class="text-sm text-gray-400">Belum ada kata dominan.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ================= ANALISIS ================= -->
|
||||
<div x-show="tab === 'analisis'" id="analisis-content">
|
||||
<?php echo $__env->make('analisis.index', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?>
|
||||
</div>
|
||||
|
||||
<!-- ================= REKOMENDASI ================= -->
|
||||
<div x-show="tab === 'rekomendasi'" id="rekomendasi-content">
|
||||
<?php echo $__env->make('rekomendasi.index', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
|
||||
|
||||
<script>
|
||||
const pieData = <?php echo json_encode($chartSentimen, 15, 512) ?>;
|
||||
const destinationData = <?php echo json_encode($chartDestinasi, 15, 512) ?>;
|
||||
const text = <?php echo json_encode($allText, 15, 512) ?>;
|
||||
|
||||
function renderAllCharts() {
|
||||
// PIE CHART
|
||||
const pieCanvas = document.getElementById('pieChart');
|
||||
if (pieCanvas) {
|
||||
if (window.pieChartInstance) {
|
||||
window.pieChartInstance.destroy();
|
||||
window.pieChartInstance = null;
|
||||
}
|
||||
|
||||
// Reset canvas dengan clone agar benar-benar bersih
|
||||
const newPie = pieCanvas.cloneNode(false);
|
||||
pieCanvas.parentNode.replaceChild(newPie, pieCanvas);
|
||||
|
||||
window.pieChartInstance = new Chart(newPie, { // <-- newPie, bukan pieCanvas
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: pieData.map(i => i.sentimen),
|
||||
datasets: [{
|
||||
data: pieData.map(i => Number(i.total)),
|
||||
backgroundColor: ['#3B82F6', '#EF4444', '#F59E0B']
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
animation: false
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// BAR CHART
|
||||
const destinationCanvas = document.getElementById('destinationChart');
|
||||
if (destinationCanvas) {
|
||||
if (window.destinationChartInstance) {
|
||||
window.destinationChartInstance.destroy();
|
||||
window.destinationChartInstance = null;
|
||||
}
|
||||
window.destinationChartInstance = new Chart(destinationCanvas, {
|
||||
type: 'bar',
|
||||
data: {
|
||||
labels: destinationData.map(item => item.wisata),
|
||||
datasets: [
|
||||
{
|
||||
label: 'Positif',
|
||||
data: destinationData.map(item => Number(item.positif || 0)),
|
||||
backgroundColor: 'rgba(96, 165, 250, 0.88)',
|
||||
borderColor: '#3B82F6',
|
||||
borderWidth: 1,
|
||||
borderRadius: 3,
|
||||
},
|
||||
{
|
||||
label: 'Negatif',
|
||||
data: destinationData.map(item => Number(item.negatif || 0)),
|
||||
backgroundColor: 'rgba(248, 113, 113, 0.9)',
|
||||
borderColor: '#EF4444',
|
||||
borderWidth: 1,
|
||||
borderRadius: 3,
|
||||
},
|
||||
{
|
||||
label: 'Netral',
|
||||
data: destinationData.map(item => Number(item.netral || 0)),
|
||||
backgroundColor: 'rgba(251, 191, 36, 0.72)',
|
||||
borderColor: '#F59E0B',
|
||||
borderWidth: 1,
|
||||
borderRadius: 3,
|
||||
},
|
||||
],
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
animation: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'top',
|
||||
align: 'center',
|
||||
labels: { boxWidth: 38, boxHeight: 10, color: '#4B5563', font: { size: 12 } },
|
||||
},
|
||||
tooltip: {
|
||||
callbacks: {
|
||||
label: context => `${context.dataset.label}: ${context.parsed.y} ulasan`,
|
||||
},
|
||||
},
|
||||
},
|
||||
scales: {
|
||||
x: {
|
||||
grid: { color: 'rgba(156, 163, 175, 0.22)' },
|
||||
ticks: { color: '#4B5563', maxRotation: 14, minRotation: 14, font: { size: 12 } },
|
||||
},
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
ticks: { color: '#4B5563', precision: 0 },
|
||||
grid: { color: 'rgba(156, 163, 175, 0.28)' },
|
||||
},
|
||||
},
|
||||
categoryPercentage: 0.72,
|
||||
barPercentage: 0.82,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// WORD CLOUD
|
||||
const wordCloud = document.getElementById('wordCloud');
|
||||
const stopwords = new Set([
|
||||
'yang','dan','dari','untuk','dengan','ini','itu','tidak','ada','juga',
|
||||
'sangat','lebih','sudah','bisa','tapi','karena','pada','atau','saya',
|
||||
'kami','mereka','nya','jadi','kalau','dalam','akan','saat','tempat'
|
||||
]);
|
||||
|
||||
if (wordCloud && text.trim().length > 0) {
|
||||
const wordCount = {};
|
||||
text.toLowerCase().split(/\s+/).forEach(word => {
|
||||
const cleanWord = word.replace(/[^a-z]/g, '');
|
||||
if (cleanWord.length > 3 && !stopwords.has(cleanWord)) {
|
||||
wordCount[cleanWord] = (wordCount[cleanWord] || 0) + 1;
|
||||
}
|
||||
});
|
||||
|
||||
const words = Object.entries(wordCount)
|
||||
.sort((a, b) => b[1] - a[1])
|
||||
.slice(0, 28);
|
||||
|
||||
if (words.length > 0) {
|
||||
const max = words[0][1] || 1;
|
||||
const colors = ['text-blue-700', 'text-green-600', 'text-red-500', 'text-yellow-600', 'text-indigo-600'];
|
||||
wordCloud.innerHTML = words.map(([word, count], index) => {
|
||||
const size = 13 + Math.round((count / max) * 20);
|
||||
const weight = count === max ? 800 : 600;
|
||||
return `<span class="${colors[index % colors.length]} inline-block" style="font-size:${size}px;font-weight:${weight}" title="${count}x">${word}</span>`;
|
||||
}).join('');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
const container = document.getElementById('analisis-content');
|
||||
|
||||
// FILTER AJAX
|
||||
document.addEventListener('submit', function(e){
|
||||
if(e.target.id === 'filter-form'){
|
||||
e.preventDefault();
|
||||
const params = new URLSearchParams(new FormData(e.target)).toString();
|
||||
fetch('/dashboard?' + params)
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const doc = new DOMParser().parseFromString(html, 'text/html');
|
||||
container.innerHTML = doc.getElementById('analisis-content').innerHTML;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// PAGINATION AJAX
|
||||
document.addEventListener('click', function(e){
|
||||
const link = e.target.closest('a');
|
||||
if(link && link.href.includes('page=')){
|
||||
e.preventDefault();
|
||||
fetch(link.href)
|
||||
.then(res => res.text())
|
||||
.then(html => {
|
||||
const doc = new DOMParser().parseFromString(html, 'text/html');
|
||||
container.innerHTML = doc.getElementById('analisis-content').innerHTML;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php $__env->stopSection(); ?>
|
||||
<?php echo $__env->make('layouts.sentara', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?><?php /**PATH C:\laragon\www\SistemAnalisisSentimen\resources\views/dashboard.blade.php ENDPATH**/ ?>
|
||||
|
|
@ -0,0 +1,366 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="id">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Login - SENTARA</title>
|
||||
|
||||
<link rel="icon" type="image/png" href="<?php echo e(asset('favicon.png')); ?>">
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600&display=swap" rel="stylesheet">
|
||||
|
||||
<style>
|
||||
*{
|
||||
margin:0;
|
||||
padding:0;
|
||||
box-sizing:border-box;
|
||||
font-family:'Poppins',sans-serif;
|
||||
}
|
||||
|
||||
body{
|
||||
background:#f3f5fb;
|
||||
min-height:100vh;
|
||||
display:flex;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
padding:40px;
|
||||
}
|
||||
|
||||
/* CONTAINER */
|
||||
.container{
|
||||
width:1350px;
|
||||
max-width:100%;
|
||||
height:720px;
|
||||
background:#fff;
|
||||
border-radius:25px;
|
||||
display:flex;
|
||||
overflow:hidden;
|
||||
box-shadow:0 30px 80px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
/* LEFT */
|
||||
.left{
|
||||
width:50%;
|
||||
padding:60px 80px;
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
justify-content:center;
|
||||
}
|
||||
|
||||
/* LOGO */
|
||||
.logo{
|
||||
text-align:center;
|
||||
margin-bottom:25px;
|
||||
}
|
||||
|
||||
.logo img{
|
||||
width:200px;
|
||||
}
|
||||
|
||||
/* TITLE */
|
||||
.title{
|
||||
text-align:center;
|
||||
font-size:28px;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
.title span{
|
||||
color:#ff5c8d;
|
||||
}
|
||||
|
||||
.subtitle{
|
||||
text-align:center;
|
||||
font-size:14px;
|
||||
color:#777;
|
||||
margin:12px 0 35px;
|
||||
}
|
||||
|
||||
/* FORM */
|
||||
.form-group{
|
||||
margin-bottom:20px;
|
||||
}
|
||||
|
||||
label{
|
||||
font-size:13px;
|
||||
font-weight:500;
|
||||
}
|
||||
|
||||
input{
|
||||
width:100%;
|
||||
padding:14px;
|
||||
border-radius:12px;
|
||||
border:1px solid #ddd;
|
||||
margin-top:6px;
|
||||
font-size:14px;
|
||||
}
|
||||
|
||||
.input-group{
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.toggle{
|
||||
position:absolute;
|
||||
right:12px;
|
||||
top:14px;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.forgot{
|
||||
text-align:right;
|
||||
margin-top:6px;
|
||||
}
|
||||
|
||||
.forgot a{
|
||||
font-size:12px;
|
||||
color:#2d5be3;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
/* BUTTON */
|
||||
.btn{
|
||||
width:100%;
|
||||
padding:14px;
|
||||
border:none;
|
||||
border-radius:12px;
|
||||
background:linear-gradient(90deg,#2d5be3,#4c7dff);
|
||||
color:#fff;
|
||||
font-weight:500;
|
||||
margin-top:20px;
|
||||
cursor:pointer;
|
||||
transition:0.3s;
|
||||
}
|
||||
|
||||
.btn:hover{
|
||||
opacity:0.9;
|
||||
}
|
||||
|
||||
.right{
|
||||
width:50%;
|
||||
position:relative;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
/* GAMBAR */
|
||||
.right img{
|
||||
position:absolute;
|
||||
top:0;
|
||||
right:0;
|
||||
width:100%;
|
||||
height:100%;
|
||||
object-fit:cover;
|
||||
|
||||
/* SHAPE DIPERBAIKI */
|
||||
clip-path: ellipse(120% 100% at 100% 50%);
|
||||
}
|
||||
|
||||
/* OVERLAY */
|
||||
.overlay{
|
||||
position:absolute;
|
||||
width:100%;
|
||||
height:100%;
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
align-items:center;
|
||||
justify-content:center;
|
||||
text-align:center;
|
||||
color:#fff;
|
||||
background:rgba(0,0,0,0.25);
|
||||
padding:20px;
|
||||
z-index:2; /* DI ATAS */
|
||||
}
|
||||
|
||||
/* QUOTE */
|
||||
.quote{
|
||||
font-size:42px;
|
||||
color:#ff5c8d;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
|
||||
/* TEXT */
|
||||
.overlay p{
|
||||
font-size:30px;
|
||||
font-weight:500;
|
||||
line-height:1.5;
|
||||
max-width:420px;
|
||||
}
|
||||
|
||||
.overlay span{
|
||||
color:#ff5c8d;
|
||||
font-weight:600;
|
||||
}
|
||||
|
||||
/* GARIS */
|
||||
.line{
|
||||
width:70px;
|
||||
height:3px;
|
||||
background:#fff;
|
||||
border-radius:10px;
|
||||
margin-top:18px;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.line::after{
|
||||
content:'';
|
||||
position:absolute;
|
||||
width:12px;
|
||||
height:12px;
|
||||
border:2px solid #fff;
|
||||
border-left:none;
|
||||
border-top:none;
|
||||
transform:rotate(-45deg);
|
||||
right:-12px;
|
||||
top:-5px;
|
||||
}
|
||||
|
||||
/* MOBILE */
|
||||
@media(max-width:900px){
|
||||
.container{
|
||||
flex-direction:column;
|
||||
height:auto;
|
||||
}
|
||||
|
||||
.left{
|
||||
width:100%;
|
||||
padding:40px;
|
||||
}
|
||||
|
||||
.right{
|
||||
width:100%;
|
||||
height:260px;
|
||||
}
|
||||
|
||||
.overlay p{
|
||||
font-size:20px;
|
||||
}
|
||||
|
||||
.logo img{
|
||||
width:150px;
|
||||
}
|
||||
}
|
||||
|
||||
@media(max-width:900px){
|
||||
.container{
|
||||
flex-direction:column;
|
||||
height:auto;
|
||||
}
|
||||
|
||||
.left{
|
||||
width:100%;
|
||||
padding:40px;
|
||||
}
|
||||
|
||||
.right{
|
||||
width:100%;
|
||||
height:260px;
|
||||
}
|
||||
|
||||
.overlay p{
|
||||
font-size:20px;
|
||||
}
|
||||
|
||||
.logo img{
|
||||
width:150px;
|
||||
}
|
||||
}
|
||||
|
||||
/* HILANGKAN ICON PASSWORD BAWAAN BROWSER */
|
||||
input[type="password"]::-ms-reveal,
|
||||
input[type="password"]::-ms-clear {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input::-ms-reveal,
|
||||
input::-ms-clear {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
|
||||
<!-- LEFT -->
|
||||
<div class="left">
|
||||
|
||||
<div class="logo">
|
||||
<img src="<?php echo e(asset('images/logo-sentara.png')); ?>">
|
||||
</div>
|
||||
|
||||
<?php if($errors->any()): ?>
|
||||
<script src="https://cdn.jsdelivr.net/npm/sweetalert2@11"></script>
|
||||
|
||||
<script>
|
||||
Swal.fire({
|
||||
icon: 'error',
|
||||
title: 'Login Gagal',
|
||||
text: 'Email atau password yang dimasukkan salah.',
|
||||
confirmButtonColor: '#2d5be3'
|
||||
});
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="title">
|
||||
Selamat Datang <span>Kembali!</span>
|
||||
</div>
|
||||
|
||||
<div class="subtitle">
|
||||
Login untuk mengakses Dashboard Analisis Sentimen Wisata Jember
|
||||
</div>
|
||||
|
||||
<form method="POST" action="<?php echo e(route('login')); ?>">
|
||||
<?php echo csrf_field(); ?>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Email</label>
|
||||
<input type="email" name="email" placeholder="Masukkan email Anda" required>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label>Password</label>
|
||||
<div class="input-group">
|
||||
<input type="password" id="password" name="password" placeholder="Masukkan password Anda" required>
|
||||
<span class="toggle" onclick="togglePass()">👁</span>
|
||||
</div>
|
||||
|
||||
<div class="forgot">
|
||||
<a href="<?php echo e(route('password.request')); ?>">Lupa password?</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn">Login</button>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- RIGHT -->
|
||||
<div class="right">
|
||||
|
||||
<img src="<?php echo e(asset('images/papuma.jpg')); ?>" alt="bg">
|
||||
|
||||
<div class="overlay">
|
||||
|
||||
<p>
|
||||
Memahami opini,<br>
|
||||
meningkatkan <span>pariwisata</span><br>
|
||||
Jember.
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function togglePass(){
|
||||
let x = document.getElementById("password");
|
||||
x.type = x.type === "password" ? "text" : "password";
|
||||
}
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html><?php /**PATH C:\laragon\www\SistemAnalisisSentimen\resources\views/auth/login.blade.php ENDPATH**/ ?>
|
||||
|
|
@ -0,0 +1,204 @@
|
|||
<?php $__env->startSection('content'); ?>
|
||||
|
||||
<div class="max-w-7xl mx-auto px-4 md:px-0 space-y-6">
|
||||
|
||||
<!-- HEADER -->
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold text-gray-800">Data Ulasan</h2>
|
||||
<p class="text-sm text-gray-500">
|
||||
Periode aktif: <?php echo e($periodeAktif->nama ?? 'Belum ada data'); ?>
|
||||
|
||||
<a href="<?php echo e(route('riwayat.index')); ?>" class="text-blue-600 hover:underline ml-2">Lihat riwayat</a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-col md:flex-row gap-3 md:items-center">
|
||||
<form action="<?php echo e(route('ulasan.ambil')); ?>" method="POST" class="flex flex-col md:flex-row gap-3 md:items-center">
|
||||
<?php echo csrf_field(); ?>
|
||||
<input type="hidden" name="redirect_to" value="ulasan">
|
||||
<input type="month" name="periode_bulan" value="<?php echo e($periodeAktif
|
||||
? $periodeAktif->tahun . '-' . str_pad($periodeAktif->bulan, 2, '0', STR_PAD_LEFT)
|
||||
: now()->format('Y-m')); ?>"
|
||||
class="border rounded-lg px-3 py-2 text-sm bg-white shadow-sm min-w-[150px]">
|
||||
<select name="wisata" class="border rounded-lg pl-3 pr-9 py-2 text-sm bg-white shadow-sm min-w-[220px]">
|
||||
<option value="">Semua Lokasi</option>
|
||||
<?php $__currentLoopData = ($scraperDestinations ?? []); $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $scraperDestination): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||
<option value="<?php echo e($scraperDestination); ?>"><?php echo e($scraperDestination); ?></option>
|
||||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||
</select>
|
||||
<button class="border border-blue-500 text-blue-600 px-5 py-2.5 rounded-full hover:bg-blue-50 transition">
|
||||
Ambil Data
|
||||
</button>
|
||||
</form>
|
||||
<form action="<?php echo e(route('proses.analisis')); ?>" method="POST">
|
||||
<?php echo csrf_field(); ?>
|
||||
<input type="hidden" name="periode_id" value="<?php echo e($periodeId); ?>">
|
||||
<button
|
||||
<?php echo e($totalUlasan <= 0 ? 'disabled' : ''); ?>
|
||||
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white px-6 py-2.5 rounded-full shadow-md transition disabled:opacity-50 disabled:cursor-not-allowed">
|
||||
Proses Analisis
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- SUMMARY -->
|
||||
<div class="bg-white rounded-3xl shadow p-6 mb-6 mt-5">
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-blue-100 text-blue-600 p-3 rounded-full">📄</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500">Total Ulasan</p>
|
||||
<p class="font-bold text-lg"><?php echo e($totalUlasan); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-green-100 text-green-600 p-3 rounded-full">📍</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500">Total Wisata</p>
|
||||
<p class="font-bold text-lg"><?php echo e($totalWisata); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="bg-orange-100 text-orange-600 p-3 rounded-full">📅</div>
|
||||
<div>
|
||||
<p class="text-xs text-gray-500">Terakhir Update</p>
|
||||
<p class="text-sm font-semibold">
|
||||
<?php echo e($lastUpdate ? \Carbon\Carbon::parse($lastUpdate)->format('d M Y H:i') : '-'); ?>
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ALERT -->
|
||||
<?php if(session('success')): ?>
|
||||
<div class="bg-green-100 text-green-700 px-4 py-2 rounded-lg text-sm">
|
||||
<?php echo e(session('success')); ?>
|
||||
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if(session('error')): ?>
|
||||
<div class="bg-red-100 text-red-700 px-4 py-2 rounded-lg text-sm whitespace-pre-line">
|
||||
<?php echo e(session('error')); ?>
|
||||
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- SEARCH -->
|
||||
<form method="GET" action="<?php echo e(route('ulasan.index')); ?>" class="flex flex-col md:flex-row gap-3 items-center">
|
||||
<?php if(request('periode_id')): ?>
|
||||
<input type="hidden" name="periode_id" value="<?php echo e(request('periode_id')); ?>">
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<input type="text" name="search" value="<?php echo e(request('search')); ?>"
|
||||
placeholder="Cari ulasan atau wisata..."
|
||||
class="flex-1 border px-3 py-2 rounded-lg text-sm">
|
||||
|
||||
<button class="bg-blue-500 text-white px-4 py-2 rounded-lg text-sm">Cari</button>
|
||||
|
||||
<button type="button"
|
||||
onclick="if (confirm('Reset akan mengosongkan semua ulasan dan hasil analisis untuk periode ini. Lanjutkan?')) document.getElementById('resetPeriodeForm').submit();"
|
||||
class="bg-gray-200 px-4 py-2 rounded-lg text-sm">
|
||||
Reset
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
<?php if($periodeId): ?>
|
||||
<form id="resetPeriodeForm" action="<?php echo e(route('ulasan.kosongkan-periode')); ?>" method="POST" class="hidden">
|
||||
<?php echo csrf_field(); ?>
|
||||
<?php echo method_field('DELETE'); ?>
|
||||
<input type="hidden" name="periode_id" value="<?php echo e($periodeId); ?>">
|
||||
</form>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- TABLE -->
|
||||
<div class="bg-white rounded-xl shadow overflow-hidden">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="bg-gray-100">
|
||||
<tr>
|
||||
<th class="px-4 py-3 w-[5%]">No</th>
|
||||
<th class="px-4 py-3 w-[20%]">Nama Wisata</th>
|
||||
<th class="px-4 py-3 w-[10%] text-center">Rating</th>
|
||||
<th class="px-4 py-3 w-[45%]">Ulasan</th>
|
||||
<th class="px-4 py-3 w-[20%] text-center">Tanggal</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y">
|
||||
<?php $__empty_1 = true; $__currentLoopData = $mentah; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $i => $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
|
||||
<tr class="hover:bg-gray-50">
|
||||
<td class="px-4 py-3"><?php echo e($mentah->firstItem() + $i); ?></td>
|
||||
<td class="px-4 py-3 font-medium"><?php echo e($item->wisata); ?></td>
|
||||
<td class="px-4 py-3 text-center text-yellow-500">
|
||||
<?php echo e(str_repeat('★', round($item->rating))); ?>
|
||||
|
||||
<span class="text-gray-500 ml-1"><?php echo e($item->rating); ?></span>
|
||||
</td>
|
||||
<td class="px-4 py-3">
|
||||
<div class="line-clamp-2 text-gray-600"><?php echo e($item->ulasan); ?></div>
|
||||
</td>
|
||||
<td class="px-4 py-3 text-center text-gray-500">
|
||||
<?php
|
||||
try {
|
||||
$tanggalUlasan = $item->tanggal
|
||||
? \Carbon\Carbon::parse($item->tanggal)->format('d M Y')
|
||||
: '-';
|
||||
} catch (\Throwable $e) {
|
||||
$tanggalUlasan = $item->tanggal ?: '-';
|
||||
}
|
||||
?>
|
||||
<?php echo e($tanggalUlasan); ?>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
|
||||
<tr>
|
||||
<td colspan="5" class="text-center py-6 text-gray-400">Belum ada data</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="p-4 flex flex-col md:flex-row gap-3 justify-between items-center text-sm text-gray-500">
|
||||
<div>
|
||||
Menampilkan <?php echo e($mentah->firstItem() ?? 0); ?> - <?php echo e($mentah->lastItem() ?? 0); ?>
|
||||
|
||||
dari <?php echo e($mentah->total()); ?> data
|
||||
</div>
|
||||
<div class="flex items-center gap-1">
|
||||
<?php if($mentah->onFirstPage()): ?>
|
||||
<span class="px-3 py-1 bg-gray-200 rounded-lg">«</span>
|
||||
<?php else: ?>
|
||||
<a href="<?php echo e($mentah->previousPageUrl()); ?>" class="px-3 py-1 bg-gray-100 rounded-lg">«</a>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php for($i = 1; $i <= $mentah->lastPage(); $i++): ?>
|
||||
<?php if($i == $mentah->currentPage()): ?>
|
||||
<span class="px-3 py-1 bg-blue-600 text-white rounded-lg"><?php echo e($i); ?></span>
|
||||
<?php elseif($i <= 3 || $i > $mentah->lastPage() - 2 || abs($i - $mentah->currentPage()) <= 1): ?>
|
||||
<a href="<?php echo e($mentah->url($i)); ?>" class="px-3 py-1 bg-gray-100 rounded-lg"><?php echo e($i); ?></a>
|
||||
<?php elseif($i == 4 || $i == $mentah->lastPage() - 3): ?>
|
||||
<span class="px-2">...</span>
|
||||
<?php endif; ?>
|
||||
<?php endfor; ?>
|
||||
|
||||
<?php if($mentah->hasMorePages()): ?>
|
||||
<a href="<?php echo e($mentah->nextPageUrl()); ?>" class="px-3 py-1 bg-gray-100 rounded-lg">»</a>
|
||||
<?php else: ?>
|
||||
<span class="px-3 py-1 bg-gray-200 rounded-lg">»</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php $__env->stopSection(); ?>
|
||||
|
||||
<?php echo $__env->make('layouts.sentara', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?><?php /**PATH C:\laragon\www\SistemAnalisisSentimen\resources\views/ulasan/index.blade.php ENDPATH**/ ?>
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
<?php if($standalone ?? false): ?>
|
||||
|
||||
<?php $__env->startSection('content'); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
$totalHasilAnalisis ??= $hasil->total() ?? 0;
|
||||
$jumlahKelasAnalisis ??= 0;
|
||||
$evaluasiTersedia = $evaluasi && $jumlahKelasAnalisis >= 2;
|
||||
?>
|
||||
|
||||
<div class="space-y-4">
|
||||
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<div>
|
||||
<h2 class="text-2xl font-bold">Hasil Analisis Sentimen</h2>
|
||||
<p class="text-gray-500 text-sm">
|
||||
Evaluasi memakai pseudo-label dari rating/rule otomatis, bukan anotasi manual.
|
||||
</p>
|
||||
<?php if($totalHasilAnalisis > 0 && !$evaluasiTersedia): ?>
|
||||
<p class="text-sm text-yellow-700 bg-yellow-50 border border-yellow-200 rounded-lg px-3 py-2 mt-3">
|
||||
Semua hasil hanya memiliki <?php echo e($jumlahKelasAnalisis); ?> kelas sentimen. Precision, recall, F1, dan akurasi tidak dihitung karena evaluasi klasifikasi membutuhkan minimal 2 kelas. Detail hasil analisis tetap ditampilkan di bawah.
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-4">
|
||||
|
||||
<div class="bg-white p-5 rounded-xl shadow">
|
||||
<p class="text-gray-500 text-sm">Precision</p>
|
||||
<h3 class="text-2xl font-bold text-blue-600">
|
||||
<?php echo e($evaluasiTersedia ? number_format($evaluasi->precision ?? 0, 2) : '-'); ?>
|
||||
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="bg-white p-5 rounded-xl shadow">
|
||||
<p class="text-gray-500 text-sm">Recall</p>
|
||||
<h3 class="text-2xl font-bold text-green-600">
|
||||
<?php echo e($evaluasiTersedia ? number_format($evaluasi->recall ?? 0, 2) : '-'); ?>
|
||||
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="bg-white p-5 rounded-xl shadow">
|
||||
<p class="text-gray-500 text-sm">F1 Score</p>
|
||||
<h3 class="text-2xl font-bold text-purple-600">
|
||||
<?php echo e($evaluasiTersedia ? number_format($evaluasi->f1_score ?? 0, 2) : '-'); ?>
|
||||
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div class="bg-white p-5 rounded-xl shadow">
|
||||
<p class="text-gray-500 text-sm">Akurasi</p>
|
||||
<h3 class="text-2xl font-bold text-indigo-600">
|
||||
<?php echo e($evaluasiTersedia ? number_format($evaluasi->accuracy ?? 0, 2) : '-'); ?>
|
||||
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="flex items-end gap-3 mb-4">
|
||||
|
||||
<form id="filter-form"
|
||||
method="GET"
|
||||
action="<?php echo e(route('dashboard')); ?>"
|
||||
class="flex items-end gap-2">
|
||||
|
||||
<input type="hidden" name="tab" value="analisis">
|
||||
<input type="hidden" name="periode_id"
|
||||
value="<?php echo e($periodeAktif->id ?? ''); ?>">
|
||||
|
||||
<select
|
||||
name="wisata"
|
||||
class="border rounded px-3 py-2 h-[46px]">
|
||||
|
||||
<option value="">Semua Destinasi</option>
|
||||
|
||||
<?php $__currentLoopData = $wisataList; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||
<option value="<?php echo e($item); ?>"
|
||||
<?php echo e(request('wisata') == $item ? 'selected' : ''); ?>>
|
||||
<?php echo e($item); ?>
|
||||
|
||||
</option>
|
||||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||
|
||||
</select>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
class="bg-blue-600 text-white px-4 rounded h-[46px]">
|
||||
Filter
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
||||
<a href="<?php echo e(route('riwayat.index')); ?>"
|
||||
class="inline-flex items-center justify-center bg-blue-600 hover:bg-blue-700 text-white px-5 rounded-lg shadow transition h-[46px]">
|
||||
|
||||
<i class="fas fa-history mr-2"></i>
|
||||
Lihat Riwayat
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="bg-white rounded-xl shadow p-4 h-fit">
|
||||
|
||||
<h3 class="font-semibold mb-4">Detail Hasil Analisis Sentimen</h3>
|
||||
|
||||
<table class="w-full text-sm">
|
||||
<thead class="border-b text-left">
|
||||
<tr>
|
||||
<th>No</th>
|
||||
<th>Wisata</th>
|
||||
<th>Ulasan Asli</th>
|
||||
<th>Ulasan Bersih</th>
|
||||
<th>Sentimen</th>
|
||||
<th>Probabilitas</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<?php $__empty_1 = true; $__currentLoopData = $hasil; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $item): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); $__empty_1 = false; ?>
|
||||
<tr class="border-b">
|
||||
<td><?php echo e(($hasil->currentPage() - 1) * $hasil->perPage() + $loop->iteration); ?></td>
|
||||
<td><?php echo e($item->wisata); ?></td>
|
||||
<td class="text-gray-500"><?php echo e(Str::limit($item->ulasan_asli ?? '-', 80)); ?></td>
|
||||
<td><?php echo e(Str::limit($item->hasil_preprocessing ?? '-', 80)); ?></td>
|
||||
<td>
|
||||
<span class="px-2 py-1 rounded text-xs
|
||||
<?php echo e(strtolower($item->sentimen) == 'positif' ? 'bg-green-100 text-green-600' : ''); ?>
|
||||
|
||||
<?php echo e(strtolower($item->sentimen) == 'negatif' ? 'bg-red-100 text-red-600' : ''); ?>
|
||||
|
||||
<?php echo e(strtolower($item->sentimen) == 'netral' ? 'bg-yellow-100 text-yellow-600' : ''); ?>
|
||||
|
||||
">
|
||||
<?php echo e(ucfirst($item->sentimen)); ?>
|
||||
|
||||
</span>
|
||||
</td>
|
||||
<td><?php echo e(number_format($item->probabilitas ?? 0, 2)); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); if ($__empty_1): ?>
|
||||
<tr>
|
||||
<td colspan="6" class="text-center py-4 text-gray-500">Tidak ada data</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
<?php if($hasil->hasPages()): ?>
|
||||
<?php
|
||||
$current = $hasil->currentPage();
|
||||
$last = $hasil->lastPage();
|
||||
$query = http_build_query(request()->except('page'));
|
||||
// Window 2 halaman kiri & kanan dari current
|
||||
$window = collect(range(max(1, $current - 2), min($last, $current + 2)));
|
||||
?>
|
||||
|
||||
<div class="mt-4 flex items-center justify-between text-sm text-gray-600">
|
||||
|
||||
|
||||
<p>Menampilkan <?php echo e($hasil->firstItem()); ?> - <?php echo e($hasil->lastItem()); ?> dari <?php echo e($hasil->total()); ?> data</p>
|
||||
|
||||
|
||||
<div class="flex items-center gap-1">
|
||||
|
||||
|
||||
<?php if($hasil->onFirstPage()): ?>
|
||||
<span class="px-3 py-1 rounded border bg-gray-100 text-gray-400 cursor-not-allowed">«</span>
|
||||
<?php else: ?>
|
||||
<a href="<?php echo e($hasil->previousPageUrl()); ?>&<?php echo e($query); ?>" class="px-3 py-1 rounded border hover:bg-blue-50 text-blue-600">«</a>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<?php if(!$window->contains(1)): ?>
|
||||
<a href="<?php echo e($hasil->url(1)); ?>&<?php echo e($query); ?>" class="px-3 py-1 rounded border hover:bg-blue-50 text-blue-600">1</a>
|
||||
<?php if($window->min() > 2): ?>
|
||||
<span class="px-2 py-1 text-gray-400">...</span>
|
||||
<?php endif; ?>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<?php $__currentLoopData = $window; $__env->addLoop($__currentLoopData); foreach($__currentLoopData as $page): $__env->incrementLoopIndices(); $loop = $__env->getLastLoop(); ?>
|
||||
<?php if($page == $current): ?>
|
||||
<span class="px-3 py-1 rounded border bg-blue-600 text-white font-semibold"><?php echo e($page); ?></span>
|
||||
<?php else: ?>
|
||||
<a href="<?php echo e($hasil->url($page)); ?>&<?php echo e($query); ?>" class="px-3 py-1 rounded border hover:bg-blue-50 text-blue-600"><?php echo e($page); ?></a>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; $__env->popLoop(); $loop = $__env->getLastLoop(); ?>
|
||||
|
||||
|
||||
<?php if(!$window->contains($last)): ?>
|
||||
<?php if($window->max() < $last - 1): ?>
|
||||
<span class="px-2 py-1 text-gray-400">...</span>
|
||||
<?php endif; ?>
|
||||
<a href="<?php echo e($hasil->url($last)); ?>&<?php echo e($query); ?>" class="px-3 py-1 rounded border hover:bg-blue-50 text-blue-600"><?php echo e($last); ?></a>
|
||||
<?php endif; ?>
|
||||
|
||||
|
||||
<?php if($hasil->hasMorePages()): ?>
|
||||
<a href="<?php echo e($hasil->nextPageUrl()); ?>&<?php echo e($query); ?>" class="px-3 py-1 rounded border hover:bg-blue-50 text-blue-600">»</a>
|
||||
<?php else: ?>
|
||||
<span class="px-3 py-1 rounded border bg-gray-100 text-gray-400 cursor-not-allowed">»</span>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<?php if($standalone ?? false): ?>
|
||||
<?php $__env->stopSection(); ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php echo $__env->make('layouts.sentara', array_diff_key(get_defined_vars(), ['__data' => 1, '__path' => 1]))->render(); ?><?php /**PATH C:\laragon\www\SistemAnalisisSentimen\resources\views/analisis/index.blade.php ENDPATH**/ ?>
|
||||
Loading…
Reference in New Issue