style: aligne le balayage de re-extraction sur le design system
All checks were successful
Build and Publish Docker Image / Build App Image (push) Successful in 1m16s
Build and Publish Docker Image / Build Summary (push) Successful in 3s

La page et le panneau de differences avaient ete ecrits avant que main ne pose
un design system unique : classes Tailwind brutes, et surtout un detail
depliable reste sur fond clair alors que son contenu venait de passer en sombre.

Reprend les classes du systeme (page, card, table, btn, badge, subcard,
empty-state, spinner) et ramene le detail au fond sombre. Les avertissements de
reecriture passent en amber-400, illisibles jusqu'ici sur fond sombre.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 07:09:46 +02:00
parent 92cf21309f
commit 41107c984c
2 changed files with 45 additions and 58 deletions

View File

@@ -30,7 +30,7 @@
class="flex-1 min-w-0 px-1.5 py-0.5 rounded border border-gray-600 bg-gray-900 text-green-400 font-medium disabled:opacity-40 disabled:line-through focus:ring-1 focus:ring-amber-500 focus:border-amber-500 focus:outline-none"
/>
</div>
<p v-if="overrideLabel(c.id)" class="pl-6 text-orange-700"> {{ overrideLabel(c.id) }}</p>
<p v-if="overrideLabel(c.id)" class="pl-6 text-amber-400"> {{ overrideLabel(c.id) }}</p>
</div>
</div>
</div>
@@ -53,7 +53,7 @@
</span>
<span class="font-medium text-gray-200">{{ loc.title }}</span>
</div>
<p v-if="loc.id && overrideLabel(loc.id)" class="pl-5 text-orange-700 mb-0.5"> {{ overrideLabel(loc.id) }}</p>
<p v-if="loc.id && overrideLabel(loc.id)" class="pl-5 text-amber-400 mb-0.5"> {{ overrideLabel(loc.id) }}</p>
<div v-for="c in loc.changes" :key="c.id">
<!-- Champ identitaire : cochable et modifiable individuellement -->
@@ -83,7 +83,7 @@
class="flex-1 min-w-0 px-1.5 py-0.5 rounded border border-gray-600 bg-gray-900 text-green-400 font-medium disabled:opacity-40 disabled:line-through focus:ring-1 focus:ring-amber-500 focus:border-amber-500 focus:outline-none"
/>
</div>
<p v-if="overrideLabel(c.id)" class="pl-6 text-orange-700"> {{ overrideLabel(c.id) }}</p>
<p v-if="overrideLabel(c.id)" class="pl-6 text-amber-400"> {{ overrideLabel(c.id) }}</p>
</div>
<!-- Montants et lignes : un seul bloc, pour que les sommes restent justes -->
@@ -107,7 +107,7 @@
<span class="text-green-400 font-medium break-all" :class="!accepted(c.id) && 'line-through'">{{ f.after }}</span>
</div>
</div>
<p v-if="overrideLabel(c.id)" class="pl-5 text-orange-700"> {{ overrideLabel(c.id) }}</p>
<p v-if="overrideLabel(c.id)" class="pl-5 text-amber-400"> {{ overrideLabel(c.id) }}</p>
</div>
</div>
</div>
@@ -136,7 +136,7 @@
<div class="text-red-400 break-all" :class="accepted(op.id) && 'line-through'">{{ op.before }}</div>
<div class="text-green-400 font-medium break-all" :class="!accepted(op.id) && 'line-through'">{{ op.after }}</div>
</div>
<p v-if="overrideLabel(op.id)" class="pl-2 text-orange-700"> {{ overrideLabel(op.id) }}</p>
<p v-if="overrideLabel(op.id)" class="pl-2 text-amber-400"> {{ overrideLabel(op.id) }}</p>
</div>
</div>
</div>

View File

