.
This commit is contained in:
parent
679461d3a3
commit
89c68f340f
@ -153,17 +153,19 @@ func ControlHardware(c *gin.Context) {
|
||||
haToken := os.Getenv("HA_TOKEN")
|
||||
var entityID string
|
||||
|
||||
switch req.Device {
|
||||
switch req.Device {
|
||||
case "ac":
|
||||
if req.Action == "on" {
|
||||
switch req.Action {
|
||||
case "on":
|
||||
entityID = "scene.ac_d101_on"
|
||||
} else {
|
||||
default:
|
||||
entityID = "scene.ac_d101_off"
|
||||
}
|
||||
case "projector":
|
||||
if req.Action == "on" {
|
||||
switch req.Action {
|
||||
case "on":
|
||||
entityID = "scene.projector_d101_on"
|
||||
} else {
|
||||
case "off":
|
||||
entityID = "scene.projector_d101_off"
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,6 @@ export default function PowerMonitoringPage() {
|
||||
const backendData = result.data;
|
||||
|
||||
// Kita terjemahkan data Golang ("on"/"off") menjadi boolean (true/false)
|
||||
// dan masukkan khusus untuk Kelas D101 (id: 1)
|
||||
setRoomDeviceStatus(prev => ({
|
||||
...prev,
|
||||
"room_1": {
|
||||
@ -59,7 +58,7 @@ export default function PowerMonitoringPage() {
|
||||
// 3. INISIALISASI & POLLING (AUTO-REFRESH)
|
||||
// =========================================================================
|
||||
useEffect(() => {
|
||||
// A. Simulasi Data Ruangan dari DB/IoT
|
||||
// Simulasi Data Ruangan
|
||||
const dummyRooms = [
|
||||
{ id: 1, name: "Kelas D101", power: 0, isRelayOn: true, lastUpdate: "Real-time" },
|
||||
{ id: 2, name: "Kelas D102", power: 0, isRelayOn: false, lastUpdate: "2 mnt lalu" },
|
||||
@ -68,7 +67,7 @@ export default function PowerMonitoringPage() {
|
||||
];
|
||||
setRooms(dummyRooms);
|
||||
|
||||
// B. Inisialisasi status default semua device OFF
|
||||
// Inisialisasi status default semua device OFF
|
||||
const initialStatus: { [roomId: string]: { [deviceName: string]: boolean } } = {};
|
||||
dummyRooms.forEach(room => {
|
||||
initialStatus[`room_${room.id}`] = {
|
||||
@ -80,17 +79,15 @@ export default function PowerMonitoringPage() {
|
||||
});
|
||||
setRoomDeviceStatus(initialStatus);
|
||||
|
||||
// C. Tarik data pertama kali saat halaman dibuka
|
||||
// Tarik data pertama kali & set Interval 2 detik
|
||||
fetchPowerStatus();
|
||||
fetchDeviceStatus();
|
||||
|
||||
// D. Jalankan Polling setiap 2 detik (2000 ms)
|
||||
const interval = setInterval(() => {
|
||||
fetchPowerStatus();
|
||||
fetchDeviceStatus();
|
||||
}, 2000);
|
||||
|
||||
// E. Bersihkan interval jika admin pindah halaman
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
|
||||
@ -100,18 +97,24 @@ export default function PowerMonitoringPage() {
|
||||
const handleDeviceToggle = async (roomId: number, roomName: string, deviceName: string) => {
|
||||
const roomIdKey = `room_${roomId}`;
|
||||
const currentStatus = roomDeviceStatus[roomIdKey]?.[deviceName] || false;
|
||||
|
||||
// Logika Pintar: Jika sedang ON, maka klik selanjutnya adalah OFF. Sebaliknya.
|
||||
const actionType = currentStatus ? "off" : "on";
|
||||
|
||||
const confirmMsg = `Apakah Anda yakin ingin mematikan ${deviceName} di ${roomName}?`;
|
||||
if (currentStatus && !confirm(confirmMsg)) return;
|
||||
// Konfirmasi mematikan (Biar admin gak salah pencet)
|
||||
if (currentStatus) {
|
||||
const confirmMsg = `Apakah Anda yakin ingin mematikan ${deviceName} di ${roomName}?`;
|
||||
if (!window.confirm(confirmMsg)) return; // Jika di-cancel, berhenti di sini
|
||||
}
|
||||
|
||||
// Mapping nama device untuk backend
|
||||
let backendDevice = "";
|
||||
if (deviceName === 'AC 1') backendDevice = "ac";
|
||||
else if (deviceName === 'Proyektor') backendDevice = "projector";
|
||||
else if (deviceName === 'Lampu 1') backendDevice = "lampu1";
|
||||
else if (deviceName === 'Lampu 2') backendDevice = "lampu2";
|
||||
|
||||
// Update UI seketika agar terasa responsif bagi admin yang menekan tombol
|
||||
// 1. UBAH UI SEKETIKA (Optimistic UI) agar layar merespons tanpa delay
|
||||
setRoomDeviceStatus(prev => ({
|
||||
...prev,
|
||||
[roomIdKey]: {
|
||||
@ -120,6 +123,7 @@ export default function PowerMonitoringPage() {
|
||||
},
|
||||
}));
|
||||
|
||||
// 2. KIRIM KE GOLANG
|
||||
try {
|
||||
const response = await fetch("http://172.17.172.17:8080/api/hardware/control", {
|
||||
method: "POST",
|
||||
@ -127,8 +131,8 @@ export default function PowerMonitoringPage() {
|
||||
body: JSON.stringify({ device: backendDevice, action: actionType }),
|
||||
});
|
||||
|
||||
// 3. JIKA GAGAL, KEMBALIKAN UI KE POSISI SEMULA
|
||||
if (!response.ok) {
|
||||
// Jika gagal, kembalikan posisi tombol ke keadaan semula
|
||||
setRoomDeviceStatus(prev => ({
|
||||
...prev,
|
||||
[roomIdKey]: {
|
||||
@ -137,11 +141,11 @@ export default function PowerMonitoringPage() {
|
||||
},
|
||||
}));
|
||||
const errorData = await response.json();
|
||||
alert(`GAGAL: ${errorData.error || response.statusText}`);
|
||||
alert(`GAGAL: ${errorData.error || "Server menolak perintah"}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error API:", error);
|
||||
// Jika server mati, kembalikan posisi tombol
|
||||
// Rollback UI jika koneksi mati
|
||||
setRoomDeviceStatus(prev => ({
|
||||
...prev,
|
||||
[roomIdKey]: {
|
||||
@ -154,7 +158,7 @@ export default function PowerMonitoringPage() {
|
||||
};
|
||||
|
||||
const handleCutOff = (roomName: string) => {
|
||||
if (confirm(`PERINGATAN: Anda yakin ingin mematikan daya secara paksa di ${roomName}?`)) {
|
||||
if (window.confirm(`PERINGATAN: Anda yakin ingin mematikan daya secara paksa di ${roomName}?`)) {
|
||||
alert(`Sinyal pemutusan daya dikirim ke Relay Master ${roomName}.`);
|
||||
}
|
||||
};
|
||||
@ -164,7 +168,6 @@ export default function PowerMonitoringPage() {
|
||||
// =========================================================================
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
{/* Header section */}
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<div className="bg-blue-100 p-3 rounded-lg text-blue-600">
|
||||
<Activity size={28} />
|
||||
@ -184,7 +187,6 @@ export default function PowerMonitoringPage() {
|
||||
return (
|
||||
<div key={room.id} className="bg-white p-6 rounded-xl border border-gray-100 shadow-sm relative overflow-hidden flex flex-col">
|
||||
|
||||
{/* Status Badge */}
|
||||
<div className={`absolute top-0 right-0 px-4 py-1.5 text-[10px] font-black uppercase tracking-wider rounded-bl-xl
|
||||
${room.isRelayOn ? 'bg-green-100 text-green-700' : 'bg-red-100 text-red-700'}`}>
|
||||
{room.isRelayOn ? 'Sirkuit Aktif' : 'Sirkuit Terputus'}
|
||||
@ -192,7 +194,6 @@ export default function PowerMonitoringPage() {
|
||||
|
||||
<h3 className="text-lg font-bold text-gray-800 mb-4">{room.name}</h3>
|
||||
|
||||
{/* Power display */}
|
||||
<div className="flex items-end gap-2 mb-6">
|
||||
<span className={`text-5xl font-black tracking-tight ${room.power > 1000 ? 'text-orange-500' : 'text-gray-800'}`}>
|
||||
{room.power}
|
||||
@ -206,7 +207,6 @@ export default function PowerMonitoringPage() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* PANEL KONTROL IoT */}
|
||||
<div className="mt-2 mb-6 pt-4 border-t border-gray-100">
|
||||
<p className="text-[10px] font-bold text-gray-400 uppercase tracking-wider mb-3">IoT Device Control</p>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
@ -262,7 +262,6 @@ export default function PowerMonitoringPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="flex items-center justify-between mt-auto pt-4 border-t border-gray-100">
|
||||
<span className="text-xs text-gray-400 font-medium">Update: {room.lastUpdate}</span>
|
||||
<button
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user