Initial commit
This commit is contained in:
206
templates/index.html
Normal file
206
templates/index.html
Normal file
@@ -0,0 +1,206 @@
|
||||
{% 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 %}
|
||||
Reference in New Issue
Block a user