gigafibre-fsm/apps/ops/src/pages/ConversationFullPage.vue
louispaulb 512c4a5f1b feat(ops): dispatch auto complet + perf Boîte/rapports + fix session
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>
2026-07-02 08:49:35 -04:00

47 lines
2.2 KiB
Vue

<template>
<q-page class="cfp-page">
<div class="cfp-bar">
<q-btn flat dense icon="arrow_back" label="Boîte" no-caps color="primary" @click="$router.push('/communications')" />
</div>
<ConversationPanel inline />
</q-page>
</template>
<script setup>
import { onMounted, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import ConversationPanel from 'src/components/shared/ConversationPanel.vue'
import { useConversations } from 'src/composables/useConversations'
const route = useRoute()
const router = useRouter()
const { discussions, activeDiscussion, fetchList, openDiscussion, openConversation } = useConversations()
async function openByToken (token) {
if (!token) return
const find = () => (discussions.value || []).find(d => d.token === token || (d.conversations || []).some(c => c.token === token))
let disc = find()
if (!disc) { await fetchList(); disc = find() }
if (disc) { openDiscussion(disc); return } // ouvre le fil (active la vue thread plein écran)
await openConversation(token) // repli : ouverture directe par jeton (pose aussi activeDiscussion)
if (!activeDiscussion.value) router.push('/communications') // introuvable/supprimée → retour à la boîte, pas de loader infini
}
onMounted(() => openByToken(route.params.token))
watch(() => route.params.token, t => openByToken(t))
</script>
<style scoped>
/* Plein écran : la page occupe la hauteur du viewport (moins l'en-tête) → le fil défile à l'intérieur, le bloc de réponse reste ancré en bas */
.cfp-page { padding: 0; height: calc(100dvh - 51px); display: flex; flex-direction: column; overflow: hidden; }
.cfp-bar { padding: 4px 8px; border-bottom: 1px solid var(--ops-border, #e2e8f0); background: #fff; flex: 0 0 auto; }
.cfp-page :deep(.conv-fullpage) { flex: 1 1 auto; min-height: 0; }
/* Mobile : ne pas CLIPPER. La hauteur fixe + overflow:hidden cachait le bouton « Envoyer » quand
le composeur était long (grosse signature). On laisse la PAGE défiler verticalement ; l'éditeur
est borné (max-height 40vh) et défile en interne → le bouton reste toujours atteignable. */
@media (max-width: 700px) {
.cfp-page { height: auto; min-height: calc(100dvh - 50px); overflow: visible; }
}
</style>