feat: init plesna-gerance - extracteur de comptes rendus de gerance

- Backend Python (uv + click + FastAPI)
  - CLI: plesna-gerance extract <pdf> pour extraire les donnees
  - CLI: plesna-gerance serve pour lancer le serveur API
  - API REST: POST /api/extract pour upload et extraction de PDF
  - Parsers modulaires: metadata, locataires, operations
  - Utilise pdftotext (poppler-utils) pour l'extraction de texte

- Frontend Vue.js + Tailwind CSS
  - Interface split-screen: PDF a gauche, donnees a droite
  - Preview PDF avec zoom et navigation pages (pdf.js)
  - Visualisation structuree des donnees extraites
  - Sections depliables: metadata, locataires, operations
  - Drag & drop pour upload de PDF
  - Extraction automatique a la selection du fichier
This commit is contained in:
2026-01-18 05:36:27 +01:00
commit 6bad5fbaf9
34 changed files with 5692 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
<template>
<div class="bg-gray-50 rounded-lg p-3">
<h4 class="text-sm font-medium text-gray-700 mb-2 flex items-center gap-2">
<!-- Icons -->
<svg v-if="icon === 'building'" class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" />
</svg>
<svg v-else-if="icon === 'user'" class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
</svg>
<svg v-else-if="icon === 'document'" class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
</svg>
<svg v-else-if="icon === 'home'" class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6" />
</svg>
<svg v-else-if="icon === 'currency'" class="w-4 h-4 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.121 15.536c-1.171 1.952-3.07 1.952-4.242 0-1.172-1.953-1.172-5.119 0-7.072 1.171-1.952 3.07-1.952 4.242 0M8 10.5h4m-4 3h4m9-1.5a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
{{ title }}
</h4>
<div class="space-y-1">
<slot />
</div>
</div>
</template>
<script setup>
defineProps({
title: {
type: String,
required: true
},
icon: {
type: String,
default: null
}
})
</script>