From dcc0457848acb15db4bd7545ef68b0058d077902 Mon Sep 17 00:00:00 2001 From: hmo Date: Mon, 27 Apr 2026 19:28:04 +0800 Subject: [PATCH] feat: add student/class statistics page with Chart.js visualizations --- app/routes/students.py | 75 ++++++++++ app/templates/base.html | 5 + app/templates/statistics.html | 249 ++++++++++++++++++++++++++++++++++ 3 files changed, 329 insertions(+) create mode 100644 app/templates/statistics.html diff --git a/app/routes/students.py b/app/routes/students.py index a1b6718..20b5d8b 100644 --- a/app/routes/students.py +++ b/app/routes/students.py @@ -16,6 +16,7 @@ from app.models import ( db, Student, Class, + StudentProblem, PracticePlan, PROBLEM_LIST, SEVERITY_LEVELS, @@ -67,6 +68,14 @@ def students_page(): ) +@main_bp.route("/statistics") +def statistics_page(): + """数据统计页""" + if not check_login(): + return redirect("/login") + return render_template("statistics.html", active_nav="statistics") + + @main_bp.route("/api/students", methods=["GET"]) @login_required_json def get_students(): @@ -366,3 +375,69 @@ def import_students(): except Exception as e: return jsonify({"error": f"导入失败: {str(e)}"}), 500 + + +@main_bp.route("/api/statistics/students") +def get_student_statistics(): + """获取学员统计数据""" + # 全体学员数量 + total_students = Student.query.count() + + # 全体问题记录 + problems = StudentProblem.query.all() + + # 问题级别分布(来自 StudentProblem.level) + levels = ["启蒙", "入门", "进阶", "熟练", "精通"] + level_dist = {lv: 0 for lv in levels} + for p in problems: + if p.level in level_dist: + level_dist[p.level] += 1 + + # 问题严重程度分布 + severity_dist = {"轻微": 0, "中等": 0, "严重": 0} + for p in problems: + if p.severity in severity_dist: + severity_dist[p.severity] += 1 + + # 各班级学员数量 + classes = Class.query.filter_by(active=True).all() + class_student_count = [] + for c in classes: + class_student_count.append({ + "class_id": c.id, + "class_name": c.name, + "level": c.level, + "student_count": len(c.students) + }) + + # 问题×级别矩阵(严重程度 × 学员级别) + severities = ["轻微", "中等", "严重"] + matrix = {} + for sev in severities: + matrix[sev] = {} + for lv in levels: + matrix[sev][lv] = 0 + + for p in problems: + if p.level in levels and p.severity in severities: + matrix[p.severity][p.level] += 1 + + # 各班级问题数量 + class_problem_count = [] + for c in classes: + class_problems = [p for p in problems if p.student.class_id == c.id] + class_problem_count.append({ + "class_id": c.id, + "class_name": c.name, + "problem_count": len(class_problems) + }) + + return jsonify({ + "total_students": total_students, + "total_problems": len(problems), + "level_distribution": level_dist, + "severity_distribution": severity_dist, + "class_student_count": class_student_count, + "class_problem_count": class_problem_count, + "problem_level_matrix": matrix, + }) diff --git a/app/templates/base.html b/app/templates/base.html index b3d05f5..eaf07f7 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -10,6 +10,8 @@ + + {% block extra_css %}{% endblock %}