Planificateur « Suggérer » : 4 stratégies (smart / meilleurs d'abord / équilibré / juste ce qu'il faut), compétences+niveaux par tech (édition inline), niveau requis par compétence + par job, carte des tournées (1 couleur/tech, domicile→arrêts, sélecteur de jour), fenêtre de dispatch auj.+demain (dates sélectionnées), règle week-end + placeholder « en attente du quart », clustering + lasso + filtre-date sur la carte, accès rapide « À assigner » (badge). Boîte : liste /conversations allégée (45 Mo → ~1 Mo, 17×) + messages chargés à l'ouverture. Rapports : cache SWR sur revenue-explorer (22×). Session : keep-alive + timeout fetch global + authFetch durci → fin des rechargements manuels. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
38 lines
1.9 KiB
Vue
38 lines
1.9 KiB
Vue
<template>
|
|
<!-- En-tête de page unifié : bouton retour optionnel + titre (+ compteur) + actions à droite + barre de filtres.
|
|
Usage : <PageHeader title="Clients" :count="total"><template #actions>…</template><template #filters>…</template></PageHeader> -->
|
|
<div class="page-header">
|
|
<div class="ph-title-row">
|
|
<q-btn v-if="back" flat dense round icon="arrow_back" :to="back" class="ph-back"><q-tooltip>Retour</q-tooltip></q-btn>
|
|
<h1 class="ph-title">
|
|
{{ title }}
|
|
<span v-if="count !== null && count !== undefined" class="ph-count">{{ count }}</span>
|
|
</h1>
|
|
<q-space />
|
|
<div v-if="$slots.actions" class="ph-actions"><slot name="actions" /></div>
|
|
</div>
|
|
<div v-if="$slots.filters" class="ph-filters"><slot name="filters" /></div>
|
|
<div v-if="$slots.default" class="ph-sub"><slot /></div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
defineProps({
|
|
title: { type: String, default: '' },
|
|
count: { type: [Number, String], default: null },
|
|
back: { type: [String, Object], default: null },
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.page-header { margin-bottom: 16px; }
|
|
.ph-title-row { display: flex; align-items: center; gap: 8px; min-height: 34px; }
|
|
.ph-back { margin-left: -6px; }
|
|
.ph-title { font-size: 1.4rem; font-weight: 720; letter-spacing: -0.01em; margin: 0; display: flex; align-items: center; gap: 10px; text-wrap: balance; }
|
|
.ph-count { font-size: 0.78rem; font-weight: 600; color: var(--ops-text-muted); background: var(--ops-bg-light); border: 1px solid var(--ops-border); border-radius: 20px; padding: 2px 10px; font-variant-numeric: tabular-nums; }
|
|
.ph-actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
|
|
.ph-filters { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end; margin-top: 12px; }
|
|
.ph-sub { margin-top: 8px; }
|
|
@media (max-width: 599px) { .ph-title { font-size: 1.2rem; } }
|
|
</style>
|