Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Permet de consulter les exercices passés (table hebdomadaire RTT) en réutilisant le pattern de l'onglet Congés. Plage bornée par max(début historique contrat, RTT_START_DATE). Bouton + Payer les RTT verrouillé sur exercices clos. Onglet masqué pour FORFAIT (inchangé). Backend : rttStartDate désormais toujours exposé sur EmployeeRttSummary pour que le sélecteur conserve sa borne lors de la navigation vers un exercice passé. Le masquage existant des lignes Report continue de fonctionner (comparaison mois-à-mois). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
361 lines
16 KiB
Vue
361 lines
16 KiB
Vue
<template>
|
|
<div class="h-full overflow-hidden flex flex-col">
|
|
|
|
<div v-if="isLoading" class="mt-6 rounded-lg border border-neutral-200 bg-white p-6 text-md text-neutral-600">
|
|
Chargement...
|
|
</div>
|
|
|
|
<div v-else-if="!employee"
|
|
class="mt-6 rounded-lg border border-neutral-200 bg-white p-6 text-md text-neutral-600">
|
|
Employé introuvable.
|
|
</div>
|
|
|
|
<div v-else class="flex min-h-0 flex-1 flex-col">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<div class="flex items-center gap-4">
|
|
<h1 class="text-[32px] font-bold">{{ employee.firstName }} {{ employee.lastName }}</h1>
|
|
<button
|
|
class="inline-flex items-center justify-center rounded-md p-1 transition-colors duration-150 focus:outline-none focus-visible:ring-2 bg-primary-500 hover:bg-secondary-500 active:bg-primary-500 text-white cursor-pointer"
|
|
title="Export heures"
|
|
@click="isYearlyHoursDrawerOpen = true"
|
|
>
|
|
<Icon name="mdi:printer" size="24" />
|
|
</button>
|
|
</div>
|
|
<p>Date d'entrée : {{ employee.entryDate ? employee.entryDate.split('-').reverse().join('/') : '-' }}</p>
|
|
</div>
|
|
<div class="text-right">
|
|
<p class="font-bold text-[22px]">{{ contractNatureLabel(employee.currentContractNature) }} {{ employeeContractWorkLabel }}{{ forfaitRemainingDaysLabel }}</p>
|
|
<p class="text-[18px]">{{ employee.site?.name ?? '-' }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="mt-[44px] border-b border-primary-500">
|
|
<div class="flex justify-center gap-16 text-2xl font-bold">
|
|
<button
|
|
class="pb-2 border-b-2 flex items-center gap-3"
|
|
:class="activeTab === 'contract'
|
|
? 'border-primary-500 text-primary-500'
|
|
: 'border-transparent text-primary-500/50 hover:text-primary-500'"
|
|
@click="activeTab = 'contract'"
|
|
>
|
|
<Icon name="mdi:file-check-outline" size="24" class="align-self"/>
|
|
Suivi contrat
|
|
</button>
|
|
<button
|
|
v-if="showLeaveTab"
|
|
class="pb-2 border-b-2 flex items-center gap-3"
|
|
:class="activeTab === 'leave'
|
|
? 'border-primary-500 text-primary-500'
|
|
: 'border-transparent text-primary-500/50 hover:text-primary-500'"
|
|
@click="activeTab = 'leave'"
|
|
>
|
|
<Icon name="mdi:event-blank-outline" size="24" class="align-self"/>
|
|
Congé
|
|
</button>
|
|
<button
|
|
v-if="showRttTab"
|
|
class="pb-2 border-b-2 flex items-center gap-3"
|
|
:class="activeTab === 'rtt'
|
|
? 'border-primary-500 text-primary-500'
|
|
: 'border-transparent text-primary-500/50 hover:text-primary-500'"
|
|
@click="activeTab = 'rtt'"
|
|
>
|
|
<Icon name="mdi:schedule" size="24" class="align-self"/>
|
|
RTT
|
|
</button>
|
|
<button
|
|
class="pb-2 border-b-2 flex items-center gap-3"
|
|
:class="activeTab === 'mileage'
|
|
? 'border-primary-500 text-primary-500'
|
|
: 'border-transparent text-primary-500/50 hover:text-primary-500'"
|
|
@click="activeTab = 'mileage'"
|
|
>
|
|
<Icon name="mdi:account-cash-outline" size="24" class="align-self"/>
|
|
Frais
|
|
</button>
|
|
<button
|
|
class="pb-2 border-b-2 flex items-center gap-3"
|
|
:class="activeTab === 'formation'
|
|
? 'border-primary-500 text-primary-500'
|
|
: 'border-transparent text-primary-500/50 hover:text-primary-500'"
|
|
@click="activeTab = 'formation'"
|
|
>
|
|
<Icon name="mdi:school-outline" size="24" class="align-self"/>
|
|
Formation
|
|
</button>
|
|
<button
|
|
class="pb-2 border-b-2 flex items-center gap-3"
|
|
:class="activeTab === 'bonus'
|
|
? 'border-primary-500 text-primary-500'
|
|
: 'border-transparent text-primary-500/50 hover:text-primary-500'"
|
|
@click="activeTab = 'bonus'"
|
|
>
|
|
<Icon name="mdi:money-100" size="24" class="align-self"/>
|
|
Prime
|
|
</button>
|
|
<button
|
|
class="pb-2 border-b-2 flex items-center gap-3"
|
|
:class="activeTab === 'observation'
|
|
? 'border-primary-500 text-primary-500'
|
|
: 'border-transparent text-primary-500/50 hover:text-primary-500'"
|
|
@click="activeTab = 'observation'"
|
|
>
|
|
<Icon name="mdi:note-text-outline" size="24" class="align-self"/>
|
|
Observation
|
|
</button>
|
|
</div>
|
|
</div>
|
|
<div class="min-h-0 flex-1">
|
|
<EmployeesContractTab
|
|
v-if="activeTab === 'contract'"
|
|
class="h-full overflow-y-auto pr-1"
|
|
:contract-history="contractHistory"
|
|
:contract-nature-label="contractNatureLabel"
|
|
:contract-history-label="contractHistoryLabel"
|
|
:format-date="formatDate"
|
|
:is-contract-submitting="isContractSubmitting"
|
|
:can-close-current-contract="canCloseCurrentContract"
|
|
:is-create-contract-submitting="isCreateContractSubmitting"
|
|
:contracts="contracts"
|
|
:can-create-contract="canCreateContract"
|
|
:is-contract-drawer-open="isContractDrawerOpen"
|
|
:contract-form="contractForm"
|
|
:readonly-field-class="readonlyFieldClass"
|
|
:close-contract-worked-hours-label="closeContractWorkedHoursLabel"
|
|
:contract-end-date-field-class="contractEndDateFieldClass"
|
|
:show-contract-end-date-error="showContractEndDateError"
|
|
:is-contract-end-date-valid="isContractEndDateValid"
|
|
:is-create-contract-drawer-open="isCreateContractDrawerOpen"
|
|
:create-contract-form="createContractForm"
|
|
:create-contract-nature-field-class="createContractNatureFieldClass"
|
|
:create-contract-field-class="createContractFieldClass"
|
|
:create-contract-start-date-field-class="createContractStartDateFieldClass"
|
|
:shows-create-contract-end-date="showsCreateContractEndDate"
|
|
:requires-create-contract-end-date="requiresCreateContractEndDate"
|
|
:create-contract-end-date-field-class="createContractEndDateFieldClass"
|
|
:is-create-contract-form-valid="isCreateContractFormValid"
|
|
:requires-create-work-days-hours="requiresCreateWorkDaysHours"
|
|
:selected-create-contract="selectedCreateContract"
|
|
:on-open-close-contract-drawer="openCloseContractDrawer"
|
|
:on-open-create-contract-drawer="openCreateContractDrawer"
|
|
:on-update-contract-drawer-open="setContractDrawerOpen"
|
|
:on-update-create-contract-drawer-open="setCreateContractDrawerOpen"
|
|
:on-submit-close-contract="submitContractUpdate"
|
|
:on-submit-create-contract="submitCreateContract"
|
|
:suspension-forms="suspensionForms"
|
|
:is-suspension-submitting="isSuspensionSubmitting"
|
|
:on-submit-suspension="submitSuspension"
|
|
:on-add-suspension-form="addSuspensionForm"
|
|
:current-contract-period-id="currentActiveContractPeriodId"
|
|
:interim-agencies="interimAgencies"
|
|
/>
|
|
<div v-else-if="showLeaveTab && activeTab === 'leave'" class="h-full">
|
|
<div v-if="isLeaveLoading" class="mt-6 rounded-lg border border-neutral-200 bg-white p-6 text-md text-neutral-600">
|
|
Chargement...
|
|
</div>
|
|
<EmployeesLeaveTab
|
|
v-else
|
|
class="h-full"
|
|
:absences="employeeAbsences"
|
|
:summary="leaveSummary"
|
|
:public-holidays="publicHolidays"
|
|
:selected-year="selectedLeaveYear"
|
|
:available-years="availableLeaveYears"
|
|
:current-year="currentLeaveYear"
|
|
@update-fractioned-days="submitFractionedDays"
|
|
@update-paid-leave-days="submitPaidLeaveDays"
|
|
@update-selected-year="setSelectedLeaveYear"
|
|
/>
|
|
</div>
|
|
<div v-else-if="showRttTab && activeTab === 'rtt'" class="h-full">
|
|
<div v-if="isRttLoading" class="mt-6 rounded-lg border border-neutral-200 bg-white p-6 text-md text-neutral-600">
|
|
Chargement...
|
|
</div>
|
|
<EmployeesRttTab
|
|
v-else
|
|
class="h-full"
|
|
:summary="rttSummary"
|
|
:selected-year="selectedRttYear"
|
|
:available-years="availableRttYears"
|
|
:current-year="currentRttYear"
|
|
@submit-rtt-payment="submitRttPayment"
|
|
@update-selected-year="setSelectedRttYear"
|
|
/>
|
|
</div>
|
|
<div v-else-if="activeTab === 'mileage'" class="h-full">
|
|
<div v-if="isMileageLoading" class="mt-6 rounded-lg border border-neutral-200 bg-white p-6 text-md text-neutral-600">
|
|
Chargement...
|
|
</div>
|
|
<EmployeesMileageTab
|
|
v-else
|
|
class="h-full"
|
|
:allowances="mileageAllowances"
|
|
:api-base="mileageApiBase"
|
|
@create="submitCreateMileage"
|
|
@update="submitUpdateMileage"
|
|
@delete="submitDeleteMileage"
|
|
/>
|
|
</div>
|
|
<div v-else-if="activeTab === 'formation'" class="h-full">
|
|
<div v-if="isFormationLoading" class="mt-6 rounded-lg border border-neutral-200 bg-white p-6 text-md text-neutral-600">
|
|
Chargement...
|
|
</div>
|
|
<EmployeesFormationTab
|
|
v-else
|
|
class="h-full"
|
|
:formations="formations"
|
|
:api-base="formationApiBase"
|
|
@create="submitCreateFormation"
|
|
@update="submitUpdateFormation"
|
|
@delete="submitDeleteFormation"
|
|
/>
|
|
</div>
|
|
<div v-else-if="activeTab === 'bonus'" class="h-full">
|
|
<div v-if="isBonusLoading" class="mt-6 rounded-lg border border-neutral-200 bg-white p-6 text-md text-neutral-600">
|
|
Chargement...
|
|
</div>
|
|
<EmployeesBonusTab
|
|
v-else
|
|
class="h-full"
|
|
:bonuses="bonuses"
|
|
@create="submitCreateBonus"
|
|
@update="submitUpdateBonus"
|
|
@delete="submitDeleteBonus"
|
|
/>
|
|
</div>
|
|
<div v-else-if="activeTab === 'observation'" class="h-full">
|
|
<div v-if="isObservationLoading" class="mt-6 rounded-lg border border-neutral-200 bg-white p-6 text-md text-neutral-600">
|
|
Chargement...
|
|
</div>
|
|
<EmployeesObservationTab
|
|
v-else
|
|
class="h-full"
|
|
:observations="observations"
|
|
@create="submitCreateObservation"
|
|
@update="submitUpdateObservation"
|
|
@delete="submitDeleteObservation"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<EmployeeYearlyHoursDrawer
|
|
v-if="employee"
|
|
v-model="isYearlyHoursDrawerOpen"
|
|
:employee-id="employee.id"
|
|
@submit="handleYearlyHoursPrint"
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { ref } from 'vue'
|
|
import EmployeeYearlyHoursDrawer from '~/components/EmployeeYearlyHoursDrawer.vue'
|
|
import { usePdfPrinter } from '~/composables/usePdfPrinter'
|
|
|
|
const { printPdf } = usePdfPrinter()
|
|
const isYearlyHoursDrawerOpen = ref(false)
|
|
|
|
const {
|
|
employee,
|
|
isLoading,
|
|
activeTab,
|
|
contracts,
|
|
employeeAbsences,
|
|
leaveSummary,
|
|
rttSummary,
|
|
publicHolidays,
|
|
selectedLeaveYear,
|
|
currentLeaveYear,
|
|
availableLeaveYears,
|
|
setSelectedLeaveYear,
|
|
selectedRttYear,
|
|
currentRttYear,
|
|
availableRttYears,
|
|
setSelectedRttYear,
|
|
showLeaveTab,
|
|
showRttTab,
|
|
contractHistory,
|
|
employeeContractWorkLabel,
|
|
forfaitRemainingDaysLabel,
|
|
contractForm,
|
|
createContractForm,
|
|
isContractDrawerOpen,
|
|
isContractSubmitting,
|
|
isCreateContractDrawerOpen,
|
|
isCreateContractSubmitting,
|
|
canCloseCurrentContract,
|
|
canCreateContract,
|
|
readonlyFieldClass,
|
|
closeContractWorkedHoursLabel,
|
|
contractEndDateFieldClass,
|
|
showContractEndDateError,
|
|
isContractEndDateValid,
|
|
createContractNatureFieldClass,
|
|
createContractFieldClass,
|
|
createContractStartDateFieldClass,
|
|
showsCreateContractEndDate,
|
|
requiresCreateContractEndDate,
|
|
createContractEndDateFieldClass,
|
|
isCreateContractFormValid,
|
|
requiresCreateWorkDaysHours,
|
|
selectedCreateContract,
|
|
contractNatureLabel,
|
|
contractHistoryLabel,
|
|
formatDate,
|
|
openCloseContractDrawer,
|
|
openCreateContractDrawer,
|
|
setContractDrawerOpen,
|
|
setCreateContractDrawerOpen,
|
|
submitContractUpdate,
|
|
submitCreateContract,
|
|
submitFractionedDays,
|
|
submitPaidLeaveDays,
|
|
submitRttPayment,
|
|
suspensionForms,
|
|
isSuspensionSubmitting,
|
|
submitSuspension,
|
|
addSuspensionForm,
|
|
currentActiveContractPeriodId,
|
|
interimAgencies,
|
|
isLeaveLoading,
|
|
isRttLoading,
|
|
mileageAllowances,
|
|
isMileageLoading,
|
|
mileageApiBase,
|
|
submitCreateMileage,
|
|
submitUpdateMileage,
|
|
submitDeleteMileage,
|
|
formations,
|
|
isFormationLoading,
|
|
formationApiBase,
|
|
submitCreateFormation,
|
|
submitUpdateFormation,
|
|
submitDeleteFormation,
|
|
bonuses,
|
|
isBonusLoading,
|
|
submitCreateBonus,
|
|
submitUpdateBonus,
|
|
submitDeleteBonus,
|
|
observations,
|
|
isObservationLoading,
|
|
submitCreateObservation,
|
|
submitUpdateObservation,
|
|
submitDeleteObservation
|
|
} = useEmployeeDetailPage()
|
|
|
|
const handleYearlyHoursPrint = async (payload: { year: number; month: number | null }) => {
|
|
if (!employee.value) return
|
|
const monthParam = null !== payload.month ? `&month=${payload.month}` : ''
|
|
await printPdf(`/yearly-hours/print?employeeId=${employee.value.id}&year=${payload.year}${monthParam}`)
|
|
isYearlyHoursDrawerOpen.value = false
|
|
}
|
|
|
|
useHead(() => ({
|
|
title: employee.value
|
|
? `${employee.value.firstName} ${employee.value.lastName}`
|
|
: 'Détail employé'
|
|
}))
|
|
</script>
|