fix send nama ruang
This commit is contained in:
parent
b7cec503d1
commit
822b613cb1
|
@ -46,9 +46,9 @@ public function history()
|
|||
->when(request('date'), function($query, $date) {
|
||||
return $query->whereDate('sent_at', $date);
|
||||
})
|
||||
->when(request('ruangan'), function($query, $ruanganId) {
|
||||
return $query->whereHas('ruangans', function($q) use ($ruanganId) {
|
||||
$q->where('ruangan.id', $ruanganId);
|
||||
->when(request('ruangan'), function($query, $ruanganName) {
|
||||
return $query->whereHas('ruangans', function($q) use ($ruanganName) {
|
||||
$q->where('nama_ruangan', $ruanganName); // Filter by name
|
||||
});
|
||||
})
|
||||
->orderBy('sent_at', 'desc')
|
||||
|
@ -74,6 +74,25 @@ public function store(StoreAnnouncementRequest $request)
|
|||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
// 1. Konversi nama ruangan ke ID
|
||||
$ruanganNames = $request->ruangans;
|
||||
$ruanganRecords = Ruangan::whereIn('nama_ruangan', $ruanganNames)->get();
|
||||
|
||||
// Validasi semua nama ruangan ditemukan
|
||||
if ($ruanganRecords->count() !== count($ruanganNames)) {
|
||||
$missingRooms = array_diff(
|
||||
$ruanganNames,
|
||||
$ruanganRecords->pluck('nama_ruangan')->toArray()
|
||||
);
|
||||
|
||||
throw new \Exception(
|
||||
'Ruangan tidak ditemukan: ' . implode(', ', $missingRooms)
|
||||
);
|
||||
}
|
||||
|
||||
$ruanganIds = $ruanganRecords->pluck('id')->toArray();
|
||||
|
||||
// 2. Persiapkan data pengumuman
|
||||
$announcementData = [
|
||||
'mode' => $request->mode,
|
||||
'sent_at' => now(),
|
||||
|
@ -83,47 +102,57 @@ public function store(StoreAnnouncementRequest $request)
|
|||
$announcementData['message'] = $request->message;
|
||||
}
|
||||
|
||||
// 3. Simpan pengumuman dan relasinya
|
||||
$announcement = Announcement::create($announcementData);
|
||||
$announcement->ruangans()->sync($request->ruangans);
|
||||
$announcement->ruangans()->sync($ruanganIds);
|
||||
|
||||
// 4. Kirim perintah ke MQTT
|
||||
$mqttService = app(MqttService::class);
|
||||
$success = false;
|
||||
|
||||
if ($request->mode === self::MODE_TTS) {
|
||||
$success = $mqttService->sendTTSAnnouncement(
|
||||
$request->ruangans,
|
||||
$ruanganNames, // Kirim nama ruangan (bukan ID)
|
||||
$request->message
|
||||
);
|
||||
} else {
|
||||
$success = $mqttService->sendRelayControl(
|
||||
'activate', // Default action for announcements
|
||||
$request->ruangans,
|
||||
self::ACTION_ACTIVATE,
|
||||
$ruanganNames, // Kirim nama ruangan (bukan ID)
|
||||
$request->mode
|
||||
);
|
||||
}
|
||||
|
||||
if (!$success) {
|
||||
throw new \Exception('Gagal mengirim perintah ke perangkat');
|
||||
throw new \Exception('Gagal mengirim perintah ke perangkat MQTT');
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Pengumuman berhasil dikirim'
|
||||
'message' => 'Pengumuman berhasil dikirim',
|
||||
'data' => [
|
||||
'announcement_id' => $announcement->id,
|
||||
'ruangan' => $ruanganNames
|
||||
]
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
Log::error('Failed to store announcement: ' . $e->getMessage());
|
||||
Log::error('Failed to store announcement', [
|
||||
'error' => $e->getMessage(),
|
||||
'request' => $request->all()
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'Gagal mengirim pengumuman: ' . $e->getMessage()
|
||||
'message' => 'Gagal mengirim pengumuman: ' . $e->getMessage(),
|
||||
'error_details' => $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function details($id)
|
||||
{
|
||||
try {
|
||||
|
@ -196,7 +225,7 @@ public function controlRelay(Request $request)
|
|||
{
|
||||
$validated = $request->validate([
|
||||
'ruangans' => 'required|array|min:1',
|
||||
'ruangans.*' => 'exists:ruangan,id',
|
||||
'ruangans.*' => 'string|exists:ruangan,nama_ruangan', // Pastikan validasi string
|
||||
'action' => 'required|in:'.self::ACTION_ACTIVATE.','.self::ACTION_DEACTIVATE,
|
||||
'mode' => 'required|in:'.self::MODE_MANUAL.','.self::MODE_TTS
|
||||
]);
|
||||
|
@ -204,13 +233,15 @@ public function controlRelay(Request $request)
|
|||
DB::beginTransaction();
|
||||
|
||||
try {
|
||||
$state = $validated['action'] === self::ACTION_ACTIVATE ? 'on' : 'off';
|
||||
$ruanganIds = $validated['ruangans'];
|
||||
// Dapatkan ID untuk operasi database
|
||||
$ruanganIds = Ruangan::whereIn('nama_ruangan', $validated['ruangans'])
|
||||
->pluck('id')
|
||||
->toArray();
|
||||
|
||||
$mqttService = app(MqttService::class);
|
||||
$success = $mqttService->sendRelayControl(
|
||||
$validated['action'],
|
||||
$ruanganIds,
|
||||
$validated['ruangans'], // Kirim NAMA ruangan ke MQTT
|
||||
$validated['mode']
|
||||
);
|
||||
|
||||
|
@ -218,10 +249,11 @@ public function controlRelay(Request $request)
|
|||
throw new \Exception('Gagal mengirim perintah ke perangkat');
|
||||
}
|
||||
|
||||
// Update database
|
||||
// Update database menggunakan ID
|
||||
$state = $validated['action'] === self::ACTION_ACTIVATE ? 'on' : 'off';
|
||||
Ruangan::whereIn('id', $ruanganIds)->update(['relay_state' => $state]);
|
||||
|
||||
// Log manual activations as announcements
|
||||
// Log manual activations
|
||||
if ($validated['action'] === self::ACTION_ACTIVATE && $validated['mode'] === self::MODE_MANUAL) {
|
||||
$announcement = Announcement::create([
|
||||
'mode' => self::MODE_MANUAL,
|
||||
|
@ -229,14 +261,15 @@ public function controlRelay(Request $request)
|
|||
'sent_at' => now()
|
||||
]);
|
||||
|
||||
$announcement->ruangans()->sync($ruanganIds);
|
||||
$announcement->ruangans()->sync($ruanganIds); // Gunakan ID untuk relasi
|
||||
}
|
||||
|
||||
DB::commit();
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'message' => 'Relay berhasil dikontrol'
|
||||
'message' => 'Relay berhasil dikontrol',
|
||||
'ruangans' => $validated['ruangans'] // Kembalikan nama ruangan
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
@ -253,11 +286,16 @@ public function controlRelay(Request $request)
|
|||
public function relayStatus()
|
||||
{
|
||||
try {
|
||||
$ruangans = Ruangan::select('id', 'nama_ruangan', 'relay_state')->get();
|
||||
$ruangans = Ruangan::select('nama_ruangan', 'relay_state')->get(); // Hanya ambil nama dan status
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $ruangans
|
||||
'data' => $ruangans->map(function($ruangan) {
|
||||
return [
|
||||
'nama_ruangan' => $ruangan->nama_ruangan,
|
||||
'relay_state' => $ruangan->relay_state
|
||||
];
|
||||
})
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
|
@ -274,7 +312,7 @@ public function announcementStatus(Request $request)
|
|||
try {
|
||||
$request->validate([
|
||||
'ruangans' => 'required|array|min:1',
|
||||
'ruangans.*' => 'exists:ruangan,id'
|
||||
'ruangans.*' => 'exists:ruangan,nama_ruangan'
|
||||
]);
|
||||
|
||||
$mqttService = app(MqttService::class);
|
||||
|
|
|
@ -14,10 +14,10 @@ public function authorize()
|
|||
public function rules()
|
||||
{
|
||||
return [
|
||||
'message' => 'required|string|max:500',
|
||||
'message' => 'required_if:mode,tts|string|max:500',
|
||||
'mode' => 'required|in:tts,manual',
|
||||
'ruangans' => 'required|array|min:1',
|
||||
'ruangans.*' => 'exists:ruangan,id',
|
||||
'ruangans.*' => 'string|exists:ruangan,nama_ruangan', // Ubah validasi ke nama ruangan
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -199,7 +199,8 @@ class="inline-flex items-center px-3 py-1.5 border border-transparent text-sm fo
|
|||
<script>
|
||||
// Show announcement details in modal
|
||||
function showAnnouncementDetails(id) {
|
||||
$.get(`/admin/announcement/${id}/details`, function(data) {
|
||||
$.get(`/admin/announcement/${id}/details`, function(response) {
|
||||
const data = response.data; // ambil data sebenarnya dari response
|
||||
Swal.fire({
|
||||
title: 'Detail Pengumuman',
|
||||
html: `
|
||||
|
@ -211,10 +212,6 @@ function showAnnouncementDetails(id) {
|
|||
${data.mode === 'tts' ? 'Text-to-Speech' : 'Manual'}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-medium w-24">Waktu:</span>
|
||||
<span>${data.formatted_sent_at}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="font-medium w-24">Ruangan:</span>
|
||||
<div class="flex flex-wrap gap-1 mt-1">
|
||||
|
|
|
@ -85,25 +85,24 @@ class="flex items-center px-5 py-2.5 bg-white border border-blue-500 text-blue-6
|
|||
@foreach($ruangans as $ruangan)
|
||||
<div class="relative flex items-start p-3 rounded-lg border border-gray-200 hover:border-blue-300 transition-colors">
|
||||
<div class="flex items-center h-5 mt-1">
|
||||
<input id="manual-ruang-{{ $ruangan->id }}" name="ruangans[]"
|
||||
type="checkbox" value="{{ $ruangan->id }}"
|
||||
<input id="manual-ruang-{{ $ruangan->nama_ruangan }}"
|
||||
name="ruangans[]"
|
||||
type="checkbox"
|
||||
value="{{ $ruangan->nama_ruangan }}"
|
||||
class="focus:ring-blue-500 h-4 w-4 text-blue-600 border-gray-300 rounded">
|
||||
</div>
|
||||
<div class="ml-3 text-sm flex-1">
|
||||
<div class="flex items-center justify-between">
|
||||
<label for="manual-ruang-{{ $ruangan->id }}" class="font-medium text-gray-700 flex items-center">
|
||||
<label for="manual-ruang-{{ $ruangan->nama_ruangan }}" class="font-medium text-gray-700 flex items-center">
|
||||
<span class="inline-block w-2.5 h-2.5 rounded-full bg-blue-500 mr-2"></span>
|
||||
{{ $ruangan->nama_ruangan }}
|
||||
</label>
|
||||
<span id="status-ruang-{{ $ruangan->id }}" class="text-xs px-2 py-0.5 rounded-full
|
||||
<span id="status-ruang-{{ $ruangan->nama_ruangan }}"
|
||||
class="text-xs px-2 py-0.5 rounded-full
|
||||
{{ $ruangan->relay_state === 'on' ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800' }}">
|
||||
{{ $ruangan->relay_state === 'on' ? 'AKTIF' : 'NONAKTIF' }}
|
||||
</span>
|
||||
</div>
|
||||
<!-- <p class="text-xs text-gray-500 mt-1 flex items-center">
|
||||
<i class="fas fa-map-marker-alt mr-1 text-gray-400"></i>
|
||||
{{ $ruangan->lokasi }}
|
||||
</p> -->
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
@ -169,19 +168,17 @@ class="block w-full px-4 py-3 border border-gray-300 rounded-lg shadow-sm focus:
|
|||
@foreach($ruangans as $ruangan)
|
||||
<div class="relative flex items-start p-3 rounded-lg border border-gray-200 hover:border-green-300 transition-colors">
|
||||
<div class="flex items-center h-5 mt-1">
|
||||
<input id="tts-ruang-{{ $ruangan->id }}" name="ruangans[]"
|
||||
type="checkbox" value="{{ $ruangan->id }}"
|
||||
<input id="tts-ruang-{{ $ruangan->nama_ruangan }}"
|
||||
name="ruangans[]"
|
||||
type="checkbox"
|
||||
value="{{ $ruangan->nama_ruangan }}"
|
||||
class="focus:ring-green-500 h-4 w-4 text-green-600 border-gray-300 rounded">
|
||||
</div>
|
||||
<div class="ml-3 text-sm">
|
||||
<label for="tts-ruang-{{ $ruangan->id }}" class="font-medium text-gray-700 flex items-center">
|
||||
<label for="tts-ruang-{{ $ruangan->nama_ruangan }}" class="font-medium text-gray-700 flex items-center">
|
||||
<span class="inline-block w-2.5 h-2.5 rounded-full bg-green-500 mr-2"></span>
|
||||
{{ $ruangan->nama_ruangan }}
|
||||
</label>
|
||||
<!-- <p class="text-xs text-gray-500 mt-1 flex items-center">
|
||||
<i class="fas fa-map-marker-alt mr-1 text-gray-400"></i>
|
||||
{{ $ruangan->lokasi }}
|
||||
</p> -->
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
|
@ -210,6 +207,11 @@ class="focus:ring-green-500 h-4 w-4 text-green-600 border-gray-300 rounded">
|
|||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
// Fungsi untuk membuat selector aman dari karakter khusus
|
||||
function getSafeRoomSelector(roomName) {
|
||||
return roomName.replace(/[^a-zA-Z0-9-]/g, '-');
|
||||
}
|
||||
|
||||
// Tab switching functionality
|
||||
function switchTab(activeTab, inactiveTab, activeBtn, inactiveBtn) {
|
||||
activeTab.classList.remove('hidden');
|
||||
|
@ -282,12 +284,12 @@ function switchTab(activeTab, inactiveTab, activeBtn, inactiveBtn) {
|
|||
e.preventDefault();
|
||||
const form = this;
|
||||
const formData = new FormData(form);
|
||||
const rooms = formData.getAll('ruangans[]');
|
||||
const roomNames = formData.getAll('ruangans[]');
|
||||
|
||||
// Reset error states
|
||||
$('#ruanganError').addClass('hidden');
|
||||
|
||||
if (rooms.length === 0) {
|
||||
if (roomNames.length === 0) {
|
||||
$('#ruanganError').removeClass('hidden');
|
||||
Swal.fire({
|
||||
title: 'Peringatan',
|
||||
|
@ -324,8 +326,9 @@ function switchTab(activeTab, inactiveTab, activeBtn, inactiveBtn) {
|
|||
},
|
||||
success: function(response) {
|
||||
// Update room status indicators
|
||||
rooms.forEach(roomId => {
|
||||
const statusElement = $(`#status-ruang-${roomId}`);
|
||||
roomNames.forEach(roomName => {
|
||||
const safeRoomName = getSafeRoomSelector(roomName);
|
||||
const statusElement = $(`#status-ruang-${safeRoomName}`);
|
||||
statusElement.text(isRelayActive ? 'AKTIF' : 'NONAKTIF');
|
||||
statusElement.removeClass('bg-gray-100 text-gray-800 bg-green-100 text-green-800')
|
||||
.addClass(isRelayActive ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800');
|
||||
|
@ -409,8 +412,8 @@ function switchTab(activeTab, inactiveTab, activeBtn, inactiveBtn) {
|
|||
return;
|
||||
}
|
||||
|
||||
const rooms = formData.getAll('ruangans[]');
|
||||
if (rooms.length === 0) {
|
||||
const roomNames = formData.getAll('ruangans[]');
|
||||
if (roomNames.length === 0) {
|
||||
$('#ttsRuanganError').removeClass('hidden');
|
||||
Swal.fire({
|
||||
title: 'Peringatan',
|
||||
|
@ -484,7 +487,8 @@ function switchTab(activeTab, inactiveTab, activeBtn, inactiveBtn) {
|
|||
function checkRelayStatus() {
|
||||
$.get("{{ url('/api/announcements/relay/status') }}", function(data) {
|
||||
data.forEach(room => {
|
||||
const statusElement = $(`#status-ruang-${room.id}`);
|
||||
const safeRoomName = getSafeRoomSelector(room.nama_ruangan);
|
||||
const statusElement = $(`#status-ruang-${safeRoomName}`);
|
||||
if (statusElement.length) {
|
||||
statusElement.text(room.relay_state === 'on' ? 'AKTIF' : 'NONAKTIF');
|
||||
statusElement.removeClass('bg-gray-100 text-gray-800 bg-green-100 text-green-800')
|
||||
|
|
|
@ -111,6 +111,8 @@
|
|||
Route::get('/', 'index')->name('admin.announcement.index');
|
||||
Route::get('/history', 'history')->name('admin.announcement.history');
|
||||
Route::delete('/{id}', 'destroy')->name('announcement.destroy');
|
||||
Route::get('{id}/details', 'details')->name('announcement.details');
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue