Ansprechpartner-Felder für Willkommensseite mit Markdown-Support
This commit is contained in:
27
app.py
27
app.py
@@ -685,6 +685,7 @@ def add_customer():
|
||||
success = None
|
||||
logo_urls = [None, None, None]
|
||||
customer_names = ["", "", ""]
|
||||
contacts = ["", "", ""]
|
||||
site = request.args.get("site") or request.form.get("site") or ""
|
||||
|
||||
# Fallback auf ersten für den User zugänglichen Standort
|
||||
@@ -703,6 +704,11 @@ def add_customer():
|
||||
request.form.get("customer_name_2", "").strip(),
|
||||
request.form.get("customer_name_3", "").strip(),
|
||||
]
|
||||
contacts = [
|
||||
request.form.get("contact_1", "").strip(),
|
||||
request.form.get("contact_2", "").strip(),
|
||||
request.form.get("contact_3", "").strip(),
|
||||
]
|
||||
filled_names = [n for n in customer_names if n]
|
||||
|
||||
print(f"🔍 APP.PY - Suche nach Kunden: {filled_names} (site: {site})")
|
||||
@@ -725,6 +731,14 @@ def add_customer():
|
||||
else:
|
||||
valid_names = [n for n, l in valid]
|
||||
valid_urls = [l for n, l in valid]
|
||||
valid_contacts = []
|
||||
for name in valid_names:
|
||||
for i, cn in enumerate(customer_names):
|
||||
if cn == name:
|
||||
valid_contacts.append(contacts[i] if i < len(contacts) else "")
|
||||
break
|
||||
else:
|
||||
valid_contacts.append("")
|
||||
for i, name in enumerate(customer_names):
|
||||
for j, (vn, vu) in enumerate(zip(valid_names, valid_urls)):
|
||||
if vn == name:
|
||||
@@ -732,14 +746,14 @@ def add_customer():
|
||||
break
|
||||
|
||||
bg_url = get_background_url(site)
|
||||
html_filename = generate_welcome_page.save_welcome_page(valid_names, valid_urls, site=site, background_url=bg_url)
|
||||
html_filename = generate_welcome_page.save_welcome_page(valid_names, valid_urls, contacts=valid_contacts, site=site, background_url=bg_url)
|
||||
|
||||
if html_filename:
|
||||
if generate_welcome_page.add_customer_to_lobby_playlist(html_filename, site=site):
|
||||
# Letzte Kundendaten für Background-Update speichern
|
||||
config = load_config()
|
||||
site_cfg = config.setdefault("sites", {}).setdefault(site, {})
|
||||
site_cfg["welcome_data"] = {"names": valid_names, "logo_urls": valid_urls}
|
||||
site_cfg["welcome_data"] = {"names": valid_names, "logo_urls": valid_urls, "contacts": valid_contacts}
|
||||
save_config(config)
|
||||
add_history_entry("customer_added", f"Kunden ({', '.join(valid_names)}) zur Willkommensseite an Standort '{site}' hinzugefügt", current_user.email)
|
||||
success = f"✅ Willkommensseite mit {len(valid_names)} Kunden erstellt!"
|
||||
@@ -755,12 +769,17 @@ def add_customer():
|
||||
config = load_config()
|
||||
site_list = get_site_list(config)
|
||||
background_url = get_background_url(site)
|
||||
welcome_data = config.get("sites", {}).get(site, {}).get("welcome_data", {})
|
||||
saved_contacts = welcome_data.get("contacts", ["", "", ""])
|
||||
if not contacts:
|
||||
contacts = saved_contacts
|
||||
return render_template(
|
||||
"customer.html",
|
||||
error=error,
|
||||
success=success,
|
||||
logo_urls=logo_urls,
|
||||
customer_names=customer_names,
|
||||
contacts=contacts,
|
||||
site=site,
|
||||
site_list=site_list,
|
||||
current_site=site,
|
||||
@@ -804,7 +823,9 @@ def api_add_customer():
|
||||
if not logo_url:
|
||||
return jsonify({"error": "Logo not found"}), 400
|
||||
|
||||
html_filename = generate_welcome_page.save_welcome_page(customer_name, logo_url, site=site)
|
||||
contact = data.get("contact", "").strip()
|
||||
|
||||
html_filename = generate_welcome_page.save_welcome_page([customer_name], [logo_url], contacts=[contact], site=site)
|
||||
|
||||
if not html_filename:
|
||||
return jsonify({"error": "Failed to create welcome page"}), 500
|
||||
|
||||
@@ -97,14 +97,26 @@ def search_customer_logo(customer_name):
|
||||
# HTML-Generierung
|
||||
# -------------------------------------------------
|
||||
|
||||
def generate_welcome_html(customer_names, logo_urls, site="stuttgart", background_url=None):
|
||||
def md_to_html(text):
|
||||
"""Wandelt einfaches Markdown in HTML um (fett, kursiv, code, zeilenumbrüche)."""
|
||||
import re
|
||||
text = re.sub(r'\*\*(.+?)\*\*', r'<strong>\1</strong>', text)
|
||||
text = re.sub(r'\*(.+?)\*', r'<em>\1</em>', text)
|
||||
text = re.sub(r'`(.+?)`', r'<code>\1</code>', text)
|
||||
lines = text.split('\n')
|
||||
return '<br>'.join(line.strip() for line in lines)
|
||||
|
||||
|
||||
def generate_welcome_html(customer_names, logo_urls, contacts=None, site="stuttgart", background_url=None):
|
||||
"""
|
||||
Generiert den HTML-Code für die Willkommensseite.
|
||||
- Links oben: CANCOM-Logo + "meets" + Kundenlogos (280px Breite)
|
||||
- Rechts unten: "Herzlich Willkommen in unserer Niederlassung {Standort}"
|
||||
- Links oben: CANCOM-Logo + "meets" + Kundenlogos
|
||||
- Unter jedem Logo: Ansprechpartner-Kontaktdaten (Landscape)
|
||||
- Portrait: Kontaktdaten links neben den Logos
|
||||
|
||||
customer_names: Liste der Kundennamen (max. 3)
|
||||
logo_urls: Liste der Logo-URLs (gleiche Reihenfolge)
|
||||
contacts: Liste der Ansprechpartner-Texte (Markdown, optional)
|
||||
site: Standort-Name für die Anzeige
|
||||
background_url: URLs zum Hintergrundbild (None → Standard-Wallpaper)
|
||||
"""
|
||||
@@ -113,15 +125,25 @@ def generate_welcome_html(customer_names, logo_urls, site="stuttgart", backgroun
|
||||
print(f"✅ Generate - Willkommensseite wird generiert für: {names_str} (site: {site})")
|
||||
site_display = site.capitalize()
|
||||
|
||||
if contacts is None:
|
||||
contacts = [""] * len(customer_names)
|
||||
|
||||
bg_image = background_url if background_url else "/static/wallpaper.png"
|
||||
cancom_svg = '''<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xcs="https://www.xtool.com/pages/software" version="1.1" preserveAspectRatio="xMinYMin meet" width="61.682394106284505mm" height="9.909010347638684mm" viewBox="136.55880294685778 209.2954948261807 61.682394106284505 9.909010347638684" xcs:version="2.7.22"><style></style><path transform="matrix(0.158038,0,0,0.158038,133.2558,163.322122)" stroke="none" fill="currentColor" data-view-type="laser" d="M125.9,352.1h18.9L119,291.7h-16.2l-25,60.4h18.2l14.6-38.9L125.9,352.1z M323.6,322 c0,8.8-6.1,16.4-15.4,16.4c-9.1,0-15.4-7.6-15.4-16.4s6.1-16.4,15.2-16.4C317,305.6,323.6,313.4,323.6,322 M340.5,322.3 c0-17.4-13.4-31.3-32.3-31.3c-18.7,0-32.3,14.1-32.3,31.3c0,17.4,13.4,31.3,32.3,31.3C326.9,353.6,340.5,339.4,340.5,322.3 M230.4,322.5c0-8.8,6.1-16.4,14.9-16.4c3,0,5.8,0.8,8.1,2l6.6-13.4c-3-2-8.1-3.8-14.9-3.8c-18.2,0-31.6,14.1-31.6,31.3 c0,18.2,12.6,31.1,31.6,31.1c17.2,0,26-10.6,28.8-21l-13.6-5.6c-1.8,5.8-6.3,11.6-14.4,11.6C236.5,338.4,230.4,331.4,230.4,322.5 M38,322.5c0-8.8,6.1-16.4,14.9-16.4c3,0,5.8,0.8,8.1,2l6.6-13.4c-3-2-8.1-3.8-14.9-3.8c-18.4,0-31.8,14.1-31.8,31.3 c0,18.2,12.6,31.1,31.6,31.1c17.2,0,26-10.6,28.8-21l-13.6-5.6c-1.8,5.8-6.3,11.6-14.4,11.6C44,338.4,38,331.4,38,322.5 M191.8,352.1h14.4v-59.8H190v33.1l-25-33.1h-15.4v60.1h16.2v-34.1L191.8,352.1z M411.2,352.1v-59.8h-17.7l-14.4,23.2l-14.4-23.2 h-17.7v60.1h16.4V318l15.4,23.2h0.3l15.4-23.5v34.6L411.2,352.1L411.2,352.1z" fill-rule="nonzero"></path></svg>'''
|
||||
|
||||
logo_html = ""
|
||||
for i, (name, url) in enumerate(zip(customer_names, logo_urls)):
|
||||
if url:
|
||||
contact_html = ""
|
||||
if i < len(contacts) and contacts[i]:
|
||||
contact_html = f'''<div class="contact-info">{md_to_html(contacts[i])}</div>'''
|
||||
logo_html += f'''
|
||||
<div class="customer-logo-item">
|
||||
<img src="{url}" alt="{name}" class="customer-logo" crossorigin="anonymous">
|
||||
<div class="customer-meta">
|
||||
<span class="customer-name">{name}</span>
|
||||
{contact_html}
|
||||
</div>
|
||||
</div>'''
|
||||
|
||||
html_content = f"""<!DOCTYPE html>
|
||||
@@ -165,13 +187,13 @@ def generate_welcome_html(customer_names, logo_urls, site="stuttgart", backgroun
|
||||
}}
|
||||
.customer-logos {{
|
||||
display: flex; flex-direction: row;
|
||||
align-items: center; justify-content: flex-end;
|
||||
align-items: flex-start; justify-content: flex-end;
|
||||
gap: 48px; max-width: 100%;
|
||||
}}
|
||||
.customer-logo-item {{
|
||||
flex: 0 0 280px;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
min-height: 100px;
|
||||
display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: flex-start;
|
||||
}}
|
||||
.customer-logo {{
|
||||
width: 100%; height: auto;
|
||||
@@ -179,15 +201,40 @@ def generate_welcome_html(customer_names, logo_urls, site="stuttgart", backgroun
|
||||
object-fit: contain;
|
||||
filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.15));
|
||||
}}
|
||||
.customer-name {{
|
||||
font-size: 1rem; font-weight: 600; color: #000;
|
||||
margin-top: 8px; text-align: center;
|
||||
}}
|
||||
.contact-info {{
|
||||
font-size: 0.85rem; color: #333; line-height: 1.5;
|
||||
margin-top: 6px; text-align: center;
|
||||
}}
|
||||
.contact-info strong {{ color: #000; }}
|
||||
.contact-info code {{
|
||||
font-size: 0.8rem; padding: 1px 4px;
|
||||
background: rgba(0,0,0,0.06); border-radius: 3px;
|
||||
}}
|
||||
@media (orientation: portrait) {{
|
||||
.customer-logos {{
|
||||
flex-direction: column; gap: 24px;
|
||||
flex-direction: column; gap: 20px;
|
||||
}}
|
||||
.customer-logo-item {{
|
||||
flex: 0 0 200px;
|
||||
flex: 0 0 auto;
|
||||
flex-direction: row; gap: 20px;
|
||||
width: 100%; max-width: 600px;
|
||||
}}
|
||||
.customer-logo {{
|
||||
max-height: 120px;
|
||||
max-height: 100px; width: 180px; flex-shrink: 0;
|
||||
}}
|
||||
.customer-name {{
|
||||
margin-top: 0; text-align: left;
|
||||
}}
|
||||
.contact-info {{
|
||||
text-align: left;
|
||||
}}
|
||||
.customer-meta {{
|
||||
display: flex; flex-direction: column;
|
||||
align-items: flex-start; flex: 1;
|
||||
}}
|
||||
}}
|
||||
.content {{
|
||||
@@ -226,15 +273,16 @@ def generate_welcome_html(customer_names, logo_urls, site="stuttgart", backgroun
|
||||
# Speichern + Playlist-Einfügung
|
||||
# -------------------------------------------------
|
||||
|
||||
def save_welcome_page(customer_names, logo_urls, site="stuttgart", background_url=None):
|
||||
def save_welcome_page(customer_names, logo_urls, contacts=None, site="stuttgart", background_url=None):
|
||||
"""Speichert die generierte Willkommensseite als welcome.html im Lobby-Verzeichnis.
|
||||
contacts: Liste der Ansprechpartner-Texte (Markdown, optional)
|
||||
background_url: Benutzerdefiniertes Hintergrundbild oder None (Standard).
|
||||
Gibt den Dateinamen zurück oder None bei Fehler."""
|
||||
try:
|
||||
welcome_dir = os.path.join(MEDIA_DIR, site, "lobby")
|
||||
os.makedirs(welcome_dir, exist_ok=True)
|
||||
filepath = os.path.join(os.path.abspath(welcome_dir), WELCOME_FILENAME)
|
||||
html_content = generate_welcome_html(customer_names, logo_urls, site=site, background_url=background_url)
|
||||
html_content = generate_welcome_html(customer_names, logo_urls, contacts=contacts, site=site, background_url=background_url)
|
||||
|
||||
with open(filepath, "w", encoding="utf-8") as f:
|
||||
f.write(html_content)
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
[
|
||||
{
|
||||
"timestamp": "2026-07-02 12:25:24",
|
||||
"action": "user_login",
|
||||
"detail": "User 'admin' angemeldet",
|
||||
"user": "admin"
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-06-28 16:04:39",
|
||||
"action": "user_login",
|
||||
|
||||
@@ -129,24 +129,34 @@
|
||||
<input type="text" class="form-control" id="customer_name_1"
|
||||
name="customer_name_1" placeholder="z. B. Beispiel GmbH"
|
||||
value="{{ customer_names[0] if customer_names else '' }}">
|
||||
<label class="form-label mt-2" for="contact_1">Ansprechpartner (optional)</label>
|
||||
<textarea class="form-control" id="contact_1" name="contact_1" rows="4"
|
||||
placeholder="**Max Mustermann** +49 123 4567890 *E-Mail*: max@beispiel.de">{{ contacts[0] if contacts else '' }}</textarea>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" for="customer_name_2">Kunde 2 (optional)</label>
|
||||
<input type="text" class="form-control" id="customer_name_2"
|
||||
name="customer_name_2" placeholder="z. B. Muster AG"
|
||||
value="{{ customer_names[1] if customer_names else '' }}">
|
||||
<label class="form-label mt-2" for="contact_2">Ansprechpartner (optional)</label>
|
||||
<textarea class="form-control" id="contact_2" name="contact_2" rows="4"
|
||||
placeholder="**Maria Schmidt** +49 456 7890123 *E-Mail*: maria@muster.de">{{ contacts[1] if contacts else '' }}</textarea>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label class="form-label" for="customer_name_3">Kunde 3 (optional)</label>
|
||||
<input type="text" class="form-control" id="customer_name_3"
|
||||
name="customer_name_3" placeholder="z. B. Firma GmbH"
|
||||
value="{{ customer_names[2] if customer_names else '' }}">
|
||||
<label class="form-label mt-2" for="contact_3">Ansprechpartner (optional)</label>
|
||||
<textarea class="form-control" id="contact_3" name="contact_3" rows="4"
|
||||
placeholder="**Sabine Weber** +49 789 0123456 *E-Mail*: sabine@firma.de">{{ contacts[2] if contacts else '' }}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3 text-muted">
|
||||
<p class="mb-1">Das System sucht automatisch nach den Kundenlogos</p>
|
||||
<p class="mb-0">und erstellt eine angepasste Willkommensseite für die Lobby-Playlist.</p>
|
||||
<p class="mb-0 small"><i class="ti ti-markdown me-1"></i>Ansprechpartner unterstützen <strong>fett</strong>, <em>kursiv</em> und <code>Code</code> sowie Zeilenumbrüche.</p>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
|
||||
Reference in New Issue
Block a user