feat: reimport pdf

This commit is contained in:
2026-01-22 21:23:46 +01:00
parent 981fabcc27
commit 4f0ca67dc4
13 changed files with 1068 additions and 14 deletions

View File

@@ -0,0 +1,217 @@
<template>
<div class="flex-1 flex flex-col overflow-hidden">
<!-- Header avec breadcrumb et actions -->
<div class="flex-shrink-0 px-6 py-4 bg-gray-800 border-b border-gray-700">
<div class="flex items-center justify-between">
<div>
<div class="flex items-center gap-2 text-sm text-gray-400 mb-1">
<router-link to="/documents" class="hover:text-white transition-colors">Documents</router-link>
<span></span>
<span class="text-white">{{ documentData?.reference || 'Chargement...' }}</span>
</div>
<h1 class="text-xl font-semibold text-white">
Édition du document {{ documentData?.reference }}
</h1>
<p v-if="documentData" class="text-sm text-gray-400 mt-1">
{{ documentData.immeuble?.adresse || '-' }} - {{ formatDate(documentData.date) }}
</p>
</div>
<div class="flex items-center gap-3">
<button
@click="cancel"
:disabled="isSaving"
class="px-4 py-2 text-sm text-gray-400 hover:text-white transition-colors disabled:opacity-50"
>
Annuler
</button>
<button
v-if="!showTagging && extractedData"
@click="goToTagging"
:disabled="isSaving"
class="px-4 py-2 text-sm bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50 flex items-center gap-2"
>
<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="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
</svg>
Continuer vers le tagging
</button>
</div>
</div>
</div>
<!-- Loading state -->
<div v-if="isLoading" class="flex-1 flex items-center justify-center bg-gray-800">
<div class="text-center">
<div class="inline-block animate-spin rounded-full h-12 w-12 border-4 border-gray-600 border-t-blue-400 mb-4"></div>
<p class="text-gray-400">Chargement du document...</p>
</div>
</div>
<!-- Corps : Split view PDF + Données -->
<div v-else class="flex-1 flex overflow-hidden">
<!-- Gauche : PDF Preview -->
<div class="w-1/2 border-r border-gray-700 flex flex-col">
<div class="flex-shrink-0 px-4 py-2 bg-gray-700/50 border-b border-gray-700">
<span class="text-sm text-gray-300">Aperçu PDF</span>
</div>
<div class="flex-1 overflow-hidden">
<PdfPreview
v-if="documentData?.has_pdf"
:url="`/api/documents/${documentId}/pdf`"
:file-name="documentData?.source_file || 'document.pdf'"
class="h-full"
/>
<div v-else class="h-full flex items-center justify-center bg-gray-800 text-gray-500">
<div class="text-center">
<svg class="mx-auto h-16 w-16 text-gray-600 mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<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>
<p class="text-lg font-medium">PDF non disponible</p>
<p class="text-sm text-gray-600 mt-1">Ce document a été importé sans stockage du PDF</p>
</div>
</div>
</div>
</div>
<!-- Droite : Édition ou Tagging -->
<div class="w-1/2 flex flex-col bg-gray-50">
<!-- Vue 1 : JsonViewer (mode édition) -->
<JsonViewer
v-if="!showTagging && extractedData"
:data="extractedData"
@update:data="extractedData = $event"
:is-loading="false"
class="flex-1"
/>
<!-- Vue 2 : TaggingStep -->
<TaggingStep
v-if="showTagging && extractedData"
:depenses="extractedData.data.recapitulatif_operations"
:is-duplicate="true"
@save="handleSave"
@cancel="showTagging = false"
class="flex-1"
/>
<!-- Error message -->
<div v-if="saveError" class="flex-shrink-0 px-4 py-3 bg-red-500/10 border-t border-red-500/30">
<div class="flex items-center gap-2 text-sm text-red-400">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
<span>{{ saveError }}</span>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useRouter, useRoute } from 'vue-router'
import PdfPreview from '../components/PdfPreview.vue'
import JsonViewer from '../components/JsonViewer.vue'
import TaggingStep from '../components/TaggingStep.vue'
const router = useRouter()
const route = useRoute()
const documentId = route.params.id
const documentData = ref(null)
const extractedData = ref(null)
const isLoading = ref(true)
const showTagging = ref(false)
const isSaving = ref(false)
const saveError = ref(null)
onMounted(async () => {
await loadDocument()
})
async function loadDocument() {
isLoading.value = true
try {
const response = await fetch(`/api/documents/${documentId}`)
if (!response.ok) {
throw new Error('Document non trouvé')
}
documentData.value = await response.json()
// Formatter les données pour JsonViewer (même structure que ExtractPage)
extractedData.value = {
source_file: documentData.value.source_file,
data: documentData.value.json_data
}
} catch (err) {
console.error('Error loading document:', err)
alert('Erreur lors du chargement du document: ' + err.message)
router.push('/documents')
} finally {
isLoading.value = false
}
}
function formatDate(dateStr) {
if (!dateStr) return '-'
const [year, month, day] = dateStr.split('-')
return `${day}/${month}/${year}`
}
function cancel() {
const hasChanges = extractedData.value !== null
if (hasChanges) {
const confirmed = confirm('Abandonner les modifications ?')
if (!confirmed) return
}
router.push('/documents')
}
function goToTagging() {
showTagging.value = true
saveError.value = null
}
async function handleSave(depensesTags, shouldOverwrite) {
isSaving.value = true
saveError.value = null
try {
const response = await fetch('/api/save', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
source_file: extractedData.value.source_file,
data: extractedData.value.data,
depenses_tags: depensesTags,
overwrite: true // Toujours true en mode édition
})
})
const result = await response.json()
if (!response.ok) {
throw new Error(result.detail || 'Erreur lors de la sauvegarde')
}
if (result.success) {
// Succès - redirection vers la liste des documents
router.push('/documents')
} else {
throw new Error(result.message || 'Échec de la sauvegarde')
}
} catch (err) {
console.error('Save error:', err)
saveError.value = err.message || 'Une erreur est survenue lors de la sauvegarde'
// Scroll to top to show error
window.scrollTo({ top: 0, behavior: 'smooth' })
} finally {
isSaving.value = false
}
}
</script>