feat(heures) : affichage des jours travaillés (CUSTOM) sur la vue Jour
Auto Tag Develop / tag (push) Successful in 12s

Le libellé sous le nom de l'employé affiche en suffixe les jours du planning
workDaysHours au format court (ex. BUREAU — CDI — LU,JE) pour les contrats CUSTOM.
Résolu à la date filtrée et exposé via WorkHourDayContext.workDaysHours ; formaté
front par formatWorkedDaysShort. Limité aux CUSTOM (35h/39h/forfait/intérim sans
planning → rien affiché) et à l'écran Heures (pas Heures Conducteurs).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-12 14:33:46 +02:00
parent 4b22270c60
commit 7187989003
12 changed files with 106 additions and 7 deletions
+3 -2
View File
@@ -14,7 +14,7 @@
<span class="font-normal text-neutral-600 text-sm">({{ contractLabel(employee) }})</span>
</p>
<p class="text-sm text-neutral-500 truncate">
{{ employee.site?.name ?? 'Sans site' }}<span v-if="getRowContractNature(employee.id)"> {{ contractNatureLabel(getRowContractNature(employee.id) ?? undefined) }}</span>
{{ employee.site?.name ?? 'Sans site' }}<span v-if="getRowContractNature(employee.id)"> — {{ contractNatureLabel(getRowContractNature(employee.id) ?? undefined) }}</span><span v-if="getRowWorkedDaysLabel(employee.id)"> {{ getRowWorkedDaysLabel(employee.id) }}</span>
</p>
</div>
@@ -212,7 +212,7 @@
</p>
<p class="text-neutral-500 truncate inline-flex items-center gap-2">
<span>
{{ employee.site?.name ?? 'Sans site' }}<span v-if="getRowContractNature(employee.id)"> {{ contractNatureLabel(getRowContractNature(employee.id) ?? undefined) }}</span>
{{ employee.site?.name ?? 'Sans site' }}<span v-if="getRowContractNature(employee.id)"> — {{ contractNatureLabel(getRowContractNature(employee.id) ?? undefined) }}</span><span v-if="getRowWorkedDaysLabel(employee.id)"> {{ getRowWorkedDaysLabel(employee.id) }}</span>
</span>
<span
v-if="isAdmin && (rows[employee.id]?.isSiteValid ?? false)"
@@ -406,6 +406,7 @@ const props = defineProps<{
hasRowFormation: (employeeId: number) => boolean
getRowFormationLabel: (employeeId: number) => string
getRowContractNature: (employeeId: number) => 'CDI' | 'CDD' | 'INTERIM' | null
getRowWorkedDaysLabel: (employeeId: number) => string | null
getRowUpdatedAt: (employeeId: number) => string
getPresenceDayValue: (employeeId: number) => string
onAbsenceClick: (employeeId: number) => void
+6
View File
@@ -517,6 +517,11 @@ export const useHoursPage = () => {
return dayContextByEmployeeId.value.get(employeeId)?.contractNature ?? null
}
// Jours travaillés du planning (contrats CUSTOM uniquement), ex. "LU,VE". null sinon.
const getRowWorkedDaysLabel = (employeeId: number): string | null => {
return formatWorkedDaysShort(dayContextByEmployeeId.value.get(employeeId)?.workDaysHours)
}
const getRowUpdatedAt = (employeeId: number): string => {
const raw = rows.value[employeeId]?.updatedAt
if (!raw) return ''
@@ -1207,6 +1212,7 @@ export const useHoursPage = () => {
hasRowFormation,
getRowFormationLabel,
getRowContractNature,
getRowWorkedDaysLabel,
getRowUpdatedAt,
getPresenceDayValue,
openAbsenceDrawer,
+1
View File
@@ -29,6 +29,7 @@ export const documentationSections: DocSection[] = [
{ type: 'list', content: 'Boutons "Hier" / "Aujourd\'hui" / "Demain" pour naviguer rapidement\nSélecteur de date pour choisir une date spécifique\nFiltrage par site si vous avez accès à plusieurs sites' },
{ type: 'paragraph', content: 'Seuls les employés ayant un contrat actif à la date sélectionnée sont affichés.' },
{ type: 'note', content: 'Sous le nom de l\'employé, la nature du contrat (CDI / CDD / Intérim) affichée correspond à la période couvrant la date filtrée, et non à aujourd\'hui.' },
{ type: 'paragraph', content: 'Pour un contrat à temps partiel avec un planning de jours travaillés (contrat « personnalisé »), les jours travaillés sont rappelés à la suite du libellé site et nature, en abrégé : par exemple « BUREAU — CDI — LU,JE » pour un salarié travaillant le lundi et le jeudi. Les contrats 35h, 39h, forfait et intérim n\'affichent pas ce rappel.' },
{ type: 'paragraph', content: 'Sur la vue Jour, l\'affichage (saisie d\'heures ou cases de présence) et le libellé de contrat correspondent au contrat de l\'employé à la date consultée. Si un salarié a changé de type de contrat (par exemple un passage en forfait), les jours antérieurs à ce changement restent affichés selon l\'ancien contrat.' },
],
},
+2
View File
@@ -87,6 +87,7 @@
:has-row-formation="hasRowFormation"
:get-row-formation-label="getRowFormationLabel"
:get-row-contract-nature="getRowContractNature"
:get-row-worked-days-label="getRowWorkedDaysLabel"
:get-row-updated-at="getRowUpdatedAt"
:get-presence-day-value="getPresenceDayValue"
:on-absence-click="openAbsenceDrawer"
@@ -215,6 +216,7 @@ const {
hasRowFormation,
getRowFormationLabel,
getRowContractNature,
getRowWorkedDaysLabel,
getRowUpdatedAt,
getPresenceDayValue,
openAbsenceDrawer,
+1
View File
@@ -119,6 +119,7 @@ export type WorkHourDayContextRow = {
weeklyHours?: number | null
contractType?: ContractType | null
contractName?: string | null
workDaysHours?: Record<number, number> | null
}
export type WorkHourDayContext = {
+20
View File
@@ -37,6 +37,26 @@ export const requiresWorkDaysHours = (
const DAY_SHORT_LABELS: Record<number, string> = { 1: 'Lun', 2: 'Mar', 3: 'Mer', 4: 'Jeu', 5: 'Ven' }
const DAY_TINY_LABELS: Record<number, string> = { 1: 'LU', 2: 'MA', 3: 'ME', 4: 'JE', 5: 'VE' }
/**
* Very compact worked-days summary for the day view header, e.g. "LU,VE".
* Lists the iso days actually worked (minutes > 0), uppercase 2-letter, comma-separated.
* Returns null when the schedule is empty/unset (non-CUSTOM contracts have no schedule).
*/
export const formatWorkedDaysShort = (
workDaysHours: Record<number, number> | null | undefined
): string | null => {
if (!workDaysHours) return null
const days = Object.entries(workDaysHours)
.map(([iso, minutes]) => [Number(iso), Number(minutes)] as const)
.filter(([iso, minutes]) => iso >= 1 && iso <= 5 && minutes > 0)
.sort(([a], [b]) => a - b)
.map(([iso]) => DAY_TINY_LABELS[iso])
if (days.length === 0) return null
return days.join(',')
}
/**
* Compact human-readable summary of a per-day schedule, e.g. "Lun 2h, Jeu 2h".
* Returns null when the schedule is empty/unset.