fix report and add filter
This commit is contained in:
parent
3381eb11b5
commit
beb4d15d11
|
@ -56,6 +56,23 @@ void setup() {
|
|||
Firebase.begin(&config, &auth);
|
||||
Firebase.reconnectWiFi(true);
|
||||
|
||||
// Konfigurasi NTP dan tunggu sinkronisasi
|
||||
configTime(7 * 3600, 0, "pool.ntp.org"); // GMT+7
|
||||
Serial.println("Menunggu sinkronisasi waktu");
|
||||
while (time(nullptr) < 1000000000) {
|
||||
Serial.print(".");
|
||||
delay(100);
|
||||
}
|
||||
Serial.println("\nWaktu tersinkronisasi!");
|
||||
|
||||
// Setelah waktu tersinkronisasi, baru kirim timestamp pertama
|
||||
unsigned long epochTime = time(nullptr);
|
||||
if (Firebase.setInt(firebaseData, "/device/lastActiveWemos", epochTime)) {
|
||||
Serial.println("Initial timestamp sent: " + String(epochTime));
|
||||
} else {
|
||||
Serial.println("Failed to send initial timestamp");
|
||||
}
|
||||
|
||||
// Inisialisasi RFID
|
||||
SPI.begin();
|
||||
mfrc522.PCD_Init();
|
||||
|
@ -84,13 +101,6 @@ void setup() {
|
|||
// Update path untuk restart control
|
||||
Firebase.setBool(firebaseData, "/control/restartWemos", false);
|
||||
|
||||
// Konfigurasi NTP
|
||||
configTime(7 * 3600, 0, "pool.ntp.org"); // GMT+7
|
||||
|
||||
// Kirim timestamp pertama kali
|
||||
unsigned long epochTime = time(nullptr);
|
||||
Firebase.setInt(firebaseData, "/device/lastActiveWemos", epochTime);
|
||||
|
||||
// Update status device saat startup
|
||||
Firebase.setString(firebaseData, "/logs/systemWemos", "Device Online");
|
||||
}
|
||||
|
|
|
@ -43,59 +43,135 @@ public function handle()
|
|||
// Ambil data terakhir jika ada
|
||||
$lastEntry = !empty($historyData) ? end($historyData) : null;
|
||||
|
||||
// Cek apakah ada perubahan pada security, smartcab, control, atau logs
|
||||
// Cek perubahan pada setiap kategori data
|
||||
$securityChanged = false;
|
||||
$smartcabChanged = false;
|
||||
$controlChanged = false;
|
||||
$logsChanged = false;
|
||||
$dht11Changed = false;
|
||||
$deviceChanged = false;
|
||||
$hasChanges = false;
|
||||
|
||||
if ($lastEntry === null) {
|
||||
$hasChanges = true;
|
||||
// Jika belum ada data, anggap semua kategori berubah (kecuali yang dikecualikan)
|
||||
$securityChanged = !empty($securityData);
|
||||
$smartcabChanged = !empty($smartcabData);
|
||||
$controlChanged = !empty($controlData);
|
||||
$logsChanged = !empty($logsData);
|
||||
|
||||
// Untuk DHT11 dan Device, kita hanya anggap berubah jika ada data selain yang dikecualikan
|
||||
$dht11Changed = !empty($dht11Data) && $this->hasNonTrivialDHT11Data($dht11Data);
|
||||
$deviceChanged = !empty($deviceData) && $this->hasNonTrivialDeviceData($deviceData);
|
||||
|
||||
$hasChanges = $securityChanged || $smartcabChanged || $controlChanged ||
|
||||
$logsChanged || $dht11Changed || $deviceChanged;
|
||||
} else {
|
||||
// Cek perubahan pada setiap kategori
|
||||
$securityChanged = $this->hasDataChanged($lastEntry['security'] ?? [], $securityData);
|
||||
$smartcabChanged = $this->hasDataChanged($lastEntry['smartcab'] ?? [], $smartcabData);
|
||||
$controlChanged = $this->hasDataChanged($lastEntry['control'] ?? [], $controlData);
|
||||
$logsChanged = $this->hasDataChanged($lastEntry['logs'] ?? [], $logsData);
|
||||
|
||||
$hasChanges = $securityChanged || $smartcabChanged || $controlChanged || $logsChanged;
|
||||
// Untuk dht11 dan device kita periksa secara khusus, mengabaikan field yang sering berubah
|
||||
$dht11Changed = $this->hasNonTrivialDHT11Changes($lastEntry['dht11'] ?? [], $dht11Data);
|
||||
$deviceChanged = $this->hasNonTrivialDeviceChanges($lastEntry['device'] ?? [], $deviceData);
|
||||
|
||||
$hasChanges = $securityChanged || $smartcabChanged || $controlChanged ||
|
||||
$logsChanged || $dht11Changed || $deviceChanged;
|
||||
}
|
||||
|
||||
// Hanya simpan jika ada perubahan
|
||||
if ($hasChanges) {
|
||||
$newData = [
|
||||
'id' => Str::uuid()->toString(), // Generate ID unik
|
||||
'timestamp' => now()->toIso8601String(),
|
||||
// Proses setiap perubahan secara terpisah
|
||||
$changesMade = false;
|
||||
|
||||
// Buat template data lengkap
|
||||
$fullData = [
|
||||
'security' => $securityData,
|
||||
'smartcab' => $smartcabData,
|
||||
'control' => $controlData,
|
||||
'logs' => $logsData
|
||||
];
|
||||
'logs' => $logsData,
|
||||
'dht11' => $dht11Data,
|
||||
'device' => $deviceData
|
||||
];
|
||||
|
||||
if (!empty($dht11Data)) {
|
||||
$newData['dht11'] = $dht11Data;
|
||||
}
|
||||
// Simpan setiap perubahan secara terpisah dengan data lengkap
|
||||
if ($securityChanged && !empty($securityData)) {
|
||||
$newEntry = $fullData;
|
||||
$newEntry['id'] = Str::uuid()->toString();
|
||||
$newEntry['timestamp'] = now()->toIso8601String();
|
||||
$newEntry['change_type'] = 'security'; // Tambahkan informasi apa yang berubah
|
||||
|
||||
if (!empty($deviceData)) {
|
||||
$newData['device'] = $deviceData;
|
||||
}
|
||||
$historyData[] = $newEntry;
|
||||
event(new ReportUpdated($newEntry, 'security'));
|
||||
$this->info('Perubahan terdeteksi pada security, ID: ' . $newEntry['id']);
|
||||
$changesMade = true;
|
||||
}
|
||||
|
||||
$historyData[] = $newData;
|
||||
if ($smartcabChanged && !empty($smartcabData)) {
|
||||
$newEntry = $fullData;
|
||||
$newEntry['id'] = Str::uuid()->toString();
|
||||
$newEntry['timestamp'] = now()->toIso8601String();
|
||||
$newEntry['change_type'] = 'smartcab';
|
||||
|
||||
$historyData[] = $newEntry;
|
||||
event(new ReportUpdated($newEntry, 'smartcab'));
|
||||
$this->info('Perubahan terdeteksi pada smartcab, ID: ' . $newEntry['id']);
|
||||
$changesMade = true;
|
||||
}
|
||||
|
||||
if ($controlChanged && !empty($controlData)) {
|
||||
$newEntry = $fullData;
|
||||
$newEntry['id'] = Str::uuid()->toString();
|
||||
$newEntry['timestamp'] = now()->toIso8601String();
|
||||
$newEntry['change_type'] = 'control';
|
||||
|
||||
$historyData[] = $newEntry;
|
||||
event(new ReportUpdated($newEntry, 'control'));
|
||||
$this->info('Perubahan terdeteksi pada control, ID: ' . $newEntry['id']);
|
||||
$changesMade = true;
|
||||
}
|
||||
|
||||
if ($logsChanged && !empty($logsData)) {
|
||||
$newEntry = $fullData;
|
||||
$newEntry['id'] = Str::uuid()->toString();
|
||||
$newEntry['timestamp'] = now()->toIso8601String();
|
||||
$newEntry['change_type'] = 'logs';
|
||||
|
||||
$historyData[] = $newEntry;
|
||||
event(new ReportUpdated($newEntry, 'logs'));
|
||||
$this->info('Perubahan terdeteksi pada logs, ID: ' . $newEntry['id']);
|
||||
$changesMade = true;
|
||||
}
|
||||
|
||||
if ($dht11Changed && !empty($dht11Data)) {
|
||||
$newEntry = $fullData;
|
||||
$newEntry['id'] = Str::uuid()->toString();
|
||||
$newEntry['timestamp'] = now()->toIso8601String();
|
||||
$newEntry['change_type'] = 'dht11';
|
||||
|
||||
$historyData[] = $newEntry;
|
||||
event(new ReportUpdated($newEntry, 'dht11'));
|
||||
$this->info('Perubahan signifikan terdeteksi pada dht11, ID: ' . $newEntry['id']);
|
||||
$changesMade = true;
|
||||
}
|
||||
|
||||
if ($deviceChanged && !empty($deviceData)) {
|
||||
$newEntry = $fullData;
|
||||
$newEntry['id'] = Str::uuid()->toString();
|
||||
$newEntry['timestamp'] = now()->toIso8601String();
|
||||
$newEntry['change_type'] = 'device';
|
||||
|
||||
$historyData[] = $newEntry;
|
||||
event(new ReportUpdated($newEntry, 'device'));
|
||||
$this->info('Perubahan signifikan terdeteksi pada device, ID: ' . $newEntry['id']);
|
||||
$changesMade = true;
|
||||
}
|
||||
|
||||
// Jika ada perubahan yang disimpan, update file
|
||||
if ($changesMade) {
|
||||
Storage::put('reports.json', json_encode($historyData, JSON_PRETTY_PRINT));
|
||||
$this->info('Data baru tersimpan dengan ID: ' . $newData['id']);
|
||||
|
||||
// Broadcast event untuk realtime update
|
||||
event(new ReportUpdated($newData));
|
||||
|
||||
if (isset($securityChanged) && $securityChanged) {
|
||||
$this->info('Perubahan terdeteksi pada security');
|
||||
}
|
||||
if (isset($smartcabChanged) && $smartcabChanged) {
|
||||
$this->info('Perubahan terdeteksi pada smartcab');
|
||||
}
|
||||
if (isset($controlChanged) && $controlChanged) {
|
||||
$this->info('Perubahan terdeteksi pada control');
|
||||
}
|
||||
if (isset($logsChanged) && $logsChanged) {
|
||||
$this->info('Perubahan terdeteksi pada logs');
|
||||
}
|
||||
$this->info('Semua perubahan berhasil disimpan.');
|
||||
} else {
|
||||
$this->info('Tidak ada perubahan pada data, data tidak disimpan');
|
||||
$this->info('Tidak ada perubahan signifikan pada data, data tidak disimpan');
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
@ -110,4 +186,96 @@ private function hasDataChanged($oldData, $newData)
|
|||
|
||||
return $oldJson !== $newJson;
|
||||
}
|
||||
|
||||
/**
|
||||
* Memeriksa perubahan pada data dht11 selain humidity dan temperature
|
||||
*/
|
||||
private function hasNonTrivialDHT11Changes($oldData, $newData)
|
||||
{
|
||||
// Buat salinan data untuk perbandingan
|
||||
$oldDataCompare = is_array($oldData) ? $oldData : [];
|
||||
$newDataCompare = is_array($newData) ? $newData : [];
|
||||
|
||||
// Hapus field yang sering berubah
|
||||
if (isset($oldDataCompare['humidity'])) {
|
||||
unset($oldDataCompare['humidity']);
|
||||
}
|
||||
if (isset($oldDataCompare['temperature'])) {
|
||||
unset($oldDataCompare['temperature']);
|
||||
}
|
||||
if (isset($newDataCompare['humidity'])) {
|
||||
unset($newDataCompare['humidity']);
|
||||
}
|
||||
if (isset($newDataCompare['temperature'])) {
|
||||
unset($newDataCompare['temperature']);
|
||||
}
|
||||
|
||||
// Bandingkan data yang tersisa
|
||||
return json_encode($oldDataCompare) !== json_encode($newDataCompare);
|
||||
}
|
||||
|
||||
/**
|
||||
* Memeriksa apakah DHT11 data memiliki field selain yang dikecualikan
|
||||
*/
|
||||
private function hasNonTrivialDHT11Data($data)
|
||||
{
|
||||
$dataCopy = is_array($data) ? $data : [];
|
||||
|
||||
// Hapus field yang sering berubah
|
||||
if (isset($dataCopy['humidity'])) {
|
||||
unset($dataCopy['humidity']);
|
||||
}
|
||||
if (isset($dataCopy['temperature'])) {
|
||||
unset($dataCopy['temperature']);
|
||||
}
|
||||
|
||||
// Periksa apakah masih ada data lain
|
||||
return !empty($dataCopy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Memeriksa perubahan pada data device selain lastActive dan lastActiveWemos
|
||||
*/
|
||||
private function hasNonTrivialDeviceChanges($oldData, $newData)
|
||||
{
|
||||
// Buat salinan data untuk perbandingan
|
||||
$oldDataCompare = is_array($oldData) ? $oldData : [];
|
||||
$newDataCompare = is_array($newData) ? $newData : [];
|
||||
|
||||
// Hapus field yang sering berubah
|
||||
if (isset($oldDataCompare['lastActive'])) {
|
||||
unset($oldDataCompare['lastActive']);
|
||||
}
|
||||
if (isset($oldDataCompare['lastActiveWemos'])) {
|
||||
unset($oldDataCompare['lastActiveWemos']);
|
||||
}
|
||||
if (isset($newDataCompare['lastActive'])) {
|
||||
unset($newDataCompare['lastActive']);
|
||||
}
|
||||
if (isset($newDataCompare['lastActiveWemos'])) {
|
||||
unset($newDataCompare['lastActiveWemos']);
|
||||
}
|
||||
|
||||
// Bandingkan data yang tersisa
|
||||
return json_encode($oldDataCompare) !== json_encode($newDataCompare);
|
||||
}
|
||||
|
||||
/**
|
||||
* Memeriksa apakah Device data memiliki field selain yang dikecualikan
|
||||
*/
|
||||
private function hasNonTrivialDeviceData($data)
|
||||
{
|
||||
$dataCopy = is_array($data) ? $data : [];
|
||||
|
||||
// Hapus field yang sering berubah
|
||||
if (isset($dataCopy['lastActive'])) {
|
||||
unset($dataCopy['lastActive']);
|
||||
}
|
||||
if (isset($dataCopy['lastActiveWemos'])) {
|
||||
unset($dataCopy['lastActiveWemos']);
|
||||
}
|
||||
|
||||
// Periksa apakah masih ada data lain
|
||||
return !empty($dataCopy);
|
||||
}
|
||||
}
|
|
@ -15,15 +15,19 @@ class ReportUpdated implements ShouldBroadcast
|
|||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $report;
|
||||
public $changeType;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param array $report Data report
|
||||
* @param string|null $changeType Tipe perubahan (security, smartcab, dll)
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($report)
|
||||
public function __construct($report, $changeType = null)
|
||||
{
|
||||
$this->report = $report;
|
||||
$this->changeType = $changeType ?? ($report['change_type'] ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -35,4 +39,18 @@ public function broadcastOn()
|
|||
{
|
||||
return new Channel('reports');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data to broadcast.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function broadcastWith()
|
||||
{
|
||||
return [
|
||||
'report' => $this->report,
|
||||
'change_type' => $this->changeType,
|
||||
'timestamp' => now()->toIso8601String()
|
||||
];
|
||||
}
|
||||
}
|
|
@ -29,6 +29,27 @@
|
|||
50% { background-color: #d1ecf1; }
|
||||
100% { background-color: #fff; }
|
||||
}
|
||||
/* Styling untuk multiple select */
|
||||
select[multiple] {
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
select[multiple] optgroup {
|
||||
font-weight: 600;
|
||||
color: #374151;
|
||||
padding: 0.25rem 0;
|
||||
}
|
||||
|
||||
select[multiple] option {
|
||||
padding: 0.25rem 0.5rem;
|
||||
margin: 0.125rem 0;
|
||||
}
|
||||
|
||||
select[multiple] option:checked {
|
||||
background-color: #2563eb;
|
||||
color: white;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50">
|
||||
|
@ -57,43 +78,59 @@
|
|||
<ul class="space-y-2 text-sm">
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-green-500 mr-2"></span>
|
||||
<span><strong>Keamanan Normal:</strong> Sistem keamanan berjalan dengan baik</span>
|
||||
<span><strong>Fan:</strong> Perubahan pada status kipas</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-red-500 mr-2"></span>
|
||||
<span><strong>Status Bahaya:</strong> Sistem keamanan mendeteksi potensi bahaya</span>
|
||||
<span><strong>Status:</strong> Perubahan status keamanan (aman/bahaya)</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-yellow-500 mr-2"></span>
|
||||
<span><strong>Gerakan Terdeteksi:</strong> Sensor gerakan mendeteksi aktivitas</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-lime-500 mr-2"></span>
|
||||
<span><strong>Tidak Ada Gerakan:</strong> Tidak ada gerakan yang terdeteksi</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-blue-500 mr-2"></span>
|
||||
<span><strong>Servo Terkunci:</strong> Servo dalam keadaan terkunci</span>
|
||||
<span><strong>Motion:</strong> Perubahan status gerakan</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-cyan-500 mr-2"></span>
|
||||
<span><strong>Servo Terbuka:</strong> Servo dalam keadaan terbuka</span>
|
||||
<span><strong>Servo Status:</strong> Perubahan status servo (terbuka/terkunci)</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-violet-400 mr-2"></span>
|
||||
<span><strong>Akses Terakhir:</strong> Perubahan pada akses terakhir</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-purple-500 mr-2"></span>
|
||||
<span><strong>Kontrol Diubah:</strong> Terjadi perubahan pada kontrol perangkat</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-pink-500 mr-2"></span>
|
||||
<span><strong>Status Perangkat:</strong> Perubahan pada status perangkat</span>
|
||||
<span><strong>Last Access:</strong> Perubahan pada akses terakhir</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-orange-500 mr-2"></span>
|
||||
<span><strong>Error/Warning:</strong> Terdapat kesalahan atau peringatan dalam sistem</span>
|
||||
<span><strong>Restart ESP:</strong> Perangkat ESP direstart</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-amber-500 mr-2"></span>
|
||||
<span><strong>Restart Wemos:</strong> Perangkat Wemos direstart</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-indigo-500 mr-2"></span>
|
||||
<span><strong>RFID:</strong> Perubahan pada status RFID</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-lime-500 mr-2"></span>
|
||||
<span><strong>DHT:</strong> Perubahan pada sensor DHT</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-teal-500 mr-2"></span>
|
||||
<span><strong>MPU:</strong> Perubahan pada sensor MPU</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-sky-500 mr-2"></span>
|
||||
<span><strong>Servo Log:</strong> Perubahan pada log servo</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-rose-500 mr-2"></span>
|
||||
<span><strong>System ESP:</strong> Perubahan status sistem ESP</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-pink-500 mr-2"></span>
|
||||
<span><strong>System Wemos:</strong> Perubahan status sistem Wemos</span>
|
||||
</li>
|
||||
<li class="flex items-center">
|
||||
<span class="w-3 h-3 rounded-full bg-gray-500 mr-2"></span>
|
||||
<span><strong>Device Status:</strong> Perubahan status perangkat lainnya</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -169,6 +206,38 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Tambahkan ini di dalam form filter, setelah Time Range Picker -->
|
||||
<div class="md:col-span-2">
|
||||
<label for="categories" class="block mb-2 text-sm font-medium text-gray-700">Filter Kategori</label>
|
||||
<select id="categories" data-te-select-init multiple
|
||||
class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
|
||||
<optgroup label="Keamanan">
|
||||
<option value="motion">Motion</option>
|
||||
<option value="status">Status Keamanan</option>
|
||||
<option value="fan">Fan</option>
|
||||
</optgroup>
|
||||
<optgroup label="Perangkat">
|
||||
<option value="servo-status">Servo Status</option>
|
||||
<option value="last-access">Last Access</option>
|
||||
<option value="device">Device Status</option>
|
||||
</optgroup>
|
||||
<optgroup label="Kontrol">
|
||||
<option value="restart-esp">Restart ESP</option>
|
||||
<option value="restart-wemos">Restart Wemos</option>
|
||||
</optgroup>
|
||||
<optgroup label="Sensor">
|
||||
<option value="rfid">RFID</option>
|
||||
<option value="dht">DHT</option>
|
||||
<option value="mpu">MPU</option>
|
||||
</optgroup>
|
||||
<optgroup label="Log">
|
||||
<option value="servo-log">Servo Log</option>
|
||||
<option value="system-esp">System ESP</option>
|
||||
<option value="system-wemos">System Wemos</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="md:col-span-2 flex justify-end space-x-2">
|
||||
<button type="button" id="applyFilter" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5">
|
||||
Terapkan Filter
|
||||
|
@ -287,6 +356,7 @@
|
|||
const pageSize = 10; // Jumlah item per halaman
|
||||
let filteredReports = []; // Menyimpan hasil filter
|
||||
let isFilterActive = false; // Flag untuk menandai apakah filter aktif
|
||||
let selectedCategories = [];
|
||||
|
||||
// Variabel untuk menyimpan instance chart
|
||||
let systemOverviewChart = null;
|
||||
|
@ -367,89 +437,84 @@ function goToNextPage() {
|
|||
function applyFilters() {
|
||||
const filterDate = document.getElementById('filterDate').value;
|
||||
const timeFilterEnabled = document.getElementById('filterTimeToggle').checked;
|
||||
|
||||
// Simpan halaman sebelumnya
|
||||
const prevPage = currentPage;
|
||||
const categories = Array.from(document.getElementById('categories').selectedOptions).map(opt => opt.value);
|
||||
|
||||
// Set flag filter aktif
|
||||
isFilterActive = filterDate || timeFilterEnabled;
|
||||
isFilterActive = filterDate || timeFilterEnabled || categories.length > 0;
|
||||
selectedCategories = categories;
|
||||
|
||||
let startTime = null;
|
||||
let endTime = null;
|
||||
let filteredData = allReports;
|
||||
|
||||
if (timeFilterEnabled) {
|
||||
startTime = document.getElementById('startTime').value;
|
||||
endTime = document.getElementById('endTime').value;
|
||||
|
||||
// Convert to minutes for easier comparison
|
||||
const [startHour, startMinute] = startTime.split(':').map(Number);
|
||||
const [endHour, endMinute] = endTime.split(':').map(Number);
|
||||
|
||||
const startTotalMinutes = startHour * 60 + startMinute;
|
||||
const endTotalMinutes = endHour * 60 + endMinute;
|
||||
|
||||
// Filter data berdasarkan kriteria
|
||||
filteredReports = allReports.filter(report => {
|
||||
// Filter berdasarkan tanggal dan waktu
|
||||
if (filterDate || timeFilterEnabled) {
|
||||
filteredData = filteredData.filter(report => {
|
||||
const reportDate = new Date(report.timestamp);
|
||||
|
||||
// Filter berdasarkan tanggal
|
||||
// Filter tanggal
|
||||
if (filterDate) {
|
||||
const dateStr = reportDate.toISOString().split('T')[0];
|
||||
if (dateStr !== filterDate) return false;
|
||||
}
|
||||
|
||||
// Filter berdasarkan rentang waktu
|
||||
// Filter waktu
|
||||
if (timeFilterEnabled) {
|
||||
const startTime = document.getElementById('startTime').value;
|
||||
const endTime = document.getElementById('endTime').value;
|
||||
const [startHour, startMinute] = startTime.split(':').map(Number);
|
||||
const [endHour, endMinute] = endTime.split(':').map(Number);
|
||||
|
||||
const startTotalMinutes = startHour * 60 + startMinute;
|
||||
const endTotalMinutes = endHour * 60 + endMinute;
|
||||
|
||||
const hour = reportDate.getHours();
|
||||
const minute = reportDate.getMinutes();
|
||||
const totalMinutes = hour * 60 + minute;
|
||||
|
||||
// Handle case where time range crosses midnight
|
||||
if (startTotalMinutes <= endTotalMinutes) {
|
||||
// Normal case (e.g., 08:00 to 17:00)
|
||||
if (totalMinutes < startTotalMinutes || totalMinutes > endTotalMinutes) return false;
|
||||
} else {
|
||||
// Overnight case (e.g., 22:00 to 06:00)
|
||||
if (totalMinutes < startTotalMinutes && totalMinutes > endTotalMinutes) return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
} else {
|
||||
// Jika filter waktu tidak aktif, hanya filter berdasarkan tanggal
|
||||
filteredReports = allReports.filter(report => {
|
||||
const reportDate = new Date(report.timestamp);
|
||||
}
|
||||
|
||||
// Filter berdasarkan tanggal
|
||||
if (filterDate) {
|
||||
const dateStr = reportDate.toISOString().split('T')[0];
|
||||
if (dateStr !== filterDate) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
// Filter berdasarkan kategori
|
||||
if (categories.length > 0) {
|
||||
filteredData = filteredData.filter(report => {
|
||||
// Deteksi perubahan untuk report ini
|
||||
const changes = detectChanges(report, allReports, allReports.indexOf(report));
|
||||
// Cek apakah ada perubahan yang masuk dalam kategori yang dipilih
|
||||
return changes.some(change => categories.includes(change.badge));
|
||||
});
|
||||
}
|
||||
|
||||
// Reset halaman ke 1 HANYA ketika menerapkan filter baru (karena ini eksplisit pengguna memfilter)
|
||||
// Update data terfilter
|
||||
filteredReports = filteredData;
|
||||
|
||||
// Reset ke halaman pertama
|
||||
currentPage = 1;
|
||||
|
||||
// PENTING: Update chart dengan data yang sudah difilter
|
||||
// Update chart
|
||||
renderSystemOverviewChart(filteredReports);
|
||||
|
||||
// Render data yang telah difilter
|
||||
// Render data
|
||||
renderPaginatedReports(true);
|
||||
|
||||
// Tampilkan notifikasi hasil filter
|
||||
const filterCount = filteredReports.length;
|
||||
const totalCount = allReports.length;
|
||||
if (filterCount === 0) {
|
||||
showFilterNotification(`Tidak ada data yang cocok dengan filter`);
|
||||
} else {
|
||||
showFilterNotification(`Ditemukan ${filterCount} dari ${totalCount} data`);
|
||||
|
||||
let filterMessage = `Ditemukan ${filterCount} dari ${totalCount} data`;
|
||||
if (categories.length > 0) {
|
||||
filterMessage += ` dengan kategori: ${categories.join(', ')}`;
|
||||
}
|
||||
|
||||
// Tambahkan badge untuk menampilkan status filter pada chart
|
||||
showFilterNotification(filterCount === 0 ? 'Tidak ada data yang cocok dengan filter' : filterMessage);
|
||||
|
||||
// Update status filter pada chart
|
||||
updateChartFilterStatus();
|
||||
}
|
||||
|
||||
|
@ -481,6 +546,8 @@ function resetFilters() {
|
|||
document.getElementById('filterTimeToggle').checked = false;
|
||||
document.getElementById('timeRangePicker').classList.add('hidden');
|
||||
document.getElementById('timeToggleStatus').textContent = 'Semua Waktu';
|
||||
document.getElementById('categories').selectedIndex = -1; // Reset multiple select
|
||||
selectedCategories = [];
|
||||
|
||||
// Reset flag filter
|
||||
isFilterActive = false;
|
||||
|
@ -489,7 +556,7 @@ function resetFilters() {
|
|||
filteredReports = allReports;
|
||||
currentPage = 1;
|
||||
|
||||
// PENTING: Update chart dengan semua data
|
||||
// Update chart dengan semua data
|
||||
renderSystemOverviewChart(allReports);
|
||||
|
||||
// Update chart filter status
|
||||
|
@ -745,15 +812,25 @@ function renderReports(reports) {
|
|||
const changes = detectChanges(report, allReports, allReports.indexOf(report));
|
||||
changes.forEach(change => {
|
||||
const badge = document.createElement('span');
|
||||
// Flowbite badge styles
|
||||
|
||||
// Flowbite badge styles dengan warna khusus untuk setiap jenis
|
||||
const badgeClasses = {
|
||||
'primary': 'bg-blue-100 text-blue-800',
|
||||
'secondary': 'bg-gray-100 text-gray-800',
|
||||
'danger': 'bg-red-100 text-red-800',
|
||||
'warning': 'bg-yellow-100 text-yellow-800',
|
||||
'info': 'bg-indigo-100 text-indigo-800',
|
||||
'light': 'bg-gray-100 text-gray-800',
|
||||
'dark': 'bg-gray-700 text-gray-300'
|
||||
'motion': 'bg-yellow-100 text-yellow-800',
|
||||
'status': 'bg-red-100 text-red-800',
|
||||
'fan': 'bg-green-100 text-green-800',
|
||||
'last-access': 'bg-violet-100 text-violet-800',
|
||||
'servo-status': 'bg-cyan-100 text-cyan-800',
|
||||
'restart-esp': 'bg-orange-100 text-orange-800',
|
||||
'restart-wemos': 'bg-amber-100 text-amber-800',
|
||||
'rfid': 'bg-indigo-100 text-indigo-800',
|
||||
'dht': 'bg-lime-100 text-lime-800',
|
||||
'mpu': 'bg-teal-100 text-teal-800',
|
||||
'servo-log': 'bg-sky-100 text-sky-800',
|
||||
'system-esp': 'bg-rose-100 text-rose-800',
|
||||
'system-wemos': 'bg-pink-100 text-pink-800',
|
||||
'device': 'bg-gray-100 text-gray-800',
|
||||
'light': 'bg-gray-100 text-gray-400'
|
||||
};
|
||||
|
||||
badge.className = `px-2 py-0.5 rounded text-xs font-medium me-2 ${badgeClasses[change.badge] || badgeClasses['light']}`;
|
||||
|
@ -810,41 +887,81 @@ function detectChanges(report, reports, index) {
|
|||
// Security changes
|
||||
if (report.security && prevReport.security) {
|
||||
if (report.security.motion !== prevReport.security.motion) {
|
||||
changes.push({ type: 'Gerakan', badge: 'danger' });
|
||||
changes.push({ type: 'Motion', badge: 'motion' });
|
||||
}
|
||||
|
||||
if (report.security.status !== prevReport.security.status) {
|
||||
changes.push({ type: 'Status Keamanan', badge: 'danger' });
|
||||
changes.push({ type: 'Status', badge: 'status' });
|
||||
}
|
||||
|
||||
if (report.security.fan !== prevReport.security.fan) {
|
||||
changes.push({ type: 'Fan', badge: 'fan' });
|
||||
}
|
||||
}
|
||||
|
||||
// Smartcab changes
|
||||
if (report.smartcab && prevReport.smartcab) {
|
||||
if (report.smartcab.last_access !== prevReport.smartcab.last_access) {
|
||||
changes.push({ type: 'Akses Terakhir', badge: 'info' });
|
||||
changes.push({ type: 'Last Access', badge: 'last-access' });
|
||||
}
|
||||
|
||||
if (report.smartcab.servo_status !== prevReport.smartcab.servo_status) {
|
||||
changes.push({ type: 'Status Servo', badge: 'warning' });
|
||||
changes.push({ type: 'Servo Status', badge: 'servo-status' });
|
||||
}
|
||||
}
|
||||
|
||||
// Control changes
|
||||
if (report.control && prevReport.control &&
|
||||
JSON.stringify(report.control) !== JSON.stringify(prevReport.control)) {
|
||||
changes.push({ type: 'Kontrol Perangkat', badge: 'secondary' });
|
||||
}
|
||||
if (report.control && prevReport.control) {
|
||||
if (report.control.restartESP !== prevReport.control.restartESP) {
|
||||
changes.push({ type: 'Restart ESP', badge: 'restart-esp' });
|
||||
}
|
||||
|
||||
// Device changes
|
||||
if (report.device && prevReport.device &&
|
||||
JSON.stringify(report.device) !== JSON.stringify(prevReport.device)) {
|
||||
changes.push({ type: 'Status Perangkat', badge: 'secondary' });
|
||||
if (report.control.restartWemos !== prevReport.control.restartWemos) {
|
||||
changes.push({ type: 'Restart Wemos', badge: 'restart-wemos' });
|
||||
}
|
||||
}
|
||||
|
||||
// Logs changes
|
||||
if (report.logs && prevReport.logs &&
|
||||
JSON.stringify(report.logs) !== JSON.stringify(prevReport.logs)) {
|
||||
changes.push({ type: 'Log Sistem', badge: 'dark' });
|
||||
if (report.logs && prevReport.logs) {
|
||||
// RFID logs
|
||||
if (report.logs.RFID && prevReport.logs.RFID &&
|
||||
JSON.stringify(report.logs.RFID) !== JSON.stringify(prevReport.logs.RFID)) {
|
||||
changes.push({ type: 'RFID', badge: 'rfid' });
|
||||
}
|
||||
|
||||
// DHT logs
|
||||
if (report.logs.dht && prevReport.logs.dht &&
|
||||
JSON.stringify(report.logs.dht) !== JSON.stringify(prevReport.logs.dht)) {
|
||||
changes.push({ type: 'DHT', badge: 'dht' });
|
||||
}
|
||||
|
||||
// MPU logs
|
||||
if (report.logs.mpu && prevReport.logs.mpu &&
|
||||
JSON.stringify(report.logs.mpu) !== JSON.stringify(prevReport.logs.mpu)) {
|
||||
changes.push({ type: 'MPU', badge: 'mpu' });
|
||||
}
|
||||
|
||||
// Servo logs
|
||||
if (report.logs.servo && prevReport.logs.servo &&
|
||||
JSON.stringify(report.logs.servo) !== JSON.stringify(prevReport.logs.servo)) {
|
||||
changes.push({ type: 'Servo Log', badge: 'servo-log' });
|
||||
}
|
||||
|
||||
// System ESP logs
|
||||
if (report.logs.systemESP !== prevReport.logs.systemESP) {
|
||||
changes.push({ type: 'System ESP', badge: 'system-esp' });
|
||||
}
|
||||
|
||||
// System Wemos logs
|
||||
if (report.logs.systemWemos !== prevReport.logs.systemWemos) {
|
||||
changes.push({ type: 'System Wemos', badge: 'system-wemos' });
|
||||
}
|
||||
}
|
||||
|
||||
// Device changes - general fallback if needed
|
||||
if (report.device && prevReport.device &&
|
||||
JSON.stringify(report.device) !== JSON.stringify(prevReport.device)) {
|
||||
changes.push({ type: 'Device Status', badge: 'device' });
|
||||
}
|
||||
|
||||
if (changes.length === 0) {
|
||||
|
@ -1039,145 +1156,186 @@ function showDetail(report) {
|
|||
function analyzeSystemOverview(reports) {
|
||||
// Siapkan variabel untuk menyimpan hitungan status
|
||||
const statusCounts = {
|
||||
'securityNormal': 0, // Status keamanan normal
|
||||
'securityDanger': 0, // Status keamanan bahaya
|
||||
'motionDetected': 0, // Gerakan terdeteksi
|
||||
'motionNotDetected': 0, // Gerakan tidak terdeteksi
|
||||
'servoLocked': 0, // Servo terkunci
|
||||
'servoUnlocked': 0, // Servo terbuka
|
||||
'accessChanged': 0, // Perubahan akses terakhir
|
||||
'controlChanged': 0, // Perubahan kontrol perangkat
|
||||
'deviceChanged': 0, // Perubahan status perangkat
|
||||
'logError': 0 // Log error
|
||||
'motion': 0, // Motion status
|
||||
'status': 0, // Security status
|
||||
'fan': 0, // Fan status
|
||||
'servoStatus': 0, // Servo status
|
||||
'lastAccess': 0, // Last access
|
||||
'restartEsp': 0, // Restart ESP
|
||||
'restartWemos': 0, // Restart Wemos
|
||||
'rfid': 0, // RFID
|
||||
'dht': 0, // DHT sensor
|
||||
'mpu': 0, // MPU sensor
|
||||
'servoLog': 0, // Servo log
|
||||
'systemEsp': 0, // System ESP
|
||||
'systemWemos': 0, // System Wemos
|
||||
'deviceStatus': 0 // Device status
|
||||
};
|
||||
|
||||
// Total untuk persentase dan statusCounts
|
||||
// Total untuk persentase
|
||||
let totalCounts = 0;
|
||||
|
||||
// Fungsi untuk menghitung perubahan antar report
|
||||
function countChanges(report, index) {
|
||||
if (index === 0 || index >= reports.length - 1) return [];
|
||||
|
||||
const changes = [];
|
||||
const prevReport = reports[index + 1]; // Data baris sebelumnya (karena data sorted terbaru dulu)
|
||||
|
||||
// Security changes
|
||||
if (report.security && prevReport.security) {
|
||||
if (report.security.motion !== prevReport.security.motion) {
|
||||
changes.push('motion');
|
||||
}
|
||||
|
||||
if (report.security.status !== prevReport.security.status) {
|
||||
changes.push('status');
|
||||
}
|
||||
|
||||
if (report.security.fan !== prevReport.security.fan) {
|
||||
changes.push('fan');
|
||||
}
|
||||
}
|
||||
|
||||
// Smartcab changes
|
||||
if (report.smartcab && prevReport.smartcab) {
|
||||
if (report.smartcab.last_access !== prevReport.smartcab.last_access) {
|
||||
changes.push('lastAccess');
|
||||
}
|
||||
|
||||
if (report.smartcab.servo_status !== prevReport.smartcab.servo_status) {
|
||||
changes.push('servoStatus');
|
||||
}
|
||||
}
|
||||
|
||||
// Control changes
|
||||
if (report.control && prevReport.control) {
|
||||
if (report.control.restartESP !== prevReport.control.restartESP) {
|
||||
changes.push('restartEsp');
|
||||
}
|
||||
|
||||
if (report.control.restartWemos !== prevReport.control.restartWemos) {
|
||||
changes.push('restartWemos');
|
||||
}
|
||||
}
|
||||
|
||||
// Logs changes
|
||||
if (report.logs && prevReport.logs) {
|
||||
// RFID logs
|
||||
if (report.logs.RFID && prevReport.logs.RFID &&
|
||||
JSON.stringify(report.logs.RFID) !== JSON.stringify(prevReport.logs.RFID)) {
|
||||
changes.push('rfid');
|
||||
}
|
||||
|
||||
// DHT logs
|
||||
if (report.logs.dht && prevReport.logs.dht &&
|
||||
JSON.stringify(report.logs.dht) !== JSON.stringify(prevReport.logs.dht)) {
|
||||
changes.push('dht');
|
||||
}
|
||||
|
||||
// MPU logs
|
||||
if (report.logs.mpu && prevReport.logs.mpu &&
|
||||
JSON.stringify(report.logs.mpu) !== JSON.stringify(prevReport.logs.mpu)) {
|
||||
changes.push('mpu');
|
||||
}
|
||||
|
||||
// Servo logs
|
||||
if (report.logs.servo && prevReport.logs.servo &&
|
||||
JSON.stringify(report.logs.servo) !== JSON.stringify(prevReport.logs.servo)) {
|
||||
changes.push('servoLog');
|
||||
}
|
||||
|
||||
// System ESP logs
|
||||
if (report.logs.systemESP !== prevReport.logs.systemESP) {
|
||||
changes.push('systemEsp');
|
||||
}
|
||||
|
||||
// System Wemos logs
|
||||
if (report.logs.systemWemos !== prevReport.logs.systemWemos) {
|
||||
changes.push('systemWemos');
|
||||
}
|
||||
}
|
||||
|
||||
// Device changes - general fallback if needed
|
||||
if (report.device && prevReport.device &&
|
||||
JSON.stringify(report.device) !== JSON.stringify(prevReport.device)) {
|
||||
changes.push('deviceStatus');
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
// Periksa setiap laporan untuk mengisi kategori
|
||||
reports.forEach(report => {
|
||||
let categoriesAdded = 0;
|
||||
reports.forEach((report, index) => {
|
||||
const changes = countChanges(report, index);
|
||||
|
||||
// Cek status keamanan
|
||||
if (report.security) {
|
||||
if (report.security.status) {
|
||||
if (report.security.status.toLowerCase() === 'bahaya') {
|
||||
statusCounts['securityDanger']++;
|
||||
categoriesAdded++;
|
||||
} else if (report.security.status.toLowerCase() === 'aman') {
|
||||
statusCounts['securityNormal']++;
|
||||
categoriesAdded++;
|
||||
}
|
||||
}
|
||||
changes.forEach(change => {
|
||||
statusCounts[change]++;
|
||||
totalCounts++;
|
||||
});
|
||||
|
||||
if (report.security.motion) {
|
||||
if (report.security.motion.toLowerCase() === 'detected') {
|
||||
statusCounts['motionDetected']++;
|
||||
categoriesAdded++;
|
||||
} else if (report.security.motion.toLowerCase() === 'not detected') {
|
||||
statusCounts['motionNotDetected']++;
|
||||
categoriesAdded++;
|
||||
}
|
||||
}
|
||||
// Jika tidak ada perubahan, tambahkan satu ke total untuk report ini
|
||||
if (changes.length === 0 && index > 0 && index < reports.length - 1) {
|
||||
totalCounts++;
|
||||
}
|
||||
|
||||
// Cek status smartcab
|
||||
if (report.smartcab) {
|
||||
if (report.smartcab.servo_status) {
|
||||
if (report.smartcab.servo_status.toLowerCase() === 'locked') {
|
||||
statusCounts['servoLocked']++;
|
||||
categoriesAdded++;
|
||||
} else if (report.smartcab.servo_status.toLowerCase() === 'unlocked') {
|
||||
statusCounts['servoUnlocked']++;
|
||||
categoriesAdded++;
|
||||
}
|
||||
}
|
||||
|
||||
if (report.smartcab.last_access) {
|
||||
statusCounts['accessChanged']++;
|
||||
categoriesAdded++;
|
||||
}
|
||||
}
|
||||
|
||||
// Cek perubahan kontrol
|
||||
if (report.control && Object.keys(report.control).length > 0) {
|
||||
statusCounts['controlChanged']++;
|
||||
categoriesAdded++;
|
||||
}
|
||||
|
||||
// Cek perubahan device
|
||||
if (report.device && Object.keys(report.device).length > 0) {
|
||||
statusCounts['deviceChanged']++;
|
||||
categoriesAdded++;
|
||||
}
|
||||
|
||||
// Cek logs untuk error
|
||||
if (report.logs) {
|
||||
let hasError = false;
|
||||
for (const logKey in report.logs) {
|
||||
if (report.logs[logKey] && report.logs[logKey].status) {
|
||||
const status = report.logs[logKey].status.toLowerCase();
|
||||
if (status.includes('error') || status.includes('warning')) {
|
||||
hasError = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasError) {
|
||||
statusCounts['logError']++;
|
||||
categoriesAdded++;
|
||||
}
|
||||
}
|
||||
|
||||
// Tambahkan jumlah kategori ke total
|
||||
totalCounts += categoriesAdded > 0 ? categoriesAdded : 1;
|
||||
});
|
||||
|
||||
// Update counter
|
||||
document.getElementById('system-chart-count').textContent =
|
||||
`Total: ${reports.length} laporan dengan ${totalCounts} status`;
|
||||
`Total: ${reports.length} laporan dengan ${totalCounts} perubahan status`;
|
||||
|
||||
// Kembalikan array untuk chart dengan hanya nilai yang bukan nol
|
||||
const resultData = [
|
||||
statusCounts['securityNormal'],
|
||||
statusCounts['securityDanger'],
|
||||
statusCounts['motionDetected'],
|
||||
statusCounts['motionNotDetected'],
|
||||
statusCounts['servoLocked'],
|
||||
statusCounts['servoUnlocked'],
|
||||
statusCounts['accessChanged'],
|
||||
statusCounts['controlChanged'],
|
||||
statusCounts['deviceChanged'],
|
||||
statusCounts['logError']
|
||||
statusCounts['fan'],
|
||||
statusCounts['status'],
|
||||
statusCounts['motion'],
|
||||
statusCounts['servoStatus'],
|
||||
statusCounts['lastAccess'],
|
||||
statusCounts['restartEsp'],
|
||||
statusCounts['restartWemos'],
|
||||
statusCounts['rfid'],
|
||||
statusCounts['dht'],
|
||||
statusCounts['mpu'],
|
||||
statusCounts['servoLog'],
|
||||
statusCounts['systemEsp'],
|
||||
statusCounts['systemWemos'],
|
||||
statusCounts['deviceStatus']
|
||||
];
|
||||
|
||||
// Label yang sesuai dengan resultData
|
||||
const resultLabels = [
|
||||
'Keamanan Normal',
|
||||
'Status Bahaya',
|
||||
'Gerakan Terdeteksi',
|
||||
'Tidak Ada Gerakan',
|
||||
'Servo Terkunci',
|
||||
'Servo Terbuka',
|
||||
'Akses Terakhir',
|
||||
'Kontrol Diubah',
|
||||
'Status Perangkat',
|
||||
'Error/Warning'
|
||||
'Fan',
|
||||
'Status Keamanan',
|
||||
'Motion',
|
||||
'Servo Status',
|
||||
'Last Access',
|
||||
'Restart ESP',
|
||||
'Restart Wemos',
|
||||
'RFID',
|
||||
'DHT',
|
||||
'MPU',
|
||||
'Servo Log',
|
||||
'System ESP',
|
||||
'System Wemos',
|
||||
'Device Status'
|
||||
];
|
||||
|
||||
// Warna yang sesuai dengan resultData
|
||||
// Warna yang sesuai dengan resultData (sesuai dengan badge colors)
|
||||
const resultColors = [
|
||||
'#22c55e', // Keamanan Normal (Hijau)
|
||||
'#ef4444', // Status Bahaya (Merah)
|
||||
'#eab308', // Gerakan Terdeteksi (Kuning)
|
||||
'#84cc16', // Tidak Ada Gerakan (Hijau Muda)
|
||||
'#3b82f6', // Servo Terkunci (Biru)
|
||||
'#06b6d4', // Servo Terbuka (Cyan)
|
||||
'#8b5cf6', // Akses Terakhir (Ungu Muda)
|
||||
'#a855f7', // Kontrol Diubah (Ungu)
|
||||
'#ec4899', // Status Perangkat (Pink)
|
||||
'#f97316' // Error/Warning (Oranye)
|
||||
'#22c55e', // Fan (Hijau)
|
||||
'#ef4444', // Status (Merah)
|
||||
'#eab308', // Motion (Kuning)
|
||||
'#06b6d4', // Servo Status (Cyan)
|
||||
'#8b5cf6', // Last Access (Ungu Muda)
|
||||
'#f97316', // Restart ESP (Oranye)
|
||||
'#f59e0b', // Restart Wemos (Amber)
|
||||
'#6366f1', // RFID (Indigo)
|
||||
'#84cc16', // DHT (Lime)
|
||||
'#14b8a6', // MPU (Teal)
|
||||
'#0ea5e9', // Servo Log (Sky)
|
||||
'#e11d48', // System ESP (Rose)
|
||||
'#ec4899', // System Wemos (Pink)
|
||||
'#6b7280' // Device Status (Gray)
|
||||
];
|
||||
|
||||
// Filter untuk menghilangkan kategori dengan nilai nol
|
||||
|
@ -1298,32 +1456,36 @@ function updateChartFilterStatus() {
|
|||
const filterDate = document.getElementById('filterDate').value;
|
||||
const timeFilterEnabled = document.getElementById('filterTimeToggle').checked;
|
||||
|
||||
let filterInfo = '';
|
||||
let filterInfo = [];
|
||||
|
||||
if (filterDate) {
|
||||
const formattedDate = new Date(filterDate).toLocaleDateString('id-ID', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric'
|
||||
});
|
||||
filterInfo += `Tanggal: ${formattedDate}`;
|
||||
filterInfo.push(`Tanggal: ${formattedDate}`);
|
||||
}
|
||||
|
||||
if (timeFilterEnabled) {
|
||||
const startTime = document.getElementById('startTime').value;
|
||||
const endTime = document.getElementById('endTime').value;
|
||||
if (filterInfo) filterInfo += ' | ';
|
||||
filterInfo += `Waktu: ${startTime} - ${endTime}`;
|
||||
filterInfo.push(`Waktu: ${startTime} - ${endTime}`);
|
||||
}
|
||||
|
||||
if (selectedCategories.length > 0) {
|
||||
filterInfo.push(`Kategori: ${selectedCategories.join(', ')}`);
|
||||
}
|
||||
|
||||
// Update text pada chart count
|
||||
if (filterInfo) {
|
||||
if (filterInfo.length > 0) {
|
||||
chartCountElement.innerHTML = `
|
||||
<span class="font-medium">Data Terfilter:</span> ${filteredReports.length} dari ${allReports.length}
|
||||
`;
|
||||
|
||||
// Tampilkan badge filter
|
||||
chartFilterBadge.classList.remove('hidden');
|
||||
chartFilterText.textContent = filterInfo;
|
||||
chartFilterText.textContent = filterInfo.join(' | ');
|
||||
} else {
|
||||
chartCountElement.textContent = `Total: ${allReports.length} laporan dengan ${analyzeSystemOverview(allReports).series.reduce((a, b) => a + b, 0)} status`;
|
||||
|
||||
|
|
Loading…
Reference in New Issue