Files
volleyball_miniapp/templates/index.html
2026-07-01 17:58:05 +03:00

207 lines
8.4 KiB
HTML

{% extends "base.html" %}
{% block title %}Voley — отметка посещения{% endblock %}
{% block header %}Отметка посещения{% endblock %}
{% block content %}
<section class="glass rounded-2xl p-4 sm:p-5">
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div>
<div class="text-sm text-slate-300">Выбранное воскресенье</div>
<div class="text-xl font-semibold">{{ selected_date }}</div>
</div>
<div class="w-full sm:w-[320px]">
<label class="text-sm text-slate-300">Календарь (только воскресенья)</label>
<input
id="datePicker"
class="mt-2 w-full rounded-xl bg-slate-950/60 border border-slate-800 px-3 py-2 text-slate-100 placeholder:text-slate-500 focus:outline-none focus:ring-2 focus:ring-indigo-500"
placeholder="Выберите воскресенье"
value="{{ selected_date }}"
/>
</div>
</div>
</section>
<section class="mt-5">
<div class="flex items-center justify-between">
<h2 class="text-lg font-semibold">Игроки</h2>
<div class="text-xs text-slate-400">{{ players|length }} активн.</div>
</div>
<div id="playersList" class="mt-3 grid gap-3">
{% for player in players %}
{% set present = present_map.get(player.id, False) %}
{% include "partials/player_row.html" %}
{% endfor %}
</div>
</section>
<section class="mt-8" id="teamsSection">
<div id="teamsBox">
{# По умолчанию рендерим команды детерминированно (по алфавиту): #}
{% set present_names = [] %}
{% for player in players %}
{% if present_map.get(player.id, False) %}
{% set _ = present_names.append(player.name) %}
{% endif %}
{% endfor %}
{% set count = present_names|length %}
{% set mid = (count + 1) // 2 %}
{% set team_a = present_names[:mid] %}
{% set team_b = present_names[mid:] %}
{% include "partials/teams.html" %}
</div>
</section>
<section class="mt-8 glass rounded-2xl p-4 sm:p-5">
<div class="flex items-center justify-between gap-3 flex-wrap">
<div>
<h2 class="text-lg font-semibold">График</h2>
<div class="text-xs text-slate-400">{{ chart_title }}</div>
</div>
<div class="flex gap-2">
<a
href="/?date={{ selected_date }}&view=month"
class="px-3 py-2 rounded-xl border text-sm {{ 'bg-indigo-600 border-indigo-500' if chart_view=='month' else 'bg-slate-950/40 border-slate-800 text-slate-200' }}"
>Месяц</a>
<a
href="/?date={{ selected_date }}&view=year"
class="px-3 py-2 rounded-xl border text-sm {{ 'bg-indigo-600 border-indigo-500' if chart_view=='year' else 'bg-slate-950/40 border-slate-800 text-slate-200' }}"
>Год</a>
</div>
</div>
<div class="mt-4 h-56 sm:h-64">
{# SVG-график без JS/CDN — всегда отображается #}
{% set max_v = (chart_values|max) if chart_values else 0 %}
{% if max_v < 1 %}{% set max_v = 1 %}{% endif %}
{% set n = chart_labels|length %}
<svg viewBox="0 0 200 100" class="w-full h-full block" style="width:100%;height:100%;display:block" role="img" aria-label="{{ chart_title }}">
<defs>
<linearGradient id="barGrad" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="rgba(129,140,248,0.95)"></stop>
<stop offset="55%" stop-color="rgba(99,102,241,0.86)"></stop>
<stop offset="100%" stop-color="rgba(59,130,246,0.62)"></stop>
</linearGradient>
<linearGradient id="bgGlow" x1="0" y1="0" x2="1" y2="1">
<stop offset="0%" stop-color="rgba(99,102,241,0.20)"></stop>
<stop offset="60%" stop-color="rgba(15,23,42,0.00)"></stop>
</linearGradient>
<filter id="softShadow" x="-20%" y="-20%" width="140%" height="140%">
<feDropShadow dx="0" dy="1.2" stdDeviation="1.2" flood-color="rgba(0,0,0,0.45)"></feDropShadow>
</filter>
</defs>
<!-- карточка/фон -->
<rect x="0" y="0" width="200" height="100" rx="5" fill="rgba(2,6,23,0.22)"></rect>
<rect x="0" y="0" width="200" height="100" rx="5" fill="url(#bgGlow)"></rect>
<rect x="0.8" y="0.8" width="198.4" height="98.4" rx="5" fill="transparent" stroke="rgba(148,163,184,0.16)" stroke-width="0.7"></rect>
{# параметры области построения #}
{% set padL = 16 %}
{% set padR = 3 %}
{% set padT = 8 %}
{% set padB = 18 %}
{% set plotW = 200 - padL - padR %}
{% set plotH = 100 - padT - padB %}
<!-- оси -->
<line x1="{{ padL }}" y1="{{ padT + plotH }}" x2="{{ 200 - padR }}" y2="{{ padT + plotH }}" stroke="rgba(148,163,184,0.18)" stroke-width="0.7"></line>
<line x1="{{ padL }}" y1="{{ padT }}" x2="{{ padL }}" y2="{{ padT + plotH }}" stroke="rgba(148,163,184,0.14)" stroke-width="0.7"></line>
<!-- сетка + подписи Y -->
{% for p in [0,25,50,75,100] %}
{% set y = padT + plotH - (plotH * p / 100) %}
<line x1="{{ padL }}" y1="{{ y }}" x2="{{ 200 - padR }}" y2="{{ y }}" stroke="rgba(148,163,184,0.12)" stroke-width="0.6"></line>
<text x="5" y="{{ y + 1.7 }}" font-size="3.6" fill="rgba(226,232,240,0.70)">{{ (max_v * p / 100)|round|int }}</text>
{% endfor %}
{% if n == 0 %}
<text x="{{ padL }}" y="50" font-size="5" fill="rgba(226,232,240,0.85)">Нет данных</text>
{% else %}
{% set barGap = 1.4 %}
{% set slot = plotW / n %}
{% set barW = slot - barGap %}
{% if barW < 0.9 %}{% set barW = 0.9 %}{% endif %}
{% for lab in chart_labels %}
{% set i = loop.index0 %}
{% set v = chart_values[i] %}
{% set h = (v / max_v) * plotH %}
{% set x = padL + (i * slot) + (barGap/2) %}
{% set y = padT + plotH - h %}
{% set cx = x + (barW/2) %}
<rect
x="{{ x }}"
y="{{ y }}"
width="{{ barW }}"
height="{{ h }}"
fill="url(#barGrad)"
stroke="rgba(165,180,252,0.55)"
stroke-width="0.25"
rx="1.1"
filter="url(#softShadow)"
>
<title>{{ lab }}: {{ v }}</title>
</rect>
{# значение над столбцом (если место позволяет) #}
{% if v > 0 and barW >= 2.2 %}
<text
x="{{ cx }}"
y="{{ y - 1.4 }}"
text-anchor="middle"
font-size="3.6"
fill="rgba(226,232,240,0.88)"
>{{ v }}</text>
{% endif %}
{% if (i % chart_label_step) == 0 %}
{% if chart_view == 'month' and lab|length == 10 %}
{% set show = lab[8:10] ~ '.' ~ lab[5:7] %}
{% elif chart_view == 'year' and lab|length == 7 %}
{% set show = lab[5:7] %}
{% else %}
{% set show = lab %}
{% endif %}
<text
x="{{ cx }}"
y="96.7"
text-anchor="middle"
font-size="3.6"
fill="rgba(226,232,240,0.70)"
>{{ show }}</text>
{% endif %}
{% endfor %}
{% endif %}
</svg>
</div>
</section>
<section class="mt-8 glass rounded-2xl p-4 sm:p-5">
<div class="flex items-center justify-between gap-3 flex-wrap">
<div>
<h2 class="text-lg font-semibold">Выгрузка данных</h2>
<div class="text-xs text-slate-400">История посещений игроков по датам</div>
</div>
<a
href="/api/export/attendance.xlsx"
class="px-4 py-2 rounded-xl bg-green-600 hover:bg-green-500 border border-green-500 text-sm font-medium transition-colors"
download
>Скачать Excel</a>
</div>
</section>
{% endblock %}
{% block scripts %}
<script>
window.__VOLEY__ = {
selectedDate: {{ selected_date|tojson }},
chartLabels: {{ chart_labels_json|safe }},
chartValues: {{ chart_values_json|safe }},
chartView: {{ chart_view|tojson }},
};
</script>
{% endblock %}