Les cellules de jour étaient à largeur fixe (52px) → une bande de 7 jours (~400px)
débordait de ~57px sur mobile et défilait légèrement (6,5 jours visibles).
Override mobile `.os-day { flex:1 0 40px; width:auto }` : jusqu'à 7 jours, les
cellules s'étirent pour remplir la largeur (tableau de bord « cette/prochaine
semaine » = 7 tiennent pile). Au-delà (tournées = bande 14 j) elles gardent leur
plancher 40px et la bande défile comme avant.
Vérifié 375px : tableau de bord 7 j = ne défile plus (jour 41px) ; Planif 14 j =
défile toujours (jour 40px). Portée mobile uniquement.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
75 lines
4.5 KiB
Vue
75 lines
4.5 KiB
Vue
<template>
|
|
<!-- Bande d'occupation réutilisable : 1 cellule par jour, barre verticale « chaleur » (vert → rouge).
|
|
Extraite de la bande mobile Planif (.pm-strip). Utilisée : tableau de bord (charge de la semaine),
|
|
et partout où un aperçu de charge par jour est utile. Clic → @select(iso). -->
|
|
<div class="os-strip">
|
|
<button
|
|
v-for="d in days" :key="d.iso" type="button" class="os-day"
|
|
:class="{ active: d.iso === selected, today: d.today, weekend: d.weekend, holiday: d.holiday }"
|
|
:title="dayTitle(d)"
|
|
@click="$emit('select', d.iso)"
|
|
>
|
|
<span v-if="d.holiday" class="os-hol">★</span>
|
|
<span v-if="d.noShift && !d.unassigned" class="os-warn" title="Aucun quart planifié — capacité estimée">▲</span>
|
|
<span v-if="d.unassigned" class="os-unassigned" :title="d.unassigned + ' job(s) dû(s) ce jour, non assigné(s) — à répartir'">{{ d.unassigned }}</span>
|
|
<span class="os-dow">{{ d.dow }}</span>
|
|
<span class="os-num">{{ d.dnum }}</span>
|
|
<span class="os-bar"><span class="os-fill" :style="{ height: fillH(d) + '%', background: heatColor(d.ratio) }"></span></span>
|
|
<span class="os-h">{{ d.cap > 0 ? Math.round(d.h) + '/' + Math.round(d.cap) : (Math.round(d.h) + 'h') }}<span v-if="d.over" class="os-over">⚠</span></span>
|
|
</button>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { heatColor } from 'src/composables/useHelpers'
|
|
|
|
defineProps({
|
|
days: { type: Array, default: () => [] }, // [{ iso, dow, dnum, h, cap, ratio, over, weekend, holiday, noShift, today }]
|
|
selected: { type: String, default: '' },
|
|
})
|
|
defineEmits(['select'])
|
|
|
|
// Barre : min 12 % quand il y a de la charge (visible), 0 si rien ; plafonnée à 100 %.
|
|
function fillH (d) { return d.h > 0 ? Math.max(12, Math.min(100, Math.round((d.ratio || 0) * 100))) : 0 }
|
|
function dayTitle (d) {
|
|
const parts = [Math.round(d.h) + 'h à faire']
|
|
if (d.cap > 0) parts.push('/ ' + Math.round(d.cap) + 'h de capacité')
|
|
if (d.over) parts.push('· surchargé ⚠')
|
|
if (d.noShift) parts.push('· aucun quart (estimé)')
|
|
if (d.holiday) parts.unshift('★ férié —')
|
|
return parts.join(' ')
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
.os-strip { display: flex; gap: 6px; overflow-x: auto; padding-bottom: 4px; }
|
|
.os-strip::-webkit-scrollbar { height: 0; }
|
|
.os-day {
|
|
position: relative; flex: 0 0 auto; width: 52px; border: 1px solid var(--ops-border, #e2e8f0);
|
|
border-radius: 10px; background: #fff; display: flex; flex-direction: column; align-items: center;
|
|
gap: 2px; padding: 7px 2px; cursor: pointer; transition: border-color .15s, box-shadow .15s;
|
|
}
|
|
.os-day:hover { border-color: #c7d2fe; }
|
|
.os-day.active { border-color: #6366f1; box-shadow: 0 0 0 2px rgba(99, 102, 241, .18); }
|
|
.os-day.today .os-num { color: #6366f1; font-weight: 700; }
|
|
/* Différenciateur « jour courant » : liseré indigo en haut de la cellule (n'écrase pas la bague .active) */
|
|
.os-day.today::before { content: ''; position: absolute; top: -1px; left: 22%; right: 22%; height: 3px; border-radius: 0 0 3px 3px; background: #6366f1; }
|
|
.os-day.weekend { background: #f8fafc; }
|
|
.os-day.holiday { background: #fff7ed; border-color: #fdba74; }
|
|
.os-hol { position: absolute; top: 1px; left: 3px; color: #ea580c; font-size: 9px; line-height: 1; }
|
|
.os-warn { position: absolute; top: 2px; right: 3px; color: #ef4444; font-size: 9px; line-height: 1; pointer-events: none; }
|
|
/* Badge « dus non assignés ce jour » (flottant coin haut-droit) */
|
|
.os-unassigned { position: absolute; top: -5px; right: -5px; min-width: 16px; height: 16px; padding: 0 3px; border-radius: 8px; background: #ef4444; color: #fff; font-size: 10px; font-weight: 700; line-height: 16px; text-align: center; box-shadow: 0 1px 3px rgba(2, 6, 23, .3); pointer-events: none; }
|
|
.os-dow { font-size: 10px; color: var(--ops-text-secondary, #64748b); text-transform: capitalize; }
|
|
.os-num { font-size: 13px; font-weight: 600; color: var(--ops-text, #1e293b); }
|
|
.os-bar { width: 10px; height: 44px; background: #eef2f7; border-radius: 5px; overflow: hidden; display: flex; align-items: flex-end; margin: 3px 0; }
|
|
.os-fill { width: 100%; border-radius: 5px; transition: height .3s; }
|
|
.os-h { font-size: 10px; color: var(--ops-text-secondary, #64748b); white-space: nowrap; }
|
|
.os-over { color: #ef4444; margin-left: 1px; }
|
|
/* Mobile : ≤ 7 jours (bandes hebdo du tableau de bord) → les cellules s'étirent pour remplir la largeur
|
|
(fini le micro-défilement) ; au-delà (bande 14 j des tournées) elles gardent leur plancher et défilent. */
|
|
@media (max-width: 599px) {
|
|
.os-day { flex: 1 0 40px; width: auto; }
|
|
}
|
|
</style>
|