import { ref } from 'vue' import { useApi } from './useApi' import { useToast } from './useToast' import { extractCollection } from '~/shared/utils/apiHelpers' export interface Document { id: string name: string filename: string mimeType: string size: number fileUrl: string downloadUrl: string /** @deprecated Legacy Base64 data URI — use fileUrl instead */ path?: string createdAt?: string siteId?: string machineId?: string composantId?: string productId?: string pieceId?: string site?: { id: string; name?: string } | null machine?: { id: string; name?: string } | null composant?: { id: string; name?: string } | null piece?: { id: string; name?: string } | null product?: { id: string; name?: string } | null } export interface UploadContext { siteId?: string machineId?: string composantId?: string productId?: string pieceId?: string } export interface DocumentResult { success: boolean data?: Document | Document[] error?: string } interface LoadDocumentsOptions { search?: string page?: number itemsPerPage?: number orderBy?: string orderDir?: 'asc' | 'desc' attachmentFilter?: string force?: boolean } const documents = ref([]) const total = ref(0) const loading = ref(false) const loaded = ref(false) const extractTotal = (payload: unknown, fallbackLength: number): number => { const p = payload as Record | null if (typeof p?.totalItems === 'number') return p.totalItems if (typeof p?.['hydra:totalItems'] === 'number') return p['hydra:totalItems'] return fallbackLength } export function useDocuments() { const { get, postFormData, delete: del } = useApi() const { showError, showSuccess } = useToast() const loadFromEndpoint = async ( endpoint: string, { updateStore = false, itemsPerPage }: { updateStore?: boolean; itemsPerPage?: number } = {}, ): Promise => { loading.value = true try { const url = itemsPerPage ? `${endpoint}${endpoint.includes('?') ? '&' : '?'}itemsPerPage=${itemsPerPage}` : endpoint const result = await get(url) if (result.success) { const data = extractCollection(result.data) if (updateStore) { documents.value = data } return { success: true, data } } if (result.error) { showError(result.error) } return result as DocumentResult } catch (error) { const err = error as Error console.error(`Erreur lors du chargement des documents (${endpoint}):`, error) showError('Impossible de charger les documents') return { success: false, error: err.message } } finally { loading.value = false } } const loadDocuments = async (options: LoadDocumentsOptions = {}): Promise => { const { search = '', page = 1, itemsPerPage = 30, orderBy = 'createdAt', orderDir = 'desc', attachmentFilter = 'all', force = false, } = options if (!force && loaded.value && !search && page === 1 && attachmentFilter === 'all') { return { success: true, data: documents.value } } if (loading.value) { return { success: true, data: documents.value } } loading.value = true try { const params = new URLSearchParams() params.set('itemsPerPage', String(itemsPerPage)) params.set('page', String(page)) if (search && search.trim()) { params.set('name', search.trim()) } if (attachmentFilter && attachmentFilter !== 'all') { params.set(`exists[${attachmentFilter}]`, 'true') } params.set(`order[${orderBy}]`, orderDir) const result = await get(`/documents?${params.toString()}`) if (result.success) { const items = extractCollection(result.data) documents.value = items total.value = extractTotal(result.data, items.length) loaded.value = true return { success: true, data: items } } if (result.error) { showError(result.error) } return result as DocumentResult } catch (error) { const err = error as Error console.error('Erreur lors du chargement des documents:', error) showError('Impossible de charger les documents') return { success: false, error: err.message } } finally { loading.value = false } } const loadDocumentsBySite = async ( siteId: string, options: { updateStore?: boolean } = {}, ): Promise => { if (!siteId) { return { success: false, error: 'Aucun site sélectionné' } } return loadFromEndpoint(`/documents/site/${siteId}`, { updateStore: options.updateStore ?? false }) } const loadDocumentsByMachine = async ( machineId: string, options: { updateStore?: boolean } = {}, ): Promise => { if (!machineId) { return { success: false, error: 'Aucune machine sélectionnée' } } return loadFromEndpoint(`/documents/machine/${machineId}`, { updateStore: options.updateStore ?? false }) } const loadDocumentsByComponent = async ( componentId: string, options: { updateStore?: boolean } = {}, ): Promise => { if (!componentId) { return { success: false, error: 'Aucun composant sélectionné' } } return loadFromEndpoint(`/documents/composant/${componentId}`, { updateStore: options.updateStore ?? false }) } const loadDocumentsByProduct = async ( productId: string, options: { updateStore?: boolean } = {}, ): Promise => { if (!productId) { return { success: false, error: 'Aucun produit sélectionné' } } return loadFromEndpoint(`/documents/product/${productId}`, { updateStore: options.updateStore ?? false }) } const loadDocumentsByPiece = async ( pieceId: string, options: { updateStore?: boolean } = {}, ): Promise => { if (!pieceId) { return { success: false, error: 'Aucune pièce sélectionnée' } } return loadFromEndpoint(`/documents/piece/${pieceId}`, { updateStore: options.updateStore ?? false }) } const uploadDocuments = async ( { files, context = {} }: { files: File[]; context?: UploadContext }, { updateStore = false }: { updateStore?: boolean } = {}, ): Promise => { if (!files.length) { return { success: false, error: 'Aucun fichier sélectionné' } } loading.value = true const created: Document[] = [] try { for (const file of files) { const formData = new FormData() formData.append('file', file) formData.append('name', file.name) if (context.siteId) formData.append('siteId', context.siteId) if (context.machineId) formData.append('machineId', context.machineId) if (context.composantId) formData.append('composantId', context.composantId) if (context.productId) formData.append('productId', context.productId) if (context.pieceId) formData.append('pieceId', context.pieceId) const result = await postFormData('/documents', formData) if (result.success) { created.push(result.data as Document) showSuccess(`Document "${file.name}" ajouté`) } else if (result.error) { showError(`Erreur sur ${file.name} : ${result.error}`) } } if (created.length) { if (updateStore) { documents.value = [...created, ...documents.value] } return { success: true, data: created } } return { success: false, error: 'Aucun document ajouté' } } catch (error) { const err = error as Error console.error("Erreur lors de l'upload des documents:", error) showError("Échec de l'ajout des documents") return { success: false, error: err.message } } finally { loading.value = false } } const deleteDocument = async ( id: string | number, { updateStore = false }: { updateStore?: boolean } = {}, ): Promise => { if (!id) { return { success: false, error: 'Identifiant manquant' } } loading.value = true try { const result = await del(`/documents/${id}`) if (result.success) { if (updateStore) { documents.value = documents.value.filter((doc) => doc.id !== id) } showSuccess('Document supprimé') } return result as DocumentResult } catch (error) { const err = error as Error console.error('Erreur lors de la suppression du document:', error) showError('Impossible de supprimer le document') return { success: false, error: err.message } } finally { loading.value = false } } return { documents, total, loading, loaded, loadDocuments, loadDocumentsBySite, loadDocumentsByMachine, loadDocumentsByComponent, loadDocumentsByPiece, loadDocumentsByProduct, uploadDocuments, deleteDocument, } }