feat: score chart

main
ccicnce113424 5 months ago
parent 7210fc46e6
commit 695bce53b5

@ -356,3 +356,75 @@ def score_student():
"random_called_count": student.random_called_count,
}
)
@main_bp.route("/api/stats/top_students_timeline")
@login_required
def top_students_timeline():
# 选取当前账号积分前5名学生
top_students = (
Student.query.filter_by(user_id=current_user.id)
.order_by(
Student.total_score.desc(),
Student.attendance_count.desc(),
Student.student_no.asc(),
)
.limit(5)
.all()
)
if not top_students:
return jsonify({"labels": [], "series": []})
student_ids = [s.id for s in top_students]
# 取这些学生的所有点名记录,按时间排序
records = (
RollCall.query.filter(
RollCall.user_id == current_user.id,
RollCall.student_id.in_(student_ids),
)
.order_by(RollCall.call_time.asc())
.all()
)
if not records:
return jsonify({"labels": [], "series": []})
# 构造全局时间轴(去重后的时间点)
time_points = []
for rc in records:
local_time = utc_to_local(rc.call_time)
label = local_time.strftime("%m-%d %H:%M")
if label not in time_points:
time_points.append(label)
# 为每个学生按时间累积分数
series = []
for s in top_students:
cumulative = 0.0
# 取该学生记录
s_records = [rc for rc in records if rc.student_id == s.id]
idx = 0
points = []
for label in time_points:
# 把该时间点及之前所有还未计入的记录加入累计
while idx < len(s_records):
rc = s_records[idx]
local_time = utc_to_local(rc.call_time)
rc_label = local_time.strftime("%m-%d %H:%M")
if rc_label <= label:
cumulative += rc.score_change
idx += 1
else:
break
points.append(round(cumulative, 2))
series.append(
{
"name": f"{s.name}({s.student_no})",
"data": points,
}
)
return jsonify({"labels": time_points, "series": series})

@ -3,9 +3,10 @@
{% block content %}
<div class="row mb-3">
<div class="col-md-8">
<h4>积分排行榜</h4>
<h4>积分随时间走势图(前几名)</h4>
<canvas id="scoreChart" height="150"></canvas>
</div>
<div class="col-md-4 text-end">
<div class="col-md-4 text-end align-self-end">
<a href="{{ url_for('main.export_students') }}" class="btn btn-sm btn-outline-primary">
导出积分详单
</a>
@ -18,7 +19,7 @@
</div>
</div>
<div class="row">
<div class="row mt-3">
<div class="col-md-8">
<table class="table table-striped table-bordered">
<thead>
@ -88,4 +89,51 @@
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
<script>
async function loadScoreChart() {
const resp = await fetch("/api/stats/top_students_timeline");
const data = await resp.json();
if (!data.labels || data.labels.length === 0) {
return;
}
const ctx = document.getElementById("scoreChart");
const colors = [
"#007bff",
"#28a745",
"#ffc107",
"#dc3545",
"#6610f2",
];
new Chart(ctx, {
type: "line",
data: {
labels: data.labels,
datasets: data.series.map((s, idx) => ({
label: s.name,
data: s.data,
borderColor: colors[idx % colors.length],
backgroundColor: "rgba(0,0,0,0)",
tension: 0.2,
})),
},
options: {
responsive: true,
interaction: { mode: "index", intersect: false },
stacked: false,
plugins: {
legend: { position: "bottom" },
},
scales: {
x: { title: { display: true, text: "时间" } },
y: { title: { display: true, text: "累计积分" } },
},
},
});
}
document.addEventListener("DOMContentLoaded", loadScoreChart);
</script>
{% endblock %}

Loading…
Cancel
Save