@@ -1,12 +1,12 @@
<template>
<div class="flex-1 overflow-auto bg-gray-800">
<div class="max-w-6xl mx-auto p-6 space-y-6 pb-28">
<div class="page">
<div class="page-content pb-28">
<!-- Header -->
<div class="flex items-start justify-between gap-6">
<div class="page-header">
<div>
<h1 class="text-xl font-semibold text-white">-extraction de la base</h1>
<p class="text-sm text-gray-400 mt-1 max-w-2xl">
<h1 class="page-title">-extraction de la base</h1>
<p class="page-subtitle max-w-2xl">
Rejoue l'extraction de chaque PDF stocké après une amélioration des parsers.
Rien n'est écrit en base tant que vous n'avez pas validé : les documents dont
l'extraction change sont listés ci-dessous, à appliquer en une fois.
@@ -18,26 +18,22 @@
v-if="!isScanning"
@click="startScan"
:disabled="isLoading || isApplying || documents.length === 0"
class="px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50 flex items-center gap-2"
class="btn btn-primary"
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
</svg>
{{ hasScanned ? 'Relancer le balayage' : 'Lancer le balayage' }}
</button>
<button
v-else
@click="stopScan"
class="px-4 py-2 bg-gray-700 text-white rounded-lg hover:bg-gray-600 transition-colors"
>
<button v-else @click="stopScan" class="btn btn-secondary">
Arrêter
</button>
</div>
</div>
<!-- Progression du balayage -->
<div v-if="isScanning || hasScanned" class="bg-gray-900 rounded-lg border border-gray-700 p-4 space-y-3">
<div v-if="isScanning || hasScanned" class="card card-body space-y-3">
<div class="flex items-center justify-between text-sm">
<span class="text-white">
<template v-if="isScanning">
@@ -71,13 +67,13 @@
</div>
<!-- Chargement initial -->
<div v-if="isLoading" class="bg-gray-900 rounded-lg p-12 text-center">
<div class="inline-block animate-spin rounded-full h-8 w-8 border-2 border-gray-600 border-t-blue-400"></div>
<p class="text-gray-400 mt-4">Chargement des documents...</p>
<div v-if="isLoading" class="card empty-state">
<div class="spinner h-8 w-8"></div>
<p class="mt-4">Chargement des documents...</p>
</div>
<!-- Invitation initiale -->
<div v-else-if="!hasScanned && !isScanning" class="bg-gray-900 rounded-lg border border-gray-700 p-8 text-center">
<div v-else-if="!hasScanned && !isScanning" class="card empty-state">
<p class="text-gray-300">
{{ documents.length }} document{{ documents.length > 1 ? 's' : '' }} en base,
dont {{ documents.filter((d) => d.has_pdf).length }} avec PDF stocké.
@@ -89,8 +85,8 @@
</div>
<!-- Documents modifiés -->
<div v-if="changedItems.length" class="bg-gray-900 rounded-lg border border-gray-700 overflow-hidden">
<div class="flex items-center justify-between px-4 py-3 bg-gray-800 border-b border-gray-700">
<div v-if="changedItems.length" class="card">
<div class="card-header bg-gray-800">
<label class="flex items-center gap-2 text-sm text-white cursor-pointer">
<input
type="checkbox"
@@ -126,18 +122,18 @@
<!-- Résumé des différences -->
<div class="flex items-center gap-1.5 flex-shrink-0">
<span v-if="item.diff.summary.metadata" class="px-2 py-0.5 text-xs rounded bg-purple-500/20 text-purple-300">
<span v-if="item.diff.summary.metadata" class="badge badge-neutral">
{{ item.diff.summary.metadata }} métadonnée{{ item.diff.summary.metadata > 1 ? 's' : '' }}
</span>
<span v-if="item.diff.summary.locataires" class="px-2 py-0.5 text-xs rounded bg-blue-500/20 text-blue-300">
<span v-if="item.diff.summary.locataires" class="badge badge-info">
{{ item.diff.summary.locataires }} locataire{{ item.diff.summary.locataires > 1 ? 's' : '' }}
</span>
<span v-if="item.diff.summary.operations" class="px-2 py-0.5 text-xs rounded bg-amber-500/20 text-amber-300">
<span v-if="item.diff.summary.operations" class="badge badge-warning">
{{ item.diff.summary.operations }} opération{{ item.diff.summary.operations > 1 ? 's' : '' }}
</span>
<span
v-if="item.counts.accepted < item.counts.total"
class="px-2 py-0.5 text-xs rounded bg-orange-500/20 text-orange-300"
class="badge badge-warning"
title="Une partie des modifications a été écartée"
>
{{ item.counts.accepted }}/{{ item.counts.total }} retenues
@@ -153,22 +149,19 @@
<!-- Actions -->
<div class="flex items-center gap-2 flex-shrink-0">
<span v-if="item.status === 'applique'" class="px-2 py-1 text-xs rounded bg-green-500/20 text-green-400">
<span v-if="item.status === 'applique'" class="badge badge-success">
Appliqué
</span>
<span v-else-if="item.status === 'echec'" class="px-2 py-1 text-xs rounded bg-red-500/20 text-red-400" :title="item.error">
<span v-else-if="item.status === 'echec'" class="badge badge-danger" :title="item.error">
Échec
</span>
<button
@click="toggleDetail(item.id)"
class="px-3 py-1.5 text-xs rounded bg-gray-700 text-gray-300 hover:bg-gray-600 transition-colors"
>
<button @click="toggleDetail(item.id)" class="btn btn-sm btn-secondary">
{{ openDetails[item.id] ? 'Masquer' : 'Détail' }}
</button>
<a
:href="`/api/documents/${item.id}/pdf`"
target="_blank"
class="px-2 py-1.5 text-xs rounded bg-red-500/20 text-red-400 hover:bg-red-500/30 transition-colors"
class="btn btn-sm btn-ghost"
title="Ouvrir le PDF"
>
PDF
@@ -177,23 +170,17 @@
</div>
<!-- Détail : différences (cochables) + tags à confirmer -->
<div v-if="openDetails[item.id]" class="bg-amber-50 border-t border-amber-300 px-4 py-3 space-y-4">
<div v-if="openDetails[item.id]" class="bg-gray-950 border-t border-gray-700 px-4 py-3 space-y-4">
<div class="flex items-center justify-between text-xs">
<span class="text-amber-800">
<span class="text-gray-400">
{{ item.counts.accepted }} modification{{ item.counts.accepted > 1 ? 's' : '' }}
retenue{{ item.counts.accepted > 1 ? 's' : '' }} sur {{ item.counts.total }}
</span>
<div class="flex items-center gap-2">
<button
@click="setAllChanges(item, true)"
class="px-2 py-1 rounded text-amber-700 hover:bg-amber-100 transition-colors"
>
<button @click="setAllChanges(item, true)" class="btn btn-sm btn-ghost">
Tout retenir
</button>
<button
@click="setAllChanges(item, false)"
class="px-2 py-1 rounded text-amber-700 hover:bg-amber-100 transition-colors"
>
<button @click="setAllChanges(item, false)" class="btn btn-sm btn-ghost">
Tout écarter
</button>
</div>
@@ -207,17 +194,17 @@
/>
<div v-if="item.tagsToReview.length">
<div class="font-semibold text-amber-800 text-xs mb-2">
<div class="font-semibold text-amber-300 text-xs mb-2">
Tags à confirmer ({{ item.tagStats.reported }} reporté{{ item.tagStats.reported > 1 ? 's' : '' }} automatiquement)
</div>
<div class="space-y-2">
<div
v-for="opIndex in item.tagsToReview"
:key="opIndex"
class="flex items-center gap-3 bg-white/70 rounded p-2"
class="flex items-center gap-3 subcard p-2"
>
<div class="flex-1 min-w-0 text-xs">
<div class="font-medium text-gray-800 truncate">
<div class="font-medium text-gray-200 truncate">
{{ item.newData.recapitulatif_operations[opIndex].fournisseur || 'Fournisseur inconnu' }}
</div>
<div class="text-gray-500 truncate">
@@ -225,7 +212,7 @@
|| item.newData.recapitulatif_operations[opIndex].description || '-' }}
· {{ formatAmount(item.newData.recapitulatif_operations[opIndex].montants?.debit) }}
</div>
<div v-if="item.tags[opIndex]?.origin === 'predit'" class="text-blue-600 mt-0.5">
<div v-if="item.tags[opIndex]?.origin === 'predit'" class="text-blue-400 mt-0.5">
Prédit ({{ item.tags[opIndex].confidence }}%) {{ item.tags[opIndex].reason }}
</div>
</div>
@@ -241,7 +228,7 @@
</div>
</div>
</div>
<p v-else class="text-xs text-amber-800">
<p v-else class="text-xs text-gray-400">
Les {{ item.tagStats.reported }} tag{{ item.tagStats.reported > 1 ? 's' : '' }} du document
{{ item.tagStats.reported > 1 ? 'sont reportés' : 'est reporté' }} sur la nouvelle extraction.
</p>
@@ -251,9 +238,9 @@
</div>
<!-- Documents en erreur -->
<div v-if="problemItems.length" class="bg-gray-900 rounded-lg border border-gray-700 overflow-hidden">
<div class="px-4 py-3 bg-gray-800 border-b border-gray-700 text-sm text-white">
Non -extraits ({{ problemItems.length }})
<div v-if="problemItems.length" class="card">
<div class="card-header bg-gray-800">
<span class="card-title">Non -extraits ({{ problemItems.length }})</span>
</div>
<div class="divide-y divide-gray-800">
<div v-for="item in problemItems" :key="item.id" class="flex items-center gap-3 px-4 py-2.5">
@@ -269,10 +256,10 @@
</div>
<!-- Documents inchangés -->
<div v-if="identicalItems.length" class="bg-gray-900 rounded-lg border border-gray-700 overflow-hidden">
<div v-if="identicalItems.length" class="card">
<button
@click="showIdentical = !showIdentical"
class="w-full flex items-center justify-between px-4 py-3 bg-gray-800 text-sm text-gray-300 hover:text-white transition-colors"
class="card-header w-full bg-gray-800 text-sm text-gray-300 hover:text-white transition-colors"
>
<span>{{ identicalItems.length }} document{{ identicalItems.length > 1 ? 's' : '' }} inchangé{{ identicalItems.length > 1 ? 's' : '' }}</span>
<span class="text-xs">{{ showIdentical ? 'Masquer' : 'Voir' }}</span>
@@ -281,7 +268,7 @@
<div v-for="item in identicalItems" :key="item.id" class="flex items-center gap-3 px-4 py-2 text-xs">
<span class="font-mono text-gray-300">{{ item.reference }}</span>
<span class="text-gray-500">{{ formatDate(item.date) }}</span>
<span class="text-gray-600 truncate">{{ item.immeuble_adresse || '-' }}</span>
<span class="text-gray-500 truncate">{{ item.immeuble_adresse || '-' }}</span>
</div>
</div>
</div>
@@ -293,7 +280,7 @@
v-if="changedItems.length"
class="fixed bottom-0 left-0 right-0 bg-gray-900 border-t border-gray-700 px-6 py-3"
>
<div class="max-w-6xl mx-auto flex items-center justify-between gap-4">
<div class="flex items-center justify-between gap-4">
<div class="text-sm" :class="applyError && !isApplying ? 'text-red-400' : 'text-gray-400'">
<template v-if="isApplying">
Enregistrement {{ applyDone }} / {{ applyTotal }}...
@@ -309,7 +296,7 @@
<button
@click="applySelection"
:disabled="isApplying || isScanning || selectedItems.length === 0"
class="px-5 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700 transition-colors font-medium disabled:opacity-50 disabled:cursor-not-allowed"
class="btn btn-primary font-medium"
>
Appliquer la sélection ({{ selectedItems.length }})
</button>