Add CommentSection component for inline comments on entity detail pages (machines, pieces, composants, products, categories, skeleton types). Add dedicated /comments page with filters, pagination and clickable links. Add unresolved count badge on avatar and in profile dropdown. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
231 lines
8.7 KiB
Vue
231 lines
8.7 KiB
Vue
<template>
|
|
<main class="container mx-auto px-6 py-8">
|
|
<!-- Loading State -->
|
|
<div v-if="d.loading.value" class="flex justify-center items-center py-12">
|
|
<span class="loading loading-spinner loading-lg"></span>
|
|
</div>
|
|
|
|
<!-- Machine Details -->
|
|
<div v-else-if="d.machine.value" ref="d.printAreaRef" class="space-y-8">
|
|
<DocumentPreviewModal
|
|
:document="d.previewDocument.value"
|
|
:visible="d.previewVisible.value"
|
|
@close="d.closePreview"
|
|
/>
|
|
|
|
<!-- Header with actions -->
|
|
<MachineDetailHeader
|
|
:title="machineViewTitle"
|
|
:is-details-view="s.isDetailsView.value"
|
|
:is-skeleton-view="s.isSkeletonView.value"
|
|
:is-edit-mode="d.isEditMode.value"
|
|
:has-skeleton-requirements="d.machineHasSkeletonRequirements.value"
|
|
@change-view="s.changeMachineView"
|
|
@toggle-edit="d.toggleEditMode"
|
|
@open-print="d.openPrintModal"
|
|
/>
|
|
|
|
<template v-if="s.isDetailsView.value">
|
|
<!-- Debug info -->
|
|
<div v-if="d.debug.value" class="bg-yellow-100 p-4 rounded-lg">
|
|
<p>Debug: Machine trouvée - {{ d.machine.value.name }}</p>
|
|
<p>Components count: {{ d.components.value.length }}</p>
|
|
<p>Pieces count: {{ d.pieces.value.length }}</p>
|
|
</div>
|
|
|
|
<!-- Hero -->
|
|
<PageHero
|
|
:title="d.machine.value.name"
|
|
:subtitle="d.machine.value.description || d.machine.value.typeMachine?.description"
|
|
min-height="min-h-[20vh]"
|
|
max-width="max-w-md"
|
|
rounded
|
|
>
|
|
<div class="flex justify-center gap-4">
|
|
<div v-if="d.machine.value.typeMachine?.category" class="badge badge-outline">
|
|
{{ d.machine.value.typeMachine?.category }}
|
|
</div>
|
|
<div v-if="d.machine.value.site?.name" class="badge badge-outline">
|
|
{{ d.machine.value.site?.name }}
|
|
</div>
|
|
<div v-if="d.machine.value.reference" class="badge badge-outline">
|
|
{{ d.machine.value.reference }}
|
|
</div>
|
|
</div>
|
|
</PageHero>
|
|
|
|
<!-- Machine Info Card -->
|
|
<MachineInfoCard
|
|
:is-edit-mode="d.isEditMode.value"
|
|
:machine-name="d.machineName.value"
|
|
:machine-reference="d.machineReference.value"
|
|
:machine-constructeur-ids="d.machineConstructeurIds.value"
|
|
:machine-constructeurs-display="d.machineConstructeursDisplay.value"
|
|
:has-machine-constructeur="d.hasMachineConstructeur.value"
|
|
:visible-custom-fields="d.visibleMachineCustomFields.value"
|
|
:get-machine-field-id="d.getMachineFieldId"
|
|
@update:machine-name="d.machineName.value = $event"
|
|
@update:machine-reference="d.machineReference.value = $event"
|
|
@update:constructeur-ids="d.handleMachineConstructeurChange"
|
|
@blur-field="d.updateMachineInfo"
|
|
@set-custom-field-value="d.setMachineCustomFieldValue"
|
|
@update-custom-field="d.updateMachineCustomField"
|
|
/>
|
|
|
|
<!-- Documents -->
|
|
<MachineDocumentsCard
|
|
:documents="d.machineDocumentsList.value"
|
|
:is-edit-mode="d.isEditMode.value"
|
|
:uploading="d.machineDocumentsUploading.value"
|
|
:files="d.machineDocumentFiles.value"
|
|
@update:files="d.machineDocumentFiles.value = $event"
|
|
@files-added="d.handleMachineFilesAdded"
|
|
@preview="d.openPreview"
|
|
@download="d.downloadDocument"
|
|
@remove="d.removeMachineDocument"
|
|
/>
|
|
|
|
<!-- Produits associés -->
|
|
<MachineProductsCard :products="d.machineDirectProducts.value" />
|
|
|
|
<!-- Components Section -->
|
|
<MachineComponentsCard
|
|
:components="d.components.value"
|
|
:is-edit-mode="d.isEditMode.value"
|
|
:collapsed="d.componentsCollapsed.value"
|
|
:collapse-toggle-token="d.collapseToggleToken.value"
|
|
@toggle-collapse="d.toggleAllComponents"
|
|
@update-component="d.updateComponent"
|
|
@edit-piece="d.updatePieceFromComponent"
|
|
@custom-field-update="d.updatePieceCustomField"
|
|
/>
|
|
|
|
<!-- Machine Pieces Section -->
|
|
<MachinePiecesCard
|
|
:pieces="d.machinePieces.value"
|
|
:is-edit-mode="d.isEditMode.value"
|
|
@update-piece="d.updatePieceInfo"
|
|
@edit-piece="d.editPiece"
|
|
@custom-field-update="d.updatePieceCustomField"
|
|
/>
|
|
|
|
<!-- Comments -->
|
|
<div class="mt-4">
|
|
<CommentSection
|
|
entity-type="machine"
|
|
:entity-id="String(machineId)"
|
|
:entity-name="d.machine.value?.name"
|
|
show-resolved
|
|
/>
|
|
</div>
|
|
</template>
|
|
|
|
<template v-else>
|
|
<MachineSkeletonSummary
|
|
:component-requirement-groups="d.componentRequirementGroups.value"
|
|
:piece-requirement-groups="d.pieceRequirementGroups.value"
|
|
:product-requirement-groups="d.productRequirementGroups.value"
|
|
/>
|
|
</template>
|
|
</div>
|
|
|
|
<!-- Error State -->
|
|
<div v-else class="text-center py-12">
|
|
<div class="max-w-md mx-auto">
|
|
<IconLucideAlertTriangle class="w-16 h-16 mx-auto text-gray-400 mb-4" aria-hidden="true" />
|
|
<h3 class="text-lg font-medium text-gray-900 mb-2">Machine non trouvée</h3>
|
|
<p class="text-gray-500 mb-4">La machine avec l'ID "{{ machineId }}" n'existe pas ou a été supprimée.</p>
|
|
<NuxtLink to="/machines" class="btn btn-primary">
|
|
Retour aux machines
|
|
</NuxtLink>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<MachinePrintSelectionModal
|
|
:open="d.printModalOpen.value"
|
|
:selection="d.printSelection"
|
|
:components="d.components.value"
|
|
:pieces="d.machinePieces.value"
|
|
@close="d.closePrintModal"
|
|
@confirm="d.handlePrintConfirm"
|
|
@select-all="d.setAllPrintSelection(true)"
|
|
@deselect-all="d.setAllPrintSelection(false)"
|
|
/>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { computed, onMounted } from 'vue'
|
|
import { useRoute } from 'vue-router'
|
|
import { useMachineDetailData } from '~/composables/useMachineDetailData'
|
|
import { useMachineSkeletonEditor } from '~/composables/useMachineSkeletonEditor'
|
|
import DocumentPreviewModal from '~/components/DocumentPreviewModal.vue'
|
|
import PageHero from '~/components/PageHero.vue'
|
|
import MachinePrintSelectionModal from '~/components/MachinePrintSelectionModal.vue'
|
|
import MachineDetailHeader from '~/components/machine/MachineDetailHeader.vue'
|
|
import MachineInfoCard from '~/components/machine/MachineInfoCard.vue'
|
|
import MachineDocumentsCard from '~/components/machine/MachineDocumentsCard.vue'
|
|
import MachineProductsCard from '~/components/machine/MachineProductsCard.vue'
|
|
import MachineComponentsCard from '~/components/machine/MachineComponentsCard.vue'
|
|
import MachinePiecesCard from '~/components/machine/MachinePiecesCard.vue'
|
|
import MachineSkeletonSummary from '~/components/machine/MachineSkeletonSummary.vue'
|
|
import IconLucideAlertTriangle from '~icons/lucide/alert-triangle'
|
|
|
|
const route = useRoute()
|
|
const machineId = route.params.id
|
|
const { canEdit } = usePermissions()
|
|
|
|
if (!machineId) {
|
|
console.error('ID de machine manquant')
|
|
}
|
|
|
|
const d = useMachineDetailData(machineId)
|
|
|
|
const s = useMachineSkeletonEditor({
|
|
machine: d.machine,
|
|
components: d.components,
|
|
pieces: d.pieces,
|
|
machineComponentLinks: d.machineComponentLinks,
|
|
machinePieceLinks: d.machinePieceLinks,
|
|
machineProductLinks: d.machineProductLinks,
|
|
machineType: d.machineType,
|
|
machineHasSkeletonRequirements: d.machineHasSkeletonRequirements,
|
|
componentRequirements: d.componentRequirements,
|
|
pieceRequirements: d.pieceRequirements,
|
|
productRequirements: d.productRequirements,
|
|
componentTypeLabelMap: d.componentTypeLabelMap,
|
|
pieceTypeLabelMap: d.pieceTypeLabelMap,
|
|
productInventory: d.productInventory,
|
|
flattenedComponents: d.flattenedComponents,
|
|
machinePieces: d.machinePieces,
|
|
machineDocumentsLoaded: d.machineDocumentsLoaded,
|
|
findProductById: d.findProductById,
|
|
findComponentById: d.findComponentById,
|
|
findPieceById: d.findPieceById,
|
|
transformCustomFields: d.transformCustomFields,
|
|
transformComponentCustomFields: d.transformComponentCustomFields,
|
|
applyMachineLinks: d.applyMachineLinks,
|
|
collapseAllComponents: d.collapseAllComponents,
|
|
initMachineFields: d.initMachineFields,
|
|
collectPiecesForSkeleton: d.collectPiecesForSkeleton,
|
|
constructeurs: d.constructeurs,
|
|
loadProducts: d.loadProducts,
|
|
reconfigureMachineSkeleton: d.reconfigureMachineSkeleton,
|
|
toast: d.toast,
|
|
})
|
|
|
|
const machineViewTitle = computed(() => {
|
|
if (s.isSkeletonView.value) return 'Squelette de la machine'
|
|
return d.isEditMode.value ? 'Modification de la machine' : 'Détails de la machine'
|
|
})
|
|
|
|
onMounted(() => {
|
|
d.loadMachineData()
|
|
d.loadInitialData()
|
|
|
|
if (route.query.edit === 'true' && canEdit.value) {
|
|
d.isEditMode.value = true
|
|
}
|
|
})
|
|
</script>
|