feat: enhance document management UI
This commit is contained in:
@@ -216,6 +216,63 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-base-100 shadow-lg mt-6">
|
||||
<div class="card-body space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 class="card-title">Documents de la machine</h2>
|
||||
<p class="text-xs text-gray-500">Ajoutez ou consultez les documents liés à cette machine.</p>
|
||||
</div>
|
||||
<span v-if="isEditMode && machineDocumentFiles.length" class="badge badge-outline">
|
||||
{{ machineDocumentFiles.length }} fichier{{ machineDocumentFiles.length > 1 ? 's' : '' }} sélectionné{{ machineDocumentFiles.length > 1 ? 's' : '' }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<DocumentUpload
|
||||
v-if="isEditMode"
|
||||
v-model="machineDocumentFiles"
|
||||
title="Déposer des fichiers pour la machine"
|
||||
subtitle="Formats acceptés : PDF, images, documents..."
|
||||
@files-added="handleMachineFilesAdded"
|
||||
/>
|
||||
|
||||
<div v-if="machineDocumentsList.length" class="space-y-2">
|
||||
<div
|
||||
v-for="document in machineDocumentsList"
|
||||
:key="document.id"
|
||||
class="flex items-center justify-between rounded border border-base-200 bg-base-100 px-3 py-2"
|
||||
>
|
||||
<div class="flex items-center gap-3 text-sm">
|
||||
<span class="text-xl" :class="documentIcon(document).colorClass">
|
||||
{{ documentIcon(document).icon }}
|
||||
</span>
|
||||
<div>
|
||||
<div class="font-medium">{{ document.name }}</div>
|
||||
<div class="text-xs text-gray-500">
|
||||
{{ document.mimeType || 'Inconnu' }} • {{ formatSize(document.size) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<button type="button" class="btn btn-ghost btn-xs" @click="downloadDocument(document)">
|
||||
Télécharger
|
||||
</button>
|
||||
<button
|
||||
v-if="isEditMode"
|
||||
type="button"
|
||||
class="btn btn-error btn-xs"
|
||||
:disabled="machineDocumentsUploading"
|
||||
@click="removeMachineDocument(document.id)"
|
||||
>
|
||||
Supprimer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<p v-else class="text-xs text-gray-500">Aucun document lié à cette machine.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Components Section -->
|
||||
<div class="card bg-base-100 shadow-lg">
|
||||
<div class="card-body">
|
||||
@@ -301,7 +358,10 @@ import { usePieces } from '~/composables/usePieces'
|
||||
import { useCustomFields } from '~/composables/useCustomFields'
|
||||
import { useApi } from '~/composables/useApi'
|
||||
import { useToast } from '~/composables/useToast'
|
||||
import { useDocuments } from '~/composables/useDocuments'
|
||||
import { getFileIcon } from '~/utils/fileIcons'
|
||||
import ComponentHierarchy from '~/components/ComponentHierarchy.vue'
|
||||
import DocumentUpload from '~/components/DocumentUpload.vue'
|
||||
|
||||
const route = useRoute()
|
||||
const machineId = route.params.id
|
||||
@@ -323,6 +383,13 @@ const {
|
||||
} = usePieces()
|
||||
|
||||
const { upsertCustomFieldValue } = useCustomFields()
|
||||
const {
|
||||
uploadDocuments,
|
||||
deleteDocument,
|
||||
loadDocumentsByMachine,
|
||||
loadDocumentsByComponent,
|
||||
loadDocumentsByPiece
|
||||
} = useDocuments()
|
||||
|
||||
// Data
|
||||
const loading = ref(true)
|
||||
@@ -339,6 +406,10 @@ const machineConstructeur = ref('')
|
||||
// Valeurs des champs personnalisés de la machine
|
||||
const machineCustomFieldValues = reactive({})
|
||||
|
||||
const machineDocumentFiles = ref([])
|
||||
const machineDocumentsUploading = ref(false)
|
||||
const machineDocumentsLoaded = ref(false)
|
||||
|
||||
// Mode d'édition
|
||||
const isEditMode = ref(false)
|
||||
const debug = ref(false) // Ajout de debug pour afficher les infos de debug
|
||||
@@ -379,6 +450,9 @@ const machinePieces = computed(() => {
|
||||
return filteredPieces
|
||||
})
|
||||
|
||||
const machineDocumentsList = computed(() => machine.value?.documents || [])
|
||||
const documentIcon = (doc) => getFileIcon({ name: doc.filename || doc.name, mime: doc.mimeType })
|
||||
|
||||
const allComponents = computed(() => {
|
||||
return components.value
|
||||
})
|
||||
@@ -391,6 +465,68 @@ const componentPieces = (composantId) => {
|
||||
return pieces.value.filter(piece => piece.composantId === composantId)
|
||||
}
|
||||
|
||||
const refreshMachineDocuments = async () => {
|
||||
if (!machine.value?.id) return
|
||||
const result = await loadDocumentsByMachine(machine.value.id, { updateStore: false })
|
||||
if (result.success && machine.value) {
|
||||
machine.value.documents = result.data || []
|
||||
machineDocumentsLoaded.value = true
|
||||
}
|
||||
}
|
||||
|
||||
const handleMachineFilesAdded = async (files) => {
|
||||
if (!files.length || !machine.value?.id) return
|
||||
machineDocumentsUploading.value = true
|
||||
try {
|
||||
const result = await uploadDocuments(
|
||||
{
|
||||
files,
|
||||
context: { machineId: machine.value.id }
|
||||
},
|
||||
{ updateStore: false }
|
||||
)
|
||||
|
||||
if (result.success && machine.value) {
|
||||
const newDocs = result.data || []
|
||||
machine.value.documents = [...newDocs, ...(machine.value.documents || [])]
|
||||
machineDocumentFiles.value = []
|
||||
}
|
||||
} finally {
|
||||
machineDocumentsUploading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const removeMachineDocument = async (documentId) => {
|
||||
if (!documentId) return
|
||||
const result = await deleteDocument(documentId, { updateStore: false })
|
||||
if (result.success && machine.value) {
|
||||
machine.value.documents = (machine.value.documents || []).filter(doc => doc.id !== documentId)
|
||||
}
|
||||
}
|
||||
|
||||
const downloadDocument = (doc) => {
|
||||
if (!doc?.path) return
|
||||
|
||||
if (doc.path.startsWith('data:')) {
|
||||
const link = document.createElement('a')
|
||||
link.href = doc.path
|
||||
link.download = doc.filename || doc.name || 'document'
|
||||
link.click()
|
||||
return
|
||||
}
|
||||
|
||||
window.open(doc.path, '_blank')
|
||||
}
|
||||
|
||||
const formatSize = (size) => {
|
||||
if (size === undefined || size === null) return '—'
|
||||
if (size === 0) return '0 B'
|
||||
const units = ['B', 'KB', 'MB', 'GB']
|
||||
const index = Math.min(units.length - 1, Math.floor(Math.log(size) / Math.log(1024)))
|
||||
const formatted = size / Math.pow(1024, index)
|
||||
return `${formatted.toFixed(1)} ${units[index]}`
|
||||
}
|
||||
|
||||
// Transform custom field values to custom fields format
|
||||
const transformCustomFields = (pieces) => {
|
||||
return pieces.map(piece => {
|
||||
@@ -406,7 +542,8 @@ const transformCustomFields = (pieces) => {
|
||||
|
||||
return {
|
||||
...piece,
|
||||
customFields
|
||||
customFields,
|
||||
documents: piece.documents || []
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -439,7 +576,8 @@ const transformComponentCustomFields = (componentsData) => {
|
||||
...component,
|
||||
customFields, // Use customFields for frontend display
|
||||
pieces,
|
||||
subComponents // Use the transformed sousComposants as subComponents
|
||||
subComponents, // Use the transformed sousComposants as subComponents
|
||||
documents: component.documents || []
|
||||
};
|
||||
|
||||
console.log('Transformed component:', result.name, 'with subComponents:', result.subComponents?.length || 0)
|
||||
@@ -466,6 +604,8 @@ const loadMachineData = async () => {
|
||||
|
||||
if (machineResult.success) {
|
||||
machine.value = machineResult.data
|
||||
machine.value.documents = machine.value.documents || []
|
||||
machineDocumentsLoaded.value = !!(machine.value.documents?.length)
|
||||
console.log('Machine trouvée et assignée:', machine.value)
|
||||
} else {
|
||||
console.error('Machine non trouvée:', machineId)
|
||||
@@ -515,7 +655,11 @@ const loadMachineData = async () => {
|
||||
} else {
|
||||
console.log('Aucune pièce trouvée dans la réponse de la machine')
|
||||
}
|
||||
|
||||
|
||||
if (!machineDocumentsLoaded.value) {
|
||||
await refreshMachineDocuments()
|
||||
}
|
||||
|
||||
console.log('Chargement terminé avec succès')
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du chargement des données:', error)
|
||||
@@ -666,6 +810,9 @@ const editPiece = (piece) => {
|
||||
const toggleEditMode = () => {
|
||||
isEditMode.value = !isEditMode.value
|
||||
debug.value = !debug.value // Inversez la valeur de debug
|
||||
if (isEditMode.value && !machineDocumentsLoaded.value) {
|
||||
refreshMachineDocuments()
|
||||
}
|
||||
}
|
||||
|
||||
// Lifecycle
|
||||
|
||||
Reference in New Issue
Block a user