feat: Ajout aperçu document avant et après upload
- Aperçu immédiat lors de la sélection de fichier - Aperçu détaillé après upload réussi - Support images (miniature) et PDF (icône) - Gestion des instances de graphiques Chart.js - Correction erreur 'Canvas is already in use' - Interface utilisateur améliorée avec cartes d'aperçu - Boutons d'action intégrés (Voir analyse, Fermer) - Nettoyage automatique des aperçus
This commit is contained in:
parent
e4b7dc8b58
commit
0acb87c122
@ -7,6 +7,7 @@ class NotaryApp {
|
||||
this.apiUrl = 'http://localhost:8000';
|
||||
this.currentDocument = null;
|
||||
this.documents = [];
|
||||
this.charts = {}; // Stockage des instances de graphiques
|
||||
this.init();
|
||||
}
|
||||
|
||||
@ -110,20 +111,202 @@ class NotaryApp {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update UI
|
||||
// Store file for preview
|
||||
this.selectedFile = file;
|
||||
|
||||
// Update UI with preview
|
||||
this.showFilePreview(file);
|
||||
}
|
||||
|
||||
showFilePreview(file) {
|
||||
const uploadArea = document.getElementById('upload-area');
|
||||
uploadArea.innerHTML = `
|
||||
<i class="fas fa-file fa-3x text-success mb-3"></i>
|
||||
<h5>${file.name}</h5>
|
||||
<p class="text-muted">${this.formatFileSize(file.size)}</p>
|
||||
<button type="button" class="btn btn-outline-danger" onclick="app.clearFile()">
|
||||
<i class="fas fa-times"></i> Supprimer
|
||||
</button>
|
||||
`;
|
||||
|
||||
if (file.type.startsWith('image/')) {
|
||||
// Preview for images
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
uploadArea.innerHTML = `
|
||||
<div class="file-preview">
|
||||
<div class="preview-image mb-3">
|
||||
<img src="${e.target.result}" alt="Aperçu" class="img-thumbnail" style="max-width: 200px; max-height: 200px;">
|
||||
</div>
|
||||
<div class="file-info">
|
||||
<h5>${file.name}</h5>
|
||||
<p class="text-muted">${this.formatFileSize(file.size)}</p>
|
||||
<p class="text-muted">Type: ${file.type}</p>
|
||||
</div>
|
||||
<div class="preview-actions mt-3">
|
||||
<button type="button" class="btn btn-outline-danger me-2" onclick="app.clearFile()">
|
||||
<i class="fas fa-times"></i> Supprimer
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" onclick="app.uploadDocument()">
|
||||
<i class="fas fa-upload"></i> Uploader
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else if (file.type === 'application/pdf') {
|
||||
// Preview for PDF
|
||||
uploadArea.innerHTML = `
|
||||
<div class="file-preview">
|
||||
<div class="preview-pdf mb-3">
|
||||
<i class="fas fa-file-pdf fa-4x text-danger"></i>
|
||||
<div class="mt-2">
|
||||
<small class="text-muted">Aperçu PDF non disponible</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="file-info">
|
||||
<h5>${file.name}</h5>
|
||||
<p class="text-muted">${this.formatFileSize(file.size)}</p>
|
||||
<p class="text-muted">Type: ${file.type}</p>
|
||||
</div>
|
||||
<div class="preview-actions mt-3">
|
||||
<button type="button" class="btn btn-outline-danger me-2" onclick="app.clearFile()">
|
||||
<i class="fas fa-times"></i> Supprimer
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" onclick="app.uploadDocument()">
|
||||
<i class="fas fa-upload"></i> Uploader
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
// Generic preview for other files
|
||||
uploadArea.innerHTML = `
|
||||
<div class="file-preview">
|
||||
<div class="preview-generic mb-3">
|
||||
<i class="fas fa-file fa-4x text-primary"></i>
|
||||
</div>
|
||||
<div class="file-info">
|
||||
<h5>${file.name}</h5>
|
||||
<p class="text-muted">${this.formatFileSize(file.size)}</p>
|
||||
<p class="text-muted">Type: ${file.type}</p>
|
||||
</div>
|
||||
<div class="preview-actions mt-3">
|
||||
<button type="button" class="btn btn-outline-danger me-2" onclick="app.clearFile()">
|
||||
<i class="fas fa-times"></i> Supprimer
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" onclick="app.uploadDocument()">
|
||||
<i class="fas fa-upload"></i> Uploader
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
}
|
||||
|
||||
showDocumentPreview(uploadResult, file) {
|
||||
// Create a preview modal or section
|
||||
const previewContainer = document.getElementById('upload-preview');
|
||||
if (!previewContainer) {
|
||||
// Create preview container if it doesn't exist
|
||||
const uploadSection = document.getElementById('upload-section');
|
||||
const previewDiv = document.createElement('div');
|
||||
previewDiv.id = 'upload-preview';
|
||||
previewDiv.className = 'mt-4';
|
||||
uploadSection.appendChild(previewDiv);
|
||||
}
|
||||
|
||||
const previewContainer = document.getElementById('upload-preview');
|
||||
|
||||
let previewContent = '';
|
||||
|
||||
if (file.type.startsWith('image/')) {
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => {
|
||||
previewContent = `
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<i class="fas fa-eye me-2"></i>Aperçu du document uploadé
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<img src="${e.target.result}" alt="Aperçu" class="img-fluid rounded">
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<h6>Informations du document</h6>
|
||||
<ul class="list-unstyled">
|
||||
<li><strong>Nom:</strong> ${file.name}</li>
|
||||
<li><strong>Taille:</strong> ${this.formatFileSize(file.size)}</li>
|
||||
<li><strong>Type:</strong> ${file.type}</li>
|
||||
<li><strong>ID Document:</strong> ${uploadResult.document_id}</li>
|
||||
<li><strong>Statut:</strong> <span class="badge bg-info">${uploadResult.status}</span></li>
|
||||
</ul>
|
||||
<div class="mt-3">
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="app.viewDocument('${uploadResult.document_id}')">
|
||||
<i class="fas fa-search"></i> Voir l'analyse
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary ms-2" onclick="app.hideDocumentPreview()">
|
||||
<i class="fas fa-times"></i> Fermer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
previewContainer.innerHTML = previewContent;
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
} else {
|
||||
previewContent = `
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h6 class="mb-0">
|
||||
<i class="fas fa-eye me-2"></i>Aperçu du document uploadé
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-2">
|
||||
<i class="fas fa-file-pdf fa-4x text-danger"></i>
|
||||
</div>
|
||||
<div class="col-md-10">
|
||||
<h6>Informations du document</h6>
|
||||
<ul class="list-unstyled">
|
||||
<li><strong>Nom:</strong> ${file.name}</li>
|
||||
<li><strong>Taille:</strong> ${this.formatFileSize(file.size)}</li>
|
||||
<li><strong>Type:</strong> ${file.type}</li>
|
||||
<li><strong>ID Document:</strong> ${uploadResult.document_id}</li>
|
||||
<li><strong>Statut:</strong> <span class="badge bg-info">${uploadResult.status}</span></li>
|
||||
</ul>
|
||||
<div class="mt-3">
|
||||
<button class="btn btn-sm btn-outline-primary" onclick="app.viewDocument('${uploadResult.document_id}')">
|
||||
<i class="fas fa-search"></i> Voir l'analyse
|
||||
</button>
|
||||
<button class="btn btn-sm btn-outline-secondary ms-2" onclick="app.hideDocumentPreview()">
|
||||
<i class="fas fa-times"></i> Fermer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
previewContainer.innerHTML = previewContent;
|
||||
}
|
||||
}
|
||||
|
||||
hideDocumentPreview() {
|
||||
const previewContainer = document.getElementById('upload-preview');
|
||||
if (previewContainer) {
|
||||
previewContainer.innerHTML = '';
|
||||
}
|
||||
}
|
||||
|
||||
clearFile() {
|
||||
// Clear selected file
|
||||
this.selectedFile = null;
|
||||
|
||||
// Clear file input
|
||||
document.getElementById('file-input').value = '';
|
||||
|
||||
// Reset upload area
|
||||
document.getElementById('upload-area').innerHTML = `
|
||||
<i class="fas fa-cloud-upload-alt fa-3x text-primary mb-3"></i>
|
||||
<h5>Glissez-déposez votre document ici</h5>
|
||||
@ -134,6 +317,9 @@ class NotaryApp {
|
||||
</button>
|
||||
`;
|
||||
|
||||
// Hide document preview
|
||||
this.hideDocumentPreview();
|
||||
|
||||
// Re-setup event listeners
|
||||
document.getElementById('file-input').addEventListener('change', (e) => {
|
||||
this.handleFileSelect(e.target.files[0]);
|
||||
@ -141,14 +327,7 @@ class NotaryApp {
|
||||
}
|
||||
|
||||
async uploadDocument() {
|
||||
const fileInput = document.getElementById('file-input');
|
||||
|
||||
if (!fileInput) {
|
||||
this.showAlert('Élément de fichier non trouvé', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const file = fileInput.files[0];
|
||||
const file = this.selectedFile || document.getElementById('file-input')?.files[0];
|
||||
|
||||
if (!file) {
|
||||
this.showAlert('Veuillez sélectionner un fichier', 'warning');
|
||||
@ -185,6 +364,9 @@ class NotaryApp {
|
||||
|
||||
this.updateProgress(25, 'Document reçu, traitement en cours...');
|
||||
|
||||
// Show document preview after successful upload
|
||||
this.showDocumentPreview(result, file);
|
||||
|
||||
// Poll for status updates
|
||||
this.pollDocumentStatus(result.document_id);
|
||||
|
||||
@ -487,10 +669,18 @@ class NotaryApp {
|
||||
}
|
||||
|
||||
renderCharts(stats) {
|
||||
// Détruire les graphiques existants
|
||||
if (this.charts.documentTypes) {
|
||||
this.charts.documentTypes.destroy();
|
||||
}
|
||||
if (this.charts.timeline) {
|
||||
this.charts.timeline.destroy();
|
||||
}
|
||||
|
||||
// Document types chart
|
||||
const typesCtx = document.getElementById('document-types-chart');
|
||||
if (typesCtx) {
|
||||
new Chart(typesCtx, {
|
||||
this.charts.documentTypes = new Chart(typesCtx, {
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
labels: Object.keys(stats.types_documents || {}),
|
||||
@ -516,6 +706,32 @@ class NotaryApp {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Timeline chart
|
||||
const timelineCtx = document.getElementById('timeline-chart');
|
||||
if (timelineCtx) {
|
||||
this.charts.timeline = new Chart(timelineCtx, {
|
||||
type: 'line',
|
||||
data: {
|
||||
labels: ['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Jun'],
|
||||
datasets: [{
|
||||
label: 'Documents traités',
|
||||
data: [12, 19, 3, 5, 2, 3],
|
||||
borderColor: '#007bff',
|
||||
backgroundColor: 'rgba(0, 123, 255, 0.1)',
|
||||
tension: 0.4
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async checkSystemStatus() {
|
||||
@ -587,7 +803,4 @@ function testConnection() {
|
||||
app.showAlert('Test de connexion effectué', 'info');
|
||||
}
|
||||
|
||||
// Initialize app when DOM is loaded
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
window.app = new NotaryApp();
|
||||
});
|
||||
// L'application est maintenant initialisée dans index.html
|
||||
|
@ -427,5 +427,11 @@
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<script src="app.js"></script>
|
||||
<script>
|
||||
// Initialisation de l'application
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
window.notaryApp = new NotaryApp();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
x
Reference in New Issue
Block a user