Lead Management Usability Upgrade

Dieser Commit ist enthalten in:
2025-06-22 21:12:02 +02:00
Ursprung 45e236ff1b
Commit 4a139464d1
2 geänderte Dateien mit 343 neuen und 143 gelöschten Zeilen

Datei anzeigen

@@ -2,6 +2,28 @@
{% block title %}Lead Management{% endblock %}
{% block extra_css %}
<style>
.nav-tabs .nav-link {
color: #495057;
border: 1px solid transparent;
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
}
.nav-tabs .nav-link.active {
color: #495057;
background-color: #fff;
border-color: #dee2e6 #dee2e6 #fff;
}
.tab-content {
border: 1px solid #dee2e6;
border-top: none;
padding: 1.5rem;
background-color: #fff;
}
</style>
{% endblock %}
{% block content %}
<div class="container py-5">
<div class="mb-4">
@@ -33,11 +55,11 @@
<div class="card-body">
<h5 class="card-title">Schnellaktionen</h5>
<div class="d-flex gap-2">
<a href="{{ url_for('leads.institutions') }}" class="btn btn-primary">
<i class="bi bi-building"></i> Institutionen anzeigen
</a>
<button class="btn btn-success" data-bs-toggle="modal" data-bs-target="#addInstitutionModal">
<i class="bi bi-plus"></i> Institution hinzufügen
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addInstitutionModal">
<i class="bi bi-building-add"></i> Institution hinzufügen
</button>
<button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addContactModal">
<i class="bi bi-person-plus"></i> Kontakt hinzufügen
</button>
<a href="{{ url_for('leads.export_leads') }}" class="btn btn-outline-secondary">
<i class="bi bi-download"></i> Exportieren
@@ -46,71 +68,161 @@
</div>
</div>
<!-- Recent Activity -->
<div class="card mb-4">
<div class="card-header">
<h5 class="mb-0">Letzte Aktivitäten</h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Zeitpunkt</th>
<th>Benutzer</th>
<th>Aktion</th>
<th>Details</th>
</tr>
</thead>
<tbody>
{% for activity in recent_activities %}
<tr>
<td>{{ activity.timestamp.strftime('%d.%m.%Y %H:%M') }}</td>
<td>
<span class="badge bg-{{ 'primary' if activity.username == session.username else 'secondary' }}">
{{ activity.username }}
</span>
</td>
<td>
{% if activity.action == 'CREATE' %}
<span class="text-success"> Erstellt</span>
{% elif activity.action == 'UPDATE' %}
<span class="text-info">✏️ Bearbeitet</span>
{% elif activity.action == 'DELETE' %}
<span class="text-danger">🗑️ Gelöscht</span>
{% endif %}
</td>
<td>
{{ activity.entity_type|title }}
{% if activity.additional_info %}
- {{ activity.additional_info }}
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if not recent_activities %}
<p class="text-muted text-center py-3">Noch keine Aktivitäten vorhanden.</p>
{% endif %}
</div>
</div>
</div>
<!-- Search -->
<!-- Tabbed View -->
<div class="card">
<div class="card-header">
<h5 class="mb-0">Suche</h5>
</div>
<div class="card-body">
<form method="get" action="{{ url_for('leads.institutions') }}">
<div class="input-group">
<input type="text" class="form-control" name="search" placeholder="Nach Institution oder Kontakt suchen...">
<button class="btn btn-primary" type="submit">
<i class="bi bi-search"></i> Suchen
<div class="card-body p-0">
<!-- Tabs -->
<ul class="nav nav-tabs" id="leadTabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="institutions-tab" data-bs-toggle="tab" data-bs-target="#institutions" type="button" role="tab">
<i class="bi bi-building"></i> Institutionen
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="contacts-tab" data-bs-toggle="tab" data-bs-target="#contacts" type="button" role="tab">
<i class="bi bi-people"></i> Kontakte
</button>
</li>
</ul>
<!-- Tab Content -->
<div class="tab-content" id="leadTabContent">
<!-- Institutions Tab -->
<div class="tab-pane fade show active" id="institutions" role="tabpanel">
<!-- Filter for Institutions -->
<div class="row mb-3">
<div class="col-md-6">
<input type="text" class="form-control" id="institutionSearch" placeholder="Institution suchen...">
</div>
<div class="col-md-3">
<select class="form-select" id="institutionSort">
<option value="name">Alphabetisch</option>
<option value="date">Datum hinzugefügt</option>
<option value="contacts">Anzahl Kontakte</option>
</select>
</div>
<div class="col-md-3">
<button class="btn btn-outline-primary w-100" id="filterNoContacts">
<i class="bi bi-funnel"></i> Ohne Kontakte
</button>
</div>
</div>
<!-- Institutions List -->
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Name</th>
<th>Anzahl Kontakte</th>
<th>Erstellt am</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
{% for institution in institutions %}
<tr>
<td>
<a href="{{ url_for('leads.institution_detail', institution_id=institution.id) }}">
{{ institution.name }}
</a>
</td>
<td>{{ institution.contact_count }}</td>
<td>{{ institution.created_at.strftime('%d.%m.%Y') }}</td>
<td>
<a href="{{ url_for('leads.institution_detail', institution_id=institution.id) }}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i> Details
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if not institutions %}
<p class="text-muted text-center py-3">Keine Institutionen vorhanden.</p>
{% endif %}
</div>
</div>
</form>
<!-- Contacts Tab -->
<div class="tab-pane fade" id="contacts" role="tabpanel">
<!-- Filter for Contacts -->
<div class="row mb-3">
<div class="col-md-4">
<input type="text" class="form-control" id="contactSearch" placeholder="Kontakt suchen...">
</div>
<div class="col-md-3">
<select class="form-select" id="institutionFilter">
<option value="">Alle Institutionen</option>
{% for institution in institutions %}
<option value="{{ institution.id }}">{{ institution.name }}</option>
{% endfor %}
</select>
</div>
<div class="col-md-2">
<button class="btn btn-outline-primary w-100" id="filterNoEmail">
<i class="bi bi-envelope-slash"></i> Ohne E-Mail
</button>
</div>
<div class="col-md-3">
<button class="btn btn-outline-primary w-100" id="filterNoPhone">
<i class="bi bi-telephone-x"></i> Ohne Telefon
</button>
</div>
</div>
<!-- Contacts List -->
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>Name</th>
<th>Position</th>
<th>Institution</th>
<th>E-Mail</th>
<th>Telefon</th>
<th>Aktionen</th>
</tr>
</thead>
<tbody>
{% for contact in all_contacts %}
<tr>
<td>
<a href="{{ url_for('leads.contact_detail', contact_id=contact.id) }}">
{{ contact.first_name }} {{ contact.last_name }}
</a>
</td>
<td>{{ contact.position or '-' }}</td>
<td>{{ contact.institution_name }}</td>
<td>
{% if contact.emails %}
<small>{{ contact.emails[0] }}</small>
{% else %}
<span class="text-muted">-</span>
{% endif %}
</td>
<td>
{% if contact.phones %}
<small>{{ contact.phones[0] }}</small>
{% else %}
<span class="text-muted">-</span>
{% endif %}
</td>
<td>
<a href="{{ url_for('leads.contact_detail', contact_id=contact.id) }}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i> Details
</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% if not all_contacts %}
<p class="text-muted text-center py-3">Keine Kontakte vorhanden.</p>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
@@ -138,4 +250,118 @@
</div>
</div>
</div>
<!-- Add Contact Modal -->
<div class="modal fade" id="addContactModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<form method="POST" action="{{ url_for('leads.add_contact') }}">
<div class="modal-header">
<h5 class="modal-title">Neuen Kontakt hinzufügen</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<div class="mb-3">
<label for="institution_id" class="form-label">Institution</label>
<select class="form-select" id="institution_id" name="institution_id" required>
<option value="">Bitte wählen...</option>
{% for institution in institutions %}
<option value="{{ institution.id }}">{{ institution.name }}</option>
{% endfor %}
</select>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="first_name" class="form-label">Vorname</label>
<input type="text" class="form-control" id="first_name" name="first_name" required>
</div>
<div class="col-md-6 mb-3">
<label for="last_name" class="form-label">Nachname</label>
<input type="text" class="form-control" id="last_name" name="last_name" required>
</div>
</div>
<div class="mb-3">
<label for="position" class="form-label">Position</label>
<input type="text" class="form-control" id="position" name="position">
</div>
<div class="mb-3">
<label for="email" class="form-label">E-Mail</label>
<input type="email" class="form-control" id="email" name="email">
</div>
<div class="mb-3">
<label for="phone" class="form-label">Telefon</label>
<input type="tel" class="form-control" id="phone" name="phone">
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Abbrechen</button>
<button type="submit" class="btn btn-primary">Hinzufügen</button>
</div>
</form>
</div>
</div>
</div>
{% endblock %}
{% block extra_js %}
<script>
// Filter functionality
document.addEventListener('DOMContentLoaded', function() {
// Institution search
const institutionSearch = document.getElementById('institutionSearch');
if (institutionSearch) {
institutionSearch.addEventListener('input', function() {
filterTable('institutions', this.value.toLowerCase(), 0);
});
}
// Contact search
const contactSearch = document.getElementById('contactSearch');
if (contactSearch) {
contactSearch.addEventListener('input', function() {
filterTable('contacts', this.value.toLowerCase(), [0, 1, 2]);
});
}
// Filter table function
function filterTable(tabId, searchTerm, columnIndices) {
const table = document.querySelector(`#${tabId} table tbody`);
const rows = table.getElementsByTagName('tr');
Array.from(rows).forEach(row => {
let match = false;
const indices = Array.isArray(columnIndices) ? columnIndices : [columnIndices];
indices.forEach(index => {
const cell = row.getElementsByTagName('td')[index];
if (cell && cell.textContent.toLowerCase().includes(searchTerm)) {
match = true;
}
});
row.style.display = match || searchTerm === '' ? '' : 'none';
});
}
// Institution filter
const institutionFilter = document.getElementById('institutionFilter');
if (institutionFilter) {
institutionFilter.addEventListener('change', function() {
const selectedInstitution = this.value;
const table = document.querySelector('#contacts table tbody');
const rows = table.getElementsByTagName('tr');
Array.from(rows).forEach(row => {
const institutionCell = row.getElementsByTagName('td')[2];
if (selectedInstitution === '' || institutionCell.textContent === this.options[this.selectedIndex].text) {
row.style.display = '';
} else {
row.style.display = 'none';
}
});
});
}
});
</script>
{% endblock %}