Files
drl_2/xuexiao/templates/keshibiao_snapshots.html

131 lines
7.2 KiB
HTML
Raw Normal View History

2026-05-29 10:28:07 +08:00
{% extends "base.html" %}
{% from 'macros/sortable.html' import sort_th %}
{% block title %}学员课时余额{% endblock %}
{% block content %}
<div class="page-toolbar">
<div>
<h4 class="page-title"><i class="bi bi-wallet2"></i> 学员课时余额</h4>
<p class="page-sub text-muted">
数据来自课时核对表 Excel 导入 · 当前查看
<strong class="text-primary">{{ year }}-{{ '%02d'|format(month) }}</strong>
{% if total %}(共 {{ total }} 条学员×课程){% endif %}
</p>
</div>
<div class="d-flex gap-2">
<a href="{{ url_for('keshibiao_index') }}" class="btn btn-neo-secondary btn-sm"><i class="bi bi-cloud-upload"></i> 导入</a>
</div>
</div>
{% if period_stats_list %}
<div class="neo-surface p-3 mb-3">
<div class="small text-muted mb-2">切换月份(数字为当月导入条数,请选 400+ 条的完整月份)</div>
<div class="d-flex flex-wrap gap-2">
{% for p in period_stats_list %}
<a href="{{ url_for('keshibiao_snapshots', year=p.year, month=p.month, keyword=keyword or '', sort=sort or none, order=order if sort else none) }}"
class="btn btn-sm {% if year == p.year and month == p.month %}btn-primary{% elif p.count < 20 %}btn-outline-warning{% else %}btn-outline-secondary{% endif %}">
{{ p.year }}-{{ '%02d'|format(p.month) }}
<span class="badge {% if year == p.year and month == p.month %}bg-light text-primary{% else %}bg-secondary{% endif %} ms-1">{{ p.count }}</span>
</a>
{% endfor %}
</div>
</div>
{% endif %}
<div class="neo-surface p-3 mb-3">
<form method="GET" class="row g-2 align-items-end">
<input type="hidden" name="year" value="{{ year }}">
<input type="hidden" name="month" value="{{ month }}">
{% if sort %}<input type="hidden" name="sort" value="{{ sort }}">{% endif %}
{% if sort %}<input type="hidden" name="order" value="{{ order }}">{% endif %}
<div class="col-md-6">
<label class="form-label">搜索学员或课程</label>
<input type="text" class="form-control" name="keyword" value="{{ keyword or '' }}" placeholder="姓名 / scratch / 大班 …">
</div>
<div class="col-md-2">
<button type="submit" class="btn btn-neo-primary w-100"><i class="bi bi-search"></i> 搜索</button>
</div>
</form>
</div>
<div class="neo-table-wrap">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0 keshi-balance-table">
<thead class="table-light sticky-top">
<tr>
<th>{{ sort_th('keshibiao_snapshots', 'student', '学员', sort, order, list_params, '') }}</th>
<th>{{ sort_th('keshibiao_snapshots', 'course', '课程', sort, order, list_params, '') }}</th>
<th class="text-end keshi-col-key">{{ sort_th('keshibiao_snapshots', 'end_lessons', '正课剩余', sort, order, list_params) }}</th>
<th class="text-end">{{ sort_th('keshibiao_snapshots', 'end_gift', '赠课剩余', sort, order, list_params) }}</th>
<th class="text-end keshi-col-key">{{ sort_th('keshibiao_snapshots', 'end_total', '总剩余课时', sort, order, list_params) }}</th>
<th class="text-end keshi-col-money">{{ sort_th('keshibiao_snapshots', 'end_balance', '账户余额', sort, order, list_params, title='折后口径账面余额') }}</th>
<th class="text-end keshi-col-money">{{ sort_th('keshibiao_snapshots', 'unit_price', '单价/节', sort, order, list_params) }}</th>
<th class="text-end">{{ sort_th('keshibiao_snapshots', 'consumed', '本月消课', sort, order, list_params) }}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for item in rows %}
{% set s = item.snap %}
{% set d = item.disp if item.disp is mapping else {} %}
{% set acc = item.acc %}
{% set stu = acc.student if acc else none %}
{% set crs = acc.course if acc else none %}
<tr>
<td>
{% if stu %}
<a href="{{ url_for('student_detail', id=stu.id) }}" class="fw-semibold text-decoration-none">{{ stu.name }}</a>
{% else %}<span class="text-muted">—</span>{% endif %}
</td>
<td><span class="badge bg-secondary-subtle text-dark border">{{ crs.course_code or crs.name if crs else '—' }}</span></td>
<td class="text-end keshi-col-key fs-6">{{ fmt_hours(d.get('end_lessons')) }}</td>
<td class="text-end">{{ fmt_hours(d.get('end_gift_lessons')) }}</td>
<td class="text-end keshi-col-key fs-5 fw-bold text-primary">{{ fmt_hours(d.get('end_total_lessons')) }}</td>
<td class="text-end keshi-col-money fs-5 fw-bold text-success">{{ fmt_money(d.get('end_balance')) }}</td>
<td class="text-end keshi-col-money fw-semibold">{{ fmt_price(d.get('unit_price')) }}</td>
<td class="text-end text-muted">{{ fmt_hours(s.consumed_lessons) }}</td>
<td>
{% if acc %}
<a href="{{ url_for('keshibiao_account', account_id=acc.id) }}" class="btn btn-sm btn-outline-primary">明细</a>
{% endif %}
</td>
</tr>
{% else %}
<tr>
<td colspan="9" class="text-center py-5">
<p class="text-muted mb-2">当前月份没有可显示的数据</p>
{% if period_stats_list %}
<p class="small">请点上方 <strong>2026-04(492)</strong> 等条数较多的月份;勿选仅 1 条的测试月。</p>
{% else %}
<p class="small">请先在「课时核对表」页导入 Excel。</p>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% if total > per_page %}
<nav class="mt-3">
<ul class="pagination justify-content-center">
{% if page > 1 %}
<li class="page-item"><a class="page-link" href="{{ url_for('keshibiao_snapshots', page=page-1, **list_params) }}">上一页</a></li>
{% endif %}
<li class="page-item disabled"><span class="page-link">第 {{ page }} / {{ ((total-1)//per_page)+1 }} 页</span></li>
{% if page * per_page < total %}
<li class="page-item"><a class="page-link" href="{{ url_for('keshibiao_snapshots', page=page+1, **list_params) }}">下一页</a></li>
{% endif %}
</ul>
</nav>
{% endif %}
{% endblock %}
{% block extra_css %}
<style>
.keshi-balance-table .keshi-col-key { min-width: 4.5rem; }
.keshi-balance-table .keshi-col-money { min-width: 6.5rem; }
.keshi-balance-table thead.sticky-top { top: 0; z-index: 2; }
</style>
{% endblock %}