Ajoute colonnes Δ sem. / Fin cible, supprime solde global, indicateurs minima
- Nouvelles colonnes : Δ sem. (solde cumulé semaine) et Fin cible (heure de sortie aprem optimale pour 0h suppl. en fin de semaine) - Δ sem. n'est affiché que quand la journée est complète et la chaîne de jours ininterrompue (pas de saut de jour non saisi) - Fin cible disparaît quand la journée est validée (passée/complète) - Delta = "—" pour les jours non travaillés (futur ou congé jour) - Indicateur warn (fond rouge) sur matin/aprem si horaires < minimum (matin 09:00→12:00, aprem 14:00→17:00) ; mise à jour live via JS - Suppression du solde global (3 cartes au lieu de 4) - Tableau sans largeurs fixes + container 1100 px pour éviter scroll horizontal sur écrans normaux ; touch-scroll conservé sur mobile - Base reste 39h/semaine (7h48/jour) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@ -1,3 +1,13 @@
|
||||
{% set matin_cg = 'matin' in j.conge or 'jour' in j.conge %}
|
||||
{% set aprem_cg = 'aprem' in j.conge or 'jour' in j.conge %}
|
||||
{% set matin_warn = not matin_cg and j.du_min > 0 and (
|
||||
(j.matin_entree and j.matin_entree > '09:00') or
|
||||
(j.matin_sortie and j.matin_sortie < '12:00')
|
||||
) %}
|
||||
{% set aprem_warn = not aprem_cg and j.du_min > 0 and (
|
||||
(j.aprem_entree and j.aprem_entree > '14:00') or
|
||||
(j.aprem_sortie and j.aprem_sortie < '17:00')
|
||||
) %}
|
||||
<tr id="row-{{ j.date }}">
|
||||
|
||||
<td class="col-jour">
|
||||
@ -6,7 +16,7 @@
|
||||
</td>
|
||||
|
||||
<td class="c-matin">
|
||||
<div id="cg-matin-{{ j.date }}" class="td-fill{% if 'matin' in j.conge or 'jour' in j.conge %} cg{% endif %}">
|
||||
<div id="cg-matin-{{ j.date }}" class="td-fill{% if matin_cg %} cg{% elif matin_warn %} warn{% endif %}">
|
||||
<div class="time-pair">
|
||||
<input class="time-input" type="time" name="matin_entree"
|
||||
data-date="{{ j.date }}" value="{{ j.matin_entree or '' }}">
|
||||
@ -18,7 +28,7 @@
|
||||
</td>
|
||||
|
||||
<td class="c-aprem">
|
||||
<div id="cg-aprem-{{ j.date }}" class="td-fill{% if 'aprem' in j.conge or 'jour' in j.conge %} cg{% endif %}">
|
||||
<div id="cg-aprem-{{ j.date }}" class="td-fill{% if aprem_cg %} cg{% elif aprem_warn %} warn{% endif %}">
|
||||
<div class="time-pair">
|
||||
<input class="time-input" type="time" name="aprem_entree"
|
||||
data-date="{{ j.date }}" value="{{ j.aprem_entree or '' }}">
|
||||
@ -37,14 +47,36 @@
|
||||
|
||||
<td class="col-calc">
|
||||
<span id="calc-{{ j.date }}-delta">
|
||||
<span class="{% if j.delta_min > 0 %}delta-pos{% elif j.delta_min < 0 %}delta-neg{% else %}delta-zero{% endif %}">
|
||||
{%- if j.travaille_min or j.du_min -%}
|
||||
<span class="{% if j.travaille_min and j.delta_min > 0 %}delta-pos{% elif j.travaille_min and j.delta_min < 0 %}delta-neg{% else %}delta-zero{% endif %}">
|
||||
{%- if j.travaille_min -%}
|
||||
{% if j.delta_min > 0 %}+{% endif %}{{ j.delta }}
|
||||
{%- else %}—{%- endif %}
|
||||
</span>
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="col-cumul">
|
||||
<span id="calc-{{ j.date }}-cumul">
|
||||
{%- if j.cumul_visible -%}
|
||||
<span class="{% if j.delta_cumul_min > 0 %}delta-pos{% elif j.delta_cumul_min < 0 %}delta-neg{% else %}delta-zero{% endif %}">
|
||||
{% if j.delta_cumul_min > 0 %}+{% elif j.delta_cumul_min < 0 %}-{% endif %}{{ j.delta_cumul if j.delta_cumul_min != 0 else '0h00' }}
|
||||
</span>
|
||||
{%- else -%}
|
||||
<span class="delta-zero">—</span>
|
||||
{%- endif %}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="col-cible">
|
||||
<span id="calc-{{ j.date }}-cible">
|
||||
{%- if j.sortie_cible and not j.is_complete -%}
|
||||
<span class="cible-num">{{ j.sortie_cible }}</span>
|
||||
{%- else -%}
|
||||
<span class="delta-zero">—</span>
|
||||
{%- endif %}
|
||||
</span>
|
||||
</td>
|
||||
|
||||
<td class="col-save">
|
||||
<button class="btn-valider"
|
||||
hx-post="/pointage/{{ j.date }}"
|
||||
|
||||
@ -14,11 +14,5 @@
|
||||
{% if result.solde_min > 0 %}+{% endif %}{{ result.solde }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="solde-item {% if solde_global_min > 0 %}item-pos{% elif solde_global_min < 0 %}item-neg{% endif %}">
|
||||
<div class="solde-eyebrow">Solde global</div>
|
||||
<div class="solde-num {% if solde_global_min > 0 %}pos{% elif solde_global_min < 0 %}neg{% endif %}">
|
||||
{% if solde_global_min > 0 %}+{% endif %}{{ solde_global }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -82,7 +82,7 @@
|
||||
|
||||
/* ── Layout ── */
|
||||
.container {
|
||||
max-width: 940px;
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem 1.5rem;
|
||||
display: flex;
|
||||
@ -124,7 +124,7 @@
|
||||
/* ── Soldes ── */
|
||||
.soldes {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
border: 1.5px solid var(--rule);
|
||||
background: var(--surface);
|
||||
}
|
||||
@ -156,12 +156,12 @@
|
||||
.solde-num.neutral { color: var(--text); }
|
||||
|
||||
/* ── Table ── */
|
||||
.table-section { overflow-x: auto; }
|
||||
.table-section { overflow-x: auto; -webkit-overflow-scrolling: touch; }
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
border: 1.5px solid var(--rule);
|
||||
background: var(--surface);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.th-group th {
|
||||
@ -272,14 +272,27 @@
|
||||
.time-input:focus { outline: none; border-color: var(--accent); background: #fff; }
|
||||
tr.htmx-request .time-input { opacity: .4; }
|
||||
|
||||
.col-calc { text-align: right; white-space: nowrap; width: 72px; }
|
||||
.col-calc { text-align: right; padding-left: .5rem; }
|
||||
.calc-num { font-family: var(--mono); font-size: 13px; color: var(--muted); }
|
||||
.delta-pos { font-family: var(--mono); font-size: 13px; font-weight: 500; color: var(--pos); }
|
||||
.delta-neg { font-family: var(--mono); font-size: 13px; font-weight: 500; color: var(--neg); }
|
||||
.delta-zero{ font-family: var(--mono); font-size: 13px; color: var(--rule); }
|
||||
|
||||
.col-save { width: 36px; text-align: center; padding: .4rem .3rem; }
|
||||
.g-save { width: 36px; background: var(--ground); }
|
||||
/* Warn state: time input violates minimum directive */
|
||||
td.c-matin .td-fill.warn,
|
||||
td.c-aprem .td-fill.warn { border-left-color: var(--neg); background: var(--neg-bg); }
|
||||
.td-fill.warn .time-input { background: transparent; }
|
||||
tbody tr:hover .td-fill.warn { background: var(--neg-bg); }
|
||||
|
||||
/* Cumulative delta and sortie cible columns */
|
||||
.col-cumul { text-align: right; padding-left: .5rem; }
|
||||
.col-cible { text-align: right; padding-left: .5rem; }
|
||||
.g-cumul { text-align: right; }
|
||||
.g-cible { text-align: right; }
|
||||
.cible-num { font-family: var(--mono); font-size: 12px; color: var(--accent); font-weight: 500; }
|
||||
|
||||
.col-save { text-align: center; padding: .4rem .3rem; }
|
||||
.g-save { background: var(--ground); }
|
||||
.btn-valider {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
@ -294,7 +307,7 @@
|
||||
}
|
||||
.btn-valider:hover { background: var(--accent); color: #fff; }
|
||||
.btn-valider.htmx-request { opacity: .4; pointer-events: none; }
|
||||
.col-conge { width: 88px; text-align: center; }
|
||||
.col-conge { text-align: center; }
|
||||
.conge-btns { display: flex; gap: 3px; justify-content: center; }
|
||||
.btn-cg {
|
||||
display: inline-flex;
|
||||
|
||||
@ -46,7 +46,9 @@
|
||||
<th class="g-matin">Matin</th>
|
||||
<th class="g-aprem">Après-midi</th>
|
||||
<th class="g-calc" rowspan="2">Travaillé</th>
|
||||
<th class="g-calc" rowspan="2">Delta</th>
|
||||
<th class="g-calc" rowspan="2">Δ jour</th>
|
||||
<th class="g-cumul" rowspan="2">Δ sem.</th>
|
||||
<th class="g-cible" rowspan="2">Fin cible</th>
|
||||
<th class="g-save" rowspan="2"></th>
|
||||
<th class="g-conge" rowspan="2">Congé</th>
|
||||
</tr>
|
||||
@ -202,4 +204,25 @@
|
||||
})();
|
||||
</script>
|
||||
|
||||
<script>
|
||||
// Live warn on time inputs that violate minimum directives
|
||||
document.addEventListener('input', function(e) {
|
||||
if (!e.target.matches('.time-input')) return;
|
||||
var date = e.target.dataset.date;
|
||||
var me = document.querySelector('[name="matin_entree"][data-date="' + date + '"]');
|
||||
var ms = document.querySelector('[name="matin_sortie"][data-date="' + date + '"]');
|
||||
var ae = document.querySelector('[name="aprem_entree"][data-date="' + date + '"]');
|
||||
var as = document.querySelector('[name="aprem_sortie"][data-date="' + date + '"]');
|
||||
var maDiv = document.getElementById('cg-matin-' + date);
|
||||
var apDiv = document.getElementById('cg-aprem-' + date);
|
||||
if (maDiv && !maDiv.classList.contains('cg')) {
|
||||
var warn = (me && me.value && me.value > '09:00') || (ms && ms.value && ms.value < '12:00');
|
||||
maDiv.classList.toggle('warn', !!warn);
|
||||
}
|
||||
if (apDiv && !apDiv.classList.contains('cg')) {
|
||||
var warnA = (ae && ae.value && ae.value > '14:00') || (as && as.value && as.value < '17:00');
|
||||
apDiv.classList.toggle('warn', !!warnA);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user