WeekScheduler
Import
import { WeekScheduler } from '@pzeta/vue-components'
Esempio Base
Props
| Prop | Tipo | Default | Descrizione |
|---|---|---|---|
resources | SchedulerResource[] | (required) | Elenco delle risorse mostrate sulle righe (es. autisti, mezzi, sale) |
events | SchedulerEvent[] | (required) | Elenco degli eventi/giri/turni da posizionare nella griglia |
startDate | Date | string | inizio settimana corrente | Data di riferimento; viene normalizzata all'inizio della settimana secondo weekStartsOn |
weekStartsOn | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 1 | Giorno di inizio settimana (0 = domenica, 1 = lunedi) |
resourceKey | string | (r) => string | number | 'id' | Nome del campo (o accessor) usato come chiave della risorsa |
eventResourceKey | string | (e) => string | number | null | 'resourceId' | Nome del campo (o accessor) che lega l'evento alla risorsa; null/undefined => riga non assegnati |
eventDateKey | string | (e) => string | 'date' | Nome del campo (o accessor) che fornisce la data ISO YYYY-MM-DD dell'evento |
showUnassignedRow | boolean | false | Mostra una riga aggiuntiva in alto per gli eventi senza resourceId |
unassignedLabel | string | 'Non assegnati' | Etichetta della riga non assegnati |
todayHighlight | boolean | true | Evidenzia con sfondo blu la colonna del giorno corrente |
locale | string | 'it-IT' | Locale Intl.DateTimeFormat per i label dei giorni |
minCellHeight | string | '40px' | Altezza minima della cella (CSS) |
resourceColumnWidth | string | '9rem' | Larghezza della colonna risorse (CSS) |
dayLabelFormat | 'short' | 'long' | 'numeric' | 'short' | Formato del nome del giorno nell'header colonna |
range | 'week' | 'month' | 'quarter' | 'week' | Arco delle colonne: la settimana di startDate, il suo mese, o tre mesi a partire dal suo mese |
minDayWidth | string | '6rem' | Larghezza minima di una colonna giorno: sugli archi lunghi la griglia scorre in orizzontale |
shifts | SchedulerShift[] | [] | Turni in cui si divide ogni giorno, in ordine. Vuoto = nessuna suddivisione |
eventShiftKey | string | (e) => string | number | null | 'shift' | Campo (o accessor) con il turno iniziale dell'evento, confrontato con SchedulerShift.key |
eventShiftEndKey | string | (e) => string | number | null | 'shiftEnd' | Campo (o accessor) con il turno finale, compreso, nello stesso giorno |
shiftLayout | 'columns' | 'rows' | 'columns' | columns: una sotto-colonna per turno; rows: una riga per turno |
minShiftWidth | string | minDayWidth | Solo columns: larghezza minima di ogni sotto-colonna turno |
shiftLabelWidth | string | '6rem' | Solo rows: larghezza della colonna con le etichette dei turni |
draggableEvents | boolean | false | Gli eventi si trascinano su altre celle, turni o sulla riga non assegnati ed emettono eventDrop |
eventDraggable | (e) => boolean | - | Con draggableEvents, false blocca il singolo evento (es. turni gia' confermati) |
droppable | boolean | false | Le celle accettano le righe di una DataTable con draggable-rows, o di qualunque elemento che chiama startRowsDrag, ed emettono cellDrop |
canDrop | (ctx: SchedulerCanDropContext) => boolean | - | false rifiuta la destinazione: evidenziata in rosso, nessun emit. ctx ha to e event (trascinamento interno) o data (rilascio esterno) |
SchedulerResource
| Proprieta' | Tipo | Descrizione |
|---|---|---|
id | string | number | Identificatore univoco (override possibile via resourceKey) |
[key] | unknown | Qualsiasi altro campo: viene esposto nello slot #resource per il rendering custom |
SchedulerEvent
| Proprieta' | Tipo | Descrizione |
|---|---|---|
id | string | number | Identificatore univoco dell'evento |
resourceId | string | number | null | Chiave della risorsa di appartenenza; null per gli eventi non assegnati |
date | string | Data ISO YYYY-MM-DD |
shift | string | number | Turno iniziale, solo con shifts (campo letto da eventShiftKey) |
shiftEnd | string | number | Turno finale, compreso, solo con shifts (campo letto da eventShiftEndKey) |
[key] | unknown | Qualsiasi altro campo: viene esposto nello slot #event |
SchedulerShift
| Proprieta' | Tipo | Descrizione |
|---|---|---|
key | string | number | Identificatore del turno, confrontato con il turno dell'evento (1 e '1' coincidono) |
label | string | Etichetta mostrata nell'intestazione (columns) o a inizio riga (rows) |
[key] | unknown | Campi liberi (orari, colore, ...) letti dagli slot, es. shiftHeader |
SchedulerDay
| Proprieta' | Tipo | Descrizione |
|---|---|---|
date | Date | Oggetto data del giorno |
dateStr | string | Data ISO YYYY-MM-DD |
label | string | Etichetta formattata secondo locale e dayLabelFormat |
isToday | boolean | true se corrisponde al giorno corrente |
dayIndex | number | Indice del giorno nella settimana (0-6) |
Slots
| Slot | Props | Descrizione |
|---|---|---|
resourceHeader | - | Contenuto dell'intestazione della colonna risorse (in alto a sinistra) |
dayHeader | { day: SchedulerDay } | Override del label di una colonna giorno |
shiftHeader | { day: SchedulerDay, shift: SchedulerShift } ({ shift } in rows) | Override dell'etichetta di un turno: sotto il giorno in columns, a inizio riga in rows |
resource | { resource: SchedulerResource } | Rendering della cella risorsa (colonna fissa di sinistra) |
event | { event, resource, day, shift, endShift, span, isUnassigned } | Rendering di un singolo evento. Con i turni e' il contenuto della barra: shift/endShift sono il turno iniziale e finale, span il numero di turni occupati; senza turni valgono null, null, 1 |
cell | { resource, day, shift, events, isUnassigned, dragAttrs } | Senza turni: override completo della cella. Con i turni: sfondo della sotto-cella, sotto le barre; events contiene gli eventi che coprono shift. Senza turni e con draggableEvents, v-bind="dragAttrs(event)" rende trascinabile l'elemento che disegna l'evento |
unassignedLabel | - | Override del label della riga non assegnati |
footerTotalsLabel | - | Etichetta della riga dei totali (prima colonna) |
footerTotals | { day, date, count, shift } | Una cella per giorno, o per giorno x turno in columns; count conta gli eventi del giorno, o quelli che coprono shift. La riga compare solo se lo slot e' fornito |
#cell ha precedenza sullo slot #event: se viene fornito, il rendering degli eventi all'interno della cella e' interamente delegato al consumer.
Con shifts invece le barre le posiziona sempre il componente, perche' una barra che attraversa piu' turni non puo' essere disegnata da uno slot che vede una sola sotto-cella: gli eventi si disegnano con #event, e #cell diventa lo sfondo della sotto-cella (es. un pulsante "+"), mostrato sotto le barre.Emits
| Evento | Payload | Descrizione |
|---|---|---|
update:startDate | Date | Emesso quando la data di partenza cambia (per v-model:start-date) |
cellClick | { resource: SchedulerResource | null, date: string, events: SchedulerEvent[], shift: SchedulerShift | null, originalEvent: MouseEvent } | Emesso al click su una cella vuota o sul background di una cella. Con i turni riporta la sotto-cella cliccata, ed events contiene gli eventi che coprono quel turno |
eventClick | { event: SchedulerEvent, resource: SchedulerResource | null, date: string, shift: SchedulerShift | null, endShift: SchedulerShift | null, originalEvent: MouseEvent } | Emesso al click su un singolo evento; originalEvent.stopPropagation() viene chiamato automaticamente. shift/endShift sono il turno iniziale e finale (null senza turni) |
eventDrop | { event, from: SchedulerSpanRef, to: SchedulerSpanRef, copy: boolean, originalEvent: DragEvent } | Con draggableEvents: evento rilasciato su un'altra posizione. from/to hanno resource, date, shift, endShift; copy e' true con Ctrl o Alt. Il componente non sposta niente: aggiorna events il consumer |
cellDrop | { data: unknown[], to: SchedulerCellRef, originalEvent: DragEvent } | Con droppable: elementi esterni rilasciati su una cella (to ha resource, date, shift) |
Esempi
Slot custom con stato colorato
Pattern tipico per planner di giri/turni: ogni evento ha uno stato (PIANIFICATO, IN_CORSO, ...) mappato a una variante di colore.
Riga "Non assegnati" + handler click
Abilita una riga in alto per gli eventi con resourceId: null e gestisce sia il click sulla cella sia il click sul singolo evento.
Navigazione settimana (v-model:start-date)
v-model:start-date permette di pilotare la settimana visualizzata da un controllo esterno (toolbar, date picker, scorciatoie).
Turni: Mattino e Pomeriggio
Con shifts ogni giorno si divide in una sotto-colonna per turno. Un evento con shift e shiftEnd diversi e' una sola barra sui turni che occupa; gli eventi che si sovrappongono nella stessa cella vanno su corsie diverse.
Turni in righe su un mese
Con molti giorni le sotto-colonne diventano troppe (un trimestre con 3 turni sono fino a 276 colonne): shift-layout="rows" da' a ogni risorsa una riga per turno e lascia una colonna per giorno. Un evento su piu' turni e' una barra verticale; le corsie si affiancano dentro la colonna del giorno.
Drag & drop tra celle
Con draggable-events gli eventi si trascinano su un'altra risorsa, un altro giorno o un altro turno, compresa la riga "Non assegnati". Lo scheduler emette eventDrop e non sposta niente: e' la pagina ad aggiornare events (e a salvare). Una barra su piu' turni conserva lunghezza e punto di presa; se non entra nella giornata la destinazione non e' valida. Con Ctrl (Alt su macOS) copy e' true e il consumer duplica invece di spostare.
@event-click che apre un dialog con risorsa, giorno e turni. La demo DragDrop.vue della libreria lo mostra.Rilascio da sorgenti esterne
Con droppable le celle accettano le righe di una DataTable con draggable-rows (tutta la selezione, se la riga trascinata ne fa parte) e ricevono cellDrop. Lo stesso meccanismo vale per Tree e TreeTable. Qualunque altro elemento diventa una sorgente chiamando startRowsDrag nel suo dragstart e endRowsDrag nel dragend. Un elemento esterno occupa una sola sotto-cella: se il nuovo evento deve coprire piu' turni, lo decide il consumer.
Accessor function per chiavi non standard
Se il modello dati usa chiavi diverse (es. idautista, idgiro), passa una funzione invece di una stringa.
<WeekScheduler
:resources="autisti"
:events="giri"
:resource-key="(r) => r.idautista"
:event-resource-key="(e) => e.idautista"
:event-date-key="(e) => e.data"
:event-shift-key="(e) => e.codturnoinizio"
:event-shift-end-key="(e) => e.codturnofine"
>
<template #resource="{ resource }">
{{ resource.cognome }} {{ resource.nome }}
</template>
<template #event="{ event }">
Giro #{{ event.idgiro }}
</template>
</WeekScheduler>
Note Comportamento
- La data di partenza viene normalizzata all'inizio della settimana corrente in base a
weekStartsOn: passare2026-05-14conweekStartsOn: 1produce comunque una griglia che parte da lunedi - Gli eventi vengono indicizzati per
(resourceId, date)in unMapricalcolato in modo reattivo suevents/resources: le mutazioni alle reference sono efficienti - Il click su un evento ferma la propagazione (
stopPropagation) per non far scattare anchecellClick - La colonna delle risorse e' sticky (
position: sticky; left: 0). La griglia ha una larghezza minima calcolata dalle colonne (resourceColumnWidth+ giorni xminDayWidth, o giorni x turni xminShiftWidthincolumns): sotto quella larghezza scorre in orizzontale - Eventi con
resourceIdnon presente inresourcesvengono ignorati nel rendering (non si crea una riga fantasma) - Con i turni, un evento il cui turno iniziale non corrisponde a nessuno
shift.key(o e'null) non viene mostrato, come gli eventi senza risorsa quandoshowUnassignedRowe' spento. Un turno finale assente, sconosciuto o precedente all'iniziale riduce l'evento al solo turno iniziale. Gli eventi a cavallo di due giorni non sono supportati - Con i turni le corsie sono il minimo indispensabile: gli eventi si scorrono per turno iniziale e ognuno va nella prima corsia libera, quindi una barra Mattino e una Pomeriggio stanno sulla stessa corsia
- Con i turni la tabella usa
table-layout: fixed: le colonne hanno larghezze uguali e non si adattano al contenuto, che va troncato (es.truncate) se non ci sta - Drag & drop: e' HTML5 nativo come in
DataTable,TreeeTreeTable, quindi su touch vale il supporto del browser. Durante il trascinamento la destinazione e' evidenziata su tutte le sotto-celle che l'evento occuperebbe (blu se valida, rossa se rifiutata), e vicino ai bordi la griglia scorre in orizzontale. Un rilascio nella posizione di partenza non emette nulla. SenzadraggableEventsedroppablenon c'e' nessun attributodraggablene' listener di trascinamento
Accessibilita'
- Le celle e gli eventi sono
<div>con handler click; per planner accessibili da tastiera valutare l'override via slot#cellcon elementi<button>nativi - Il giorno corrente riceve una variazione di colore (
bg-blue-50 text-blue-700) quandotodayHighlighte' attivo - Con i turni ogni barra contiene un testo visibile solo agli screen reader con giorno e intervallo di turni (es. "lun 06/10, Mattino–Pomeriggio"), letto prima del contenuto dello slot
#event
TypeScript
import type {
WeekSchedulerProps,
WeekSchedulerEmits,
SchedulerResource,
SchedulerEvent,
SchedulerCellClickPayload,
SchedulerEventClickPayload,
SchedulerShift,
SchedulerEventDropPayload,
SchedulerCellDropPayload,
} from '@pzeta/vue-components'
interface Autista extends SchedulerResource {
idautista: number
cognome: string
nome: string
}
interface Giro extends SchedulerEvent {
idgiro: number
descrizione: string
codstato: 'PIANIFICATO' | 'ASSEGNATO' | 'IN_CORSO' | 'COMPLETATO' | 'ANNULLATO'
}
const onEventClick = (payload: SchedulerEventClickPayload) => {
const giro = payload.event as Giro
console.log('giro', giro.idgiro, giro.codstato)
}
Quando usarlo
- Planner giornaliero/settimanale per risorse (autisti, mezzi, dipendenti, sale)
- Gestione turni e assegnazioni
- Visualizzazione a griglia di prenotazioni o appuntamenti
Per casi diversi:
- Vista mese con sidebar eventi del giorno → EventCalendar
- Cronologia eventi singola (non gridata per risorsa) → Timeline
- Selezione di una singola data →
DatePicker(categoria forms)
TreeTable
Tabella con struttura dati gerarchica espandibile, supporto per ordinamento, paginazione e selezione nodi tramite il sub-componente Column.
YearCalendar
Overview annuale a 12 mini-mesi in griglia responsive con eventi puntuali per giorno (pallino colorato per tipo, tooltip e drill-down via day-click).