Initial commit

This commit is contained in:
2025-03-17 19:57:41 +01:00
commit 5a2806c1cd
7 changed files with 530 additions and 0 deletions

209
templates/index.html Normal file
View File

@@ -0,0 +1,209 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>medisoftware Kundensuche</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
min-height: 100vh;
display: flex;
flex-direction: column;
margin: 0;
padding: 0;
}
.main-content {
flex: 1 0 auto;
padding: 2rem 0;
}
.search-container {
max-width: 800px;
margin: 0 auto;
}
.result-card {
margin-bottom: 1rem;
transition: all 0.3s ease;
}
.result-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0,0,0,0.1);
}
.loading {
display: none;
text-align: center;
margin: 2rem 0;
}
.phone-link, .email-link, .address-link, .customer-link {
text-decoration: none;
color: #0d6efd;
}
.phone-link:hover, .email-link:hover, .address-link:hover, .customer-link:hover {
text-decoration: underline;
}
.search-icon {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
color: #6c757d;
}
.customer-number {
color: #6c757d;
font-size: 0.9em;
}
.footer {
flex-shrink: 0;
text-align: center;
padding: 1rem;
background-color: #f8f9fa;
border-top: 1px solid #dee2e6;
width: 100%;
}
</style>
</head>
<body>
<div class="main-content">
<div class="container search-container">
<h1 class="text-center mb-4">medisoftware Kundensuche</h1>
<div class="input-group mb-4 position-relative">
<input type="text" id="searchInput" class="form-control form-control-lg"
placeholder="Suchen Sie nach Name, Fachrichtung, Ort oder Kundennummer...">
<span class="search-icon">🔍</span>
</div>
<div id="loading" class="loading">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Laden...</span>
</div>
</div>
<div id="results" class="mt-4">
<!-- Hier werden die Suchergebnisse angezeigt -->
</div>
</div>
</div>
<footer class="footer">
<p class="mb-0">(c) 2025 <a href="https://medisoftware.de" target="_blank" rel="noopener noreferrer" class="text-decoration-none">medisoftware</a></p>
</footer>
<script>
let searchTimeout;
function createPhoneLink(phone) {
if (!phone) return 'N/A';
// Entferne alle nicht-numerischen Zeichen für den tel: Link
const cleaned = phone.replace(/\D/g, '');
// Füge immer eine führende 0 hinzu
const telLink = '0' + cleaned;
// Zeige die ursprüngliche Nummer an
return `<a href="tel:${telLink}" class="phone-link">${phone}</a>`;
}
function createEmailLink(email) {
if (!email) return 'N/A';
return `<a href="mailto:${email}" class="email-link">${email}</a>`;
}
function createAddressLink(street, plz, city) {
if (!street || !plz || !city) return 'N/A';
const address = `${street}, ${plz} ${city}`;
const searchQuery = encodeURIComponent(address);
return `<a href="https://www.google.com/maps/search/?api=1&query=${searchQuery}"
class="address-link" target="_blank" rel="noopener noreferrer">
${address}
<span class="ms-1">🗺️</span>
</a>`;
}
function createCustomerLink(customerNumber) {
if (!customerNumber) return 'N/A';
return `<a href="medisw:openkkbefe/P${customerNumber}?NetGrp=4"
class="customer-link" target="_blank" rel="noopener noreferrer">
${customerNumber}
</a>`;
}
function searchCustomers() {
const query = document.getElementById('searchInput').value;
if (query.length < 2) {
document.getElementById('results').innerHTML = '';
return;
}
// Lade-Animation anzeigen
document.getElementById('loading').style.display = 'block';
document.getElementById('results').innerHTML = '';
fetch(`/search?q=${encodeURIComponent(query)}`)
.then(response => {
if (!response.ok) {
return response.json().then(data => {
throw new Error(data.error || 'Ein Fehler ist aufgetreten');
});
}
return response.json();
})
.then(data => {
const resultsDiv = document.getElementById('results');
resultsDiv.innerHTML = '';
if (data.length === 0) {
resultsDiv.innerHTML = '<div class="alert alert-info">Keine Ergebnisse gefunden.</div>';
return;
}
data.forEach(customer => {
const card = document.createElement('div');
card.className = 'card result-card';
card.innerHTML = `
<div class="card-body">
<h5 class="card-title">
${customer.Vorname} ${customer.Nachname}
<span class="customer-number ms-2">(Kunde: ${createCustomerLink(customer.Nummer)})</span>
</h5>
<p class="card-text">
<strong>Fachrichtung:</strong> ${customer.Fachrichtung || 'N/A'}<br>
<strong>Adresse:</strong> ${createAddressLink(customer.Strasse, customer.PLZ, customer.Ort)}<br>
<strong>Telefon:</strong> ${createPhoneLink(customer.Tel)}<br>
<strong>E-Mail:</strong> ${createEmailLink(customer.mail)}
</p>
</div>
`;
resultsDiv.appendChild(card);
});
})
.catch(error => {
console.error('Fehler:', error);
document.getElementById('results').innerHTML =
`<div class="alert alert-danger">${error.message}</div>`;
})
.finally(() => {
// Lade-Animation ausblenden
document.getElementById('loading').style.display = 'none';
});
}
// Event-Listener für die Live-Suche
document.getElementById('searchInput').addEventListener('input', function(e) {
// Clear previous timeout
clearTimeout(searchTimeout);
// Set new timeout
searchTimeout = setTimeout(() => {
searchCustomers();
}, 300); // 300ms Verzögerung
});
// Suche bei Enter-Taste
document.getElementById('searchInput').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
clearTimeout(searchTimeout);
searchCustomers();
}
});
</script>
</body>
</html>