120 lines
5.3 KiB
HTML
120 lines
5.3 KiB
HTML
|
|
{% extends "base.html" %}
|
|||
|
|
{% block title %}首页 - 学生课程管理系统{% endblock %}
|
|||
|
|
|
|||
|
|
{% block content %}
|
|||
|
|
<p class="greeting-title">{{ greeting }},{{ current_user.real_name or current_user.username }} 👋</p>
|
|||
|
|
<p class="greeting-sub">欢迎回到教培课程管理系统,以下是今日运营概览</p>
|
|||
|
|
|
|||
|
|
<div class="stat-grid">
|
|||
|
|
<div class="neo-surface neo-stat">
|
|||
|
|
<div class="stat-icon purple"><i class="bi bi-people-fill"></i></div>
|
|||
|
|
<div>
|
|||
|
|
<p class="stat-value">{{ total_students }}</p>
|
|||
|
|
<p class="stat-label">在读学员</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="neo-surface neo-stat">
|
|||
|
|
<div class="stat-icon green"><i class="bi bi-book-fill"></i></div>
|
|||
|
|
<div>
|
|||
|
|
<p class="stat-value">{{ total_courses }}</p>
|
|||
|
|
<p class="stat-label">启用课程</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="neo-surface neo-stat">
|
|||
|
|
<div class="stat-icon blue"><i class="bi bi-collection-fill"></i></div>
|
|||
|
|
<div>
|
|||
|
|
<p class="stat-value">{{ total_classes }}</p>
|
|||
|
|
<p class="stat-label">进行中班级</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="neo-surface neo-stat">
|
|||
|
|
<div class="stat-icon yellow"><i class="bi bi-cash-stack"></i></div>
|
|||
|
|
<div>
|
|||
|
|
<p class="stat-value">¥{{ "%.0f"|format(month_recharge) }}</p>
|
|||
|
|
<p class="stat-label">{% if period_label %}{{ period_label }} 充值{% else %}本月充值{% endif %}</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="neo-surface chart-card">
|
|||
|
|
<div class="chart-header">
|
|||
|
|
<div>
|
|||
|
|
<h5 class="mb-1 fw-bold">充值趋势</h5>
|
|||
|
|
<span class="text-muted" style="font-size:0.85rem;">近6个月充值金额</span>
|
|||
|
|
</div>
|
|||
|
|
<span class="tag tag-purple">本月 ¥{{ "%.0f"|format(month_recharge) }}</span>
|
|||
|
|
</div>
|
|||
|
|
<div class="chart-bars">
|
|||
|
|
{% for item in monthly_chart %}
|
|||
|
|
<div class="chart-col">
|
|||
|
|
<div class="chart-bar-wrap">
|
|||
|
|
{% set h = (item.amount / chart_max * 130)|int if chart_max else 8 %}
|
|||
|
|
<div class="chart-bar {% if item.is_current %}active{% endif %}" style="height: {{ [h, 8]|max }}px;"></div>
|
|||
|
|
</div>
|
|||
|
|
<span class="chart-month">{{ item.label }}</span>
|
|||
|
|
</div>
|
|||
|
|
{% endfor %}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="row g-4">
|
|||
|
|
<div class="col-lg-4">
|
|||
|
|
<div class="neo-surface feed-card">
|
|||
|
|
<h6 class="feed-title"><i class="bi bi-exclamation-circle text-warning"></i> 课时预警{% if period_label %} <small class="text-muted">({{ period_label }})</small>{% endif %}</h6>
|
|||
|
|
{% if low_hours_accounts %}
|
|||
|
|
{% for acc, remain, disp in low_hours_accounts %}
|
|||
|
|
<div class="feed-item">
|
|||
|
|
<div class="feed-avatar warn">{{ acc.student.name[:1] if acc.student else '?' }}</div>
|
|||
|
|
<div class="feed-body">
|
|||
|
|
<p class="feed-name">{{ acc.student.name if acc.student else '-' }}</p>
|
|||
|
|
<p class="feed-preview">{{ acc.course.course_code or acc.course.name if acc.course else '' }} · 剩余 {{ "%.0f"|format(remain) }} 节</p>
|
|||
|
|
</div>
|
|||
|
|
<span class="feed-meta">≤5节</span>
|
|||
|
|
</div>
|
|||
|
|
{% endfor %}
|
|||
|
|
{% else %}
|
|||
|
|
<p class="text-muted text-center py-4 mb-0">暂无预警学员</p>
|
|||
|
|
{% endif %}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="col-lg-4">
|
|||
|
|
<div class="neo-surface feed-card">
|
|||
|
|
<h6 class="feed-title"><i class="bi bi-wallet2" style="color:var(--primary)"></i> 最近充值</h6>
|
|||
|
|
{% if recent_recharges %}
|
|||
|
|
{% for r in recent_recharges[:6] %}
|
|||
|
|
<div class="feed-item">
|
|||
|
|
<div class="feed-avatar ok">{{ r.student.name[:1] if r.student else '?' }}</div>
|
|||
|
|
<div class="feed-body">
|
|||
|
|
<p class="feed-name">{{ r.student.name if r.student else '-' }}</p>
|
|||
|
|
<p class="feed-preview">充值到账 · 正课{{ r.normal_hours|int }}节</p>
|
|||
|
|
</div>
|
|||
|
|
<span class="feed-meta money">¥{{ r.amount }}</span>
|
|||
|
|
</div>
|
|||
|
|
{% endfor %}
|
|||
|
|
{% else %}
|
|||
|
|
<p class="text-muted text-center py-4 mb-0">数据来自 Excel 课时表<br><a href="{{ url_for('keshibiao_balances') }}">查看学员余额 →</a></p>
|
|||
|
|
{% endif %}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
<div class="col-lg-4">
|
|||
|
|
<div class="neo-surface feed-card">
|
|||
|
|
<h6 class="feed-title"><i class="bi bi-journal-check" style="color:#4a7fd4"></i> 最近消课</h6>
|
|||
|
|
{% if recent_consumptions %}
|
|||
|
|
{% for c in recent_consumptions[:6] %}
|
|||
|
|
<div class="feed-item">
|
|||
|
|
<div class="feed-avatar">{{ c.student.name[:1] if c.student else '?' }}</div>
|
|||
|
|
<div class="feed-body">
|
|||
|
|
<p class="feed-name">{{ c.student.name if c.student else '-' }}</p>
|
|||
|
|
<p class="feed-preview">{{ c.consume_date }} · {{ c.hours_consumed|int }} 课时</p>
|
|||
|
|
</div>
|
|||
|
|
<span class="feed-meta">-{{ c.hours_consumed|int }}节</span>
|
|||
|
|
</div>
|
|||
|
|
{% endfor %}
|
|||
|
|
{% else %}
|
|||
|
|
<p class="text-muted text-center py-4 mb-0">暂无消课记录</p>
|
|||
|
|
{% endif %}
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
{% endblock %}
|