Kursfortschrittsanzeige

This commit is contained in:
Bkolb 2026-04-10 11:59:32 +02:00
parent bc3b2505b6
commit 989422a4a7
16 changed files with 207 additions and 36 deletions

View File

@ -1119,9 +1119,20 @@ def course_start(course_id):
cur.close() cur.close()
conn.close() conn.close()
show_course_progress = True
course_progress_title = f"{course['code']} {course['title']}"
course_progress_current = 1
course_progress_total = 8
course_progress_percent = int((course_progress_current / course_progress_total) * 100)
return render_template( return render_template(
"course_video.html", "course_video.html",
course=course, course=course,
show_course_progress=show_course_progress,
course_progress_title=course_progress_title,
course_progress_current=course_progress_current,
course_progress_total=course_progress_total,
course_progress_percent=course_progress_percent,
**get_current_user() **get_current_user()
) )
@ -1142,6 +1153,13 @@ def course_page(course_id, page_number):
if not page: if not page:
abort(404) abort(404)
cur.execute("""
SELECT *
FROM course
WHERE id = %s
""", (course_id,))
course = fetchone_dict(cur)
# Fortschritt speichern # Fortschritt speichern
cur.execute(""" cur.execute("""
INSERT INTO user_course_progress (user_id, course_id, last_page) INSERT INTO user_course_progress (user_id, course_id, last_page)
@ -1155,10 +1173,21 @@ def course_page(course_id, page_number):
cur.close() cur.close()
conn.close() conn.close()
show_course_progress = True
course_progress_title = f"{course['code']} {course['title']}"
course_progress_current = page_number+1
course_progress_total = 8
course_progress_percent = int((course_progress_current / course_progress_total) * 100)
return render_template( return render_template(
page["template_name"], page["template_name"],
course_id=course_id, course_id=course_id,
page_number=page_number, page_number=page_number,
show_course_progress=show_course_progress,
course_progress_title=course_progress_title,
course_progress_current=course_progress_current,
course_progress_total=course_progress_total,
course_progress_percent=course_progress_percent,
**get_current_user() **get_current_user()
) )
@ -1591,7 +1620,7 @@ def admin_courses():
cur.execute(""" cur.execute("""
SELECT id, code, title, description, min_level, video_file, sort_order SELECT id, code, title, description, min_level, video_file, sort_order
FROM course FROM course
ORDER BY min_level, sort_order, id ORDER BY code
""") """)
courses = fetchall_dict(cur) courses = fetchall_dict(cur)

View File

@ -68,12 +68,12 @@
<thead> <thead>
<tr> <tr>
<th>ID</th> <th>ID</th>
<th>Code</th> <th style="width:60px;">Code</th>
<th>Titel</th> <th>Titel</th>
<th>Level</th> <th style="width:120px;">Level</th>
<th>Video</th> <th>Video</th>
<th>Sort</th> <th style="width:80px;">Sort</th>
<th>Aktionen</th> <th style="width:160px;">Aktionen</th>
</tr> </tr>
</thead> </thead>
@ -81,26 +81,34 @@
{% for c in courses %} {% for c in courses %}
<tr> <tr>
<form method="post"> <form method="post">
<td>
<input type="hidden" name="id" value="{{ c.id }}"> <input type="hidden" name="id" value="{{ c.id }}">
{{ c.id }}
<td>{{ c.id }}</td>
<td>
<input type="text" name="code" value="{{ c.code }}">
</td> </td>
<!-- CODE -->
<td> <td>
<input type="text" name="title" value="{{ c.title }}"> <input type="text" name="code" value="{{ c.code }}" maxlength="5" class="input-small">
</td> </td>
<!-- TITEL + BESCHREIBUNG -->
<td>
<input type="text" name="title" value="{{ c.title }}" class="input-full">
<textarea name="description" class="textarea-inline"
placeholder="Beschreibung">{{ c.description or '' }}</textarea>
</td>
<!-- LEVEL -->
<td> <td>
<select name="min_level"> <select name="min_level">
<option value="1" {% if c.min_level == 1 %}selected{% endif %}>1 - Gold</option> <option value="1" {% if c.min_level == 1 %}selected{% endif %}>Gold</option>
<option value="2" {% if c.min_level == 2 %}selected{% endif %}>2 - Silber</option> <option value="2" {% if c.min_level == 2 %}selected{% endif %}>Silber</option>
<option value="3" {% if c.min_level == 3 %}selected{% endif %}>3 - Bronze</option> <option value="3" {% if c.min_level == 3 %}selected{% endif %}>Bronze</option>
</select> </select>
</td> </td>
<!-- VIDEO -->
<td> <td>
<select name="video_file"> <select name="video_file">
{% for v in video_files %} {% for v in video_files %}
@ -111,15 +119,17 @@
</select> </select>
</td> </td>
<!-- SORT -->
<td> <td>
<input type="number" name="sort_order" value="{{ c.sort_order }}"> <input type="number" name="sort_order" value="{{ c.sort_order }}" class="input-small">
</td> </td>
<!-- ACTIONS -->
<td> <td>
<input type="hidden" name="description" value="{{ c.description or '' }}">
<button name="action" value="update" class="btn-primary btn-small">Speichern</button> <button name="action" value="update" class="btn-primary btn-small">Speichern</button>
<button name="action" value="delete" class="btn-danger btn-small">Löschen</button> <button name="action" value="delete" class="btn-danger btn-small">Löschen</button>
</td> </td>
</form> </form>
</tr> </tr>
{% endfor %} {% endfor %}

View File

@ -72,6 +72,23 @@
<main class="content-area"> <main class="content-area">
<section class="content-box"> <section class="content-box">
{% if show_course_progress %}
<div class="course-progress-box">
<div class="course-progress-header">
<strong>{{ course_progress_title }}</strong>
<span>{{ course_progress_current }} / {{ course_progress_total }}</span>
</div>
<div class="course-progress-bar">
<div class="course-progress-fill"
style="width: {{ course_progress_percent }}%;">
</div>
</div>
</div>
{% endif %}
{% block content %} {% block content %}
{% endblock %} {% endblock %}

View File

@ -0,0 +1,45 @@
{% extends "base.html" %}
{% block content %}
<h2>AI Governance Basics</h2>
<section class="content-section ai-explainer">
<div class="content-wrapper">
<h2 class="section-title">Willkommen zu Compliance Verification und zum Modul A1 AI Governance Basics</h2>
<p class="lead">
In diesem Kurs lernen Sie die Grundlagen dafür, wie moderne KI-Systeme funktionieren,
</p>
<p>
warum sie so leistungsfähig aber gleichzeitig fehleranfällig sind,
in welchen Unternehmensbereichen KI eingesetzt wird,
und welche Mindestregeln für einen sicheren und verantwortungsvollen Umgang gelten.
</p>
<p>
Unser Ziel ist nicht,
Sie zu Programmiererinnen oder Technikern zu machen.
</p>
<p>
Unser Ziel ist,
dass Sie ein realistisches Grundverständnis entwickeln:
</p>
<ul class="key-points">
<li>Was KI kann.</li>
<li>Was KI nicht kann.</li>
<li>Und welche Verantwortung Sie im Alltag tragen.</li>
</ul>
</div>
</section>
<div class="course-nav">
<a href="/course/{{ course_id }}" class="btn-secondary">Zurück</a>
<a href="/course/{{ course_id }}/page/2" class="btn-primary">Weiter</a>
</div>
{% endblock %}

View File

@ -41,8 +41,8 @@
</section> </section>
<div class="course-nav"> <div class="course-nav">
<a href="/course/{{ course_id }}" class="btn-secondary">Zurück</a> <a href="/course/{{ course_id }}/page/1" class="btn-secondary">Zurück</a>
<a href="/course/{{ course_id }}/page/2" class="btn-primary">Weiter</a> <a href="/course/{{ course_id }}/page/3" class="btn-secondary">Weiter</a>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -56,8 +56,8 @@
</section> </section>
<div class="course-nav"> <div class="course-nav">
<a href="/course/{{ course_id }}/page/1" class="btn-secondary">Zurück</a> <a href="/course/{{ course_id }}/page/2" class="btn-secondary">Zurück</a>
<a href="/course/{{ course_id }}/page/3" class="btn-secondary">Weiter</a> <a href="/course/{{ course_id }}/page/4" class="btn-secondary">Weiter</a>
</div> </div>

View File

@ -75,8 +75,8 @@
</section> </section>
<div class="course-nav"> <div class="course-nav">
<a href="/course/{{ course_id }}/page/2" class="btn-secondary">Zurück</a> <a href="/course/{{ course_id }}/page/3" class="btn-secondary">Zurück</a>
<a href="/course/{{ course_id }}/page/4" class="btn-secondary">Weiter</a> <a href="/course/{{ course_id }}/page/5" class="btn-secondary">Weiter</a>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -42,8 +42,8 @@
</section> </section>
<div class="course-nav"> <div class="course-nav">
<a href="/course/{{ course_id }}/page/3" class="btn-secondary">Zurück</a> <a href="/course/{{ course_id }}/page/4" class="btn-secondary">Zurück</a>
<a href="/course/{{ course_id }}/page/5" class="btn-secondary">Weiter</a> <a href="/course/{{ course_id }}/page/6" class="btn-secondary">Weiter</a>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -85,8 +85,8 @@
</section> </section>
<div class="course-nav"> <div class="course-nav">
<a href="/course/{{ course_id }}/page/4" class="btn-secondary">Zurück</a> <a href="/course/{{ course_id }}/page/5" class="btn-secondary">Zurück</a>
<a href="/course/{{ course_id }}/assessment" class="btn-primary">Zum Assessment</a> <a href="/course/{{ course_id }}/page/7" class="btn-secondary">Weiter</a>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -31,7 +31,7 @@
</section> </section>
<div class="course-nav"> <div class="course-nav">
<a href="/course/{{ course_id }}/page/5" class="btn-secondary">Zurück</a> <a href="/course/{{ course_id }}/page/6" class="btn-secondary">Zurück</a>
<a href="/course/{{ course_id }}/assessment" class="btn-primary">Zum Assessment</a> <a href="/course/{{ course_id }}/assessment" class="btn-primary">Zum Assessment</a>
</div> </div>

View File

@ -58,8 +58,8 @@
</section> </section>
<div class="course-nav"> <div class="course-nav">
<a href="/course/{{ course_id }}/page/4" class="btn-secondary">Zurück</a> <a href="/course/{{ course_id }}/page/5" class="btn-secondary">Zurück</a>
<a href="/course/{{ course_id }}/page/6" class="btn-primary">Weiter</a> <a href="/course/{{ course_id }}/page/7" class="btn-primary">Weiter</a>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -50,8 +50,8 @@
</section> </section>
<div class="course-nav"> <div class="course-nav">
<a href="/course/{{ course_id }}/page/1" class="btn-secondary">Zurück</a> <a href="/course/{{ course_id }}/page/3" class="btn-secondary">Zurück</a>
<a href="/course/{{ course_id }}/page/3" class="btn-primary">Weiter</a> <a href="/course/{{ course_id }}/page/5" class="btn-primary">Weiter</a>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -52,8 +52,8 @@
</section> </section>
<div class="course-nav"> <div class="course-nav">
<a href="/course/{{ course_id }}/page/1" class="btn-secondary">Zurück</a> <a href="/course/{{ course_id }}/page/4" class="btn-secondary">Zurück</a>
<a href="/course/{{ course_id }}/page/3" class="btn-primary">Weiter</a> <a href="/course/{{ course_id }}/page/6" class="btn-primary">Weiter</a>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -54,8 +54,8 @@
</section> </section>
<div class="course-nav"> <div class="course-nav">
<a href="/course/{{ course_id }}/page/1" class="btn-secondary">Zurück</a> <a href="/course/{{ course_id }}/page/5" class="btn-secondary">Zurück</a>
<a href="/course/{{ course_id }}/page/3" class="btn-primary">Weiter</a> <a href="/course/{{ course_id }}/page/7" class="btn-primary">Weiter</a>
</div> </div>
{% endblock %} {% endblock %}

View File

@ -31,7 +31,7 @@
</section> </section>
<div class="course-nav"> <div class="course-nav">
<a href="/course/{{ course_id }}/page/1" class="btn-secondary">Zurück</a> <a href="/course/{{ course_id }}/page/6" class="btn-secondary">Zurück</a>
<a href="/course/{{ course_id }}/assessment" class="btn-primary">Zum Assessment</a> <a href="/course/{{ course_id }}/assessment" class="btn-primary">Zum Assessment</a>
</div> </div>

View File

@ -1021,3 +1021,73 @@ button {
font-size: 16px; font-size: 16px;
} }
} }
.mandanten-table textarea {
width: 100%;
min-height: 70px;
padding: 10px 12px;
border: 1px solid #cfd8e3;
border-radius: 10px;
font-size: 14px;
box-sizing: border-box;
resize: vertical;
font-family: Arial, Helvetica, sans-serif;
}
/* ===============================
Kursverwaltung Tabelle
=============================== */
.input-small {
width: 60px;
padding: 6px 8px;
}
.input-full {
width: 100%;
margin-bottom: 6px;
}
.textarea-inline {
width: 100%;
min-height: 60px;
padding: 8px 10px;
border: 1px solid #cfd8e3;
border-radius: 8px;
font-size: 14px;
resize: vertical;
box-sizing: border-box;
}
/* ===============================
Kursfortschritt (grün/grau)
=============================== */
.course-progress-box {
margin-bottom: 24px;
}
.course-progress-header {
display: flex;
justify-content: space-between;
font-size: 14px;
margin-bottom: 6px;
color: #334155;
}
/* Hintergrund = grau */
.course-progress-bar {
width: 100%;
height: 12px;
background: #e5e7eb; /* grau */
border-radius: 8px;
overflow: hidden;
}
/* Fortschritt = grün */
.course-progress-fill {
height: 100%;
background: #22c55e; /* grün */
border-radius: 8px;
transition: width 0.3s ease;
}