From 734bc685f3cd0878d0a42cfe37ecd6b2903ec573 Mon Sep 17 00:00:00 2001 From: rendygaafk Date: Mon, 5 May 2025 18:41:38 +0700 Subject: [PATCH] fix controller,model,migrate,views pengumuman and fix tampilan ruangan,kelas,jurusan fix tampilan pengumuman --- .../Controllers/AnnouncementController.php | 429 +++----- .../Requests/StoreAnnouncementRequest.php | 31 + app/Models/Announcement.php | 112 +- app/Models/Ruangan.php | 21 +- ...2025_04_21_051528_create_ruangan_table.php | 3 +- ...4_22_135609_create_announcements_table.php | 24 +- resources/css/app.css | 12 + .../admin/announcement/history.blade.php | 410 ++++---- .../views/admin/announcement/index.blade.php | 976 +++++++++--------- .../views/admin/announcement/show.blade.php | 80 -- resources/views/admin/jurusan/index.blade.php | 21 - resources/views/admin/kelas/index.blade.php | 30 - resources/views/admin/ruangan/index.blade.php | 33 +- routes/web.php | 9 + 14 files changed, 923 insertions(+), 1268 deletions(-) create mode 100644 app/Http/Requests/StoreAnnouncementRequest.php delete mode 100644 resources/views/admin/announcement/show.blade.php diff --git a/app/Http/Controllers/AnnouncementController.php b/app/Http/Controllers/AnnouncementController.php index d4628c9..3e8c549 100644 --- a/app/Http/Controllers/AnnouncementController.php +++ b/app/Http/Controllers/AnnouncementController.php @@ -4,353 +4,158 @@ use App\Models\Announcement; use App\Models\Ruangan; -use App\Services\MqttService; +use App\Http\Requests\StoreAnnouncementRequest; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Log; -use Illuminate\Support\Facades\Http; -use Illuminate\Support\Facades\Validator; -use Illuminate\Support\Facades\Storage; -use Carbon\Carbon; +use PhpMqtt\Client\Facades\MQTT; class AnnouncementController extends Controller { - // Mode constants - const MODE_REGULER = 'reguler'; - const MODE_TTS = 'tts'; - - // Relay constants - const RELAY_ON = 'ON'; - const RELAY_OFF = 'OFF'; - - // TTS API constants - const TTS_API_URL = 'http://api.voicerss.org/'; - const TTS_API_KEY = '90927de8275148d79080facd20fb486c'; - const TTS_DEFAULT_VOICE = 'id-id'; - const TTS_DEFAULT_SPEED = 0; - const TTS_DEFAULT_FORMAT = 'wav'; - - protected $mqttService; - protected $mqttConfig; - - public function __construct(MqttService $mqttService) - { - $this->mqttService = $mqttService; - $this->mqttConfig = config('mqtt'); - $this->initializeMqttSubscriptions(); - } - - protected function initializeMqttSubscriptions() - { - try { - $this->mqttService->subscribe( - $this->mqttConfig['topics']['responses']['announcement_ack'], - function (string $topic, string $message) { - $this->handleAnnouncementAck($message); - } - ); - - $this->mqttService->subscribe( - $this->mqttConfig['topics']['responses']['announcement_error'], - function (string $topic, string $message) { - $this->handleAnnouncementError($message); - } - ); - - $this->mqttService->subscribe( - $this->mqttConfig['topics']['responses']['relay_status'], - function (string $topic, string $message) { - $this->handleRelayStatusUpdate($message); - } - ); - } catch (\Exception $e) { - Log::error('MQTT Subscription Error: ' . $e->getMessage()); - } - } - public function index() { - $ruangan = Ruangan::with(['kelas', 'jurusan'])->get(); - $announcements = Announcement::with(['ruangans']) - ->latest() - ->paginate(10); - - try { - $mqttStatus = $this->mqttService->isConnected() ? 'Connected' : 'Disconnected'; - } catch (\Exception $e) { - $mqttStatus = 'Disconnected'; - Log::error('MQTT check failed: ' . $e->getMessage()); - } - - return view('admin.announcement.index', [ - 'ruangans' => $ruangan, - 'announcements' => $announcements, - 'modes' => [self::MODE_REGULER, self::MODE_TTS], - 'relayStates' => [self::RELAY_ON, self::RELAY_OFF], - 'mqttStatus' => $mqttStatus - ]); - } - - public function store(Request $request) - { - $validator = Validator::make($request->all(), [ - 'mode' => 'required|in:reguler,tts', - 'ruangans' => 'required|array', - 'ruangans.*' => 'exists:ruangan,id', - 'relay_action' => 'required_if:mode,reguler|in:ON,OFF', - 'tts_text' => 'required_if:mode,tts|string|max:1000', - 'tts_voice' => 'required_if:mode,tts', - 'tts_speed' => 'required_if:mode,tts|integer|min:-10|max:10', - ]); - - if ($validator->fails()) { - return redirect()->back() - ->withErrors($validator) - ->withInput(); - } - - try { - $announcement = new Announcement(); - $announcement->mode = $request->mode; - - if ($request->mode === self::MODE_REGULER) { - $announcement->message = $request->relay_action === self::RELAY_ON - ? 'Aktivasi Relay Ruangan' - : 'Deaktivasi Relay Ruangan'; - $announcement->is_active = $request->relay_action === self::RELAY_ON; - $announcement->relay_state = $request->relay_action; - } else { - $audioContent = $this->generateTTS( - $request->tts_text, - $request->tts_voice, - $request->tts_speed - ); - - if (!$audioContent) { - throw new \Exception('Failed to generate TTS audio'); - } - - $fileName = 'tts/' . now()->format('YmdHis') . '.wav'; - Storage::disk('public')->put($fileName, $audioContent); - - $announcement->message = $request->tts_text; - $announcement->audio_path = $fileName; - $announcement->voice = $request->tts_voice; - $announcement->speed = $request->tts_speed; - $announcement->relay_state = self::RELAY_OFF; // Default untuk TTS - } - - $announcement->sent_at = now(); - $announcement->status = 'pending'; - - if (!$announcement->save()) { - throw new \Exception('Failed to save announcement'); - } - - $existingRuangan = Ruangan::whereIn('id', $request->ruangans)->pluck('id'); - if ($existingRuangan->count() != count($request->ruangans)) { - throw new \Exception('Some selected ruangan not found'); - } - - $announcement->ruangans()->sync($existingRuangan); - - $this->publishAnnouncement($announcement); - - return redirect()->route('announcement.index') - ->with('success', 'Pengumuman berhasil dikirim'); - - } catch (\Exception $e) { - Log::error('Announcement Error: ' . $e->getMessage()); - if (isset($announcement) && $announcement->exists) { - $announcement->delete(); - } - return redirect()->back() - ->with('error', 'Gagal: ' . $e->getMessage()) - ->withInput(); - } - } - - protected function publishAnnouncement(Announcement $announcement) - { - $payload = [ - 'mode' => $announcement->mode, - 'announcement_id' => $announcement->id, - 'ruangans' => $announcement->ruangans->pluck('nama_ruangan')->toArray(), - 'timestamp' => now()->toDateTimeString() - ]; - - if ($announcement->mode === self::MODE_REGULER) { - $payload['relay_state'] = $announcement->relay_state; - - // Kirim perintah relay ke masing-masing ruangan - foreach ($announcement->ruangans as $ruangan) { - $topic = $ruangan->mqtt_topic ?? "ruangan/{$ruangan->id}/relay/control"; - - $this->mqttService->publish( - $topic, - json_encode([ - 'state' => $announcement->relay_state, - 'announcement_id' => $announcement->id - ]), - 1 // QoS level - ); - - // Update status relay di database - $ruangan->update(['relay_state' => $announcement->relay_state]); - } - } else { - $payload['message'] = $announcement->message; - $payload['audio_url'] = asset('storage/' . $announcement->audio_path); - $payload['voice'] = $announcement->voice; - $payload['speed'] = $announcement->speed; - } - - // Publis ke topic announcement umum - $this->mqttService->publish( - $this->mqttConfig['topics']['commands']['announcement'], - json_encode($payload), - 1 - ); - } - - protected function generateTTS($text, $voice, $speed) - { - $response = Http::get(self::TTS_API_URL, [ - 'key' => self::TTS_API_KEY, - 'hl' => $voice, - 'src' => $text, - 'r' => $speed, - 'c' => self::TTS_DEFAULT_FORMAT, - 'f' => '8khz_8bit_mono' - ]); - - if ($response->successful()) { - return $response->body(); - } - - Log::error('TTS API Error: ' . $response->body()); - return null; - } - - protected function handleAnnouncementAck(string $message) - { - try { - $data = json_decode($message, true); - - if (isset($data['announcement_id'])) { - Announcement::where('id', $data['announcement_id']) - ->update(['status' => 'delivered']); - - Log::info('Announcement delivered', $data); - } - } catch (\Exception $e) { - Log::error('ACK Handler Error: ' . $e->getMessage()); - } + $ruangans = Ruangan::orderBy('nama_ruangan')->get(); + $mqttStatus = $this->checkMqttConnection(); + return view('admin.announcement.index', compact('ruangans', 'mqttStatus')); } - protected function handleAnnouncementError(string $message) + public function history() + { + $announcements = Announcement::with('ruangans') + ->when(request('mode'), function($query, $mode) { + return $query->where('mode', $mode); + }) + ->when(request('date'), function($query, $date) { + return $query->whereDate('sent_at', $date); + }) + ->orderBy('sent_at', 'desc') + ->paginate(10); + + return view('admin.announcement.history', compact('announcements')); + } + + private function checkMqttConnection() { try { - $data = json_decode($message, true); - - if (isset($data['announcement_id'])) { - Announcement::where('id', $data['announcement_id']) - ->update([ - 'status' => 'failed', - 'error_message' => $data['error'] ?? 'Unknown error' - ]); - - Log::error('Announcement failed', $data); - } + $mqtt = MQTT::connection(); + return $mqtt->isConnected(); } catch (\Exception $e) { - Log::error('Error Handler Error: ' . $e->getMessage()); + return false; } } - protected function handleRelayStatusUpdate(string $message) + public function store(StoreAnnouncementRequest $request) { + $announcementData = [ + 'mode' => $request->mode, + 'sent_at' => now(), + ]; + + // Hanya tambahkan message jika mode TTS + if ($request->mode === 'tts') { + $announcementData['message'] = $request->message; + } + + $announcement = Announcement::create($announcementData); + $announcement->ruangans()->sync($request->ruangans); + try { - $data = json_decode($message, true); - - if (isset($data['ruangan_id'], $data['state'])) { - Ruangan::where('id', $data['ruangan_id']) - ->update(['relay_state' => $data['state']]); - - Log::info('Relay status updated', $data); + if ($request->mode === 'tts') { + MQTT::publish('control/relay', json_encode([ + 'mode' => 'tts', + 'ruang' => $request->ruangans + ])); + + MQTT::publish('tts/play', json_encode([ + 'ruang' => $request->ruangans, + 'teks' => $request->message + ])); + } else { + MQTT::publish('control/relay', json_encode([ + 'mode' => 'reguler', + 'ruang' => $request->ruangans + ])); } } catch (\Exception $e) { - Log::error('Relay Status Handler Error: ' . $e->getMessage()); + return response()->json([ + 'message' => 'Gagal mengirim ke perangkat: ' . $e->getMessage() + ], 500); } + + return response()->json(['success' => true]); } - public function ttsPreview(Request $request) + public function details($id) { - $validator = Validator::make($request->all(), [ - 'text' => 'required|string|max:1000', - 'voice' => 'required|string', - 'speed' => 'required|integer|min:-10|max:10' + $announcement = Announcement::with('ruangans')->findOrFail($id); + return response()->json([ + 'mode' => $announcement->mode, + 'formatted_sent_at' => $announcement->formatted_sent_at, + 'message' => $announcement->message, + 'ruangans' => $announcement->ruangans->map(function($ruangan) { + return ['nama_ruangan' => $ruangan->nama_ruangan]; + }) + ]); + } + + public function destroy($id) + { + $announcement = Announcement::findOrFail($id); + $announcement->delete(); + return response()->json(['success' => true]); + } + + public function checkMqtt() + { + return response()->json([ + 'connected' => $this->checkMqttConnection() + ]); + } + + public function controlRelay(Request $request) + { + $request->validate([ + 'ruangans' => 'required|array|min:1', + 'ruangans.*' => 'exists:ruangan,id', + 'action' => 'required|in:activate,deactivate', + 'mode' => 'required|in:manual,tts' ]); - if ($validator->fails()) { - return response()->json([ - 'error' => $validator->errors()->first() - ], 400); - } + $ruangans = Ruangan::whereIn('id', $request->ruangans)->get(); + $state = $request->action === 'activate' ? 'on' : 'off'; try { - $audioContent = $this->generateTTS( - $request->text, - $request->voice, - $request->speed - ); + // Kirim perintah ke ESP32 via MQTT + MQTT::publish('control/relay', json_encode([ + 'action' => $request->action, + 'ruang' => $request->ruangans, + 'mode' => $request->mode + ])); - if (!$audioContent) { - throw new \Exception('Failed to generate TTS audio'); + // Update status relay di database + Ruangan::whereIn('id', $request->ruangans)->update(['relay_state' => $state]); + + // Jika mengaktifkan relay, simpan sebagai pengumuman manual + if ($request->action === 'activate' && $request->mode === 'manual') { + $announcement = Announcement::create([ + 'mode' => 'manual', + 'message' => 'Pengumuman via microphone manual', + 'sent_at' => now() + ]); + + $announcement->ruangans()->sync($request->ruangans); } - $fileName = 'tts/previews/' . uniqid() . '.wav'; - Storage::disk('public')->put($fileName, $audioContent); - - return response()->json([ - 'audio_url' => asset('storage/' . $fileName) - ]); + return response()->json(['success' => true]); } catch (\Exception $e) { - Log::error('TTS Preview Error: ' . $e->getMessage()); return response()->json([ - 'error' => 'Failed to generate preview' + 'message' => 'Gagal mengontrol relay: ' . $e->getMessage() ], 500); } } - - public function history(Request $request) + + public function relayStatus() { - $search = $request->input('search'); - $mode = $request->input('mode'); - $relayState = $request->input('relay_state'); - - $announcements = Announcement::with(['ruangans']) - ->when($search, function($query) use ($search) { - return $query->where('message', 'like', "%{$search}%") - ->orWhereHas('ruangans', function($q) use ($search) { - $q->where('nama_ruangan', 'like', "%{$search}%"); - }); - }) - ->when($mode, function($query) use ($mode) { - return $query->where('mode', $mode); - }) - ->when($relayState, function($query) use ($relayState) { - return $query->where('relay_state', $relayState); - }) - ->latest() - ->paginate(10); - - return view('admin.announcement.history', [ - 'announcements' => $announcements, - 'search' => $search, - 'mode' => $mode, - 'relay_state' => $relayState, - 'modes' => [self::MODE_REGULER, self::MODE_TTS], - 'relayStates' => [self::RELAY_ON, self::RELAY_OFF] - ]); + $ruangans = Ruangan::select('id', 'relay_state')->get(); + return response()->json($ruangans); } } \ No newline at end of file diff --git a/app/Http/Requests/StoreAnnouncementRequest.php b/app/Http/Requests/StoreAnnouncementRequest.php new file mode 100644 index 0000000..7b89e86 --- /dev/null +++ b/app/Http/Requests/StoreAnnouncementRequest.php @@ -0,0 +1,31 @@ + 'required|string|max:500', + 'mode' => 'required|in:tts,manual', + 'ruangans' => 'required|array|min:1', + 'ruangans.*' => 'exists:ruangan,id', + ]; + } + + public function messages() + { + return [ + 'ruangans.required' => 'Pilih minimal satu ruangan', + 'ruangans.min' => 'Pilih minimal satu ruangan', + ]; + } +} \ No newline at end of file diff --git a/app/Models/Announcement.php b/app/Models/Announcement.php index 4c81bdd..53b1960 100644 --- a/app/Models/Announcement.php +++ b/app/Models/Announcement.php @@ -4,121 +4,37 @@ use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Str; class Announcement extends Model { use HasFactory; - protected $table = 'announcements'; // Pastikan konsisten - - protected $fillable = [ - 'mode', - 'message', - 'audio_path', - 'voice', - 'speed', - 'is_active', - 'status', - 'error_message', - 'sent_at', - 'relay_state' // Tambahkan ini - ]; - - protected $attributes = [ - 'is_active' => true, - 'status' => 'pending', - 'relay_state' => 'OFF' // Default value - ]; + protected $fillable = ['message', 'mode', 'sent_at']; protected $casts = [ - 'is_active' => 'boolean', - 'sent_at' => 'datetime' + 'sent_at' => 'datetime', ]; + - // Tambahkan aksesor untuk relay - public function getRelayStateDescriptionAttribute() - { - return $this->relay_state === 'ON' ? 'Relay Menyala' : 'Relay Mati'; - } - - /** - * Relationship with Ruangan (many-to-many) - */ public function ruangans() { - return $this->belongsToMany(Ruangan::class, 'announcement_ruangan') - ->withTimestamps(); + return $this->belongsToMany(Ruangan::class); } - /** - * Scope for regular announcements - */ - public function scopeReguler($query) - { - return $query->where('mode', 'reguler'); - } - - /** - * Scope for TTS announcements - */ - public function scopeTts($query) - { - return $query->where('mode', 'tts'); - } - - /** - * Scope for delivered announcements - */ - public function scopeDelivered($query) - { - return $query->where('status', 'delivered'); - } - - /** - * Scope for failed announcements - */ - public function scopeFailed($query) - { - return $query->where('status', 'failed'); - } - - /** - * Accessor for audio URL - */ - public function getAudioUrlAttribute() - { - return $this->audio_path ? asset('storage/' . $this->audio_path) : null; - } - - /** - * Accessor for formatted sent time - */ public function getFormattedSentAtAttribute() { - return $this->sent_at->format('d M Y H:i:s'); + return $this->sent_at + ? $this->sent_at->format('d/m/Y H:i:s') + : 'Belum dikirim'; } - /** - * Accessor untuk pesan aktivasi - */ - public function getActivationMessageAttribute() + // Accessor for short message + public function getShortMessageAttribute() { - return $this->is_active ? 'Aktivasi Ruangan' : 'Deaktivasi Ruangan'; - } - - /** - * Cek apakah pengumuman reguler - */ - public function isReguler() - { - return $this->mode === 'reguler'; - } - - /** - * Cek apakah pengumuman TTS - */ - public function isTts() - { - return $this->mode === 'tts'; + if ($this->mode === 'manual') { + return 'Relay Control'; + } + return Str::limit($this->message, 30); } } \ No newline at end of file diff --git a/app/Models/Ruangan.php b/app/Models/Ruangan.php index e33a8ac..77daa82 100644 --- a/app/Models/Ruangan.php +++ b/app/Models/Ruangan.php @@ -15,15 +15,13 @@ class Ruangan extends Model 'nama_ruangan', 'id_kelas', 'id_jurusan', - 'relay_state', // Ubah dari status_relay menjadi relay_state - 'mqtt_topic' // Tambahkan kolom untuk custom MQTT topic + 'relay_state' ]; protected $casts = [ - 'relay_state' => 'string' // Ubah menjadi string untuk menyimpan 'ON'/'OFF' + 'relay_state' => 'string' ]; - /** * Relationship with Kelas */ @@ -56,19 +54,4 @@ public function getNamaRuanganAttribute($value) return strtoupper($value); } - /** - * Scope for active relay status - */ - public function scopeRelayActive($query) - { - return $query->where('status_relay', true); - } - - /** - * Scope for inactive relay status - */ - public function scopeRelayInactive($query) - { - return $query->where('status_relay', false); - } } \ No newline at end of file diff --git a/database/migrations/2025_04_21_051528_create_ruangan_table.php b/database/migrations/2025_04_21_051528_create_ruangan_table.php index 8370979..d357008 100644 --- a/database/migrations/2025_04_21_051528_create_ruangan_table.php +++ b/database/migrations/2025_04_21_051528_create_ruangan_table.php @@ -13,8 +13,7 @@ public function up(): void $table->string('nama_ruangan'); $table->foreignId('id_kelas')->constrained('kelas')->onDelete('cascade'); $table->foreignId('id_jurusan')->constrained('jurusan')->onDelete('cascade'); - $table->string('relay_state')->default('OFF'); // Ubah tipe data - $table->string('mqtt_topic')->nullable(); // Untuk custom topic per ruangan + $table->enum('relay_state', ['on', 'off'])->default('off'); $table->timestamps(); $table->index('nama_ruangan'); diff --git a/database/migrations/2025_04_22_135609_create_announcements_table.php b/database/migrations/2025_04_22_135609_create_announcements_table.php index dc19d8a..6653560 100644 --- a/database/migrations/2025_04_22_135609_create_announcements_table.php +++ b/database/migrations/2025_04_22_135609_create_announcements_table.php @@ -10,32 +10,16 @@ public function up() { Schema::create('announcements', function (Blueprint $table) { $table->id(); - $table->string('mode'); - $table->text('message'); - $table->string('audio_path')->nullable(); - $table->string('voice')->nullable(); - $table->integer('speed')->nullable(); - $table->boolean('is_active')->default(true); - $table->string('status')->default('pending'); - $table->text('error_message')->nullable(); - $table->string('relay_state')->default('OFF'); // Tambahkan kolom ini - $table->timestamp('sent_at')->useCurrent(); + $table->text('message')->nullable(); + $table->string('mode')->default('tts'); + $table->timestamp('sent_at')->nullable(); $table->timestamps(); - - $table->index('mode'); - $table->index('sent_at'); - $table->index('relay_state'); // Tambahkan index }); - // Perbaikan utama: Explicitly specify table names Schema::create('announcement_ruangan', function (Blueprint $table) { - $table->id(); $table->foreignId('announcement_id')->constrained('announcements')->onDelete('cascade'); $table->foreignId('ruangan_id')->constrained('ruangan')->onDelete('cascade'); - $table->string('relay_state_at_time')->nullable(); // State saat pengumuman dikirim - $table->timestamps(); - - $table->unique(['announcement_id', 'ruangan_id']); + $table->primary(['announcement_id', 'ruangan_id']); }); } diff --git a/resources/css/app.css b/resources/css/app.css index 94a8395..f93fe14 100644 --- a/resources/css/app.css +++ b/resources/css/app.css @@ -63,4 +63,16 @@ .badge-green { .badge-gray { @apply px-2 py-1 bg-gray-100 dark:bg-gray-700 rounded-full; +} + +.tab-content { + transition: opacity 0.3s ease; +} + +.shadow-sm { + transition: box-shadow 0.2s ease; +} + +.hover\:shadow-lg:hover { + box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); } \ No newline at end of file diff --git a/resources/views/admin/announcement/history.blade.php b/resources/views/admin/announcement/history.blade.php index 0a537e0..a764503 100644 --- a/resources/views/admin/announcement/history.blade.php +++ b/resources/views/admin/announcement/history.blade.php @@ -1,269 +1,301 @@ @extends('layouts.dashboard') -@section('title', 'Riwayat Pengumuman') +@section('title', 'Riwayat Pengumuman - Smart School') @section('content')
-
-

Riwayat Pengumuman

-

Daftar seluruh pengumuman yang pernah dikirim

-
- +

Riwayat Pengumuman

+ + Buat Pengumuman Baru +
- -
-
-
-
- -
- -
- - + +
+
+

+ Filter Riwayat +

+
+
+ +
+ +
+ +
+
- - -
- -
- -
- -
+
+
+ +
+ +
+
- - - +
+ +
+ +
+ +
+
+ + @if(request()->has('mode') || request()->has('start_date') || request()->has('end_date')) + + Reset + + @endif +
- -
- -
-
-

Daftar Pengumuman

-
- Menampilkan {{ $announcements->count() }} dari {{ $announcements->total() }} pengumuman -
-
-
- - + +
+ + - - - @forelse($announcements as $announcement) - - + @forelse($announcements as $index => $announcement) + + - - - - - - - - - - - - - + + @empty - @endforelse
- Jenis + # - Konten + Waktu Pengiriman + + Mode + + Isi Pengumuman Ruangan Tujuan - Waktu - - Status - Aksi
+ {{ $index + 1 + (($announcements->currentPage() - 1) * $announcements->perPage()) }} + -
- @if($announcement->mode === 'reguler') -
- -
- Aktivasi - @else -
- -
- TTS - @endif -
-
-
- @if($announcement->mode === 'tts') - {{ $announcement->message }} - @else - {{ $announcement->is_active ? 'Aktivasi ruangan' : 'Deaktivasi ruangan' }} -
- Status: {{ $announcement->is_active ? 'AKTIF' : 'NONAKTIF' }} -
- @endif -
- @if($announcement->mode === 'tts') -
- -
- @endif -
-
- {{ $announcement->ruangans->count() }} ruangan -
-
- @foreach($announcement->ruangans->take(3) as $ruangan) - {{ $ruangan->nama_ruangan }}@if(!$loop->last), @endif - @endforeach - @if($announcement->ruangans->count() > 3) - +{{ $announcement->ruangans->count() - 3 }} lainnya - @endif -
-
-
- {{ $announcement->sent_at->format('d M Y') }} +
+ {{ $announcement->formatted_sent_at }}
- {{ $announcement->sent_at->format('H:i') }} + {{ $announcement->sent_at->diffForHumans() }}
- @if($announcement->status === 'delivered') - - Terkirim - - @elseif($announcement->status === 'failed') - - Gagal + @if($announcement->mode === 'tts') + + TTS @else - - Proses + + Manual @endif +
{{ $announcement->short_message }}
+
{{ Str::limit($announcement->message, 80) }}
+
+
+ @foreach($announcement->ruangans as $ruangan) + + + {{ $ruangan->nama_ruangan }} + + @endforeach +
+
-
-
- +
+
+ +

Tidak ada riwayat pengumuman

+ @if(request()->has('mode') || request()->has('start_date') || request()->has('end_date')) + + Reset filter + + @endif
-

Belum Ada Pengumuman

-

Tidak ada riwayat pengumuman yang ditemukan

- + + @if($announcements->hasPages())
- {{ $announcements->appends(request()->query())->links() }} +
+
+

+ Menampilkan {{ $announcements->firstItem() }} + sampai {{ $announcements->lastItem() }} + dari {{ $announcements->total() }} hasil +

+
+
+ {{ $announcements->appends(request()->query())->links() }} +
+
+ @endif
- + - @endsection \ No newline at end of file diff --git a/resources/views/admin/announcement/index.blade.php b/resources/views/admin/announcement/index.blade.php index 41f72d3..b48df79 100644 --- a/resources/views/admin/announcement/index.blade.php +++ b/resources/views/admin/announcement/index.blade.php @@ -1,491 +1,537 @@ @extends('layouts.dashboard') -@section('title', 'Sistem Pengumuman Digital') +@section('title', 'Pengumuman Sekolah - Smart School') @section('content') -
- -
-
-
-
-

Sistem Pengumuman Digital

-

Kontrol Terpusat untuk Ruangan dan Pengumuman

-
-
-
-
- MQTT: {{ $mqttStatus }} -
- -
+
+ +
+
+
+

Sistem Pengumuman Sekolah

+ + + LIVE CONTROL +
-
-
- - -
- -
-
- -
- -
- -
-
- @csrf - - -
- -
-
-

Pilih Ruangan

- -
- -
-
- @foreach($ruangans as $ruangan) -
- - -
- @endforeach -
- @error('ruangans') -

{{ $message }}

- @enderror -
-
- - -
-

Kontrol Relay

-
-
-
- - -
-
- - -
-
- -
- -
-
-
-
-
-
- - - -
-
- - -
-
-

Riwayat Pengumuman Terakhir

-
-
- - - - - - - - - - - @forelse($announcements as $announcement) - - - - - - - @empty - - - - @endforelse - -
WaktuModeKontenStatus
-
{{ $announcement->sent_at->format('d M Y') }}
-
{{ $announcement->sent_at->format('H:i') }}
-
- - {{ $announcement->mode === 'reguler' ? 'Kontrol Relay' : 'Pengumuman Suara' }} - - -
- @if($announcement->mode === 'reguler') - {{ $announcement->message }} - - (Relay: {{ $announcement->relay_state }}) - - @else - {{ Str::limit($announcement->message, 50) }} - @endif -
-
- Ruangan: {{ $announcement->ruangans->pluck('nama_ruangan')->implode(', ') }} -
-
-
- - {{ ucfirst($announcement->status) }} - - @if($announcement->error_message) - - @endif -
-
- Belum ada riwayat pengumuman -
-
-
- {{ $announcements->links() }} -
-
-
-
- - - - - - + + - @endsection \ No newline at end of file diff --git a/resources/views/admin/announcement/show.blade.php b/resources/views/admin/announcement/show.blade.php deleted file mode 100644 index fb53039..0000000 --- a/resources/views/admin/announcement/show.blade.php +++ /dev/null @@ -1,80 +0,0 @@ -@extends('layouts.dashboard') - -@section('content') -
-
-
-

Detail Pengumuman

-
-
- -
-
-
-
-
Informasi Pengumuman
-
-
-
-
- Waktu: {{ $announcement->sent_at->format('d M Y H:i:s') }} -
-
- Mode: - - {{ strtoupper($announcement->mode) }} - -
-
- -
- Ruangan Tujuan: -
- @foreach($announcement->ruangans as $ruangan) - {{ $ruangan->nama_ruangan }} - @endforeach -
-
- -
- Isi Pengumuman: -
- @if($announcement->mode === 'tts') -

{{ $announcement->message }}

- @if($announcement->audio_path) - - @endif -
- - Suara: {{ $announcement->voice }} | - Kecepatan: {{ $announcement->speed }} - -
- @else -

{{ $announcement->message }}

- @endif -
-
- -
-
- Dibuat Oleh: {{ $announcement->user->name }} -
-
- Dibuat Pada: {{ $announcement->created_at->format('d M Y H:i:s') }} -
-
-
- -
-
-
-
-@endsection \ No newline at end of file diff --git a/resources/views/admin/jurusan/index.blade.php b/resources/views/admin/jurusan/index.blade.php index 811dc52..40ac414 100644 --- a/resources/views/admin/jurusan/index.blade.php +++ b/resources/views/admin/jurusan/index.blade.php @@ -41,21 +41,6 @@ class="bg-gradient-to-r from-blue-600 to-blue-800 hover:from-blue-700 hover:to-b
- - -
-
-
- - - -
-
-

Jurusan Aktif

-

{{ $jurusan->count() }}

-
-
-
@@ -123,15 +108,9 @@ class="block w-full md:w-64 rounded-md border-gray-300 shadow-sm focus:border-bl
{{ $item->nama_jurusan }}
-
- - - -
-
-
- - - -
-
-

Jurusan Terdaftar

-

{{ $kelas->unique('jurusan_id')->count() }}

-
-
-
diff --git a/resources/views/admin/ruangan/index.blade.php b/resources/views/admin/ruangan/index.blade.php index db2e3ec..3b8d4bb 100644 --- a/resources/views/admin/ruangan/index.blade.php +++ b/resources/views/admin/ruangan/index.blade.php @@ -41,36 +41,6 @@ class="bg-gradient-to-r from-blue-600 to-blue-800 hover:from-blue-700 hover:to-b
- - -
-
-
- - - -
-
-

Ruangan Tersedia

-

{{ $ruangan->count() }}

-
-
-
- - -
-
-
- - - -
-
-

Jurusan Terdaftar

-

{{ $ruangan->unique('jurusan_id')->count() }}

-
-
-
@@ -138,8 +108,7 @@ class="block w-full md:w-64 rounded-md border-gray-300 shadow-sm focus:border-bl
-
{{ $item->nama_ruangan }}
-
Kapasitas: 30 siswa
+
ruangan {{ $item->nama_ruangan }}
diff --git a/routes/web.php b/routes/web.php index 105340a..188ccf6 100644 --- a/routes/web.php +++ b/routes/web.php @@ -106,11 +106,20 @@ }); }); + // Announcement System // Announcement System Route::prefix('announcement')->controller(AnnouncementController::class)->group(function () { Route::get('/', 'index')->name('admin.announcement.index'); Route::get('/history', 'history')->name('admin.announcement.history'); Route::post('/', 'store')->name('admin.announcement.store'); + Route::get('/{id}/details', 'details')->name('admin.announcement.details'); + Route::delete('/{id}', 'destroy')->name('admin.announcement.destroy'); + + // MQTT & Relay + Route::get('/check/mqtt', 'checkMqtt')->name('admin.check.mqtt'); + Route::post('/control-relay', 'controlRelay')->name('admin.announcement.control-relay'); + Route::get('/relay-status', 'relayStatus')->name('admin.announcement.relay-status'); }); + }); }); \ No newline at end of file