Adresse wird aufgelöst
Optik augehübscht
This commit is contained in:
232
public/global.js
232
public/global.js
@@ -1,76 +1,172 @@
|
||||
const resultEl = document.getElementById('result');
|
||||
const espIn = document.getElementById('espId');
|
||||
const sensorIn = document.getElementById('sensorNumber');
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const saveBtn = document.getElementById('saveBtn');
|
||||
const refreshBtn = document.getElementById('refreshBtn');
|
||||
const espIdInput = document.getElementById('espId');
|
||||
const sensorNumberInput = document.getElementById('sensorNumber');
|
||||
const nameInput = document.getElementById('name');
|
||||
const descriptionInput = document.getElementById('description');
|
||||
const addressInput = document.getElementById('address');
|
||||
const pageInput = document.getElementById('page');
|
||||
const limitInput = document.getElementById('limit');
|
||||
const resultDiv = document.getElementById('result');
|
||||
const tableBody = document.querySelector('#entriesTable tbody');
|
||||
|
||||
document.getElementById('saveBtn').addEventListener('click', async () => {
|
||||
const espId = espIn.value.trim();
|
||||
const sensorNumber = sensorIn.value.trim();
|
||||
if (!espId || !sensorNumber) {
|
||||
resultEl.innerText = 'Bitte ESP-ID und Sensornummer eingeben.';
|
||||
return;
|
||||
}
|
||||
resultEl.innerText = 'Speichere...';
|
||||
try {
|
||||
const r = await fetch('/api/save', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type':'application/json'},
|
||||
body: JSON.stringify({ espId, sensorNumber })
|
||||
});
|
||||
const j = await r.json();
|
||||
if (j.ok) {
|
||||
resultEl.innerHTML = `<strong>Gespeichert:</strong> ESP-ID = ${j.entry.espId}, Sensor = ${j.entry.sensorNumber}`;
|
||||
espIn.value = '';
|
||||
sensorIn.value = '';
|
||||
loadList();
|
||||
} else {
|
||||
resultEl.innerText = 'Fehler: ' + (j.error || 'Unbekannt');
|
||||
let editId = null;
|
||||
|
||||
// Sensornummer nur Zahlen erlauben
|
||||
sensorNumberInput.addEventListener('input', () => {
|
||||
sensorNumberInput.value = sensorNumberInput.value.replace(/\D/g, '');
|
||||
});
|
||||
|
||||
// Adresse vom Server holen, wenn Enter oder Feld verlassen
|
||||
async function fetchAddressIfValid() {
|
||||
const value = sensorNumberInput.value.trim();
|
||||
if (value.length > 0) {
|
||||
try {
|
||||
const res = await fetch(`/api/address/${value}`);
|
||||
const data = await res.json();
|
||||
if (!data.error && data.address) {
|
||||
addressInput.value = data.address;
|
||||
} else {
|
||||
addressInput.value = '';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('Fehler beim Abrufen der Adresse:', err);
|
||||
}
|
||||
} catch {
|
||||
resultEl.innerText = 'Netzwerkfehler';
|
||||
}
|
||||
}
|
||||
|
||||
// Enter-Taste
|
||||
sensorNumberInput.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
e.preventDefault();
|
||||
fetchAddressIfValid();
|
||||
}
|
||||
});
|
||||
|
||||
async function loadList() {
|
||||
const page = document.getElementById('page').value || 1;
|
||||
const limit = document.getElementById('limit').value || 25;
|
||||
const listEl = document.getElementById('list');
|
||||
listEl.innerText = 'Lade...';
|
||||
try {
|
||||
const r = await fetch(`/api/list?page=${encodeURIComponent(page)}&limit=${encodeURIComponent(limit)}`);
|
||||
const j = await r.json();
|
||||
if (!j.ok) { listEl.innerText = 'Fehler beim Laden'; return; }
|
||||
if (j.items.length === 0) { listEl.innerText = 'Keine Einträge'; return;}
|
||||
let html = `<div>Ergebnis: ${j.items.length} von ${j.total} (Seite ${j.page})</div>`;
|
||||
html += '<table><thead><tr><th>Datum</th><th>ESP-ID</th><th>Sensor</th><th></th></tr></thead><tbody>';
|
||||
j.items.forEach(it => {
|
||||
html += `<tr>
|
||||
<td>${it.createdAt}</td>
|
||||
<td>${it.espId}</td>
|
||||
<td>${it.sensorNumber}</td>
|
||||
<td><button onclick="deleteEntry('${it._id}')">Löschen</button></td>
|
||||
</tr>`;
|
||||
});
|
||||
html += '</tbody></table>';
|
||||
listEl.innerHTML = html;
|
||||
} catch {
|
||||
listEl.innerText = 'Netzwerkfehler beim Laden';
|
||||
}
|
||||
}
|
||||
// Feld verlassen
|
||||
sensorNumberInput.addEventListener('blur', fetchAddressIfValid);
|
||||
|
||||
async function deleteEntry(id) {
|
||||
if (!confirm('Diesen Eintrag wirklich löschen?')) return;
|
||||
try {
|
||||
const r = await fetch(`/api/entry/${id}`, { method: 'DELETE' });
|
||||
const j = await r.json();
|
||||
if (j.ok) {
|
||||
loadList();
|
||||
} else {
|
||||
alert('Fehler beim Löschen');
|
||||
|
||||
async function saveEntry() {
|
||||
const espId = espIdInput.value.trim();
|
||||
const sensorNumber = sensorNumberInput.value.trim();
|
||||
const name = nameInput.value.trim();
|
||||
const description = descriptionInput.value.trim();
|
||||
const address = addressInput.value.trim();
|
||||
|
||||
if (!espId || !sensorNumber) {
|
||||
resultDiv.textContent = 'ESP-ID und Sensornummer sind Pflichtfelder.';
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
alert('Netzwerkfehler');
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('refreshBtn').addEventListener('click', loadList);
|
||||
loadList();
|
||||
try {
|
||||
const url = editId ? `/api/update/${editId}` : '/api/save';
|
||||
const method = editId ? 'PUT' : 'POST';
|
||||
|
||||
const res = await fetch(url, {
|
||||
method,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ espId, sensorNumber, name, description, address })
|
||||
});
|
||||
|
||||
const data = await res.json();
|
||||
if (data.error) {
|
||||
resultDiv.textContent = data.error;
|
||||
} else {
|
||||
resultDiv.textContent = editId ? 'Aktualisiert!' : 'Gespeichert!';
|
||||
clearForm();
|
||||
await loadEntries();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
resultDiv.textContent = 'Fehler beim Speichern.';
|
||||
}
|
||||
}
|
||||
|
||||
function clearForm() {
|
||||
espIdInput.value = '';
|
||||
sensorNumberInput.value = '';
|
||||
nameInput.value = '';
|
||||
descriptionInput.value = '';
|
||||
addressInput.value = '';
|
||||
editId = null;
|
||||
saveBtn.textContent = 'Speichern';
|
||||
}
|
||||
|
||||
async function loadEntries() {
|
||||
const page = parseInt(pageInput.value) || 1;
|
||||
const limit = parseInt(limitInput.value) || 10;
|
||||
|
||||
try {
|
||||
const res = await fetch(`/api/list?page=${page}&limit=${limit}`);
|
||||
const items = await res.json();
|
||||
|
||||
tableBody.innerHTML = '';
|
||||
items.forEach(item => {
|
||||
const date = new Date(item.createdAt).toISOString().split('T')[0];
|
||||
const tr = document.createElement('tr');
|
||||
tr.innerHTML = `
|
||||
<td>${item.espId}</td>
|
||||
<td>${item.sensorNumber}</td>
|
||||
<td>${item.name || ''}</td>
|
||||
<td>${item.description || ''}</td>
|
||||
<td>${item.address || ''}</td>
|
||||
<td>${date}</td>
|
||||
<td>
|
||||
<button data-id="${item._id}" class="editBtn">Bearbeiten</button>
|
||||
<button data-id="${item._id}" class="deleteBtn">Löschen</button>
|
||||
</td>
|
||||
`;
|
||||
tableBody.appendChild(tr);
|
||||
});
|
||||
|
||||
document.querySelectorAll('.deleteBtn').forEach(btn => {
|
||||
btn.addEventListener('click', async () => {
|
||||
const id = btn.getAttribute('data-id');
|
||||
await deleteEntry(id);
|
||||
});
|
||||
});
|
||||
|
||||
document.querySelectorAll('.editBtn').forEach(btn => {
|
||||
btn.addEventListener('click', async () => {
|
||||
const id = btn.getAttribute('data-id');
|
||||
const res = await fetch(`/api/list?page=1&limit=1&id=${id}`);
|
||||
const items = await res.json();
|
||||
const item = items.find(e => e._id === id);
|
||||
if (item) {
|
||||
espIdInput.value = item.espId;
|
||||
sensorNumberInput.value = item.sensorNumber;
|
||||
nameInput.value = item.name || '';
|
||||
descriptionInput.value = item.description || '';
|
||||
addressInput.value = item.address || '';
|
||||
editId = id;
|
||||
saveBtn.textContent = 'Aktualisieren';
|
||||
}
|
||||
});
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
resultDiv.textContent = 'Fehler beim Laden.';
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteEntry(id) {
|
||||
if (!confirm('Wirklich löschen?')) return;
|
||||
try {
|
||||
const res = await fetch(`/api/delete/${id}`, { method: 'DELETE' });
|
||||
const data = await res.json();
|
||||
if (data.success) {
|
||||
await loadEntries();
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
resultDiv.textContent = 'Fehler beim Löschen.';
|
||||
}
|
||||
}
|
||||
|
||||
saveBtn.addEventListener('click', saveEntry);
|
||||
refreshBtn.addEventListener('click', loadEntries);
|
||||
|
||||
loadEntries();
|
||||
});
|
||||
34
public/login.js
Normal file
34
public/login.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// public/login.js
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const emailInput = document.getElementById('email');
|
||||
const emailStatus = document.getElementById('emailStatus');
|
||||
let debounceTimeout;
|
||||
|
||||
emailInput.addEventListener('input', () => {
|
||||
clearTimeout(debounceTimeout);
|
||||
const email = emailInput.value.trim();
|
||||
|
||||
if (!email) {
|
||||
emailStatus.textContent = '';
|
||||
return;
|
||||
}
|
||||
|
||||
debounceTimeout = setTimeout(async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/check-email?email=${encodeURIComponent(email)}`);
|
||||
const data = await res.json();
|
||||
if (data.exists) {
|
||||
emailStatus.textContent = '✅ Benutzer existiert';
|
||||
emailStatus.style.color = 'green';
|
||||
} else {
|
||||
emailStatus.textContent = '❌ Benutzer nicht gefunden';
|
||||
emailStatus.style.color = 'red';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
emailStatus.textContent = 'Fehler bei der Prüfung';
|
||||
emailStatus.style.color = 'orange';
|
||||
}
|
||||
}, 300);
|
||||
});
|
||||
});
|
||||
37
public/register.js
Normal file
37
public/register.js
Normal file
@@ -0,0 +1,37 @@
|
||||
// public/register.js
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const emailInput = document.getElementById('email');
|
||||
const emailStatus = document.getElementById('emailStatus');
|
||||
|
||||
let debounceTimeout;
|
||||
|
||||
emailInput.addEventListener('input', () => {
|
||||
clearTimeout(debounceTimeout);
|
||||
const email = emailInput.value.trim();
|
||||
|
||||
if (!email) {
|
||||
emailStatus.textContent = '';
|
||||
return;
|
||||
}
|
||||
|
||||
// 300ms warten, um zu vermeiden, dass bei jedem Tastendruck eine Anfrage rausgeht
|
||||
debounceTimeout = setTimeout(async () => {
|
||||
try {
|
||||
const res = await fetch(`/api/check-email?email=${encodeURIComponent(email)}`);
|
||||
const data = await res.json();
|
||||
if (data.exists) {
|
||||
emailStatus.textContent = '❌ Diese E-Mail ist schon vergeben';
|
||||
emailStatus.style.color = 'red';
|
||||
} else {
|
||||
emailStatus.textContent = '✅ E-Mail ist frei';
|
||||
emailStatus.style.color = 'green';
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
emailStatus.textContent = 'Fehler bei der Prüfung';
|
||||
emailStatus.style.color = 'orange';
|
||||
}
|
||||
}, 300);
|
||||
});
|
||||
});
|
||||
@@ -51,4 +51,71 @@ th, td {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
form {
|
||||
max-width: 400px;
|
||||
margin: 0 auto;
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
background: #f9f9f9;
|
||||
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: 0.4rem;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0.6rem;
|
||||
border: none;
|
||||
border-radius: 4px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
font-size: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: #0056b3;
|
||||
}
|
||||
|
||||
p.error {
|
||||
color: red;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.card form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start; /* Links bündig */
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.card form label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.card form input,
|
||||
.card form textarea {
|
||||
width: 100%;
|
||||
max-width: 400px; /* gleiche Breite */
|
||||
padding: 0.4rem;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.card form textarea {
|
||||
min-height: 60px;
|
||||
resize: vertical;
|
||||
}
|
||||
Reference in New Issue
Block a user