add get and post methods
This commit is contained in:
11
index.html
11
index.html
@@ -4,12 +4,19 @@
|
|||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet">
|
<!-- <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" rel="stylesheet"> -->
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<!-- Remover link para tailwind.min.css -->
|
||||||
|
<!-- <link href="/tailwind.min.css" rel="stylesheet"> -->
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Arial', 'Helvetica', 'sans-serif'; /* Usando fontes genéricas do sistema */
|
||||||
|
}
|
||||||
|
</style>
|
||||||
<title>Vite + React</title>
|
<title>Vite + React</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
<!-- Adicionar o link para o seu arquivo CSS com o Tailwind configurado -->
|
||||||
<script type="module" src="/src/main.jsx"></script>
|
<script type="module" src="/src/main.jsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
4227
package-lock.json
generated
4227
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -21,10 +21,15 @@
|
|||||||
"@types/react": "^19.1.2",
|
"@types/react": "^19.1.2",
|
||||||
"@types/react-dom": "^19.1.2",
|
"@types/react-dom": "^19.1.2",
|
||||||
"@vitejs/plugin-react": "^4.4.1",
|
"@vitejs/plugin-react": "^4.4.1",
|
||||||
|
"autoprefixer": "^10.4.21",
|
||||||
"eslint": "^9.25.0",
|
"eslint": "^9.25.0",
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.19",
|
"eslint-plugin-react-refresh": "^0.4.19",
|
||||||
"globals": "^16.0.0",
|
"globals": "^16.0.0",
|
||||||
|
"live-server": "^1.2.2",
|
||||||
|
"postcss": "^8.5.4",
|
||||||
|
"postcss-cli": "^11.0.1",
|
||||||
|
"tailwindcss": "^3.4.17",
|
||||||
"vite": "^6.3.5"
|
"vite": "^6.3.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
6
postcss.config.cjs
Executable file
6
postcss.config.cjs
Executable file
@@ -0,0 +1,6 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
},
|
||||||
|
}
|
||||||
@@ -9,17 +9,21 @@ const Navbar = () => {
|
|||||||
setIsMenuOpen(!isMenuOpen); // Alterna o estado do menu (aberto/fechado)
|
setIsMenuOpen(!isMenuOpen); // Alterna o estado do menu (aberto/fechado)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleLinkClick = () => {
|
||||||
|
setIsMenuOpen(false); // Fecha o menu quando um link é clicado
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className="bg-gradient-to-r from-green-700 to-green-600 text-white p-4 shadow">
|
<nav className="bg-gradient-to-r from-green-700 to-green-600 text-white p-4 shadow">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="font-bold text-xl">EVSE</div>
|
<div className="font-bold text-xl">EVSE</div>
|
||||||
<ul className={`flex-col md:flex-row md:flex gap-4 ${isMenuOpen ? 'flex' : 'hidden'} md:!flex`}>
|
<ul className={`flex-col md:flex-row md:flex gap-4 ${isMenuOpen ? 'flex' : 'hidden'} md:!flex`}>
|
||||||
<li><Link className="hover:underline" to="/dashboard">Dashboard</Link></li>
|
<li><Link className="hover:underline" to="/dashboard" onClick={handleLinkClick}>Dashboard</Link></li>
|
||||||
<li><Link className="hover:underline" to="/settings">Settings</Link></li>
|
<li><Link className="hover:underline" to="/settings" onClick={handleLinkClick}>Settings</Link></li>
|
||||||
<li><Link className="hover:underline" to="/security">Security</Link></li>
|
<li><Link className="hover:underline" to="/security" onClick={handleLinkClick}>Security</Link></li>
|
||||||
<li><Link className="hover:underline" to="/connectivity">Connectivity</Link></li>
|
<li><Link className="hover:underline" to="/connectivity" onClick={handleLinkClick}>Connectivity</Link></li>
|
||||||
<li><Link className="hover:underline" to="/ocpp">OCPP</Link></li>
|
<li><Link className="hover:underline" to="/ocpp" onClick={handleLinkClick}>OCPP</Link></li>
|
||||||
<li><Link className="hover:underline" to="/electrical-network">Rede Elétrica</Link></li>
|
<li><Link className="hover:underline" to="/electrical-network" onClick={handleLinkClick}>Rede Elétrica</Link></li>
|
||||||
</ul>
|
</ul>
|
||||||
<button className="md:hidden text-3xl" onClick={toggleMenu}>
|
<button className="md:hidden text-3xl" onClick={toggleMenu}>
|
||||||
☰
|
☰
|
||||||
|
|||||||
3
src/index.css
Executable file
3
src/index.css
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
import './index.css'; // ou 'styles.css'
|
||||||
|
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
// src/pages/Connectivity.jsx
|
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { get, post } from '../api';
|
import { get, post } from '../api';
|
||||||
import PageLayout from '../components/PageLayout';
|
import PageLayout from '../components/PageLayout';
|
||||||
|
|
||||||
const Connectivity = () => {
|
const Connectivity = () => {
|
||||||
const [status, setStatus] = useState(null);
|
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
const [wifiConfig, setWifiConfig] = useState({ ssid: '', password: '' });
|
const [wifiConfig, setWifiConfig] = useState({ enabled: false, ssid: '', password: '' });
|
||||||
const [wifiNetworks, setWifiNetworks] = useState([]);
|
|
||||||
const [wifiMsg, setWifiMsg] = useState('');
|
const [wifiMsg, setWifiMsg] = useState('');
|
||||||
|
|
||||||
const [mqttConfig, setMqttConfig] = useState({
|
const [mqttConfig, setMqttConfig] = useState({
|
||||||
@@ -21,45 +18,46 @@ const Connectivity = () => {
|
|||||||
});
|
});
|
||||||
const [mqttMsg, setMqttMsg] = useState('');
|
const [mqttMsg, setMqttMsg] = useState('');
|
||||||
|
|
||||||
|
// Carregar as configurações Wi-Fi e MQTT
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const load = async () => {
|
const load = async () => {
|
||||||
try {
|
|
||||||
const conn = await get('/api/v1/connectivity');
|
|
||||||
setStatus(conn);
|
|
||||||
} catch {
|
|
||||||
// ignore errors in demo
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
const wifi = await get('/api/v1/config/wifi');
|
const wifi = await get('/api/v1/config/wifi');
|
||||||
setWifiConfig(wifi);
|
setWifiConfig(wifi); // Atualiza as configurações Wi-Fi
|
||||||
} catch {}
|
} catch (error) {
|
||||||
try {
|
console.error('Erro ao carregar configurações Wi-Fi:', error);
|
||||||
const list = await get('/api/v1/config/wifi/scan');
|
}
|
||||||
setWifiNetworks(list.networks || []);
|
|
||||||
} catch {}
|
|
||||||
try {
|
try {
|
||||||
const mqtt = await get('/api/v1/config/mqtt');
|
const mqtt = await get('/api/v1/config/mqtt');
|
||||||
setMqttConfig(mqtt);
|
setMqttConfig(mqtt); // Atualiza as configurações MQTT
|
||||||
} catch {}
|
} catch (error) {
|
||||||
setLoading(false);
|
console.error('Erro ao carregar configurações MQTT:', error);
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false); // Finaliza o carregamento
|
||||||
};
|
};
|
||||||
|
|
||||||
load();
|
load();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Salvar configuração Wi-Fi
|
||||||
const saveWifi = async () => {
|
const saveWifi = async () => {
|
||||||
try {
|
try {
|
||||||
await post('/api/v1/config/wifi', wifiConfig);
|
await post('/api/v1/config/wifi', wifiConfig); // Envia as configurações de Wi-Fi para o servidor
|
||||||
setWifiMsg('Configuração Wi-Fi gravada!');
|
setWifiMsg('Configuração Wi-Fi gravada!');
|
||||||
} catch {
|
} catch (error) {
|
||||||
setWifiMsg('Erro ao gravar Wi-Fi.');
|
setWifiMsg('Erro ao gravar Wi-Fi.');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Salvar configuração MQTT
|
||||||
const saveMqtt = async () => {
|
const saveMqtt = async () => {
|
||||||
try {
|
try {
|
||||||
await post('/api/v1/config/mqtt', mqttConfig);
|
await post('/api/v1/config/mqtt', mqttConfig); // Envia as configurações de MQTT para o servidor
|
||||||
setMqttMsg('Configuração MQTT gravada!');
|
setMqttMsg('Configuração MQTT gravada!');
|
||||||
} catch {
|
} catch (error) {
|
||||||
setMqttMsg('Erro ao gravar MQTT.');
|
setMqttMsg('Erro ao gravar MQTT.');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -69,19 +67,24 @@ const Connectivity = () => {
|
|||||||
{loading ? (
|
{loading ? (
|
||||||
<p>A carregar...</p>
|
<p>A carregar...</p>
|
||||||
) : (
|
) : (
|
||||||
<>
|
|
||||||
{status && (
|
|
||||||
<div>
|
|
||||||
<h2>Status Atual</h2>
|
|
||||||
<p>Wi-Fi: {status.wifi.status} ({status.wifi.ssid})</p>
|
|
||||||
<p>MQTT: {status.mqtt.status} - {status.mqtt.broker}:{status.mqtt.port}</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<h2 className="text-xl font-semibold mt-4">Configuração Wi-Fi</h2>
|
<h2 className="text-xl font-semibold mt-4">Configuração Wi-Fi</h2>
|
||||||
{wifiMsg && <div className="p-2 bg-gray-200 rounded mb-2">{wifiMsg}</div>}
|
{wifiMsg && <div className="p-2 bg-gray-200 rounded mb-2">{wifiMsg}</div>}
|
||||||
<form className="flex flex-col gap-4" onSubmit={e => { e.preventDefault(); saveWifi(); }}>
|
<form className="flex flex-col gap-4" onSubmit={e => { e.preventDefault(); saveWifi(); }}>
|
||||||
|
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label className="flex items-center gap-2">
|
||||||
|
Ativar WIFI
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={wifiConfig.enabled}
|
||||||
|
onChange={e => setMqttConfig({ ...wifiConfig, enabled: e.target.checked })}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block mb-1" htmlFor="wifi-ssid">SSID:</label>
|
<label className="block mb-1" htmlFor="wifi-ssid">SSID:</label>
|
||||||
<input
|
<input
|
||||||
@@ -93,7 +96,6 @@ const Connectivity = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block mb-1" htmlFor="wifi-password">Palavra-passe:</label>
|
<label className="block mb-1" htmlFor="wifi-password">Palavra-passe:</label>
|
||||||
<input
|
<input
|
||||||
@@ -178,6 +180,7 @@ const Connectivity = () => {
|
|||||||
onChange={e => setMqttConfig({ ...mqttConfig, topic: e.target.value })}
|
onChange={e => setMqttConfig({ ...mqttConfig, topic: e.target.value })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button className="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700" type="submit">Guardar</button>
|
<button className="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700" type="submit">Guardar</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,20 +1,38 @@
|
|||||||
// src/pages/Dashboard.jsx
|
import React, { useState, useEffect } from 'react';
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
const Dashboard = () => {
|
const Dashboard = () => {
|
||||||
// Mock data (substitua pelos dados reais)
|
// Estados para armazenar os dados do dashboard
|
||||||
const mockDashboardData = {
|
const [dashboardData, setDashboardData] = useState({
|
||||||
status: "Ativo",
|
status: "Ativo",
|
||||||
chargers: [
|
chargers: [
|
||||||
{ id: 1, status: "Ativo", current: 12, power: 2200 },
|
|
||||||
{ id: 2, status: "Inativo", current: 0, power: 0 },
|
|
||||||
{ id: 3, status: "Erro", current: 0, power: 0 },
|
{ id: 3, status: "Erro", current: 0, power: 0 },
|
||||||
],
|
],
|
||||||
energyConsumed: 50.3,
|
energyConsumed: 0,
|
||||||
chargingTime: 120,
|
chargingTime: 0,
|
||||||
alerts: ["Aviso: Carregador 1 está com erro."],
|
alerts: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
// Função para obter os dados do dashboard
|
||||||
|
const fetchDashboardData = async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch('/api/v1/dashboard');
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
setDashboardData(data); // Atualiza o estado com os dados recebidos
|
||||||
|
} else {
|
||||||
|
alert('Erro ao obter os dados do dashboard');
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Erro ao buscar dados do dashboard:', error);
|
||||||
|
alert('Erro de conexão');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Chamar a função fetchDashboardData quando o componente for montado
|
||||||
|
useEffect(() => {
|
||||||
|
fetchDashboardData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-3xl mx-auto p-5">
|
<div className="max-w-3xl mx-auto p-5">
|
||||||
<h1 className="text-2xl font-bold mb-5">Visão Geral</h1>
|
<h1 className="text-2xl font-bold mb-5">Visão Geral</h1>
|
||||||
@@ -23,15 +41,15 @@ const Dashboard = () => {
|
|||||||
<div className="flex flex-wrap gap-4 mb-6">
|
<div className="flex flex-wrap gap-4 mb-6">
|
||||||
<div className="bg-white p-4 rounded shadow flex-1 min-w-[150px]">
|
<div className="bg-white p-4 rounded shadow flex-1 min-w-[150px]">
|
||||||
<h3>Status do Sistema</h3>
|
<h3>Status do Sistema</h3>
|
||||||
<p>{mockDashboardData.status}</p>
|
<p>{dashboardData.status}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white p-4 rounded shadow flex-1 min-w-[150px]">
|
<div className="bg-white p-4 rounded shadow flex-1 min-w-[150px]">
|
||||||
<h3>Consumo de Energia</h3>
|
<h3>Consumo de Energia</h3>
|
||||||
<p>{mockDashboardData.energyConsumed} kWh</p>
|
<p>{dashboardData.energyConsumed} kWh</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-white p-4 rounded shadow flex-1 min-w-[150px]">
|
<div className="bg-white p-4 rounded shadow flex-1 min-w-[150px]">
|
||||||
<h3>Tempo de Carregamento</h3>
|
<h3>Tempo de Carregamento</h3>
|
||||||
<p>{mockDashboardData.chargingTime} minutos</p>
|
<p>{dashboardData.chargingTime} minutos</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -39,7 +57,7 @@ const Dashboard = () => {
|
|||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h2 className="text-xl font-semibold mb-2">Alertas</h2>
|
<h2 className="text-xl font-semibold mb-2">Alertas</h2>
|
||||||
<ul>
|
<ul>
|
||||||
{mockDashboardData.alerts.map((alert, index) => (
|
{dashboardData.alerts.map((alert, index) => (
|
||||||
<li key={index} className="p-2 bg-red-500 text-white rounded mb-2">
|
<li key={index} className="p-2 bg-red-500 text-white rounded mb-2">
|
||||||
<span>⚠️ {alert}</span>
|
<span>⚠️ {alert}</span>
|
||||||
</li>
|
</li>
|
||||||
@@ -60,7 +78,7 @@ const Dashboard = () => {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{mockDashboardData.chargers.map((charger) => (
|
{dashboardData.chargers.map((charger) => (
|
||||||
<tr key={charger.id}>
|
<tr key={charger.id}>
|
||||||
<td className="border-b p-2">{charger.id}</td>
|
<td className="border-b p-2">{charger.id}</td>
|
||||||
<td className="border-b p-2">{charger.status}</td>
|
<td className="border-b p-2">{charger.status}</td>
|
||||||
|
|||||||
@@ -7,12 +7,13 @@ export default function ElectricalNetwork() {
|
|||||||
const [msg, setMsg] = useState('');
|
const [msg, setMsg] = useState('');
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
|
|
||||||
const [monitor, setMonitor] = useState({ voltage: '', current: '', quality: '' });
|
const [monitor, setMonitor] = useState({ voltage: '0', current: '0', quality: '0' });
|
||||||
const [alerts, setAlerts] = useState(false);
|
const [alerts, setAlerts] = useState(false);
|
||||||
const [security, setSecurity] = useState({ earthFault: false, rcm: false });
|
const [security, setSecurity] = useState({ earthFault: false, rcm: false });
|
||||||
const [loadBalancing, setLoadBalancing] = useState({ enabled: false, currentLimit: 32 });
|
const [loadBalancing, setLoadBalancing] = useState({ enabled: false, currentLimit: 0 });
|
||||||
const [solar, setSolar] = useState({ capacity: 0, useSolar: false, handleExcess: false });
|
const [solar, setSolar] = useState({ capacity: 0, useSolar: false, handleExcess: false });
|
||||||
|
|
||||||
|
// Função para carregar as configurações do backend
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const load = async () => {
|
const load = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -22,8 +23,9 @@ export default function ElectricalNetwork() {
|
|||||||
if (cfg.security) setSecurity(cfg.security);
|
if (cfg.security) setSecurity(cfg.security);
|
||||||
if (cfg.loadBalancing) setLoadBalancing(cfg.loadBalancing);
|
if (cfg.loadBalancing) setLoadBalancing(cfg.loadBalancing);
|
||||||
if (cfg.solar) setSolar(cfg.solar);
|
if (cfg.solar) setSolar(cfg.solar);
|
||||||
} catch {
|
} catch (err) {
|
||||||
// endpoint opcional
|
console.error('Erro ao carregar configurações:', err);
|
||||||
|
// Endpoint opcional, sem ações adicionais
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
@@ -31,6 +33,7 @@ export default function ElectricalNetwork() {
|
|||||||
load();
|
load();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Função para salvar as configurações no backend
|
||||||
const save = async () => {
|
const save = async () => {
|
||||||
setMsg('');
|
setMsg('');
|
||||||
setError('');
|
setError('');
|
||||||
@@ -38,7 +41,8 @@ export default function ElectricalNetwork() {
|
|||||||
const body = { monitor, alerts, security, loadBalancing, solar };
|
const body = { monitor, alerts, security, loadBalancing, solar };
|
||||||
await post('/api/v1/config/electrical', body);
|
await post('/api/v1/config/electrical', body);
|
||||||
setMsg('Configuração gravada com sucesso!');
|
setMsg('Configuração gravada com sucesso!');
|
||||||
} catch {
|
} catch (err) {
|
||||||
|
console.error('Erro ao salvar configuração:', err);
|
||||||
setError('Erro ao gravar configuração.');
|
setError('Erro ao gravar configuração.');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -53,33 +57,37 @@ export default function ElectricalNetwork() {
|
|||||||
) : (
|
) : (
|
||||||
<form className="flex flex-col gap-4" onSubmit={e => { e.preventDefault(); save(); }}>
|
<form className="flex flex-col gap-4" onSubmit={e => { e.preventDefault(); save(); }}>
|
||||||
<h2 className="text-xl font-semibold">Monitoramento da Rede Elétrica</h2>
|
<h2 className="text-xl font-semibold">Monitoramento da Rede Elétrica</h2>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block mb-1">Tensão de Entrada (V):</label>
|
<label className="block mb-1">Tensão de Entrada (V):</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
className="border border-gray-300 rounded px-3 py-2 w-full"
|
className="border border-gray-300 rounded px-3 py-2 w-full"
|
||||||
value={monitor.voltage}
|
value={monitor.voltage}
|
||||||
onChange={e => setMonitor({ ...monitor, voltage: e.target.value })}
|
disabled
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block mb-1">Corrente de Entrada (A):</label>
|
<label className="block mb-1">Corrente de Entrada (A):</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="text"
|
||||||
className="border border-gray-300 rounded px-3 py-2 w-full"
|
className="border border-gray-300 rounded px-3 py-2 w-full"
|
||||||
value={monitor.current}
|
value={monitor.current}
|
||||||
onChange={e => setMonitor({ ...monitor, current: e.target.value })}
|
disabled
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block mb-1">Qualidade de Energia:</label>
|
<label className="block mb-1">Qualidade de Energia:</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
className="border border-gray-300 rounded px-3 py-2 w-full"
|
className="border border-gray-300 rounded px-3 py-2 w-full"
|
||||||
value={monitor.quality}
|
value={monitor.quality}
|
||||||
onChange={e => setMonitor({ ...monitor, quality: e.target.value })}
|
disabled
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="flex items-center gap-2">
|
<label className="flex items-center gap-2">
|
||||||
Alertas de Falha na Rede
|
Alertas de Falha na Rede
|
||||||
@@ -124,6 +132,7 @@ export default function ElectricalNetwork() {
|
|||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<label className="block mb-1" htmlFor="lb-current">Limite de Corrente (A):</label>
|
<label className="block mb-1" htmlFor="lb-current">Limite de Corrente (A):</label>
|
||||||
<input
|
<input
|
||||||
@@ -166,12 +175,14 @@ export default function ElectricalNetwork() {
|
|||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<button className="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700" type="submit">Guardar</button>
|
<button className="bg-green-600 text-white px-4 py-2 rounded hover:bg-green-700" type="submit">
|
||||||
|
Guardar
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
)}
|
)}
|
||||||
</PageLayout>
|
</PageLayout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,21 +65,35 @@ const Security = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Usuários */}
|
{/* Utilizador */}
|
||||||
<div className="mb-5">
|
<div className="overflow-x-auto mb-5">
|
||||||
<h2 className="text-xl font-semibold mb-2">Usuários</h2>
|
<h2 className="text-xl font-semibold mb-4">Utilizador</h2>
|
||||||
<ul className="mb-3 space-y-2">
|
<table className="min-w-full border border-gray-300 text-left table-auto">
|
||||||
|
<thead className="bg-gray-100">
|
||||||
|
<tr>
|
||||||
|
<th className="border-b p-2 text-sm font-medium text-gray-700">Nome de Usuário</th>
|
||||||
|
<th className="border-b p-2 text-sm font-medium text-gray-700">Ações</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
{users.map((user, index) => (
|
{users.map((user, index) => (
|
||||||
<li key={index} className="flex items-center justify-between">
|
<tr key={index} className="hover:bg-gray-50">
|
||||||
<span>{user.username} - {user.role}</span>
|
<td className="border-b p-2 text-sm">{user.username}</td>
|
||||||
<button className="text-red-600" onClick={() => removeUser(user.username)}>Remover</button>
|
<td className="border-b p-2 text-sm text-red-600">
|
||||||
</li>
|
<button onClick={() => removeUser(user.username)}>Remover</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</tbody>
|
||||||
<div>
|
</table>
|
||||||
|
<div className="mt-4">
|
||||||
<button className="bg-green-600 text-white px-4 py-2 rounded" onClick={() => addUser('newuser', 'User')}>Adicionar Novo Usuário</button>
|
<button className="bg-green-600 text-white px-4 py-2 rounded" onClick={() => addUser('newuser', 'User')}>Adicionar Novo Usuário</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
// src/pages/Settings.jsx
|
import React, { useState, useEffect } from 'react';
|
||||||
import React, { useState } from 'react';
|
|
||||||
|
|
||||||
const Settings = () => {
|
const Settings = () => {
|
||||||
// Estados para armazenar os valores dos sliders e caixas de entrada
|
// Estados para armazenar os valores dos sliders e caixas de entrada
|
||||||
@@ -9,85 +8,104 @@ const Settings = () => {
|
|||||||
const [chargingTimeLimit, setChargingTimeLimit] = useState(0);
|
const [chargingTimeLimit, setChargingTimeLimit] = useState(0);
|
||||||
const [temperatureLimit, setTemperatureLimit] = useState(60);
|
const [temperatureLimit, setTemperatureLimit] = useState(60);
|
||||||
|
|
||||||
|
// Função para preencher os campos com os dados do servidor
|
||||||
|
const fetchSettings = async () => {
|
||||||
|
const response = await fetch('/api/v1/config/settings');
|
||||||
|
if (response.ok) {
|
||||||
|
const data = await response.json();
|
||||||
|
setCurrentLimit(data.currentLimit);
|
||||||
|
setPowerLimit(data.powerLimit);
|
||||||
|
setEnergyLimit(data.energyLimit);
|
||||||
|
setChargingTimeLimit(data.chargingTimeLimit);
|
||||||
|
setTemperatureLimit(data.temperatureLimit);
|
||||||
|
} else {
|
||||||
|
alert('Erro ao obter as configurações');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Carregar as configurações ao montar o componente
|
||||||
|
useEffect(() => {
|
||||||
|
fetchSettings();
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleCurrentLimitChange = (e) => setCurrentLimit(e.target.value);
|
const handleCurrentLimitChange = (e) => setCurrentLimit(e.target.value);
|
||||||
const handlePowerLimitChange = (e) => setPowerLimit(e.target.value);
|
const handlePowerLimitChange = (e) => setPowerLimit(e.target.value);
|
||||||
const handleEnergyLimitChange = (e) => setEnergyLimit(e.target.value);
|
const handleEnergyLimitChange = (e) => setEnergyLimit(e.target.value);
|
||||||
const handleChargingTimeLimitChange = (e) => setChargingTimeLimit(e.target.value);
|
const handleChargingTimeLimitChange = (e) => setChargingTimeLimit(e.target.value);
|
||||||
const handleTemperatureLimitChange = (e) => setTemperatureLimit(e.target.value);
|
const handleTemperatureLimitChange = (e) => setTemperatureLimit(e.target.value);
|
||||||
|
|
||||||
return (
|
const handleSubmit = async () => {
|
||||||
<div className="max-w-xl mx-auto p-5 bg-white rounded shadow">
|
const settingsData = {
|
||||||
<h1 className="text-2xl font-bold mb-5 text-center">Configurações Gerais</h1>
|
currentLimit,
|
||||||
|
powerLimit,
|
||||||
|
energyLimit,
|
||||||
|
chargingTimeLimit,
|
||||||
|
temperatureLimit,
|
||||||
|
};
|
||||||
|
|
||||||
<div className="mb-5">
|
const response = await fetch('/api/v1/config/settings', {
|
||||||
<label className="block mb-2">Corrente Máxima de Carregamento (A):</label>
|
method: 'POST',
|
||||||
<div className="flex items-center justify-between">
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(settingsData),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.ok) {
|
||||||
|
alert('Configurações de energia atualizadas com sucesso!');
|
||||||
|
} else {
|
||||||
|
alert('Erro ao atualizar configurações');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<label>
|
||||||
|
Current Limit:
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="number"
|
||||||
min="5"
|
|
||||||
max="32"
|
|
||||||
className="flex-1"
|
|
||||||
value={currentLimit}
|
value={currentLimit}
|
||||||
onChange={handleCurrentLimitChange}
|
onChange={handleCurrentLimitChange}
|
||||||
/>
|
/>
|
||||||
<span>{currentLimit} A</span>
|
</label>
|
||||||
</div>
|
<br />
|
||||||
</div>
|
<label>
|
||||||
|
Power Limit:
|
||||||
<div className="mb-5">
|
|
||||||
<label className="block mb-2">Limite de Potência Máxima (W):</label>
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="number"
|
||||||
min="1000"
|
|
||||||
max="10000"
|
|
||||||
className="flex-1"
|
|
||||||
value={powerLimit}
|
value={powerLimit}
|
||||||
onChange={handlePowerLimitChange}
|
onChange={handlePowerLimitChange}
|
||||||
/>
|
/>
|
||||||
<span>{powerLimit} W</span>
|
</label>
|
||||||
</div>
|
<br />
|
||||||
</div>
|
<label>
|
||||||
|
Energy Limit:
|
||||||
<div className="mb-5">
|
|
||||||
<label className="block mb-2">Limite de Consumo Total de Energia (kWh):</label>
|
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
min="0"
|
|
||||||
className="w-full p-2 border rounded"
|
|
||||||
value={energyLimit}
|
value={energyLimit}
|
||||||
onChange={handleEnergyLimitChange}
|
onChange={handleEnergyLimitChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</label>
|
||||||
|
<br />
|
||||||
<div className="mb-5">
|
<label>
|
||||||
<label className="block mb-2">Limite de Tempo de Carregamento (h):</label>
|
Charging Time Limit:
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
min="1"
|
|
||||||
max="24"
|
|
||||||
className="w-full p-2 border rounded"
|
|
||||||
value={chargingTimeLimit}
|
value={chargingTimeLimit}
|
||||||
onChange={handleChargingTimeLimitChange}
|
onChange={handleChargingTimeLimitChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</label>
|
||||||
|
<br />
|
||||||
<div className="mb-5">
|
<label>
|
||||||
<label className="block mb-2">Limite de Temperatura Máxima do EVSE (ºC):</label>
|
Temperature Limit:
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<input
|
<input
|
||||||
type="range"
|
type="number"
|
||||||
min="60"
|
|
||||||
max="80"
|
|
||||||
className="flex-1"
|
|
||||||
value={temperatureLimit}
|
value={temperatureLimit}
|
||||||
onChange={handleTemperatureLimitChange}
|
onChange={handleTemperatureLimitChange}
|
||||||
/>
|
/>
|
||||||
<span>{temperatureLimit} ºC</span>
|
</label>
|
||||||
</div>
|
<br />
|
||||||
</div>
|
<button onClick={handleSubmit}>Save Settings</button>
|
||||||
|
|
||||||
<button className="bg-green-600 text-white w-full mt-4 p-2 rounded hover:bg-green-700">Salvar Configurações</button>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
11
tailwind.config.js
Executable file
11
tailwind.config.js
Executable file
@@ -0,0 +1,11 @@
|
|||||||
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
module.exports = {
|
||||||
|
content: [
|
||||||
|
"./index.html",
|
||||||
|
"./src/**/*.{js,jsx,ts,tsx}",
|
||||||
|
],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [],
|
||||||
|
}
|
||||||
@@ -7,10 +7,16 @@ export default defineConfig({
|
|||||||
port: 5173, // ou outro, se necessário
|
port: 5173, // ou outro, se necessário
|
||||||
proxy: {
|
proxy: {
|
||||||
'/api': {
|
'/api': {
|
||||||
target: 'http://127.0.0.1:8080',
|
target: 'http://127.0.0.1:8080', // Alvo para redirecionar as requisições
|
||||||
changeOrigin: true,
|
changeOrigin: true, // Garante que a origem seja alterada para o alvo do proxy
|
||||||
secure: false
|
secure: false // Desabilita a validação de SSL (útil para desenvolvimento em HTTP)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
outDir: 'dist', // Defina o diretório de saída (padrão é 'dist')
|
||||||
|
minify: 'esbuild', // Usa o esbuild para minimizar o código para produção
|
||||||
|
sourcemap: false, // Desativa a criação de mapas de fonte (se não for necessário)
|
||||||
|
// Outras opções de otimização de produção podem ser configuradas aqui, se necessário
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user