Layout Kursübersicht
This commit is contained in:
parent
1778bd1bae
commit
6789ac73c8
@ -1048,13 +1048,73 @@ def useradmin_user_edit(user_id):
|
|||||||
@app.route("/courses")
|
@app.route("/courses")
|
||||||
@login_required
|
@login_required
|
||||||
def course_list():
|
def course_list():
|
||||||
courses = get_available_courses_for_user()
|
user_id = session.get("user_id")
|
||||||
|
mandant_level = session.get("mandant_level", 0)
|
||||||
|
|
||||||
|
conn = get_connection()
|
||||||
|
cur = conn.cursor()
|
||||||
|
|
||||||
|
# Alle aktiven Kurse laden
|
||||||
|
cur.execute("""
|
||||||
|
SELECT id, code, title, description, video_file, sort_order, is_active
|
||||||
|
FROM course
|
||||||
|
WHERE is_active = TRUE
|
||||||
|
ORDER BY code
|
||||||
|
""")
|
||||||
|
all_courses = fetchall_dict(cur)
|
||||||
|
|
||||||
|
# Filter nach Level
|
||||||
|
available_courses = [
|
||||||
|
c for c in all_courses
|
||||||
|
if is_course_allowed_for_level(c["code"], mandant_level)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Bestandene Assessments laden
|
||||||
|
cur.execute("""
|
||||||
|
SELECT DISTINCT course_id
|
||||||
|
FROM user_assessment
|
||||||
|
WHERE user_id = %s
|
||||||
|
AND passed = TRUE
|
||||||
|
""", (user_id,))
|
||||||
|
passed_rows = cur.fetchall()
|
||||||
|
passed_course_ids = {row[0] for row in passed_rows}
|
||||||
|
|
||||||
|
cur.close()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# Kurse markieren + Modul bestimmen
|
||||||
|
for course in available_courses:
|
||||||
|
course["is_completed"] = course["id"] in passed_course_ids
|
||||||
|
course["module_code"] = (course["code"] or "")[:1].upper()
|
||||||
|
|
||||||
|
# Gruppieren + Fortschritt berechnen
|
||||||
|
grouped_courses = {}
|
||||||
|
module_progress = {}
|
||||||
|
|
||||||
|
for module_code in ("A", "B", "C"):
|
||||||
|
module_courses = [
|
||||||
|
c for c in available_courses
|
||||||
|
if c["module_code"] == module_code
|
||||||
|
]
|
||||||
|
|
||||||
|
grouped_courses[module_code] = module_courses
|
||||||
|
|
||||||
|
total = len(module_courses)
|
||||||
|
completed = sum(1 for c in module_courses if c["is_completed"])
|
||||||
|
percent = int((completed / total) * 100) if total > 0 else 0
|
||||||
|
|
||||||
|
module_progress[module_code] = {
|
||||||
|
"total": total,
|
||||||
|
"completed": completed,
|
||||||
|
"percent": percent
|
||||||
|
}
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
"course_list.html",
|
"courses.html",
|
||||||
|
grouped_courses=grouped_courses,
|
||||||
|
module_progress=module_progress,
|
||||||
page_title="Kurse",
|
page_title="Kurse",
|
||||||
active_page="courses",
|
active_page="courses",
|
||||||
courses=courses,
|
|
||||||
**get_current_user()
|
**get_current_user()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@ -19,14 +19,13 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<nav class="top-nav">
|
<nav class="top-nav">
|
||||||
<!-- <a href="/home" class="{% if active_page == 'home' %}active{% endif %}">Home</a> -->
|
|
||||||
<a href="/preise" class="{% if active_page == 'preise' %}active{% endif %}">Preise</a>
|
|
||||||
<!-- <a href="/allgemein" class="{% if active_page == 'allgemein' %}active{% endif %}">Allgemein</a> -->
|
|
||||||
|
|
||||||
{% if is_logged_in %}
|
{% if is_logged_in %}
|
||||||
<a href="/courses" class="{% if active_page == 'courses' %}active{% endif %}">
|
<a href="/courses" class="{% if active_page == 'courses' %}active{% endif %}">
|
||||||
Kurse
|
Kurse
|
||||||
</a>
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="/preise" class="{% if active_page == 'preise' %}active{% endif %}">Preise</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if is_logged_in %}
|
{% if is_logged_in %}
|
||||||
|
|||||||
85
app/flask-postgres/app/templates/courses.html
Normal file
85
app/flask-postgres/app/templates/courses.html
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="page-header">
|
||||||
|
<h1>Kurse</h1>
|
||||||
|
<p class="intro-text">Ihre verfügbaren Schulungsmodule und Kurse.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% for module_code, module_courses in grouped_courses.items() %}
|
||||||
|
{% if module_courses %}
|
||||||
|
<section class="admin-section">
|
||||||
|
|
||||||
|
<div class="admin-panel">
|
||||||
|
|
||||||
|
<!-- Modul Titel -->
|
||||||
|
<div class="admin-panel-header">
|
||||||
|
<h2>Modul {{ module_code }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fortschritt -->
|
||||||
|
<div class="progress-box">
|
||||||
|
<div class="progress-header">
|
||||||
|
<span>
|
||||||
|
{{ module_progress[module_code].completed }}
|
||||||
|
/
|
||||||
|
{{ module_progress[module_code].total }}
|
||||||
|
abgeschlossen
|
||||||
|
</span>
|
||||||
|
<span>{{ module_progress[module_code].percent }}%</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="progress-bar">
|
||||||
|
<div class="progress-fill"
|
||||||
|
style="width: {{ module_progress[module_code].percent }}%;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if module_progress[module_code].percent == 100 %}
|
||||||
|
<div style="margin-top:6px; font-size:12px; color:#15803d; font-weight:600;">
|
||||||
|
✔ Modul abgeschlossen
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Kurse -->
|
||||||
|
<div class="course-grid">
|
||||||
|
|
||||||
|
{% for course in module_courses %}
|
||||||
|
<article class="course-card {% if course.is_completed %}course-card-completed{% endif %}">
|
||||||
|
|
||||||
|
<div class="course-card-header">
|
||||||
|
<div class="course-code">{{ course.code }}</div>
|
||||||
|
|
||||||
|
{% if course.is_completed %}
|
||||||
|
<span class="course-badge course-badge-completed">
|
||||||
|
✔ abgeschlossen
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>{{ course.title }}</h3>
|
||||||
|
|
||||||
|
{% if course.description %}
|
||||||
|
<p>{{ course.description }}</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="course-actions">
|
||||||
|
<a href="/course/{{ course.id }}" class="btn-primary btn-small">
|
||||||
|
Kurs öffnen
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</section>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|
||||||
<h1>Login</h1>
|
<h1>Melden Sie sich mit Ihrer email-adresse an</h1>
|
||||||
|
|
||||||
{% if error_message %}
|
{% if error_message %}
|
||||||
<div class="error-box">{{ error_message }}</div>
|
<div class="error-box">{{ error_message }}</div>
|
||||||
|
|||||||
@ -133,10 +133,6 @@
|
|||||||
</article>
|
</article>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="pricing-bottom-note">
|
|
||||||
<div class="image-panel">
|
|
||||||
<img src="/images/TabelleUebersicht.png" alt="Paketübersicht">
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
@ -1305,3 +1305,142 @@ button {
|
|||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===============================
|
||||||
|
Kursübersicht User
|
||||||
|
=============================== */
|
||||||
|
|
||||||
|
.course-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-card {
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce3ea;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-card-completed {
|
||||||
|
background: #eaf8ee;
|
||||||
|
border: 1px solid #9fd3ac;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-code {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 800;
|
||||||
|
color: #0d2f57;
|
||||||
|
letter-spacing: 0.04em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-badge {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-badge-completed {
|
||||||
|
background: #22c55e;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-card h3 {
|
||||||
|
margin: 0 0 10px;
|
||||||
|
color: #0d2f57;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-card p {
|
||||||
|
margin: 0 0 16px;
|
||||||
|
color: #475569;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-actions {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kurs Grid */
|
||||||
|
.course-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
|
||||||
|
gap: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Karte */
|
||||||
|
.course-card {
|
||||||
|
background: #ffffff;
|
||||||
|
border: 1px solid #dce3ea;
|
||||||
|
border-radius: 16px;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 8px 24px rgba(15, 23, 42, 0.04);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fertig */
|
||||||
|
.course-card-completed {
|
||||||
|
background: #eaf8ee;
|
||||||
|
border: 1px solid #9fd3ac;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
.course-card-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Code */
|
||||||
|
.course-code {
|
||||||
|
font-weight: 800;
|
||||||
|
color: #0d2f57;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Badge */
|
||||||
|
.course-badge {
|
||||||
|
padding: 5px 10px;
|
||||||
|
border-radius: 999px;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.course-badge-completed {
|
||||||
|
background: #22c55e;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Progress */
|
||||||
|
.progress-box {
|
||||||
|
margin: 10px 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 6px;
|
||||||
|
color: #475569;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-bar {
|
||||||
|
width: 100%;
|
||||||
|
height: 10px;
|
||||||
|
background: #e5eaf0;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.progress-fill {
|
||||||
|
height: 100%;
|
||||||
|
background: linear-gradient(90deg, #22c55e, #15803d);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user