feat: enrich piece assignment labels and document previews
This commit is contained in:
@@ -86,9 +86,15 @@
|
||||
rounded
|
||||
>
|
||||
<div class="flex justify-center gap-4">
|
||||
<div class="badge badge-outline">{{ machine.typeMachine?.category || 'N/A' }}</div>
|
||||
<div class="badge badge-outline">{{ machine.site?.name }}</div>
|
||||
<div v-if="machine.reference" class="badge badge-outline">{{ machine.reference }}</div>
|
||||
<div v-if="machine.typeMachine?.category" class="badge badge-outline">
|
||||
{{ machine.typeMachine?.category }}
|
||||
</div>
|
||||
<div v-if="machine.site?.name" class="badge badge-outline">
|
||||
{{ machine.site?.name }}
|
||||
</div>
|
||||
<div v-if="machine.reference" class="badge badge-outline">
|
||||
{{ machine.reference }}
|
||||
</div>
|
||||
</div>
|
||||
</PageHero>
|
||||
|
||||
@@ -113,7 +119,7 @@
|
||||
{{ machineName }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<div v-if="isEditMode || machineReference" class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text">Référence</span>
|
||||
</label>
|
||||
@@ -126,10 +132,10 @@
|
||||
@blur="updateMachineInfo"
|
||||
/>
|
||||
<div v-else class="input input-bordered bg-base-200">
|
||||
{{ machineReference || 'Non définie' }}
|
||||
{{ machineReference }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<div v-if="isEditMode || hasMachineConstructeur" class="form-control">
|
||||
<label class="label">
|
||||
<span class="label-text">Constructeur</span>
|
||||
</label>
|
||||
@@ -143,9 +149,11 @@
|
||||
/>
|
||||
<div v-else class="input input-bordered bg-base-200">
|
||||
<div class="flex flex-col">
|
||||
<span class="font-medium">{{ machineConstructeurDisplay?.name || 'Non défini' }}</span>
|
||||
<span class="text-xs text-gray-500">
|
||||
{{ [machineConstructeurDisplay?.email, machineConstructeurDisplay?.phone].filter(Boolean).join(' • ') || '' }}
|
||||
<span class="font-medium">
|
||||
{{ machineConstructeurDisplay?.name || machineConstructeurContact }}
|
||||
</span>
|
||||
<span v-if="machineConstructeurContact" class="text-xs text-gray-500">
|
||||
{{ machineConstructeurContact }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -153,11 +161,11 @@
|
||||
</div>
|
||||
|
||||
<!-- Champs personnalisés -->
|
||||
<div v-if="machineCustomFields.length" class="mt-6 pt-4 border-t border-gray-200">
|
||||
<div v-if="visibleMachineCustomFields.length" class="mt-6 pt-4 border-t border-gray-200">
|
||||
<h4 class="font-semibold text-gray-700 mb-3">Champs personnalisés de la machine</h4>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div
|
||||
v-for="field in machineCustomFields"
|
||||
v-for="field in visibleMachineCustomFields"
|
||||
:key="field.customFieldValueId || field.id || field.name"
|
||||
class="form-control"
|
||||
>
|
||||
@@ -265,13 +273,22 @@
|
||||
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">
|
||||
<div class="h-14 w-14 flex-shrink-0 overflow-hidden rounded-md border border-base-200 bg-base-200/70 flex items-center justify-center">
|
||||
<div
|
||||
class="flex-shrink-0 overflow-hidden rounded-md border border-base-200 bg-base-200/70 flex items-center justify-center"
|
||||
:class="documentThumbnailClass(document)"
|
||||
>
|
||||
<img
|
||||
v-if="isImageDocument(document) && document.path"
|
||||
:src="document.path"
|
||||
class="h-full w-full object-cover"
|
||||
:alt="`Aperçu de ${document.name}`"
|
||||
>
|
||||
<iframe
|
||||
v-else-if="shouldInlinePdf(document)"
|
||||
:src="documentPreviewSrc(document)"
|
||||
class="h-full w-full border-0 bg-white"
|
||||
title="Aperçu PDF"
|
||||
/>
|
||||
<component
|
||||
v-else
|
||||
:is="documentIcon(document).component"
|
||||
@@ -525,7 +542,7 @@ import { useToast } from '~/composables/useToast'
|
||||
import { useDocuments } from '~/composables/useDocuments'
|
||||
import { getFileIcon } from '~/utils/fileIcons'
|
||||
import { sanitizeDefinitionOverrides, normalizeStructureForEditor } from '~/shared/modelUtils'
|
||||
import { canPreviewDocument, isImageDocument } from '~/utils/documentPreview'
|
||||
import { canPreviewDocument, isImageDocument, isPdfDocument } from '~/utils/documentPreview'
|
||||
import ComponentHierarchy from '~/components/ComponentHierarchy.vue'
|
||||
import DocumentUpload from '~/components/DocumentUpload.vue'
|
||||
import ConstructeurSelect from '~/components/ConstructeurSelect.vue'
|
||||
@@ -595,6 +612,20 @@ const machineConstructeurDisplay = computed(() => {
|
||||
if (!id) return machine.value?.constructeur || null
|
||||
return constructeurs.value.find(item => item.id === id) || machine.value?.constructeur || null
|
||||
})
|
||||
const machineConstructeurContact = computed(() => {
|
||||
const constructeur = machineConstructeurDisplay.value
|
||||
if (!constructeur) {
|
||||
return ''
|
||||
}
|
||||
return [constructeur.email, constructeur.phone].filter(Boolean).join(' • ')
|
||||
})
|
||||
const hasMachineConstructeur = computed(() => {
|
||||
const constructeur = machineConstructeurDisplay.value
|
||||
if (!constructeur) {
|
||||
return false
|
||||
}
|
||||
return Boolean(constructeur.name || machineConstructeurContact.value)
|
||||
})
|
||||
|
||||
const machineDocumentFiles = ref([])
|
||||
const machineDocumentsUploading = ref(false)
|
||||
@@ -1630,6 +1661,45 @@ const formatSize = (size) => {
|
||||
return `${formatted.toFixed(1)} ${units[index]}`
|
||||
}
|
||||
|
||||
const PDF_PREVIEW_MAX_BYTES = 5 * 1024 * 1024
|
||||
|
||||
const shouldInlinePdf = (document) => {
|
||||
if (!document || !isPdfDocument(document) || !document.path) {
|
||||
return false
|
||||
}
|
||||
if (typeof document.size === 'number' && document.size > PDF_PREVIEW_MAX_BYTES) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
const appendPdfViewerParams = (src) => {
|
||||
if (!src || src.startsWith('data:')) {
|
||||
return src || ''
|
||||
}
|
||||
if (src.includes('#')) {
|
||||
return `${src}&toolbar=0&navpanes=0`
|
||||
}
|
||||
return `${src}#toolbar=0&navpanes=0`
|
||||
}
|
||||
|
||||
const documentPreviewSrc = (document) => {
|
||||
if (!document?.path) {
|
||||
return ''
|
||||
}
|
||||
if (isPdfDocument(document)) {
|
||||
return appendPdfViewerParams(document.path)
|
||||
}
|
||||
return document.path
|
||||
}
|
||||
|
||||
const documentThumbnailClass = (document) => {
|
||||
if (shouldInlinePdf(document) || (isImageDocument(document) && document?.path)) {
|
||||
return 'h-24 w-20'
|
||||
}
|
||||
return 'h-16 w-16'
|
||||
}
|
||||
|
||||
const formatCustomFieldValue = (field) => {
|
||||
if (!field) {
|
||||
return 'Non défini'
|
||||
@@ -1674,6 +1744,14 @@ const shouldDisplayCustomField = (field) => {
|
||||
return true
|
||||
}
|
||||
|
||||
const visibleMachineCustomFields = computed(() => {
|
||||
const fields = Array.isArray(machineCustomFields.value) ? machineCustomFields.value : []
|
||||
if (isEditMode.value) {
|
||||
return fields
|
||||
}
|
||||
return fields.filter((field) => shouldDisplayCustomField(field))
|
||||
})
|
||||
|
||||
const summarizeCustomFields = (fields = []) => {
|
||||
const seen = new Set()
|
||||
return fields
|
||||
|
||||
Reference in New Issue
Block a user